ETH Price: $3,255.79 (+5.18%)
Gas: 5.76 Gwei
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Transfer Control156099412022-09-25 10:58:35858 days ago1664103515IN
0x0B8107Ea...F50685f84
0 ETH0.000152144.96139281
Claim150606252022-07-02 3:26:39943 days ago1656732399IN
0x0B8107Ea...F50685f84
0 ETH0.0008854910.78899717
Claim148849952022-06-01 13:16:53974 days ago1654089413IN
0x0B8107Ea...F50685f84
0 ETH0.0037016645.108134
Claim148791722022-05-31 14:22:35974 days ago1654006955IN
0x0B8107Ea...F50685f84
0 ETH0.0034909241.71951147
Claim148271862022-05-23 3:17:22983 days ago1653275842IN
0x0B8107Ea...F50685f84
0 ETH0.0016841420.12649795
Claim148138652022-05-20 23:12:24985 days ago1653088344IN
0x0B8107Ea...F50685f84
0 ETH0.0018260421.82020886
Claim147934862022-05-17 16:08:36988 days ago1652803716IN
0x0B8107Ea...F50685f84
0 ETH0.0032095838.73975716
Claim147204522022-05-06 0:47:001000 days ago1651798020IN
0x0B8107Ea...F50685f84
0 ETH0.0026368231.52055122
Claim147155622022-05-05 5:59:491001 days ago1651730389IN
0x0B8107Ea...F50685f84
0 ETH0.0020922525
Claim146992602022-05-02 15:57:211003 days ago1651507041IN
0x0B8107Ea...F50685f84
0 ETH0.0073201987.47004894
Claim146974552022-05-02 9:12:411004 days ago1651482761IN
0x0B8107Ea...F50685f84
0 ETH0.003038736.3143206
Claim146952962022-05-02 1:01:291004 days ago1651453289IN
0x0B8107Ea...F50685f84
0 ETH0.0043145851.57289565
Claim146917002022-05-01 11:29:081005 days ago1651404548IN
0x0B8107Ea...F50685f84
0 ETH0.0028573834.15553732
Claim146874722022-04-30 19:31:441005 days ago1651347104IN
0x0B8107Ea...F50685f84
0 ETH0.0043583852.09023088
Claim146851852022-04-30 10:54:461006 days ago1651316086IN
0x0B8107Ea...F50685f84
0 ETH0.0021125225.49204718
Claim146828262022-04-30 2:03:301006 days ago1651284210IN
0x0B8107Ea...F50685f84
0 ETH0.002284627.30169538
Claim146827782022-04-30 1:53:401006 days ago1651283620IN
0x0B8107Ea...F50685f84
0 ETH0.0024625429.72218063
Claim146827772022-04-30 1:53:031006 days ago1651283583IN
0x0B8107Ea...F50685f84
0 ETH0.0022895327.36064099
Claim146825142022-04-30 0:51:011006 days ago1651279861IN
0x0B8107Ea...F50685f84
0 ETH0.0019049722.7687631
Claim146804812022-04-29 17:13:041006 days ago1651252384IN
0x0B8107Ea...F50685f84
0 ETH0.0063127975.45233096
Claim146800492022-04-29 15:41:581006 days ago1651246918IN
0x0B8107Ea...F50685f84
0 ETH0.0045127853.94330105
Claim146792392022-04-29 12:42:201007 days ago1651236140IN
0x0B8107Ea...F50685f84
0 ETH0.0034474441.60461582
Claim146788462022-04-29 11:15:131007 days ago1651230913IN
0x0B8107Ea...F50685f84
0 ETH0.0021663725.88574283
Claim146787162022-04-29 10:45:131007 days ago1651229113IN
0x0B8107Ea...F50685f84
0 ETH0.0011808338.58552413
Claim146787132022-04-29 10:44:271007 days ago1651229067IN
0x0B8107Ea...F50685f84
0 ETH0.0028855634.48822113
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
MerkleDistributorV2

