Skip to content

Commit

Permalink
feat: enable Ethereum native restaking for Bootstrap (#121)
Browse files Browse the repository at this point in the history
* feat: enable ethereum native restaking for Bootstrap

* fmt: forge fmt

* fix: lint and format

* tests: add unit tests for Bootstrap

* test: add integration test

* fix: resolve comments

* fix: compare storage

* fix: ignore slither detection
  • Loading branch information
adu-web3 authored Nov 4, 2024
1 parent 54cb293 commit 46f9927
Show file tree
Hide file tree
Showing 20 changed files with 1,069 additions and 254 deletions.
4 changes: 2 additions & 2 deletions docs/native_deposit_workflow.wsd
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ ETHPOS -> NativeStakingController: 1.3:DepositSuccess
deactivate ETHPOS
deactivate NativeStakingController

User -> NativeStakingController: 2.1:depositBeaconChainValidator(validatorContainer, proof)
User -> NativeStakingController: 2.1:verifyAndDepositNativeStake(validatorContainer, proof)
activate NativeStakingController
NativeStakingController -> ExoCapsule: 2.2:verifyDepositProof(validatorContainer, proof)
activate ExoCapsule
Expand Down Expand Up @@ -52,7 +52,7 @@ deactivate ExocoreL0Endpoint


@startuml
title NativeRestakingController: depositBeaconChainValidator() function
title NativeRestakingController: verifyAndDepositNativeStake() function

start

Expand Down
24 changes: 15 additions & 9 deletions script/12_RedeployClientChainGateway.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import {UpgradeableBeacon} from "@openzeppelin/contracts/proxy/beacon/Upgradeabl
import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";

import {Bootstrap} from "../src/core/Bootstrap.sol";

import {ClientChainGateway} from "../src/core/ClientChainGateway.sol";
import {BootstrapStorage} from "../src/storage/BootstrapStorage.sol";

import "../src/core/ExoCapsule.sol";

Expand Down Expand Up @@ -56,15 +58,19 @@ contract RedeployClientChainGateway is BaseScript {
vm.selectFork(clientChain);
vm.startBroadcast(exocoreValidatorSet.privateKey);

ClientChainGateway clientGatewayLogic = new ClientChainGateway(
address(clientChainLzEndpoint),
exocoreChainId,
address(beaconOracle),
address(vaultBeacon),
address(rewardVaultBeacon),
address(capsuleBeacon),
address(beaconProxyBytecode)
);
// Create ImmutableConfig struct
BootstrapStorage.ImmutableConfig memory config = BootstrapStorage.ImmutableConfig({
exocoreChainId: exocoreChainId,
beaconOracleAddress: address(beaconOracle),
vaultBeacon: address(vaultBeacon),
exoCapsuleBeacon: address(capsuleBeacon),
beaconProxyBytecode: address(beaconProxyBytecode)
});

// Update ClientChainGateway constructor call
ClientChainGateway clientGatewayLogic =
new ClientChainGateway(address(clientChainLzEndpoint), config, address(rewardVaultBeacon));

// then the client chain initialization
address[] memory emptyList;
bytes memory initialization =
Expand Down
6 changes: 1 addition & 5 deletions script/13_DepositValidator.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,7 @@ contract DepositScript is BaseScript {
uint256(_getEffectiveBalance(validatorContainer)) * GWEI_TO_WEI
);
uint256 nativeFee = clientGateway.quote(msg_);
try clientGateway.depositBeaconChainValidator{value: nativeFee}(validatorContainer, validatorProof) {
console.log("finish");
} catch {
console.log("fire anyway");
}
clientGateway.verifyAndDepositNativeStake{value: nativeFee}(validatorContainer, validatorProof);
vm.stopBroadcast();
}

Expand Down
28 changes: 25 additions & 3 deletions script/14_CorrectBootstrapErrors.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {ILayerZeroEndpointV2} from "@layerzero-v2/protocol/contracts/interfaces/
import {ERC20PresetFixedSupply} from "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol";
import "forge-std/Script.sol";

import {BootstrapStorage} from "../src/storage/BootstrapStorage.sol";
import "@beacon-oracle/contracts/src/EigenLayerBeaconOracle.sol";

// This script uses the address in `deployedBootstrapOnly` and redeploys on top of it. For that to work, the
Expand Down Expand Up @@ -56,16 +57,28 @@ contract CorrectBootstrapErrors is BaseScript {
require(wstETH != address(0), "wstETH not found");

string memory deployed = vm.readFile("script/deployedBootstrapOnly.json");

proxyAddress = stdJson.readAddress(deployed, ".clientChain.bootstrap");
require(address(proxyAddress) != address(0), "bootstrap address should not be empty");

proxyAdmin = stdJson.readAddress(deployed, ".clientChain.proxyAdmin");
require(address(proxyAdmin) != address(0), "proxy admin address should not be empty");

vaultImplementation = Vault(stdJson.readAddress(deployed, ".clientChain.vaultImplementation"));
require(address(vaultImplementation) != address(0), "vault implementation should not be empty");

vaultBeacon = UpgradeableBeacon(stdJson.readAddress(deployed, ".clientChain.vaultBeacon"));
require(address(vaultBeacon) != address(0), "vault beacon should not be empty");

clientGatewayLogic = stdJson.readAddress(deployed, ".clientChain.clientGatewayLogic");
require(clientGatewayLogic != address(0), "client gateway should not be empty");

beaconOracle = EigenLayerBeaconOracle(stdJson.readAddress(deployed, ".clientChain.beaconOracle"));
require(address(beaconOracle) != address(0), "beacon oracle should not be empty");

capsuleBeacon = UpgradeableBeacon(stdJson.readAddress(deployed, ".clientChain.capsuleBeacon"));
require(address(capsuleBeacon) != address(0), "exo capsule beacon should not be empty");

initialization = abi.encodeCall(ClientChainGateway.initialize, (payable(exocoreValidatorSet.addr)));
}

Expand All @@ -76,9 +89,18 @@ contract CorrectBootstrapErrors is BaseScript {
vm.selectFork(clientChain);
vm.startBroadcast(exocoreValidatorSet.privateKey);
ProxyAdmin proxyAdmin = ProxyAdmin(proxyAdmin);
Bootstrap bootstrapLogic = new Bootstrap(
address(clientChainLzEndpoint), exocoreChainId, address(vaultBeacon), address(beaconProxyBytecode)
);

// Create ImmutableConfig struct
BootstrapStorage.ImmutableConfig memory config = BootstrapStorage.ImmutableConfig({
exocoreChainId: exocoreChainId,
beaconOracleAddress: address(beaconOracle),
vaultBeacon: address(vaultBeacon),
exoCapsuleBeacon: address(capsuleBeacon),
beaconProxyBytecode: address(beaconProxyBytecode)
});

Bootstrap bootstrapLogic = new Bootstrap(address(clientChainLzEndpoint), config);

bytes memory data = abi.encodeCall(
Bootstrap.initialize,
(
Expand Down
29 changes: 14 additions & 15 deletions script/2_DeployBoth.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import "../src/utils/BeaconProxyBytecode.sol";
import "../src/utils/CustomProxyAdmin.sol";
import {ExocoreGatewayMock} from "../test/mocks/ExocoreGatewayMock.sol";

import {BootstrapStorage} from "../src/storage/BootstrapStorage.sol";
import {BaseScript} from "./BaseScript.sol";
import "@beacon-oracle/contracts/src/EigenLayerBeaconOracle.sol";
import "@layerzero-v2/protocol/contracts/interfaces/ILayerZeroEndpointV2.sol";
Expand Down Expand Up @@ -59,33 +60,31 @@ contract DeployScript is BaseScript {
// deploy beacon chain oracle
beaconOracle = _deployBeaconOracle();

/// deploy vault implementation contract, capsule implementation contract, reward vault implementation contract
/// that has logics called by proxy
/// deploy implementations and beacons
vaultImplementation = new Vault();
capsuleImplementation = new ExoCapsule();
rewardVaultImplementation = new RewardVault();

/// deploy the vault beacon, capsule beacon, reward vault beacon that store the implementation contract address
vaultBeacon = new UpgradeableBeacon(address(vaultImplementation));
capsuleBeacon = new UpgradeableBeacon(address(capsuleImplementation));
rewardVaultBeacon = new UpgradeableBeacon(address(rewardVaultImplementation));

// deploy BeaconProxyBytecode to store BeaconProxyBytecode
beaconProxyBytecode = new BeaconProxyBytecode();

// deploy custom proxy admin
clientChainProxyAdmin = new CustomProxyAdmin();

// Create ImmutableConfig struct
BootstrapStorage.ImmutableConfig memory config = BootstrapStorage.ImmutableConfig({
exocoreChainId: exocoreChainId,
beaconOracleAddress: address(beaconOracle),
vaultBeacon: address(vaultBeacon),
exoCapsuleBeacon: address(capsuleBeacon),
beaconProxyBytecode: address(beaconProxyBytecode)
});

/// deploy client chain gateway
ClientChainGateway clientGatewayLogic = new ClientChainGateway(
address(clientChainLzEndpoint),
exocoreChainId,
address(beaconOracle),
address(vaultBeacon),
address(rewardVaultBeacon),
address(capsuleBeacon),
address(beaconProxyBytecode)
);
ClientChainGateway clientGatewayLogic =
new ClientChainGateway(address(clientChainLzEndpoint), config, address(rewardVaultBeacon));

clientGateway = ClientChainGateway(
payable(
address(
Expand Down
46 changes: 28 additions & 18 deletions script/7_DeployBootstrap.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {ILayerZeroEndpointV2} from "@layerzero-v2/protocol/contracts/interfaces/
import {ERC20PresetFixedSupply} from "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol";
import "forge-std/Script.sol";

import {BootstrapStorage} from "../src/storage/BootstrapStorage.sol";
import "@beacon-oracle/contracts/src/EigenLayerBeaconOracle.sol";

contract DeployBootstrapOnly is BaseScript {
Expand Down Expand Up @@ -59,32 +60,42 @@ contract DeployBootstrapOnly is BaseScript {

// proxy deployment
clientChainProxyAdmin = new CustomProxyAdmin();
// vault, shared between bootstrap and client chain gateway

// deploy beacon chain oracle
beaconOracle = _deployBeaconOracle();

/// deploy vault implementation contract, capsule implementation contract, reward vault implementation contract
/// that has logics called by proxy
vaultImplementation = new Vault();
capsuleImplementation = new ExoCapsule();

/// deploy the vault beacon, capsule beacon, reward vault beacon that store the implementation contract address
vaultBeacon = new UpgradeableBeacon(address(vaultImplementation));
capsuleBeacon = new UpgradeableBeacon(address(capsuleImplementation));

// Create ImmutableConfig struct
BootstrapStorage.ImmutableConfig memory config = BootstrapStorage.ImmutableConfig({
exocoreChainId: exocoreChainId,
beaconOracleAddress: address(beaconOracle),
vaultBeacon: address(vaultBeacon),
exoCapsuleBeacon: address(capsuleBeacon),
beaconProxyBytecode: address(beaconProxyBytecode)
});

// bootstrap logic
Bootstrap bootstrapLogic = new Bootstrap(
address(clientChainLzEndpoint), exocoreChainId, address(vaultBeacon), address(beaconProxyBytecode)
);
// client chain constructor (upgrade details)
capsuleImplementation = new ExoCapsule();
capsuleBeacon = new UpgradeableBeacon(address(capsuleImplementation));
Bootstrap bootstrapLogic = new Bootstrap(address(clientChainLzEndpoint), config);

// client chain constructor
rewardVaultImplementation = new RewardVault();
rewardVaultBeacon = new UpgradeableBeacon(address(rewardVaultImplementation));
ClientChainGateway clientGatewayLogic = new ClientChainGateway(
address(clientChainLzEndpoint),
exocoreChainId,
address(beaconOracle),
address(vaultBeacon),
address(rewardVaultBeacon),
address(capsuleBeacon),
address(beaconProxyBytecode)
);
ClientChainGateway clientGatewayLogic =
new ClientChainGateway(address(clientChainLzEndpoint), config, address(rewardVaultBeacon));

// then the client chain initialization
address[] memory emptyList;
bytes memory initialization =
abi.encodeWithSelector(clientGatewayLogic.initialize.selector, exocoreValidatorSet.addr, emptyList);

// bootstrap implementation
Bootstrap bootstrap = Bootstrap(
payable(
Expand All @@ -96,10 +107,9 @@ contract DeployBootstrapOnly is BaseScript {
Bootstrap.initialize,
(
exocoreValidatorSet.addr,
// 1 week from now
block.timestamp + 168 hours,
2 seconds,
whitelistTokens, // vault is auto deployed
whitelistTokens,
tvlLimits,
address(clientChainProxyAdmin),
address(clientGatewayLogic),
Expand Down
54 changes: 48 additions & 6 deletions script/integration/1_DeployBootstrap.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,22 @@ pragma solidity ^0.8.0;
import "forge-std/Script.sol";
import "forge-std/console.sol";

import "@beacon-oracle/contracts/src/EigenLayerBeaconOracle.sol";
import {IBeacon} from "@openzeppelin/contracts/proxy/beacon/IBeacon.sol";
import {UpgradeableBeacon} from "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol";
import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";

import {EndpointV2Mock} from "../../test/mocks/EndpointV2Mock.sol";

import {Bootstrap} from "../../src/core/Bootstrap.sol";
import {BootstrapStorage} from "../../src/storage/BootstrapStorage.sol";

import {ExoCapsule} from "../../src/core/ExoCapsule.sol";
import {Vault} from "../../src/core/Vault.sol";
import {IExoCapsule} from "../../src/interfaces/IExoCapsule.sol";
import {IValidatorRegistry} from "../../src/interfaces/IValidatorRegistry.sol";
import {IVault} from "../../src/interfaces/IVault.sol";

import "../../src/utils/BeaconProxyBytecode.sol";
import {CustomProxyAdmin} from "../../src/utils/CustomProxyAdmin.sol";
import {MyToken} from "../../test/foundry/unit/MyToken.sol";
Expand Down Expand Up @@ -51,8 +56,11 @@ contract DeployContracts is Script {
IVault[] vaults;
CustomProxyAdmin proxyAdmin;

EigenLayerBeaconOracle beaconOracle;
IVault vaultImplementation;
IExoCapsule capsuleImplementation;
IBeacon vaultBeacon;
IBeacon capsuleBeacon;
BeaconProxyBytecode beaconProxyBytecode;

function setUp() private {
Expand Down Expand Up @@ -106,20 +114,34 @@ contract DeployContracts is Script {
function deployContract() private {
vm.startBroadcast(contractDeployer);

/// deploy vault implementationcontract that has logics called by proxy
// deploy beacon chain oracle
beaconOracle = _deployBeaconOracle();

/// deploy vault implementation contract, capsule implementation contract
vaultImplementation = new Vault();
capsuleImplementation = new ExoCapsule();

/// deploy the vault beacon that store the implementation contract address
/// deploy the vault beacon and capsule beacon
vaultBeacon = new UpgradeableBeacon(address(vaultImplementation));
capsuleBeacon = new UpgradeableBeacon(address(capsuleImplementation));

// deploy BeaconProxyBytecode to store BeaconProxyBytecode
// deploy BeaconProxyBytecode
beaconProxyBytecode = new BeaconProxyBytecode();

proxyAdmin = new CustomProxyAdmin();
EndpointV2Mock clientChainLzEndpoint = new EndpointV2Mock(clientChainId);
Bootstrap bootstrapLogic = new Bootstrap(
address(clientChainLzEndpoint), exocoreChainId, address(vaultBeacon), address(beaconProxyBytecode)
);

// Create ImmutableConfig struct
BootstrapStorage.ImmutableConfig memory config = BootstrapStorage.ImmutableConfig({
exocoreChainId: exocoreChainId,
beaconOracleAddress: address(beaconOracle),
vaultBeacon: address(vaultBeacon),
exoCapsuleBeacon: address(capsuleBeacon),
beaconProxyBytecode: address(beaconProxyBytecode)
});

Bootstrap bootstrapLogic = new Bootstrap(address(clientChainLzEndpoint), config);

bootstrap = Bootstrap(
payable(
address(
Expand All @@ -145,6 +167,7 @@ contract DeployContracts is Script {
);
vm.stopBroadcast();
console.log("Bootstrap address: ", address(bootstrap));

// set the vaults
for (uint256 i = 0; i < whitelistTokens.length; i++) {
IVault vault = bootstrap.tokenToVault(whitelistTokens[i]);
Expand Down Expand Up @@ -294,4 +317,23 @@ contract DeployContracts is Script {
return (uint256(keccak256(abi.encodePacked(block.timestamp, block.prevrandao))) % (_range - 1)) + 1;
}

function _deployBeaconOracle() internal returns (EigenLayerBeaconOracle) {
uint256 GENESIS_BLOCK_TIMESTAMP;

if (block.chainid == 1) {
GENESIS_BLOCK_TIMESTAMP = 1_606_824_023;
} else if (block.chainid == 5) {
GENESIS_BLOCK_TIMESTAMP = 1_616_508_000;
} else if (block.chainid == 11_155_111) {
GENESIS_BLOCK_TIMESTAMP = 1_655_733_600;
} else if (block.chainid == 17_000) {
GENESIS_BLOCK_TIMESTAMP = 1_695_902_400;
} else {
revert("Unsupported chainId.");
}

EigenLayerBeaconOracle oracle = new EigenLayerBeaconOracle(GENESIS_BLOCK_TIMESTAMP);
return oracle;
}

}
Loading

0 comments on commit 46f9927

Please sign in to comment.