Treasury
0xba690293226322f899e5cdd69c3f992134729f91
Verification
Verified
v0.8.24+commit.e11b9ed9
Type
Contract
2,858 bytes
ABI entries
32
7 read · 8 write
License
none
Contract information
- Address
- 0xba690293226322f899e5cdd69c3f992134729f91
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.24+commit.e11b9ed9
- Optimization
- Enabled
- Creator
- 0x0d45254857…2E1FA4aF74
- Creation tx
- 0xb1e9426931…5c68e952fc
Token
Not a token
This contract does not expose ERC-20 metadata.
Read contract (7)
MAX_DELAY() → uint64
isKeeper(address) → bool
nonce() → uint256
owner() → address
pendingOwner() → address
withdrawDelay() → uint64
withdrawals(bytes32) → address, address, uint256, uint64, bool, bool
Events (7)
KeeperSetOwnershipTransferStartedOwnershipTransferredWithdrawDelaySetWithdrawalCanceledWithdrawalExecutedWithdrawalQueued
ABI
[
{
"inputs": [
{
"internalType": "address",
"name": "initialOwner",
"type": "address"
},
{
"internalType": "uint64",
"name": "withdrawDelay_",
"type": "uint64"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "AlreadyFinalized",
"type": "error"
},
{
"inputs": [],
"name": "BadDelay",
"type": "error"
},
{
"inputs": [],
"name": "NotKeeper",
"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": "TooEarly",
"type": "error"
},
{
"inputs": [],
"name": "UnknownWithdrawal",
"type": "error"
},
{
"inputs": [],
"name": "ZeroAddress",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "keeper",
"type": "address"
},
{
"indexed": false,
"internalType": "bool",
"name": "enabled",
"type": "bool"
}
],
"name": "KeeperSet",
"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": "uint64",
"name": "delay",
"type": "uint64"
}
],
"name": "WithdrawDelaySet",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "id",
"type": "bytes32"
}
],
"name": "WithdrawalCanceled",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "id",
"type": "bytes32"
}
],
"name": "WithdrawalExecuted",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "id",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint64",
"name": "eta",
"type": "uint64"
}
],
"name": "WithdrawalQueued",
"type": "event"
},
{
"inputs": [],
"name": "MAX_DELAY",
"outputs": [
{
"internalType": "uint64",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "acceptOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "id",
"type": "bytes32"
}
],
"name": "cancelWithdrawal",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "id",
"type": "bytes32"
}
],
"name": "executeWithdrawal",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "isKeeper",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "nonce",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "pendingOwner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "queueWithdrawal",
"outputs": [
{
"internalType": "bytes32",
"name": "id",
"type": "bytes32"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "renounceOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "keeper",
"type": "address"
},
{
"internalType": "bool",
"name": "enabled",
"type": "bool"
}
],
"name": "setKeeper",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint64",
"name": "delay",
"type": "uint64"
}
],
"name": "setWithdrawDelay",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "withdrawDelay",
"outputs": [
{
"internalType": "uint64",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"name": "withdrawals",
"outputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "uint64",
"name": "eta",
"type": "uint64"
},
{
"internalType": "bool",
"name": "executed",
"type": "bool"
},
{
"internalType": "bool",
"name": "canceled",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
}
]Source code
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Governed} from "./access/Governed.sol";
/// @title Treasury
/// @notice Timelocked custody of the protocol's WETH reserve, bought-back $MEMEDEX, and skimmed memecoins.
/// Every outflow must be queued and then executed only after `withdrawDelay` elapses, so a single
/// compromised owner key cannot instantly drain the treasury. Recommended owner: a multisig.
contract Treasury is Governed {
using SafeERC20 for IERC20;
struct Withdrawal {
address token;
address to;
uint256 amount;
uint64 eta; // earliest execution time
bool executed;
bool canceled;
}
uint64 public constant MAX_DELAY = 30 days;
uint64 public withdrawDelay;
uint256 public nonce;
mapping(bytes32 => Withdrawal) public withdrawals;
event WithdrawDelaySet(uint64 delay);
event WithdrawalQueued(bytes32 indexed id, address indexed token, address indexed to, uint256 amount, uint64 eta);
event WithdrawalExecuted(bytes32 indexed id);
event WithdrawalCanceled(bytes32 indexed id);
error ZeroAddress();
error BadDelay();
error UnknownWithdrawal();
error AlreadyFinalized();
error TooEarly();
constructor(address initialOwner, uint64 withdrawDelay_) Governed(initialOwner) {
if (withdrawDelay_ > MAX_DELAY) revert BadDelay();
withdrawDelay = withdrawDelay_;
}
/// @dev Delay can be changed but is bounded; lowering it still cannot fast-track already-queued items.
function setWithdrawDelay(uint64 delay) external onlyOwner {
if (delay > MAX_DELAY) revert BadDelay();
withdrawDelay = delay;
emit WithdrawDelaySet(delay);
}
function queueWithdrawal(address token, address to, uint256 amount)
external
onlyOwner
returns (bytes32 id)
{
if (token == address(0) || to == address(0)) revert ZeroAddress();
uint64 eta = uint64(block.timestamp) + withdrawDelay;
id = keccak256(abi.encode(token, to, amount, nonce++));
withdrawals[id] =
Withdrawal({token: token, to: to, amount: amount, eta: eta, executed: false, canceled: false});
emit WithdrawalQueued(id, token, to, amount, eta);
}
function executeWithdrawal(bytes32 id) external onlyOwner {
Withdrawal storage w = withdrawals[id];
if (w.eta == 0) revert UnknownWithdrawal();
if (w.executed || w.canceled) revert AlreadyFinalized();
if (block.timestamp < w.eta) revert TooEarly();
w.executed = true;
IERC20(w.token).safeTransfer(w.to, w.amount);
emit WithdrawalExecuted(id);
}
function cancelWithdrawal(bytes32 id) external onlyOwner {
Withdrawal storage w = withdrawals[id];
if (w.eta == 0) revert UnknownWithdrawal();
if (w.executed || w.canceled) revert AlreadyFinalized();
w.canceled = true;
emit WithdrawalCanceled(id);
}
}
Chain explorer1765msChain node88ms