Compiler Version
v0.8.10+commit.fc410830

Optimization Enabled:
Yes with 20000 runs

Other Settings:
default evmVersion
File 1 of 6 : MerkleDistributorV2.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity =0.8.10;

import {MerkleProof} from "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
import {BitMaps} from "@openzeppelin/contracts/utils/structs/BitMaps.sol";
import {SafeTransferLib} from "@rari-capital/solmate/src/utils/SafeTransferLib.sol";
import {ERC20} from "@rari-capital/solmate/src/tokens/ERC20.sol";
import {Controlled} from "../utils/Controlled.sol";

/// @notice Distributes ERC20 tokens based on a Merkle Tree, can be used for consecutive distributions.
/// @dev Based on MerkleDistributor (https://github.com/nation3/app/blob/main/contracts/src/distributors/MerkleDistributor.sol)
/// @dev Tree & claims can be reset by owner
contract MerkleDistributorV2 is Controlled {
    /*///////////////////////////////////////////////////////////////
                               LIBRARIES
    //////////////////////////////////////////////////////////////*/

    using SafeTransferLib for ERC20;
    using BitMaps for BitMaps.BitMap;

    /*///////////////////////////////////////////////////////////////
                                 ERRORS
    //////////////////////////////////////////////////////////////*/

    error InvalidProof();
    error AlreadyClaimed();

    /*///////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Claimed(uint256 indexed index, address indexed recipient, uint256 amount);

    /*///////////////////////////////////////////////////////////////
                        INMUTABLES / CONSTANTS
    //////////////////////////////////////////////////////////////*/

    address public sender;
    ERC20 public token;
    bytes32 public merkleRoot;

    /*///////////////////////////////////////////////////////////////
                                 STORAGE
    //////////////////////////////////////////////////////////////*/

    /// @dev This is a mapping of packed arrays of booleans to signal that a leaf has been claimed.
    /// As you can't delete complex structs on solidity you need to select the active bitmap
    mapping (uint16 => BitMaps.BitMap) private claims;
    /// @dev This signal de id of the drop
    /// This contract supports up to 2^16 different drops
    uint16 dropId;

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

    constructor() {}

    /*///////////////////////////////////////////////////////////////
                             CONTROLLER ACTIONS
    //////////////////////////////////////////////////////////////*/

    /// @dev Set token contract, tokens sender and merkle tree's root.
    /// @param _sender The account to send airdrop tokens from.
    /// @param _token The token to airdrop.
    /// @param _merkleRoot The root of the merkle tree.
    function setUp(address _sender, ERC20 _token, bytes32 _merkleRoot) public onlyController {
        sender = _sender;
        token = _token;
        merkleRoot = _merkleRoot;
        dropId += 1;
    }

    /*///////////////////////////////////////////////////////////////
                                USER ACTIONS
    //////////////////////////////////////////////////////////////*/

    /// @notice Claims tokens for a recipient if the proofs are valid.
    /// @param index The index into the merkle tree.
    /// @param recipient The account of the claim being made.
    /// @param merkleProof The merkle proof proving the claim is valid.
    function claim(
        uint256 index,
        address recipient,
        uint256 amount,
        bytes32[] calldata merkleProof
    ) external {
        if (isClaimed(index)) revert AlreadyClaimed();

        // Verify the merkle proof.
        bytes32 leaf = keccak256(abi.encodePacked(index, recipient, amount));
        if (!MerkleProof.verify(merkleProof, merkleRoot, leaf)) revert InvalidProof();

        // Mark it claimed and send the tokens.
        claims[dropId].set(index);
        token.safeTransferFrom(sender, recipient, amount);

        emit Claimed(index, recipient, amount);
    }

    /// @notice Check if the claim at the given index has already been made.
    /// @param index The index into the merkle tree.
    function isClaimed(uint256 index) public view returns (bool) {
        return claims[dropId].get(index);
    }
}

File 2 of 6 : Controlled.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity =0.8.10;

