diff --git a/script/5_Withdraw.s.sol b/script/5_Withdraw.s.sol index 6364d766..92011269 100644 --- a/script/5_Withdraw.s.sol +++ b/script/5_Withdraw.s.sol @@ -68,7 +68,7 @@ contract DepositScript is BaseScript { uint256 nativeFee = clientGateway.quote(msg_); console.log("l0 native fee:", nativeFee); - clientGateway.withdrawPrincipalFromExocore{value: nativeFee}(address(restakeToken), WITHDRAW_AMOUNT); + clientGateway.claimPrincipalFromExocore{value: nativeFee}(address(restakeToken), WITHDRAW_AMOUNT); vm.stopBroadcast(); if (useEndpointMock) { diff --git a/src/core/BaseRestakingController.sol b/src/core/BaseRestakingController.sol index 5e490d92..b7cc66a2 100644 --- a/src/core/BaseRestakingController.sol +++ b/src/core/BaseRestakingController.sol @@ -33,7 +33,7 @@ abstract contract BaseRestakingController is receive() external payable {} /// @inheritdoc IBaseRestakingController - function claim(address token, uint256 amount, address recipient) + function withdrawPrincipal(address token, uint256 amount, address recipient) external isTokenWhitelisted(token) isValidAmount(amount) @@ -48,8 +48,6 @@ abstract contract BaseRestakingController is IVault vault = _getVault(token); vault.withdraw(msg.sender, recipient, amount); } - - emit ClaimSucceeded(token, recipient, amount); } /// @inheritdoc IBaseRestakingController @@ -89,6 +87,8 @@ abstract contract BaseRestakingController is whenNotPaused nonReentrant { + require(token != address(0), "BaseRestakingController: token address cannot be empty or zero address"); + require(avs != address(0), "BaseRestakingController: avs address cannot be empty or zero address"); // deposit reward to reward vault rewardVault.deposit(token, msg.sender, avs, amount); // send request to exocore, and this would not expect a response since deposit is supposed to be must success by @@ -104,6 +104,7 @@ abstract contract BaseRestakingController is whenNotPaused nonReentrant { + require(token != address(0), "BaseRestakingController: token address cannot be empty or zero address"); bytes memory actionArgs = abi.encodePacked(bytes32(bytes20(token)), bytes32(bytes20(msg.sender)), amount); bytes memory encodedRequest = abi.encode(token, msg.sender, amount); _processRequest(Action.REQUEST_CLAIM_REWARD, actionArgs, encodedRequest); @@ -115,6 +116,8 @@ abstract contract BaseRestakingController is whenNotPaused nonReentrant { + require(token != address(0), "BaseRestakingController: token address cannot be empty or zero address"); + require(recipient != address(0), "BaseRestakingController: recipient address cannot be empty or zero address"); rewardVault.withdraw(token, msg.sender, recipient, amount); } diff --git a/src/core/Bootstrap.sol b/src/core/Bootstrap.sol index 0b2f92c7..04e2c454 100644 --- a/src/core/Bootstrap.sol +++ b/src/core/Bootstrap.sol @@ -390,7 +390,7 @@ contract Bootstrap is } /// @inheritdoc ILSTRestakingController - function withdrawPrincipalFromExocore(address token, uint256 amount) + function claimPrincipalFromExocore(address token, uint256 amount) external payable override @@ -403,14 +403,14 @@ contract Bootstrap is if (msg.value > 0) { revert Errors.NonZeroValue(); } - _withdraw(msg.sender, token, amount); + _claim(msg.sender, token, amount); } - /// @dev Internal version of withdraw. + /// @dev Internal version of claim. /// @param user The address of the withdrawer. /// @param token The address of the token. /// @param amount The amount of the @param token to withdraw. - function _withdraw(address user, address token, uint256 amount) internal { + function _claim(address user, address token, uint256 amount) internal { IVault vault = _getVault(token); uint256 deposited = totalDepositAmounts[user][token]; @@ -430,7 +430,7 @@ contract Bootstrap is // afterReceiveWithdrawPrincipalResponse vault.unlockPrincipal(user, amount); - emit WithdrawPrincipalResult(true, token, user, amount); + emit ClaimPrincipalResult(true, token, user, amount); } /// @inheritdoc IBaseRestakingController @@ -452,7 +452,7 @@ contract Bootstrap is } /// @inheritdoc IBaseRestakingController - function claim(address token, uint256 amount, address recipient) + function withdrawPrincipal(address token, uint256 amount, address recipient) external override beforeLocked diff --git a/src/core/LSTRestakingController.sol b/src/core/LSTRestakingController.sol index 70dca147..942f656d 100644 --- a/src/core/LSTRestakingController.sol +++ b/src/core/LSTRestakingController.sol @@ -42,7 +42,7 @@ abstract contract LSTRestakingController is } /// @inheritdoc ILSTRestakingController - function withdrawPrincipalFromExocore(address token, uint256 principalAmount) + function claimPrincipalFromExocore(address token, uint256 principalAmount) external payable isTokenWhitelisted(token) diff --git a/src/interfaces/IBaseRestakingController.sol b/src/interfaces/IBaseRestakingController.sol index 148d860e..037d23ca 100644 --- a/src/interfaces/IBaseRestakingController.sol +++ b/src/interfaces/IBaseRestakingController.sol @@ -18,13 +18,13 @@ interface IBaseRestakingController { /// @param amount The amount of tokens to undelegate. function undelegateFrom(string calldata operator, address token, uint256 amount) external payable; - /// @notice Client chain users call to claim their unlocked assets from the vault. - /// @dev This function assumes that the claimable assets should have been unlocked before calling this. + /// @notice Client chain users call to withdraw their unlocked assets from the vault. + /// @dev This function assumes that the withdrawable assets should have been unlocked before calling this. /// @dev This function does not interact with Exocore. /// @param token The address of specific token that the user wants to claim from the vault. /// @param amount The amount of @param token that the user wants to claim from the vault. /// @param recipient The destination address that the assets would be transfered to. - function claim(address token, uint256 amount, address recipient) external; + function withdrawPrincipal(address token, uint256 amount, address recipient) external; /// @notice Submits reward to the reward module on behalf of the AVS /// @param token The address of the specific token that the user wants to submit as a reward. diff --git a/src/interfaces/ILSTRestakingController.sol b/src/interfaces/ILSTRestakingController.sol index 2aeee441..69b151d9 100644 --- a/src/interfaces/ILSTRestakingController.sol +++ b/src/interfaces/ILSTRestakingController.sol @@ -18,13 +18,13 @@ interface ILSTRestakingController is IBaseRestakingController { /// @param amount The amount of the token that the user wants to deposit. function deposit(address token, uint256 amount) external payable; - /// @notice Requests withdrawal of the principal amount from Exocore to the client chain. - /// @dev This function requests withdrawal approval from Exocore. If approved, the assets are - /// unlocked and can be claimed by the user. Otherwise, they remain locked. - /// @param token The address of the specific token that the user wants to withdraw from Exocore. + /// @notice Send request to Exocore to claim the LST principal. + /// @dev This function requests claim approval from Exocore. If approved, the assets are + /// unlocked and can be withdrawn by the user. Otherwise, they remain locked. + /// @param token The address of the specific token that the user wants to claim from Exocore. /// @param principalAmount The principal amount of assets the user deposited into Exocore for delegation and /// staking. - function withdrawPrincipalFromExocore(address token, uint256 principalAmount) external payable; + function claimPrincipalFromExocore(address token, uint256 principalAmount) external payable; /// @notice Deposits tokens and then delegates them to a specific node operator. /// @dev This function locks the specified amount of tokens into a vault, informs Exocore, and diff --git a/src/storage/BootstrapStorage.sol b/src/storage/BootstrapStorage.sol index d147603e..3ebb10d9 100644 --- a/src/storage/BootstrapStorage.sol +++ b/src/storage/BootstrapStorage.sol @@ -180,9 +180,7 @@ contract BootstrapStorage is GatewayStorage { /// @param token The address of the token being withdrawn, on this chain. /// @param withdrawer The address of the withdrawer, on this chain. /// @param amount The amount of the token available to claim. - event WithdrawPrincipalResult( - bool indexed success, address indexed token, address indexed withdrawer, uint256 amount - ); + event ClaimPrincipalResult(bool indexed success, address indexed token, address indexed withdrawer, uint256 amount); /// @notice Emitted when a delegation is made to an operator. /// @dev This event is triggered whenever a delegator delegates tokens to an operator. diff --git a/test/foundry/DepositWithdrawPrinciple.t.sol b/test/foundry/DepositWithdrawPrinciple.t.sol index 65d17aba..6eeee2da 100644 --- a/test/foundry/DepositWithdrawPrinciple.t.sol +++ b/test/foundry/DepositWithdrawPrinciple.t.sol @@ -168,9 +168,7 @@ contract DepositWithdrawPrincipalTest is ExocoreDeployer { emit MessageSent( Action.REQUEST_WITHDRAW_LST, withdrawRequestId, outboundNonces[clientChainId]++, withdrawRequestNativeFee ); - clientGateway.withdrawPrincipalFromExocore{value: withdrawRequestNativeFee}( - address(restakeToken), withdrawAmount - ); + clientGateway.claimPrincipalFromExocore{value: withdrawRequestNativeFee}(address(restakeToken), withdrawAmount); // second layerzero relayers should watch the request message packet and relay the message to destination // endpoint @@ -613,7 +611,7 @@ contract DepositWithdrawPrincipalTest is ExocoreDeployer { nativeFee = clientGateway.quote(requestPayload); vm.expectEmit(address(clientGateway)); emit MessageSent(Action.REQUEST_WITHDRAW_LST, requestId, outboundNonces[clientChainId]++, nativeFee); - clientGateway.withdrawPrincipalFromExocore{value: nativeFee}(address(restakeToken), withdrawAmount); + clientGateway.claimPrincipalFromExocore{value: nativeFee}(address(restakeToken), withdrawAmount); vm.stopPrank(); principalBalance -= withdrawAmount; @@ -653,7 +651,7 @@ contract DepositWithdrawPrincipalTest is ExocoreDeployer { vm.startPrank(addr); vm.expectEmit(address(restakeToken)); emit Transfer(address(vault), addr, withdrawAmount); - clientGateway.claim(address(restakeToken), withdrawAmount, addr); + clientGateway.withdrawPrincipal(address(restakeToken), withdrawAmount, addr); vm.stopPrank(); consumedTvl -= withdrawAmount; @@ -681,7 +679,7 @@ contract DepositWithdrawPrincipalTest is ExocoreDeployer { nativeFee = clientGateway.quote(requestPayload); vm.expectEmit(address(clientGateway)); emit MessageSent(Action.REQUEST_WITHDRAW_LST, requestId, outboundNonces[clientChainId]++, nativeFee); - clientGateway.withdrawPrincipalFromExocore{value: nativeFee}(address(restakeToken), withdrawAmount); + clientGateway.claimPrincipalFromExocore{value: nativeFee}(address(restakeToken), withdrawAmount); // obtain the response responsePayload = abi.encodePacked(Action.RESPOND, outboundNonces[clientChainId] - 1, true); @@ -719,11 +717,11 @@ contract DepositWithdrawPrincipalTest is ExocoreDeployer { assertTrue(vault.getConsumedTvl() == consumedTvl); assertTrue(vault.getTvlLimit() == newTvlLimit); - // claim now + // withdraw now vm.startPrank(addr); vm.expectEmit(address(restakeToken)); emit Transfer(address(vault), addr, withdrawAmount); - clientGateway.claim(address(restakeToken), withdrawAmount, addr); + clientGateway.withdrawPrincipal(address(restakeToken), withdrawAmount, addr); consumedTvl -= withdrawAmount; vm.stopPrank(); diff --git a/test/foundry/unit/Bootstrap.t.sol b/test/foundry/unit/Bootstrap.t.sol index fa2ee032..a29fc1ab 100644 --- a/test/foundry/unit/Bootstrap.t.sol +++ b/test/foundry/unit/Bootstrap.t.sol @@ -403,8 +403,8 @@ contract BootstrapTest is Test { // now attempt to withdraw, which should go through vm.startPrank(addr); - bootstrap.withdrawPrincipalFromExocore(address(myToken), withdrawAmount); - bootstrap.claim(address(myToken), withdrawAmount, addr); + bootstrap.claimPrincipalFromExocore(address(myToken), withdrawAmount); + bootstrap.withdrawPrincipal(address(myToken), withdrawAmount, addr); vm.stopPrank(); assertTrue(vault.getConsumedTvl() == balance - withdrawAmount); @@ -422,8 +422,8 @@ contract BootstrapTest is Test { // withdraw to get just below tvl limit withdrawAmount = vault.getConsumedTvl() - vault.getTvlLimit() + 1; vm.startPrank(addr); - bootstrap.withdrawPrincipalFromExocore(address(myToken), withdrawAmount); - bootstrap.claim(address(myToken), withdrawAmount, addr); + bootstrap.claimPrincipalFromExocore(address(myToken), withdrawAmount); + bootstrap.withdrawPrincipal(address(myToken), withdrawAmount, addr); vm.stopPrank(); assertTrue(vault.getConsumedTvl() == newTvlLimit - 1); @@ -938,7 +938,7 @@ contract BootstrapTest is Test { bootstrap.undelegateFrom("exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac", address(myToken), amounts[0]); } - function test11_WithdrawPrincipalFromExocore() public { + function test11_ClaimPrincipalFromExocore() public { // delegate and then undelegate test10_UndelegateFrom(); // now, withdraw @@ -949,7 +949,7 @@ contract BootstrapTest is Test { uint256 prevTokenDeposit = bootstrap.depositsByToken(address(myToken)); uint256 prevVaultWithdrawable = Vault(address(bootstrap.tokenToVault(address(myToken)))).withdrawableBalances(addrs[i]); - bootstrap.withdrawPrincipalFromExocore(address(myToken), amounts[i]); + bootstrap.claimPrincipalFromExocore(address(myToken), amounts[i]); uint256 postDeposit = bootstrap.totalDepositAmounts(addrs[i], address(myToken)); uint256 postWithdrawable = bootstrap.withdrawableAmounts(addrs[i], address(myToken)); uint256 postTokenDeposit = bootstrap.depositsByToken(address(myToken)); @@ -964,40 +964,40 @@ contract BootstrapTest is Test { } } - function test11_WithdrawPrincipalFromExocore_TokenNotWhitelisted() public { + function test11_ClaimPrincipalFromExocore_TokenNotWhitelisted() public { vm.startPrank(addrs[0]); vm.expectRevert("BootstrapStorage: token is not whitelisted"); - bootstrap.withdrawPrincipalFromExocore(address(0xa), amounts[0]); + bootstrap.claimPrincipalFromExocore(address(0xa), amounts[0]); vm.stopPrank(); } - function test11_WithdrawPrincipalFromExocore_ZeroAmount() public { + function test11_ClaimPrincipalFromExocore_ZeroAmount() public { vm.startPrank(addrs[0]); vm.expectRevert("BootstrapStorage: amount should be greater than zero"); - bootstrap.withdrawPrincipalFromExocore(address(myToken), 0); + bootstrap.claimPrincipalFromExocore(address(myToken), 0); vm.stopPrank(); } - function test11_WithdrawPrincipalFromExocore_NoDeposits() public { + function test11_ClaimPrincipalFromExocore_NoDeposits() public { vm.startPrank(addrs[0]); vm.expectRevert(Errors.BootstrapInsufficientDepositedBalance.selector); - bootstrap.withdrawPrincipalFromExocore(address(myToken), amounts[0]); + bootstrap.claimPrincipalFromExocore(address(myToken), amounts[0]); vm.stopPrank(); } - function test11_WithdrawPrincipalFromExocore_Excess() public { + function test11_ClaimPrincipalFromExocore_Excess() public { test10_UndelegateFrom(); vm.startPrank(addrs[0]); vm.expectRevert(Errors.BootstrapInsufficientDepositedBalance.selector); - bootstrap.withdrawPrincipalFromExocore(address(myToken), amounts[0] + 1); + bootstrap.claimPrincipalFromExocore(address(myToken), amounts[0] + 1); vm.stopPrank(); } - function test11_WithdrawPrincipalFromExocore_ExcessFree() public { + function test11_ClaimPrincipalFromExocore_ExcessFree() public { test09_DelegateTo(); vm.startPrank(addrs[0]); vm.expectRevert(Errors.BootstrapInsufficientWithdrawableBalance.selector); - bootstrap.withdrawPrincipalFromExocore(address(myToken), amounts[0]); + bootstrap.claimPrincipalFromExocore(address(myToken), amounts[0]); vm.stopPrank(); } @@ -1428,12 +1428,12 @@ contract BootstrapTest is Test { bootstrap.claimRewardFromExocore(address(0x0), 1); } - function test22_Claim() public { - test11_WithdrawPrincipalFromExocore(); + function test22_WithdrawPrincipal() public { + test11_ClaimPrincipalFromExocore(); for (uint256 i = 0; i < 6; i++) { vm.startPrank(addrs[i]); uint256 prevBalance = myToken.balanceOf(addrs[i]); - bootstrap.claim(address(myToken), amounts[i], addrs[i]); + bootstrap.withdrawPrincipal(address(myToken), amounts[i], addrs[i]); uint256 postBalance = myToken.balanceOf(addrs[i]); assertTrue(postBalance == prevBalance + amounts[i]); vm.stopPrank(); @@ -1443,20 +1443,20 @@ contract BootstrapTest is Test { function test22_Claim_TokenNotWhitelisted() public { vm.startPrank(addrs[0]); vm.expectRevert("BootstrapStorage: token is not whitelisted"); - bootstrap.claim(address(0xa), amounts[0], addrs[0]); + bootstrap.withdrawPrincipal(address(0xa), amounts[0], addrs[0]); } function test22_Claim_ZeroAmount() public { vm.startPrank(addrs[0]); vm.expectRevert("BootstrapStorage: amount should be greater than zero"); - bootstrap.claim(address(myToken), 0, addrs[0]); + bootstrap.withdrawPrincipal(address(myToken), 0, addrs[0]); } - function test22_Claim_Excess() public { - test11_WithdrawPrincipalFromExocore(); + function test22_WithdrawPrincipal_Excess() public { + test11_ClaimPrincipalFromExocore(); vm.startPrank(addrs[0]); vm.expectRevert(Errors.VaultWithdrawalAmountExceeds.selector); - bootstrap.claim(address(myToken), amounts[0] + 5, addrs[0]); + bootstrap.withdrawPrincipal(address(myToken), amounts[0] + 5, addrs[0]); } function test23_RevertWhen_Deposit_WithEther() public { @@ -1467,11 +1467,11 @@ contract BootstrapTest is Test { vm.stopPrank(); } - function test23_RevertWhen_WithdrawPrincipalFromExocore_WithEther() public { + function test23_RevertWhen_ClaimPrincipalFromExocore_WithEther() public { vm.startPrank(addrs[0]); vm.deal(addrs[0], 1 ether); vm.expectRevert(Errors.NonZeroValue.selector); - bootstrap.withdrawPrincipalFromExocore{value: 0.1 ether}(address(myToken), amounts[0]); + bootstrap.claimPrincipalFromExocore{value: 0.1 ether}(address(myToken), amounts[0]); vm.stopPrank(); } diff --git a/test/foundry/unit/ClientChainGateway.t.sol b/test/foundry/unit/ClientChainGateway.t.sol index 181a7a91..76835a85 100644 --- a/test/foundry/unit/ClientChainGateway.t.sol +++ b/test/foundry/unit/ClientChainGateway.t.sol @@ -224,7 +224,7 @@ contract Pausable is SetUp { clientGateway.pause(); vm.expectRevert("Pausable: paused"); - clientGateway.claim(address(restakeToken), uint256(1), deployer.addr); + clientGateway.withdrawPrincipal(address(restakeToken), uint256(1), deployer.addr); vm.expectRevert("Pausable: paused"); clientGateway.delegateTo(operatorAddress, address(restakeToken), uint256(1)); @@ -233,7 +233,7 @@ contract Pausable is SetUp { clientGateway.deposit(address(restakeToken), uint256(1)); vm.expectRevert("Pausable: paused"); - clientGateway.withdrawPrincipalFromExocore(address(restakeToken), uint256(1)); + clientGateway.claimPrincipalFromExocore(address(restakeToken), uint256(1)); vm.expectRevert("Pausable: paused"); clientGateway.undelegateFrom(operatorAddress, address(restakeToken), uint256(1)); @@ -403,7 +403,7 @@ contract WithdrawalPrincipalFromExocore is SetUp { // Try to withdraw VIRTUAL_STAKED_ETH vm.prank(user); vm.expectRevert(Errors.VaultDoesNotExist.selector); - clientGateway.withdrawPrincipalFromExocore(VIRTUAL_STAKED_ETH_ADDRESS, WITHDRAWAL_AMOUNT); + clientGateway.claimPrincipalFromExocore(VIRTUAL_STAKED_ETH_ADDRESS, WITHDRAWAL_AMOUNT); } function test_revert_withdrawNonWhitelistedToken() public { @@ -411,13 +411,13 @@ contract WithdrawalPrincipalFromExocore is SetUp { vm.prank(players[0].addr); vm.expectRevert("BootstrapStorage: token is not whitelisted"); - clientGateway.withdrawPrincipalFromExocore(nonWhitelistedToken, WITHDRAWAL_AMOUNT); + clientGateway.claimPrincipalFromExocore(nonWhitelistedToken, WITHDRAWAL_AMOUNT); } function test_revert_withdrawZeroAmount() public { vm.prank(user); vm.expectRevert("BootstrapStorage: amount should be greater than zero"); - clientGateway.withdrawPrincipalFromExocore(address(restakeToken), 0); + clientGateway.claimPrincipalFromExocore(address(restakeToken), 0); } }