// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
contract BangDistributor is ReentrancyGuard {
using SafeERC20 for IERC20;
uint256 private constant MAGNITUDE = 2 ** 128;
uint256 public constant MAX_ASSETS = 8;
uint256 public constant MAX_CLAIM_WAIT = 7 days;
address public immutable token;
address public treasury;
struct Asset {
IERC20 rewardToken;
uint256 magnifiedRewardPerShare;
uint256 totalDistributed;
uint256 totalClaimed;
}
Asset[] private _assets;
mapping(address => uint256) private _assetIdPlusOne;
mapping(uint256 => mapping(address => int256)) private _corrections;
mapping(uint256 => mapping(address => uint256)) public claimedRewards;
uint256 public minimumTokenBalanceForRewards;
uint256 public claimWait;
uint256 public totalShares;
uint256 public lastProcessedIndex;
mapping(address => uint256) public shares;
mapping(address => uint256) public lastClaimTimes;
mapping(address => bool) public excludedFromRewards;
address[] private holders;
mapping(address => uint256) private holderIndexPlusOne;
event TreasurySet(address indexed treasury);
event AssetRegistered(uint256 indexed assetId, address indexed rewardToken);
event RewardDistributed(uint256 indexed assetId, uint256 amount);
event Claim(address indexed account, uint256 indexed assetId, uint256 amount, bool automatic);
event ClaimFailed(address indexed account, uint256 indexed assetId, uint256 amount);
event ShareUpdated(address indexed account, uint256 previousShare, uint256 newShare);
event ExcludedFromRewards(address indexed account, bool excluded);
event CriteriaUpdated(uint256 minimumTokenBalanceForRewards, uint256 claimWait);
event Processed(uint256 iterations, uint256 claims, uint256 lastProcessedIndex, uint256 gas, address indexed processor);
error OnlyToken();
error OnlyTreasury();
error OnlySelf();
error ZeroAddress();
error TreasuryAlreadySet();
error TooManyAssets();
error UnknownAsset();
error ZeroAmount();
error NoShares();
error ClaimWaitTooHigh();
modifier onlyToken() {
if (msg.sender != token) revert OnlyToken();
_;
}
modifier onlyTreasury() {
if (msg.sender != treasury) revert OnlyTreasury();
_;
}
constructor(uint256 minimumTokenBalanceForRewards_, uint256 claimWait_) {
if (claimWait_ > MAX_CLAIM_WAIT) revert ClaimWaitTooHigh();
token = msg.sender;
minimumTokenBalanceForRewards = minimumTokenBalanceForRewards_;
claimWait = claimWait_;
}
function setTreasury(address treasury_) external onlyToken {
if (treasury_ == address(0)) revert ZeroAddress();
if (treasury != address(0)) revert TreasuryAlreadySet();
treasury = treasury_;
emit TreasurySet(treasury_);
}
function registerAsset(address rewardToken_) external onlyTreasury returns (uint256 assetId) {
if (rewardToken_ == address(0)) revert ZeroAddress();
uint256 idPlusOne = _assetIdPlusOne[rewardToken_];
if (idPlusOne != 0) return idPlusOne - 1;
if (_assets.length >= MAX_ASSETS) revert TooManyAssets();
_assets.push(
Asset({rewardToken: IERC20(rewardToken_), magnifiedRewardPerShare: 0, totalDistributed: 0, totalClaimed: 0})
);
assetId = _assets.length - 1;
_assetIdPlusOne[rewardToken_] = assetId + 1;
emit AssetRegistered(assetId, rewardToken_);
}
function assetCount() external view returns (uint256) {
return _assets.length;
}
function assetAt(uint256 assetId)
external
view
returns (address rewardToken, uint256 totalDistributed, uint256 totalClaimed)
{
Asset storage a = _assets[assetId];
return (address(a.rewardToken), a.totalDistributed, a.totalClaimed);
}
function totalsAll()
external
view
returns (address[] memory tokens, uint256[] memory distributed, uint256[] memory claimed)
{
uint256 n = _assets.length;
tokens = new address[](n);
distributed = new uint256[](n);
claimed = new uint256[](n);
for (uint256 i = 0; i < n; i++) {
tokens[i] = address(_assets[i].rewardToken);
distributed[i] = _assets[i].totalDistributed;
claimed[i] = _assets[i].totalClaimed;
}
}
function accountInfo(address account)
external
view
returns (uint256 share, uint256[] memory withdrawable, uint256[] memory claimed)
{
uint256 n = _assets.length;
share = shares[account];
withdrawable = new uint256[](n);
claimed = new uint256[](n);
for (uint256 i = 0; i < n; i++) {
withdrawable[i] = withdrawableRewardOf(i, account);
claimed[i] = claimedRewards[i][account];
}
}
function holderCount() external view returns (uint256) {
return holders.length;
}
function holderAt(uint256 index) external view returns (address) {
return holders[index];
}
function holdersSlice(uint256 start, uint256 count)
external
view
returns (address[] memory accounts, uint256[] memory shareAmounts)
{
uint256 n = holders.length;
if (start >= n) return (new address[](0), new uint256[](0));
uint256 end = start + count;
if (end > n) end = n;
accounts = new address[](end - start);
shareAmounts = new uint256[](end - start);
for (uint256 i = start; i < end; i++) {
accounts[i - start] = holders[i];
shareAmounts[i - start] = shares[holders[i]];
}
}
function withdrawableRewardOf(uint256 assetId, address account) public view returns (uint256) {
uint256 accumulative = accumulativeRewardOf(assetId, account);
uint256 claimed = claimedRewards[assetId][account];
if (accumulative <= claimed) return 0;
return accumulative - claimed;
}
function accumulativeRewardOf(uint256 assetId, address account) public view returns (uint256) {
int256 corrected =
int256(_assets[assetId].magnifiedRewardPerShare * shares[account]) + _corrections[assetId][account];
if (corrected <= 0) return 0;
return uint256(corrected) / MAGNITUDE;
}
function setCriteria(uint256 minimumTokenBalanceForRewards_, uint256 claimWait_) external onlyToken {
if (claimWait_ > MAX_CLAIM_WAIT) revert ClaimWaitTooHigh();
minimumTokenBalanceForRewards = minimumTokenBalanceForRewards_;
claimWait = claimWait_;
emit CriteriaUpdated(minimumTokenBalanceForRewards_, claimWait_);
}
function setExcludedFromRewards(address account, bool excluded) external onlyToken {
excludedFromRewards[account] = excluded;
if (excluded) {
_setShare(account, 0);
}
emit ExcludedFromRewards(account, excluded);
}
function setShare(address account, uint256 newShare) external onlyToken {
if (excludedFromRewards[account] || newShare < minimumTokenBalanceForRewards) {
newShare = 0;
}
_setShare(account, newShare);
}
function distribute(uint256 assetId, uint256 amount) external onlyTreasury {
if (assetId >= _assets.length) revert UnknownAsset();
if (amount == 0) revert ZeroAmount();
if (totalShares == 0) revert NoShares();
Asset storage a = _assets[assetId];
a.magnifiedRewardPerShare += (amount * MAGNITUDE) / totalShares;
a.totalDistributed += amount;
emit RewardDistributed(assetId, amount);
}
function claim(address account) external onlyToken nonReentrant returns (uint256 paidAssets) {
return _processAccount(account, false);
}
function process(uint256 gasLimit)
external
onlyToken
nonReentrant
returns (uint256 iterations, uint256 claims, uint256 newLastProcessedIndex)
{
uint256 numberOfHolders = holders.length;
if (numberOfHolders == 0) {
return (0, 0, lastProcessedIndex);
}
uint256 gasUsed = 0;
uint256 gasLeft = gasleft();
uint256 localIndex = lastProcessedIndex;
while (gasUsed < gasLimit && iterations < numberOfHolders) {
localIndex++;
if (localIndex >= numberOfHolders) {
localIndex = 0;
}
address account = holders[localIndex];
if (_canAutoClaim(account)) {
if (_processAccount(account, true) > 0) {
claims++;
}
}
iterations++;
uint256 newGasLeft = gasleft();
if (gasLeft > newGasLeft) {
gasUsed += gasLeft - newGasLeft;
}
gasLeft = newGasLeft;
}
lastProcessedIndex = localIndex;
emit Processed(iterations, claims, lastProcessedIndex, gasLimit, tx.origin);
return (iterations, claims, lastProcessedIndex);
}
function transferReward(uint256 assetId, address account, uint256 amount) external {
if (msg.sender != address(this)) revert OnlySelf();
_assets[assetId].rewardToken.safeTransfer(account, amount);
}
function _processAccount(address account, bool automatic) internal returns (uint256 paidAssets) {
uint256 n = _assets.length;
bool paidAny = false;
for (uint256 assetId = 0; assetId < n; assetId++) {
uint256 amount = withdrawableRewardOf(assetId, account);
if (amount == 0) continue;
Asset storage a = _assets[assetId];
claimedRewards[assetId][account] += amount;
a.totalClaimed += amount;
if (automatic) {
try this.transferReward(assetId, account, amount) {
emit Claim(account, assetId, amount, true);
paidAssets++;
paidAny = true;
} catch {
claimedRewards[assetId][account] -= amount;
a.totalClaimed -= amount;
emit ClaimFailed(account, assetId, amount);
}
} else {
// C-1: manual claim is now isolated per-asset too — a frozen/reverting reward token skips
// that asset instead of reverting the holder's entire claim of all 8 assets.
try this.transferReward(assetId, account, amount) {
emit Claim(account, assetId, amount, false);
paidAssets++;
paidAny = true;
} catch {
claimedRewards[assetId][account] -= amount;
a.totalClaimed -= amount;
emit ClaimFailed(account, assetId, amount);
}
}
}
if (paidAny) {
lastClaimTimes[account] = block.timestamp;
}
}
function _canAutoClaim(address account) internal view returns (bool) {
if (claimWait == 0) return true;
uint256 lastClaimTime = lastClaimTimes[account];
if (lastClaimTime == 0) return true;
return block.timestamp >= lastClaimTime + claimWait;
}
function _setShare(address account, uint256 newShare) internal {
uint256 currentShare = shares[account];
if (currentShare == newShare) return;
uint256 n = _assets.length;
if (newShare > currentShare) {
uint256 mintAmount = newShare - currentShare;
totalShares += mintAmount;
for (uint256 i = 0; i < n; i++) {
uint256 mps = _assets[i].magnifiedRewardPerShare;
if (mps != 0) _corrections[i][account] -= int256(mps * mintAmount);
}
} else {
uint256 burnAmount = currentShare - newShare;
totalShares -= burnAmount;
for (uint256 i = 0; i < n; i++) {
uint256 mps = _assets[i].magnifiedRewardPerShare;
if (mps != 0) _corrections[i][account] += int256(mps * burnAmount);
}
}
shares[account] = newShare;
if (newShare == 0) {
_removeHolder(account);
} else {
_addHolder(account);
}
emit ShareUpdated(account, currentShare, newShare);
}
function _addHolder(address account) internal {
if (holderIndexPlusOne[account] != 0) return;
holders.push(account);
holderIndexPlusOne[account] = holders.length;
}
function _removeHolder(address account) internal {
uint256 indexPlusOne = holderIndexPlusOne[account];
if (indexPlusOne == 0) return;
uint256 index = indexPlusOne - 1;
uint256 lastIndex = holders.length - 1;
if (index != lastIndex) {
address lastHolder = holders[lastIndex];
holders[index] = lastHolder;
holderIndexPlusOne[lastHolder] = index + 1;
}
holders.pop();
delete holderIndexPlusOne[account];
if (holders.length == 0) {
lastProcessedIndex = 0;
} else if (lastProcessedIndex >= holders.length) {
lastProcessedIndex = holders.length - 1;
}
}
}[
{
"type": "constructor",
"inputs": [
{
"name": "minimumTokenBalanceForRewards_",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "claimWait_",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "nonpayable"
},
{
"name": "AddressEmptyCode",
"type": "error",
"inputs": [
{
"name": "target",
"type": "address",
"internalType": "address"
}
]
},
{
"name": "AddressInsufficientBalance",
"type": "error",
"inputs": [
{
"name": "account",
"type": "address",
"internalType": "address"
}
]
},
{
"name": "ClaimWaitTooHigh",
"type": "error",
"inputs": []
},
{
"name": "FailedInnerCall",
"type": "error",
"inputs": []
},
{
"name": "NoShares",
"type": "error",
"inputs": []
},
{
"name": "OnlySelf",
"type": "error",
"inputs": []
},
{
"name": "OnlyToken",
"type": "error",
"inputs": []
},
{
"name": "OnlyTreasury",
"type": "error",
"inputs": []
},
{
"name": "ReentrancyGuardReentrantCall",
"type": "error",
"inputs": []
},
{
"name": "SafeERC20FailedOperation",
"type": "error",
"inputs": [
{
"name": "token",
"type": "address",
"internalType": "address"
}
]
},
{
"name": "TooManyAssets",
"type": "error",
"inputs": []
},
{
"name": "TreasuryAlreadySet",
"type": "error",
"inputs": []
},
{
"name": "UnknownAsset",
"type": "error",
"inputs": []
},
{
"name": "ZeroAddress",
"type": "error",
"inputs": []
},
{
"name": "ZeroAmount",
"type": "error",
"inputs": []
},
{
"name": "AssetRegistered",
"type": "event",
"inputs": [
{
"name": "assetId",
"type": "uint256",
"indexed": true,
"internalType": "uint256"
},
{
"name": "rewardToken",
"type": "address",
"indexed": true,
"internalType": "address"
}
],
"anonymous": false
},
{
"name": "Claim",
"type": "event",
"inputs": [
{
"name": "account",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "assetId",
"type": "uint256",
"indexed": true,
"internalType": "uint256"
},
{
"name": "amount",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "automatic",
"type": "bool",
"indexed": false,
"internalType": "bool"
}
],
"anonymous": false
},
{
"name": "ClaimFailed",
"type": "event",
"inputs": [
{
"name": "account",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "assetId",
"type": "uint256",
"indexed": true,
"internalType": "uint256"
},
{
"name": "amount",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"name": "CriteriaUpdated",
"type": "event",
"inputs": [
{
"name": "minimumTokenBalanceForRewards",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "claimWait",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"name": "ExcludedFromRewards",
"type": "event",
"inputs": [
{
"name": "account",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "excluded",
"type": "bool",
"indexed": false,
"internalType": "bool"
}
],
"anonymous": false
},
{
"name": "Processed",
"type": "event",
"inputs": [
{
"name": "iterations",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "claims",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "lastProcessedIndex",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "gas",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "processor",
"type": "address",
"indexed": true,
"internalType": "address"
}
],
"anonymous": false
},
{
"name": "RewardDistributed",
"type": "event",
"inputs": [
{
"name": "assetId",
"type": "uint256",
"indexed": true,
"internalType": "uint256"
},
{
"name": "amount",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"name": "ShareUpdated",
"type": "event",
"inputs": [
{
"name": "account",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "previousShare",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "newShare",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"name": "TreasurySet",
"type": "event",
"inputs": [
{
"name": "treasury",
"type": "address",
"indexed": true,
"internalType": "address"
}
],
"anonymous": false
},
{
"name": "MAX_ASSETS",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "MAX_CLAIM_WAIT",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "accountInfo",
"type": "function",
"inputs": [
{
"name": "account",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "share",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "withdrawable",
"type": "uint256[]",
"internalType": "uint256[]"
},
{
"name": "claimed",
"type": "uint256[]",
"internalType": "uint256[]"
}
],
"stateMutability": "view"
},
{
"name": "accumulativeRewardOf",
"type": "function",
"inputs": [
{
"name": "assetId",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "account",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "assetAt",
"type": "function",
"inputs": [
{
"name": "assetId",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "rewardToken",
"type": "address",
"internalType": "address"
},
{
"name": "totalDistributed",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "totalClaimed",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "assetCount",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "claim",
"type": "function",
"inputs": [
{
"name": "account",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "paidAssets",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "nonpayable"
},
{
"name": "claimWait",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "claimedRewards",
"type": "function",
"inputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "distribute",
"type": "function",
"inputs": [
{
"name": "assetId",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "amount",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "excludedFromRewards",
"type": "function",
"inputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "",
"type": "bool",
"internalType": "bool"
}
],
"stateMutability": "view"
},
{
"name": "holderAt",
"type": "function",
"inputs": [
{
"name": "index",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"name": "holderCount",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "holdersSlice",
"type": "function",
"inputs": [
{
"name": "start",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "count",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "accounts",
"type": "address[]",
"internalType": "address[]"
},
{
"name": "shareAmounts",
"type": "uint256[]",
"internalType": "uint256[]"
}
],
"stateMutability": "view"
},
{
"name": "lastClaimTimes",
"type": "function",
"inputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "lastProcessedIndex",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "minimumTokenBalanceForRewards",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "process",
"type": "function",
"inputs": [
{
"name": "gasLimit",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "iterations",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "claims",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "newLastProcessedIndex",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "nonpayable"
},
{
"name": "registerAsset",
"type": "function",
"inputs": [
{
"name": "rewardToken_",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "assetId",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "nonpayable"
},
{
"name": "setCriteria",
"type": "function",
"inputs": [
{
"name": "minimumTokenBalanceForRewards_",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "claimWait_",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "setExcludedFromRewards",
"type": "function",
"inputs": [
{
"name": "account",
"type": "address",
"internalType": "address"
},
{
"name": "excluded",
"type": "bool",
"internalType": "bool"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "setShare",
"type": "function",
"inputs": [
{
"name": "account",
"type": "address",
"internalType": "address"
},
{
"name": "newShare",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "setTreasury",
"type": "function",
"inputs": [
{
"name": "treasury_",
"type": "address",
"internalType": "address"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "shares",
"type": "function",
"inputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "token",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"name": "totalShares",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "totalsAll",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "tokens",
"type": "address[]",
"internalType": "address[]"
},
{
"name": "distributed",
"type": "uint256[]",
"internalType": "uint256[]"
},
{
"name": "claimed",
"type": "uint256[]",
"internalType": "uint256[]"
}
],
"stateMutability": "view"
},
{
"name": "transferReward",
"type": "function",
"inputs": [
{
"name": "assetId",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "account",
"type": "address",
"internalType": "address"
},
{
"name": "amount",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "treasury",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"name": "withdrawableRewardOf",
"type": "function",
"inputs": [
{
"name": "assetId",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "account",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
}
]0x60806040526004361015610011575f80fd5b5f803560e01c806314b6ca9614610eb257806315274d6014610d85578063197bc33614610d4e5780631aab9a9f14610d315780631e83409a14610a1357806321a436e4146109f5578063226cfa3d146109bc5780633009a6091461099e5780633a98ef391461098057806361d027b3146109575780636f2789ec146109395780637625391a1461083f57806376b1d08f146108235780637b551f3d146107fc578063995652a5146107d557806399aab83a146107b7578063a7310b58146106f7578063aa9239f5146106af578063b00dc77b146105df578063b33068c41461059a578063c6f5def7146104c8578063ce7c2ac21461048f578063d312998f1461043e578063d78c629e146103f7578063eafe7a74146103d9578063f0f442601461030c578063f259f3df1461026a578063f82f235f1461022b578063fc0c546a146101e65763ffb2c47914610164575f80fd5b346101e35760203660031901126101e3577f000000000000000000000000abcdef96793d3f2c06c7e3b5bf73c7d4bd665f956001600160a01b031633036101d4576060906101b0611984565b60016101bd60043561142f565b929091935560405192835260208301526040820152f35b633d0f0d9f60e21b8152600490fd5b80fd5b50346101e357806003193601126101e3576040517f000000000000000000000000abcdef96793d3f2c06c7e3b5bf73c7d4bd665f956001600160a01b03168152602090f35b50346101e35760203660031901126101e35760209060ff906040906001600160a01b03610256610f46565b168152600c84522054166040519015158152f35b50346101e35761027936610f72565b7f000000000000000000000000abcdef96793d3f2c06c7e3b5bf73c7d4bd665f956001600160a01b031633036102fd5762093a8081116102ee57816040917f2f4d1814657d140c6d8df30ea0eb3e78cfc8a32ba4c202deb5920147d51be621936006558060075582519182526020820152a180f35b63b2034bbb60e01b8352600483fd5b633d0f0d9f60e21b8352600483fd5b50346101e35760203660031901126101e357610326610f46565b7f000000000000000000000000abcdef96793d3f2c06c7e3b5bf73c7d4bd665f956001600160a01b031633036103ca576001600160a01b031680156103bb576001546001600160a01b0381166103ac576001600160a01b03191681176001557f3c864541ef71378c6229510ed90f376565ee42d9c5e0904a984a9e863e6db44f8280a280f35b636f98f01d60e11b8352600483fd5b63d92e233d60e01b8252600482fd5b633d0f0d9f60e21b8252600482fd5b50346101e357806003193601126101e3576020600254604051908152f35b50346101e35761042c61043a61041561040f36610f72565b90611328565b604092919251938493604085526040850190610fbb565b908382036020850152610f88565b0390f35b50346101e35760203660031901126101e357610458610f46565b6001549091906001600160a01b03163303610480576020610478836111e6565b604051908152f35b632298d39d60e11b8152600490fd5b50346101e35760203660031901126101e3576020906040906001600160a01b036104b7610f46565b168152600a83522054604051908152f35b50346101e35760403660031901126101e3576104e2610f46565b6024359081151590818303610596577f000000000000000000000000abcdef96793d3f2c06c7e3b5bf73c7d4bd665f956001600160a01b03163303610587577f6fb704e328736eb59ac6758cc1df5a98a609cfd47a1877201101c614dffc92e99160209160018060a01b03811694858752600c84526040872060ff1981541660ff8516179055610578575b50604051908152a280f35b610581906116ea565b5f61056d565b633d0f0d9f60e21b8452600484fd5b8380fd5b50346101e35760403660031901126101e35760406105b6610f5c565b9160043581526005602052209060018060a01b03165f52602052602060405f2054604051908152f35b50346101e357806003193601126101e357600254906105fd826111a0565b90610607836111a0565b92610611816111a0565b915b8181106106565761063a8461043a8561064889604051958695606087526060870190610fbb565b908582036020870152610f88565b908382036040850152610f88565b80610662600192610ff7565b50828060a01b0390541661067682876111d2565b52600261068282610ff7565b50015461068f82886111d2565b52600361069b82610ff7565b5001546106a882866111d2565b5201610613565b50346101e35760203660031901126101e35760606106ce600435610ff7565b5060018060a01b0381541690600360028201549101549060405192835260208301526040820152f35b50346101e35760203660031901126101e357610711610f46565b6002546001600160a01b0382168352600a6020526040832054919290610736816111a0565b93610740826111a0565b926001600160a01b03821691815b84811061077757878761043a886106486040519485948552606060208601526060850190610f88565b806107848360019361109c565b61078e828b6111d2565b52808452600560205260408420855f5260205260405f20546107b082896111d2565b520161074e565b50346101e357806003193601126101e357602060405162093a808152f35b50346101e35760403660031901126101e35760206104786107f4610f5c565b6004356110fb565b50346101e35760403660031901126101e357602061047861081b610f5c565b60043561109c565b50346101e357806003193601126101e357602060405160088152f35b50346101e35761084e36610f72565b6001546001600160a01b0316330361092a5760025482101561091b57801561090c5760085480156108fd5761088283610ff7565b5090608083901b838104600160801b036108e9576020927feaf3d57629d9b1ce95715ccd98d6f5bf48023be1d5a06e09f64ab7f6d8be01d59492600292046108cf60018301918254611082565b9055016108dd828254611082565b9055604051908152a280f35b634e487b7160e01b86526011600452602486fd5b63b317087b60e01b8452600484fd5b631f2a200560e01b8352600483fd5b63c97d95cf60e01b8352600483fd5b632298d39d60e11b8352600483fd5b50346101e357806003193601126101e3576020600754604051908152f35b50346101e357806003193601126101e3576001546040516001600160a01b039091168152602090f35b50346101e357806003193601126101e3576020600854604051908152f35b50346101e357806003193601126101e3576020600954604051908152f35b50346101e35760203660031901126101e3576020906040906001600160a01b036109e4610f46565b168152600b83522054604051908152f35b50346101e357806003193601126101e3576020600654604051908152f35b5034610d15576020366003190112610d1557610a2d610f46565b7f000000000000000000000000abcdef96793d3f2c06c7e3b5bf73c7d4bd665f956001600160a01b03163303610d2257610a65611984565b6002545f916001600160a01b038116918391825b828110610aa9576020866001898888610a97575b5055604051908152f35b8152600b845242604082205584610a8d565b610ab3828261109c565b8015610d19576003610ac483610ff7565b50838a52600560205260408a20885f5260205260405f20610ae6848254611082565b905501610af4828254611082565b81558815610c1457303b15610c105760405162a93a6b60e51b8152600481018490526001600160a01b038516602482015260448101839052899081808260648183305af19182610bf7575b5050610bab577f9d9e98f5e08c69876edaf0f6cb5a710145dffdf28a008e0e756bee3319d6fb4e6020859485946040856001998e97526005855220855f52835260405f20610b8e83825461108f565b9055610b9b82825461108f565b9055604051908152a35b01610a79565b505081945090857fad82e4ded87b4f1d117a62956445ec6ff411c4f2eb80134db1573f8cb74b86e76040610bed959994815190815260016020820152a3611421565b9360018093610ba5565b81610c0191611166565b610c0c57815f610b3f565b5080fd5b8880fd5b303b15610d155760405162a93a6b60e51b8152600481018490526001600160a01b0385166024820152604481018390525f8160648183305af19081610d00575b508990610cbf577f9d9e98f5e08c69876edaf0f6cb5a710145dffdf28a008e0e756bee3319d6fb4e6020859485946040856001998e97526005855220855f52835260405f20610ca483825461108f565b9055610cb182825461108f565b9055604051908152a3610ba5565b505081945090857fad82e4ded87b4f1d117a62956445ec6ff411c4f2eb80134db1573f8cb74b86e76040610bed95999481519081528b6020820152a3611421565b610d0d919a505f90611166565b5f985f610c54565b5f80fd5b50600190610ba5565b633d0f0d9f60e21b5f5260045ffd5b34610d15575f366003190112610d15576020600d54604051908152f35b34610d15576020366003190112610d15576020610d6c600435611043565b905460405160039290921b1c6001600160a01b03168152f35b34610d15576060366003190112610d1557610d9e610f5c565b303303610ea3575f80610db2600435610ff7565b505460405163a9059cbb60e01b602082019081526001600160a01b039586166024830152604480358184015282529190941693610df0606482611166565b519082855af13d15610e97573d67ffffffffffffffff8111610e8357610e389160405191610e286020601f19601f8401160184611166565b82523d5f602084013e5b83611b56565b8051908115159182610e5f575b5050610e4d57005b635274afe760e01b5f5260045260245ffd5b8192509060209181010312610d155760200151801590811503610d15578280610e45565b634e487b7160e01b5f52604160045260245ffd5b610e3890606090610e32565b63029a949d60e31b5f5260045ffd5b34610d15576040366003190112610d1557610ecb610f46565b6024357f000000000000000000000000abcdef96793d3f2c06c7e3b5bf73c7d4bd665f956001600160a01b03163303610d22576001600160a01b0382165f908152600c6020526040902054610f30929060ff16828115610f3a575b50610f32576117c6565b005b5f91506117c6565b90506006541184610f26565b600435906001600160a01b0382168203610d1557565b602435906001600160a01b0382168203610d1557565b6040906003190112610d15576004359060243590565b90602080835192838152019201905f5b818110610fa55750505090565b8251845260209384019390920191600101610f98565b90602080835192838152019201905f5b818110610fd85750505090565b82516001600160a01b0316845260209384019390920191600101610fcb565b60025481101561102f5760025f81815291901b7f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace0191565b634e487b7160e01b5f52603260045260245ffd5b600d5481101561102f57600d5f5260205f2001905f90565b8181029291811591840414171561106e57565b634e487b7160e01b5f52601160045260245ffd5b9190820180921161106e57565b9190820391821161106e57565b906110a781836110fb565b915f52600560205260405f209060018060a01b03165f5260205260405f2054808211156110da576110d79161108f565b90565b50505f90565b9190915f838201938412911290801582169115161761106e57565b6111539161112e600161110d84610ff7565b5001546001600160a01b0383165f908152600a60205260409020549061105b565b915f52600460205260405f209060018060a01b03165f5260205260405f2054906110e0565b5f8113156111615760801c90565b505f90565b90601f8019910116810190811067ffffffffffffffff821117610e8357604052565b67ffffffffffffffff8111610e835760051b60200190565b906111aa82611188565b6111b76040519182611166565b82815280926111c8601f1991611188565b0190602036910137565b805182101561102f5760209160051b010190565b6001600160a01b031690811561131957815f52600360205260405f205480611308575060025460088110156112f9576040516080810181811067ffffffffffffffff821117610e835760405283815260208101915f8352604082015f815260608301915f8352600160401b811015610e83578060016112689201600255610ff7565b9490946112e65760039360018060a01b039051166bffffffffffffffffffffffff60a01b86541617855551600185015551600284015551910155600254915f19830183811161106e578093825f52600360205260405f20557f85819f62de3f36778ef25274607ec7071cf41151e6e04a29971d86f30e8bbf915f80a3565b634e487b7160e01b5f525f60045260245ffd5b63df8153c760e01b5f5260045ffd5b9091505f19810190811161106e5790565b63d92e233d60e01b5f5260045ffd5b9091600d5492838310156113ec576113409083611082565b928084116113e4575b5061135c611357838561108f565b6111a0565b9261136a611357848361108f565b92805b82811061137957505050565b80611385600192611043565b838060a01b0391549060031b1c166113a66113a0858461108f565b896111d2565b526113b081611043565b838060a01b0391549060031b1c165f52600a60205260405f20546113dd6113d7858461108f565b886111d2565b520161136d565b92505f611349565b509150506020906040516114008382611166565b5f81525f368137604051926114158185611166565b5f8452505f3681379190565b5f19811461106e5760010190565b5f915f92600d5480156116dc575f9392915a926009545b858710806116d3575b156116855761145d90611421565b918383101561167d575b61147083611043565b905460039190911b1c6001600160a01b031661148b816119a2565b6114c9575b5061149a90611421565b935a908181116114ad575b509391611446565b966114bc826114c2939961108f565b90611082565b955f6114a5565b6002545f919082906001600160a01b03831690825b8181106115215750505061150e575b506114f9575b5f611490565b9661150661149a91611421565b9790506114f3565b5f52600b6020524260405f20555f6114ed565b61152b858261109c565b801561167457600361153c83610ff7565b50835f52600560205260405f20865f5260205260405f2061155e848254611082565b90550161156c828254611082565b8155303b15610d155760405162a93a6b60e51b8152600481018490526001600160a01b0388166024820152604481018390525f8160648183305af19081611664575b506116195791867f9d9e98f5e08c69876edaf0f6cb5a710145dffdf28a008e0e756bee3319d6fb4e60208394600196855f526005835260405f208a5f52835260405f206115fc83825461108f565b905561160982825461108f565b9055604051908152a35b016114de565b5081945090857fad82e4ded87b4f1d117a62956445ec6ff411c4f2eb80134db1573f8cb74b86e7604061165a959994815190815260016020820152a3611421565b9360018093611613565b5f61166e91611166565b5f6115ae565b50600190611613565b5f9250611467565b95509391509150836009556040519082825285602083015284604083015260608201527f30a24227f922fbe8461722b748679f146da10df67921abe743ce85386ca32bf860803292a2929190565b5083831061144f565b50506009545f935083925090565b6001600160a01b0381165f818152600a6020526040902054909181156117c1576002546117198360085461108f565b6008555f5b81811061176f5750507fd8a33efa58f607a36c49d8a8c5477fce4b2c71986998476cbe3494fb8f5fb75891611761604092855f52600a6020525f84812055611a5c565b81519081525f6020820152a2565b80600161177c8193610ff7565b500154858161178e575b50500161171e565b6117979161105b565b815f52600460205260405f20875f526020526117b860405f209182546110e0565b90555f85611786565b505050565b6001600160a01b0381165f818152600a60205260409020549092909182821461197e57600254838311156118dc576117fe848461108f565b61180a81600854611082565b6008555f5b82811061187957505050916040917fd8a33efa58f607a36c49d8a8c5477fce4b2c71986998476cbe3494fb8f5fb758935b855f52600a60205281845f205581155f1461186b5761185e90611a5c565b82519182526020820152a2565b611874906119e0565b61185e565b81600161188583610ff7565b50015480611898575b505060010161180f565b906118a29161105b565b90805f52600460205260405f20885f5260205260405f209182545f828203921281831281169183139015161761106e57909155815f61188e565b6118e6838561108f565b6118f28160085461108f565b6008555f5b82811061192c57505050916040917fd8a33efa58f607a36c49d8a8c5477fce4b2c71986998476cbe3494fb8f5fb75893611840565b8060016119398193610ff7565b500154838161194b575b5050016118f7565b6119549161105b565b815f52600460205260405f20895f5260205261197560405f209182546110e0565b90555f83611943565b50505050565b60025f54146119935760025f55565b633ee5aeb560e01b5f5260045ffd5b6007549081156119d9576001600160a01b03165f908152600b60205260409020549081156119d9576119d391611082565b42101590565b5050600190565b6001600160a01b0381165f818152600e6020526040902054909190611a5857600d5490600160401b821015610e8357611a22826001611a469401600d55611043565b81546001600160a01b0393841660039290921b91821b9390911b1916919091179055565b600d54905f52600e60205260405f2055565b5050565b6001600160a01b03165f818152600e60205260409020548015611a58575f19810181811161106e57600d545f19810190811161106e57808203611b18575b505050600d548015611b04575f1901611ab281611043565b81549060018060a01b039060031b1b19169055600d555f52600e6020525f6040812055600d5480155f14611ae757505f600955565b806009541015611af45750565b5f19810190811161106e57600955565b634e487b7160e01b5f52603160045260245ffd5b611a2291611b28611b4292611043565b905460039190911b1c6001600160a01b0316928391611043565b5f52600e60205260405f20555f8080611a9a565b90611b7a5750805115611b6b57805190602001fd5b630a12f52160e11b5f5260045ffd5b81511580611bab575b611b8b575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b15611b8356fea164736f6c634300081a000a
| Token | Symbol | Balance | Price | Value |
|---|---|---|---|---|
Microsoft • Robinhood Token (MSFT) | MSFT | 0.023027 | $495.22 | $11.4 |
NVIDIA • Robinhood Token (NVDA) | NVDA | 0.043970 | $224.64 | $9.88 |
Tesla • Robinhood Token (TSLA) | TSLA | 0.027537 | $342.54 | $9.43 |
Meta Platforms • Robinhood Token (META) | META | 0.014644 | $592.01 | $8.67 |
Apple • Robinhood Token (AAPL) | AAPL | 0.026758 | $305.28 | $8.17 |
| DIH | 2 | $0.0000102 | $0 | |
Space Exploration Technologies Corp. Class A Common Stock • Robinhood Token (SPCX) | SPCX | 0.077465 | — | — |
Amazon • Robinhood Token (AMZN) | AMZN | 0.037597 | — | — |
Alphabet Class A • Robinhood Token (GOOGL) | GOOGL | 0.027210 | — | — |
| Type | Age | Block | Details |
|---|---|---|---|
| no cross-chain L1↔L2 transactions for this address | |||
| Txn Hash | Age | Event | Topics / Data |
|---|---|---|---|
| 0xda4df1…987e16 | 1 hr agoSun, 16 Aug 2026 20:06:39 UTC | 0xd8a33e…b758 | [0] 0x000000000000…10d09799 data: 0x000000000000000000…ee58b839 |
| 0xd66e81…e1be53 | 6 hrs agoSun, 16 Aug 2026 15:30:58 UTC | 0xd8a33e…b758 | [0] 0x000000000000…f82f50aa data: 0x000000000000000000…00000000 |
| 0xa34ad2…6b4078 | 6 hrs agoSun, 16 Aug 2026 15:30:17 UTC | 0xd8a33e…b758 | [0] 0x000000000000…f82f50aa data: 0x000000000000000000…9b492082 |
| 0xa34ad2…6b4078 | 6 hrs agoSun, 16 Aug 2026 15:30:17 UTC | 0xd8a33e…b758 | [0] 0x000000000000…20cbbe5f data: 0x000000000000000000…00000000 |
| 0xa34ad2…6b4078 | 6 hrs agoSun, 16 Aug 2026 15:30:17 UTC | 0xd8a33e…b758 | [0] 0x000000000000…20cbbe5f data: 0x000000000000000000…9b492082 |
| 0x27c51a…cf87d7 | 12 hrs agoSun, 16 Aug 2026 09:28:50 UTC | 0xd8a33e…b758 | [0] 0x000000000000…03d3e2e4 data: 0x000000000000000000…00000000 |
| 0xfb3b10…9c71e0 | 21 hrs agoSun, 16 Aug 2026 00:27:39 UTC | 0xd8a33e…b758 | [0] 0x000000000000…db8c0904 data: 0x000000000000000000…00000000 |
| 0xfb3b10…9c71e0 | 21 hrs agoSun, 16 Aug 2026 00:27:39 UTC | 0xd8a33e…b758 | [0] 0x000000000000…db8c0904 data: 0x000000000000000000…23347cb6 |
| 0xfb3b10…9c71e0 | 21 hrs agoSun, 16 Aug 2026 00:27:39 UTC | 0xd8a33e…b758 | [0] 0x000000000000…f43aa4be data: 0x000000000000000000…00000000 |
| 0xde0126…b061b2 | 1 day agoSat, 15 Aug 2026 19:29:50 UTC | 0xd8a33e…b758 | [0] 0x000000000000…83095237 data: 0x000000000000000000…dc1fa7e3 |
| 0x7ac93b…82c145 | 1 day agoSat, 15 Aug 2026 15:01:51 UTC | 0xd8a33e…b758 | [0] 0x000000000000…c1409878 data: 0x000000000000000000…907099a2 |
| 0x7ac93b…82c145 | 1 day agoSat, 15 Aug 2026 15:01:51 UTC | 0xd8a33e…b758 | [0] 0x000000000000…20cbbe5f data: 0x000000000000000000…00000000 |
| 0x7ac93b…82c145 | 1 day agoSat, 15 Aug 2026 15:01:51 UTC | 0xd8a33e…b758 | [0] 0x000000000000…20cbbe5f data: 0x000000000000000000…cd9ff46e |
| 0x0e6e0b…effd9d | 1 day agoSat, 15 Aug 2026 09:17:00 UTC | 0xd8a33e…b758 | [0] 0x000000000000…d3f70049 data: 0x000000000000000000…618ee891 |
| 0x0e6e0b…effd9d | 1 day agoSat, 15 Aug 2026 09:17:00 UTC | 0xd8a33e…b758 | [0] 0x000000000000…ec4fff4f data: 0x000000000000000000…00000000 |
| 0x0e6e0b…effd9d | 1 day agoSat, 15 Aug 2026 09:17:00 UTC | 0xd8a33e…b758 | [0] 0x000000000000…ec4fff4f data: 0x000000000000000000…dc4e8af6 |
| 0x0e6e0b…effd9d | 1 day agoSat, 15 Aug 2026 09:17:00 UTC | 0xd8a33e…b758 | [0] 0x000000000000…20cbbe5f data: 0x000000000000000000…00000000 |
| 0x0e6e0b…effd9d | 1 day agoSat, 15 Aug 2026 09:17:00 UTC | 0xd8a33e…b758 | [0] 0x000000000000…20cbbe5f data: 0x000000000000000000…dc4e8af6 |
| 0x2fa549…be617c | 1 day agoSat, 15 Aug 2026 01:09:19 UTC | 0xd8a33e…b758 | [0] 0x000000000000…d3f70049 data: 0x000000000000000000…85405d9b |
| 0x2fa549…be617c | 1 day agoSat, 15 Aug 2026 01:09:19 UTC | 0xd8a33e…b758 | [0] 0x000000000000…ec4fff4f data: 0x000000000000000000…00000000 |
| 0x2fa549…be617c | 1 day agoSat, 15 Aug 2026 01:09:19 UTC | 0xd8a33e…b758 | [0] 0x000000000000…ec4fff4f data: 0x000000000000000000…a6a05d9b |
| 0x2fa549…be617c | 1 day agoSat, 15 Aug 2026 01:09:19 UTC | 0xd8a33e…b758 | [0] 0x000000000000…20cbbe5f data: 0x000000000000000000…00000000 |
| 0x2fa549…be617c | 1 day agoSat, 15 Aug 2026 01:09:19 UTC | 0xd8a33e…b758 | [0] 0x000000000000…20cbbe5f data: 0x000000000000000000…a6a05d9b |
| 0xd3dd32…3120c9 | 1 day agoFri, 14 Aug 2026 21:53:46 UTC | 0xd8a33e…b758 | [0] 0x000000000000…db8c0904 data: 0x000000000000000000…00000000 |
| 0xd3dd32…3120c9 | 1 day agoFri, 14 Aug 2026 21:53:46 UTC | 0xd8a33e…b758 | [0] 0x000000000000…db8c0904 data: 0x000000000000000000…b271a512 |
| Transaction Hash | Method ? | Block | Age | From | To | Amount | Txn Fee ? | ||
|---|---|---|---|---|---|---|---|---|---|
| No direct transactions — this address is only ever reached via internal calls (common for a contract only invoked through a router or proxy). View Internal Transactions → | |||||||||
| Block | Age | Parent Transaction Hash | Type | Method | From | To | Value | |
|---|---|---|---|---|---|---|---|---|
| 12,498,446 | 29 days agoFri, 17 Jul 2026 23:02:05 UTC | 0x167d5d…63d03b | CREATE | optimized_routeFill921336808 | 0xabcd…5f95 | IN | 0x6edd…8136 | 0 ETH |
| Transaction Hash | Method | Block | Age | From | To | Type | Item | ||
|---|---|---|---|---|---|---|---|---|---|
| no NFT transfers for this address yet | |||||||||