ETH Price: $2,089.15 (-2.89%)
 

Overview

ETH Balance

0 ETH

ETH Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To
Claim1072701122023-07-23 19:03:21956 days ago1690139001IN
0xE29bD121...FfdF148b0
0 ETH0.0001920228250.1
Claim1072700932023-07-23 19:02:43956 days ago1690138963IN
0xE29bD121...FfdF148b0
0 ETH0.0001921961310.1
Claim1072700872023-07-23 19:02:31956 days ago1690138951IN
0xE29bD121...FfdF148b0
0 ETH0.0001951436330.1
Claim1072700842023-07-23 19:02:25956 days ago1690138945IN
0xE29bD121...FfdF148b0
0 ETH0.0001961267990.1
Claim1072700632023-07-23 19:01:43956 days ago1690138903IN
0xE29bD121...FfdF148b0
0 ETH0.0001757593540.1
Claim1072700512023-07-23 19:01:19956 days ago1690138879IN
0xE29bD121...FfdF148b0
0 ETH0.000162090390.1
Claim1072700472023-07-23 19:01:11956 days ago1690138871IN
0xE29bD121...FfdF148b0
0 ETH0.0001706806730.1
Claim1072700442023-07-23 19:01:05956 days ago1690138865IN
0xE29bD121...FfdF148b0
0 ETH0.0001713130910.1
Claim1072700332023-07-23 19:00:43956 days ago1690138843IN
0xE29bD121...FfdF148b0
0 ETH0.0001715598290.1
Claim1072700112023-07-23 18:59:59956 days ago1690138799IN
0xE29bD121...FfdF148b0
0 ETH0.0001699148740.1
Claim1072699802023-07-23 18:58:57956 days ago1690138737IN
0xE29bD121...FfdF148b0
0 ETH0.0001785864320.1
Claim1072699702023-07-23 18:58:37956 days ago1690138717IN
0xE29bD121...FfdF148b0
0 ETH0.0001769658940.1
Claim1072699572023-07-23 18:58:11956 days ago1690138691IN
0xE29bD121...FfdF148b0
0 ETH0.0001767979310.1
Claim1072699392023-07-23 18:57:35956 days ago1690138655IN
0xE29bD121...FfdF148b0
0 ETH0.0001787918760.1
Claim1072699332023-07-23 18:57:23956 days ago1690138643IN
0xE29bD121...FfdF148b0
0 ETH0.0001858729320.1
Claim1072699182023-07-23 18:56:53956 days ago1690138613IN
0xE29bD121...FfdF148b0
0 ETH0.0001761675180.1
Claim1072699142023-07-23 18:56:45956 days ago1690138605IN
0xE29bD121...FfdF148b0
0 ETH0.0001809379910.1
Claim1072699072023-07-23 18:56:31956 days ago1690138591IN
0xE29bD121...FfdF148b0
0 ETH0.0001876720340.1
Claim1072698962023-07-23 18:56:09956 days ago1690138569IN
0xE29bD121...FfdF148b0
0 ETH0.0001821128220.1
Claim1072698852023-07-23 18:55:47956 days ago1690138547IN
0xE29bD121...FfdF148b0
0 ETH0.0001788448340.1
Claim1072698822023-07-23 18:55:41956 days ago1690138541IN
0xE29bD121...FfdF148b0
0 ETH0.0001790687380.1
Claim1072698542023-07-23 18:54:45956 days ago1690138485IN
0xE29bD121...FfdF148b0
0 ETH0.0001682437580.1
Claim1072698502023-07-23 18:54:37956 days ago1690138477IN
0xE29bD121...FfdF148b0
0 ETH0.0001679759070.1
Claim1072698272023-07-23 18:53:51956 days ago1690138431IN
0xE29bD121...FfdF148b0
0 ETH0.0001743916730.1
Claim1072698162023-07-23 18:53:29956 days ago1690138409IN
0xE29bD121...FfdF148b0
0 ETH0.0001767533680.1
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
1072701122023-07-23 19:03:21956 days ago1690139001
0xE29bD121...FfdF148b0
0 ETH
1072701122023-07-23 19:03:21956 days ago1690139001
0xE29bD121...FfdF148b0
0 ETH
1072701122023-07-23 19:03:21956 days ago1690139001
0xE29bD121...FfdF148b0
0 ETH
1072701122023-07-23 19:03:21956 days ago1690139001
0xE29bD121...FfdF148b0
0 ETH
1072700932023-07-23 19:02:43956 days ago1690138963
0xE29bD121...FfdF148b0
0 ETH
1072700932023-07-23 19:02:43956 days ago1690138963
0xE29bD121...FfdF148b0
0 ETH
1072700932023-07-23 19:02:43956 days ago1690138963
0xE29bD121...FfdF148b0
0 ETH
1072700932023-07-23 19:02:43956 days ago1690138963
0xE29bD121...FfdF148b0
0 ETH
1072700872023-07-23 19:02:31956 days ago1690138951
0xE29bD121...FfdF148b0
0 ETH
1072700872023-07-23 19:02:31956 days ago1690138951
0xE29bD121...FfdF148b0
0 ETH
1072700872023-07-23 19:02:31956 days ago1690138951
0xE29bD121...FfdF148b0
0 ETH
1072700872023-07-23 19:02:31956 days ago1690138951
0xE29bD121...FfdF148b0
0 ETH
1072700842023-07-23 19:02:25956 days ago1690138945
0xE29bD121...FfdF148b0
0 ETH
1072700842023-07-23 19:02:25956 days ago1690138945
0xE29bD121...FfdF148b0
0 ETH
1072700842023-07-23 19:02:25956 days ago1690138945
0xE29bD121...FfdF148b0
0 ETH
1072700842023-07-23 19:02:25956 days ago1690138945
0xE29bD121...FfdF148b0
0 ETH
1072700632023-07-23 19:01:43956 days ago1690138903
0xE29bD121...FfdF148b0
0 ETH
1072700632023-07-23 19:01:43956 days ago1690138903
0xE29bD121...FfdF148b0
0 ETH
1072700632023-07-23 19:01:43956 days ago1690138903
0xE29bD121...FfdF148b0
0 ETH
1072700632023-07-23 19:01:43956 days ago1690138903
0xE29bD121...FfdF148b0
0 ETH
1072700512023-07-23 19:01:19956 days ago1690138879
0xE29bD121...FfdF148b0
0 ETH
1072700512023-07-23 19:01:19956 days ago1690138879
0xE29bD121...FfdF148b0
0 ETH
1072700512023-07-23 19:01:19956 days ago1690138879
0xE29bD121...FfdF148b0
0 ETH
1072700512023-07-23 19:01:19956 days ago1690138879
0xE29bD121...FfdF148b0
0 ETH
1072700472023-07-23 19:01:11956 days ago1690138871
0xE29bD121...FfdF148b0
0 ETH
View All Internal Transactions

