false
false
0
The new Blockscout UI is now open source! Learn how to deploy it here
- We're indexing this chain right now. Some of the counts may be inaccurate.

Contract Address Details

0xA3291dF14D09f71151a0a0b2E732DC26be21CDcD

Contract Name
ShadowVerifier
Creator
0xe36c0f–9ad9cb at 0x66b3ec–e8080d
Balance
0 ETH
Tokens
Fetching tokens...
Transactions
0 Transactions
Transfers
0 Transfers
Gas Used
Fetching gas used...
Last Balance Update
5595299
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
ShadowVerifier




Optimization enabled
true
Compiler version
v0.8.33+commit.64118f21




Optimization runs
200
EVM Version
shanghai




Verified at
2026-02-26T23:13:46.913689Z

Constructor Arguments

0x00000000000000000000000016701300000000000000000000000000000100010000000000000000000000009a4d9720e9ec87b7c9e5f5f8fb1b083b4d6e5b29

Arg [0] (address) : 0x1670130000000000000000000000000000010001
Arg [1] (address) : 0x9a4d9720e9ec87b7c9e5f5f8fb1b083b4d6e5b29

              

src/impl/ShadowVerifier.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.33;

import {IAnchor} from "../iface/IAnchor.sol";
import {ICircuitVerifier} from "../iface/ICircuitVerifier.sol";
import {IShadow} from "../iface/IShadow.sol";
import {IShadowVerifier} from "../iface/IShadowVerifier.sol";
import {ShadowPublicInputs} from "../lib/ShadowPublicInputs.sol";

/// @title ShadowVerifier
/// @notice Verifies Shadow claim proofs using TaikoAnchor for block hash validation.
/// @dev The ZK proof commits to a blockHash. The stateRoot is derived in-circuit from
/// the RLP-encoded block header. We verify the blockHash is canonical via TaikoAnchor.
/// @custom:security-contact security@taiko.xyz

contract ShadowVerifier is IShadowVerifier {
    ICircuitVerifier public immutable circuitVerifier;
    IAnchor public immutable anchor;

    constructor(address _anchor, address _circuitVerifier) {
        require(_anchor != address(0), ZeroAddress());
        require(_circuitVerifier != address(0), ZeroAddress());
        anchor = IAnchor(_anchor);
        circuitVerifier = ICircuitVerifier(_circuitVerifier);
    }

    /// @notice Verifies a proof and its public inputs.
    /// @dev Fetches the canonical blockHash from TaikoAnchor and builds public inputs.
    /// The ZK proof verifies: keccak256(block_header_rlp) == blockHash, then derives
    /// stateRoot from the header and verifies the account balance against it.
    function verifyProof(bytes calldata _proof, IShadow.PublicInput calldata _input)
        external
        view
        returns (bool _isValid_)
    {
        require(_input.blockNumber > 0, BlockHashNotFound(_input.blockNumber));

        // Get canonical block hash from TaikoAnchor
        bytes32 blockHash = anchor.blockHashes(_input.blockNumber);
        require(blockHash != bytes32(0), BlockHashNotFound(_input.blockNumber));

        uint256[] memory publicInputs = ShadowPublicInputs.toArray(_input, blockHash);
        bool ok = circuitVerifier.verifyProof(_proof, publicInputs);
        require(ok, ProofVerificationFailed());
        _isValid_ = true;
    }
}
        

src/iface/ICircuitVerifier.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.33;

/// @custom:security-contact security@taiko.xyz

interface ICircuitVerifier {
    /// @notice Verifies a proof against public inputs.
    function verifyProof(bytes calldata _proof, uint256[] calldata _publicInputs)
        external
        view
        returns (bool _isValid_);
}
          

src/iface/IShadow.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.33;

/// @custom:security-contact security@taiko.xyz

interface IShadow {
    struct PublicInput {
        uint64 blockNumber;
        uint256 chainId;
        uint256 amount;
        address recipient;
        bytes32 nullifier;
    }

