Contract 0xec11fc239bb43474b270242ddaae9fb7973936c1 2

 

Contract Overview

Balance:
0 MATIC

MATIC Value:
$0.00

Token:
 
Txn Hash
Method
Block
From
To
Value [Txn Fee]
0x686981bb2700a2a71c80e1e3f32bd7ea68c180306a5196ff0ca896692d28198fClaim432613242023-05-28 19:56:5615 secs ago0x65bf36d6499a504100eb504f0719271f5c4174ec IN  0xec11fc239bb43474b270242ddaae9fb7973936c10 MATIC0.068443204609 171.948841359
0x3ffdeb51d2caa8b281adcc01157e81b81825782a2f814567cf3d0f852b1491c5Claim432613222023-05-28 19:56:5219 secs ago0xb54a5205ee454f48ddfc23ca26a3836ba3dacc07 IN  0xec11fc239bb43474b270242ddaae9fb7973936c10 MATIC0.068021013823 170.888177747
0x8a17885b9edf5041f21303fa2c3522bd7bfa044664da7c851787dce0cdc2d881Claim432613222023-05-28 19:56:5219 secs ago0xabe494eaa4ed80de8583c49183e9cbdadbc3b954 IN  0xec11fc239bb43474b270242ddaae9fb7973936c10 MATIC0.070352862829 176.767763569
0x1d74b917984eca8983ec407e8059b213ee6a5ee7e593a54bba0b9733bd9d9c22Claim432613222023-05-28 19:56:5219 secs ago0x65bf36d6499a504100eb504f0719271f5c4174ec IN  0xec11fc239bb43474b270242ddaae9fb7973936c10 MATIC0.073377712799 176.767763569
0x681b3daba22a330335b61843ce261ecc98dde78b8f3e006745cb897cda6336d1Claim432613202023-05-28 19:56:4823 secs ago0x4399fa85585f90da110d5ba150ff96c763bc0aba IN  0xec11fc239bb43474b270242ddaae9fb7973936c10 MATIC0.065250516202 163.93778253
0xbb5d3c3c98a5be834ede2addc14296fc3f3f93ce732e480cb40de3cf6b020506Claim432613192023-05-28 19:56:4625 secs ago0xb54a5205ee454f48ddfc23ca26a3836ba3dacc07 IN  0xec11fc239bb43474b270242ddaae9fb7973936c10 MATIC0.062142901349 156.125390295
0x5997b00b500d3e441d8eddd60e2398b4318b2e14c6bb109452b38b86c4f830aeClaim432613192023-05-28 19:56:4625 secs ago0xd8f7d2d62514895475afe0c7d75f31390dd40de4 IN  0xec11fc239bb43474b270242ddaae9fb7973936c10 MATIC0.06213915434 156.125390295
0x977bed7d77f8b86c4aaaa42cb48a7c081277348d4d13d557aa7413deb3c61206Claim432613192023-05-28 19:56:4625 secs ago0xabe494eaa4ed80de8583c49183e9cbdadbc3b954 IN  0xec11fc239bb43474b270242ddaae9fb7973936c10 MATIC0.062141027845 156.125390295
0xf9f75c4b166cce529c430adfd57885b830d528513c80a03d7894503eddf081a0Claim432613192023-05-28 19:56:4625 secs ago0xabe494eaa4ed80de8583c49183e9cbdadbc3b954 IN  0xec11fc239bb43474b270242ddaae9fb7973936c10 MATIC0.062142901349 156.125390295
0xb329f9dad7ce3fbd26478b719535bf1e0330c2f143fa3b69077852e4709840caClaim432613192023-05-28 19:56:4625 secs ago0xb54a5205ee454f48ddfc23ca26a3836ba3dacc07 IN  0xec11fc239bb43474b270242ddaae9fb7973936c10 MATIC0.062142901349 156.125390295
0xaf6cb11780b1ab84641773506671ef3504df077f97b410f7dc2b9b64fb145851Claim432613182023-05-28 19:56:4427 secs ago0xd8f7d2d62514895475afe0c7d75f31390dd40de4 IN  0xec11fc239bb43474b270242ddaae9fb7973936c10 MATIC0.061762601274 148.77392248
0xe9f3e1b77cffb47c41b74c033c43edcb422aa29c5e3b9f56b007f2477f7ec233Claim432613182023-05-28 19:56:4427 secs ago0xd8f7d2d62514895475afe0c7d75f31390dd40de4 IN  0xec11fc239bb43474b270242ddaae9fb7973936c10 MATIC0.059214996625 148.77392248
0xdbc2b9da8c11d74b72bef9233f498939bafa7a2bc5b31218eae5eb8e4ef7c96dClaim432613182023-05-28 19:56:4427 secs ago0x4399fa85585f90da110d5ba150ff96c763bc0aba IN  0xec11fc239bb43474b270242ddaae9fb7973936c10 MATIC0.059216781912 148.77392248
0x272cce18778f366148c5a654b8cef9c52a0452ca4ae2b29c765389edfb3c9e6aClaim432613182023-05-28 19:56:4427 secs ago0xd8f7d2d62514895475afe0c7d75f31390dd40de4 IN  0xec11fc239bb43474b270242ddaae9fb7973936c10 MATIC0.059211426051 148.77392248
0x1fc1916ffdd58b7890955b275ae6b2175af99c74704232a0ac371fa521206e40Claim432613182023-05-28 19:56:4427 secs ago0xd8f7d2d62514895475afe0c7d75f31390dd40de4 IN  0xec11fc239bb43474b270242ddaae9fb7973936c10 MATIC0.059214996625 148.77392248
0x6a873744736dcd7333a84b58e09441f4461a3e30e56a28a1aeca73b74a74cb26Claim432613182023-05-28 19:56:4427 secs ago0x65bf36d6499a504100eb504f0719271f5c4174ec IN  0xec11fc239bb43474b270242ddaae9fb7973936c10 MATIC0.059218567199 148.77392248
0x0a72500181a8839b41ec26a2c263f555edae2b1784ed0cec4c2556f360bc7b6cClaim432613182023-05-28 19:56:4427 secs ago0x65bf36d6499a504100eb504f0719271f5c4174ec IN  0xec11fc239bb43474b270242ddaae9fb7973936c10 MATIC0.059214996625 148.77392248
0x67e81dbcf49d50e0ab8ca1d9503a083b084e9e1106421542084b9af43f37f8c2Claim432613182023-05-28 19:56:4427 secs ago0xd8f7d2d62514895475afe0c7d75f31390dd40de4 IN  0xec11fc239bb43474b270242ddaae9fb7973936c10 MATIC0.059218567199 148.77392248
0xade0da83265af7f4de9b4ea861fba188ab753d369bd0c5d3349c32f4ef9453beClaim432613182023-05-28 19:56:4427 secs ago0x4399fa85585f90da110d5ba150ff96c763bc0aba IN  0xec11fc239bb43474b270242ddaae9fb7973936c10 MATIC0.059216781912 148.77392248
0xecc2b8e81b13e14672ffbb3e5f741c0556bbd969ea46d4476b85e15c2c182144Claim432613182023-05-28 19:56:4427 secs ago0xd8f7d2d62514895475afe0c7d75f31390dd40de4 IN  0xec11fc239bb43474b270242ddaae9fb7973936c10 MATIC0.059218567199 148.77392248
0xa22a76ce74f40a61ddf8c49932acf6b5b5a3408197023ebb6be4e3b058070a39Claim432613182023-05-28 19:56:4427 secs ago0x65bf36d6499a504100eb504f0719271f5c4174ec IN  0xec11fc239bb43474b270242ddaae9fb7973936c10 MATIC0.059218567199 148.77392248
0x1a39aa46d7e7256146362e664d966189202f408f8c072495b71e76c32ac2ed70Claim432613112023-05-28 19:56:071 min ago0xb54a5205ee454f48ddfc23ca26a3836ba3dacc07 IN  0xec11fc239bb43474b270242ddaae9fb7973936c10 MATIC0.062625571325 157.342775049
0xd054664a6d5f1e7384b91bda50eb824a1c3aeeefb5bf906d367b99e9794cfb1fClaim432613092023-05-28 19:56:031 min ago0xd8f7d2d62514895475afe0c7d75f31390dd40de4 IN  0xec11fc239bb43474b270242ddaae9fb7973936c10 MATIC0.064297340908 161.538119821
0xb4cf9d62bab30853e9e06ab03fda201f53a974f53a0cf31426cf8afb25a6a655Claim432613062023-05-28 19:55:571 min ago0x4399fa85585f90da110d5ba150ff96c763bc0aba IN  0xec11fc239bb43474b270242ddaae9fb7973936c10 MATIC0.07045794636 175.075156695
0xe3867781119e01d4303b846bf5447ccc80afe895e7e407767af4fe0d34aa240bClaim432613052023-05-28 19:55:551 min ago0xb54a5205ee454f48ddfc23ca26a3836ba3dacc07 IN  0xec11fc239bb43474b270242ddaae9fb7973936c10 MATIC0.069712876347 175.154460081
[ Download CSV Export 
Parent Txn Hash Block From To Value
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
RecurringGrantDrop

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 10000 runs

Other Settings:
default evmVersion
File 1 of 7 : RecurringGrantDrop.sol
// 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";
import {ByteHasher} from "world-id-contracts/libraries/ByteHasher.sol";

/// @title RecurringGrantDrop
/// @author Worldcoin
contract RecurringGrantDrop {
    using ByteHasher for bytes;

    ///////////////////////////////////////////////////////////////////////////////
    ///                                  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 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 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(
            groupId,
            root,
            abi.encodePacked(receiver).hashToField(),
            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);
    }
}

