// File: Eth2BatchDepositContract.sol



// SPDX-License-Identifier: CC0-1.0

pragma solidity 0.8.9;

import {IDepositContract} from "./IEth2ConsensusDepositContract.sol";

interface IBatchDeposit {
    function batchDeposit(bytes calldata args) external payable;
}

contract BatchDeposit is IBatchDeposit {
    IDepositContract public immutable depositContract;

    uint constant private pubkeyLength = 48;
    uint constant private withdrawalCredentialsLength = 32;
    uint constant private signatureLength = 96;
    uint constant private depositDataRootLength = 32;
    uint constant private depositArgsLength =
        pubkeyLength +
        withdrawalCredentialsLength +
        signatureLength +
        depositDataRootLength;

    constructor(IDepositContract _depositContract) {
        require(address(_depositContract) != address(0),
                "Please specify the correct deposit contract");
        depositContract = _depositContract;
    }

    function batchDeposit(bytes calldata args) external payable {
        require(
            args.length % depositArgsLength == 0,
            "Input data length must be multiple of depositArgsLength"
        );
        uint count = args.length / depositArgsLength;
        require(msg.value % 32 ether == 0, "msg.value must be multiple of 32 ETH");
        require(msg.value / 32 ether == count, "msg.value must be 32 ETH * count");

        uint withdrawalCredentialsStart;
        uint signatureStart;
        uint depositDataRootStart;

        for (uint pubkeyStart = 0; pubkeyStart < args.length; ) {
            unchecked
            {
                withdrawalCredentialsStart = pubkeyStart + pubkeyLength;
                signatureStart = withdrawalCredentialsStart + withdrawalCredentialsLength;
                depositDataRootStart = signatureStart + signatureLength;
            }

            uint depositDataRootEnd;
            unchecked { depositDataRootEnd = depositDataRootStart + depositDataRootLength; }
            bytes32 depositDataRoot = bytes32(args[depositDataRootStart : depositDataRootEnd]);

            depositContract.deposit{value: 32 ether}(
                args[pubkeyStart : withdrawalCredentialsStart],
                args[withdrawalCredentialsStart : signatureStart],
                args[signatureStart : depositDataRootStart],
                depositDataRoot
            );
            pubkeyStart = depositDataRootEnd;
        }
    }
}
// File: IEth2ConsensusDepositContract.sol



// ┏━━━┓━┏┓━┏┓━━┏━━━┓━━┏━━━┓━━━━┏━━━┓━━━━━━━━━━━━━━━━━━━┏┓━━━━━┏━━━┓━━━━━━━━━┏┓━━━━━━━━━━━━━━┏┓━
// ┃┏━━┛┏┛┗┓┃┃━━┃┏━┓┃━━┃┏━┓┃━━━━┗┓┏┓┃━━━━━━━━━━━━━━━━━━┏┛┗┓━━━━┃┏━┓┃━━━━━━━━┏┛┗┓━━━━━━━━━━━━┏┛┗┓
// ┃┗━━┓┗┓┏┛┃┗━┓┗┛┏┛┃━━┃┃━┃┃━━━━━┃┃┃┃┏━━┓┏━━┓┏━━┓┏━━┓┏┓┗┓┏┛━━━━┃┃━┗┛┏━━┓┏━┓━┗┓┏┛┏━┓┏━━┓━┏━━┓┗┓┏┛
// ┃┏━━┛━┃┃━┃┏┓┃┏━┛┏┛━━┃┃━┃┃━━━━━┃┃┃┃┃┏┓┃┃┏┓┃┃┏┓┃┃━━┫┣┫━┃┃━━━━━┃┃━┏┓┃┏┓┃┃┏┓┓━┃┃━┃┏┛┗━┓┃━┃┏━┛━┃┃━
// ┃┗━━┓━┃┗┓┃┃┃┃┃┃┗━┓┏┓┃┗━┛┃━━━━┏┛┗┛┃┃┃━┫┃┗┛┃┃┗┛┃┣━━┃┃┃━┃┗┓━━━━┃┗━┛┃┃┗┛┃┃┃┃┃━┃┗┓┃┃━┃┗┛┗┓┃┗━┓━┃┗┓
// ┗━━━┛━┗━┛┗┛┗┛┗━━━┛┗┛┗━━━┛━━━━┗━━━┛┗━━┛┃┏━┛┗━━┛┗━━┛┗┛━┗━┛━━━━┗━━━┛┗━━┛┗┛┗┛━┗━┛┗┛━┗━━━┛┗━━┛━┗━┛
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┃┃━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┗┛━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

// SPDX-License-Identifier: CC0-1.0

pragma solidity 0.8.9;

// 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);
}