Skip to content

Commit

Permalink
fix: respond to AI comments
Browse files Browse the repository at this point in the history
  • Loading branch information
MaxMustermann2 committed Nov 18, 2024
1 parent bd81e0a commit 7e48df8
Show file tree
Hide file tree
Showing 9 changed files with 212 additions and 102 deletions.
34 changes: 20 additions & 14 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,31 @@ EXOCORE_GENESIS_PRIVATE_KEY=0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3f
USE_ENDPOINT_MOCK=true
USE_EXOCORE_PRECOMPILE_MOCK=true

VALIDATOR_KEYS=
EXO_ADDRESSES=
NAMES=
CONS_KEYS=

# The following are used by generate.js, in addition to CLIENT_CHAIN_RPC above.
BOOTSTRAP_ADDRESS=
EXCHANGE_RATES=
BASE_GENESIS_FILE_PATH=
RESULT_GENESIS_FILE_PATH=
BEACON_CHAIN_ENDPOINT=

# For contract verification
ETHERSCAN_API_KEY=

# These are used for integration testing ETH PoS
# These are used for integration testing the Bootstrap contract, in addition to
# CLIENT_CHAIN_RPC and BEACON_CHAIN_ENDPOINT above.
INTEGRATION_VALIDATOR_KEYS=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80,0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d,0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a
INTEGRATION_STAKERS=0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6,0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a,0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba,0x92db14e403b83dfe3df233f83dfa3a0d7096f21ca9b0d6d6b8d88b2b4ec1564e,0x4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356,0xdbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97,0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6
INTEGRATION_TOKEN_DEPLOYERS=0x701b615bbdfb9de65240bc28bd21bbc0d996645a3dd57e7b12bc2bdf6f192c82,0xa267530f49f8280200edf313ee7af6b827f2a8bce2897751d06a843f644967b1
INTEGRATION_CONTRACT_DEPLOYER=0xf214f2b2cd398c806f84e317254e0f0b801d0643303237d97a22a48e01628897
# Specially ETH PoS related parameters.
INTEGRATION_DEPOSIT_ADDRESS=0x6969696969696969696969696969696969696969
INTEGRATION_SECONDS_PER_SLOT=4
INTEGRATION_SLOTS_PER_EPOCH=3
INTEGRATION_BEACON_GENESIS_TIMESTAMP=
INTEGRATION_DENEB_TIMESTAMP=
NST_DEPOSITOR=
INTEGRATION_NST_DEPOSITOR=0x47c99abed3324a2707c28affff1267e45918ec8c3f20b8aa892e8b065d2942dd
# margin tank lunch prison top episode peanut approve dish seat nominee illness
INTEGRATION_PUBKEY=0x98db81971df910a5d46314d21320f897060d76fdf137d22f0eb91a8693a4767d2a22730a3aaa955f07d13ad604f968e9
INTEGRATION_SIGNATURE=0x922a316bdc3516bfa66e88259d5e93e339ef81bc85b70e6c715542222025a28fa1e3644c853beb8c3ba76a2c5c03b726081bf605bde3a16e1f33f902cc1b6c01093c19609de87da9383fa4b1f347bd2d4222e1ae5428727a7896c8e553cc8071
# derived from pubkey + network params == chain id + genesis {fork version + validators root}
INTEGRATION_DEPOSIT_DATA_ROOT=0x456934ced8f08ff106857418a6d885ba69d31e1b7fab9a931be06da25490cd1d
INTEGRATION_BEACON_CHAIN_ENDPOINT=http://localhost:3500
INTEGRATION_PROVE_ENDPOINT=http://localhost:8989
# for generate.js
INTEGRATION_BOOTSTRAP_ADDRESS=0xF801fc13AA08876F343fEBf50dFfA52A78180811
INTEGRATION_EXCHANGE_RATES=1000.123,2000.123,1799.345345
INTEGRATION_BASE_GENESIS_FILE_PATH=
INTEGRATION_RESULT_GENESIS_FILE_PATH=
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,6 @@
"scripts": {
"test": "mocha"
},
"type": "module",
"keywords": [],
"author": "",
"license": "ISC"
Expand Down
64 changes: 30 additions & 34 deletions script/generate.js → script/generate.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ import dotenv from 'dotenv';
dotenv.config();
import { decode } from 'bech32';
import { promises as fs } from 'fs';
import { Web3 } from 'web3';
import Web3 from 'web3';
import Decimal from 'decimal.js';

