ETH Price: $2,950.16 (-2.13%)
Gas: 3 Gwei

Transaction Decoder

Block:
19689270 at Apr-19-2024 11:45:11 AM +UTC
Transaction Fee:
0.00058839 ETH $1.74
Gas Used:
53,490 Gas / 11 Gwei

Emitted Events:

233 DepositContract.DepositEvent( pubkey=0xB46E78D5B9223964FB10A2B24A5B3844C72D14C1E73161A319BE65842F0A6C663B07CEDAF2AD3260BCA7A42F736C3515, withdrawal_credentials=0x010000000000000000000000BACE5A7E2FC96055D463166A9F6AD781C0F35BE8, amount=0x0040597307000000, signature=0x87C1DC9B82E26E7FBB2244DA8579B88F0D1C47F40422C11A6F497147351C3A0614EED009E691179E7EC9F717E1F773A913344AA48B26A9F432D6EDBBF45D3106B0BE262931EDDC937F1BD94C2758592244C0AC2EA96CC8A3DD24E1456576CBE2, index=0xC10E160000000000 )

Account State Difference:

  Address   Before After State Difference Code
0x00000000...03d7705Fa
(Beacon Deposit Contract)
43,876,382.376960633295804796 Eth43,876,414.376960633295804796 Eth32
(Titan Builder)
7.33168632580465655 Eth7.33173022711595438 Eth0.00004390131129783
0xBAcE5a7E...1C0f35BE8
1,344.409337484711027207 Eth
Nonce: 553
1,312.408749094711027207 Eth
Nonce: 554
32.00058839

Execution Trace

ETH 32 DepositContract.deposit( pubkey=0xB46E78D5B9223964FB10A2B24A5B3844C72D14C1E73161A319BE65842F0A6C663B07CEDAF2AD3260BCA7A42F736C3515, withdrawal_credentials=0x010000000000000000000000BACE5A7E2FC96055D463166A9F6AD781C0F35BE8, signature=0x87C1DC9B82E26E7FBB2244DA8579B88F0D1C47F40422C11A6F497147351C3A0614EED009E691179E7EC9F717E1F773A913344AA48B26A9F432D6EDBBF45D3106B0BE262931EDDC937F1BD94C2758592244C0AC2EA96CC8A3DD24E1456576CBE2, deposit_data_root=BA60B96B19A6093D6FCF3A32F30098BC18313A912541CA028FA1121AA078C447 )
  • Null: 0x000...002.b46e78d5( )
  • Null: 0x000...002.87c1dc9b( )
  • Null: 0x000...002.b0be2629( )
  • Null: 0x000...002.d0207a66( )
  • Null: 0x000...002.75c582b3( )
  • Null: 0x000...002.00405973( )
  • Null: 0x000...002.f49a2afa( )
  • Null: 0x000...002.e32ee8f8( )
    // ┏━━━┓━┏┓━┏┓━━┏━━━┓━━┏━━━┓━━━━┏━━━┓━━━━━━━━━━━━━━━━━━━┏┓━━━━━┏━━━┓━━━━━━━━━┏┓━━━━━━━━━━━━━━┏┓━
    // ┃┏━━┛┏┛┗┓┃┃━━┃┏━┓┃━━┃┏━┓┃━━━━┗┓┏┓┃━━━━━━━━━━━━━━━━━━┏┛┗┓━━━━┃┏━┓┃━━━━━━━━┏┛┗┓━━━━━━━━━━━━┏┛┗┓
    // ┃┗━━┓┗┓┏┛┃┗━┓┗┛┏┛┃━━┃┃━┃┃━━━━━┃┃┃┃┏━━┓┏━━┓┏━━┓┏━━┓┏┓┗┓┏┛━━━━┃┃━┗┛┏━━┓┏━┓━┗┓┏┛┏━┓┏━━┓━┏━━┓┗┓┏┛
    // ┃┏━━┛━┃┃━┃┏┓┃┏━┛┏┛━━┃┃━┃┃━━━━━┃┃┃┃┃┏┓┃┃┏┓┃┃┏┓┃┃━━┫┣┫━┃┃━━━━━┃┃━┏┓┃┏┓┃┃┏┓┓━┃┃━┃┏┛┗━┓┃━┃┏━┛━┃┃━
    // ┃┗━━┓━┃┗┓┃┃┃┃┃┃┗━┓┏┓┃┗━┛┃━━━━┏┛┗┛┃┃┃━┫┃┗┛┃┃┗┛┃┣━━┃┃┃━┃┗┓━━━━┃┗━┛┃┃┗┛┃┃┃┃┃━┃┗┓┃┃━┃┗┛┗┓┃┗━┓━┃┗┓
    // ┗━━━┛━┗━┛┗┛┗┛┗━━━┛┗┛┗━━━┛━━━━┗━━━┛┗━━┛┃┏━┛┗━━┛┗━━┛┗┛━┗━┛━━━━┗━━━┛┗━━┛┗┛┗┛━┗━┛┗┛━┗━━━┛┗━━┛━┗━┛
    // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┃┃━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┗┛━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    
    // SPDX-License-Identifier: CC0-1.0
    
    pragma solidity 0.6.11;
    
    // 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() public {
            // 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];
        }
    }