Cross-Chain Transactions
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0x7D8ee529...A64FaEb0A
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
RecurringGrantDrop

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 10000 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

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

import {ERC20} from "solmate/tokens/ERC20.sol";
import {SafeTransferLib} from "solmate/utils/SafeTransferLib.sol";
import { IGrant } from './IGrant.sol';
import {IWorldID} from "world-id-contracts/interfaces/IWorldID.sol";
import {IWorldIDGroups} from "world-id-contracts/interfaces/IWorldIDGroups.sol";

/// @title RecurringGrantDrop
/// @author Worldcoin
contract RecurringGrantDrop {
    ///////////////////////////////////////////////////////////////////////////////
    ///                                  ERRORS                                ///
    //////////////////////////////////////////////////////////////////////////////

    /// @notice Thrown when restricted functions are called by not allowed addresses
    error Unauthorized();

    /// @notice Thrown when attempting to reuse a nullifier
    error InvalidNullifier();

    ///////////////////////////////////////////////////////////////////////////////
    ///                                  EVENTS                                ///
    //////////////////////////////////////////////////////////////////////////////

    /// @notice Emitted when a grant is successfully claimed
    /// @param receiver The address that received the tokens
    event GrantClaimed(uint256 grantId, address receiver);

    /// @notice Emitted when the grant is changed
    /// @param grant The new grant instance
    event GrantUpdated(IGrant grant);

    ///////////////////////////////////////////////////////////////////////////////
    ///                              CONFIG STORAGE                            ///
    //////////////////////////////////////////////////////////////////////////////

    /// @dev The WorldID router instance that will be used for managing groups and verifying proofs
    IWorldIDGroups internal immutable worldIdRouter;

    /// @dev The World ID group whose participants can claim this airdrop
    uint256 internal immutable groupId;

    /// @notice The ERC20 token airdropped
    ERC20 public immutable token;

    /// @notice The address that holds the tokens that are being airdropped
    /// @dev Make sure the holder has approved spending for this contract!
    address public immutable holder;

    /// @notice The address that manages this airdrop
    address public immutable manager = msg.sender;

    /// @notice The     grant instance used
    IGrant public grant;

    /// @dev Whether a nullifier hash has been used already. Used to prevent double-signaling
    mapping(uint256 => bool) internal nullifierHashes;

    /// @dev Allowed addresses to call `claim`
    mapping(address => bool) internal allowedCallers;

    ///////////////////////////////////////////////////////////////////////////////
    ///                               CONSTRUCTOR                              ///
    //////////////////////////////////////////////////////////////////////////////

    /// @notice Deploys a WorldIDAirdrop instance
    /// @param _worldIdRouter The WorldID router that will manage groups and verify proofs
    /// @param _groupId The group ID of the World ID
    /// @param _token The ERC20 token that will be airdropped
    /// @param _holder The address holding the tokens that will be airdropped
    /// @param _grant The grant that contains the amounts and validity
    constructor(
        IWorldIDGroups _worldIdRouter,
        uint256 _groupId,
        ERC20 _token,
        address _holder,
        IGrant _grant
    ) {
        worldIdRouter = _worldIdRouter;
        groupId = _groupId;
        token = _token;
        holder = _holder;
        grant = _grant;
    }

    ///////////////////////////////////////////////////////////////////////////////
    ///                               CLAIM LOGIC                               ///
    //////////////////////////////////////////////////////////////////////////////

    /// @notice Claim the airdrop
    /// @param grantId The grant ID to claim
    /// @param receiver The address that will receive the tokens (this is also the signal of the ZKP)
    /// @param root The root of the Merkle tree (signup-sequencer or world-id-contracts provides this)
    /// @param nullifierHash The nullifier for this proof, preventing double signaling
    /// @param proof The zero knowledge proof that demonstrates the claimer has a verified World ID
    /// @dev hashToField function docs are in lib/world-id-contracts/src/libraries/ByteHasher.sol
    function claim(uint256 grantId, address receiver, uint256 root, uint256 nullifierHash, uint256[8] calldata proof)
        public
    {
        if (!allowedCallers[msg.sender]) revert Unauthorized();

        checkClaim(grantId, receiver, root, nullifierHash, proof);

        nullifierHashes[nullifierHash] = true;

        SafeTransferLib.safeTransferFrom(token, holder, receiver, grant.getAmount(grantId));

        emit GrantClaimed(grantId, receiver);
    }

    /// @notice Check whether a claim is valid
    /// @param grantId The grant ID to claim
    /// @param receiver The address that will receive the tokens (this is also the signal of the ZKP)
    /// @param root The root of the Merkle tree (signup-sequencer or world-id-contracts provides this)
    /// @param nullifierHash The nullifier for this proof, preventing double signaling
    /// @param proof The zero knowledge proof that demonstrates the claimer has a verified World ID
    function checkClaim(uint256 grantId, address receiver, uint256 root, uint256 nullifierHash, uint256[8] calldata proof)
        public
    {
        if (nullifierHashes[nullifierHash]) revert InvalidNullifier();
        
        grant.checkValidity(grantId);

        worldIdRouter.verifyProof(
            root,
            groupId,
            uint256(keccak256(abi.encodePacked(receiver))) >> 8,
            nullifierHash,
            grantId,
            proof
        );
    }

    ///////////////////////////////////////////////////////////////////////////////
    ///                               CONFIG LOGIC                             ///
    //////////////////////////////////////////////////////////////////////////////

    /// @notice Add a caller to the list of allowed callers
    /// @param _caller The address to add
    function addAllowedCaller(address _caller) public {
        if (msg.sender != manager) revert Unauthorized();
        allowedCallers[_caller] = true;
    }

    /// @notice Remove a caller to the list of allowed callers
    /// @param _caller The address to remove
    function removeAllowedCaller(address _caller) public {
        if (msg.sender != manager) revert Unauthorized();
        allowedCallers[_caller] = false;
    }

    /// @notice Update the grant
    /// @param _grant The new grant
    function setGrant(IGrant _grant) public {
        if (msg.sender != manager) revert Unauthorized();
        grant = _grant;
        emit GrantUpdated(_grant);
    }
}

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Transfer(address indexed from, address indexed to, uint256 amount);

    event Approval(address indexed owner, address indexed spender, uint256 amount);

    /*//////////////////////////////////////////////////////////////
                            METADATA STORAGE
    //////////////////////////////////////////////////////////////*/

    string public name;

    string public symbol;

    uint8 public immutable decimals;

    /*//////////////////////////////////////////////////////////////
                              ERC20 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 public totalSupply;

    mapping(address => uint256) public balanceOf;

    mapping(address => mapping(address => uint256)) public allowance;

    /*//////////////////////////////////////////////////////////////
                            EIP-2612 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 internal immutable INITIAL_CHAIN_ID;

    bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;

    mapping(address => uint256) public nonces;

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(
        string memory _name,
        string memory _symbol,
        uint8 _decimals
    ) {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;

        INITIAL_CHAIN_ID = block.chainid;
        INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
    }

    /*//////////////////////////////////////////////////////////////
                               ERC20 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 amount) public virtual returns (bool) {
        allowance[msg.sender][spender] = amount;

        emit Approval(msg.sender, spender, amount);

        return true;
    }

    function transfer(address to, uint256 amount) public virtual returns (bool) {
        balanceOf[msg.sender] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(msg.sender, to, amount);

        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual returns (bool) {
        uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.

        if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;

        balanceOf[from] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(from, to, amount);

        return true;
    }

    /*//////////////////////////////////////////////////////////////
                             EIP-2612 LOGIC
    //////////////////////////////////////////////////////////////*/

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual {
        require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");

        // Unchecked because the only math done is incrementing
        // the owner's nonce which cannot realistically overflow.
        unchecked {
            address recoveredAddress = ecrecover(
                keccak256(
                    abi.encodePacked(
                        "\x19\x01",
                        DOMAIN_SEPARATOR(),
                        keccak256(
                            abi.encode(
                                keccak256(
                                    "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
                                ),
                                owner,
                                spender,
                                value,
                                nonces[owner]++,
                                deadline
                            )
                        )
                    )
                ),
                v,
                r,
                s
            );

            require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");

            allowance[recoveredAddress][spender] = value;
        }

        emit Approval(owner, spender, value);
    }

    function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
        return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
    }

    function computeDomainSeparator() internal view virtual returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                    keccak256(bytes(name)),
                    keccak256("1"),
                    block.chainid,
                    address(this)
                )
            );
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(address to, uint256 amount) internal virtual {
        totalSupply += amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(address(0), to, amount);
    }

    function _burn(address from, uint256 amount) internal virtual {
        balanceOf[from] -= amount;

        // Cannot underflow because a user's balance
        // will never be larger than the total supply.
        unchecked {
            totalSupply -= amount;
        }

        emit Transfer(from, address(0), amount);
    }
}

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

