Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0x3F124C700fb5E741F128e28985267D44f56B242F
Balance 0 ETH
Nonce 1
Code Size 1694 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

1694 bytes
0x6080604052600436106100295760003560e01c8063592c0b7d1461002e578063e94ad65b14610043575b600080fd5b61004161003c366004610455565b6100a0565b005b34801561004f57600080fd5b506100777f00000000000000000000000000000000219ab540356cbb839cbe05303d7705fa81565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b824210610134576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f5472616e73616374696f6e207375626d6974746564206166746572206167726560448201527f65642075706f6e20646561646c696e650000000000000000000000000000000060648201526084015b60405180910390fd5b602060606101438260306104d1565b61014d91906104d1565b61015791906104d1565b610161908261053f565b156101ee576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603760248201527f496e7075742064617461206c656e677468206d757374206265206d756c74697060448201527f6c65206f66206465706f736974417267734c656e677468000000000000000000606482015260840161012b565b6000602060606101ff8260306104d1565b61020991906104d1565b61021391906104d1565b61021d9083610553565b90506102326801bc16d674ec8000003461053f565b156102be576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6d73672e76616c7565206d757374206265206d756c7469706c65206f6620333260448201527f2045544800000000000000000000000000000000000000000000000000000000606482015260840161012b565b806102d26801bc16d674ec80000034610553565b14610339576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f6d73672e76616c7565206d75737420626520333220455448202a20636f756e74604482015260640161012b565b60008080805b8581101561044b5760308101935060508101925060b08101915060d08101600061036b82858a8c610567565b61037491610591565b905073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000219ab540356cbb839cbe05303d7705fa1663228951186801bc16d674ec8000006103c889878d8f610567565b8d8d8c908c926103da93929190610567565b8f8f8d908d926103ec93929190610567565b896040518963ffffffff1660e01b815260040161040f9796959493929190610617565b6000604051808303818588803b15801561042857600080fd5b505af115801561043c573d6000803e3d6000fd5b5050505050819250505061033f565b5050505050505050565b60008060006040848603121561046a57600080fd5b83359250602084013567ffffffffffffffff8082111561048957600080fd5b818601915086601f83011261049d57600080fd5b8135818111156104ac57600080fd5b8760208285010111156104be57600080fd5b6020830194508093505050509250925092565b6000821982111561050b577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261054e5761054e610510565b500690565b60008261056257610562610510565b500490565b6000808585111561057757600080fd5b8386111561058457600080fd5b5050820193919092039150565b803560208310156105c8577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b165b92915050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60808152600061062b60808301898b6105ce565b828103602084015261063e81888a6105ce565b905082810360408401526106538186886105ce565b9150508260608301529897505050505050505056fea2646970667358221220074b09d874e02c55c037e2f92c03ac96e1141c8f0575df39a6b7c7521d62a68664736f6c63430008090033

Verified Source Code Full Match

Compiler: v0.8.9+commit.e5eed63a EVM: london Optimization: Yes (200000 runs)
eth2-batch-deposit.sol 67 lines
// SPDX-License-Identifier: CC0-1.0

pragma solidity 0.8.9;

import {IDepositContract} from "./eth2-official-deposit-contract.sol";

interface IBatchDeposit {
    function batchDeposit(uint validUntil, 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(uint validUntil, bytes calldata args) external payable {
        require(
            block.timestamp < validUntil,
            "Transaction submitted after agreed upon deadline");
        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;
        }
    }
}
eth2-official-deposit-contract.sol 178 lines
// ┏━━━┓━┏┓━┏┓━━┏━━━┓━━┏━━━┓━━━━┏━━━┓━━━━━━━━━━━━━━━━━━━┏┓━━━━━┏━━━┓━━━━━━━━━┏┓━━━━━━━━━━━━━━┏┓━
// ┃┏━━┛┏┛┗┓┃┃━━┃┏━┓┃━━┃┏━┓┃━━━━┗┓┏┓┃━━━━━━━━━━━━━━━━━━┏┛┗┓━━━━┃┏━┓┃━━━━━━━━┏┛┗┓━━━━━━━━━━━━┏┛┗┓
// ┃┗━━┓┗┓┏┛┃┗━┓┗┛┏┛┃━━┃┃━┃┃━━━━━┃┃┃┃┏━━┓┏━━┓┏━━┓┏━━┓┏┓┗┓┏┛━━━━┃┃━┗┛┏━━┓┏━┓━┗┓┏┛┏━┓┏━━┓━┏━━┓┗┓┏┛
// ┃┏━━┛━┃┃━┃┏┓┃┏━┛┏┛━━┃┃━┃┃━━━━━┃┃┃┃┃┏┓┃┃┏┓┃┃┏┓┃┃━━┫┣┫━┃┃━━━━━┃┃━┏┓┃┏┓┃┃┏┓┓━┃┃━┃┏┛┗━┓┃━┃┏━┛━┃┃━
// ┃┗━━┓━┃┗┓┃┃┃┃┃┃┗━┓┏┓┃┗━┛┃━━━━┏┛┗┛┃┃┃━┫┃┗┛┃┃┗┛┃┣━━┃┃┃━┃┗┓━━━━┃┗━┛┃┃┗┛┃┃┃┃┃━┃┗┓┃┃━┃┗┛┗┓┃┗━┓━┃┗┓
// ┗━━━┛━┗━┛┗┛┗┛┗━━━┛┗┛┗━━━┛━━━━┗━━━┛┗━━┛┃┏━┛┗━━┛┗━━┛┗┛━┗━┛━━━━┗━━━┛┗━━┛┗┛┗┛━┗━┛┗┛━┗━━━┛┗━━┛━┗━┛
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┃┃━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┗┛━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

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

