Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/native restaking withdraw #10

Merged
merged 100 commits into from
Jul 17, 2024
Merged
Show file tree
Hide file tree
Changes from 82 commits
Commits
Show all changes
100 commits
Select commit Hold shift + click to select a range
9d71017
initialize ExocoreCapsule
adu-web3 Feb 20, 2024
e440d18
add ValidatorContainer library
adu-web3 Feb 22, 2024
d4b6d5b
implement capsule deposit
adu-web3 Feb 24, 2024
b904a61
initiate updateStakingBalance
adu-web3 Mar 20, 2024
12eb183
add index=>pubkey mapping
adu-web3 Mar 22, 2024
c73d017
add withdrawal container and integrate exocapsule into clientchaingat…
adu-web3 Apr 12, 2024
e11feb4
add isValidWithdrawalContainerRoot implementation to verify withdrawa…
adu-web3 Apr 15, 2024
0d1fa3d
add NativeRestakingController contract
adu-web3 Apr 16, 2024
2e11c2b
add createExoCapsule function
adu-web3 Apr 17, 2024
5ff831c
add depositBeaconChainValidator implementation
adu-web3 Apr 17, 2024
92f7dd6
abstract CommonRestakingController
adu-web3 Apr 18, 2024
c201ee1
add whenNotPaused modifier to functions
adu-web3 Apr 18, 2024
c6b241b
rename CommonRestakingController as BaseRestakingController
adu-web3 Apr 18, 2024
973a8e8
remove unused imports and fix errors
adu-web3 Apr 18, 2024
a5e8b3f
fix operator address length
adu-web3 Apr 18, 2024
44f3e63
optimize some code with DRY princple
bwhour Apr 18, 2024
b18324e
update log and reuse some code
bwhour Apr 18, 2024
68b7505
fix test
adu-web3 Apr 19, 2024
bbb4527
move stake interface to NativeRestakingController
adu-web3 Apr 19, 2024
e2d1b34
update principleBalance upon receiving deposit response
adu-web3 Apr 19, 2024
dd99dd7
draft plantuml diagram
adu-web3 Apr 21, 2024
9d87ca4
fix depositBeaconChainValidator diagram
adu-web3 Apr 22, 2024
aeb5e69
fix container merklizatiion function
adu-web3 Apr 22, 2024
8fc724f
forge install: eigenlayer-beacon-oracle
adu-web3 Apr 23, 2024
c6e459c
integrate EigenLayerBeaconOracle into ExoCapsule
adu-web3 Apr 23, 2024
8404a42
add uint test for ExoCapsule.verifyDepositProof
adu-web3 Apr 25, 2024
30103b8
Optimize reuse code
bwhour Apr 26, 2024
db30157
add other uint tests for ExoCapsule.verifyDepositProof
adu-web3 Apr 28, 2024
e1ca5bd
adapt to use beacon proxies and create2 for vaults and capsules creation
adu-web3 Apr 30, 2024
52b894d
add nativedepositwithdraw integration test
adu-web3 May 6, 2024
4c8329c
fix #30(remove TSSReceiver), deploy vaults with beacon proxy, fix inc…
adu-web3 May 9, 2024
2ef02eb
reuse _getVault and rename exocoreAddressIsValid
adu-web3 May 10, 2024
bd0aea8
reuse modifiers
adu-web3 May 11, 2024
c28f379
fix some warnings and reuse some code
bwhour May 13, 2024
eba19b6
fix: add prettier for audit, implement non beacon chain ETH withdraw …
May 13, 2024
9e25adc
fix: move variable to ExoCapsuleStorage
May 14, 2024
f89cb94
feat: consolidiate partial and full withdraw workflow in a single fun…
May 14, 2024
555446c
fix ExocoreGateway.requestUndelegateFrom and add undeletion integrati…
adu-web3 May 16, 2024
0fa6f75
optmize the _processRequest to make it simple and gas saving
bwhour May 17, 2024
aae7dad
store BEACON_PROXY_BYTECODE in a separate contract to fix code size t…
adu-web3 May 17, 2024
8c64426
remove unused file and comment on chainid
adu-web3 May 20, 2024
741ca19
fix name typo prerequisite
adu-web3 May 20, 2024
8c3b1e0
deploy vault when adding whitelist token
adu-web3 May 20, 2024
eb7b9a0
remove license infos
adu-web3 May 20, 2024
fbcfa86
remove unused codes in Merkle.sol
adu-web3 May 20, 2024
2a80048
clearBootstrapData => _clearBootstrapData
adu-web3 May 20, 2024
fa80b66
fix ExoCapsule according Max's review
adu-web3 May 20, 2024
8644d22
optimize _isStaleProof and _hasFullyWithdrawn
adu-web3 May 20, 2024
7a9f17e
fix bootstrap unit test
adu-web3 May 20, 2024
d46ca9f
add comments for request lenght
adu-web3 May 20, 2024
f54dde4
Merge branch 'native-deposit-withdraw' into fix/native-restaking-with…
May 21, 2024
aa2e346
Merge branch 'main' into fix/native-restaking-withdraw-in-progress
May 21, 2024
140b7a1
fix: merge conflict
May 21, 2024
bc80017
fix: update principle and withdraw balance after request
May 27, 2024
d8dc3b3
fix: update withdraw modifiers
May 27, 2024
d4d1923
Merge branch 'main' of github.com:ExocoreNetwork/exocore-contracts in…
May 27, 2024
0851432
fix: isValidWCRootAgainstExecutionPayloadRoot check logic updated wit…
May 28, 2024
1e18542
Merge branch 'main' of github.com:ExocoreNetwork/exocore-contracts in…
May 28, 2024
c095a37
feat: update withdrawal test setup contract
May 28, 2024
78d576b
feat: refactor validator container set using internal setter functions
May 28, 2024
7459af1
fix: withdrwal proof generation test
May 28, 2024
c47efd3
fix: historial summaries verification pass with beacon state root
May 29, 2024
57fca49
feat: update has restaking logic
Jun 11, 2024
6a8e9ec
Merge branch 'main' into fix/native-restaking-withdraw-in-progress
Jun 11, 2024
33076b3
fix: remove prettier config and stick with forge fmt
Jun 11, 2024
15e5ab5
fix: forge fmt without prettier conflict
Jun 11, 2024
b3b5fb1
feat: add vscode extension settings
Jun 11, 2024
ee6f109
feat: full withdraw test improved
Jun 14, 2024
ddc9bfa
feat: partial withdraw tests done
Jun 14, 2024
2519101
fix: remove unused vars
Jun 14, 2024
c1b3205
fix: remove complex callback lint
Jun 14, 2024
74aae9a
fix: temporary increase for line length
Jun 14, 2024
8fb4ecf
fix: remove console log
Jun 14, 2024
48fb245
fix: failing CI tests and get rid of hasRestake check
Jun 21, 2024
6687eed
fix: merge conflict
Jun 21, 2024
fbeb696
fix: process request args
Jun 21, 2024
b30f4eb
chore(fmt): run `forge fmt`
MaxMustermann2 Jun 21, 2024
2e6957d
fix: use event emit rather than revert when withdraw from exocore is …
Jun 25, 2024
3c4233c
fix: remove hasRestaked flag and choose plan A
Jun 25, 2024
71b3111
fix: use beaconBlockRoot from oracle
Jun 25, 2024
93aaf6d
fix: proof validation issue with beacon block root
Jun 25, 2024
715a77e
fix: remove console log
Jun 25, 2024
3111048
fix: remove unused struct
Jun 25, 2024
8dd38cc
feat: integration test for native withdrwal
Jun 26, 2024
a7c7893
feat: deposit with 32 ether cap
Jun 26, 2024
145aa3a
fix: typo for principal
Jun 27, 2024
3a9b5fd
feat: update withdrawal verification logic
Jul 10, 2024
080f796
feat: withdraw index instead of withdraw timestamp
Jul 12, 2024
5b6b11e
feat: reentrancy guard for sending ETH
Jul 15, 2024
0d4c19a
fix: typo
Jul 15, 2024
4c3e4c2
Merge branch 'main' into fix/native-restaking-withdraw-in-progress
Jul 15, 2024
1128eac
fix: forge formatter
Jul 15, 2024
8e27ced
fix: withdraw epoch calculation
Jul 15, 2024
5b24682
fix: lib version
Jul 15, 2024
260f6de
fix: update reentrancy guard import
Jul 15, 2024
8b3634c
fix: add more constants for beaconchain proofs
Jul 15, 2024
cc41593
feat: beacon chain proof verification updated
Jul 16, 2024
806c749
fix: integration test with 32 ether deposit cap
Jul 16, 2024
9426325
fix: remove unused variable for slither check
Jul 16, 2024
be519f2
fix: ignore slither for withdraw eth to recipient address
Jul 16, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"[solidity]": {
"editor.defaultFormatter": "JuanBlanco.solidity"
},
"solidity.formatter": "forge"
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@
"death": "^1.1.0",
"debug": "^4.3.4",
"decamelize": "^4.0.0",
"decimal.js":"10.4.3",
"decimal.js": "10.4.3",
"deep-eql": "^4.1.3",
"deep-extend": "^0.6.0",
"deep-is": "^0.1.4",
Expand Down
7 changes: 4 additions & 3 deletions src/.solhint.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"extends": "solhint:recommended",
"rules": {
"max-line-length": ["error", 121],
"max-line-length": ["error", 128],
"compiler-version": ["error", "^0.8.0"],
"func-visibility": ["warn", {"ignoreConstructors": true}],
"func-visibility": ["warn", { "ignoreConstructors": true }],
"no-inline-assembly": "off",
"no-empty-blocks": "off",
"no-unused-vars": "error",
Expand All @@ -13,6 +13,7 @@
"max-states-count": "off",
"reason-string": "off",
"gas-custom-errors": "off",
"state-visibility": "error"
"state-visibility": "error",
"no-complex-fallback": "off"
}
}
25 changes: 19 additions & 6 deletions src/core/ClientGatewayLzReceiver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ abstract contract ClientGatewayLzReceiver is PausableUpgradeable, OAppReceiverUp
error UnexpectedResponse(uint64 nonce);
error DepositShouldNotFailOnExocore(address token, address depositor);