File 2 of 7 : ERC20.sol
// 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);
    }
}

File 3 of 7 : SafeTransferLib.sol
// 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), from) // Append the "from" argument.
            mstore(add(freeMemoryPointer, 36), to) // Append the "to" argument.
            mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument.

            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), to) // Append the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument.

            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), to) // Append the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument.

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

File 4 of 7 : IGrant.sol
// 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;
}

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

/// @title WorldID Interface
/// @author Worldcoin
/// @notice The interface to the proof verification for WorldID.
interface IWorldID {
    /// @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;
}

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

/// @title WorldID Interface with Groups
/// @author Worldcoin
/// @notice The interface to the proof verification for WorldID.
interface IWorldIDGroups {
    /// @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 groupId,
        uint256 root,
        uint256 signalHash,
        uint256 nullifierHash,
        uint256 externalNullifierHash,
        uint256[8] calldata proof
    ) external;
}

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

library ByteHasher {
    /// @dev Creates a keccak256 hash of a bytestring.
    /// @param value The bytestring to hash
    /// @return The hash of the specified value
    /// @dev `>> 8` makes sure that the result is included in our field
    function hashToField(bytes memory value) internal pure returns (uint256) {
        return uint256(keccak256(abi.encodePacked(value))) >> 8;
    }
}

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/",
    "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": {
    "bytecodeHash": "none",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"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"}]