// Based on official specification in https://eips.ethereum.org/EIPS/eip-165
interface ERC165 {
    /// @notice Query if a contract implements an interface
    /// @param interfaceId The interface identifier, as specified in ERC-165
    /// @dev Interface identification is specified in ERC-165. This function
    ///  uses less than 30,000 gas.
    /// @return `true` if the contract implements `interfaceId` and
    ///  `interfaceId` is not 0xffffffff, `false` otherwise
    function supportsInterface(bytes4 interfaceId) external pure returns (bool);
}

// This is a rewrite of the Vyper Eth2.0 deposit contract in Solidity.
// It tries to stay as close as possible to the original source code.
/// @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
contract DepositContract is IDepositContract, ERC165 {
    uint constant DEPOSIT_CONTRACT_TREE_DEPTH = 32;
    // NOTE: this also ensures `deposit_count` will fit into 64-bits
    uint constant MAX_DEPOSIT_COUNT = 2**DEPOSIT_CONTRACT_TREE_DEPTH - 1;

    bytes32[DEPOSIT_CONTRACT_TREE_DEPTH] branch;
    uint256 deposit_count;

    bytes32[DEPOSIT_CONTRACT_TREE_DEPTH] zero_hashes;

    constructor() {
        // Compute hashes in empty sparse 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 get_deposit_root() override external view returns (bytes32) {
        bytes32 node;
        uint size = deposit_count;
        for (uint height = 0; height < DEPOSIT_CONTRACT_TREE_DEPTH; height++) {
            if ((size & 1) == 1)
                node = sha256(abi.encodePacked(branch[height], node));
            else
                node = sha256(abi.encodePacked(node, zero_hashes[height]));
            size /= 2;
        }
        return sha256(abi.encodePacked(
            node,
            to_little_endian_64(uint64(deposit_count)),
            bytes24(0)
        ));
    }

    function get_deposit_count() override external view returns (bytes memory) {
        return to_little_endian_64(uint64(deposit_count));
    }

    function deposit(
        bytes calldata pubkey,
        bytes calldata withdrawal_credentials,
        bytes calldata signature,
        bytes32 deposit_data_root
    ) override external payable {
        // Extended ABI length checks since dynamic types are used.
        require(pubkey.length == 48, "DepositContract: invalid pubkey length");
        require(withdrawal_credentials.length == 32, "DepositContract: invalid withdrawal_credentials length");
        require(signature.length == 96, "DepositContract: invalid signature length");

        // Check deposit amount
        require(msg.value >= 1 ether, "DepositContract: deposit value too low");
        require(msg.value % 1 gwei == 0, "DepositContract: deposit value not multiple of gwei");
        uint deposit_amount = msg.value / 1 gwei;
        require(deposit_amount <= type(uint64).max, "DepositContract: deposit value too high");

        // Emit `DepositEvent` log
        bytes memory amount = to_little_endian_64(uint64(deposit_amount));
        emit DepositEvent(
            pubkey,
            withdrawal_credentials,
            amount,
            signature,
            to_little_endian_64(uint64(deposit_count))
        );

        // Compute deposit data root (`DepositData` hash tree root)
        bytes32 pubkey_root = sha256(abi.encodePacked(pubkey, bytes16(0)));
        bytes32 signature_root = sha256(abi.encodePacked(
            sha256(abi.encodePacked(signature[:64])),
            sha256(abi.encodePacked(signature[64:], bytes32(0)))
        ));
        bytes32 node = sha256(abi.encodePacked(
            sha256(abi.encodePacked(pubkey_root, withdrawal_credentials)),
            sha256(abi.encodePacked(amount, bytes24(0), signature_root))
        ));

        // Verify computed and expected deposit data roots match
        require(node == deposit_data_root, "DepositContract: reconstructed DepositData does not match supplied deposit_data_root");

        // Avoid overflowing the Merkle tree (and prevent edge case in computing `branch`)
        require(deposit_count < MAX_DEPOSIT_COUNT, "DepositContract: merkle tree full");

        // Add deposit data root to Merkle tree (update a single `branch` node)
        deposit_count += 1;
        uint size = deposit_count;
        for (uint height = 0; height < DEPOSIT_CONTRACT_TREE_DEPTH; height++) {
            if ((size & 1) == 1) {
                branch[height] = node;
                return;
            }
            node = sha256(abi.encodePacked(branch[height], node));
            size /= 2;
        }
        // As the loop should always end prematurely with the `return` statement,
        // this code should be unreachable. We assert `false` just to be safe.
        assert(false);
    }

    function supportsInterface(bytes4 interfaceId) override external pure returns (bool) {
        return interfaceId == type(ERC165).interfaceId || interfaceId == type(IDepositContract).interfaceId;
    }

    function to_little_endian_64(uint64 value) internal pure returns (bytes memory ret) {
        ret = new bytes(8);
        bytes8 bytesValue = bytes8(value);
        // Byteswapping during copying to bytes.
        ret[0] = bytesValue[7];
        ret[1] = bytesValue[6];
        ret[2] = bytesValue[5];
        ret[3] = bytesValue[4];
        ret[4] = bytesValue[3];
        ret[5] = bytesValue[2];
        ret[6] = bytesValue[1];
        ret[7] = bytesValue[0];
    }
}

Read Contract

depositContract 0xe94ad65b → address

Write Contract 1 functions

These functions modify contract state and require a wallet transaction to execute.

batchDeposit 0x592c0b7d
uint256 validUntil
bytes args

Recent Transactions

No transactions found for this address