Skip to content

Commit 675199a

Browse files
committed
feat: remove unnecessary steps while deposit and claim
1 parent c2b620a commit 675199a

7 files changed

+101
-76
lines changed

contracts/OperatorRewardsCollector.sol

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { ISDUtilityPool, UserData, OperatorLiquidation } from "./interfaces/ISDU
1616
import { ISDCollateral } from "./interfaces/SDCollateral/ISDCollateral.sol";
1717
import { IWETH } from "./interfaces/IWETH.sol";
1818
import { IStaderOracle } from "../contracts/interfaces/IStaderOracle.sol";
19+
import { IPoolUtils } from "../contracts/interfaces/IPoolUtils.sol";
1920

2021
contract OperatorRewardsCollector is IOperatorRewardsCollector, AccessControlUpgradeable {
2122
IStaderConfig public staderConfig;
@@ -52,10 +53,18 @@ contract OperatorRewardsCollector is IOperatorRewardsCollector, AccessControlUpg
5253
* @dev This function first checks for any unpaid liquidations for the operator and repays them if necessary. Then, it transfers any remaining balance to the operator's reward address.
5354
*/
5455
function claim() external {
55-
claimLiquidation(msg.sender);
56-
uint256 amount = balances[msg.sender] > withdrawableInEth(msg.sender)
57-
? withdrawableInEth(msg.sender)
58-
: balances[msg.sender];
56+
IPoolUtils poolUtils = IPoolUtils(staderConfig.getPoolUtils());
57+
uint8 poolId = poolUtils.getOperatorPoolId(msg.sender);
58+
address permissionlessNodeRegistry = staderConfig.getPermissionlessNodeRegistry();
59+
uint256 amount;
60+
if (INodeRegistry(permissionlessNodeRegistry).POOL_ID() == poolId) {
61+
claimLiquidation(msg.sender);
62+
amount = balances[msg.sender] > withdrawableInEth(msg.sender)
63+
? withdrawableInEth(msg.sender)
64+
: balances[msg.sender];
65+
} else {
66+
amount = balances[msg.sender];
67+
}
5968
_claim(msg.sender, amount);
6069
}
6170

@@ -66,7 +75,17 @@ contract OperatorRewardsCollector is IOperatorRewardsCollector, AccessControlUpg
6675
* @param _amount amount of ETH to claim
6776
*/
6877
function claimWithAmount(uint256 _amount) external {
69-
claimLiquidation(msg.sender);
78+
IPoolUtils poolUtils = IPoolUtils(staderConfig.getPoolUtils());
79+
uint8 poolId = poolUtils.getOperatorPoolId(msg.sender);
80+
address permissionlessNodeRegistry = staderConfig.getPermissionlessNodeRegistry();
81+
82+
if (INodeRegistry(permissionlessNodeRegistry).POOL_ID() == poolId) {
83+
claimLiquidation(msg.sender);
84+
uint256 maxWithdrawableInEth = withdrawableInEth(msg.sender);
85+
if (_amount > maxWithdrawableInEth || _amount > balances[msg.sender]) revert InsufficientBalance();
86+
} else {
87+
if (_amount > balances[msg.sender]) revert InsufficientBalance();
88+
}
7089
_claim(msg.sender, _amount);
7190
}
7291

@@ -181,9 +200,6 @@ contract OperatorRewardsCollector is IOperatorRewardsCollector, AccessControlUpg
181200
* @param amount The amount to be claimed.
182201
*/
183202
function _claim(address operator, uint256 amount) internal {
184-
uint256 maxWithdrawableInEth = withdrawableInEth(operator);
185-
if (amount > maxWithdrawableInEth || amount > balances[operator]) revert InsufficientBalance();
186-
187203
balances[operator] -= amount;
188204

189205
// If there's an amount to send, transfer it to the operator's rewards address

contracts/PermissionedNodeRegistry.sol

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -720,22 +720,6 @@ contract PermissionedNodeRegistry is
720720
revert InvalidKeyCount();
721721
}
722722
totalKeys = getOperatorTotalKeys(_operatorId);
723-
uint256 totalNonTerminalKeys = getOperatorTotalNonTerminalKeys(msg.sender, 0, totalKeys);
724-
if ((totalNonTerminalKeys + keyCount) > maxNonTerminalKeyPerOperator) {
725-
revert MaxKeyLimitReached();
726-
}
727-
728-
//checks if operator has enough SD collateral for adding `keyCount` keys
729-
//SD threshold for permissioned NOs is 0 for phase1
730-
if (
731-
!ISDCollateral(staderConfig.getSDCollateral()).hasEnoughSDCollateral(
732-
msg.sender,
733-
POOL_ID,
734-
totalNonTerminalKeys + keyCount
735-
)
736-
) {
737-
revert NotEnoughSDCollateral();
738-
}
739723
}
740724

