Ethereum Batch Deposit Contract

Save gas by performing deposits in batches

The Pier Two batch deposit contract facilitates the pooling of multiple ETH deposits for submission to the Ethereum beacon chain in a single transaction. This method is not only convenient but also maximises gas efficiency, reducing overall costs.

Hashlock Audit

Our batch deposit contract underwent an audit by Hashlock, see the report here

Deposit for multiple withdrawal addresses

Our batch deposit contract implementation allows you to specify an arbitrary withdrawal address for each deposit. This additional flexbility is useful when your security practises prevent re-use of withdrawal credentials among validators.

Pectra Era

Since Pectra allows staking arbitrary amounts between 32 and 2048 ETH, the upgraded batch deposit contract allows you to specify an amount per deposit.

Mainnet: 0xcD7a6C118Ac8F6544BC5076F2D8Fb86D2C546756

Hoodi Testnet: 0x4c9506eE2fCd962f03022D9d8ebf6f7828abEfaf

See a more detailed breakdown of the changes coming in Pectra

View ABI
[
{
  "inputs": [],
  "name": "DepositValueGreaterThan2048ETH",
  "type": "error"
},
{
  "inputs": [],
  "name": "DepositValueLessThan1ETH",
  "type": "error"
},
{
  "inputs": [],
  "name": "DepositValueMustBeMultipleOfGwei",
  "type": "error"
},
{
  "inputs": [],
  "name": "InvalidPubKeyLength",
  "type": "error"
},
{
  "inputs": [],
  "name": "InvalidSignatureLength",
  "type": "error"
},
{
  "inputs": [],
  "name": "InvalidWithdrawalCredLength",
  "type": "error"
},
{
  "inputs": [],
  "name": "MsgValueNotEqualToTotalDepositAmount",
  "type": "error"
},
{
  "inputs": [],
  "name": "NoDepositsProvided",
  "type": "error"
},
{
  "anonymous": false,
  "inputs": [
    {
      "indexed": true,
      "internalType": "bytes",
      "name": "pubKey",
      "type": "bytes"
    },
    {
      "indexed": true,
      "internalType": "bytes",
      "name": "withdrawalCredentials",
      "type": "bytes"
    },
    {
      "indexed": false,
      "internalType": "uint256",
      "name": "amount",
      "type": "uint256"
    }
  ],
  "name": "ValidatorDeposit",
  "type": "event"
},
{
  "inputs": [
    {
      "components": [
        {
          "internalType": "bytes",
          "name": "pubKey",
          "type": "bytes"
        },
        {
          "internalType": "bytes",
          "name": "withdrawalCredentials",
          "type": "bytes"
        },
        {
          "internalType": "bytes",
          "name": "signature",
          "type": "bytes"
        },
        {
          "internalType": "uint256",
          "name": "amount",
          "type": "uint256"
        }
      ],
      "internalType": "struct IBatchDeposit.Deposit[]",
      "name": "_deposits",
      "type": "tuple[]"
    }
  ],
  "name": "batchDeposit",
  "outputs": [],
  "stateMutability": "payable",
  "type": "function"
},
{
  "inputs": [],
  "name": "depositContract",
  "outputs": [
    {
      "internalType": "contract IDepositContract",
      "name": "",
      "type": "address"
    }
  ],
  "stateMutability": "view",
  "type": "function"
}
]

Shapella Era

Mainnet: 0x12EB6257b03Bc63F9b0121FEc484150A6aDb0De7

Hoodi Testnet: 0xCC408Ad84DAda990fAFF4Fe7da8DAB246dFE533E

View ABI
[
{
  "inputs": [
    {
      "internalType": "address",
      "name": "deposit_contract_address",
      "type": "address"
    }
  ],
  "stateMutability": "nonpayable",
  "type": "constructor"
},
{
  "anonymous": false,
  "inputs": [
    {
      "indexed": false,
      "internalType": "address",
      "name": "to",
      "type": "address"
    },
    {
      "indexed": false,
      "internalType": "uint256",
      "name": "amount",
      "type": "uint256"
    }
  ],
  "name": "LogDepositLeftover",
  "type": "event"
},
{
  "anonymous": false,
  "inputs": [
    {
      "indexed": false,
      "internalType": "bytes",
      "name": "pubkey",
      "type": "bytes"
    },
    {
      "indexed": false,
      "internalType": "bytes",
      "name": "withdrawal",
      "type": "bytes"
    }
  ],
  "name": "LogDepositSent",
  "type": "event"
},
{
  "inputs": [
    {
      "internalType": "bytes[]",
      "name": "pubkeys",
      "type": "bytes[]"
    },
    {
      "internalType": "bytes[]",
      "name": "withdrawal_credentials",
      "type": "bytes[]"
    },
    {
      "internalType": "bytes[]",
      "name": "signatures",
      "type": "bytes[]"
    },
    {
      "internalType": "bytes32[]",
      "name": "deposit_data_roots",
      "type": "bytes32[]"
    }
  ],
  "name": "batchDeposit",
  "outputs": [],
  "stateMutability": "payable",
  "type": "function"
},
{
  "inputs": [],
  "name": "depositContract_",
  "outputs": [
    {
      "internalType": "contract IDeposit",
      "name": "",
      "type": "address"
    }
  ],
  "stateMutability": "view",
  "type": "function"
},
{
  "inputs": [],
  "name": "kDepositAmount",
  "outputs": [
    {
      "internalType": "uint256",
      "name": "",
      "type": "uint256"
    }
  ],
  "stateMutability": "view",
  "type": "function"
}
]

🚧

Avoid EVM gas limits

Due to EVM constraints relating to large amounts of loop iterations, it is recommended to deposit in batches of up to 500 at a time.

If you encounter issues with failing transactions, try a smaller batch.