    event Claimed(bytes32 indexed nullifier, address indexed recipient, uint256 amount);

    error ChainIdMismatch(uint256 expected, uint256 actual);
    error InvalidAmount(uint256 amount);
    error InvalidRecipient(address recipient);
    error NullifierAlreadyConsumed(bytes32 nullifier);
    error ProofVerificationFailed();

    /// @notice Submits a proof and public inputs to mint ETH via the configured minter hook.
    /// @dev The Shadow implementation applies a 0.1% claim fee (`amount / 1000`) to an immutable feeRecipient.
    function claim(bytes calldata _proof, PublicInput calldata _input) external;
}
          

src/iface/IShadowVerifier.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.33;

import {IShadow} from "./IShadow.sol";

/// @custom:security-contact security@taiko.xyz

interface IShadowVerifier {
    error BlockHashNotFound(uint64 blockNumber);
    error ProofVerificationFailed();
    error ZeroAddress();

    /// @notice Verifies a proof and its public inputs.
    function verifyProof(bytes calldata _proof, IShadow.PublicInput calldata _input)
        external
        view
        returns (bool _isValid_);
}
          

src/iface/IAnchor.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.33;

/// @custom:security-contact security@taiko.xyz

interface IAnchor {
    function blockHashes(uint256 _blockNumber) external view returns (bytes32 _blockHash_);
}
          

src/lib/ShadowPublicInputs.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.33;

import {IShadow} from "../iface/IShadow.sol";

/// @title ShadowPublicInputs
/// @notice Encodes public inputs for Shadow ZK proof verification.
/// @dev Layout matches the prover's ClaimJournal:
/// - Index 0: blockNumber (u64)
/// - Index 1-32: blockHash (32 bytes, each byte as uint256)
/// - Index 33: chainId (u64)
/// - Index 34: amount (u128)
/// - Index 35-54: recipient (20 bytes)
/// - Index 55-86: nullifier (32 bytes)
/// @custom:security-contact security@taiko.xyz

library ShadowPublicInputs {
    uint256 private constant _PUBLIC_INPUTS_LEN = 87;
    uint256 private constant _IDX_BLOCK_NUMBER = 0;
    uint256 private constant _IDX_BLOCK_HASH = 1;
    uint256 private constant _IDX_CHAIN_ID = 33;
    uint256 private constant _IDX_AMOUNT = 34;
    uint256 private constant _IDX_RECIPIENT = 35;
    uint256 private constant _IDX_NULLIFIER = 55;

    /// @notice Converts a PublicInput struct to a uint256 array for circuit verification.
    /// @dev blockHash is fetched on-chain from TaikoAnchor, so it is not part of
    /// `IShadow.PublicInput` calldata.
    function toArray(IShadow.PublicInput calldata _input, bytes32 _blockHash)
        internal
        pure
        returns (uint256[] memory inputs_)
    {
        inputs_ = new uint256[](_PUBLIC_INPUTS_LEN);

        inputs_[_IDX_BLOCK_NUMBER] = _input.blockNumber;

        _writeBytes32(inputs_, _IDX_BLOCK_HASH, _blockHash);

        inputs_[_IDX_CHAIN_ID] = _input.chainId;
        inputs_[_IDX_AMOUNT] = _input.amount;

        _writeAddress(inputs_, _IDX_RECIPIENT, _input.recipient);
        _writeBytes32(inputs_, _IDX_NULLIFIER, _input.nullifier);
    }

    function _writeBytes32(uint256[] memory _inputs, uint256 _offset, bytes32 _value) private pure {
        for (uint256 i = 0; i < 32;) {
            _inputs[_offset + i] = uint256(uint8(_value[i]));
            unchecked {
                ++i;
            }
        }
    }

    function _writeAddress(uint256[] memory _inputs, uint256 _offset, address _value) private pure {
        for (uint256 i = 0; i < 20;) {
            _inputs[_offset + i] = uint256(uint8(bytes20(_value)[i]));
            unchecked {
                ++i;
            }
        }
    }
}
          