610120604052336101005234801561001657600080fd5b50604051610b6e380380610b6e83398101604081905261003591610086565b6001600160a01b0394851660805260a09390935290831660c052821660e052600080546001600160a01b031916919092161790556100f1565b6001600160a01b038116811461008357600080fd5b50565b600080600080600060a0868803121561009e57600080fd5b85516100a98161006e565b6020870151604088015191965094506100c18161006e565b60608701519093506100d28161006e565b60808701519092506100e38161006e565b809150509295509295909350565b60805160a05160c05160e05161010051610a166101586000396000818161010b015281816101df015281816102c7015261038501526000818161017e01526106e80152600081816101a501526106c601526000610531015260006104f50152610a166000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c80639546f95e11610076578063a41e6ceb1161005b578063a41e6ceb14610166578063e534155d14610179578063fc0c546a146101a057600080fd5b80639546f95e1461014057806398359fd11461015357600080fd5b806330c3eaa8146100a85780633e450d71146100f1578063481c6a7514610106578063613a7b481461012d575b600080fd5b6000546100c89073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6101046100ff366004610909565b6101c7565b005b6100c87f000000000000000000000000000000000000000000000000000000000000000081565b61010461013b366004610909565b6102af565b61010461014e366004610909565b61036d565b61010461016136600461092d565b610428565b61010461017436600461092d565b610601565b6100c87f000000000000000000000000000000000000000000000000000000000000000081565b6100c87f000000000000000000000000000000000000000000000000000000000000000081565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610236576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f7f877502ebf2038c3656d0c4c3a24f370b4bc208246c5138817a9babdb433c2a9060200160405180910390a150565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461031e576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff16600090815260026020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146103dc576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff16600090815260026020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b60008281526001602052604090205460ff1615610471576040517f5d904cb200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000546040517f77153fd00000000000000000000000000000000000000000000000000000000081526004810187905273ffffffffffffffffffffffffffffffffffffffff909116906377153fd09060240160006040518083038186803b1580156104db57600080fd5b505afa1580156104ef573d6000803e3d6000fd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16633bc778e37f0000000000000000000000000000000000000000000000000000000000000000856105a488604051602001610590919060609190911b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016815260140190565b6040516020818303038152906040526107c7565b868a876040518763ffffffff1660e01b81526004016105c896959493929190610989565b600060405180830381600087803b1580156105e257600080fd5b505af11580156105f6573d6000803e3d6000fd5b505050505050505050565b3360009081526002602052604090205460ff1661064a576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6106578585858585610428565b600082815260016020819052604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016909217909155905490517f9980ec8600000000000000000000000000000000000000000000000000000000815260048101879052610772917f0000000000000000000000000000000000000000000000000000000000000000917f000000000000000000000000000000000000000000000000000000000000000091889173ffffffffffffffffffffffffffffffffffffffff90911690639980ec8690602401602060405180830381865afa158015610749573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061076d91906109c1565b61081a565b6040805186815273ffffffffffffffffffffffffffffffffffffffff861660208201527fcb745ef40e04fcff0b474c186c7befb757851b212a93baa6c1665c7ae52e3a7a910160405180910390a15050505050565b60006008826040516020016107dc91906109da565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120901c92915050565b60006040517f23b872dd0000000000000000000000000000000000000000000000000000000081528460048201528360248201528260448201526020600060648360008a5af13d15601f3d11600160005114161716915050806108dd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c4544000000000000000000000000604482015260640160405180910390fd5b5050505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461090657600080fd5b50565b60006020828403121561091b57600080fd5b8135610926816108e4565b9392505050565b600080600080600061018080878903121561094757600080fd5b863595506020870135610959816108e4565b9450604087013593506060870135925080870188101561097857600080fd5b506080860190509295509295909350565b60006101a0820190508782528660208301528560408301528460608301528360808301526101008360a0840137979650505050505050565b6000602082840312156109d357600080fd5b5051919050565b6000825160005b818110156109fb57602081860181015185830152016109e1565b50600092019182525091905056fea164736f6c6343000813000a000000000000000000000000f7134ce138832c1456f2a91d64621ee90c2bddea00000000000000000000000000000000000000000000000000000000000000010000000000000000000000008acecfa353f46c6afe235b2b838154426612cdd800000000000000000000000080dc00811e7c4a03c1f1599d3dc8febaad87bf87000000000000000000000000d7243020c24895e669773868ffbff4b581d8cd6d

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000f7134ce138832c1456f2a91d64621ee90c2bddea00000000000000000000000000000000000000000000000000000000000000010000000000000000000000008acecfa353f46c6afe235b2b838154426612cdd800000000000000000000000080dc00811e7c4a03c1f1599d3dc8febaad87bf87000000000000000000000000d7243020c24895e669773868ffbff4b581d8cd6d

-----Decoded View---------------
Arg [0] : _worldIdRouter (address): 0xf7134ce138832c1456f2a91d64621ee90c2bddea
Arg [1] : _groupId (uint256): 1
Arg [2] : _token (address): 0x8acecfa353f46c6afe235b2b838154426612cdd8
Arg [3] : _holder (address): 0x80dc00811e7c4a03c1f1599d3dc8febaad87bf87
Arg [4] : _grant (address): 0xd7243020c24895e669773868ffbff4b581d8cd6d

-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 000000000000000000000000f7134ce138832c1456f2a91d64621ee90c2bddea
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [2] : 0000000000000000000000008acecfa353f46c6afe235b2b838154426612cdd8
Arg [3] : 00000000000000000000000080dc00811e7c4a03c1f1599d3dc8febaad87bf87
Arg [4] : 000000000000000000000000d7243020c24895e669773868ffbff4b581d8cd6d


Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.