import {ERC20} from "../tokens/ERC20.sol";

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.
library SafeTransferLib {
    /*//////////////////////////////////////////////////////////////
                             ETH OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferETH(address to, uint256 amount) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Transfer the ETH and store if it succeeded or not.
            success := call(gas(), to, amount, 0, 0, 0, 0)
        }

        require(success, "ETH_TRANSFER_FAILED");
    }

    /*//////////////////////////////////////////////////////////////
                            ERC20 OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferFrom(
        ERC20 token,
        address from,
        address to,
        uint256 amount
    ) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "from" argument.
            mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
            mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
            )
        }

        require(success, "TRANSFER_FROM_FAILED");
    }

    function safeTransfer(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
            )
        }

        require(success, "TRANSFER_FAILED");
    }

    function safeApprove(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
            )
        }

        require(success, "APPROVE_FAILED");
    }
}

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

interface IGrant {
    /// @notice Error in case the grant is invalid.
    error InvalidGrant();

    /// @notice Returns the current grant id.
    function getCurrentId() external view returns (uint256);

    /// @notice Returns the amount of tokens for a grant.
    /// @notice This may contain more complicated logic and is therefore not just a member variable.
    /// @param grantId The grant id to get the amount for.
    function getAmount(uint256 grantId) external view returns (uint256);

