From 6d9640b0e10586942e6678b1527a4ac975261f27 Mon Sep 17 00:00:00 2001 From: Stefan Nikolov Date: Tue, 27 Jun 2023 20:16:39 +0300 Subject: [PATCH 1/5] feat(circom): fully constraint is_valid_merkle_branch_out --- .../circuits/is_valid_merkle_branch_out.circom | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/beacon-light-client/circom/circuits/is_valid_merkle_branch_out.circom b/beacon-light-client/circom/circuits/is_valid_merkle_branch_out.circom index 14f4943e2..574bc96f2 100644 --- a/beacon-light-client/circom/circuits/is_valid_merkle_branch_out.circom +++ b/beacon-light-client/circom/circuits/is_valid_merkle_branch_out.circom @@ -3,6 +3,7 @@ pragma circom 2.1.5; include "hash_two.circom"; include "../../../node_modules/circomlib/circuits/comparators.circom"; include "utils/arrays.circom"; +include "utils/numerical.circom"; template IsValidMerkleBranchOut(N) { signal input branch[N][256]; @@ -14,12 +15,27 @@ template IsValidMerkleBranchOut(N) { component hashers[N]; component isZero[N]; + component pow[N]; + component divisionByTwo[N]; + component divisionByPow[N]; for(var i = 0; i < N; i++) { hashers[i] = HashTwo(); isZero[i] = IsZero(); - isZero[i].in <-- (index \ (2**i)) % 2; + pow[i] = Pow(256); + pow[i].base <== 2; + pow[i].power <== i; + + divisionByPow[i] = DivisionBy(); + divisionByPow[i].dividend <== index; + divisionByPow[i].divisor <== pow[i].out; + + divisionByTwo[i] = DivisionBy(); + divisionByTwo[i].dividend <== divisionByPow[i].quotient; + divisionByTwo[i].divisor <== 2; + + isZero[i].in <== divisionByTwo[i].remainder; var current[256]; From ca95a9a2603c952e623b8de2673d7d523c7f2f75 Mon Sep 17 00:00:00 2001 From: Stefan Nikolov Date: Wed, 28 Jun 2023 15:29:31 +0300 Subject: [PATCH 2/5] feat(circom): Add additional test for pow template --- beacon-light-client/circom/test/pow/data/case05/input.json | 4 ++++ beacon-light-client/circom/test/pow/data/case05/output.json | 3 +++ 2 files changed, 7 insertions(+) create mode 100644 beacon-light-client/circom/test/pow/data/case05/input.json create mode 100644 beacon-light-client/circom/test/pow/data/case05/output.json diff --git a/beacon-light-client/circom/test/pow/data/case05/input.json b/beacon-light-client/circom/test/pow/data/case05/input.json new file mode 100644 index 000000000..192a6d259 --- /dev/null +++ b/beacon-light-client/circom/test/pow/data/case05/input.json @@ -0,0 +1,4 @@ +{ + "base": "10", + "power": "0" +} diff --git a/beacon-light-client/circom/test/pow/data/case05/output.json b/beacon-light-client/circom/test/pow/data/case05/output.json new file mode 100644 index 000000000..8575e58cd --- /dev/null +++ b/beacon-light-client/circom/test/pow/data/case05/output.json @@ -0,0 +1,3 @@ +{ + "out": "1" +} From 14f514536948f913bbbd0c4994ec51d2c4ae8a67 Mon Sep 17 00:00:00 2001 From: Stefan Nikolov Date: Thu, 29 Jun 2023 14:45:06 +0300 Subject: [PATCH 3/5] fix(circom): Constrain index remainder by idx2Bits --- .../is_valid_merkle_branch_out.circom | 23 +++++-------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/beacon-light-client/circom/circuits/is_valid_merkle_branch_out.circom b/beacon-light-client/circom/circuits/is_valid_merkle_branch_out.circom index 574bc96f2..6546a42dc 100644 --- a/beacon-light-client/circom/circuits/is_valid_merkle_branch_out.circom +++ b/beacon-light-client/circom/circuits/is_valid_merkle_branch_out.circom @@ -2,6 +2,8 @@ pragma circom 2.1.5; include "hash_two.circom"; include "../../../node_modules/circomlib/circuits/comparators.circom"; +include "../../../node_modules/circomlib/circuits/bitify.circom"; + include "utils/arrays.circom"; include "utils/numerical.circom"; @@ -15,27 +17,14 @@ template IsValidMerkleBranchOut(N) { component hashers[N]; component isZero[N]; - component pow[N]; - component divisionByTwo[N]; - component divisionByPow[N]; - + component idx2Bits; + idx2Bits = Num2Bits(N+1); + idx2Bits.in <== index; for(var i = 0; i < N; i++) { hashers[i] = HashTwo(); isZero[i] = IsZero(); - pow[i] = Pow(256); - pow[i].base <== 2; - pow[i].power <== i; - - divisionByPow[i] = DivisionBy(); - divisionByPow[i].dividend <== index; - divisionByPow[i].divisor <== pow[i].out; - - divisionByTwo[i] = DivisionBy(); - divisionByTwo[i].dividend <== divisionByPow[i].quotient; - divisionByTwo[i].divisor <== 2; - - isZero[i].in <== divisionByTwo[i].remainder; + isZero[i].in <== idx2Bits.out[i]; var current[256]; From 3845dcfb8b5e6a3fe24b0ec4fa77f08178229dfb Mon Sep 17 00:00:00 2001 From: Dimo99 Date: Tue, 27 Jun 2023 17:57:44 +0300 Subject: [PATCH 4/5] doc(zk): Add description of the validator accumulator --- .../validator_accumulator_description.md | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 beacon-light-client/circom/scripts/validator_balances/validator_accumulator_description.md diff --git a/beacon-light-client/circom/scripts/validator_balances/validator_accumulator_description.md b/beacon-light-client/circom/scripts/validator_balances/validator_accumulator_description.md new file mode 100644 index 000000000..db0ce4709 --- /dev/null +++ b/beacon-light-client/circom/scripts/validator_balances/validator_accumulator_description.md @@ -0,0 +1,78 @@ +`validatorsAccumulator` is a Merkle tree accumulator that contains the public keys of validators and their corresponding Eth1 deposit indexes. +The purpose of storing the Eth1 deposit index is to ascertain whether a particular validator is already a participant in the beacon chain. + +A Merkle tree accumulator is a binary tree of hashes, which is used for efficiently proving membership of an element in a set. In this context, the set comprises of validators. + +This is a sample solidity implementation of the `validatorsAccumulator` + +``` +// The depth of the validator accumulator tree +uint constant VALIDATOR_ACCUMULATOR_TREE_DEPTH = 32; + +// An array to hold the branch hashes for the Merkle tree +bytes32[VALIDATOR_ACCUMULATOR_TREE_DEPTH] branch; + +// A counter for the total number of validators +uint validators_count; + +constructor() { + // Compute hashes in empty Merkle tree + for (uint height = 0; height < DEPOSIT_CONTRACT_TREE_DEPTH - 1; height++) + zero_hashes[height + 1] = sha256(abi.encodePacked(zero_hashes[height], zero_hashes[height])); +} + +// Function to calculate and return the Merkle accumulator root of the validators +function get_validators_accumulator() override external view returns (bytes32) { + bytes32 node; + uint size = validators_count; + + // Calculate the Merkle accumulator root + for (uint height = 0; height < VALIDATOR_ACCUMULATOR_TREE_DEPTH; height++) { + // This if-else structure supports tree balancing + // If size is odd, the new node will be hashed with the previous node on this level + // If size is even, the new node will be hashed with a predefined zero hash + if ((size & 1) == 1) + node = sha256(abi.encodePacked(branch[height], node)); + else + node = sha256(abi.encodePacked(node, zero_hashes[height])); + + size /= 2; + } + + return node; +} + +// Function to handle deposits from validators +function deposit( + bytes calldata pubkey, + bytes calldata withdrawal_credentials, + bytes calldata signature, + bytes32 deposit_data_root) { + // Perform the deposit using the DepositContract + IDepositContract(depositAddress).deposit(pubkey, withdrawal_credentials, signature, deposit_data_root); + + // Get the deposit count and increase the validator count + bytes deposit_index = IDepositContract(depositAddress).get_deposit_count(); + validators_count += 1; + + // Create a node for the validator + bytes32 node = sha256(abi.encodePacked(pubkey, deposit_index)); + + // Insert the node into the Merkle accumulator tree + uint size = validators_count; + for(uint height = 0; height < VALIDATOR_ACCUMULATOR_TREE_DEPTH; height++) { + if ((size & 1) == 1) { + branch[height] = node; + return; + } + node = sha256(abi.encodePacked(branch[height], node)); + size /= 2; + } +} +``` + +In the deposit function, each validator's public key and their Eth1 deposit index are packed together and hashed to form a node. This node represents the validator in the Merkle tree. + +The node is then inserted into the Merkle tree at the appropriate level, based on the current number of validators. The path to insert the node is determined using the binary representation of the total validator count. The leftmost branch is taken for every 0, and the rightmost branch for every 1. + +The get_validators_accumulator function calculates and returns the Merkle root of the validatorsAccumulator. This root is a single hash that effectively represents all the validators in the accumulator. From 6c8d8d307d5cf7d7af036866c427572dd05c070e Mon Sep 17 00:00:00 2001 From: Dimo99 Date: Thu, 29 Jun 2023 14:15:15 +0300 Subject: [PATCH 5/5] feat(solidity): Add ValidatorsAccumulator.sol --- .github/workflows/ci.yml | 3 + Makefile | 4 + .../scripts/validator_balances/get_input.ts | 5 +- .../validator_accumulator_description.md | 158 ++- .../ValidatorsAccumulator.sol | 122 ++ .../solidity/hardhat.config.ts | 33 +- .../test/ValidatorAccumulator.test.ts | 1047 +++++++++++++++++ libs/typescript/ts-utils/ssz-utils.ts | 34 +- 8 files changed, 1343 insertions(+), 63 deletions(-) create mode 100644 beacon-light-client/solidity/contracts/validators_accumulator/ValidatorsAccumulator.sol create mode 100644 beacon-light-client/solidity/test/ValidatorAccumulator.test.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1224e0b83..df9a5fecc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -64,6 +64,9 @@ jobs: - name: Run Verifier in Cosmos - Relayer test run: nix develop -c yarn test './tests/cosmosLightClient/test-verifier-in-cosmos-relay.ts' + - name: Run Solidity Validators accumulator tests + run: nix develop -c make test-validator-accumulator + # - name: Run Verifier in EOS test # run: nix develop -c yarn test './tests/eosLightClient/test-verifier-in-EOS.ts' diff --git a/Makefile b/Makefile index b49671103..bdb61fd5e 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,10 @@ build-relay-image: docker build -t relayimage -f Dockerfile.relay . +test-validator-accumulator: yarn-check + cd beacon-light-client/solidity && \ + yarn hardhat test test/ValidatorAccumulator.test.ts + evm-simulation: yarn-check cd beacon-light-client/solidity && \ yarn hardhat test test/BeaconLightClientReadyProofs.test.ts diff --git a/beacon-light-client/circom/scripts/validator_balances/get_input.ts b/beacon-light-client/circom/scripts/validator_balances/get_input.ts index d6e0a58d9..909439428 100644 --- a/beacon-light-client/circom/scripts/validator_balances/get_input.ts +++ b/beacon-light-client/circom/scripts/validator_balances/get_input.ts @@ -23,7 +23,8 @@ function getValidatorTree(validator, ssz): Tree { return new Tree(validatorView.node); } -function calculateValidatorsAccumulator( +// TODO: fix so it matches the test in beacon-light-client/solidity +export function calculateValidatorsAccumulator( validatorsPubkeys: Uint8Array[], eth1DepositIndexes: BigInt[], ) { @@ -41,7 +42,7 @@ function calculateValidatorsAccumulator( ); } - const validatorsAccumulator = hexToBytes(hashTreeRoot(leaves)); + const validatorsAccumulator = hexToBytes(hashTreeRoot(leaves, leaves.length)); return bytesToBinaryArray(validatorsAccumulator); } diff --git a/beacon-light-client/circom/scripts/validator_balances/validator_accumulator_description.md b/beacon-light-client/circom/scripts/validator_balances/validator_accumulator_description.md index db0ce4709..2ded291dd 100644 --- a/beacon-light-client/circom/scripts/validator_balances/validator_accumulator_description.md +++ b/beacon-light-client/circom/scripts/validator_balances/validator_accumulator_description.md @@ -6,69 +6,129 @@ A Merkle tree accumulator is a binary tree of hashes, which is used for efficien This is a sample solidity implementation of the `validatorsAccumulator` ``` -// The depth of the validator accumulator tree -uint constant VALIDATOR_ACCUMULATOR_TREE_DEPTH = 32; +// SPDX-License-Identifier: MIT +pragma solidity 0.8.18; + +// This interface is designed to be compatible with the Vyper version. +/// @notice This is the Ethereum 2.0 deposit contract interface. +/// For more information see the Phase 0 specification under https://github.com/ethereum/eth2.0-specs +interface IDepositContract { + /// @notice A processed deposit event. + event DepositEvent( + bytes pubkey, + bytes withdrawal_credentials, + bytes amount, + bytes signature, + bytes index + ); + + /// @notice Submit a Phase 0 DepositData object. + /// @param pubkey A BLS12-381 public key. + /// @param withdrawal_credentials Commitment to a public key for withdrawals. + /// @param signature A BLS12-381 signature. + /// @param deposit_data_root The SHA-256 hash of the SSZ-encoded DepositData object. + /// Used as a protection against malformed input. + function deposit( + bytes calldata pubkey, + bytes calldata withdrawal_credentials, + bytes calldata signature, + bytes32 deposit_data_root + ) external payable; + + /// @notice Query the current deposit root hash. + /// @return The deposit root hash. + function get_deposit_root() external view returns (bytes32); + + /// @notice Query the current deposit count. + /// @return The deposit count encoded as a little endian 64-bit number. + function get_deposit_count() external view returns (bytes memory); +} -// An array to hold the branch hashes for the Merkle tree -bytes32[VALIDATOR_ACCUMULATOR_TREE_DEPTH] branch; +contract ValidatorsAccumulator { + address depositAddress; -// A counter for the total number of validators -uint validators_count; + // The depth of the validator accumulator tree + uint constant VALIDATOR_ACCUMULATOR_TREE_DEPTH = 32; -constructor() { - // Compute hashes in empty Merkle tree - for (uint height = 0; height < DEPOSIT_CONTRACT_TREE_DEPTH - 1; height++) - zero_hashes[height + 1] = sha256(abi.encodePacked(zero_hashes[height], zero_hashes[height])); -} + // An array to hold the branch hashes for the Merkle tree + bytes32[VALIDATOR_ACCUMULATOR_TREE_DEPTH] branch; + + bytes32[VALIDATOR_ACCUMULATOR_TREE_DEPTH] zero_hashes; + + // A counter for the total number of validators + uint validators_count; + + constructor(address _depositAddress) { + depositAddress = _depositAddress; -// Function to calculate and return the Merkle accumulator root of the validators -function get_validators_accumulator() override external view returns (bytes32) { + // Compute hashes in empty Merkle tree + for ( + uint height = 0; + height < VALIDATOR_ACCUMULATOR_TREE_DEPTH - 1; + height++ + ) + zero_hashes[height + 1] = sha256( + abi.encodePacked(zero_hashes[height], zero_hashes[height]) + ); + } + + // Function to calculate and return the Merkle accumulator root of the validators + function get_validators_accumulator() external view returns (bytes32) { bytes32 node; uint size = validators_count; // Calculate the Merkle accumulator root for (uint height = 0; height < VALIDATOR_ACCUMULATOR_TREE_DEPTH; height++) { - // This if-else structure supports tree balancing - // If size is odd, the new node will be hashed with the previous node on this level - // If size is even, the new node will be hashed with a predefined zero hash - if ((size & 1) == 1) - node = sha256(abi.encodePacked(branch[height], node)); - else - node = sha256(abi.encodePacked(node, zero_hashes[height])); - - size /= 2; + // This if-else structure supports tree balancing + // If size is odd, the new node will be hashed with the previous node on this level + // If size is even, the new node will be hashed with a predefined zero hash + if ((size & 1) == 1) + node = sha256(abi.encodePacked(branch[height], node)); + else node = sha256(abi.encodePacked(node, zero_hashes[height])); + + size /= 2; } return node; -} - -// Function to handle deposits from validators -function deposit( - bytes calldata pubkey, - bytes calldata withdrawal_credentials, - bytes calldata signature, - bytes32 deposit_data_root) { - // Perform the deposit using the DepositContract - IDepositContract(depositAddress).deposit(pubkey, withdrawal_credentials, signature, deposit_data_root); - - // Get the deposit count and increase the validator count - bytes deposit_index = IDepositContract(depositAddress).get_deposit_count(); - validators_count += 1; - - // Create a node for the validator - bytes32 node = sha256(abi.encodePacked(pubkey, deposit_index)); - - // Insert the node into the Merkle accumulator tree - uint size = validators_count; - for(uint height = 0; height < VALIDATOR_ACCUMULATOR_TREE_DEPTH; height++) { - if ((size & 1) == 1) { - branch[height] = node; - return; + } + + // Function to handle deposits from validators + function deposit( + bytes calldata pubkey, + bytes calldata withdrawal_credentials, + bytes calldata signature, + bytes32 deposit_data_root + ) public payable { + // Perform the deposit using the DepositContract + + IDepositContract(depositAddress).deposit{value: msg.value}( + pubkey, + withdrawal_credentials, + signature, + deposit_data_root + ); + + // Get the deposit count and increase the validator count + bytes memory deposit_index = IDepositContract(depositAddress) + .get_deposit_count(); + validators_count += 1; + + // Create a node for the validator + bytes32 node = sha256(abi.encodePacked(pubkey, deposit_index)); + + // Insert the node into the Merkle accumulator tree + uint size = validators_count; + for (uint height = 0; height < VALIDATOR_ACCUMULATOR_TREE_DEPTH; height++) { + if ((size & 1) == 1) { + branch[height] = node; + return; + } + node = sha256(abi.encodePacked(branch[height], node)); + size /= 2; } - node = sha256(abi.encodePacked(branch[height], node)); - size /= 2; - } + } } + ``` In the deposit function, each validator's public key and their Eth1 deposit index are packed together and hashed to form a node. This node represents the validator in the Merkle tree. diff --git a/beacon-light-client/solidity/contracts/validators_accumulator/ValidatorsAccumulator.sol b/beacon-light-client/solidity/contracts/validators_accumulator/ValidatorsAccumulator.sol new file mode 100644 index 000000000..da5fb4516 --- /dev/null +++ b/beacon-light-client/solidity/contracts/validators_accumulator/ValidatorsAccumulator.sol @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.18; + +// This interface is designed to be compatible with the Vyper version. +/// @notice This is the Ethereum 2.0 deposit contract interface. +/// For more information see the Phase 0 specification under https://github.com/ethereum/eth2.0-specs +interface IDepositContract { + /// @notice A processed deposit event. + event DepositEvent( + bytes pubkey, + bytes withdrawal_credentials, + bytes amount, + bytes signature, + bytes index + ); + + /// @notice Submit a Phase 0 DepositData object. + /// @param pubkey A BLS12-381 public key. + /// @param withdrawal_credentials Commitment to a public key for withdrawals. + /// @param signature A BLS12-381 signature. + /// @param deposit_data_root The SHA-256 hash of the SSZ-encoded DepositData object. + /// Used as a protection against malformed input. + function deposit( + bytes calldata pubkey, + bytes calldata withdrawal_credentials, + bytes calldata signature, + bytes32 deposit_data_root + ) external payable; + + /// @notice Query the current deposit root hash. + /// @return The deposit root hash. + function get_deposit_root() external view returns (bytes32); + + /// @notice Query the current deposit count. + /// @return The deposit count encoded as a little endian 64-bit number. + function get_deposit_count() external view returns (bytes memory); +} + +contract ValidatorsAccumulator { + address depositAddress; + + // The depth of the validator accumulator tree + uint constant VALIDATOR_ACCUMULATOR_TREE_DEPTH = 32; + + // An array to hold the branch hashes for the Merkle tree + bytes32[VALIDATOR_ACCUMULATOR_TREE_DEPTH] branch; + + bytes32[VALIDATOR_ACCUMULATOR_TREE_DEPTH] zero_hashes; + + // A counter for the total number of validators + uint validators_count; + + constructor(address _depositAddress) { + depositAddress = _depositAddress; + + // Compute hashes in empty Merkle tree + for ( + uint height = 0; + height < VALIDATOR_ACCUMULATOR_TREE_DEPTH - 1; + height++ + ) + zero_hashes[height + 1] = sha256( + abi.encodePacked(zero_hashes[height], zero_hashes[height]) + ); + } + + // Function to calculate and return the Merkle accumulator root of the validators + function get_validators_accumulator() external view returns (bytes32) { + bytes32 node; + uint size = validators_count; + + // Calculate the Merkle accumulator root + for (uint height = 0; height < VALIDATOR_ACCUMULATOR_TREE_DEPTH; height++) { + // This if-else structure supports tree balancing + // If size is odd, the new node will be hashed with the previous node on this level + // If size is even, the new node will be hashed with a predefined zero hash + if ((size & 1) == 1) + node = sha256(abi.encodePacked(branch[height], node)); + else node = sha256(abi.encodePacked(node, zero_hashes[height])); + + size /= 2; + } + + return node; + } + + // Function to handle deposits from validators + function deposit( + bytes calldata pubkey, + bytes calldata withdrawal_credentials, + bytes calldata signature, + bytes32 deposit_data_root + ) public payable { + // Perform the deposit using the DepositContract + + IDepositContract(depositAddress).deposit{value: msg.value}( + pubkey, + withdrawal_credentials, + signature, + deposit_data_root + ); + + // Get the deposit count and increase the validator count + bytes memory deposit_index = IDepositContract(depositAddress) + .get_deposit_count(); + validators_count += 1; + + // Create a node for the validator + bytes32 node = sha256(abi.encodePacked(pubkey, deposit_index)); + + // Insert the node into the Merkle accumulator tree + uint size = validators_count; + for (uint height = 0; height < VALIDATOR_ACCUMULATOR_TREE_DEPTH; height++) { + if ((size & 1) == 1) { + branch[height] = node; + return; + } + node = sha256(abi.encodePacked(branch[height], node)); + size /= 2; + } + } +} diff --git a/beacon-light-client/solidity/hardhat.config.ts b/beacon-light-client/solidity/hardhat.config.ts index 0e9c88cc0..b887426e6 100644 --- a/beacon-light-client/solidity/hardhat.config.ts +++ b/beacon-light-client/solidity/hardhat.config.ts @@ -39,13 +39,26 @@ if (!/^0x[0-9a-fA-F]{64}$/.test(conf.USER_PRIVATE_KEY ?? '')) { export default { solidity: { - version: '0.8.9', - settings: { - optimizer: { - enabled: true, - runs: 200, + compilers: [ + { + version: '0.8.9', + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + }, }, - }, + { + version: '0.8.18', + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + }, + }, + ], }, defaultNetwork: 'hardhat', networks: { @@ -54,8 +67,10 @@ export default { accounts: [conf.LOCAL_HARDHAT_PRIVATE_KEY], }, hardhat: { - blockGasLimit: 30000000, - allowUnlimitedContractSize: true, + forking: { + url: 'https://eth.llamarpc.com', + blockNumber: 17578101, + }, }, ropsten: { url: `https://ropsten.infura.io/v3/${conf.INFURA_API_KEY}`, @@ -118,7 +133,7 @@ export default { accounts: [conf.USER_PRIVATE_KEY], }, gnosis: { - url: `https://gnosis.api.onfinality.io/public`, + url: `https://rpc.gnosis.gateway.fm`, accounts: [conf.USER_PRIVATE_KEY], }, }, diff --git a/beacon-light-client/solidity/test/ValidatorAccumulator.test.ts b/beacon-light-client/solidity/test/ValidatorAccumulator.test.ts new file mode 100644 index 000000000..47ccb86a0 --- /dev/null +++ b/beacon-light-client/solidity/test/ValidatorAccumulator.test.ts @@ -0,0 +1,1047 @@ +import * as path from 'path'; +import { ethers } from 'hardhat'; +import { getFilesInDir, Proof } from './utils'; +import { convertProofToSolidityCalldata } from '../../../libs/typescript/ts-utils/zk-utils'; +import INITIAL_UPDATE from '../../../vendor/eth2-light-client-updates/prater/capella-updates-94/update_5601823_5609044.json'; +import { Contract } from 'ethers'; +import { sha256 } from 'ethers/lib/utils'; +import { hashTreeRoot } from '../../../libs/typescript/ts-utils/ssz-utils'; +import { + bytesToHex, + formatHex, + hexToBytes, +} from '../../../libs/typescript/ts-utils/bls'; +import { expect } from 'chai'; + +const depositContractAbi = [ + { inputs: [], stateMutability: 'nonpayable', type: 'constructor' }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: 'bytes', name: 'pubkey', type: 'bytes' }, + { + indexed: false, + internalType: 'bytes', + name: 'withdrawal_credentials', + type: 'bytes', + }, + { indexed: false, internalType: 'bytes', name: 'amount', type: 'bytes' }, + { + indexed: false, + internalType: 'bytes', + name: 'signature', + type: 'bytes', + }, + { indexed: false, internalType: 'bytes', name: 'index', type: 'bytes' }, + ], + name: 'DepositEvent', + type: 'event', + }, + { + inputs: [ + { internalType: 'bytes', name: 'pubkey', type: 'bytes' }, + { internalType: 'bytes', name: 'withdrawal_credentials', type: 'bytes' }, + { internalType: 'bytes', name: 'signature', type: 'bytes' }, + { internalType: 'bytes32', name: 'deposit_data_root', type: 'bytes32' }, + ], + name: 'deposit', + outputs: [], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [], + name: 'get_deposit_count', + outputs: [{ internalType: 'bytes', name: '', type: 'bytes' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'get_deposit_root', + outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'bytes4', name: 'interfaceId', type: 'bytes4' }], + name: 'supportsInterface', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'pure', + type: 'function', + }, +]; + +const depositItems = [ + { + pubkey: + '0x89bcf22c91a560d95d09c1192664eea1baab0780b6d4441ca39d1cb5094b177b17f47a67b16fb972bfd3b78b602ffeee', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xaf92ccc88c4b1eca2f7dffb7c9288c014b2dc358d4846037a71f22a7ebab387795fd88fd29ab6304e25021fae7d99e320b8f9cbf6a5809a9b61e6612a2c838cea8f90a2e90172f111d17c429215d61452ee341ab17915c415696531ff9a69fe8', + depositDataRoot: + '0x757b092b9157a2a946ebf5209660433a71ccabe15b50dbf0cfcc21b9f090e1b5', + }, + { + pubkey: + '0x957882961f53250f9b2b0ca1ad5b5f4fc1a89c3a55cd2dbba3df9e851f06c93e9fe2e691971884a269d4e40f3d054604', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x90b6e69502e7cf0bf1f385d121d1f60bd57d83081fcf96e130a7abc2beac046e1e28ec360e5455d226602d6ddd2eb39c162f09bc9420271eb8199c891d7bb52984a09fe416807ff7ed0eddd5eeeb2c07b13b38afafad77ec4f109828c8a73587', + depositDataRoot: + '0xe3d15b9aaa074aac4a55583a13f463d6b565ed8e4b1366c203616e75642ab2db', + }, + { + pubkey: + '0x92d0fcb9349a39352519c9f3930916d7c36ca3e4f8610dc41698622becddb39ea0bf27173a56233474ef95cb7f035f80', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xaafeee8adaf0b486d14c7eefc9164b0e0adab47fd9014c604bf629955185e111863797a8e9a6ade9c387f79daaaaf8530faa8cfd6d4d6e9964e206fc02618f5b0bb8a497f5271d0e542cb5d3bb27701cb5a38b1d65d278ff931ed1057f65b684', + depositDataRoot: + '0xc4bfe4fadc951bdd1ce9d63d9c65c9189670c19c6d535be5ca121070b7138855', + }, + { + pubkey: + '0x965e2f75c43c93fc7b5efbc03649f13b5bd18bd1fd02a6294a6941b314989c9a5ba729276c2f3981a763d008f1957fe4', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xb792cb5952280a52a23b14d39158911016214fda575b6884fbaa8b66d29a7fa55d8909380021a38410f4a2b25edb47cd0222bb9d175ddfe4e6545b58d5bcd0b099d6193db5e8d161fac6c0292ae24aac0e24fa2a17484e2112e89ef505b25a46', + depositDataRoot: + '0xc004a0e0c4a536077caacf346c1a868d6ba5a605a40f80d9e4d0e786d3324bef', + }, + { + pubkey: + '0xa7a3e154aed45c46b01953f74695bf4a0ee50b15ad0f89157dddd7d8783fd3bafb1ad7c279b2e57e2c58071162c35e81', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x8ae6a82e2a51cf69dc962c08b65a5c6d769ecdc47bc518a6d3d8f65525237e03e09f154159183831296f65bdeae47be506f0ac5bfaa9f8f95c081c2d9318d55a84f580b2dd3ee8b35a84d849eaa01324065cd32785ea89850ce761bb91cb107f', + depositDataRoot: + '0x9713ebfa939e06f42066ddc605a0a866eb75c4d7bb78091588273a8c8c70afbc', + }, + { + pubkey: + '0x90e25c49b32bda80d9d07738f01f7550f0adbbedf598fc34c5bb7b084fad6f38cebf39046d79f51a1ab99526e1cbfebd', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x88411327903f1f341524e671284a9c5b0df540b5915515710e51bf3f82b254abba36d110b3571ccccdd5d0fe3921ad4512f1fc63b493d5afe746cbe349440dceebee8a6a6cc13607be82bf1c93e94beebefde23cb078515a4f575eebb80f4bb7', + depositDataRoot: + '0xd462d74e6425e06ca174ad3ed805a5742c1b87404c6ef17dd8dcd810e3fd6fa9', + }, + { + pubkey: + '0x81d30decfd9ef8fdebc115998be6f6d36ad48d29defb31a19d7f4eca9501f2bb467a843203aaa4a0a9df25cd2e1de9f8', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x8dc3b898805de91fe98da49f3937cbed88b8fc1450734870e792082873346de2e976683bc7a02e81f0d5e8afc625c54a00a697acbcfcc1ad61c8577dc3e26a647806abcc8c11ad327c3b6382887d8537b28e17673e74e5692257c16ef318ed4f', + depositDataRoot: + '0x5878b7d122477ecd4c30cfa69ac6f6ae3131435b17a9244f15d1c09c7ca9b618', + }, + { + pubkey: + '0xb08620c051d972e6e74613f3491933a32c6fb7244de106d004eaee230299bd019164874ea5df124560a467f8888e43f1', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xb61357a9a275eb09c1c00f3edf69d18d3a54c0ea9073a500a242113fffb59b0da579bc65f48580a5969e45c53352ebcd02d6e8240960b89f8da39b338a5a5a851e6156ef8510a9ca2facd6f274745f73ec80349ebbd8248a13afd5362f26c4ed', + depositDataRoot: + '0x2e60d40c133d6e8e159787089936c392b3018c09bb861d45dd0ef883fe2097ac', + }, + { + pubkey: + '0xad6ba9d6b7e87373568b42cc3b8df4717812092c6f5ea91dbd72b59c827623bafe3999ca7fec5f1c4af8b66b305c9b13', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xa09cb7d15872bbd62409dcc96e04c92fa7419098ed7108a1d7b9d6bcf8cdb9f8c27123b9d20ede944eeef47c01bab2180dfdd6cb3381259135100a57d8de48a2f70d5f681a13f1cf98e2b1a78c6420910132096713dadbcca17cf9004bf97052', + depositDataRoot: + '0xca97880108c27ab520daee9298aa04abcbbfb5111d3d7588b39af2eabfbd0b96', + }, + { + pubkey: + '0xb79c926fb0e5dff048b2a8a89506c87a317d0fc7318c8723f67b6518617692df0ca02a3679db65c34f6a8041da4ae961', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x9815aec7424bc1918c1e0e3b2fa1d1e77ea5609e3c29485a281b6d83812a7d023d703e061d4cffa78171d360544e361811e1746bb90fbc010d16310e330103c8fd8378b5f9f692a1a5153d69459e3955a97fb170f3b4ba47d3acae2e471a7d4a', + depositDataRoot: + '0x5c1643e2c735ad3e493efdc154192106d442db19b5b9b8c5b87e62b327e50637', + }, + { + pubkey: + '0xa3f714a37e0fa87a96256bf58a0ab29c156148131c87fdfefee1c8201025ce3fafbb97a3fff67f77e454df622e2a9bee', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x8fd9712c371b18aa5d868bf191576d5cd1da84f07994086ca15374d400d5f4349c0547d303852663371eb547b0e44dfd0b3c6dcec44d64fd709e990a48cb03c3228e46fa4e5c272608ba6d73411c44b31d20a4edce78991c0b07c08875fb587a', + depositDataRoot: + '0xa11bbce086b7d3394a87d9f0a7a4836d317033eedda55cb099d969d4fea31b76', + }, + { + pubkey: + '0x94767f1d73c4cd2e0588c2fdbcede391ca26977f78522fc9cdf9dbb519244df7381783c54bf822aef872a59f73e3dcd4', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x98c4039ea7f696aeb8a2e8d941fde3fd779522dd42af56a149fa8629d276639ea446f2ad1bae8e18543e1ccf54afdb360911958d9d96749a5c3af6fecd687c99bd2579adc00c6b2fbde9aedbf93e50062c7dfb5238dfdaad0a35503afb921c8c', + depositDataRoot: + '0xcf9613088b05c0420f02432c380f9f234eef3ab5f6f17a42b1152a6b17479ff1', + }, + { + pubkey: + '0x900ac4c458401824a12023d1cbc71684230de02cf5e86369657f7de083079d54080bbb6a22c46e11b77a2a8ed80c4798', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x8cd1c985e861a18113f8c76b36947ad3b56b0b72368c6d739d7081a804aa0b23d6d5af53af65e7b4401814c6a012288f145fea62c55d143bdd4a823158790ea131db415ea31807c0e14e45ea6bd9ee9bc672e24a4a13636e5e5eaf021f3d04e6', + depositDataRoot: + '0x69cb6592f039ea2cc27d2350e98beeb5a5f895b301c3cbda4cd213cbf85fd193', + }, + { + pubkey: + '0x89f36f1f4f86ba98a899ab021ef39f10e9ac761e8e770e99be1b90b215a14d9409f946cc93d1b1e21b00b6de2a79445b', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x95bfd017dea1ec956310461f0bb846f094d8aea6d9111ead55f16269bc25257cec31e5bf561ca2b6aba26cfd5fca67010fe2d32a7bfb6cc69b68d49625a3038d7a46d4eb053f7a75bd2ce3ffd9dd48ff651e0956e5270330a88d6d3eb7e04bbe', + depositDataRoot: + '0xcff086cff1f83727b7e135b7a133755cf67277fa32beaf65c67ebb0f94cbfd96', + }, + { + pubkey: + '0x8b85c0e1ebcf9a8e6980ef94fd3933db8144916fac01eec83f7f7de74df9ad90923b6c57cc9744da2f2e078a230cf708', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x93e4c6b4f3eb4181036b6c43d9f0a7ecb64f590497c75d5add9c7be92da68a5918e9521666cefac59d4e3bcb8e4059eb07b57144f6803ac732a75fbc61388f34f5680c2edbe427ee85b23bcdf4467868a1fb87fba5c613289555765731b44ace', + depositDataRoot: + '0xb35b88b53cd8d73ae68a20856f0a03719efd59da21c627c08346a547c29d5b2f', + }, + { + pubkey: + '0x9175495df91ea6bce297e1e8b6fd3dedf4d38b68ad3098ad741e495abcb592a24becee47e75048ce43fc6dd9ca8c4c0d', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xa3bb7be5f60b6e1df64cd0d3b63afd280f59849515c96b52bf48a0fda0c75897ac812a395e4cec6fd3590adedd99a8dd164cc6b5d39b4f4c95e69893f02ff07764976cd5ab0317e1b050b6e69db241bc06be42244d204edb265756d46f48e5b4', + depositDataRoot: + '0x19f5b694738e77a29b9f6bdfbb25c14be12a853fb8b891efcb8ed32cd8994ac1', + }, + { + pubkey: + '0xa462be8b2b9b616991ac4ebea15cabe09de067c76ad85fd81a771f34e56efbb30cc7742f80464edce56b0e738df67f7a', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x830c823669d2f3b0834a03c864dcc4cc80173d41025dc61fb9d4ea908afd03895fa4712d94b64d1e2be04124ddadfefc0e7edc4abc74b3cbcf5b9486c12533748ac824381b3a60c74bddb927a7941fcc422456af6b8dc4a09f7ef60e4716bc3a', + depositDataRoot: + '0x749ede17afb7414cbaf413d2c5c439220be90cf0b751a6334337493247131762', + }, + { + pubkey: + '0xb13902f76467bf13710a77f8c8b0028beef845823426237b91cc066b462794a8b70785002475900844bdd9b820608cd5', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xa1450df77809a48b24d7ecdda42c936268cd6540a595beefb54784db1e38d9cb76c41fbb7d23c29b76666f3b9d1756191578dd67aae5679d5d3f6c50e583a6b39bd1de7bd7865ec18c2c1a8e75ed3524dd7ece8ace9026ac75f5c57fed7c70df', + depositDataRoot: + '0xa2dc07230095c4506ca4851cf595f8a197cc27a2fb8704059ff69d3191c6d40a', + }, + { + pubkey: + '0x966e99e202db09cfa407cedb176fc692ad620474ec37c2bce23fdb1c565b1f50bff989245200e3b7dd33edc8c204c938', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xb39521083226d7b13c4bbbe5f749f6fac5104de6742c9088f256d5e4048b9910042e097c5846dff50327593ee9e4324f0295426ee43972ca9bf261e1932bb020ed3b4bf66e495b5fb9ef854e11f159fe53cf601923f5360e80efffd235c816c5', + depositDataRoot: + '0xe5e380e59ef85764ebb7837ba1133e50f6fa25e050deaaba078b62a68a9c4dbc', + }, + { + pubkey: + '0x8373ace9d9201e08f0e424722ed4b68f2b236c0ccde0f82cfa9e87fa5fcfdd09eeb057d0da88a10cbd07f187a888c073', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xb849fad5b877a8bd1176f4a0b313b0ea6cb4ce38b1267525c5c0b338fed1416130e0501a68edc0520f6baa71d9cef9610f399a645f8f6d5611d77eb8229f2892a5994eb4331026f2c957fedad26e26a58164ea6c896ba9c3f279f01d2ccf6e6c', + depositDataRoot: + '0xe8743c77286dc9a3cd373b20d703cf2d9714949788d6fd3ae482d1c29da12702', + }, + { + pubkey: + '0xb4e215f7e7dca63ec0cfa8309e1f852892f50f2c90873082c04cc2b73b4b968abb9dce1930e1888e8fd949312768a517', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xa73c20b1bce035a81dfb0118896b2ea795e01c114fff464731dd14c29e5aa37e200fe8816a5b71922dc820f42312be6c0befb90717750bcea2165fcad71d47ad15db84c85cff0c3b43d5ae176ef2b555aedeacff62a0aa54b09f382cb42351ff', + depositDataRoot: + '0xd1be80ab0a2c9f6cc1b45555c8cfcc25fa1f9c8d26ed0a37c8673201aa0afa8b', + }, + { + pubkey: + '0x8bb50657366de1bbd904b53763cebae471d171888c887cf769a823d88704e413b4b0f59921e313c291f05aaf092d343b', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x84922c523d337ea189210fbb9ae6af79af61d2eaa9e2f6b2c875e31c97ee617ccc304e7f98782b312fecdd0fd86b60c70b3458dea5ce892b5c2d037d6f02601976fdebd22e4fe9c46182347da6f92fe82ae0b027541a89d1573b2d34f5fd7fcb', + depositDataRoot: + '0x51036d18c80d4a7c6c680582ed98d267081b3920103252f599f6398490b3587b', + }, + { + pubkey: + '0xa00f9d801ef265436ad251c33895667bab7e5e0098d945ad5ba99eb576dff65adc8295d2ad44c78827ad911bf2bc3d86', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x86528f09304a2c87b41cd8812cc6b4a44ebcb079549331f3723c353bdd87a35ff62b587520fb0d6fb3d6cf34dfa2103205cef4bbb1d49b488464e1a43c0d2bd11c5385a4d7adc352ab67abb6fa0135f93d429cddd39695c3c7a192af38898e44', + depositDataRoot: + '0xfc409460d51d097e7b55edf8b42ed7964623d152a19e851bad26cb0b0c190f3d', + }, + { + pubkey: + '0x8c08481744bf74828f368a583bdc2d8dd6d0d1335a4397c23e73ff19e8a871eda607df33ebe3fcdacd8ed6cf9c1abee9', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x8c1ac6dba7fa04fd6a93214096ac7d952b1ad3dad749da9b594964974dda82911b9508bfcd0ec753641e45072c627f750da0d039e2896c71f908904f2bc50840871f420eedfada10c491c78f24bc9f698f9fbfa51b930e1fa74963d2c4f01a25', + depositDataRoot: + '0x7bb8e59bd9c15e25e07dcbc1d2eac1216a88c9706a9364f2b465821a3cd53eed', + }, + { + pubkey: + '0xa6e9c962abca48b0fd81564bc0f62007ad0f71964c29759ce2ebe7d106e2d10bac08f585ec9459ef275e5e1c5c528049', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x939073b9cd70affe327a1fbc7a208a6ab9e3c33d2fa0bc723eb54843e391c6954c9a0e49056ff9c465247bad7fc8c8bf0ef12e11a7c6dbd144b553757044a17d3703f35ecfdcc51fc4cfb6f971bd186c9995085cdc87d377d6b11931acc3d572', + depositDataRoot: + '0x479a777dab71194b694390d6545f95c5d57294bd86ee8b2f7642966ab57f73d1', + }, + { + pubkey: + '0xb4f7fa7be9751c7aee510d5fad843a93114178fc21155f611c6fb53ac4ff712f1ff8815dc2440e44510405b55277ae19', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xb984f363e279f735b9cfdb9ff92f0338261c2adb42f0d4fee9626d8f58266089ec0f2d3b9da6074819bf4e4d9f6b754a0d3994a819480f2f1a0370a1dfc4013ccb114423bb6057ddd5c0dbed6ab2231233f78ab19b0955f56a9048b2c9bd119e', + depositDataRoot: + '0xbd6243636dd89abe2c9982829091c7dbef74f99df1ae424da05b0b5fce3eb895', + }, + { + pubkey: + '0xa4d8b3541d2230e6add4cc860784a7b82f06742c1136668d79a46186f527cf557e45c51189a41c21d7c54a97c1a55c59', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xb5bcfb34deb16c034883824325e527b32838f5232b2f6a3dc7d04eb65ab1daab8059496e63378503581c5db8e6ee723b07f7cecb2e5271d3d0cf2f809d098f30dd660acf6328aba64fed760e2a8e0a9fa911685977f07eb138c9a4ffbf587a06', + depositDataRoot: + '0x738166674190e18fe4ff7eca6fba2cc9be7796326ca02c49ce15c66a7ac46e6e', + }, + { + pubkey: + '0xa624973ae52339f139105250b68f1aeea61dabd818ddd43471f820003eb97129cd279a27ca109e903f536c104faa17a5', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x93647af0d8d2584ffb228219cdd2c560eef8f5b76bcc42b12cb81eff6a41b609f9af20e5df49d22c1132705b41f7e04606cb7df3ce27b8713a01d20bd1ca00a2deb750d08e691e8278559b2a5a0090587c07d5c5c92e30081dc77ad374fbd059', + depositDataRoot: + '0xdd35f76017f1879040211a386203d6ea4589b49b3c0c64b5bbc6634a6c49c716', + }, + { + pubkey: + '0xb6c098d6f05550ec1f215409d6f684b488927f13a26d2397710c792c9221ded1f9ac5f588434b01726e10581ad6f3c4a', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x8c28a9851aecca30b577fa15e03504ae8d079ece9f3231299976162c9c80c6ef4acfa2bb0a164b6765a6cbb9ecae1b2a12c4fcbac9d3c375c512377126b64dbba74d8000282c816edb7c7e660e427b1d63ee6604b6ecfb59461ed5aba663652f', + depositDataRoot: + '0x73ee8d5c8692567357114fe958a663792b134309fc98751fc2ad95b9e8201dd3', + }, + { + pubkey: + '0xa0d6f34abe5c9df47d36410d3a8f6b68d517d3d2bbcac4aaa4f17d29cd8b618a326cd7eb14fe13af2f4c7927075a9e0f', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x938ebe82a9314597fbaf60c1aa507aa3899f2e62479d3b086b8e481431df0a49fcfcc16fc0a4cd9f48106ffb52b8302115ba5c554a39b54f8fc9a97c2bbd5bbd23c239764d294f830888de1e6195db61f46fe9e101c9a6439e26176578e0f085', + depositDataRoot: + '0xf509089de47badce14105966188e5c9a420f2c377e7d56d2aa9b04f06678a764', + }, + { + pubkey: + '0xa1a374b55950cd4ce36fd7a423a50bdab1246896224859239f920ccd0356cc69eb4598dbfeb15517d8d14c511bc3474b', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xacae5f159a98e3fdae448fd8a2bf7a8cce7f197c0e99cc83176fcd4f77e9e361a42c70a8314da0c203e57983b591e8a7037789cffa86b8e5b71e1aef123aba17c576153c4f688e742cbe49ebf36de3f62eb2556b973e2b1db4d11f8535cbd695', + depositDataRoot: + '0x4d3aec5be99856efd078b8e11c02a807baf6a47ed5b1cd8469b64478d6806c69', + }, + { + pubkey: + '0x9049ba59d8c58c6afaae3ba9dd4520a21433a4b640d3e21fb8ac01bf76db0da7b4a0e503b57cacb33faa8d91e4f6fc15', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xa0ec2ef54400491dccc126b95ccd7ba1c2977dd91dc929c080aa4d7dffdd96853813b6e2f455cf7ce0d2b9cd078f0ff2158d068bf13fb6cc4a982106cc79c37c250fb23150c5431dffeda300e3dacbebe45b7e9d6bac02a7461c93f6cb625480', + depositDataRoot: + '0x7821d47452510ebdf759f096ff3cdd6c70d9fdb0f1902889c9446775519e6b08', + }, + { + pubkey: + '0x972ef891ac655333bc1cf99543dfd0cdc09e10abcf5fee635fb4457553549a07be6fd96ca75418b3c761952775837b23', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xa25d9ad3a4fa2bb96e774be9c1ad47bad90c4d1f61b197d8a756d40cfcb8abd56894e61c4a7e06b100b39c5d614c56c2056cc80f5b25c9996e473d90f384b5ffbfa05a525a9c9694dfc13128df45bab7ef867252655ddfc5f967ab57f1177def', + depositDataRoot: + '0xcef875096ddfd5d018dab7459d7a9e7d2bdbe7416109e118e49383494732bfa3', + }, + { + pubkey: + '0x83201635b83797c4b600306f6c469497d126d71257910314ffff972f827c766fc2552da554ff64c7685c740b5ba4afb6', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x92e67ab1bf26ace00783c026b6154ecf0da7a7f9ac52f872732a07aa609cb7418f06d332c850932009d3289b8f1c8d430369ece513145a3b68b560bbc26020b157f85df265eb175f08958d13f9c88dce698804030c5981967b50cb11941b776c', + depositDataRoot: + '0xb620b3f0938cc03b9047fdeb47e6693f132779443e9c495031691bb7b67cacbc', + }, + { + pubkey: + '0xaf30664280a679cf3205b034dd825f297881bd1e5e4ff7003048dd54fd58dd5983f2e7867a83d27129e84ab97c2ff977', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xa5af3844a980f76e9d02eb0e22025dd60723056138e2e30a120ce6c00d18d21dfb641a5fe314d85f7a0a8e90c3f51b430eef2935c73f3e8814f149e79b9cd71e494c0a8c2100a871e3cd7472446fbaf217a04cb1ead459bd8d78b0b5d7bcd3b1', + depositDataRoot: + '0xde1aad0e6148a1efe85763a24cd90254beb78814dcd736acd77d130207d83f25', + }, + { + pubkey: + '0xa4f3745b1bafb0805c12c227010688956598c5c5178778de34ba400b2fa276fcdecf2fc4179300c500e047e8e02d8d41', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xa772ad562fccda797c80f51189eab3ef1363387f5b4e285b49b42720becb6d13726a7d4287035dded03416cc346056b713eac3664d72e4a5ebe333161684c38882e389d798ba7b8cdbbd1fe84bacbc95952f9f7a0252c480d3db0c4a38177396', + depositDataRoot: + '0xa1ab0ac4aafee4d60fefa44bcbcbc47628159dd0424fcfcec9b517f2be67fd28', + }, + { + pubkey: + '0xa24e76f2e77d5bc884e34c4bc866db378a777e104d8b2ee1243e8f4c9c09d97df784fd317bb3448d1d44b30482c2cc4f', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x8c247b51a8bf443236616ebf01631a50800cd470eb556f97d95ab6c3a0a8d0161eaa049ad0562b9291b84f8c21f651810d756bfbc187a59edaa6898fea39996c778079d7c9188d14e82c6d164b31fe28ade18aac8b1d8798276ea23ea2696bcd', + depositDataRoot: + '0xba84eb151ad0a0dc23acb2c6b845e5a2e8c1011d582103121bd4281c5017eb8b', + }, + { + pubkey: + '0x84aa94f113104113b7b02732cef95911bdcf7bef99010c272f3f605310b11fba01a7305c7e7ba11fc8f87a2f44e1ac31', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x812480b17cdeaf305edc72ff5dcb13d1a9d2d750f052348da9e760f0d89c7a0b7084c47bb21ee921dcea1912c47ac2551563fbfedca768389d4ca3a8b3fb88516b038205045ca29658b7e983f8ebb3169c31f7cb10fe54e7282f00cd7953bb6c', + depositDataRoot: + '0xc4e8504874a426e85d5e4063bea82534e8cfe9aaf0ccebf61eac1099ca76926e', + }, + { + pubkey: + '0x928c6475e450b8b8d70cae68189229bf35bf5c7b0ac72a72eaa1657f82fd5dc9adbdf5b060f41575aa9698976e16ec9e', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xa897534b779899129579aacd0e787ac8118c724cc92f3ae7723616a859bcfe8d70353c74d2e65377d1fffa06205879fb0860f5d29c6beea742867f09c83359a934dec704aae142bbc77dafda164978782a99195312a7e1991904ccd4b9ed5de6', + depositDataRoot: + '0x3d7eee2804b993b96e875abbdacfbcfae91e3d0402259fc28a608b07654c68e4', + }, + { + pubkey: + '0x867bfa6fee3a93fed71b7ff065e465d33f332502b083899603ba7ee38977e91037b6efd08fe0bed0ee19c9391eacc0c5', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x99ddbffeaf6d317b600698da67e1bc9903cc6c9c3813c633d03052ce4d248b63841eb526add836e95aa95f62fc0a5d170ab14717f9b3504a6fd273fa046b9ea791c08e10148a711150f606b4777dceac00f2973c70749be91b50aee4ae71533a', + depositDataRoot: + '0xfc8b953f60c8f46afef6ed40c06dbffbe4808300de5fb7738ccce2df9adeb832', + }, + { + pubkey: + '0xb996325d00142b292d7496ab394b9daf4a639b7c5328f13a1a806c94510839694ca2868843fc9afe4f2830111c781458', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xa6f70902d8efa72dddb767314fc4359765a2cd7eb3785c39d2f5de37b58ed1cd3fe9e9347f38c0978c72cc4342192ee202153c841137845aa64f09a32e2b55154f7bf790423554df697c7115e638354cfb8d0747e1ef94b976ca1b4414335333', + depositDataRoot: + '0x3e19cfad789fb293b412ad27704f709d92437d9d7b26174e02d96658d5c12a2e', + }, + { + pubkey: + '0x8c3c12979805edd47672325d71abe668f41af144add0207184d662762f2dd02b2081cf373b7dd805e4ed2167e456a44c', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x83725eb631b8e4aedb19b5f933ed77a1c7df16f6bfc81914ca5b150c5d788e720514898445a0dbb114a779a0cb2dcb1c0c388400a2f908edf2fa7d9783d1524445b9eb40a211d522698dbf1b808aaae55a4a0943566c7662b6f1515e1ce02e3d', + depositDataRoot: + '0x84db6f103e56f587275b602faa0716e511981f6dc398a2737ba08aad8574c578', + }, + { + pubkey: + '0xb0843a4c9c43fdc96b6c819b6a9ddc16a9175ab405278381c20830b62409b14e61c42fd07855fca886b4b51142a5b649', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x9290077b1f20b1bfc25920ad9b9d83c673366efb744cde3d09005c5e0ad6955b8e89f91ca3da929cc27923a02f34c44e0ce3974155a5709ba0071d03b97173a5f150ab2726cee2ab0240f6c1f68338bed1d0e2a08a1bcc9f4bf78c7d25e9dcb2', + depositDataRoot: + '0x2c85b3df635819ad21fd8297b6ad453c729f3f4011d0d6444c70237f57fbf5e6', + }, + { + pubkey: + '0x90d4d4d5b3180c14305a07a7ed8e418a1a1a6169de93a11b38011b80735ce6546e33825ca2aaf6d7fde36c30a47db28b', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x9451f9cf00ebe8e705dcc83d86c269a1510037c44fa80bcf526a6541143fb5d858487445397e026e6184987ef9c801e10fcdf32f316af34f9581a54d6207a7dd47349ac73d224e0c4dc9302b0f5793fc26e29d2c0cfbec4c9f6edc02654a30f4', + depositDataRoot: + '0x5e3fffcabfb9f97388bc47f81df6d1850080867f616d6a3722f15c469860e33e', + }, + { + pubkey: + '0x98e1f977d2261ddabc3d281627f8b7f36b973b0d66ac9723c243da6cdc2c408d53cba8a6b8dfe298a5d396d19596ecd7', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x98c480eb2508dced8e41b68c7427d6ccae3481e79ab7f54e267faa1f10637978f810b84c879362dd7ec5cac9920c857c123cf09092ca9960c15e52b87fc38e5249f61b7b7b998d87beb8569f580e131842b1f531a811e068db06593d5e534a9e', + depositDataRoot: + '0xe859beb3ac42a3caa9fc4f4a75aff4698554309f32ea0a44284a7d0284dabd76', + }, + { + pubkey: + '0x9348651b6582f78775be8afa4e94ee564089a1da640e5347060f6a4b54e30ef8c3c7b024a51e2d9b8c8a557abf724640', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xa8992f24c3e349714ff0211a966ed07f9bf81803d6a6b5dc372c15d5bf55fe913c7e78c1ade9c40dd45baa65906bd42f087656b83f490a0f50d43e95a62d7cb04c6b2df4e4e31886a0d8408bf72764c397221e2c771a3e150db52738c67893f9', + depositDataRoot: + '0xd376c75c38641b4c40bf8cda170ea9b0c6f7bc653375804ebc23802388ac93ac', + }, + { + pubkey: + '0x80d88b1861724839b0f88d27205c1d58705855726d6b46a2cd4b7b2f4dc1e3293285681353c87b6ebfa08a3dc284e218', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xa53106415008c640232b99f4c5c21acd9c83695b73a5f6c6a96abf16bce3d0b675b94c9dee3c2c83dc15002c856150da093c2f4bbe904c290c26b9591bf116f17b93a65fe621898d1a8ef7267070059660e8561fe2e98ec8b03974f872ec14cd', + depositDataRoot: + '0xe84a2020d96aa25bc32eb3880ba4ec961d42b2c6e0cbebe6a199df87ed28c06f', + }, + { + pubkey: + '0xb9a72268e4a40088e8d86f591420b0fe898c0c9c0e9da2e2dab94511ebd03ae665e7b91e450183393f1b1d085939aeac', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xb44c3597cfb1164941176e18ee22719b030fa0ce7983d9d67342180f93103f34bd4e39349cde131d950ca670c9010fb00179f71d797211063a9ddf0863aa3533aca92004dbd276d0bd04d0f169d04a351e5abd141c6bbcaae379db3446a2715c', + depositDataRoot: + '0x8f5b2d6989564ff8698d946d8071939de9f27267f99f1dc33213b57d25721e14', + }, + { + pubkey: + '0x97a8972ec398ca98a239744df60dcc3696ad5baf0f71df51c1994e37d4e3853e7ea54895d95503e773c4b1a6588c7d9c', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x81aea62e0778ad25da5fcdcfe084cb60c1f64aac68467db6869a0694356307bb7c046c42fcfb73de4eba52dea6a184180218db535b389aa548780c7d2dbff357f8f70d6fa9b7b08e3d445910bbf87307c4b40638e9fad8275ec86ee4b2d005bf', + depositDataRoot: + '0xfc73c98d151beaaa70457f76ab515d8ae213f57aaabe6dbfd2fcf642807a0ce8', + }, + { + pubkey: + '0x85f56d7ccdca63a3b30118d49314d3adef4001f3730bbb2454863b0f072c6549872c47978f89bd2c1bc5ac5e0843a495', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x83a7aae322e41bcb5aa9dffe8c8ef7ade3760c3af657ab7d780b4e998981b66f311c8e42f0ff9c3c9943d5f9184d95dd0475819100704d70a3f126830b89170680dfc353e24b0714438cbe3db42e19845a4ddff3f050f9f35b181f2405b42721', + depositDataRoot: + '0x57394d0d6e84ff8c2f85eb4392bda59faa4d4d4a2ef3d2aa42c2034da728baa3', + }, + { + pubkey: + '0xb977442770e725d38d62ebf5a179c3f3a35a3c97318b127b85ca5a7c0eb375796ee94499f50fae6deb05bc203f877648', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x9658daf44cbf9ed63293ac2dbc8904df40c4604816bf6125bd8f548a90871264c355908878b7e4ddb8472e8de07e9cfd11623a3a857a417b7c7d76d3b23b7e02ab335add818db9244e4fa6ed1ba9a9a5e0d1e141ddc36641476df79c27591f6d', + depositDataRoot: + '0xd6d7dce52b979ca8d520b8d7ba379071736d37530a782d03e127f31241cbffa2', + }, + { + pubkey: + '0xa98ad562baf8c5b358fffc5a38ac2a1c31a40ad1fdefcb1b855481e5fd24d4796b5097165724e3ddec6db057104d68fc', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x903ff98eefda4f22e3477fd801d6af87e67e0b36629edddf88b6988d27f7629ac44a75e2bf9132ddb0c45a8ecd1f68dc000d9959d88ee9592a8d72797610d3dd11016bc4833c8d9db19bc6e806e116547741dcb8445d6580eb1530e4d837af75', + depositDataRoot: + '0x4e664e7af54a16170b003f702c1c4e1f530b3de02f5c1c5413a66b62e5a41015', + }, + { + pubkey: + '0x9680290d285945351569b9e80c1c517e6a21dca20cd890c762562b5376d282a29ae5db15c6100f406a9829fae0103ff2', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x834009e22c4684978d36762b3aa3873e447de33530ec73e8244307cc60aab8bd2ba61f8ae69c55963dc6642c66fa6a6d1159d119c377d8021b25bd65fa351b3cd13b0bca1453fac94476ab419cfff02f9fcc49a95a12e98276611ae1075f0165', + depositDataRoot: + '0xf0d60e0a87abe9a55908c6ce95d450430ac120e32d470c4d902d2aacae30fa41', + }, + { + pubkey: + '0x90a6dc52c9be3ea6c4760ce1bd8852924bfb2a16a7458aac1574868e8bf6262ead93f7bd5abc0c28eb21276007871dc4', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xa8c274bc21a1df15c32f7fbdc19776b9a6541358cc36cdb044f4e9ac8e2bcd0b45479714b9f6affbdb4e1468eeacaec203c4b30daf4d8f78713a3fc5fca15b30b81e301432edba90a9053a52136a26459ab98b384a5953fe22c25eb6acbbf52b', + depositDataRoot: + '0x8002a17ca41644cc57c8d7583468366ee44abaeae8aed37e007a6188034aa8ff', + }, + { + pubkey: + '0xb0279fc59acd376123f9a4de9330ccc1c330ae820d5ac0d17443f98617e86963bb02fc78f60c6deb4dda808c52e4d513', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x82ee29eb29f5c19ecf0dd0cebf308a9ad1b1a70aa76007875041ec89e3cd2fd6b3bc457f3554806e5fd135452fa537b915c0ce7ea9b614e10c2b05ae9c0de1ed44bb274a25814e5eaea3314e0e24fd869963e48ba32873c0827fe452853b418d', + depositDataRoot: + '0x6301918a55b3e7423e785a50c984359b2138ba1cbfb5a4b3afa2746421f27c1a', + }, + { + pubkey: + '0x8283a2a3fac680fff115303eddc823edf42766050ecbfe3bfa5d8e7ef2759692c85b63becae97966839d407f0df2658b', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xac8340e401493fac6c3c871d0bbccb3133843d0d3c58458073c0ac894f16d5034b0e507eeeab52f61e39b158c2d97e9c0f1a0dd920726a366524601712bf7f54d193ba0e569c8c4bf5dd3d849554ad15f5005a9049579dc157b37b360410e9e1', + depositDataRoot: + '0x12f303d5e7e147e42dd8c9b2d44cffdae26db58f071dce41b6de8f43b0ef8679', + }, + { + pubkey: + '0x93ff1812acac88e8795ed99aec46171efee197ca4af0025364741a194c0d6a0f0bb7d01810b5f7a5c77f7be8f59bcef4', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xb73d5e94e047c0a2150b8a8a04807320b35edb2bf11d8b84de60260f6f988414ea0a05fece79c557cd16274107ea4924123c47e0b7955c2faf375ed1bcab54a4a003bdec526ae19467823e5977e313d19ad5952953dce045d3087af3cf907265', + depositDataRoot: + '0x14ab450ab5452b812e57ca7b2b45a50447b5d20a5b0f541bc991c31a2ec5c64d', + }, + { + pubkey: + '0xb977357369b95d9f7f364cf0236c4389a478a1e86592ffff54f6afd6e579798457a3c9c4aff64296a0b034cf2d9b264e', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x8403452eaba03118156e4a9010e5e6592752c93499e2c93367f66f62055485e0429c3233db251656f5c2eed0c46db36701f37ca905441e2e5a76e96a92340d8e724f8e11a235cf3cd435719d1e4036fe6a67bf8626a1402fb32bcf8723b8e66a', + depositDataRoot: + '0xc7cc1d35f029795df31f4c8071eb841d7e548be0963ab00f26dcd47f31d8787d', + }, + { + pubkey: + '0xa8bed576dcb4c4019ab975826bfee4590056aa61a868134bd51458c5d74324633709e5432fe193d3e1ee0405e0a645bc', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x9845e03c7f2e608f085056731db11eaf8cc2c05c57ed9e9ffaf6c26b3f0ca286dd69bc0a9b3468b8554ae9e4b6d5c67f00b1ca25398af88a5f6cf2994c839a3d8fe53dfd11af45748305a3a91398772fb5eb296ab2e87da2328e593d0b319bbb', + depositDataRoot: + '0xabe0081caeccdbab39eb1a60298f06adaa5f9e5519606ee6156a73b516ba8062', + }, + { + pubkey: + '0x8f97d11db5658a2c13ab427ab75b7d080b7199b978d1df4fa8efe88fa58153bb873e85de306877df5f32eada58faa345', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xa10127f0e14159b2ad5c685c6461272a6e720fc2abe45d15d3b01ca2aeef2ee44e932fe6d1473607808dd028739432c0006b2ec50f13a0f433273b6f08d5759d44d8277aad9663fe80f373630b6c487333f5a57cd7b0310dd858f05de32d8079', + depositDataRoot: + '0xb8010334d99364ce959077fd143be39c7e9e7a26cae42c983ab9f5122f3dd67c', + }, + { + pubkey: + '0xa51521ecc49a47f8124b9514bff1108a412bcb91fb68d665b4e99fe1021e8d5c7b9ae9c12f7053944384b593868c6946', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x877682114673b230fedcc758fc0a2388b3c1e118ab41d906fad0fcc4bd74b145f1f19defe32f6fac9bfc54491ebf0622091587dc0d2f2f3b6ff95a3c2e060f3a66385b9c1dee7af4950c5453f0f4d54e8c87de6ceb828bb1f90a5aac20af9f3b', + depositDataRoot: + '0x65804da937127af18df81788d7736e7bb7a53b387751615665307812bd55d59e', + }, + { + pubkey: + '0x9411b3579efdec6fe865d6d78dc564063a81a6c85b39cd5f0141fed8c590081d5538afe9eb2e29d725974397feb98bb4', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x994931c679fd0542cd0d8cc6f391e1f88830f365f2756c55888254b94be3fa23dfed4d2c0b38681dcb3603f5245462f30f0b69168999a5c32faed2f4b2e44f886030f643bd3e32e6f4e217477f640d90e8cc79e48dcbb6111276b28c73c41d71', + depositDataRoot: + '0x2cbe6a69bbd4606588a707ff0599d4001e15da5d79c22800ea29cc60b1a0f230', + }, + { + pubkey: + '0x8ae257ec2f4e1cc3ec5b7160f09f294c5b78c14b2dcfca5e905c25ad1ddaa0071f4ed0df0f96889ca34da7308d2335d7', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x86effb8be7ba32715bd68cddd5f4554c1446898f15886ed1dc6e413aeb15356fc0d8649f9f1aa5a0b6475efaf23fa7450b883118d536712addc34c5fe2b4e4545f6c14a662ae1cd13ab9c53631aed38ef48e9fd9e3e232c0e06b00ca9dd6410e', + depositDataRoot: + '0x12d45588d5b0f20cc34f94e2bbf4af748813cd4f8b6fc86b0d2596e55a7a11e0', + }, + { + pubkey: + '0xaf2d528d7f12e180334658baf63272725f2012ce5476990bc82eced85ecbe89e01e7ee47e02cb8db9d16c48c5fda6b69', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xa596a04c4d1bc721e6cbbfcf68488580162a644ce0a57c195560137fc4aa17eeca7aecc296843bd8e636aa99d84f0d0a02ca31f0f8e5d57c8373ad6c0b76180b82d27ac208ec75957da52c87fbb17cebf20aec02ff7caf383a6cb37e9f4911b7', + depositDataRoot: + '0x7bb13dccffb958b107ef5a8e56f20e3d4d91e35505e247b3fdc3a31f44dcc7a1', + }, + { + pubkey: + '0xa82295a10363818d8360d014f6cc0d1a6817ad9689dabb5d344418ae7487087c95abde42ec9ae5d91b869cc8d3c97d21', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x988ac3c6713e78b497d6fea053cbff226d7df1f03f8455aceb43cbcd78b734b15cef128b23c1881db3f0c12fa8c2c9a6121e4d336ed2f148ebf918fac7cd8dacb2e9db94252b7c373586e6c480fc854218066a210e836625d27f3bd1b5803920', + depositDataRoot: + '0xfe00d823213e9a456ba8afd5c487101e1387def0b70502d54dd1695376f07e51', + }, + { + pubkey: + '0xa4bbef25dd5aa10d5663fd7dde738f50c2dd026ab2b52e28a5390af11e0baeab8db9e64017d13be84478b4a9e71be99d', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xac8b7f0b2e74f5a6d0c1c27d88b45496560372d5fc1635f503a53d62a44d261c346af0bdad1567c520161d45fb0a33660fb4aa8a6659a0a085b45460f3220f623ab301ab32a2a6dffd191423f2a3ed8a66308eade87e68ffa8b520d1b4c5b271', + depositDataRoot: + '0xe6c8838960eb553b5ca1a819ff8e093b0ec05f2fa7fa43928833a9b8d02784c5', + }, + { + pubkey: + '0x8245a537e592e1e1d01686c5bfaa730327b84e827a18b891db37437f1c1c6e6e27e5bfd3703e00fe4f4e9ff06e5d9cfe', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x8f5928ffe56f11260ea1411ad025de7652aa8d89a7b164b1a8f66bd4f84b2b50cf078921dc0ecdc559994297bf3a250a19b1adfd8745381e641c3c262181434ecd3c4f073810d509662959f2793900d364e2375022b61ea58ed9d19a2f3479d2', + depositDataRoot: + '0x998cef58a606d1e088a73a977c2b746b557ebdab2e1da2be227200583164d23c', + }, + { + pubkey: + '0xafa99b5577d57bf0a0b955a621b017b60593bbcd17e40a70b90d3009a944c405c2b199928642dd6b0541c23df5a09977', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xb21d43931e79a4efb850433f66b1db56610cca17ef05ee4f65a26f2d609042c04c31bd1be37ea75d5fe0a8ee7e5ed09308cee1bcd9a5341f2a3a46d618ba9e47bb56525f4aad955f91d38a45c9b443f3cb282288e3b958b5617dcc3282bb8721', + depositDataRoot: + '0x40adae5add2557c8ed4d0163ba017dd27baedcc2220a6eef8e11eb766775022a', + }, + { + pubkey: + '0x8548f2e2f1b2fdf6b1033b5bf6bd9fa7c2017de000c5f85d0103e16133f3f38e194f303293933123d0ba4fe9744cce92', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x8ec2fba70324d991efc784ee2082bf4a4ec271525927435ed8b0674544628b3fecdd0f46069d69a3055438f4b36f49da0c5537eff0a0c076db003e00fde1198ad527d2d456c1a9443b1a132bf6541a6bea481cd8f2590373ee573996197c4283', + depositDataRoot: + '0x5cdfe6f4099fdf6d12d7202dc930dfdec9d2efccef076ac42b8a0e9f49ccee65', + }, + { + pubkey: + '0x8c74c9742f8c464a8469cb3802b354c05622090bc84272b10be268baaf3762c8d6fa607a6cefc8d3d5f304750439d968', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x803e030f80c219f47cb1d79729b107bd81bf67a50fe146dafaaeb02506fc5a3e5b74f295836dbcc500a79cf26c9f1f521590627b511c915020408100280470323a127f9bd3662eb000e23ef176454b55d1261879b04ba94b6a640e24e054a2f6', + depositDataRoot: + '0x4aabf0c232c3104b2f1627cd5f8e4566dbd87f5e2a5af096bb1ef3a4036145db', + }, + { + pubkey: + '0x82029b3a16aed0b1b58c37f2252b4d7415614cd1ee444f4b9a9b1b1e7a4d8bd2a019414b66d46b63b625f7f5c96d4256', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x854cb318106f29b49f4cced38d7848e460cf0a992ffb5438d03d23c01625c63c45b224d74d79edb9bc1d89402a1266430f6833f30985067cf203158fdc296a6a0598fa8965c3e7bd28463f2418a583de1ec81d960e8d5c568fb88ba189e9570f', + depositDataRoot: + '0x5821fc19effb5a536be7399f21a7ff057a1497341a3db4f11dec76f0bc28378a', + }, + { + pubkey: + '0x8b1ba3b72dcefef5a18082e127dbf5297f971d12f01dc8a58bfb2296826b40fb2687b8acbfc8c3d893e9b1a1f04ad323', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xa2b4349fe7e7aec14f697ba82a62a4c47b6c65b1a4a8dd476a5296aad59787f10083608cf3a6deb70dd8b6d5abb286fe0864b26b3347ad36484dbb7986d763ba992397f70276dd37ea7b1cc738eb799c5892c6c233c9f4431a00520072826a43', + depositDataRoot: + '0x4464a121c10bdb13c75392e166c3f1a0f5f640d90d8f3df26b2d3333b00fa580', + }, + { + pubkey: + '0x856be8761baaae096b0473eddc93e1e99910bf0c1b850d22f30881dafbf7ae74eebf6dc7cc6d4f70f01bf00e202475fa', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x912365d4aed2bddcfc533d9d9587606f2cac7e1c48bac8a9eafcbe218eb1f09a7fc35d17fb3ed64eeec4d2e4c022a93801bbaadfcbae52b859ff2d032577b98bb98c7d374092f706e7b2f8399616932b16cb9ab7bb43d8df585fe1fe7a1c0124', + depositDataRoot: + '0x0ac97ced8ecc2237fd301e69894feeb85de71da08d40e21ee31529d4d9d7835b', + }, + { + pubkey: + '0x8794f2a3ccf056ac37e00cb840c25c1b60416fbf36ff7618d76403c6975096baeeb8ce3899f38bf605e747e30de7aab4', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xabbbfe9b867b51f38f62ee73595d3b33fae281d064e5a3af9b9a4ee47c33d413e328cd3f43181de5a60a6c69dde312f519db98d865cd52e942207e7de040b9db858161f85b33d57732a8abb540b9073ca409cb4a52e5b50634e9e5e445ef916a', + depositDataRoot: + '0xf69b17a90b44ec1bc5329ea51d6b59f879d3b97dbbb5dbb4371e3d24704c9fe5', + }, + { + pubkey: + '0xa0efa257a4181b195440dc3a1a12b734d32fe7a5a9bd2530fc06d438f56742cb3b979d1b181a674052abc8b16ec0caf6', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x8c6b16f8ff0827524fe288ab9a26b9a93bb693db8783420d03b4b5ca569a12cde66ef7e5879a84b4d374af940a5fe0df1379c09fedaa7a00229edfdc3d7a4ccf2aa7c1a80fa273782854b4303e3bd21fe2daa97f37bf97db6e2328b47b4cbbea', + depositDataRoot: + '0x1ae1232267d1fe813ff6a1d551e53386ba8c68d8107982a5e987af9609750fc6', + }, + { + pubkey: + '0x883ca1959878c4fb8ec57d91e8c4620973374411c5a2aa8071ebcc29f9310a5840768cb2efae5382ab82ac7d109f13b9', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xa05c551e30ad904cfd49b78fe4e8609123f6161c4b9738c2c606ebc111594ff569f33e3849684124dbc4e94ea9b104df020ddd885786b482487619bde3c51d55f376e8a77f17b9157a7bba4c7f5098746d615e207e7963b80bf49025eff07ed5', + depositDataRoot: + '0x876f11b5e5965237a8359ea937806e80360fae3b295b15bb997b9194701a22ea', + }, + { + pubkey: + '0xb6397284a5218013fe98172d27be3723d247d6c9f7f117cc250900fe560f7b5c20311c80264ceaac415c8f254c4f40dc', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x83f118e22e2b042eb83e91400eb624bdc85936c7c25dbebd82f20b98a5597a1a5d391e3dd71f9bd0d90bcb456ddfc62a064bbe65f29e18e6ae72535e7130c6878d420f8611e41c286e0454c2c4a4c0fc57b0909b435496934f25c336a9dea5e8', + depositDataRoot: + '0xe846507ab8b2a1f3233d0197576234ff447eb3d75e60a0911f51c403b9350260', + }, + { + pubkey: + '0x9107618fb9ef426c532b27bbc7f61cc8f7c36b4de0a34f18a116eed1a15ce159b11fdc5deaa7092a66b7debc029883a0', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x9032d242f173f1bf1428bfa34dfc017e32b6a8b085f628acba9d91c0035115b5c54d6663b433880682b93da263accc6212ed2c999e3471c63848199366c5facf026a82920aefa4b3b45503eaf09ad99fd2a4c51f7fc074864f2ea3655994721b', + depositDataRoot: + '0xae47feb399f1c4dcd580c72577c971cbb0cb4cbfbfb35c29d0e31736fcdd52c9', + }, + { + pubkey: + '0x97f4675c8b33872d70e9189f89aacbfc6a2a2b0033f2b1a4d02b422fe9dd4dd01fdd16efb391e03763b69c69b91e41bb', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x83f95fda2e90ef217bbda7c1125247357d7bcd08a2052f22e25e8ace4f3305f4385b466f6abffba68afa01e64ae1342712f64a5786c9e0d89f00db7aef8b666ce9a2583a188b352bfaf375bdfeb6af0d0b5f363fb118590972889e223666eb19', + depositDataRoot: + '0x996a78cc473784011ff167bf7c4a831b52923e9b4144361e87d91bf07d075696', + }, + { + pubkey: + '0x94c9d809a78def0a7542f995a2e30915f6f09576b1c99a503eac1a40f31266994ea331bee6e9e787172852282b24cf99', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x835411a188ab9be5d61375879cb191aaf9e158814e9f0ec8c8d32068f3cba678b0d842f010a1712a2e96836480adbf4918e5fd6c3f080dc3a86318f6c308d12636c7fdc3fffbdfb95812728af593f382060ea89276facd840c615f47a3fa2bd2', + depositDataRoot: + '0x36d3bc7d9ab0f7aee133e93f074925bd23bb23444771b953d230e893af487865', + }, + { + pubkey: + '0x881466c4ede19c0cd04b57d735d19143edf6141f67f8422478a161a3aaf1b9294f53ff2931184bb005d6ffef723e55c4', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x85a8959210b3126ec116d751113725eaaf74f2d611041facfccdc67ac92b8f1c666a649d717271da8fded95fb9b4230801d450a8cb087c25928e3936709bcdccf1f36916df2ca9b342ad9734480f6cb7309e8f26dd489bbd6139dfdd965c2c1e', + depositDataRoot: + '0xcf55c58cd8963413e9a10243a2514fb77dee565c01ed1acd4d05e7bd8ab850a9', + }, + { + pubkey: + '0x958937c1059860821de619e6ee61a647ff33523d670806ab1aec8edfeb13faca944a612ebfe0a359fdc596d70e0b2516', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x8041f8a26e76cbac8e3d53330968a80bca2cf2b3e05aac369a5819b34a9c1ddd041f57667655dc1660a8f79c53c2fe80166cc4859ab783b81705d43306699dce3b3bb997b1b5bcd09c3900057b38b945036f292976a607001125c805d1215bc3', + depositDataRoot: + '0xb40f33b765d67893ac8149caf5a15ff804c17ef4dfca3ce298030394080e7e18', + }, + { + pubkey: + '0x801f5200ccd592053ba6e8fc442309c7bf5d5a7c89b4ae0813fdd0d75e30939c77c108445cfc50598fd9d0eb29207a56', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xb5decddd9dddacea83e74f17db3bd35695d843019de63c9b30da4d95fc235fe90ffb1d50eaa980d8abcb96b6862c7855084ac22798537b44ad8610750c5fd145e9fb9b6c9d621cc93d8c83aa0d7643aecf58b6ea930df2b4be17072b0204f05f', + depositDataRoot: + '0x292f86f3ff84574a016f7c61003be70648865df6c1c6d929047517eab13c2661', + }, + { + pubkey: + '0xb4976ac8f9755cb85cdfd791f636511bd87244e5c93afcb7b69b75b888ea767910e5a4522b5a3aa81a2da51ba166aefb', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xb063a33cdd922d8da9279c27ac6914c24ed289f882cdba0595dc06be44c9acfad657f9e6b24b7e4986f415cad38883220b39d6670cdb7c1aff89f68d2cc3209c5b4dc929ecacb2484bd5c725863752a30f9f12a43f9c3ac5c4b01108323a6501', + depositDataRoot: + '0xfd575b934098cf01c7f16b7b8790d63af68ff0e94bc85e17774d3aed62656864', + }, + { + pubkey: + '0xb997141bd45fa4edc4246d6facebe8608ca4df46d1cb095ee09278ce4b1ce55e3f04a2d8fe8dcdb85416474dabfea915', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x84cd71555c729d91f2c2c241ef6e0a1c38683b10ff811f49b0fb9cfec31796c96f50eb4a585f95f6dccf7990d04f758a05493eb94e11c85964b0cdb57986636ee6405bece464a8d6e790de9af1e3bd84df784c2a742aaca37a725e6929bdab22', + depositDataRoot: + '0xdd62ae2901dfb98fbc7a18eedd5d9e6e3d40df52094d65cafdd9fc3df0f94048', + }, + { + pubkey: + '0xa5fadae6fae0d2eb3709e18741c4804acaafe6f685c49e598d2be523381fda8678ebdcf905417e32e007bb36bdfeab68', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x865423fb473e67849cd0d439886ea4be2236c596051c7b96d0b0f921d459f066b1d4b089754f4fdf72f0c4e6b83c49ab0d6e515c7a729c355ac881c237bf11ed1853d9ff45cb57c652b928fc7260b197a81b5d0875aef73f2a133bcdee1fd4f9', + depositDataRoot: + '0xfaa6aca095138a8fa1449bbc9cc2b0aba95a0a3d9644c262972a82f8d41e5ef4', + }, + { + pubkey: + '0xae8c6be869d23bf14a0f85e28ba3b94fed089bc85f83cf2cd87280ba8defa9bf2ae9bea8d8ff8bb96133b9529986960d', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0xadd9f35acf6996a2ea4f660539620bacb5930522be05a3c70e6805bffbf4cc5a59e3aa0b961c99b1f644e1d7f187c25114b6299cc557b28ebc2dd82f348b791d7669fbfcf1763e74a91d4771a55c79d28069b88453d0143d4297ff0cb0cc7224', + depositDataRoot: + '0x6a29310647900458320294dc8174009c98e0af148070743bd9bcb425936b8097', + }, + { + pubkey: + '0xb4338229a52cc05475f0c286a313b37e1ab9ed83c774d3daceaa6c63f815062e8d31bf2b9593999ce168b0a544807825', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x93147471ecdd8f41b7c9c8070858698a8340c90582fb884bfed3cae5d3e09cf2b3755d455a13ac374b664ba183b181440dcb3f23c70c8ebd3247cac14b2fe8afff9d8fcee59f4b1988a189c502904d0f81db0068d37c5a347b4096ee8bd71da7', + depositDataRoot: + '0xe09b81f2a711303bdc0a8da62cbb54858d2a707b0a6879b944d067d9fc50c2a5', + }, + { + pubkey: + '0xa0da8aff80f7cb0ce0b5e0ca03edc292d89588624c4d62862bc3f1fa33f46d84071b7ff67266c8608d67699020e8b0bf', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x869a8831db5591eb49a0c0215f56231afcc141c54165c6375f68ed2d19fae96a2b0d2208c938a02c7e2148c4d590095000a5f8a00ed19732e3c4aaadefba5e55d06ece2609616bf8ec4fef914db47a360effd7a313a581e7b6bb14db7a93b82d', + depositDataRoot: + '0xe338702fdf04d583b23d94f70ff23146caa7d2527debcf3e7bc70f00e3381e87', + }, + { + pubkey: + '0x8498a47d75b9c4a37f8867496f37655465f5fa687cf217382fe8f6c118d3265f3f512deca2629b2286b8ea01cacae30a', + withdrawalCredentials: + '0x0100000000000000000000008ead0e8fec8319fd62c8508c71a90296efd4f042', + signature: + '0x8af164af59caa4ced3eeaf0c5e43f20011ebef30da4ae16be6bf0484e0881f3d835f26ba353e017ece16db3e4e24d4f11605e0d7b1ec513a33298e56f608af0e21636933a42f84d09a503793bac4762a2b69ed67d474c28adfe2b023c830ae5d', + depositDataRoot: + '0xce19f076205d248e29bf11b450f8c02305d87109e5be64e056fba8366f38e6de', + }, +]; + +export function calculateValidatorsAccumulator( + validatorsPubkeys: Uint8Array[], + eth1DepositIndexes: Uint8Array[], +): string { + const leaves = validatorsPubkeys.map((pubkey, i) => { + const validatorPubkey = bytesToHex(pubkey).padStart(96, '0'); + const eth1DepositIndex = bytesToHex(eth1DepositIndexes[i]).padStart( + 16, + '0', + ); + + return sha256( + '0x' + formatHex(validatorPubkey) + formatHex(eth1DepositIndex), + ); + }); + + return hashTreeRoot(leaves, 32); +} + +describe.only('ValidatorsAccumulator tests', async function () { + let blc: Contract; + let depositContract: Contract; + let pubkeys: Uint8Array[] = []; + let eth1DepositIndexes: Uint8Array[] = []; + + beforeEach(async function () { + const [signer] = await ethers.getSigners(); + + depositContract = new Contract( + '0x00000000219ab540356cBB839Cbe05303d7705Fa', + depositContractAbi, + signer, + ); + + const contractFactory = await ethers.getContractFactory( + 'ValidatorsAccumulator', + ); + blc = await contractFactory.deploy( + '0x00000000219ab540356cBB839Cbe05303d7705Fa', + ); + }); + + async function deposit(depositItem) { + console.log('Deposit', depositItem); + await ( + await blc.deposit( + depositItem.pubkey, + depositItem.withdrawalCredentials, + depositItem.signature, + depositItem.depositDataRoot, + { value: ethers.utils.parseEther('32').toString() }, + ) + ).wait(); + + const pubkey = hexToBytes(depositItem.pubkey); + const eth1DepositIndex = await depositContract.get_deposit_count(); + + pubkeys.push(pubkey); + eth1DepositIndexes.push(hexToBytes(eth1DepositIndex)); + } + + it('Deposit', async function () { + for (const depositItem of depositItems) { + await deposit(depositItem); + expect(await blc.get_validators_accumulator()).to.equal( + calculateValidatorsAccumulator(pubkeys, eth1DepositIndexes), + ); + } + }); +}); diff --git a/libs/typescript/ts-utils/ssz-utils.ts b/libs/typescript/ts-utils/ssz-utils.ts index 0f37f1d00..dcc684615 100644 --- a/libs/typescript/ts-utils/ssz-utils.ts +++ b/libs/typescript/ts-utils/ssz-utils.ts @@ -25,8 +25,28 @@ export function verifyMerkleProof( return formatHex(hash) === formatHex(hashTreeRoot); } -export function hashTreeRoot(_leaves: string[]) { - const leaves = [..._leaves]; +function nearestUpperPowerOfTwo(num) { + let power = Math.ceil(Math.log2(num)); + return Math.pow(2, power); +} + +export function hashTreeRoot(_leaves: string[], treeDepth: number): string { + const zero_hashes: string[] = []; + + zero_hashes[0] = '0x' + '0'.repeat(64); + + for (let height = 0; height < treeDepth - 1; height++) { + zero_hashes[height + 1] = sha256( + '0x' + formatHex(zero_hashes[height]) + formatHex(zero_hashes[height]), + ); + } + + const leavesLength = _leaves.length; + const treeLeaves = nearestUpperPowerOfTwo(leavesLength); + const leaves = [ + ..._leaves, + ...Array(treeLeaves - leavesLength).fill('0x' + '0'.repeat(64)), + ]; const UPPER_SIZE = leaves.length; let n = 2; @@ -41,7 +61,15 @@ export function hashTreeRoot(_leaves: string[]) { n *= 2; } - return leaves[0]; + let subtreeRoot = leaves[0]; + + for (let i = Math.log2(treeLeaves); i < treeDepth; i++) { + subtreeRoot = sha256( + '0x' + formatHex(subtreeRoot) + formatHex(zero_hashes[i]), + ); + } + + return subtreeRoot; } export async function jsonToSerializedBase64(