// Events
event WithdrawFailedOnExocore(address indexed token, address indexed withdrawer);

modifier onlyCalledFromThis() {
require(
msg.sender == address(this),
Expand Down Expand Up @@ -115,14 +118,24 @@ abstract contract ClientGatewayLzReceiver is PausableUpgradeable, OAppReceiverUp

bool success = (uint8(bytes1(responsePayload[0])) == 1);
uint256 lastlyUpdatedPrincipalBalance = uint256(bytes32(responsePayload[1:33]));
if (success) {
IVault vault = _getVault(token);

vault.updatePrincipalBalance(withdrawer, lastlyUpdatedPrincipalBalance);
vault.updateWithdrawableBalance(withdrawer, unlockPrincipalAmount, 0);
}
if (!success) {
emit WithdrawFailedOnExocore(token, withdrawer);
} else {
if (token == VIRTUAL_STAKED_ETH_ADDRESS) {
IExoCapsule capsule = _getCapsule(withdrawer);

capsule.updatePrincipalBalance(lastlyUpdatedPrincipalBalance);
capsule.updateWithdrawableBalance(unlockPrincipalAmount);
} else {
IVault vault = _getVault(token);

emit WithdrawPrincipalResult(success, token, withdrawer, unlockPrincipalAmount);
vault.updatePrincipalBalance(withdrawer, lastlyUpdatedPrincipalBalance);
vault.updateWithdrawableBalance(withdrawer, unlockPrincipalAmount, 0);
}

emit WithdrawPrincipalResult(success, token, withdrawer, unlockPrincipalAmount);
}
}

function afterReceiveWithdrawRewardResponse(bytes memory requestPayload, bytes calldata responsePayload)
Expand Down
128 changes: 83 additions & 45 deletions src/core/ExoCapsule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,27 @@ contract ExoCapsule is Initializable, ExoCapsuleStorage, IExoCapsule {
event PrincipalBalanceUpdated(address, uint256);
event WithdrawableBalanceUpdated(address, uint256);
event WithdrawalSuccess(address, address, uint256);
/// @notice Emitted when a partial withdrawal claim is successfully redeemed
event PartialWithdrawalRedeemed(
bytes32 pubkey, uint256 withdrawalTimestamp, address indexed recipient, uint64 partialWithdrawalAmountGwei
);
/// @notice Emitted when an ETH validator is prove to have fully withdrawn from the beacon chain
event FullWithdrawalRedeemed(
bytes32 pubkey, uint256 withdrawalTimestamp, address indexed recipient, uint64 withdrawalAmountGwei
);
/// @notice Emitted when capsuleOwner enables restaking
event RestakingActivated(address indexed capsuleOwner);
/// @notice Emitted when ETH is received via the `receive` fallback
event NonBeaconChainETHReceived(uint256 amountReceived);
/// @notice Emitted when ETH that was previously received via the `receive` fallback is withdrawn
event NonBeaconChainETHWithdrawn(address indexed recipient, uint256 amountWithdrawn);

error InvalidValidatorContainer(bytes32 pubkey);
error InvalidWithdrawalContainer(uint64 validatorIndex);
error InvalidHistoricalSummaries(uint64 validatorIndex);
error DoubleDepositedValidator(bytes32 pubkey);
error StaleValidatorContainer(bytes32 pubkey, uint256 timestamp);
error WithdrawalAlreadyProven(bytes32 pubkey, uint256 timestamp);
error UnregisteredValidator(bytes32 pubkey);
error UnregisteredOrWithdrawnValidatorContainer(bytes32 pubkey);
error FullyWithdrawnValidatorContainer(bytes32 pubkey);
Expand All @@ -47,6 +63,11 @@ contract ExoCapsule is Initializable, ExoCapsuleStorage, IExoCapsule {
_disableInitializers();
}

receive() external payable {
nonBeaconChainETHBalance += msg.value;
emit NonBeaconChainETHReceived(msg.value);
}

function initialize(address gateway_, address capsuleOwner_, address beaconOracle_) external initializer {
require(gateway_ != address(0), "ExoCapsule: gateway address can not be empty");
require(capsuleOwner_ != address(0), "ExoCapsule: capsule owner address can not be empty");
Expand All @@ -55,6 +76,8 @@ contract ExoCapsule is Initializable, ExoCapsuleStorage, IExoCapsule {
gateway = INativeRestakingController(gateway_);
beaconOracle = IBeaconChainOracle(beaconOracle_);
capsuleOwner = capsuleOwner_;

emit RestakingActivated(capsuleOwner);
wewecalibrate marked this conversation as resolved.
Show resolved Hide resolved
}

function verifyDepositProof(bytes32[] calldata validatorContainer, ValidatorContainerProof calldata proof)
Expand Down Expand Up @@ -95,61 +118,54 @@ contract ExoCapsule is Initializable, ExoCapsuleStorage, IExoCapsule {
_capsuleValidatorsByIndex[proof.validatorIndex] = validatorPubkey;
}

function verifyPartialWithdrawalProof(
bytes32[] calldata validatorContainer,
ValidatorContainerProof calldata validatorProof,
bytes32[] calldata withdrawalContainer,
WithdrawalContainerProof calldata withdrawalProof
) external view onlyGateway {
bytes32 validatorPubkey = validatorContainer.getPubkey();
uint64 withdrawableEpoch = validatorContainer.getWithdrawableEpoch();

bool partialWithdrawal = _timestampToEpoch(validatorProof.beaconBlockTimestamp) < withdrawableEpoch;

if (!validatorContainer.verifyValidatorContainerBasic()) {
revert InvalidValidatorContainer(validatorPubkey);
}

if (!partialWithdrawal) {
revert NotPartialWithdrawal(validatorPubkey);
}

if (validatorProof.beaconBlockTimestamp != withdrawalProof.beaconBlockTimestamp) {
revert UnmatchedValidatorAndWithdrawal(validatorPubkey);
}

_verifyValidatorContainer(validatorContainer, validatorProof);
_verifyWithdrawalContainer(withdrawalContainer, withdrawalProof);
}

function verifyFullWithdrawalProof(
function verifyWithdrawalProof(
bytes32[] calldata validatorContainer,
ValidatorContainerProof calldata validatorProof,
bytes32[] calldata withdrawalContainer,
WithdrawalContainerProof calldata withdrawalProof
) external onlyGateway {
) external onlyGateway returns (bool partialWithdrawal, uint256 withdrawalAmount) {
wewecalibrate marked this conversation as resolved.
Show resolved Hide resolved
bytes32 validatorPubkey = validatorContainer.getPubkey();
uint64 withdrawableEpoch = validatorContainer.getWithdrawableEpoch();

Validator storage validator = _capsuleValidators[validatorPubkey];
bool fullyWithdrawal = _timestampToEpoch(validatorProof.beaconBlockTimestamp) > withdrawableEpoch;
partialWithdrawal = _timestampToEpoch(validatorProof.beaconBlockTimestamp) < withdrawableEpoch;
wewecalibrate marked this conversation as resolved.
Show resolved Hide resolved

if (!validatorContainer.verifyValidatorContainerBasic()) {
revert InvalidValidatorContainer(validatorPubkey);
}

if (!fullyWithdrawal) {
revert NotPartialWithdrawal(validatorPubkey);
if (validator.status == VALIDATOR_STATUS.UNREGISTERED) {
revert UnregisteredOrWithdrawnValidatorContainer(validatorPubkey);
}

if (validatorProof.beaconBlockTimestamp != withdrawalProof.beaconBlockTimestamp) {
revert UnmatchedValidatorAndWithdrawal(validatorPubkey);
if (provenWithdrawal[validatorPubkey][withdrawalProof.beaconBlockTimestamp]) {
revert WithdrawalAlreadyProven(validatorPubkey, withdrawalProof.beaconBlockTimestamp);
}

provenWithdrawal[validatorPubkey][withdrawalProof.beaconBlockTimestamp] = true;

_verifyValidatorContainer(validatorContainer, validatorProof);
_verifyWithdrawalContainer(withdrawalContainer, withdrawalProof);
wewecalibrate marked this conversation as resolved.
Show resolved Hide resolved

validator.status = VALIDATOR_STATUS.WITHDRAWN;
uint64 withdrawalAmountGwei = withdrawalContainer.getAmount();

if (partialWithdrawal) {
// Immediately send ETH without sending request to Exocore side
wewecalibrate marked this conversation as resolved.
Show resolved Hide resolved
emit PartialWithdrawalRedeemed(
validatorPubkey, withdrawalProof.beaconBlockTimestamp, capsuleOwner, withdrawalAmountGwei
);
_sendETH(capsuleOwner, withdrawalAmountGwei * GWEI_TO_WEI);
} else {
// Full withdrawal
validator.status = VALIDATOR_STATUS.WITHDRAWN;
validator.restakedBalanceGwei = 0;
// If over MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR = 32 * 1e9, then send remaining amount immediately
emit FullWithdrawalRedeemed(
validatorPubkey, withdrawalProof.beaconBlockTimestamp, capsuleOwner, withdrawalAmountGwei
);
if (withdrawalAmountGwei > MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR) {
withdrawalAmount = (withdrawalAmountGwei - MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR) * GWEI_TO_WEI;
_sendETH(capsuleOwner, withdrawalAmount);
}
}
wewecalibrate marked this conversation as resolved.
Show resolved Hide resolved
}

function withdraw(uint256 amount, address payable recipient) external onlyGateway {
Expand All @@ -158,16 +174,24 @@ contract ExoCapsule is Initializable, ExoCapsuleStorage, IExoCapsule {
);

withdrawableBalance -= amount;
(bool sent,) = recipient.call{value: amount}("");
if (!sent) {
revert WithdrawalFailure(capsuleOwner, recipient, amount);
}
_sendETH(recipient, amount);

emit WithdrawalSuccess(capsuleOwner, recipient, amount);
}

/// @notice Called by the capsule owner to withdraw the nonBeaconChainETHBalance
function withdrawNonBeaconChainETHBalance(address recipient, uint256 amountToWithdraw) external onlyGateway {
require(
amountToWithdraw <= nonBeaconChainETHBalance,
"ExoCapsule.withdrawNonBeaconChainETHBalance: amountToWithdraw is greater than nonBeaconChainETHBalance"
);
nonBeaconChainETHBalance -= amountToWithdraw;
_sendETH(recipient, amountToWithdraw);
emit NonBeaconChainETHWithdrawn(recipient, amountToWithdraw);
}

function updatePrincipalBalance(uint256 lastlyUpdatedPrincipalBalance) external onlyGateway {
principalBalance = lastlyUpdatedPrincipalBalance;
principleBalance = lastlyUpdatedPrincipalBalance;
wewecalibrate marked this conversation as resolved.
Show resolved Hide resolved

emit PrincipalBalanceUpdated(capsuleOwner, lastlyUpdatedPrincipalBalance);
}
Expand Down Expand Up @@ -215,6 +239,13 @@ contract ExoCapsule is Initializable, ExoCapsuleStorage, IExoCapsule {
return validator;
}

function _sendETH(address recipient, uint256 amountWei) internal {
wewecalibrate marked this conversation as resolved.
Show resolved Hide resolved
(bool sent,) = recipient.call{value: amountWei}("");
wewecalibrate marked this conversation as resolved.
Show resolved Hide resolved
if (!sent) {
revert WithdrawalFailure(capsuleOwner, recipient, amountWei);
}
}

function _verifyValidatorContainer(bytes32[] calldata validatorContainer, ValidatorContainerProof calldata proof)
internal
view
Expand Down Expand Up @@ -244,11 +275,19 @@ contract ExoCapsule is Initializable, ExoCapsuleStorage, IExoCapsule {
proof.withdrawalIndex,
beaconBlockRoot,
proof.executionPayloadRoot,
proof.executionPayloadRootProof
proof.executionPayloadRootProof,
proof.beaconBlockTimestamp
);
if (!valid) {
revert InvalidWithdrawalContainer(withdrawalContainer.getValidatorIndex());
}
// Verify historical summaries
bool validHistoricalSummaries = proof.stateRoot.isValidHistoricalSummaryRoot(
wewecalibrate marked this conversation as resolved.
Show resolved Hide resolved
proof.historicalSummaryBlockRootProof, proof.historicalSummaryIndex, beaconBlockRoot, proof.blockRootIndex
);
if (!validHistoricalSummaries) {
revert InvalidHistoricalSummaries(withdrawalContainer.getValidatorIndex());
}
}

function _isActivatedAtEpoch(bytes32[] calldata validatorContainer, uint256 atTimestamp)
Expand All @@ -258,9 +297,8 @@ contract ExoCapsule is Initializable, ExoCapsuleStorage, IExoCapsule {
{
uint64 atEpoch = _timestampToEpoch(atTimestamp);
uint64 activationEpoch = validatorContainer.getActivationEpoch();
uint64 exitEpoch = validatorContainer.getExitEpoch();

return (atEpoch >= activationEpoch && atEpoch < exitEpoch);
wewecalibrate marked this conversation as resolved.
Show resolved Hide resolved
return atEpoch >= activationEpoch;
}

function _isStaleProof(Validator storage validator, uint256 proofTimestamp) internal view returns (bool) {
Expand Down
27 changes: 16 additions & 11 deletions src/core/NativeRestakingController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {INativeRestakingController} from "../interfaces/INativeRestakingControll

import {ValidatorContainer} from "../libraries/ValidatorContainer.sol";
import {BaseRestakingController} from "./BaseRestakingController.sol";
import {ExoCapsule} from "./ExoCapsule.sol";

import {PausableUpgradeable} from "@openzeppelin-upgradeable/contracts/utils/PausableUpgradeable.sol";
import {Create2} from "@openzeppelin/contracts/utils/Create2.sol";
Expand Down Expand Up @@ -39,7 +38,7 @@ abstract contract NativeRestakingController is
address(ownerToCapsule[msg.sender]) == address(0),
"NativeRestakingController: message sender has already created the capsule"
);
ExoCapsule capsule = ExoCapsule(
IExoCapsule capsule = IExoCapsule(
Create2.deploy(
0,
bytes32(uint256(uint160(msg.sender))),
Expand Down Expand Up @@ -70,18 +69,24 @@ abstract contract NativeRestakingController is
_processRequest(Action.REQUEST_DEPOSIT, actionArgs, encodedRequest);
}

function processBeaconChainPartialWithdrawal(
function processBeaconChainWithdrawal(
bytes32[] calldata validatorContainer,
IExoCapsule.ValidatorContainerProof calldata validatorProof,
bytes32[] calldata withdrawalContainer,
IExoCapsule.WithdrawalContainerProof calldata withdrawalProof
) external payable whenNotPaused {}

function processBeaconChainFullWithdrawal(
bytes32[] calldata validatorContainer,
IExoCapsule.ValidatorContainerProof calldata validatorProof,
bytes32[] calldata withdrawalContainer,
IExoCapsule.WithdrawalContainerProof calldata withdrawalProof
) external payable whenNotPaused {}
) external payable whenNotPaused {
IExoCapsule capsule = _getCapsule(msg.sender);
(bool partialWithdrawal, uint256 withdrawalAmount) =
capsule.verifyWithdrawalProof(validatorContainer, validatorProof, withdrawalContainer, withdrawalProof);
if (!partialWithdrawal) {
// request full withdraw
bytes memory actionArgs = abi.encodePacked(
bytes32(bytes20(VIRTUAL_STAKED_ETH_ADDRESS)), bytes32(bytes20(msg.sender)), withdrawalAmount
);
bytes memory encodedRequest = abi.encode(VIRTUAL_STAKED_ETH_ADDRESS, msg.sender, withdrawalAmount);

_processRequest(Action.REQUEST_WITHDRAW_PRINCIPAL_FROM_EXOCORE, actionArgs, encodedRequest);
}
}

}
29 changes: 20 additions & 9 deletions src/interfaces/IExoCapsule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,39 @@ interface IExoCapsule {

struct WithdrawalContainerProof {
wewecalibrate marked this conversation as resolved.
Show resolved Hide resolved
uint256 beaconBlockTimestamp;
bytes32 stateRoot;
bytes32 executionPayloadRoot;
bytes32[] executionPayloadRootProof;
bytes32[] withdrawalContainerRootProof;
bytes32[] historicalSummaryBlockRootProof;
uint256 historicalSummaryIndex;
uint256 blockRootIndex;
uint256 withdrawalIndex;
}

struct HistoricalBlockRootProof {
uint256 beaconBlockTimestamp;
bytes32 stateRoot;
bytes32 executionPayloadRoot;
bytes32[] executionPayloadRootProof;
bytes32[] withdrawalContainerRootProof;
bytes32[] historicalSummaryBlockRootProof;
uint256 historicalSummaryIndex;
uint256 blockRootIndex;
uint256 withdrawalIndex;
}

function initialize(address gateway, address capsuleOwner, address beaconOracle) external;

function verifyDepositProof(bytes32[] calldata validatorContainer, ValidatorContainerProof calldata proof)
external;

function verifyPartialWithdrawalProof(
bytes32[] calldata validatorContainer,
ValidatorContainerProof calldata validatorProof,
bytes32[] calldata withdrawalContainer,
WithdrawalContainerProof calldata withdrawalProof
) external;

function verifyFullWithdrawalProof(
function verifyWithdrawalProof(
bytes32[] calldata validatorContainer,
ValidatorContainerProof calldata validatorProof,
bytes32[] calldata withdrawalContainer,
WithdrawalContainerProof calldata withdrawalProof
) external;
) external returns (bool partialWithdrawal, uint256 withdrawalAmount);

function withdraw(uint256 amount, address payable recipient) external;

Expand Down
Loading
Loading