    /// @notice Checks whether a grant is valid.
    /// @param grantId The grant id to check.
    function checkValidity(uint256 grantId) external view;
}

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

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

/// @title WorldID Interface
/// @author Worldcoin
/// @notice The interface to the proof verification for WorldID.
interface IWorldID is IBaseWorldID {
    /// @notice Verifies a WorldID zero knowledge proof.
    /// @dev Note that a double-signaling check is not included here, and should be carried by the
    ///      caller.
    /// @dev It is highly recommended that the implementation is restricted to `view` if possible.
    ///
    /// @param root The of the Merkle tree
    /// @param signalHash A keccak256 hash of the Semaphore signal
    /// @param nullifierHash The nullifier hash
    /// @param externalNullifierHash A keccak256 hash of the external nullifier
    /// @param proof The zero-knowledge proof
    ///
    /// @custom:reverts string If the `proof` is invalid.
    function verifyProof(
        uint256 root,
        uint256 signalHash,
        uint256 nullifierHash,
        uint256 externalNullifierHash,
        uint256[8] calldata proof
    ) external;
}

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

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

/// @title WorldID Interface with Groups
/// @author Worldcoin
/// @notice The interface to the proof verification for WorldID.
interface IWorldIDGroups is IBaseWorldID {
    /// @notice Verifies a WorldID zero knowledge proof.
    /// @dev Note that a double-signaling check is not included here, and should be carried by the
    ///      caller.
    /// @dev It is highly recommended that the implementation is restricted to `view` if possible.
    ///
    /// @param groupId The group identifier for the group to verify a proof for.
    /// @param root The of the Merkle tree
    /// @param signalHash A keccak256 hash of the Semaphore signal
    /// @param nullifierHash The nullifier hash
    /// @param externalNullifierHash A keccak256 hash of the external nullifier
    /// @param proof The zero-knowledge proof
    ///
    /// @custom:reverts string If the `proof` is invalid.
    /// @custom:reverts NoSuchGroup If the provided `groupId` references a group that does not exist.
    function verifyProof(
        uint256 root,
        uint256 groupId,
        uint256 signalHash,
        uint256 nullifierHash,
        uint256 externalNullifierHash,
        uint256[8] calldata proof
    ) external;
}

