P2P Eth2 Depositor allows a convenient way to send 1 to 400 deposits in one transaction to the Eth2 Deposit Contract.
Below is a list of contracts we use for this service:
- Ownable, Pausable
- OpenZeppelin Contracts (installed as a Foundry dependency under
lib/openzeppelin-contracts, tagv5.6.1). The first contract manages ownership; the second supports pausing.
- P2pEth2Depositor
- A smart contract that forwards the same per-validator deposit amount for every entry in a batch (capped at 2048 ETH per validator) and sends up to 400 deposit calls per transaction to the Eth2 Deposit Contract. Each transaction uses one
withdrawal_credentialsvalue (same type for all validators in that batch, e.g.0x01or0x02).
Install Foundry and pull the repository from GitHub:
curl -L https://foundry.paradigm.xyz | bash
foundryup
git clone https://github.com/p2p-org/p2p-eth2-depositor
cd p2p-eth2-depositor
git submodule update --init --recursive
forge create --rpc-url https://mainnet.infura.io/v3/<YOUR INFURA KEY> \
--private-key <YOUR PRIVATE KEY> \
src/P2pEth2Depositor.sol:P2pEth2Depositor \
--constructor-args 0x00000000219ab540356cBB839Cbe05303d7705Fa \
--etherscan-api-key <YOUR ETHERSCAN API KEY> \
--verifyPass the canonical DepositContract address for the target network as the constructor argument. Ethereum mainnet and Hoodi both use 0x00000000219ab540356cBB839Cbe05303d7705Fa.
- Choose the number of Eth2 validator nodes you want to create in one batch (1–400).
- Build arrays of
pubkeys,signatures, anddeposit_data_roots(length = number of validators). Provide a single 32-bytewithdrawal_credentialsblob shared by all validators in the batch, and a singleamount(ETH per validator). - Call
depositonP2pEth2Depositorwithmsg.valueequal toamount * number_of_validators.
The batch amount must be at least 1 ETH per validator, divisible by 1 gwei, and no more than 2048 ETH per validator.
Operators should ensure pubkeys are unique off-chain because repeated pubkeys can top up an existing validator instead of creating distinct validators.
Deposits strictly above 32 ETH require compounding withdrawal credentials whose first byte is 0x02. Deposits at most 32 ETH remain credential-type independent aside from length.
On success, the contract emits DepositEvent(from, validatorCount, totalAmount).
This wrapper does not replicate every protocol rule: the official deposit contract may still revert on amounts or deposit data that consensus rejects.
Important: each deposit_data_root must be generated from the exact deposit data, including the exact amount and the shared withdrawal_credentials. Do not fake or reuse a 32 ETH deposit_data_root for different amounts.
Foundry tests live in test/P2pEth2Depositor.t.sol. Unit tests cover validation paths that revert before calling the canonical Eth2 deposit contract.
Fork tests replay static deposit fixtures copied from recent successful mainnet and Hoodi DepositContract transactions. They do not mock or replace the canonical DepositContract. Set the corresponding RPC URL to run them:
ETH_RPC_URL_MAINNET=<mainnet_rpc> forge test --match-contract P2pEth2DepositorForkTest -vv
ETH_RPC_URL_HOODI=<hoodi_rpc> forge test --match-contract P2pEth2DepositorForkTest -vvMIT
Code based on Abyss finance example https://github.com/abyssfinance/abyss-eth2depositor