DIHBurnEvent
0x31ffab7e0bdc5ed96bbc15e76291582ac82aef30
Verification
Verified
v0.8.24+commit.e11b9ed9
Type
Contract
3,950 bytes
ABI entries
53
22 read · 7 write
License
none
Contract information
- Address
- 0x31ffab7e0bdc5ed96bbc15e76291582ac82aef30
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.24+commit.e11b9ed9
- Optimization
- Enabled
- Creator
- 0x16E9f87D89…4E380C8BE5
- Creation tx
- 0x13e17c51e1…462b4ce26e
Token
Not a token
This contract does not expose ERC-20 metadata.
Read contract (22)
DEAD_ADDRESS() → address
DEFAULT_ADMIN_ROLE() → bytes32
MANAGER_ROLE() → bytes32
burnTransactionCount() → uint256
burnedBy(address) → uint256
contractDIHBalance() → uint256
dih() → address
endTime() → uint64
eventActive() → bool
eventEnded() → bool
getRoleAdmin(bytes32) → bytes32
hasParticipated(address) → bool
hasRole(bytes32, address) → bool
minimumBurn() → uint256
participantAt(uint256) → address
participantCount() → uint256
participantsLength() → uint256
paused() → bool
scheduleConfigured() → bool
startTime() → uint64
supportsInterface(bytes4) → bool
totalBurned() → uint256
Events (7)
DIHBurnedPausedRoleAdminChangedRoleGrantedRoleRevokedScheduleConfiguredUnpaused
ABI
[
{
"inputs": [
{
"internalType": "address",
"name": "dihToken",
"type": "address"
},
{
"internalType": "address",
"name": "admin",
"type": "address"
},
{
"internalType": "uint256",
"name": "minimumBurnAmount",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "AccessControlBadConfirmation",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "bytes32",
"name": "neededRole",
"type": "bytes32"
}
],
"name": "AccessControlUnauthorizedAccount",
"type": "error"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "received",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "minimum",
"type": "uint256"
}
],
"name": "BurnBelowMinimum",
"type": "error"
},
{
"inputs": [],
"name": "EnforcedPause",
"type": "error"
},
{
"inputs": [],
"name": "EventEnded",
"type": "error"
},
{
"inputs": [],
"name": "EventNotStarted",
"type": "error"
},
{
"inputs": [],
"name": "ExpectedPause",
"type": "error"
},
{
"inputs": [],
"name": "InvalidMinimumBurn",
"type": "error"
},
{
"inputs": [],
"name": "InvalidSchedule",
"type": "error"
},
{
"inputs": [],
"name": "ReentrancyGuardReentrantCall",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
}
],
"name": "SafeERC20FailedOperation",
"type": "error"
},
{
"inputs": [],
"name": "ScheduleAlreadyConfigured",
"type": "error"
},
{
"inputs": [],
"name": "ScheduleNotConfigured",
"type": "error"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "balanceBefore",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "balanceAfter",
"type": "uint256"
}
],
"name": "UnexpectedTokenAccounting",
"type": "error"
},
{
"inputs": [],
"name": "ZeroAddress",
"type": "error"
},
{
"inputs": [],
"name": "ZeroAmount",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "burner",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "requestedAmount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "burnedAmount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "walletTotalBurned",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "eventTotalBurned",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "participantCount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "burnTransactionCount",
"type": "uint256"
}
],
"name": "DIHBurned",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "Paused",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "bytes32",
"name": "previousAdminRole",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "bytes32",
"name": "newAdminRole",
"type": "bytes32"
}
],
"name": "RoleAdminChanged",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "address",
"name": "account",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "sender",
"type": "address"
}
],
"name": "RoleGranted",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "address",
"name": "account",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "sender",
"type": "address"
}
],
"name": "RoleRevoked",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "uint64",
"name": "startTime",
"type": "uint64"
},
{
"indexed": true,
"internalType": "uint64",
"name": "endTime",
"type": "uint64"
}
],
"name": "ScheduleConfigured",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "Unpaused",
"type": "event"
},
{
"inputs": [],
"name": "DEAD_ADDRESS",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "DEFAULT_ADMIN_ROLE",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MANAGER_ROLE",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "requestedAmount",
"type": "uint256"
}
],
"name": "burn",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "burnTransactionCount",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "burnedBy",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint64",
"name": "newStartTime",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "newEndTime",
"type": "uint64"
}
],
"name": "configureSchedule",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "contractDIHBalance",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "dih",
"outputs": [
{
"internalType": "contract IERC20",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "endTime",
"outputs": [
{
"internalType": "uint64",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "eventActive",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "eventEnded",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
}
],
"name": "getRoleAdmin",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "grantRole",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "hasParticipated",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "hasRole",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "minimumBurn",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "index",
"type": "uint256"
}
],
"name": "participantAt",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "participantCount",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "participantsLength",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"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": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "callerConfirmation",
"type": "address"
}
],
"name": "renounceRole",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "revokeRole",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "scheduleConfigured",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "startTime",
"outputs": [
{
"internalType": "uint64",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes4",
"name": "interfaceId",
"type": "bytes4"
}
],
"name": "supportsInterface",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "totalBurned",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "unpause",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]Source code
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import {AccessControl} from
"@openzeppelin/contracts/access/AccessControl.sol";
import {Pausable} from
"@openzeppelin/contracts/utils/Pausable.sol";
import {ReentrancyGuard} from
"@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import {IERC20} from
"@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from
"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
/**
* @title DIHBurnEvent
* @notice Limited-time DOGINHOOD community burn event.
*
* Users approve this contract, then call burn(amount).
* Tokens move directly from the user to the dead address.
*
* The contract is used only for:
* - enforcing the minimum burn;
* - enforcing the event window;
* - tracking participants;
* - tracking total amounts burned;
* - emitting public on-chain statistics.
*
* This contract does not select a winner and does not distribute rewards.
*/
contract DIHBurnEvent is
AccessControl,
Pausable,
ReentrancyGuard
{
using SafeERC20 for IERC20;
bytes32 public constant MANAGER_ROLE =
keccak256("MANAGER_ROLE");
address public constant DEAD_ADDRESS =
0x000000000000000000000000000000000000dEaD;
IERC20 public immutable dih;
uint256 public immutable minimumBurn;
uint64 public startTime;
uint64 public endTime;
bool public scheduleConfigured;
uint256 public totalBurned;
uint256 public participantCount;
uint256 public burnTransactionCount;
mapping(address => uint256) public burnedBy;
mapping(address => bool) public hasParticipated;
address[] private participants;
error ZeroAddress();
error ZeroAmount();
error InvalidMinimumBurn();
error InvalidSchedule();
error ScheduleAlreadyConfigured();
error ScheduleNotConfigured();
error EventNotStarted();
error EventEnded();
error BurnBelowMinimum(
uint256 received,
uint256 minimum
);
error UnexpectedTokenAccounting(
uint256 balanceBefore,
uint256 balanceAfter
);
event ScheduleConfigured(
uint64 indexed startTime,
uint64 indexed endTime
);
event DIHBurned(
address indexed burner,
uint256 requestedAmount,
uint256 burnedAmount,
uint256 walletTotalBurned,
uint256 eventTotalBurned,
uint256 participantCount,
uint256 burnTransactionCount
);
constructor(
address dihToken,
address admin,
uint256 minimumBurnAmount
) {
if (
dihToken == address(0) ||
admin == address(0)
) {
revert ZeroAddress();
}
if (minimumBurnAmount == 0) {
revert InvalidMinimumBurn();
}
dih = IERC20(dihToken);
minimumBurn = minimumBurnAmount;
_grantRole(DEFAULT_ADMIN_ROLE, admin);
_grantRole(MANAGER_ROLE, admin);
_pause();
}
/**
* @notice Configures the event window exactly once.
* @dev Must be called while the contract is paused.
*/
function configureSchedule(
uint64 newStartTime,
uint64 newEndTime
)
external
onlyRole(MANAGER_ROLE)
whenPaused
{
if (scheduleConfigured) {
revert ScheduleAlreadyConfigured();
}
if (
newStartTime <= block.timestamp ||
newEndTime <= newStartTime
) {
revert InvalidSchedule();
}
startTime = newStartTime;
endTime = newEndTime;
scheduleConfigured = true;
emit ScheduleConfigured(
newStartTime,
newEndTime
);
}
/**
* @notice Permanently burns DIH by sending it directly
* from the caller to the dead address.
*/
function burn(
uint256 requestedAmount
)
external
nonReentrant
whenNotPaused
{
if (!scheduleConfigured) {
revert ScheduleNotConfigured();
}
if (block.timestamp < startTime) {
revert EventNotStarted();
}
if (block.timestamp >= endTime) {
revert EventEnded();
}
if (requestedAmount == 0) {
revert ZeroAmount();
}
uint256 deadBalanceBefore =
dih.balanceOf(DEAD_ADDRESS);
dih.safeTransferFrom(
msg.sender,
DEAD_ADDRESS,
requestedAmount
);
uint256 deadBalanceAfter =
dih.balanceOf(DEAD_ADDRESS);
if (deadBalanceAfter < deadBalanceBefore) {
revert UnexpectedTokenAccounting(
deadBalanceBefore,
deadBalanceAfter
);
}
uint256 burnedAmount =
deadBalanceAfter - deadBalanceBefore;
if (burnedAmount < minimumBurn) {
revert BurnBelowMinimum(
burnedAmount,
minimumBurn
);
}
if (!hasParticipated[msg.sender]) {
hasParticipated[msg.sender] = true;
participants.push(msg.sender);
unchecked {
participantCount += 1;
}
}
burnedBy[msg.sender] += burnedAmount;
totalBurned += burnedAmount;
unchecked {
burnTransactionCount += 1;
}
emit DIHBurned(
msg.sender,
requestedAmount,
burnedAmount,
burnedBy[msg.sender],
totalBurned,
participantCount,
burnTransactionCount
);
}
function pause()
external
onlyRole(MANAGER_ROLE)
{
_pause();
}
function unpause()
external
onlyRole(MANAGER_ROLE)
{
if (!scheduleConfigured) {
revert ScheduleNotConfigured();
}
_unpause();
}
function participantAt(
uint256 index
)
external
view
returns (address)
{
return participants[index];
}
function participantsLength()
external
view
returns (uint256)
{
return participants.length;
}
function eventActive()
public
view
returns (bool)
{
return (
scheduleConfigured &&
!paused() &&
block.timestamp >= startTime &&
block.timestamp < endTime
);
}
function eventEnded()
external
view
returns (bool)
{
return (
scheduleConfigured &&
block.timestamp >= endTime
);
}
function contractDIHBalance()
external
view
returns (uint256)
{
return dih.balanceOf(address(this));
}
}
Chain explorer2386msChain node75ms