File 7 of 7 : IBaseWorldID.sol
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

/// @title Base WorldID interface
/// @author Worldcoin
/// @notice The interface providing basic types across various WorldID contracts.
interface IBaseWorldID {
    ///////////////////////////////////////////////////////////////////////////////
    ///                                  ERRORS                                 ///
    ///////////////////////////////////////////////////////////////////////////////

    /// @notice Thrown when attempting to validate a root that has expired.
    error ExpiredRoot();

    /// @notice Thrown when attempting to validate a root that has yet to be added to the root
    ///         history.
    error NonExistentRoot();
}

Settings
{
  "remappings": [
    "@openzeppelin/=lib/openzeppelin-contracts/",
    "@prb/test/=lib/prb-test/src/",
    "@zk-kit/=lib/zk-kit/packages/",
    "contracts-upgradeable/=lib/world-id-contracts/lib/openzeppelin-contracts-upgradeable/contracts/",
    "ds-test/=lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts-upgradeable/=lib/world-id-contracts/lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "openzeppelin/=lib/openzeppelin-contracts/contracts/",
    "prb-test/=lib/prb-test/src/",
    "semaphore/=lib/semaphore/",
    "solmate/=lib/solmate/src/",
    "src/=src/",
    "world-id-contracts/=lib/world-id-contracts/src/",
    "zk-kit/=lib/zk-kit/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 10000,
    "details": {
      "peephole": true,
      "inliner": true,
      "deduplicate": true,
      "cse": true,
      "yul": true
    }
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "none",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"contract IWorldIDGroups","name":"_worldIdRouter","type":"address"},{"internalType":"uint256","name":"_groupId","type":"uint256"},{"internalType":"contract ERC20","name":"_token","type":"address"},{"internalType":"address","name":"_holder","type":"address"},{"internalType":"contract IGrant","name":"_grant","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InvalidNullifier","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"grantId","type":"uint256"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"}],"name":"GrantClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IGrant","name":"grant","type":"address"}],"name":"GrantUpdated","type":"event"},{"inputs":[{"internalType":"address","name":"_caller","type":"address"}],"name":"addAllowedCaller","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"grantId","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"root","type":"uint256"},{"internalType":"uint256","name":"nullifierHash","type":"uint256"},{"internalType":"uint256[8]","name":"proof","type":"uint256[8]"}],"name":"checkClaim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"grantId","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"root","type":"uint256"},{"internalType":"uint256","name":"nullifierHash","type":"uint256"},{"internalType":"uint256[8]","name":"proof","type":"uint256[8]"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"grant","outputs":[{"internalType":"contract IGrant","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"holder","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"manager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_caller","type":"address"}],"name":"removeAllowedCaller","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IGrant","name":"_grant","type":"address"}],"name":"setGrant","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