Compiler Settings

{"viaIR":true,"remappings":["forge-std/=node_modules/forge-std/src/","@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/","@openzeppelin/contracts-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/","risc0-ethereum/=lib/risc0-ethereum/contracts/src/","openzeppelin/contracts/=node_modules/@openzeppelin/contracts/"],"outputSelection":{"*":{"*":["*"],"":["*"]}},"optimizer":{"runs":200,"enabled":true},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"libraries":{},"evmVersion":"shanghai"}
              

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_anchor","internalType":"address"},{"type":"address","name":"_circuitVerifier","internalType":"address"}]},{"type":"error","name":"BlockHashNotFound","inputs":[{"type":"uint64","name":"blockNumber","internalType":"uint64"}]},{"type":"error","name":"ProofVerificationFailed","inputs":[]},{"type":"error","name":"ZeroAddress","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IAnchor"}],"name":"anchor","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract ICircuitVerifier"}],"name":"circuitVerifier","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"_isValid_","internalType":"bool"}],"name":"verifyProof","inputs":[{"type":"bytes","name":"_proof","internalType":"bytes"},{"type":"tuple","name":"_input","internalType":"struct IShadow.PublicInput","components":[{"type":"uint64","name":"blockNumber","internalType":"uint64"},{"type":"uint256","name":"chainId","internalType":"uint256"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"address","name":"recipient","internalType":"address"},{"type":"bytes32","name":"nullifier","internalType":"bytes32"}]}]}]
              

Contract Creation Code

0x60c0346100b657601f6105f438819003918201601f19168301916001600160401b038311848410176100ba5780849260409485528339810103126100b657610052602061004b836100ce565b92016100ce565b6001600160a01b039091169081156100a7576001600160a01b03169081156100a75760a05260805260405161051190816100e38239608051818181609701526102d8015260a051818181604f01526101740152f35b63d92e233d60e01b5f5260045ffd5b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b03821682036100b65756fe60806040526004361015610011575f80fd5b5f3560e01c8063ca167509146100c6578063d0ea9ff0146100825763d3fb73b41461003a575f80fd5b3461007e575f36600319011261007e576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b5f80fd5b3461007e575f36600319011261007e576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461007e5760c036600319011261007e5760043567ffffffffffffffff811161007e573660238201121561007e57806004013567ffffffffffffffff811161007e57366024828401011161007e5760a036602319011261007e5761014567ffffffffffffffff610134610455565b16151561013f610455565b9061046c565b61014d610455565b6040516334cdf78d60e01b815267ffffffffffffffff9190911660048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561036b575f91610423575b506101c06101b8610455565b82151561046c565b610b0091604051916101d28484610491565b605783526020830193601f190136853767ffffffffffffffff6101f3610455565b168351156103eb5784525f5b602081106103ff5750508151602110156103eb576044356104408301528151602210156103eb576064356104608301526084356001600160a01b038116810361007e5760601b6bffffffffffffffffffffffff19165f5b601481106103c757505060a4355f5b6020811061038f57602486868660848780604051968796631e8e1e1360e01b8852604060048901528260448901520160648701375f60648287010152601f801991011684016064810192600319606487840301016024870152518093520191905f5b8181106103765784602081808703817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561036b575f91610330575b501561032157602060405160018152f35b631ac2386360e31b5f5260045ffd5b90506020813d602011610363575b8161034b60209383610491565b8101031261007e5751801515810361007e5781610310565b3d915061033e565b6040513d5f823e3d90fd5b82518452859450602093840193909201916001016102c7565b8060370190816037116103b3576001916103ac84831a91876104c7565b5201610265565b634e487b7160e01b5f52601160045260245ffd5b8060230190816023116103b3576001916103e484831a91876104c7565b5201610256565b634e487b7160e01b5f52603260045260245ffd5b8060010190816001116103b35760019161041c84831a91876104c7565b52016101ff565b90506020813d60201161044d575b8161043e60209383610491565b8101031261007e5751836101ac565b3d9150610431565b60243567ffffffffffffffff8116810361007e5790565b156104745750565b67ffffffffffffffff906328e89c8b60e01b5f521660045260245ffd5b90601f8019910116810190811067ffffffffffffffff8211176104b357604052565b634e487b7160e01b5f52604160045260245ffd5b80518210156103eb5760209160051b01019056fea26469706673582212205e31ce7a58695ed70aeb299ab7d44bf75540f4e30db65eee511a2105d2c9d03e64736f6c6343000821003300000000000000000000000016701300000000000000000000000000000100010000000000000000000000009a4d9720e9ec87b7c9e5f5f8fb1b083b4d6e5b29