/// @notice Minimal implementation of access control mechanism with two roles (owner & controller)
/// @dev Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol)
contract Controlled {
    /*///////////////////////////////////////////////////////////////
                                 ERRORS
    //////////////////////////////////////////////////////////////*/

    error CallerIsNotAuthorized();
    error TargetIsZeroAddress();

    /*///////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    event ControlTransferred(address indexed previousController, address indexed newController);

    /*///////////////////////////////////////////////////////////////
                             ROLES STORAGE
    //////////////////////////////////////////////////////////////*/

    address private _owner;
    address private _controller;

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

    constructor() {
        _transferOwnership(msg.sender);
        _transferControl(msg.sender);
    }

    /*///////////////////////////////////////////////////////////////
                               MODIFIERS
    //////////////////////////////////////////////////////////////*/

    modifier onlyOwner() {
        if (_owner != msg.sender) revert CallerIsNotAuthorized();
        _;
    }

    modifier onlyController() {
        if (_controller != msg.sender) revert CallerIsNotAuthorized();
        _;
    }

    modifier onlyOwnerOrController() {
        if (_owner != msg.sender && _controller != msg.sender) revert CallerIsNotAuthorized();
        _;
    }

    /*///////////////////////////////////////////////////////////////
                                VIEWS
    //////////////////////////////////////////////////////////////*/

    function owner() public view virtual returns (address) {
        return _owner;
    }

    function controller() public view virtual returns (address) {
        return _controller;
    }

    /*///////////////////////////////////////////////////////////////
                               ACTIONS
    //////////////////////////////////////////////////////////////*/

    function renounceOwnership() external virtual onlyOwner {
        _transferOwnership(address(0));
    }

    function removeControl() external virtual onlyOwnerOrController {
        _transferControl(address(0));
    }

    function transferOwnership(address newOwner) external virtual onlyOwner {
        if (newOwner == address(0)) revert TargetIsZeroAddress();
        _transferOwnership(newOwner);
    }

    function transferControl(address newController) external virtual onlyOwnerOrController {
        if (newController == address(0)) revert TargetIsZeroAddress();
        _transferControl(newController);
    }

    /*///////////////////////////////////////////////////////////////
                            INTERNAL LOGIC
    //////////////////////////////////////////////////////////////*/

    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }

    function _transferControl(address newController) internal virtual {
        address oldController = _controller;
        _controller = newController;
        emit ControlTransferred(oldController, newController);
    }
}

