TreasuryDropper
0x7f61daac811b10360861a66d527cbeb2a0db8b21
Verification
Verified
v0.8.26+commit.8a97fa7a
Type
Contract
2,122 bytes
ABI entries
32
7 read · 8 write
License
none
Contract information
- Address
- 0x7f61daac811b10360861a66d527cbeb2a0db8b21
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.26+commit.8a97fa7a
- Optimization
- Enabled
- Creator
- 0x8a81358C88…4d29D9617a
- Creation tx
- 0xb0fe67ccaf…7aa7e3f8a5
Token
Not a token
This contract does not expose ERC-20 metadata.
Read contract (7)
claimed(bytes32) → bool
maxDrop() → uint256
operator() → address
owner() → address
paused() → bool
pendingOwner() → address
token() → address
Events (7)
DroppedMaxDropUpdatedOperatorUpdatedOwnershipTransferStartedOwnershipTransferredPausedUnpaused
ABI
[
{
"inputs": [
{
"internalType": "address",
"name": "token_",
"type": "address"
},
{
"internalType": "address",
"name": "owner_",
"type": "address"
},
{
"internalType": "address",
"name": "operator_",
"type": "address"
},
{
"internalType": "uint256",
"name": "maxDrop_",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "claimId",
"type": "bytes32"
}
],
"name": "AlreadyClaimed",
"type": "error"
},
{
"inputs": [],
"name": "EnforcedPause",
"type": "error"
},
{
"inputs": [],
"name": "ExpectedPause",
"type": "error"
},
{
"inputs": [],
"name": "InvalidAmount",
"type": "error"
},
{
"inputs": [],
"name": "NotOperator",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
}
],
"name": "OwnableInvalidOwner",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "OwnableUnauthorizedAccount",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
}
],
"name": "SafeERC20FailedOperation",
"type": "error"
},
{
"inputs": [],
"name": "ZeroAddress",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "claimId",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "Dropped",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "maxDrop",
"type": "uint256"
}
],
"name": "MaxDropUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "operator",
"type": "address"
}
],
"name": "OperatorUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "previousOwner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "OwnershipTransferStarted",
"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": false,
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "Paused",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "Unpaused",
"type": "event"
},
{
"inputs": [],
"name": "acceptOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "claimId",
"type": "bytes32"
}
],
"name": "claimed",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "claimId",
"type": "bytes32"
},
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "drop",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "maxDrop",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "operator",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "pause",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "paused",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "pendingOwner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "renounceOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "maxDrop_",
"type": "uint256"
}
],
"name": "setMaxDrop",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "operator_",
"type": "address"
}
],
"name": "setOperator",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "token",
"outputs": [
{
"internalType": "contract IERC20",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "unpause",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]Source code
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol";
import {Pausable} from "@openzeppelin/contracts/utils/Pausable.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
/// @notice Holds a token balance and pays it out via `drop`: at most one
/// payout per claim id, at most `maxDrop` per payout, callable only by the
/// operator. The owner can replace the operator, change `maxDrop` and pause.
contract TreasuryDropper is Ownable2Step, Pausable {
using SafeERC20 for IERC20;
error NotOperator();
error ZeroAddress();
error InvalidAmount();
error AlreadyClaimed(bytes32 claimId);
event Dropped(bytes32 indexed claimId, address indexed to, uint256 amount);
event OperatorUpdated(address indexed operator);
event MaxDropUpdated(uint256 maxDrop);
IERC20 public immutable token;
address public operator;
uint256 public maxDrop;
mapping(bytes32 claimId => bool) public claimed;
constructor(address token_, address owner_, address operator_, uint256 maxDrop_) Ownable(owner_) {
if (token_ == address(0) || operator_ == address(0)) revert ZeroAddress();
if (maxDrop_ == 0) revert InvalidAmount();
token = IERC20(token_);
operator = operator_;
maxDrop = maxDrop_;
}
function drop(bytes32 claimId, address to, uint256 amount) external whenNotPaused {
if (msg.sender != operator) revert NotOperator();
if (to == address(0)) revert ZeroAddress();
if (amount == 0 || amount > maxDrop) revert InvalidAmount();
if (claimed[claimId]) revert AlreadyClaimed(claimId);
claimed[claimId] = true;
token.safeTransfer(to, amount);
emit Dropped(claimId, to, amount);
}
function setOperator(address operator_) external onlyOwner {
if (operator_ == address(0)) revert ZeroAddress();
operator = operator_;
emit OperatorUpdated(operator_);
}
function setMaxDrop(uint256 maxDrop_) external onlyOwner {
if (maxDrop_ == 0) revert InvalidAmount();
maxDrop = maxDrop_;
emit MaxDropUpdated(maxDrop_);
}
function pause() external onlyOwner {
_pause();
}
function unpause() external onlyOwner {
_unpause();
}
}
Chain explorer2258msChain node86ms