0x610120604052336101005234801561001657600080fd5b50604051610b55380380610b5583398101604081905261003591610086565b6001600160a01b0394851660805260a09390935290831660c052821660e052600080546001600160a01b031916919092161790556100f1565b6001600160a01b038116811461008357600080fd5b50565b600080600080600060a0868803121561009e57600080fd5b85516100a98161006e565b6020870151604088015191965094506100c18161006e565b60608701519093506100d28161006e565b60808701519092506100e38161006e565b809150509295509295909350565b60805160a05160c05160e051610100516109fd6101586000396000818161010b015281816101df015281816102c7015261038501526000818161017e01526107250152600081816101a5015261070301526000610532015260006104f501526109fd6000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c80639546f95e11610076578063a41e6ceb1161005b578063a41e6ceb14610166578063e534155d14610179578063fc0c546a146101a057600080fd5b80639546f95e1461014057806398359fd11461015357600080fd5b806330c3eaa8146100a85780633e450d71146100f1578063481c6a7514610106578063613a7b481461012d575b600080fd5b6000546100c89073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6101046100ff36600461091f565b6101c7565b005b6100c87f000000000000000000000000000000000000000000000000000000000000000081565b61010461013b36600461091f565b6102af565b61010461014e36600461091f565b61036d565b610104610161366004610943565b610428565b610104610174366004610943565b61063e565b6100c87f000000000000000000000000000000000000000000000000000000000000000081565b6100c87f000000000000000000000000000000000000000000000000000000000000000081565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610236576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f7f877502ebf2038c3656d0c4c3a24f370b4bc208246c5138817a9babdb433c2a9060200160405180910390a150565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461031e576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff16600090815260026020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146103dc576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff16600090815260026020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b60008281526001602052604090205460ff1615610471576040517f5d904cb200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000546040517f77153fd00000000000000000000000000000000000000000000000000000000081526004810187905273ffffffffffffffffffffffffffffffffffffffff909116906377153fd09060240160006040518083038186803b1580156104db57600080fd5b505afa1580156104ef573d6000803e3d6000fd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16633bc778e3847f000000000000000000000000000000000000000000000000000000000000000060088860405160200161058f919060609190911b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016815260140190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905280516020909101207fffffffff0000000000000000000000000000000000000000000000000000000060e087901b1682526106059493921c9088908c90899060040161099f565b600060405180830381600087803b15801561061f57600080fd5b505af1158015610633573d6000803e3d6000fd5b505050505050505050565b3360009081526002602052604090205460ff16610687576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6106948585858585610428565b600082815260016020819052604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016909217909155905490517f9980ec86000000000000000000000000000000000000000000000000000000008152600481018790526107af917f0000000000000000000000000000000000000000000000000000000000000000917f000000000000000000000000000000000000000000000000000000000000000091889173ffffffffffffffffffffffffffffffffffffffff90911690639980ec8690602401602060405180830381865afa158015610786573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107aa91906109d7565b610804565b6040805186815273ffffffffffffffffffffffffffffffffffffffff861660208201527fcb745ef40e04fcff0b474c186c7befb757851b212a93baa6c1665c7ae52e3a7a910160405180910390a15050505050565b60006040517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015273ffffffffffffffffffffffffffffffffffffffff841660248201528260448201526020600060648360008a5af13d15601f3d11600160005114161716915050806108f3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c4544000000000000000000000000604482015260640160405180910390fd5b5050505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461091c57600080fd5b50565b60006020828403121561093157600080fd5b813561093c816108fa565b9392505050565b600080600080600061018080878903121561095d57600080fd5b86359550602087013561096f816108fa565b9450604087013593506060870135925080870188101561098e57600080fd5b506080860190509295509295909350565b60006101a0820190508782528660208301528560408301528460608301528360808301526101008360a0840137979650505050505050565b6000602082840312156109e957600080fd5b505191905056fea164736f6c6343000813000a00000000000000000000000057f928158c3ee7cdad1e4d8642503c4d0201f61100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000346c32e5d7e98bd57100b6f7002a0ae1718804800000000000000000000000080dc00811e7c4a03c1f1599d3dc8febaad87bf87000000000000000000000000e89fa795611a1da4cf5e4c7ec908f4244f13aad1

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100a35760003560e01c80639546f95e11610076578063a41e6ceb1161005b578063a41e6ceb14610166578063e534155d14610179578063fc0c546a146101a057600080fd5b80639546f95e1461014057806398359fd11461015357600080fd5b806330c3eaa8146100a85780633e450d71146100f1578063481c6a7514610106578063613a7b481461012d575b600080fd5b6000546100c89073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6101046100ff36600461091f565b6101c7565b005b6100c87f0000000000000000000000007d896339a80dd38bc3bbb04383894c62b2ef258581565b61010461013b36600461091f565b6102af565b61010461014e36600461091f565b61036d565b610104610161366004610943565b610428565b610104610174366004610943565b61063e565b6100c87f00000000000000000000000080dc00811e7c4a03c1f1599d3dc8febaad87bf8781565b6100c87f0000000000000000000000000346c32e5d7e98bd57100b6f7002a0ae1718804881565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000007d896339a80dd38bc3bbb04383894c62b2ef25851614610236576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f7f877502ebf2038c3656d0c4c3a24f370b4bc208246c5138817a9babdb433c2a9060200160405180910390a150565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000007d896339a80dd38bc3bbb04383894c62b2ef2585161461031e576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff16600090815260026020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000007d896339a80dd38bc3bbb04383894c62b2ef258516146103dc576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff16600090815260026020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b60008281526001602052604090205460ff1615610471576040517f5d904cb200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000546040517f77153fd00000000000000000000000000000000000000000000000000000000081526004810187905273ffffffffffffffffffffffffffffffffffffffff909116906377153fd09060240160006040518083038186803b1580156104db57600080fd5b505afa1580156104ef573d6000803e3d6000fd5b505050507f00000000000000000000000057f928158c3ee7cdad1e4d8642503c4d0201f61173ffffffffffffffffffffffffffffffffffffffff16633bc778e3847f000000000000000000000000000000000000000000000000000000000000000160088860405160200161058f919060609190911b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016815260140190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905280516020909101207fffffffff0000000000000000000000000000000000000000000000000000000060e087901b1682526106059493921c9088908c90899060040161099f565b600060405180830381600087803b15801561061f57600080fd5b505af1158015610633573d6000803e3d6000fd5b505050505050505050565b3360009081526002602052604090205460ff16610687576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6106948585858585610428565b600082815260016020819052604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016909217909155905490517f9980ec86000000000000000000000000000000000000000000000000000000008152600481018790526107af917f0000000000000000000000000346c32e5d7e98bd57100b6f7002a0ae17188048917f00000000000000000000000080dc00811e7c4a03c1f1599d3dc8febaad87bf8791889173ffffffffffffffffffffffffffffffffffffffff90911690639980ec8690602401602060405180830381865afa158015610786573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107aa91906109d7565b610804565b6040805186815273ffffffffffffffffffffffffffffffffffffffff861660208201527fcb745ef40e04fcff0b474c186c7befb757851b212a93baa6c1665c7ae52e3a7a910160405180910390a15050505050565b60006040517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015273ffffffffffffffffffffffffffffffffffffffff841660248201528260448201526020600060648360008a5af13d15601f3d11600160005114161716915050806108f3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c4544000000000000000000000000604482015260640160405180910390fd5b5050505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461091c57600080fd5b50565b60006020828403121561093157600080fd5b813561093c816108fa565b9392505050565b600080600080600061018080878903121561095d57600080fd5b86359550602087013561096f816108fa565b9450604087013593506060870135925080870188101561098e57600080fd5b506080860190509295509295909350565b60006101a0820190508782528660208301528560408301528460608301528360808301526101008360a0840137979650505050505050565b6000602082840312156109e957600080fd5b505191905056fea164736f6c6343000813000a

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.