账户
0xbf...d04f
0xBf...D04f

0xBf...D04f

US$0.00
此合同的源代码已经过验证!
合同元数据
编译器
0.8.20+commit.a1b79de6
语言
Solidity
合同源代码
文件 1 的 4:BatchDistributor.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "../interfaces/IDistributor.sol";
import "../Errors.sol";

/**
 * @title BatchDistributor
 * @author @trmaphi
 * @notice This contract is used to claim airdrops for multiple users in one call.
 */
contract BatchDistributor is ReentrancyGuard {
    struct BatchClaimParams {
        address distributorContract;
        bool isInit;
        bytes32 userVestingId;
        bytes proof;
    }

    event BatchClaimed(address indexed caller, address[] distributors, address recipient);

    constructor() {
    }

    /**
     * Claim for multiple airdrops
     * @param params BatchClaimParams[]
     * @param recipient address
     */
    function batchClaim(BatchClaimParams[] calldata params, address recipient) external nonReentrant {
        if (params.length == 0) revert EmptyArray();
        if (recipient != msg.sender) revert InvalidRecipient();
        address[] memory distributors = new address[](params.length);
        for (uint256 i = 0; i < params.length; i++) {
            BatchClaimParams memory param = params[i];
            distributors[i] = param.distributorContract;
            IDistributor distributor = IDistributor(param.distributorContract);
            
            if (param.isInit) {
                if (param.proof.length == 0) revert InvalidProofs();
                distributor.initClaim(
                    msg.sender,
                    param.proof,
                    recipient
                );
            } else {
                distributor.claim(
                    msg.sender,
                    param.userVestingId,
                    recipient
                );
            }
        }

        emit BatchClaimed(msg.sender, distributors, recipient);
    }
}
合同源代码
文件 2 的 4:Errors.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;

error InvalidSignature();
error AlreadyClaimed();
error ZeroAddress();
error DeadlinePassed();
error InvalidProofs();
error RootHashAlreadySet();
error SlotExists();
error InvalidRecipient();
error InvalidCaller();
error VestingConfigNotSet();
error InvalidVestingConfig();
error EmptyArray();
error InvalidUserVestingId();
合同源代码
文件 3 的 4:IDistributor.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;
import "../Errors.sol";

interface IDistributor {
    function initClaim(address caller, bytes calldata proofs, address recipient) external;
    function claim(address caller, bytes32 userVestingId, address recipient) external;
}
合同源代码
文件 4 的 4:ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
 * consider using {ReentrancyGuardTransient} instead.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    uint256 private _status;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    constructor() {
        _status = NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if (_status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        _status = ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == ENTERED;
    }
}
设置
{
  "compilationTarget": {
    "contracts/v2/BatchDistributor.sol": "BatchDistributor"
  },
  "evmVersion": "paris",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "remappings": []
}
ABI
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"EmptyArray","type":"error"},{"inputs":[],"name":"InvalidProofs","type":"error"},{"inputs":[],"name":"InvalidRecipient","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"address[]","name":"distributors","type":"address[]"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"}],"name":"BatchClaimed","type":"event"},{"inputs":[{"components":[{"internalType":"address","name":"distributorContract","type":"address"},{"internalType":"bool","name":"isInit","type":"bool"},{"internalType":"bytes32","name":"userVestingId","type":"bytes32"},{"internalType":"bytes","name":"proof","type":"bytes"}],"internalType":"struct BatchDistributor.BatchClaimParams[]","name":"params","type":"tuple[]"},{"internalType":"address","name":"recipient","type":"address"}],"name":"batchClaim","outputs":[],"stateMutability":"nonpayable","type":"function"}]