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

0x91aa12Ba1A1c5AD3D7215ad0ac075c0b86e1C75B

Contract Name
ShadowVerifier
Creator
0xe36c0f–9ad9cb at 0x7bb63e–b829c1
Balance
0 ETH
Tokens
Fetching tokens...
Transactions
Fetching transactions...
Transfers
Fetching transfers...
Gas Used
Fetching gas used...
Last Balance Update
5796970
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-03-07T07:15:48.852384Z

Constructor Arguments

0x0000000000000000000000001670130000000000000000000000000000010001000000000000000000000000da3d906d59c5969062e5811b18b69798934d12b6

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

              

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 {
        require(_input.blockNumber > 0, BlockHashNotFound(_input.blockNumber));
        require(_input.chainId == uint64(block.chainid), IShadow.ChainIdMismatch(_input.chainId, uint64(block.chainid)));

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

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/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;
        uint64 chainId;
        uint256 amount;
        address recipient;
        bytes32 nullifier;
        address token; // address(0) = ETH
    }

    /// @dev `amount` is the gross (pre-fee) value from the ZK proof. The recipient receives `amount - fee`.
    event Claimed(bytes32 indexed nullifier, address indexed recipient, uint256 amount, address token);

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

    /// @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.
    /// @dev Reverts on any failure (BlockHashNotFound, ProofVerificationFailed). Never returns false.
    function verifyProof(bytes calldata _proof, IShadow.PublicInput calldata _input) external view;
}
          

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)
/// - Index 87-106: token (20 bytes, all zeros = ETH)
/// @custom:security-contact security@taiko.xyz

library ShadowPublicInputs {
    uint256 private constant _PUBLIC_INPUTS_LEN = 107;
    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;
    uint256 private constant _IDX_TOKEN = 87;

    /// @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);
        _writeAddress(inputs_, _IDX_TOKEN, _input.token);
    }

    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/","erc4626-tests/=lib/risc0-ethereum/lib/openzeppelin-contracts/lib/erc4626-tests/","halmos-cheatcodes/=lib/risc0-ethereum/lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/","openzeppelin-contracts/=lib/risc0-ethereum/lib/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":"ChainIdMismatch","inputs":[{"type":"uint64","name":"expected","internalType":"uint64"},{"type":"uint64","name":"actual","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":[],"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":"uint64","name":"chainId","internalType":"uint64"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"address","name":"recipient","internalType":"address"},{"type":"bytes32","name":"nullifier","internalType":"bytes32"},{"type":"address","name":"token","internalType":"address"}]}]}]
              

Contract Creation Code

0x60c0346100b657601f6106a838819003918201601f19168301916001600160401b038311848410176100ba5780849260409485528339810103126100b657610052602061004b836100ce565b92016100ce565b6001600160a01b039091169081156100a7576001600160a01b03169081156100a75760a0526080526040516105c590816100e382396080518181816097015261033f015260a051818181604f015261019d0152f35b63d92e233d60e01b5f5260045ffd5b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b03821682036100b65756fe60806040526004361015610011575f80fd5b5f3560e01c8063364ff306146100c6578063d0ea9ff0146100825763d3fb73b41461003a575f80fd5b3461007e575f36600319011261007e576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b5f80fd5b3461007e575f36600319011261007e576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461007e5760e036600319011261007e576004356001600160401b03811161007e573660238201121561007e5780600401356001600160401b03811161007e57366024828401011161007e5760c036602319011261007e576101426001600160401b036101316104f6565b16151561013c6104f6565b90610522565b61014a61050c565b6001600160401b03461690816001600160401b0361016661050c565b9216036104d75750506101776104f6565b6040516334cdf78d60e01b81526001600160401b039190911660048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156103c9575f916104a5575b506101e96101e16104f6565b821515610522565b610d8091604051916101fb8484610546565b606b83526020830193601f19013685376001600160401b0361021b6104f6565b1683511561046d5784525f5b602081106104815750506001600160401b0361024161050c565b1682516021101561046d5761044083015281516022101561046d576064356104608301526084356001600160a01b038116810361007e5760601b6bffffffffffffffffffffffff19165f5b6014811061044957505060a4355f5b6020811061042557505060c4356001600160a01b038116810361007e5760601b6bffffffffffffffffffffffff19165f5b601481106103ed57602486868660848780604051968796631e8e1e1360e01b8852604060048901528260448901520160648701375f60648287010152601f801991011684016064810192600319606487840301016024870152518093520191905f5b8181106103d45784602081808703817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156103c9575f9161038e575b501561037f57005b631ac2386360e31b5f5260045ffd5b90506020813d6020116103c1575b816103a960209383610546565b8101031261007e5751801515810361007e5781610377565b3d915061039c565b6040513d5f823e3d90fd5b825184528594506020938401939092019160010161032e565b8060570190816057116104115760019161040a84831a918761057b565b52016102cc565b634e487b7160e01b5f52601160045260245ffd5b8060370190816037116104115760019161044284831a918761057b565b520161029b565b8060230190816023116104115760019161046684831a918761057b565b520161028c565b634e487b7160e01b5f52603260045260245ffd5b8060010190816001116104115760019161049e84831a918761057b565b5201610227565b90506020813d6020116104cf575b816104c060209383610546565b8101031261007e5751836101d5565b3d91506104b3565b6001600160401b03906304cce86960e51b5f521660045260245260445ffd5b6024356001600160401b038116810361007e5790565b6044356001600160401b038116810361007e5790565b1561052a5750565b6001600160401b03906328e89c8b60e01b5f521660045260245ffd5b90601f801991011681019081106001600160401b0382111761056757604052565b634e487b7160e01b5f52604160045260245ffd5b805182101561046d5760209160051b01019056fea2646970667358221220b76aab514dac661585234004b7a345c61271ce9cec3f65321bf2a0d9f370f04e64736f6c634300082100330000000000000000000000001670130000000000000000000000000000010001000000000000000000000000da3d906d59c5969062e5811b18b69798934d12b6