File 3 of 6 : 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/Rari-Capital/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
    //////////////////////////////////////////////////////////////*/

    bytes32 public constant PERMIT_TYPEHASH =
        keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");

    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 {
            bytes32 digest = keccak256(
                abi.encodePacked(
                    "\x19\x01",
                    DOMAIN_SEPARATOR(),
                    keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
                )
            );

            address recoveredAddress = ecrecover(digest, 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 4 of 6 : 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/Rari-Capital/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @author Modified from Gnosis (https://github.com/gnosis/gp-v2-contracts/blob/main/src/contracts/libraries/GPv2SafeERC20.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
library SafeTransferLib {
    /*///////////////////////////////////////////////////////////////
                            ETH OPERATIONS
    //////////////////////////////////////////////////////////////*/

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

        assembly {
            // Transfer the ETH and store if it succeeded or not.
            callStatus := call(gas(), to, amount, 0, 0, 0, 0)
        }

        require(callStatus, "ETH_TRANSFER_FAILED");
    }

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

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

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

            // Write the abi-encoded calldata to memory piece by piece:
            mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000) // Begin with the function selector.
            mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Mask and append the "from" argument.
            mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Mask and append the "to" argument.
            mstore(add(freeMemoryPointer, 68), amount) // Finally append the "amount" argument. No mask as it's a full 32 byte value.

            // Call the token and store if it succeeded or not.
            // We use 100 because the calldata length is 4 + 32 * 3.
            callStatus := call(gas(), token, 0, freeMemoryPointer, 100, 0, 0)
        }

        require(didLastOptionalReturnCallSucceed(callStatus), "TRANSFER_FROM_FAILED");
    }

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

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

            // Write the abi-encoded calldata to memory piece by piece:
            mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) // Begin with the function selector.
            mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Mask and append the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Finally append the "amount" argument. No mask as it's a full 32 byte value.

            // Call the token and store if it succeeded or not.
            // We use 68 because the calldata length is 4 + 32 * 2.
            callStatus := call(gas(), token, 0, freeMemoryPointer, 68, 0, 0)
        }

        require(didLastOptionalReturnCallSucceed(callStatus), "TRANSFER_FAILED");
    }

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

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

            // Write the abi-encoded calldata to memory piece by piece:
            mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000) // Begin with the function selector.
            mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Mask and append the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Finally append the "amount" argument. No mask as it's a full 32 byte value.

            // Call the token and store if it succeeded or not.
            // We use 68 because the calldata length is 4 + 32 * 2.
            callStatus := call(gas(), token, 0, freeMemoryPointer, 68, 0, 0)
        }

        require(didLastOptionalReturnCallSucceed(callStatus), "APPROVE_FAILED");
    }

    /*///////////////////////////////////////////////////////////////
                         INTERNAL HELPER LOGIC
    //////////////////////////////////////////////////////////////*/

    function didLastOptionalReturnCallSucceed(bool callStatus) private pure returns (bool success) {
        assembly {
            // Get how many bytes the call returned.
            let returnDataSize := returndatasize()

            // If the call reverted:
            if iszero(callStatus) {
                // Copy the revert message into memory.
                returndatacopy(0, 0, returnDataSize)

                // Revert with the same message.
                revert(0, returnDataSize)
            }

            switch returnDataSize
            case 32 {
                // Copy the return data into memory.
                returndatacopy(0, 0, returnDataSize)

                // Set success to whether it returned true.
                success := iszero(iszero(mload(0)))
            }
            case 0 {
                // There was no return data.
                success := 1
            }
            default {
                // It returned some malformed input.
                success := 0
            }
        }
    }
}

File 5 of 6 : BitMaps.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/structs/BitMaps.sol)
pragma solidity ^0.8.0;

/**
 * @dev Library for managing uint256 to bool mapping in a compact and efficient way, providing the keys are sequential.
 * Largelly inspired by Uniswap's https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol[merkle-distributor].
 */
library BitMaps {
    struct BitMap {
        mapping(uint256 => uint256) _data;
    }

    /**
     * @dev Returns whether the bit at `index` is set.
     */
    function get(BitMap storage bitmap, uint256 index) internal view returns (bool) {
        uint256 bucket = index >> 8;
        uint256 mask = 1 << (index & 0xff);
        return bitmap._data[bucket] & mask != 0;
    }

    /**
     * @dev Sets the bit at `index` to the boolean `value`.
     */
    function setTo(
        BitMap storage bitmap,
        uint256 index,
        bool value
    ) internal {
        if (value) {
            set(bitmap, index);
        } else {
            unset(bitmap, index);
        }
    }

    /**
     * @dev Sets the bit at `index`.
     */
    function set(BitMap storage bitmap, uint256 index) internal {
        uint256 bucket = index >> 8;
        uint256 mask = 1 << (index & 0xff);
        bitmap._data[bucket] |= mask;
    }

    /**
     * @dev Unsets the bit at `index`.
     */
    function unset(BitMap storage bitmap, uint256 index) internal {
        uint256 bucket = index >> 8;
        uint256 mask = 1 << (index & 0xff);
        bitmap._data[bucket] &= ~mask;
    }
}

File 6 of 6 : MerkleProof.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (utils/cryptography/MerkleProof.sol)

pragma solidity ^0.8.0;