741725
// operator in active state

lib/openzeppelin-foundry-upgrades

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Subproject commit 16e0ae21e0e39049f619f2396fa28c57fad07368
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { ethers, network } from "hardhat";
2+
import "dotenv/config";
3+
import { impersonateAccount, setBalance } from "@nomicfoundation/hardhat-network-helpers";
4+
5+
const PROXY_OWNER = "0x1112D5C55670Cb5144BF36114C20a122908068B9"
6+
const PROXY_ADMIN = "0x67B12264Ca3e0037Fc7E22F2457b42643a04C86e";
7+
const OPERATOR_REWARDS_COLLECTOR_ADDRESS = "0x84ffDC9De310144D889540A49052F6d1AdB2C335";
8+
const OPERATOR = "0xb851788Fa34B0d9215F54531061D4e2e06A74AEE"
9+
10+
async function setForkBlock(blockNumber: number) {
11+
await network.provider.request({
12+
method: "hardhat_reset",
13+
params: [
14+
{
15+
forking: {
16+
jsonRpcUrl: process.env.PROVIDER_URL_MAINNET,
17+
blockNumber: blockNumber,
18+
},
19+
},
20+
],
21+
});
22+
}
23+
24+
async function configureNewContract (contractName: String, contractAddress: String) {
25+
await setBalance(PROXY_OWNER, ethers.parseEther("1"))
26+
await impersonateAccount(PROXY_OWNER)
27+
28+
const impersonatedProxyOwner = await ethers.getSigner(PROXY_OWNER);
29+
30+
const contractFactory = await ethers.getContractFactory(contractName);
31+
const contractImpl = await contractFactory.deploy();
32+
console.log(`${contractName} Implementation deployed to:`, await contractImpl.getAddress());
33+
34+
const proxyAdminContract = await ethers.getContractAt("ProxyAdmin", PROXY_ADMIN);
35+
await proxyAdminContract.connect(impersonatedProxyOwner).upgrade(contractAddress, await contractImpl.getAddress());
36+
37+
const contract = await ethers.getContractAt(contractName, contractAddress)
38+
39+
return contract;
40+
}
41+
42+
describe("Gas Coverage", function () {
43+
it("should consume less gas after upgrade", async () => {
44+
await setForkBlock(21270988);
45+
await setBalance(OPERATOR, ethers.parseEther("100"))
46+
await impersonateAccount(OPERATOR);
47+
const impersonatedOperator = await ethers.getSigner(OPERATOR);
48+
49+
const newOperatorRewardsCollector = await configureNewContract("OperatorRewardsCollector", OPERATOR_REWARDS_COLLECTOR_ADDRESS);
50+
51+
// Firing a txn with updated contracts
52+
const claimTxn = await newOperatorRewardsCollector.connect(impersonatedOperator).claim();
53+
const claimTxnReceipt = await claimTxn.wait();
54+
console.log("Claim Txn Gas Estimate:", claimTxnReceipt.gasUsed);
55+
});
56+
});