Deployed ByteCode

0x60806040526004361015610011575f80fd5b5f3560e01c8063364ff306146100c6578063d0ea9ff0146100825763d3fb73b41461003a575f80fd5b3461007e575f36600319011261007e576040517f00000000000000000000000016701300000000000000000000000000000100016001600160a01b03168152602090f35b5f80fd5b3461007e575f36600319011261007e576040517f000000000000000000000000da3d906d59c5969062e5811b18b69798934d12b66001600160a01b03168152602090f35b3461007e5760e036600319011261007e576004356001600160401b03811161007e573660238201121561007e5780600401356001600160401b03811161007e57366024828401011161007e5760c036602319011261007e576101426001600160401b036101316104f6565b16151561013c6104f6565b90610522565b61014a61050c565b6001600160401b03461690816001600160401b0361016661050c565b9216036104d75750506101776104f6565b6040516334cdf78d60e01b81526001600160401b039190911660048201526020816024817f00000000000000000000000016701300000000000000000000000000000100016001600160a01b03165afa9081156103c9575f916104a5575b506101e96101e16104f6565b821515610522565b610d8091604051916101fb8484610546565b606b83526020830193601f19013685376001600160401b0361021b6104f6565b1683511561046d5784525f5b602081106104815750506001600160401b0361024161050c565b1682516021101561046d5761044083015281516022101561046d576064356104608301526084356001600160a01b038116810361007e5760601b6bffffffffffffffffffffffff19165f5b6014811061044957505060a4355f5b6020811061042557505060c4356001600160a01b038116810361007e5760601b6bffffffffffffffffffffffff19165f5b601481106103ed57602486868660848780604051968796631e8e1e1360e01b8852604060048901528260448901520160648701375f60648287010152601f801991011684016064810192600319606487840301016024870152518093520191905f5b8181106103d45784602081808703817f000000000000000000000000da3d906d59c5969062e5811b18b69798934d12b66001600160a01b03165afa9081156103c9575f9161038e575b501561037f57005b631ac2386360e31b5f5260045ffd5b90506020813d6020116103c1575b816103a960209383610546565b8101031261007e5751801515810361007e5781610377565b3d915061039c565b6040513d5f823e3d90fd5b825184528594506020938401939092019160010161032e565b8060570190816057116104115760019161040a84831a918761057b565b52016102cc565b634e487b7160e01b5f52601160045260245ffd5b8060370190816037116104115760019161044284831a918761057b565b520161029b565b8060230190816023116104115760019161046684831a918761057b565b520161028c565b634e487b7160e01b5f52603260045260245ffd5b8060010190816001116104115760019161049e84831a918761057b565b5201610227565b90506020813d6020116104cf575b816104c060209383610546565b8101031261007e5751836101d5565b3d91506104b3565b6001600160401b03906304cce86960e51b5f521660045260245260445ffd5b6024356001600160401b038116810361007e5790565b6044356001600160401b038116810361007e5790565b1561052a5750565b6001600160401b03906328e89c8b60e01b5f521660045260245ffd5b90601f801991011681019081106001600160401b0382111761056757604052565b634e487b7160e01b5f52604160045260245ffd5b805182101561046d5760209160051b01019056fea2646970667358221220b76aab514dac661585234004b7a345c61271ce9cec3f65321bf2a0d9f370f04e64736f6c63430008210033