/**
 * @dev These functions deal with verification of Merkle Trees proofs.
 *
 * The proofs can be generated using the JavaScript library
 * https://github.com/miguelmota/merkletreejs[merkletreejs].
 * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.
 *
 * See `test/utils/cryptography/MerkleProof.test.js` for some examples.
 *
 * WARNING: You should avoid using leaf values that are 64 bytes long prior to
 * hashing, or use a hash function other than keccak256 for hashing leaves.
 * This is because the concatenation of a sorted pair of internal nodes in
 * the merkle tree could be reinterpreted as a leaf value.
 */
library MerkleProof {
    /**
     * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
     * defined by `root`. For this, a `proof` must be provided, containing
     * sibling hashes on the branch from the leaf to the root of the tree. Each
     * pair of leaves and each pair of pre-images are assumed to be sorted.
     */
    function verify(
        bytes32[] memory proof,
        bytes32 root,
        bytes32 leaf
    ) internal pure returns (bool) {
        return processProof(proof, leaf) == root;
    }

    /**
     * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
     * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
     * hash matches the root of the tree. When processing the proof, the pairs
     * of leafs & pre-images are assumed to be sorted.
     *
     * _Available since v4.4._
     */
    function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            bytes32 proofElement = proof[i];
            if (computedHash <= proofElement) {
                // Hash(current computed hash + current element of the proof)
                computedHash = _efficientHash(computedHash, proofElement);
            } else {
                // Hash(current element of the proof + current computed hash)
                computedHash = _efficientHash(proofElement, computedHash);
            }
        }
        return computedHash;
    }

    function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
        assembly {
            mstore(0x00, a)
            mstore(0x20, b)
            value := keccak256(0x00, 0x40)
        }
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 20000
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyClaimed","type":"error"},{"inputs":[],"name":"CallerIsNotAuthorized","type":"error"},{"inputs":[],"name":"InvalidProof","type":"error"},{"inputs":[],"name":"TargetIsZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousController","type":"address"},{"indexed":true,"internalType":"address","name":"newController","type":"address"}],"name":"ControlTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"controller","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"isClaimed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"merkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"removeControl","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sender","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"contract ERC20","name":"_token","type":"address"},{"internalType":"bytes32","name":"_merkleRoot","type":"bytes32"}],"name":"setUp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newController","type":"address"}],"name":"transferControl","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]