Deployed ByteCode

0x60806040526004361015610011575f80fd5b5f3560e01c8063ca167509146100c6578063d0ea9ff0146100825763d3fb73b41461003a575f80fd5b3461007e575f36600319011261007e576040517f00000000000000000000000016701300000000000000000000000000000100016001600160a01b03168152602090f35b5f80fd5b3461007e575f36600319011261007e576040517f0000000000000000000000009a4d9720e9ec87b7c9e5f5f8fb1b083b4d6e5b296001600160a01b03168152602090f35b3461007e5760c036600319011261007e5760043567ffffffffffffffff811161007e573660238201121561007e57806004013567ffffffffffffffff811161007e57366024828401011161007e5760a036602319011261007e5761014567ffffffffffffffff610134610455565b16151561013f610455565b9061046c565b61014d610455565b6040516334cdf78d60e01b815267ffffffffffffffff9190911660048201526020816024817f00000000000000000000000016701300000000000000000000000000000100016001600160a01b03165afa90811561036b575f91610423575b506101c06101b8610455565b82151561046c565b610b0091604051916101d28484610491565b605783526020830193601f190136853767ffffffffffffffff6101f3610455565b168351156103eb5784525f5b602081106103ff5750508151602110156103eb576044356104408301528151602210156103eb576064356104608301526084356001600160a01b038116810361007e5760601b6bffffffffffffffffffffffff19165f5b601481106103c757505060a4355f5b6020811061038f57602486868660848780604051968796631e8e1e1360e01b8852604060048901528260448901520160648701375f60648287010152601f801991011684016064810192600319606487840301016024870152518093520191905f5b8181106103765784602081808703817f0000000000000000000000009a4d9720e9ec87b7c9e5f5f8fb1b083b4d6e5b296001600160a01b03165afa90811561036b575f91610330575b501561032157602060405160018152f35b631ac2386360e31b5f5260045ffd5b90506020813d602011610363575b8161034b60209383610491565b8101031261007e5751801515810361007e5781610310565b3d915061033e565b6040513d5f823e3d90fd5b82518452859450602093840193909201916001016102c7565b8060370190816037116103b3576001916103ac84831a91876104c7565b5201610265565b634e487b7160e01b5f52601160045260245ffd5b8060230190816023116103b3576001916103e484831a91876104c7565b5201610256565b634e487b7160e01b5f52603260045260245ffd5b8060010190816001116103b35760019161041c84831a91876104c7565b52016101ff565b90506020813d60201161044d575b8161043e60209383610491565b8101031261007e5751836101ac565b3d9150610431565b60243567ffffffffffffffff8116810361007e5790565b156104745750565b67ffffffffffffffff906328e89c8b60e01b5f521660045260245ffd5b90601f8019910116810190811067ffffffffffffffff8211176104b357604052565b634e487b7160e01b5f52604160045260245ffd5b80518210156103eb5760209160051b01019056fea26469706673582212205e31ce7a58695ed70aeb299ab7d44bf75540f4e30db65eee511a2105d2c9d03e64736f6c63430008210033