import { getClient } from "@lodestar/api";
Expand All @@ -70,7 +70,14 @@ const isValidBech32 = (address) => {


// Load variables from .env file
const { BEACON_CHAIN_ENDPOINT, CLIENT_CHAIN_RPC, BOOTSTRAP_ADDRESS, BASE_GENESIS_FILE_PATH, RESULT_GENESIS_FILE_PATH, EXCHANGE_RATES } = process.env;
const {
INTEGRATION_BEACON_CHAIN_ENDPOINT,
CLIENT_CHAIN_RPC,
INTEGRATION_BOOTSTRAP_ADDRESS,
INTEGRATION_BASE_GENESIS_FILE_PATH,
INTEGRATION_RESULT_GENESIS_FILE_PATH,
INTEGRATION_EXCHANGE_RATES
} = process.env;

import pkg from 'js-sha3';
const { keccak256 } = pkg;
Expand Down Expand Up @@ -106,9 +113,9 @@ async function updateGenesisFile() {
const web3 = new Web3(CLIENT_CHAIN_RPC);

// Create contract instance
const myContract = new web3.eth.Contract(contractABI, BOOTSTRAP_ADDRESS);
const myContract = new web3.eth.Contract(contractABI, INTEGRATION_BOOTSTRAP_ADDRESS);
// Create beacon API client
const api = getClient({baseUrl: BEACON_CHAIN_ENDPOINT}, {config});
const api = getClient({baseUrl: INTEGRATION_BEACON_CHAIN_ENDPOINT}, {config});
const spec = (await api.config.getSpec()).value();
const maxEffectiveBalance = new Decimal(spec.MAX_EFFECTIVE_BALANCE).mul(GWEI_TO_WEI);
const ejectIonBalance = new Decimal(spec.EJECTION_BALANCE).mul(GWEI_TO_WEI);
Expand All @@ -123,10 +130,10 @@ async function updateGenesisFile() {
const stateRoot = web3.utils.bytesToHex(lastHeader.header.message.stateRoot);

// Read exchange rates
const exchangeRates = EXCHANGE_RATES.split(',').map(Decimal);
const exchangeRates = INTEGRATION_EXCHANGE_RATES.split(',').map(Decimal);

// Read the genesis file
const genesisData = await fs.readFile(BASE_GENESIS_FILE_PATH);
const genesisData = await fs.readFile(INTEGRATION_BASE_GENESIS_FILE_PATH);
const genesisJSON = jsonBig.parse(genesisData);

const height = parseInt(genesisJSON.initial_height, 10);
Expand Down Expand Up @@ -207,7 +214,8 @@ async function updateGenesisFile() {
const decimals = [];
const supportedTokens = [];
const assetIds = [];
const oracleTokens = {};
// start with the initial value
const oracleTokens = genesisJSON.app_state.oracle.params.tokens;
const oracleTokenFeeders = [];
let offset = 0;
for (let i = 0; i < supportedTokensCount; i++) {
Expand All @@ -231,32 +239,32 @@ async function updateGenesisFile() {
assetIds.push(token.tokenAddress.toLowerCase() + clientChainSuffix);
const oracleToken = {
name: tokenNamesForOracle[i],
index: offset,
chain_id: 1, // constant intentionally, representing the first chain in the list (after the reserved blank one)
contract_address: token.tokenAddress,
active: true,
asset_id: token.tokenAddress.toLowerCase() + clientChainSuffix,
decimal: 8, // price decimals, not token decimals
}
const oracleTokenFeeder = {
index: offset,
token_id: (i + 1 - offset).toString(), // first is reserved
rule_id: "1",
start_round_id: "1",
start_base_block: (height + 10000).toString(),
interval: "30",
end_block: "0",
}
if (oracleTokens.name in oracleTokens) {
oracleTokens[oracleTokens.name].asset_id += ',' + oracleToken.asset_id;
if (oracleToken.name in oracleTokens) {
oracleTokens[oracleToken.name].asset_id += ',' + oracleToken.asset_id;
offset += 1;
} else {
oracleTokens[oracleTokens.name] = oracleToken;
oracleTokens[oracleToken.name] = oracleToken;
oracleTokenFeeders.push(oracleTokenFeeder);
}
// break;
}
genesisJSON.app_state.oracle.params.tokens = Object.values(oracleTokens)
.sort((a, b) => {a.index - b.uindex})
.sort((a, b) => {a.index - b.index})
.map(({index, ...rest}) => rest);
genesisJSON.app_state.oracle.params.token_feeders = oracleTokenFeeders;
supportedTokens.sort((a, b) => {
Expand Down Expand Up @@ -325,8 +333,6 @@ async function updateGenesisFile() {
}
totalEffectiveBalance = totalEffectiveBalance.plus(valEffectiveBalance);
}
console.log(`Total effective balance for staker ${stakerAddress}: ${totalEffectiveBalance}`);
console.log(`Total deposit value for staker ${stakerAddress}: ${depositValue}`);
if (depositValue > totalEffectiveBalance) {
console.log("Staker has more deposit than effective balance.");
// deposited 32 ETH and left with 31 ETH, aka downtime slashing
Expand All @@ -348,11 +354,6 @@ async function updateGenesisFile() {
continue;
}
}
let pendingSlashAmount = toSlash.sub(withdrawableValue);
if (pendingSlashAmount.gt(0)) {
withdrawableValue = withdrawableValue.minus(pendingSlashAmount);
depositValue = depositValue.minus(pendingSlashAmount);
}
} else if (depositValue < totalEffectiveBalance) {
// deposited 32 ETH and left with 33 ETH, aka rewards
const delta = totalEffectiveBalance.minus(depositValue);
Expand All @@ -363,25 +364,17 @@ async function updateGenesisFile() {
staker_addr: stakerAddress.toLowerCase(),
staker_index: staker_index_counter,
validator_pubkey_list: pubKeys,
balance_list: [
{
// TODO: check these values with Qing
round_id: 0,
block: height,
index: 0,
change: 0,
balance: depositValue.toString(),
}
]
// the balance list represents the history of the balance. for bootstrap, that is empty.
balance_list: []
});
staker_index_counter += 1;
}
const depositByStakerForAsset = {
asset_id: tokenAddress.toLowerCase() + clientChainSuffix,
info: {
// adjusted for slashing by ETH beacon chain
total_deposit_amount: depositValue.toString(),
withdrawable_amount: withdrawableValue.toString(),
total_deposit_amount: depositValue.toFixed(),
withdrawable_amount: withdrawableValue.toFixed(),
pending_undelegation_amount: "0",
}
};
Expand Down Expand Up @@ -810,10 +803,10 @@ async function updateGenesisFile() {
}
}
];
genesisJSON.app_state.oracle.staker_infos_assets = {
genesisJSON.app_state.oracle.staker_infos_assets = [{
asset_id: VIRTUAL_STAKED_ETH_ADDR.toLowerCase() + clientChainSuffix,
staker_infos: staker_infos,
};
}];

// add the native chain and at the end so that count-related issues don't arise.
genesisJSON.app_state.assets.client_chains.push(nativeChain);
Expand All @@ -824,7 +817,10 @@ async function updateGenesisFile() {
nativeAsset.asset_basic_info.layer_zero_chain_id.toString(16)
);

await fs.writeFile(RESULT_GENESIS_FILE_PATH, jsonBig.stringify(genesisJSON, null, 2));
await fs.writeFile(
INTEGRATION_RESULT_GENESIS_FILE_PATH,
jsonBig.stringify(genesisJSON, null, 2)
);
console.log('Genesis file updated successfully.');
} catch (error) {
console.error('Error updating genesis file:', error.message);
Expand Down
54 changes: 29 additions & 25 deletions script/integration/1_DeployBootstrap.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -47,19 +47,12 @@ contract DeployContracts is Script {
// neither is the ownership of the contract being tested here
address exocoreValidatorSet = vm.addr(uint256(0x8));

// assumes 3 validators, to add more - change registerValidators and delegate.
uint256[] validators;
uint256[] stakers;
string[] exos;
uint256 contractDeployer;
uint256 nstDepositor;
Bootstrap bootstrap;
// to add more tokens,
// 0. add deployer private keys
// 1. update the decimals
// 2. increase the size of MyToken
// 3. add information about tokens to deployTokens.
// 4. update deposit and delegate amounts in fundAndApprove and delegate.
// everywhere else we use the length of the myTokens array.
uint256[] tokenDeployers;
uint8[2] decimals = [18, 6];
address[] whitelistTokens;
Expand All @@ -82,6 +75,9 @@ contract DeployContracts is Script {
uint64 secondsPerSlot;
uint64 slotsPerEpoch;
uint256 beaconGenesisTimestamp;
bytes pubkey;
bytes signature;
bytes32 depositDataRoot;

function setUp() private {
// placate the pre-simulation runner
Expand All @@ -106,15 +102,21 @@ contract DeployContracts is Script {
ANVIL_TOKEN_DEPLOYERS[0] = uint256(0x701b615bbdfb9de65240bc28bd21bbc0d996645a3dd57e7b12bc2bdf6f192c82);
ANVIL_TOKEN_DEPLOYERS[1] = uint256(0xa267530f49f8280200edf313ee7af6b827f2a8bce2897751d06a843f644967b1);

uint256 CONTRACT_DEPLOYER = uint256(0xf214f2b2cd398c806f84e317254e0f0b801d0643303237d97a22a48e01628897);
uint256 ANVIL_CONTRACT_DEPLOYER = uint256(0xf214f2b2cd398c806f84e317254e0f0b801d0643303237d97a22a48e01628897);

uint256 NST_DEPOSITOR = uint256(0x47c99abed3324a2707c28affff1267e45918ec8c3f20b8aa892e8b065d2942dd);
uint256 ANVIL_NST_DEPOSITOR = uint256(0x47c99abed3324a2707c28affff1267e45918ec8c3f20b8aa892e8b065d2942dd);

validators = vm.envOr("ANVIL_VALIDATORS", ",", ANVIL_VALIDATORS);
stakers = vm.envOr("ANVIL_STAKERS", ",", ANVIL_STAKERS);
tokenDeployers = vm.envOr("ANVIL_TOKEN_DEPLOYERS", ",", ANVIL_TOKEN_DEPLOYERS);
contractDeployer = vm.envOr("CONTRACT_DEPLOYER", CONTRACT_DEPLOYER);
nstDepositor = vm.envOr("NST_DEPOSITOR", NST_DEPOSITOR);
// load the keys for validators, stakers, token deployers, and the contract deployer
validators = vm.envOr("INTEGRATION_VALIDATOR_KEYS", ",", ANVIL_VALIDATORS);
// we don't validate the contents of the keys because vm.addr will throw if they are invalid
require(validators.length == 3, "Modify this script to support validators.length other than 3");
stakers = vm.envOr("INTEGRATION_STAKERS", ",", ANVIL_STAKERS);
require(stakers.length == 7, "Modify this script to support stakers.length other than 7");
tokenDeployers = vm.envOr("INTEGRATION_TOKEN_DEPLOYERS", ",", ANVIL_TOKEN_DEPLOYERS);
require(tokenDeployers.length == 2, "Modify this script to support tokenDeployers.length other than 2");
require(decimals.length == tokenDeployers.length, "Decimals and tokenDeployers must have the same length");
contractDeployer = vm.envOr("INTEGRATION_CONTRACT_DEPLOYER", ANVIL_CONTRACT_DEPLOYER);
nstDepositor = vm.envOr("INTEGRATION_NST_DEPOSITOR", ANVIL_NST_DEPOSITOR);

// read the network configuration parameters and validate them
depositAddress = vm.envOr("INTEGRATION_DEPOSIT_ADDRESS", address(0x6969696969696969696969696969696969696969));
Expand All @@ -131,6 +133,13 @@ contract DeployContracts is Script {
require(slotsPerEpoch_ > 0, "Slots per epoch must be set");
require(slotsPerEpoch_ <= type(uint64).max, "Slots per epoch must be less than or equal to uint64 max");
slotsPerEpoch = uint64(slotsPerEpoch_);
// then, the Ethereum-native validator configuration
pubkey = vm.envBytes("INTEGRATION_PUBKEY");
require(pubkey.length == 48, "Pubkey must be 48 bytes");
signature = vm.envBytes("INTEGRATION_SIGNATURE");
require(signature.length == 96, "Signature must be 96 bytes");
depositDataRoot = vm.envBytes32("INTEGRATION_DEPOSIT_DATA_ROOT");
require(depositDataRoot != bytes32(0), "Deposit data root must be set");
}

function deployTokens() private {
Expand Down Expand Up @@ -255,20 +264,11 @@ contract DeployContracts is Script {
myAddress = bootstrap.createExoCapsule();
}
console.log("ExoCapsule address", myAddress);
bootstrap.stake{value: 32 ether}(
// mnemonic: margin tank lunch prison top episode peanut approve dish seat nominee illness
hex"98db81971df910a5d46314d21320f897060d76fdf137d22f0eb91a8693a4767d2a22730a3aaa955f07d13ad604f968e9", // pubkey
hex"922a316bdc3516bfa66e88259d5e93e339ef81bc85b70e6c715542222025a28fa1e3644c853beb8c3ba76a2c5c03b726081bf605bde3a16e1f33f902cc1b6c01093c19609de87da9383fa4b1f347bd2d4222e1ae5428727a7896c8e553cc8071", // signature
bytes32(0x456934ced8f08ff106857418a6d885ba69d31e1b7fab9a931be06da25490cd1d) // deposit data root
);
bootstrap.stake{value: 32 ether}(pubkey, signature, depositDataRoot);
vm.stopBroadcast();
}

function registerValidators() private {
// the mnemonics corresponding to the consensus public keys are given here. to recover,
// echo "${MNEMONIC}" | exocored init localnet --chain-id exocorelocal_233-1 --recover
// the value in this script is this one
// exocored keys consensus-pubkey-to-bytes --output json | jq -r .bytes
string[3] memory exos = [
// these addresses will accrue rewards but they are not needed to keep the chain
// running.
Expand All @@ -277,6 +277,10 @@ contract DeployContracts is Script {
"exo1rtg0cgw94ep744epyvanc0wdd5kedwql73vlmr"
];
string[3] memory names = ["validator1", "validator2", "validator3"];
// the mnemonics corresponding to the consensus public keys are given here. to recover,
// echo "${MNEMONIC}" | exocored init localnet --chain-id exocorelocal_233-1 --recover
// the value in this script is this one
// exocored keys consensus-pubkey-to-bytes --output json | jq -r .bytes
bytes32[3] memory pubKeys = [
// wonder quality resource ketchup occur stadium vicious output situate plug second
// monkey harbor vanish then myself primary feed earth story real soccer shove like
Expand Down
17 changes: 12 additions & 5 deletions script/integration/2_VerifyDepositNST.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,28 @@ contract VerifyDepositNST is Script {
uint256 nstDepositor;

function setUp() public virtual {
// vm.chainId(ALLOWED_CHAIN_ID);
// obtain the address
string memory deployments = vm.readFile("script/integration/deployments.json");
bootstrapAddress = deployments.readAddress(".bootstrapAddress");
require(bootstrapAddress != address(0), "Bootstrap address not found");
beaconOracleAddress = deployments.readAddress(".beaconOracleAddress");
require(beaconOracleAddress != address(0), "BeaconOracle address not found");
nstDepositor =
vm.envOr("NST_DEPOSITOR", uint256(0x47c99abed3324a2707c28affff1267e45918ec8c3f20b8aa892e8b065d2942dd));
nstDepositor = vm.envOr(
"INTEGRATION_NST_DEPOSITOR", uint256(0x47c99abed3324a2707c28affff1267e45918ec8c3f20b8aa892e8b065d2942dd)
);
require(nstDepositor != 0, "INTEGRATION_NST_DEPOSITOR not set");
}

function run() external {
bytes32[] memory validatorContainer;
vm.startBroadcast(nstDepositor);
Bootstrap bootstrap = Bootstrap(bootstrapAddress);
require(vm.exists("script/integration/proof.json"), "Proof file not found");
string memory data = vm.readFile("script/integration/proof.json");
// load the validator container
validatorContainer = data.readBytes32Array(".validatorContainer");
// load the validator proof
// we don't validate it; that task is left to the contract. it is a test, after all.
validatorProof = BeaconChainProofs.ValidatorContainerProof({
stateRoot: data.readBytes32(".stateRoot"),
stateRootProof: data.readBytes32Array(".stateRootProof"),
Expand All @@ -58,9 +61,13 @@ contract VerifyDepositNST is Script {
oracle.addTimestamp(validatorProof.beaconBlockTimestamp);
// now, the transactions
bootstrap.verifyAndDepositNativeStake(validatorContainer, validatorProof);
// delegate only a small portion of the deposit for our test
bootstrap.delegateTo(
"exo1rtg0cgw94ep744epyvanc0wdd5kedwql73vlmr", address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE), 18 ether
// a validator in 1_DeployBootstrap.s.sol
"exo1rtg0cgw94ep744epyvanc0wdd5kedwql73vlmr",
// the native token address
address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE),
// delegate only a small portion of the deposit for our test
18 ether
);
vm.stopBroadcast();
}
Expand Down
3 changes: 3 additions & 0 deletions script/integration/BeaconOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ contract BeaconOracle is IBeaconChainOracle {
}

function addTimestamp(uint256 _targetTimestamp) external {
if (_targetTimestamp < GENESIS_BLOCK_TIMESTAMP) {
revert InvalidBlockTimestamp();
}
// If the targetTimestamp is not guaranteed to be within the beacon block root ring buffer, revert.
if ((block.timestamp - _targetTimestamp) >= (BEACON_ROOTS_HISTORY_BUFFER_LENGTH * SECONDS_PER_SLOT)) {
revert TimestampOutOfRange();
Expand Down
Loading

0 comments on commit 7e48df8

Please sign in to comment.