608060405234801561001057600080fd5b5061001a33610028565b61002333610078565b6100ca565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907fa06677f7b64342b4bcbde423684dbdb5356acfe41ad0285b6ecbe6dc4bf427f290600090a35050565b610c44806100d96000396000f3fe608060405234801561001057600080fd5b50600436106100d45760003560e01c80637bee684b11610081578063f2fde38b1161005b578063f2fde38b146101f6578063f77c479114610209578063fc0c546a1461022757600080fd5b80637bee684b1461017d5780638da5cb5b146101855780639e34070f146101a357600080fd5b806367e404ce116100b257806367e404ce1461011d5780636d16fa4114610162578063715018a61461017557600080fd5b80632e7ba6ef146100d95780632eb4a7ab146100ee57806361fa554f1461010a575b600080fd5b6100ec6100e7366004610a3a565b610247565b005b6100f760045481565b6040519081526020015b60405180910390f35b6100ec610118366004610ad3565b610434565b60025461013d9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610101565b6100ec610170366004610b14565b610518565b6100ec6105e8565b6100ec610645565b60005473ffffffffffffffffffffffffffffffffffffffff1661013d565b6101e66101b1366004610b38565b60065461ffff166000908152600560209081526040808320600885901c8452909152812054600160ff84161b16151592915050565b6040519015158152602001610101565b6100ec610204366004610b14565b6106c6565b60015473ffffffffffffffffffffffffffffffffffffffff1661013d565b60035461013d9073ffffffffffffffffffffffffffffffffffffffff1681565b60065461ffff166000908152600560209081526040808320600889901c8452909152902054600160ff87161b16156102ab576040517f646cf55800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051602081018790527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606087901b16918101919091526054810184905260009060740160405160208183030381529060405280519060200120905061034a83838080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050600454915084905061076d565b610380576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60065461ffff16600090815260056020908152604080832060088a901c845290915290208054600160ff89161b1790556002546003546103db9173ffffffffffffffffffffffffffffffffffffffff91821691168787610783565b8473ffffffffffffffffffffffffffffffffffffffff16867f4ec90e965519d92681267467f775ada5bd214aa92c0dc93d90a5e880ce9ed0268660405161042491815260200190565b60405180910390a3505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610485576040517f2e57521500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002805473ffffffffffffffffffffffffffffffffffffffff8086167fffffffffffffffffffffffff0000000000000000000000000000000000000000928316179092556003805492851692909116919091179055600481905560068054600191906000906104f990849061ffff16610b80565b92506101000a81548161ffff021916908361ffff160217905550505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314801590610558575060015473ffffffffffffffffffffffffffffffffffffffff163314155b1561058f576040517f2e57521500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166105dc576040517f1b8fe22300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105e581610871565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314610639576040517f2e57521500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61064360006108e8565b565b60005473ffffffffffffffffffffffffffffffffffffffff163314801590610685575060015473ffffffffffffffffffffffffffffffffffffffff163314155b156106bc576040517f2e57521500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6106436000610871565b60005473ffffffffffffffffffffffffffffffffffffffff163314610717576040517f2e57521500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116610764576040517f1b8fe22300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105e5816108e8565b60008261077a858461095d565b14949350505050565b60006040517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015273ffffffffffffffffffffffffffffffffffffffff8416602482015282604482015260008060648360008a5af1915050610800816109d1565b61086a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c4544000000000000000000000000604482015260640160405180910390fd5b5050505050565b6001805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907fa06677f7b64342b4bcbde423684dbdb5356acfe41ad0285b6ecbe6dc4bf427f290600090a35050565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600081815b84518110156109c957600085828151811061097f5761097f610ba6565b602002602001015190508083116109a557600083815260208290526040902092506109b6565b600081815260208490526040902092505b50806109c181610bd5565b915050610962565b509392505050565b60003d826109e357806000803e806000fd5b80602081146109fb578015610a0c5760009250610a11565b816000803e60005115159250610a11565b600192505b5050919050565b73ffffffffffffffffffffffffffffffffffffffff811681146105e557600080fd5b600080600080600060808688031215610a5257600080fd5b853594506020860135610a6481610a18565b935060408601359250606086013567ffffffffffffffff80821115610a8857600080fd5b818801915088601f830112610a9c57600080fd5b813581811115610aab57600080fd5b8960208260051b8501011115610ac057600080fd5b9699959850939650602001949392505050565b600080600060608486031215610ae857600080fd5b8335610af381610a18565b92506020840135610b0381610a18565b929592945050506040919091013590565b600060208284031215610b2657600080fd5b8135610b3181610a18565b9392505050565b600060208284031215610b4a57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061ffff808316818516808303821115610b9d57610b9d610b51565b01949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415610c0757610c07610b51565b506001019056fea264697066735822122009af9abdf9569e97985e22bf2e24ef3ec2fd33f98139805f7f5eac4e0a33621764736f6c634300080a0033

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100d45760003560e01c80637bee684b11610081578063f2fde38b1161005b578063f2fde38b146101f6578063f77c479114610209578063fc0c546a1461022757600080fd5b80637bee684b1461017d5780638da5cb5b146101855780639e34070f146101a357600080fd5b806367e404ce116100b257806367e404ce1461011d5780636d16fa4114610162578063715018a61461017557600080fd5b80632e7ba6ef146100d95780632eb4a7ab146100ee57806361fa554f1461010a575b600080fd5b6100ec6100e7366004610a3a565b610247565b005b6100f760045481565b6040519081526020015b60405180910390f35b6100ec610118366004610ad3565b610434565b60025461013d9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610101565b6100ec610170366004610b14565b610518565b6100ec6105e8565b6100ec610645565b60005473ffffffffffffffffffffffffffffffffffffffff1661013d565b6101e66101b1366004610b38565b60065461ffff166000908152600560209081526040808320600885901c8452909152812054600160ff84161b16151592915050565b6040519015158152602001610101565b6100ec610204366004610b14565b6106c6565b60015473ffffffffffffffffffffffffffffffffffffffff1661013d565b60035461013d9073ffffffffffffffffffffffffffffffffffffffff1681565b60065461ffff166000908152600560209081526040808320600889901c8452909152902054600160ff87161b16156102ab576040517f646cf55800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051602081018790527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606087901b16918101919091526054810184905260009060740160405160208183030381529060405280519060200120905061034a83838080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050600454915084905061076d565b610380576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60065461ffff16600090815260056020908152604080832060088a901c845290915290208054600160ff89161b1790556002546003546103db9173ffffffffffffffffffffffffffffffffffffffff91821691168787610783565b8473ffffffffffffffffffffffffffffffffffffffff16867f4ec90e965519d92681267467f775ada5bd214aa92c0dc93d90a5e880ce9ed0268660405161042491815260200190565b60405180910390a3505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610485576040517f2e57521500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002805473ffffffffffffffffffffffffffffffffffffffff8086167fffffffffffffffffffffffff0000000000000000000000000000000000000000928316179092556003805492851692909116919091179055600481905560068054600191906000906104f990849061ffff16610b80565b92506101000a81548161ffff021916908361ffff160217905550505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314801590610558575060015473ffffffffffffffffffffffffffffffffffffffff163314155b1561058f576040517f2e57521500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166105dc576040517f1b8fe22300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105e581610871565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314610639576040517f2e57521500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61064360006108e8565b565b60005473ffffffffffffffffffffffffffffffffffffffff163314801590610685575060015473ffffffffffffffffffffffffffffffffffffffff163314155b156106bc576040517f2e57521500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6106436000610871565b60005473ffffffffffffffffffffffffffffffffffffffff163314610717576040517f2e57521500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116610764576040517f1b8fe22300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105e5816108e8565b60008261077a858461095d565b14949350505050565b60006040517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015273ffffffffffffffffffffffffffffffffffffffff8416602482015282604482015260008060648360008a5af1915050610800816109d1565b61086a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c4544000000000000000000000000604482015260640160405180910390fd5b5050505050565b6001805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907fa06677f7b64342b4bcbde423684dbdb5356acfe41ad0285b6ecbe6dc4bf427f290600090a35050565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600081815b84518110156109c957600085828151811061097f5761097f610ba6565b602002602001015190508083116109a557600083815260208290526040902092506109b6565b600081815260208490526040902092505b50806109c181610bd5565b915050610962565b509392505050565b60003d826109e357806000803e806000fd5b80602081146109fb578015610a0c5760009250610a11565b816000803e60005115159250610a11565b600192505b5050919050565b73ffffffffffffffffffffffffffffffffffffffff811681146105e557600080fd5b600080600080600060808688031215610a5257600080fd5b853594506020860135610a6481610a18565b935060408601359250606086013567ffffffffffffffff80821115610a8857600080fd5b818801915088601f830112610a9c57600080fd5b813581811115610aab57600080fd5b8960208260051b8501011115610ac057600080fd5b9699959850939650602001949392505050565b600080600060608486031215610ae857600080fd5b8335610af381610a18565b92506020840135610b0381610a18565b929592945050506040919091013590565b600060208284031215610b2657600080fd5b8135610b3181610a18565b9392505050565b600060208284031215610b4a57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061ffff808316818516808303821115610b9d57610b9d610b51565b01949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415610c0757610c07610b51565b506001019056fea264697066735822122009af9abdf9569e97985e22bf2e24ef3ec2fd33f98139805f7f5eac4e0a33621764736f6c634300080a0033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
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  ]

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.