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

feat: enable Ethereum native restaking for Bootstrap #121

Merged
merged 8 commits into from
Nov 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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)
adu-web3 marked this conversation as resolved.
Show resolved Hide resolved
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;
}
adu-web3 marked this conversation as resolved.
Show resolved Hide resolved

}
Loading
Loading