Skip to content

Commit 6ebd161

Browse files
authored
Merge pull request #11 from LemonTreeTechnologies/refactor_curating_access
refactor: external staking curating agent access
2 parents 40f3fc4 + ce23b66 commit 6ebd161

2 files changed

Lines changed: 69 additions & 23 deletions

File tree

contracts/l2/ExternalStakingDistributor.sol

Lines changed: 67 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,9 @@ contract ExternalStakingDistributor is Implementation, ERC721TokenReceiver {
179179
);
180180
event SetStakingProxyConfigs(address[] stakingProxies, uint256[] proxyTypes);
181181
event SetManagingAgentStatuses(address[] managingAgents, bool[] statuses);
182-
event SetCuratingAgentStatuses(address[] managingAgents, bool[] statuses);
182+
event SetCuratingAgentStatuses(
183+
address indexed stakingGuard, address indexed stakingProxy, address[] managingAgents, bool[] statuses
184+
);
183185
event Deposit(address indexed sender, bytes32 indexed operation, uint256 amount);
184186
event Withdraw(address indexed sender, bytes32 indexed operation, uint256 amount, uint256 unstakeRequestedAmount);
185187
event Claimed(address[] stakingProxies, uint256[] serviceIds, uint256[] rewards);
@@ -231,20 +233,23 @@ contract ExternalStakingDistributor is Implementation, ERC721TokenReceiver {
231233
uint256 internal _locked = 1;
232234

233235
// Mapping of whitelisted staking proxy address => (staking reward distributions | staking type)
234-
// Staking config: collectorRewardFactor 16 bits | protocolRewardFactor 16 bits
236+
// Staking config: stakingGuard 160 bits | collectorRewardFactor 16 bits | protocolRewardFactor 16 bits
235237
// | curatingAgentRewardFactor 16 bits | stakingType 8 bits
236238
mapping(address => uint256) public mapStakingProxyConfigs;
237239
// Mapping of unstake requests: unstake operation => amount requested
238240
mapping(bytes32 => uint256) public mapUnstakeOperationRequestedAmounts;
239241
// Mapping of service Id => agent address curating it
240242
mapping(uint256 => address) public mapServiceIdCuratingAgents;
241-
// Mapping whitelisted curating agent addresses
243+
// UNUSED for now: Mapping whitelisted curating agent addresses
242244
mapping(address => bool) public mapCuratingAgents;
243245
// Mapping of whitelisted managing agent addresses
244246
mapping(address => bool) public mapManagingAgents;
245247
// Mapping of multisig address => service Id
246248
mapping(address => uint256) public mapMultisigServiceIds;
247249

250+
// Mapping of (staking guard + staking proxy) hash => whitelisted curating agent addresses
251+
mapping(bytes32 => mapping(address => bool)) public mapStakingGuardHashCuratingAgents;
252+
248253
/// @dev ExternalStakingDistributor constructor.
249254
/// @param _olas OLAS token address.
250255
/// @param _serviceManager Service manager address.
@@ -485,7 +490,7 @@ contract ExternalStakingDistributor is Implementation, ERC721TokenReceiver {
485490
uint256 config = mapStakingProxyConfigs[stakingProxy];
486491

487492
// Unwrap config
488-
(uint256 collectorAmount, uint256 protocolAmount,, StakingType stakingType) = unwrapStakingConfig(config);
493+
(, uint256 collectorAmount, uint256 protocolAmount,, StakingType stakingType) = unwrapStakingConfig(config);
489494

490495
// Calculate reward distribution
491496
collectorAmount = (reward * collectorAmount) / MAX_REWARD_FACTOR;
@@ -580,16 +585,36 @@ contract ExternalStakingDistributor is Implementation, ERC721TokenReceiver {
580585
}
581586
_locked = 2;
582587

583-
// Check for access: whitelisted curating agent or owner
584-
if (!mapCuratingAgents[msg.sender] && msg.sender != owner) {
585-
revert UnauthorizedAccount(msg.sender);
586-
}
588+
// Get proxy config value
589+
uint256 config = mapStakingProxyConfigs[stakingProxy];
587590

588591
// Check for whitelisted staking proxy type
589-
if (mapStakingProxyConfigs[stakingProxy] == 0) {
592+
if (config == 0) {
590593
revert ZeroValue();
591594
}
592595

596+
// If staker is not owner - check for curating agent access
597+
if (msg.sender != owner) {
598+
// Curating agent access is true, if not set otherwise
599+
bool curatingAgentAccess = true;
600+
601+
// Get staking guard address
602+
(address stakingGuard,,,,) = unwrapStakingConfig(config);
603+
604+
// Check for msg.sender access
605+
if (stakingGuard != address(0)) {
606+
// Get staking hash
607+
bytes32 stakingHash = keccak256(abi.encode(stakingGuard, stakingProxy));
608+
// Check access
609+
curatingAgentAccess = mapStakingGuardHashCuratingAgents[stakingHash][msg.sender];
610+
}
611+
612+
// Check for access: whitelisted curating agent
613+
if (!curatingAgentAccess) {
614+
revert UnauthorizedAccount(msg.sender);
615+
}
616+
}
617+
593618
// Check for zero value
594619
if (configHash == 0) {
595620
revert ZeroValue();
@@ -760,7 +785,7 @@ contract ExternalStakingDistributor is Implementation, ERC721TokenReceiver {
760785
}
761786

762787
// Check proxy configs
763-
(uint256 collectorRewardFactor, uint256 protocolRewardFactor, uint256 curatingAgentRewardFactor,) =
788+
(, uint256 collectorRewardFactor, uint256 protocolRewardFactor, uint256 curatingAgentRewardFactor,) =
764789
unwrapStakingConfig(configs[i]);
765790

766791
// Check for collector and zero value
@@ -812,32 +837,48 @@ contract ExternalStakingDistributor is Implementation, ERC721TokenReceiver {
812837

813838
/// @dev Sets curating agents statuses.
814839
/// @notice This is required such that potential malicious agents do not stake for no reason.
840+
/// @notice Contract owner sets stakingProxy config, however this function call is for staking guards only.
841+
/// @param stakingProxy Staking proxy address.
815842
/// @param curatingAgents Set of curating agents.
816843
/// @param statuses Corresponding set of statuses: true / false.
817-
function setCuratingAgents(address[] memory curatingAgents, bool[] memory statuses) external {
818-
// Check for the ownership
819-
if (msg.sender != owner) {
820-
revert OwnerOnly(msg.sender, owner);
821-
}
822-
844+
function setCuratingAgents(address stakingProxy, address[] memory curatingAgents, bool[] memory statuses) external {
823845
// Get number of agents
824846
uint256 numAgents = curatingAgents.length;
825847
// Check for array length
826848
if (numAgents == 0 || numAgents != statuses.length) {
827849
revert WrongArrayLength();
828850
}
829851

852+
// Get proxy config value
853+
uint256 config = mapStakingProxyConfigs[stakingProxy];
854+
855+
// Check for whitelisted staking proxy type
856+
if (config == 0) {
857+
revert ZeroValue();
858+
}
859+
860+
// Get staking guard address
861+
(address stakingGuard,,,,) = unwrapStakingConfig(config);
862+
863+
// Check for access: only staking guard
864+
if (msg.sender != stakingGuard) {
865+
revert UnauthorizedAccount(msg.sender);
866+
}
867+
830868
// Traverse curating agents
831869
for (uint256 i = 0; i < numAgents; ++i) {
832870
// Check for zero address
833871
if (curatingAgents[i] == address(0)) {
834872
revert ZeroAddress();
835873
}
836874

837-
mapCuratingAgents[curatingAgents[i]] = statuses[i];
875+
// Encode staking hash
876+
bytes32 stakingHash = keccak256(abi.encode(stakingGuard, stakingProxy));
877+
// Set curating agent status
878+
mapStakingGuardHashCuratingAgents[stakingHash][curatingAgents[i]] = statuses[i];
838879
}
839880

840-
emit SetCuratingAgentStatuses(curatingAgents, statuses);
881+
emit SetCuratingAgentStatuses(stakingGuard, stakingProxy, curatingAgents, statuses);
841882
}
842883

843884
/// @dev Deposits OLAS for further staking.
@@ -962,11 +1003,13 @@ contract ExternalStakingDistributor is Implementation, ERC721TokenReceiver {
9621003
}
9631004

9641005
/// @dev Wraps staking proxy config: reward factors and staking type value.
1006+
/// @param stakingGuard Staking proxy proposer address.
9651007
/// @param collectorRewardFactor Collector reward factor.
9661008
/// @param protocolRewardFactor Protocol reward factor.
9671009
/// @param curatingAgentRewardFactor Curating agent reward factor.
9681010
/// @param stakingType Staking type.
9691011
function wrapStakingConfig(
1012+
address stakingGuard,
9701013
uint256 collectorRewardFactor,
9711014
uint256 protocolRewardFactor,
9721015
uint256 curatingAgentRewardFactor,
@@ -975,11 +1018,12 @@ contract ExternalStakingDistributor is Implementation, ERC721TokenReceiver {
9751018
// Staking config: collectorRewardFactor 16 bits | protocolRewardFactor 16 bits
9761019
// | curatingAgentRewardFactor 16 bits | stakingType 8 bits
9771020
config = uint8(stakingType) | curatingAgentRewardFactor << 8 | protocolRewardFactor << 24
978-
| collectorRewardFactor << 40;
1021+
| collectorRewardFactor << 40 | uint160(stakingGuard) << 56;
9791022
}
9801023

9811024
/// @dev Unwraps staking proxy config: reward factors and staking type value.
9821025
/// @param config Staking proxy config value.
1026+
/// @return stakingGuard Staking proxy proposer address.
9831027
/// @return collectorRewardFactor Collector reward factor.
9841028
/// @return protocolRewardFactor Protocol reward factor.
9851029
/// @return curatingAgentRewardFactor Curating agent reward factor.
@@ -988,15 +1032,17 @@ contract ExternalStakingDistributor is Implementation, ERC721TokenReceiver {
9881032
public
9891033
pure
9901034
returns (
1035+
address stakingGuard,
9911036
uint256 collectorRewardFactor,
9921037
uint256 protocolRewardFactor,
9931038
uint256 curatingAgentRewardFactor,
9941039
StakingType stakingType
9951040
)
9961041
{
997-
// Staking config: collectorRewardFactor 16 bits | protocolRewardFactor 16 bits
1042+
// Staking config: stakingGuard 160 bits | collectorRewardFactor 16 bits | protocolRewardFactor 16 bits
9981043
// | curatingAgentRewardFactor 16 bits | stakingType 8 bits
999-
collectorRewardFactor = config >> 40;
1044+
stakingGuard = address(uint160(config >> 56));
1045+
collectorRewardFactor = uint16(config >> 40);
10001046
protocolRewardFactor = uint16(config >> 24);
10011047
curatingAgentRewardFactor = uint16(config >> 8);
10021048
stakingType = StakingType(uint8(config));

test/LiquidStaking.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1777,9 +1777,9 @@ describe("Liquid Staking", function () {
17771777

17781778
// Create staking proxy config: 80% of rewards - to stOLAS, 17.5% - to protocol, 2.5% - to curating agent
17791779
// Staking type - STAKING_TYPE_OLAS_V1
1780-
const stakingConfigValueV1 = await externalStakingDistributor.wrapStakingConfig(8000, 1750, 250, 0);
1780+
const stakingConfigValueV1 = await externalStakingDistributor.wrapStakingConfig(AddressZero, 8000, 1750, 250, 0);
17811781
// Staking type - STAKING_TYPE_OLAS_V2
1782-
const stakingConfigValueV2 = await externalStakingDistributor.wrapStakingConfig(8000, 1750, 250, 1);
1782+
const stakingConfigValueV2 = await externalStakingDistributor.wrapStakingConfig(AddressZero, 8000, 1750, 250, 1);
17831783

17841784
// Whitelist staking proxies
17851785
await externalStakingDistributor.setStakingProxyConfigs([externalStakingTokenAddressV1,

0 commit comments

Comments
 (0)