Contract 0x80b3ecb0cbbbc2a6cbf0e84bcdae8f9c00518b8e 1

 

Contract Overview

Balance:
0 MATIC

MATIC Value:
$0.00

Token:
 
Txn Hash Method
Block
From
To
Value [Txn Fee]
0x98da00bbf73b62587774949699911b947c18a8177c1fd94cf7b2df1afe50e921Claim336061292022-09-26 22:03:5510 hrs 22 mins ago0xc1a219b38b7a68e0c1e9970e2da9b7692ebb466a IN  0x80b3ecb0cbbbc2a6cbf0e84bcdae8f9c00518b8e0 MATIC0.003562967697 31.48721851
0xdcceb09abf52cf133528472f04bb4acaa95a9bddf921483f3c0575003aaa53b6Claim333330552022-09-20 6:23:257 days 2 hrs ago0xa90626f3ed8e2da950edfd3b89b72db719e16f1a IN  0x80b3ecb0cbbbc2a6cbf0e84bcdae8f9c00518b8e0 MATIC0.003952524961 34.920000017
0xe44978500163dd62c4f80f557d3de532673461766c6eb698b55e6c411e235c1aClaim333217392022-09-19 23:50:077 days 8 hrs ago0x8777330c6757dd80a20257ba4fd509e539912b2d IN  0x80b3ecb0cbbbc2a6cbf0e84bcdae8f9c00518b8e0 MATIC0.003395640001 30.000000009
0xc8966ecec7ca64465e2bfef660b1968d79639de09fe31dc6ae399a892dbcb03dClaim333003032022-09-19 11:31:097 days 20 hrs ago0xd4de4de57f5a79201162e1de70084b539c0ee433 IN  0x80b3ecb0cbbbc2a6cbf0e84bcdae8f9c00518b8e0 MATIC0.005658450
0x457168a68d7c49b4d516f61edc02eec53f7b4542afa9b56197d10fb86d634f31Claim332605332022-09-18 12:36:218 days 19 hrs ago0x88a4fe5aa4b4880d5b102e54a00af2ee53b1e268 IN  0x80b3ecb0cbbbc2a6cbf0e84bcdae8f9c00518b8e0 MATIC0.003394680005 30.000000048
0xbfff3ade9828f9f9303a42c5b75bcabb45b0d6bf1fa6b79cd216884f5f0ac0b4Claim330536942022-09-13 12:57:5513 days 19 hrs ago0x7659365e286ac02f716d28c443ab1a2d04cba844 IN  0x80b3ecb0cbbbc2a6cbf0e84bcdae8f9c00518b8e0 MATIC0.150425087512 1,329.219280297
0x8e136eb798184851c08d9efc85f486fc559ecc1b4c95435b6c20a3409922320aClaim330532562022-09-13 12:42:5513 days 19 hrs ago0xfd02f6cd1aadd2b284a926f9ef39b14ab154b87e IN  0x80b3ecb0cbbbc2a6cbf0e84bcdae8f9c00518b8e0 MATIC0.030062825316 265.600817368
0xb4a6946bf290afdd619450acb4fcaab1a53253e2dfdc715f5e053b88c88b1915Claim330531412022-09-13 12:38:5713 days 19 hrs ago0x900a8005a288b8e41939fe30496d39b630860ba0 IN  0x80b3ecb0cbbbc2a6cbf0e84bcdae8f9c00518b8e0 MATIC0.042121772516 372.205681076
0xdac1d99a361c665e8f5607dda838bebe7e133556cf8a203903f33dfe19e68e87Claim325728972022-09-01 22:22:4025 days 10 hrs ago0xd913e61edb2743baa73df61c75809530142398b9 IN  0x80b3ecb0cbbbc2a6cbf0e84bcdae8f9c00518b8e0 MATIC0.003403563159 30.069999994
0xcc5fb9482e3d6cfdd3864eefa5bbe426743be7344dbcc5ec396b8f192acfed5fClaim324821892022-08-30 12:23:3327 days 20 hrs ago0x6d4eacbcdd13b87cda8166c799cfb7876904b4d1 IN  0x80b3ecb0cbbbc2a6cbf0e84bcdae8f9c00518b8e0 MATIC0.003052884954 31.782345238
0x1344bde198a07624dad385bc67808aefc35a013490707b4857564c92df6ce6deClaim321235632022-08-20 20:03:2937 days 12 hrs ago0xa13d0df9075c4d61cee4f3051d30215e32e61e76 IN  0x80b3ecb0cbbbc2a6cbf0e84bcdae8f9c00518b8e0 MATIC0.003485872788 30.802636684
0x325b17b834929279109859f33942d1d512358fef1a4b82eedd9d384ebed410dbClaim320621492022-08-19 6:59:5339 days 1 hr ago0xb65aebf7cc84b3f6818a6277b762760121dc9492 IN  0x80b3ecb0cbbbc2a6cbf0e84bcdae8f9c00518b8e0 MATIC0.009258841997 96.369977911
0x962a18a36fedacbac08f59b55b623a9c35527885a019ca1eb2f080ee5fc76635Claim320572212022-08-19 4:06:0339 days 4 hrs ago0x99ba1e0d7a9f9ca3782c84016fa5347d48bc3d0b IN  0x80b3ecb0cbbbc2a6cbf0e84bcdae8f9c00518b8e0 MATIC0.003232835827 33.644532379
0x211f315685c2a652908ed643b21d97cc69b75d5c69274feb5ef4dbb51808e6a8Claim319866432022-08-17 6:48:4541 days 1 hr ago0x005a191ab8001efec30a836554997448ee273c39 IN  0x80b3ecb0cbbbc2a6cbf0e84bcdae8f9c00518b8e0 MATIC0.002881320006 30.000000064
0xc35b3956acc8649aa59e3b510a0ddd5cc39baa4f6b9bb8826de5fa1e9897e2a8Claim317214702022-08-10 5:33:3548 days 2 hrs ago0x66cb7714752be6a0f9e703103fa417a26194d013 IN  0x80b3ecb0cbbbc2a6cbf0e84bcdae8f9c00518b8e0 MATIC0.003541227547 31.291774597
0x248642b0d3d467dbb2fb760125c16ed556fab2fa750fa1c3c506f2e1028951bbClaim316144642022-08-07 6:44:5651 days 1 hr ago0x6687c671980e65ebd722b9146fc61e2471558dd6 IN  0x80b3ecb0cbbbc2a6cbf0e84bcdae8f9c00518b8e0 MATIC0.00690251661
0xa0fc4dfb6981d90065d212ae2e0088c735f5c66f2b345bbb8bdf476f96a89a29Claim316072462022-08-07 1:49:0651 days 6 hrs ago0x7d9335a43254233359892a3b8df039b4204b277b IN  0x80b3ecb0cbbbc2a6cbf0e84bcdae8f9c00518b8e0 MATIC0.003518691976 31.087146843
0xe5a31a79cb1a5b36854b82a11f87582b4b71af72742f7171954c03ca01107fc5Claim315485572022-08-05 12:46:0152 days 19 hrs ago0xff5de4b5b323f6aaea92bead362f5f418ce9e195 IN  0x80b3ecb0cbbbc2a6cbf0e84bcdae8f9c00518b8e0 MATIC0.003961836455 41.231334355
0x0b0fe2e7aea2c1c8a38e11da07adca8880efeb5c15c648090dfba68ec67d966fClaim315485362022-08-05 12:45:1552 days 19 hrs ago0xf5f8fe45dbbc5e2d13dcf7b052f4d5ae9f6140d0 IN  0x80b3ecb0cbbbc2a6cbf0e84bcdae8f9c00518b8e0 MATIC0.004275474486 37.783895562
0x9f92028c16dad5a7d0e00e79e82f283c4fdda83c9d846451ed9bcaaa141b372aClaim315078532022-08-04 10:51:3653 days 21 hrs ago0xb8268407a0b6b2292bb9cd61663aaab6175a97da IN  0x80b3ecb0cbbbc2a6cbf0e84bcdae8f9c00518b8e0 MATIC0.003560175565 31.462543437
0xd5b375c8e7adba9e253272ccc28c1cd632539d90d463b63378941c5599140130Claim314674732022-08-03 9:29:0754 days 22 hrs ago0x746bb7befd31d9052bb8eba7d5dd74c9acf54c6d IN  0x80b3ecb0cbbbc2a6cbf0e84bcdae8f9c00518b8e0 MATIC0.004855299593 42.903467356
0xbcf119df4de2aab5e7cbe8b2a4dab693265ec4ffa4deef41e6300b084f226921Claim314376382022-08-02 15:22:3155 days 17 hrs ago0xb3d1e41f84acd0e77f83473aa62fc8560c2a3c0c IN  0x80b3ecb0cbbbc2a6cbf0e84bcdae8f9c00518b8e0 MATIC0.059702291409 527.554533166
0xdc99d79293547fd81b82637e29954251bc4b1316739386a2c838e69b8d2424a7Claim314245512022-08-02 7:22:3156 days 1 hr ago0x2d8a36abca760d066dfdefcbd61b213d2edf675e IN  0x80b3ecb0cbbbc2a6cbf0e84bcdae8f9c00518b8e0 MATIC0.006686035691 59.070181394
0x78c0b0aaa25c3c221d1d5b33ff9d0899c02a23bb2efa52980b2f97eeb3dba586Claim314127882022-08-02 0:08:0856 days 8 hrs ago0x0041df1e2c32ced11bf89ed72ca090b51970b736 IN  0x80b3ecb0cbbbc2a6cbf0e84bcdae8f9c00518b8e0 MATIC0.003394936271 30.00014379
0x12d5f65be7cd8b82297f5998fdb20545480c4afa8f9f43c287eec558d5cc96d7Claim313082642022-07-30 9:01:5658 days 23 hrs ago0xd66eed53d6fe72b1fa85c1e52f8ccd15f85a76b6 IN  0x80b3ecb0cbbbc2a6cbf0e84bcdae8f9c00518b8e0 MATIC0.002882040765 30.000007967
[ Download CSV Export 
Parent Txn Hash Block From To Value
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Fairdrop

Compiler Version
v0.8.13+commit.abaa5c0e

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 7 : Fairdrop.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.13;

import '@openzeppelin/contracts/access/Ownable.sol';
import '@openzeppelin/contracts/utils/cryptography/ECDSA.sol';
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';

import './IFairdrop.sol';

// https://github.com/Uniswap/merkle-distributor
contract Fairdrop is IFairdrop, Ownable {
    using ECDSA for bytes32;

    address public immutable token;
    address public signer;
    uint256 public amountPerAddress;

    mapping(address => bool) public addressClaimed;
    mapping(bytes32 => bool) public userIdClaimed;

    constructor(
        address token_,
        address signer_,
        address owner_,
        uint256 amountPerAddress_
    ) {
        if (token_ == address(0) || signer_ == address(0) || owner_ == address(0)) {
            revert ZeroAddress();
        }

        token = token_;
        signer = signer_;
        amountPerAddress = amountPerAddress_;

        // immediately transfer ownership to a multisig
        if (owner_ != address(0)) {
            transferOwnership(owner_);
        }
    }

    //////////////////////////////
    /// Claim
    //////////////////////////////

    /// @inheritdoc IFairdrop
    function claim(
        address account_,
        bytes32 userId_,
        string memory nonce_,
        uint256 expiredAt_,
        uint8 v_,
        bytes32 r_,
        bytes32 s_
    ) external returns (bool success) {
        // Check if the claim is expired
        // slither-disable-next-line timestamp
        if (expiredAt_ < block.timestamp) {
            revert ClaimExpired();
        }

        // Check if the address/userId has already claimed a fairdrop
        if (addressClaimed[account_]) {
            revert AddressAlreadyClaimed(account_);
        }
        if (userIdClaimed[userId_]) {
            revert UserIdAlreadyClaimed(userId_);
        }

        // Verify the signature
        bytes32 hash = keccak256(abi.encodePacked(account_, userId_, nonce_, expiredAt_, address(this)))
            .toEthSignedMessageHash();
        if (!_verify(hash, v_, r_, s_)) {
            revert InvalidSignature();
        }

        // Mark as claimed
        addressClaimed[account_] = true;
        userIdClaimed[userId_] = true;

        // Transfer tokens
        uint256 amount = amountPerAddress;

        emit Claimed(account_, userId_, amount);

        if (!IERC20(token).transfer(account_, amount)) {
            revert TransferFailed(account_, amount);
        }

        return true;
    }

    /// @inheritdoc IFairdrop
    function setAmountPerAddress(uint256 amount_) external onlyOwner {
        amountPerAddress = amount_;
        emit AmountChanged(amount_);
    }

    //////////////////////////////
    /// Withdraw
    //////////////////////////////

    /// @inheritdoc IFairdrop
    function sweep(address target_) external onlyOwner {
        IERC20 tokenContract = IERC20(token);
        uint256 balance = tokenContract.balanceOf(address(this));

        emit Swept(target_, balance);

        if (!tokenContract.transfer(target_, balance)) {
            revert TransferFailed(target_, balance);
        }
    }

    //////////////////////////////
    /// Verify
    //////////////////////////////

    /// @inheritdoc IFairdrop
    function setSigner(address signer_) external onlyOwner {
        if (signer_ == address(0)) {
            revert ZeroAddress();
        }

        signer = signer_;
        emit SignerChanged(signer_);
    }

    /**
     * @dev verify if a signature is signed by signer
     */
    function _verify(
        bytes32 hash_,
        uint8 v_,
        bytes32 r_,
        bytes32 s_
    ) internal view returns (bool isSignedBySigner) {
        address recoveredAddress = hash_.recover(v_, r_, s_);
        isSignedBySigner = recoveredAddress != address(0) && recoveredAddress == signer;
    }
}

File 2 of 7 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

File 3 of 7 : ECDSA.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.0;

import "../Strings.sol";

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS,
        InvalidSignatureV
    }

    function _throwError(RecoverError error) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert("ECDSA: invalid signature");
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert("ECDSA: invalid signature length");
        } else if (error == RecoverError.InvalidSignatureS) {
            revert("ECDSA: invalid signature 's' value");
        } else if (error == RecoverError.InvalidSignatureV) {
            revert("ECDSA: invalid signature 'v' value");
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature` or error string. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
        // Check the signature length
        // - case 65: r,s,v signature (standard)
        // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else if (signature.length == 64) {
            bytes32 r;
            bytes32 vs;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            assembly {
                r := mload(add(signature, 0x20))
                vs := mload(add(signature, 0x40))
            }
            return tryRecover(hash, r, vs);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength);
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, signature);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address, RecoverError) {
        bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
        uint8 v = uint8((uint256(vs) >> 255) + 27);
        return tryRecover(hash, v, r, s);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     *
     * _Available since v4.2._
     */
    function recover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, r, vs);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address, RecoverError) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS);
        }
        if (v != 27 && v != 28) {
            return (address(0), RecoverError.InvalidSignatureV);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature);
        }

        return (signer, RecoverError.NoError);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from a `hash`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from `s`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
    }

    /**
     * @dev Returns an Ethereum Signed Typed Data, created from a
     * `domainSeparator` and a `structHash`. This produces hash corresponding
     * to the one signed with the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
     * JSON-RPC method as part of EIP-712.
     *
     * See {recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
    }
}

File 4 of 7 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
}

File 5 of 7 : IFairdrop.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

/**
 * @title Interface for fairdrop contract
 *
 * The fairdrop
 *
 * @author Michael Bauer <[email protected]>
 */
interface IFairdrop {
    //////////////////////////////
    /// Error types
    //////////////////////////////

    /**
     * @dev Address has already claimed the fairdrop.
     */
    error AddressAlreadyClaimed(address account);

    /**
     * @dev Requires non-zero address.
     */
    error ZeroAddress();

    /**
     * @dev Address has already claimed the fairdrop.
     */
    error UserIdAlreadyClaimed(bytes32 userId);

    /**
     * @dev The fairdrop claiming has expired.
     */
    error ClaimExpired();

    /**
     * @dev Invalid signature.
     */
    error InvalidSignature();

    /**
     * @dev Failed to transfer tokens.
     */
    error TransferFailed(address account, uint256 amount);

    //////////////////////////////
    /// Event types
    //////////////////////////////

    /**
     * @notice Drop is claimed.
     * @param account Address that claimed the drop.
     * @param userId Hashed User ID that claimed the drop.
     * @param amount Amount of tokens that were claimed.
     */
    event Claimed(address indexed account, bytes32 indexed userId, uint256 amount);

    /**
     * @notice Unclaimed funds were swept.
     * @param target Address that received the funds.
     * @param amount Amount of tokens that were swept.
     */
    event Swept(address indexed target, uint256 amount);

    /**
     * @notice Amount is changed.
     * @param amount New amount.
     */
    event AmountChanged(uint256 amount);

    /**
     * @notice Signer is changed.
     * @param signer New signer of the fairdrop.
     */
    event SignerChanged(address indexed signer);

    //////////////////////////////
    /// Claim
    //////////////////////////////

    /**
     * @notice Claim a fairdrop.
     *
     * @dev Throws: `AlreadyClaimed` or `ClaimExpired` error.
     * @dev Emits: `Claimed` events.
     *
     * @param account_ Address that claims the drop.
     * @param userId_ Hashed User ID that claims the drop.
     * @param nonce_ Unique ID to claim the drop.
     * @param expiredAt_ Timestamp when the drop expires.
     * @param v_ Signature field.
     * @param r_ Signature field.
     * @param s_ Signature field.
     * @return success Whether the claim was successful.
     */
    function claim(
        address account_,
        bytes32 userId_,
        string memory nonce_,
        uint256 expiredAt_,
        uint8 v_,
        bytes32 r_,
        bytes32 s_
    ) external returns (bool success);

    /**
     * @notice Set the amount of tokens can be claimed per address.
     * @param amount_ New amount.
     */
    function setAmountPerAddress(uint256 amount_) external;

    //////////////////////////////
    /// Withdraw
    //////////////////////////////

    /**
     * @notice Sweep any unclaimed funds
     * @dev Transfers the full tokenbalance from the contract to `target` address.
     *
     * @param target_ Address that should receive the unclaimed funds
     */
    function sweep(address target_) external;

    //////////////////////////////
    /// Verify
    //////////////////////////////

    /**
     * @notice Set a new signer for the contract
     * @param signer_ Address of the new signer.
     */
    function setSigner(address signer_) external;
}

File 6 of 7 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

File 7 of 7 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)

pragma solidity ^0.8.0;

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0x00";
        }
        uint256 temp = value;
        uint256 length = 0;
        while (temp != 0) {
            length++;
            temp >>= 8;
        }
        return toHexString(value, length);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _HEX_SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }
}

Settings
{
  "remappings": [
    "@openzeppelin/=lib/openzeppelin-contracts/",
    "ds-test/=lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "contracts/=contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"token_","type":"address"},{"internalType":"address","name":"signer_","type":"address"},{"internalType":"address","name":"owner_","type":"address"},{"internalType":"uint256","name":"amountPerAddress_","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressAlreadyClaimed","type":"error"},{"inputs":[],"name":"ClaimExpired","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TransferFailed","type":"error"},{"inputs":[{"internalType":"bytes32","name":"userId","type":"bytes32"}],"name":"UserIdAlreadyClaimed","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"AmountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"bytes32","name":"userId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Claimed","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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"signer","type":"address"}],"name":"SignerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Swept","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"addressClaimed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"amountPerAddress","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account_","type":"address"},{"internalType":"bytes32","name":"userId_","type":"bytes32"},{"internalType":"string","name":"nonce_","type":"string"},{"internalType":"uint256","name":"expiredAt_","type":"uint256"},{"internalType":"uint8","name":"v_","type":"uint8"},{"internalType":"bytes32","name":"r_","type":"bytes32"},{"internalType":"bytes32","name":"s_","type":"bytes32"}],"name":"claim","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"setAmountPerAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"signer_","type":"address"}],"name":"setSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"signer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"target_","type":"address"}],"name":"sweep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"userIdClaimed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]

60a06040523480156200001157600080fd5b506040516200109438038062001094833981016040819052620000349162000215565b6200003f33620000d3565b6001600160a01b03841615806200005d57506001600160a01b038316155b806200007057506001600160a01b038216155b156200008f5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b03848116608052600180546001600160a01b0319168583161790556002829055821615620000c957620000c98262000123565b5050505062000267565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000546001600160a01b03163314620001835760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b6001600160a01b038116620001ea5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016200017a565b620001f581620000d3565b50565b80516001600160a01b03811681146200021057600080fd5b919050565b600080600080608085870312156200022c57600080fd5b6200023785620001f8565b93506200024760208601620001f8565b92506200025760408601620001f8565b6060959095015193969295505050565b608051610e0362000291600039600081816101d50152818161023f01526106550152610e036000f3fe608060405234801561001057600080fd5b50600436106100b45760003560e01c8063772dc32f11610071578063772dc32f14610163578063782a09b6146101865780638da5cb5b14610199578063f2fde38b146101aa578063f722c203146101bd578063fc0c546a146101d057600080fd5b806301681a62146100b95780630bdde5b8146100ce5780632027e75d146100ea578063238ac9331461011d5780636c19e78314610148578063715018a61461015b575b600080fd5b6100cc6100c7366004610b77565b6101f7565b005b6100d760025481565b6040519081526020015b60405180910390f35b61010d6100f8366004610b99565b60046020526000908152604090205460ff1681565b60405190151581526020016100e1565b600154610130906001600160a01b031681565b6040516001600160a01b0390911681526020016100e1565b6100cc610156366004610b77565b6103a3565b6100cc61043e565b61010d610171366004610b77565b60036020526000908152604090205460ff1681565b61010d610194366004610bd9565b610474565b6000546001600160a01b0316610130565b6100cc6101b8366004610b77565b610701565b6100cc6101cb366004610b99565b61079c565b6101307f000000000000000000000000000000000000000000000000000000000000000081565b6000546001600160a01b0316331461022a5760405162461bcd60e51b815260040161022190610cd2565b60405180910390fd5b6040516370a0823160e01b81523060048201527f0000000000000000000000000000000000000000000000000000000000000000906000906001600160a01b038316906370a0823190602401602060405180830381865afa158015610293573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102b79190610d07565b9050826001600160a01b03167fc36b5179cb9c303b200074996eab2b3473eac370fdd7eba3bec636fe35109696826040516102f491815260200190565b60405180910390a260405163a9059cbb60e01b81526001600160a01b0384811660048301526024820183905283169063a9059cbb906044016020604051808303816000875af115801561034b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061036f9190610d20565b61039e57604051630e21dcbb60e11b81526001600160a01b038416600482015260248101829052604401610221565b505050565b6000546001600160a01b031633146103cd5760405162461bcd60e51b815260040161022190610cd2565b6001600160a01b0381166103f45760405163d92e233d60e01b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b0383169081179091556040517f5719a5656c5cfdaafa148ecf366fd3b0a7fae06449ce2a46225977fb7417e29d90600090a250565b6000546001600160a01b031633146104685760405162461bcd60e51b815260040161022190610cd2565b6104726000610800565b565b600042851015610497576040516341524ecf60e11b815260040160405180910390fd5b6001600160a01b03881660009081526003602052604090205460ff16156104dc5760405163096238d760e31b81526001600160a01b0389166004820152602401610221565b60008781526004602052604090205460ff161561050f57604051630fe0aca960e41b815260048101889052602401610221565b600061058d898989893060405160200161052d959493929190610d42565b60408051601f1981840301815282825280516020918201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000084830152603c8085019190915282518085039091018152605c909301909152815191012090565b905061059b81868686610850565b6105b857604051638baa579f60e01b815260040160405180910390fd5b6001600160a01b03891660008181526003602090815260408083208054600160ff1991821681179092558d85526004845293829020805490941617909255600254915182815291928b9290917f9b01158d4bc10c112ba32b5240cda97e49e2eb86021f03f6a0f460342ac4dfda910160405180910390a360405163a9059cbb60e01b81526001600160a01b038b81166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af115801561069e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106c29190610d20565b6106f157604051630e21dcbb60e11b81526001600160a01b038b16600482015260248101829052604401610221565b5060019998505050505050505050565b6000546001600160a01b0316331461072b5760405162461bcd60e51b815260040161022190610cd2565b6001600160a01b0381166107905760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610221565b61079981610800565b50565b6000546001600160a01b031633146107c65760405162461bcd60e51b815260040161022190610cd2565b60028190556040518181527e0569af47cfda5b90a610f5fc8eb22530de4a7c3794039d529423097c07898c9060200160405180910390a150565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60008061085f86868686610890565b90506001600160a01b0381161580159061088657506001546001600160a01b038281169116145b9695505050505050565b60008060006108a1878787876108b8565b915091506108ae816109a5565b5095945050505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156108ef575060009050600361099c565b8460ff16601b1415801561090757508460ff16601c14155b15610918575060009050600461099c565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561096c573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166109955760006001925092505061099c565b9150600090505b94509492505050565b60008160048111156109b9576109b9610db7565b036109c15750565b60018160048111156109d5576109d5610db7565b03610a225760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610221565b6002816004811115610a3657610a36610db7565b03610a835760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610221565b6003816004811115610a9757610a97610db7565b03610aef5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610221565b6004816004811115610b0357610b03610db7565b036107995760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b6064820152608401610221565b80356001600160a01b0381168114610b7257600080fd5b919050565b600060208284031215610b8957600080fd5b610b9282610b5b565b9392505050565b600060208284031215610bab57600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b803560ff81168114610b7257600080fd5b600080600080600080600060e0888a031215610bf457600080fd5b610bfd88610b5b565b965060208801359550604088013567ffffffffffffffff80821115610c2157600080fd5b818a0191508a601f830112610c3557600080fd5b813581811115610c4757610c47610bb2565b604051601f8201601f19908116603f01168101908382118183101715610c6f57610c6f610bb2565b816040528281528d6020848701011115610c8857600080fd5b82602086016020830137600060208483010152809950505050505060608801359350610cb660808901610bc8565b925060a0880135915060c0880135905092959891949750929550565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b600060208284031215610d1957600080fd5b5051919050565b600060208284031215610d3257600080fd5b81518015158114610b9257600080fd5b60006bffffffffffffffffffffffff19808860601b168352866014840152855160005b81811015610d825760208189018101516034878401015201610d65565b81811115610d94576000603483870101525b5090920160348101949094525060609190911b1660548201526068019392505050565b634e487b7160e01b600052602160045260246000fdfea2646970667358221220bf11efa27999806c29337d7047d791b147f93248c641996322c3aa92c56d16ff64736f6c634300080d0033000000000000000000000000264808855b0a6a5a318d238c6ee9f299179f27fc000000000000000000000000046367167cb304efb8045feb7df0987bf3995894000000000000000000000000e9798e7c81289c1f267786b1bbedde2975804b490000000000000000000000000000000000000000000000056bc75e2d63100000

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

000000000000000000000000264808855b0a6a5a318d238c6ee9f299179f27fc000000000000000000000000046367167cb304efb8045feb7df0987bf3995894000000000000000000000000e9798e7c81289c1f267786b1bbedde2975804b490000000000000000000000000000000000000000000000056bc75e2d63100000

-----Decoded View---------------
Arg [0] : token_ (address): 0x264808855b0a6a5a318d238c6ee9f299179f27fc
Arg [1] : signer_ (address): 0x046367167cb304efb8045feb7df0987bf3995894
Arg [2] : owner_ (address): 0xe9798e7c81289c1f267786b1bbedde2975804b49
Arg [3] : amountPerAddress_ (uint256): 100000000000000000000

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000264808855b0a6a5a318d238c6ee9f299179f27fc
Arg [1] : 000000000000000000000000046367167cb304efb8045feb7df0987bf3995894
Arg [2] : 000000000000000000000000e9798e7c81289c1f267786b1bbedde2975804b49
Arg [3] : 0000000000000000000000000000000000000000000000056bc75e2d63100000


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.