BangDistributor
0x6edd4dbb53cb2718e6c669e43ba2f0811f548136
Verification
Verified
v0.8.26+commit.8a97fa7a
Type
Contract
7,105 bytes
ABI entries
55
21 read · 9 write
License
none
Contract information
- Address
- 0x6edd4dbb53cb2718e6c669e43ba2f0811f548136
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.26+commit.8a97fa7a
- Optimization
- Enabled
- Creator
- 0xABCdEF9679…D4Bd665F95
- Creation tx
- 0x167d5d466c…6bbf63d03b
Token
Not a token
This contract does not expose ERC-20 metadata.
Read contract (21)
MAX_ASSETS() → uint256
MAX_CLAIM_WAIT() → uint256
accountInfo(address) → uint256, uint256[], uint256[]
accumulativeRewardOf(uint256, address) → uint256
assetAt(uint256) → address, uint256, uint256
assetCount() → uint256
claimWait() → uint256
claimedRewards(uint256, address) → uint256
excludedFromRewards(address) → bool
holderAt(uint256) → address
holderCount() → uint256
holdersSlice(uint256, uint256) → address[], uint256[]
lastClaimTimes(address) → uint256
lastProcessedIndex() → uint256
minimumTokenBalanceForRewards() → uint256
shares(address) → uint256
token() → address
totalShares() → uint256
totalsAll() → address[], uint256[], uint256[]
treasury() → address
withdrawableRewardOf(uint256, address) → uint256
Events (9)
AssetRegisteredClaimClaimFailedCriteriaUpdatedExcludedFromRewardsProcessedRewardDistributedShareUpdatedTreasurySet
ABI
[
{
"inputs": [
{
"internalType": "uint256",
"name": "minimumTokenBalanceForRewards_",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "claimWait_",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [
{
"internalType": "address",
"name": "target",
"type": "address"
}
],
"name": "AddressEmptyCode",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "AddressInsufficientBalance",
"type": "error"
},
{
"inputs": [],
"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": [
{
"internalType": "address",
"name": "token",
"type": "address"
}
],
"name": "SafeERC20FailedOperation",
"type": "error"
},
{
"inputs": [],
"name": "TooManyAssets",
"type": "error"
},
{
"inputs": [],
"name": "TreasuryAlreadySet",
"type": "error"
},
{
"inputs": [],
"name": "UnknownAsset",
"type": "error"
},
{
"inputs": [],
"name": "ZeroAddress",
"type": "error"
},
{
"inputs": [],
"name": "ZeroAmount",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "uint256",
"name": "assetId",
"type": "uint256"
},
{
"indexed": true,
"internalType": "address",
"name": "rewardToken",
"type": "address"
}
],
"name": "AssetRegistered",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "account",
"type": "address"
},
{
"indexed": true,
"internalType": "uint256",
"name": "assetId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "bool",
"name": "automatic",
"type": "bool"
}
],
"name": "Claim",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "account",
"type": "address"
},
{
"indexed": true,
"internalType": "uint256",
"name": "assetId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "ClaimFailed",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "minimumTokenBalanceForRewards",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "claimWait",
"type": "uint256"
}
],
"name": "CriteriaUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "account",
"type": "address"
},
{
"indexed": false,
"internalType": "bool",
"name": "excluded",
"type": "bool"
}
],
"name": "ExcludedFromRewards",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"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": true,
"internalType": "address",
"name": "processor",
"type": "address"
}
],
"name": "Processed",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "uint256",
"name": "assetId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "RewardDistributed",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "account",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "previousShare",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "newShare",
"type": "uint256"
}
],
"name": "ShareUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "treasury",
"type": "address"
}
],
"name": "TreasurySet",
"type": "event"
},
{
"inputs": [],
"name": "MAX_ASSETS",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MAX_CLAIM_WAIT",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "accountInfo",
"outputs": [
{
"internalType": "uint256",
"name": "share",
"type": "uint256"
},
{
"internalType": "uint256[]",
"name": "withdrawable",
"type": "uint256[]"
},
{
"internalType": "uint256[]",
"name": "claimed",
"type": "uint256[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "assetId",
"type": "uint256"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "accumulativeRewardOf",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "assetId",
"type": "uint256"
}
],
"name": "assetAt",
"outputs": [
{
"internalType": "address",
"name": "rewardToken",
"type": "address"
},
{
"internalType": "uint256",
"name": "totalDistributed",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "totalClaimed",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "assetCount",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "claim",
"outputs": [
{
"internalType": "uint256",
"name": "paidAssets",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "claimWait",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
},
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "claimedRewards",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "assetId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "distribute",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "excludedFromRewards",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "index",
"type": "uint256"
}
],
"name": "holderAt",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "holderCount",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "start",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "count",
"type": "uint256"
}
],
"name": "holdersSlice",
"outputs": [
{
"internalType": "address[]",
"name": "accounts",
"type": "address[]"
},
{
"internalType": "uint256[]",
"name": "shareAmounts",
"type": "uint256[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "lastClaimTimes",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "lastProcessedIndex",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "minimumTokenBalanceForRewards",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "gasLimit",
"type": "uint256"
}
],
"name": "process",
"outputs": [
{
"internalType": "uint256",
"name": "iterations",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "claims",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "newLastProcessedIndex",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "rewardToken_",
"type": "address"
}
],
"name": "registerAsset",
"outputs": [
{
"internalType": "uint256",
"name": "assetId",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "minimumTokenBalanceForRewards_",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "claimWait_",
"type": "uint256"
}
],
"name": "setCriteria",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "bool",
"name": "excluded",
"type": "bool"
}
],
"name": "setExcludedFromRewards",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "uint256",
"name": "newShare",
"type": "uint256"
}
],
"name": "setShare",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "treasury_",
"type": "address"
}
],
"name": "setTreasury",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "shares",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "token",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "totalShares",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "totalsAll",
"outputs": [
{
"internalType": "address[]",
"name": "tokens",
"type": "address[]"
},
{
"internalType": "uint256[]",
"name": "distributed",
"type": "uint256[]"
},
{
"internalType": "uint256[]",
"name": "claimed",
"type": "uint256[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "assetId",
"type": "uint256"
},
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "transferReward",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "treasury",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "assetId",
"type": "uint256"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "withdrawableRewardOf",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
}
]Source code
// 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;
}
}
}
Chain explorer1722msChain node90ms