test/foundry_tests/NodeELRewardVault.t.sol

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { PoolUtilsMock } from "../mocks/PoolUtilsMock.sol";
1919
import { StakePoolManagerMock } from "../mocks/StakePoolManagerMock.sol";
2020
import { StaderOracleMock } from "../mocks/StaderOracleMock.sol";
2121
import { SDUtilityPoolMock } from "../mocks/SDUtilityPoolMock.sol";
22+
import { PermissionlessNodeRegistryMock } from "../mocks/PermissionlessNodeRegistryMock.sol";
2223

2324
contract NodeELRewardVaultTest is Test {
2425
address private constant OPERATOR_ADDRESSS = address(500);
@@ -59,6 +60,7 @@ contract NodeELRewardVaultTest is Test {
5960
address operator = OPERATOR_ADDRESSS;
6061
mockStaderOracle(staderOracleMock);
6162
mockSdUtilityPool(sdUtilityPoolMock, operator);
63+
mockPermissionlessNodeRegistry(vm.addr(105));
6264

6365
OperatorRewardsCollector operatorRCImpl = new OperatorRewardsCollector();
6466
TransparentUpgradeableProxy operatorRCProxy = new TransparentUpgradeableProxy(
@@ -95,6 +97,7 @@ contract NodeELRewardVaultTest is Test {
9597
staderConfig.updateSDCollateral(address(sdCollateral));
9698
staderConfig.updateSDUtilityPool(sdUtilityPoolMock);
9799
staderConfig.updateStaderOracle(staderOracleMock);
100+
staderConfig.updatePermissionlessNodeRegistry(vm.addr(105));
98101
staderConfig.grantRole(staderConfig.MANAGER(), staderManager);
99102
vaultFactory.grantRole(vaultFactory.NODE_REGISTRY_CONTRACT(), address(poolUtils.nodeRegistry()));
100103
vm.stopPrank();
@@ -265,4 +268,11 @@ contract NodeELRewardVaultTest is Test {
265268
bytes memory mockCode = address(implementation).code;
266269
vm.etch(staderOracleMock, mockCode);
267270
}
271+
272+
function mockPermissionlessNodeRegistry(address _permissionlessNodeRegistry) private {
273+
emit log_named_address("permissionlessNodeRegistry", _permissionlessNodeRegistry);
274+
PermissionlessNodeRegistryMock nodeRegistryMock = new PermissionlessNodeRegistryMock();
275+
bytes memory mockCode = address(nodeRegistryMock).code;
276+
vm.etch(_permissionlessNodeRegistry, mockCode);
277+
}
268278
}

test/foundry_tests/PermissionedNodeRegistry.t.sol

Lines changed: 0 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -227,24 +227,6 @@ contract PermissionedNodeRegistryTest is Test {
227227
assertEq(nodeRegistry.isExistingPubkey(pubkeys[0]), true);
228228
}
229229

230-
function testAddValidatorKeysNotEnoughSDCollateral() public {
231-
(
232-
bytes[] memory pubkeys,
233-
bytes[] memory preDepositSignature,
234-
bytes[] memory depositSignature
235-
) = getValidatorKeys();
236-
vm.startPrank(permissionedNO);
237-
nodeRegistry.onboardNodeOperator("testOP", payable(address(this)));
238-
vm.mockCall(
239-
address(sdCollateral),
240-
abi.encodeWithSelector(ISDCollateral.hasEnoughSDCollateral.selector),
241-
abi.encode(false)
242-
);
243-
vm.expectRevert(INodeRegistry.NotEnoughSDCollateral.selector);
244-
nodeRegistry.addValidatorKeys(pubkeys, preDepositSignature, depositSignature);
245-
vm.stopPrank();
246-
}
247-
248230
function test_addValidatorKeysWithMisMatchingInputs() public {
249231
bytes[] memory pubkeys = new bytes[](1);
250232
bytes[] memory preDepositSignature = new bytes[](1);
@@ -271,40 +253,6 @@ contract PermissionedNodeRegistryTest is Test {
271253
vm.stopPrank();
272254
}
273255

274-
function test_addValidatorKeysOPCrossingMaxNonTerminalKeys() public {
275-
(
276-
bytes[] memory pubkeys,
277-
bytes[] memory preDepositSignature,
278-
bytes[] memory depositSignature
279-
) = getValidatorKeys();
280-
vm.prank(staderManager);
281-
nodeRegistry.updateMaxNonTerminalKeyPerOperator(2);
282-
vm.startPrank(permissionedNO);
283-
nodeRegistry.onboardNodeOperator("testOP", payable(address(this)));
284-
vm.expectRevert(INodeRegistry.MaxKeyLimitReached.selector);
285-
nodeRegistry.addValidatorKeys(pubkeys, preDepositSignature, depositSignature);
286-
vm.stopPrank();
287-
}
288-
289-
function test_addValidatorKeysWithInsufficientSDCollateral() public {
290-
(
291-
bytes[] memory pubkeys,
292-
bytes[] memory preDepositSignature,
293-
bytes[] memory depositSignature
294-
) = getValidatorKeys();
295-
296-
vm.startPrank(permissionedNO);
297-
nodeRegistry.onboardNodeOperator("testOP", payable(address(this)));
298-
vm.mockCall(
299-
address(sdCollateral),
300-
abi.encodeWithSelector(ISDCollateral.hasEnoughSDCollateral.selector),
301-
abi.encode(false)
302-
);
303-
vm.expectRevert(INodeRegistry.NotEnoughSDCollateral.selector);
304-
nodeRegistry.addValidatorKeys(pubkeys, preDepositSignature, depositSignature);
305-
vm.stopPrank();
306-
}
307-
308256
function test_markReadyToDepositValidator() public {
309257
(
310258
bytes[] memory pubkeys,

test/foundry_tests/ValidatorWithdrawalVault.t.sol

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import "../mocks/StakePoolManagerMock.sol";
2121

2222
import { SDUtilityPoolMock } from "../mocks/SDUtilityPoolMock.sol";
2323
import { StaderOracleMock } from "../mocks/StaderOracleMock.sol";
24+
import { PermissionlessNodeRegistryMock } from "../mocks/PermissionlessNodeRegistryMock.sol";
2425

2526
contract ValidatorWithdrawalVaultTest is Test {
2627
address private constant OPERATOR_ADDRESS = address(500);
@@ -52,6 +53,7 @@ contract ValidatorWithdrawalVaultTest is Test {
5253

5354
mockStaderOracle(staderOracleMock);
5455
mockSDUtilityPool(sdUtilityPoolMock, operator);
56+
mockPermissionlessNodeRegistry(vm.addr(105));
5557

5658
ProxyAdmin proxyAdmin = new ProxyAdmin();
5759

@@ -93,6 +95,7 @@ contract ValidatorWithdrawalVaultTest is Test {
9395
staderConfig.updateOperatorRewardsCollector(address(operatorRC));
9496
staderConfig.updateValidatorWithdrawalVaultImplementation(address(withdrawVaultImpl));
9597
staderConfig.updateStaderOracle(staderOracleMock);
98+
staderConfig.updatePermissionlessNodeRegistry(vm.addr(105));
9699
staderConfig.grantRole(staderConfig.MANAGER(), staderManager);
97100
vaultFactory.grantRole(vaultFactory.NODE_REGISTRY_CONTRACT(), address(poolUtils.nodeRegistry()));
98101
vm.stopPrank();
@@ -384,4 +387,11 @@ contract ValidatorWithdrawalVaultTest is Test {
384387
abi.encode(UserData(0 ether, 4 ether, 1, 0))
385388
);
386389
}
390+
391+
function mockPermissionlessNodeRegistry(address _permissionlessNodeRegistry) private {
392+
emit log_named_address("permissionlessNodeRegistry", _permissionlessNodeRegistry);
393+
PermissionlessNodeRegistryMock nodeRegistryMock = new PermissionlessNodeRegistryMock();
394+
bytes memory mockCode = address(nodeRegistryMock).code;
395+
vm.etch(_permissionlessNodeRegistry, mockCode);
396+
}
387397
}

0 commit comments

Comments
 (0)