Skip to content

Functions

DISCLAIMER // NFA // DYOR

This analysis is based on decompiled bytecode and observations of the contract behavior. We are not smart contract security experts. This document aims to explain what the contract appears to do based on the code. It should not be considered a comprehensive security audit or financial advice. Always verify critical information independently and consult with blockchain security professionals for important decisions.

⊙ generated by robots | curated by humans

METADATA
Proxy Address 0x2a9848c39fff51eb184326d65f1238cc36764069 (etherscan)
Implementation Address 0xe528d428c188a80c4824aad89211d292f9a62d77 (etherscan)
Network Ethereum Mainnet
Analysis Date 2025-12-14

Function Summary

CATEGORY NUM FUNCTIONS
Initialization 1
User Functions 5
Operator Functions 8
Admin Functions 12+
View Functions 15+

Initialization Function

initialize(address tokenAddress)

One-time initialization of the contract with the external token address.

ATTRIBUTE VALUE
Location Implementation:243-258
Parameters tokenAddress
Access Anyone (but only works once)
FLAG OBSERVATION
Can only be called once (prevents re-initialization)
First caller becomes admin
No protection on who can initialize (should be called immediately after deployment)
Token address cannot be changed after initialization
STEP ACTION
1 Validate not already initialized
2 Validate token address is not zero
3 Store token address
4 Set initialized flag to 1
5 Set caller as admin
6 Initialize pause states to 0
7 Set minimum balance requirement to 0
8 Set snapshot interval to 3600 (1 hour)
9 Set last snapshot time to block.timestamp
10 Emit initialization event
VARIABLE CHANGE
tokenAddress Set to provided token address
initialized Set to 1
adminAddress Set to msg.sender
minBalance Set to 0
snapshotInterval Set to 3600
lastSnapshotTime Set to block.timestamp
CONDITION REVERT MESSAGE
Already initialized "Already initialized"
Token address is zero "Invalid XCL token"

User Functions

register()

Registers the caller to participate in rewards distribution based on their token holdings.

ATTRIBUTE VALUE
Location Implementation:431-458
Selector N/A (decompiled)
Access External - Any eligible address
FLAG OBSERVATION
Registration is a one-time action per address
Initial reward debt prevents claiming past rewards
User's token balance is snapshot at registration time
External token balance query could fail if token contract is malicious
CONDITION REQUIREMENT
Contract state Not paused
Registration Must be open
Caller status Not blacklisted
Caller status Not already registered
Token balance >= minimum requirement
STEP ACTION
1 Check all preconditions
2 Query caller's token balance from external contract
3 Mark caller as registered
4 Add caller to participants array
5 Store caller's index in mapping
6 Increment participantCount
7 Store caller's balance snapshot
8 Record registration timestamp
9 Add balance to total tracked
10 Calculate initial reward debt
VARIABLE CHANGE
isRegistered[caller] Set to 1
participantIndex[caller] Set to index in array
participants Caller added to array
participantCount Incremented
userBalance[caller] Set to token balance
lastUpdate[caller] Set to block.timestamp
totalTrackedBalance Increased by caller's balance
rewardDebt[caller] Set to balance * rewardsPerShare / 10^18
CONDITION REVERT MESSAGE
Contract paused "Contract is paused"
Registration closed "Registration closed"
Caller blacklisted "Address blacklisted"
Already registered "Already registered"
Insufficient balance "Insufficient XCL balance"
External call fails Depends on token contract
flowchart TD
    Start([register called])

    Start --> Check1{Paused?}
    Check1 -->|Yes| Revert1[Revert: Contract is paused]
    Check1 -->|No| Check2{Registration Open?}

    Check2 -->|No| Revert2[Revert: Registration closed]
    Check2 -->|Yes| Check3{Blacklisted?}

    Check3 -->|Yes| Revert3[Revert: Address blacklisted]
    Check3 -->|No| Check4{Already Registered?}

    Check4 -->|Yes| Revert4[Revert: Already registered]
    Check4 -->|No| ExtCall[Query Token Balance]

    ExtCall --> Check5{Balance >= Minimum?}
    Check5 -->|No| Revert5[Revert: Insufficient balance]
    Check5 -->|Yes| Process[Register User]

    Process --> UpdateState[Update Storage]
    UpdateState --> CalcDebt[Calculate Reward Debt]
    CalcDebt --> EmitEvent[Emit Registration Event]
    EmitEvent --> Success([Registration Complete])

    style Start fill:#e1f5ff
    style Success fill:#e1ffe1
    style Revert1 fill:#ffe1e1
    style Revert2 fill:#ffe1e1
    style Revert3 fill:#ffe1e1
    style Revert4 fill:#ffe1e1
    style Revert5 fill:#ffe1e1

claimRewards()

Allows registered users to claim their accumulated ETH rewards.

ATTRIBUTE VALUE
Location Implementation:568-599
Access External - Registered users
FLAG OBSERVATION
Uses rewards-per-share accounting
Multiple safety checks ensure solvency
ETH transfer uses raw call
State updated after external call (reentrancy risk)
Caller must be able to receive ETH
CONDITION REQUIREMENT
Contract state Not paused
Caller status Not blacklisted
Caller rewards Not individually paused
Caller status Is registered
Pending rewards > 0
Contract balance Sufficient ETH
Reward pool Sufficient balance
STEP ACTION
1 Validate all preconditions
2 Calculate pending rewards
3 Decrease reward pool by pending amount
4 Increase totalClaimed[caller]
5 Increase totalDistributed
6 Update reward debt
7 Transfer ETH to caller
8 Emit claim event
VARIABLE CHANGE
rewardPool Decreased by claimed amount
totalClaimed[caller] Increased by claimed amount
totalDistributed Increased by claimed amount
rewardDebt[caller] Updated to current rewardsPerShare * balance / 10^18
CONDITION REVERT MESSAGE
Contract paused "Contract is paused"
Caller blacklisted "Address blacklisted"
Rewards paused "Rewards paused for this address"
Not registered "Not registered"
No rewards "No rewards to claim"
Low ETH balance "Insufficient contract balance"
Low reward pool "Insufficient reward pool"
Transfer failed "ETH transfer failed"
sequenceDiagram
    participant User
    participant Contract

    User->>Contract: claimRewards()
    Note over Contract: Validate preconditions

    alt Any check fails
        Contract-->>User: Revert with error
    else All checks pass
        Contract->>Contract: Calculate pending rewards
        Note over Contract: balance * rewardsPerShare / 1e18<br/>minus rewardDebt

        Contract->>Contract: Update state

        Contract->>User: Transfer ETH

        alt Transfer succeeds
            Contract->>Contract: Emit claim event
            Contract-->>User: Return amount claimed
        else Transfer fails
            Contract-->>User: Revert: ETH transfer failed
        end
    end

deregister()

Allows users to unregister from the rewards system, claiming any pending rewards first.

ATTRIBUTE VALUE
Location Implementation:640-678
Access External - Registered users
FLAG OBSERVATION
Attempts to claim rewards automatically
Does not revert if reward claim fails (allows exit)
Uses array compaction to avoid gaps
Fully clears user state
No cooldown or penalty for deregistering
CONDITION REQUIREMENT
Contract state Not paused
Caller status Is registered
STEP ACTION
1 Check preconditions
2 If pending rewards exist and sufficient funds, claim them
3 Decrease total tracked balance by user's balance
4 If user is not last in array, compact array
5 Remove last array element
6 Clear all user state
7 Decrement participantCount
8 Emit deregistration event
VARIABLE CHANGE
totalTrackedBalance Decreased by user's balance
participants User removed, array compacted
participantCount Decremented
isRegistered[caller] Cleared
userBalance[caller] Cleared
lastUpdate[caller] Cleared
rewardDebt[caller] Cleared
participantIndex[caller] Cleared
CONDITION REVERT MESSAGE
Contract paused "Contract is paused"
Not registered "Not registered"
ETH transfer fails "ETH transfer failed" (during reward claim)
flowchart TD
    Start([deregister called])

    Start --> Check1{Paused?}
    Check1 -->|Yes| Revert1[Revert: Contract is paused]
    Check1 -->|No| Check2{Registered?}

    Check2 -->|No| Revert2[Revert: Not registered]
    Check2 -->|Yes| Check3{Has Pending Rewards?}

    Check3 -->|Yes| Check4{Sufficient Funds?}
    Check4 -->|Yes| ClaimRewards[Claim Pending Rewards]
    Check4 -->|No| SkipClaim[Skip Reward Claim]
    Check3 -->|No| SkipClaim

    ClaimRewards --> UpdateTotal[Decrease Total Balance]
    SkipClaim --> UpdateTotal

    UpdateTotal --> Check5{Last in Array?}
    Check5 -->|Yes| RemoveLast[Remove from Array End]
    Check5 -->|No| Compact[Move Last Participant<br/>to User's Position]

    Compact --> RemoveLast
    RemoveLast --> ClearState[Clear User State]

    ClearState --> DecrementCount[Decrement Participant Count]
    DecrementCount --> EmitEvent[Emit Deregistration Event]
    EmitEvent --> Success([Deregistration Complete])

    style Start fill:#e1f5ff
    style Success fill:#e1ffe1
    style Revert1 fill:#ffe1e1
    style Revert2 fill:#ffe1e1

updateBalanceSnapshot()

Allows users to manually update their token balance snapshot, claiming any pending rewards first.

ATTRIBUTE VALUE
Location Implementation:601-638
Access External - Registered users
FLAG OBSERVATION
Rate-limited by snapshot interval
Automatically claims pending rewards from old balance
Essential for users whose token balance changes
Relies on external token contract being accurate
CONDITION REQUIREMENT
Contract state Not paused
Caller status Is registered
Time elapsed Snapshot interval elapsed since last update
STEP ACTION
1 Check preconditions
2 Query current token balance from external contract
3 If balance changed from stored balance
4 - If pending rewards exist, claim them
5 - Update stored balance to new balance
6 - Update timestamp
7 - Adjust total tracked balance
8 - Recalculate reward debt
CONDITION REVERT MESSAGE
Contract paused "Contract is paused"
Not registered "Not registered"
Too soon "Snapshot interval not elapsed"
External call fails Depends on token contract

canRegister(address sender)

Checks if an address is eligible to register and returns status message.

ATTRIBUTE VALUE
Location Implementation:375-395
Access Public (view)
CONDITION REQUIREMENT
Contract state Not paused
Registration Is open
Address status Not blacklisted
Address status Not already registered
Token balance >= minimum requirement
TYPE DESCRIPTION
bool Can register
Multiple strings Status/error description

Operator Functions

depositRewards()

Deposits ETH into the reward pool for distribution to participants.

ATTRIBUTE VALUE
Location Implementation:210-221
Access Admin or Operator
Payable Yes
FLAG OBSERVATION
ETH sent is immediately available for distribution
Rewards distributed proportionally to token holdings
If no participants, ETH accumulates without updating rewardsPerShare
No cap on deposit amount
Critical function for system operation
STEP ACTION
1 Validate caller has permission
2 Validate ETH amount > 0
3 Add ETH to reward pool
4 If participants exist, increase rewardsPerShare
5 Emit deposit event
VARIABLE CHANGE
rewardPool Increased by msg.value
rewardsPerShare Increased by (10^18 * depositAmount) / totalTrackedBalance
sequenceDiagram
    participant Operator
    participant Contract

    Operator->>Contract: depositRewards() + ETH
    Note over Contract: Check operator permission

    alt Not operator
        Contract-->>Operator: Revert: Not operator
    else Is operator
        alt Amount <= 0
            Contract-->>Operator: Revert: Amount must be positive
        else Amount > 0
            Contract->>Contract: Increase reward pool

            alt Participants exist
                Contract->>Contract: Calculate rewards per share
                Contract->>Contract: Increase rewardsPerShare
            else No participants
                Note over Contract: ETH stored but not<br/>distributed yet
            end

            Contract->>Contract: Emit deposit event
            Contract-->>Operator: Success
        end
    end

pause() / unpause()

Controls global pause state of the contract.

ATTRIBUTE VALUE
Location Implementation:137-153
Access Admin or Operator
FUNCTION ACTION
pause() Sets paused flag to 1
unpause() Sets paused flag to 0

openRegistration() / closeRegistration()

Controls whether new users can register.

ATTRIBUTE VALUE
Location Implementation:155-181
Access Admin or Operator

blacklistAddress(address)

Adds an address to the blacklist, preventing registration and claims.

ATTRIBUTE VALUE
Location Implementation:273-284
Access Admin or Operator
FLAG OBSERVATION
Does not automatically deregister if user already registered
Prevents future registrations and claims
Separate from pause functionality (address-specific)

pauseUserRewards(address)

Pauses rewards for a specific registered user.

ATTRIBUTE VALUE
Location Implementation:286-297
Access Admin or Operator

forceDeregister(address, bool)

Forcibly deregisters a user, optionally claiming their rewards first.

ATTRIBUTE VALUE
Location Implementation:680-727
Access Admin or Operator
FLAG OBSERVATION
Admin/operator can remove users without their consent
Can choose whether to claim user's rewards first
Clears pause status when removing

globalBalanceSnapshot()

Updates token balance snapshots for all registered participants.

ATTRIBUTE VALUE
Location Implementation:491-529
Access Anyone
FLAG OBSERVATION
Can be called by anyone (public utility function)
Rate-limited by interval to prevent spam
Gas cost scales linearly with participant count
Critical for maintaining accurate distribution
flowchart TD
    Start([globalSnapshot called])

    Start --> Check1{Interval Elapsed?}
    Check1 -->|No| Revert1[Revert: Interval not elapsed]
    Check1 -->|Yes| Init[Initialize: idx=0, sum=0]

    Init --> Loop{idx < participants.length?}
    Loop -->|No| UpdateTotal[Update Total Tracked Balance]
    Loop -->|Yes| QueryBalance[Query participant balance]

    QueryBalance --> Check2{Balance Changed?}
    Check2 -->|No| AddToSum[Add old balance to sum]
    Check2 -->|Yes| UpdateUser[Update user balance]

    UpdateUser --> EmitUserEvent[Emit balance change event]
    EmitUserEvent --> AddNewToSum[Add new balance to sum]

    AddToSum --> Increment[idx++]
    AddNewToSum --> Increment
    Increment --> Loop

    UpdateTotal --> UpdateTime[Update last snapshot time]
    UpdateTime --> EmitGlobal[Emit global snapshot event]
    EmitGlobal --> Success([Snapshot Complete])

    style Start fill:#e1f5ff
    style Success fill:#e1ffe1
    style Revert1 fill:#ffe1e1

Admin Functions

addOperator(address newOperator)

Grants operator role to a new address.

ATTRIBUTE VALUE
Location Implementation:260-271
Access Admin only
CONDITION REQUIREMENT
Caller Is admin
Address Not zero
Status Not already an operator

queueAdminTransfer(address) / acceptAdminTransfer()

Two-step admin transfer with 24-hour timelock.

ATTRIBUTE VALUE
Access Admin (queue) / Pending Admin (accept)
Timelock 24 hours
FLAG OBSERVATION
Two-step process prevents accidental transfers
Pending admin must actively accept
24-hour delay provides warning

queueOperatorRemoval(address) / executeOperatorRemoval(address, uint256)

Queues and executes operator removal with 24-hour timelock.

ATTRIBUTE VALUE
Access Admin only
Timelock 24 hours

queueParameterChange(uint256) / executeParameterChange(uint256, uint256)

Queues and executes minimum balance requirement change with timelock.

ATTRIBUTE VALUE
Access Admin only
Timelock 24 hours

queueEmergencyWithdrawal(...) / executeEmergencyWithdrawal(...)

Queues and executes emergency withdrawal of ETH or ERC20 tokens.

ATTRIBUTE VALUE
Location Implementation:350-360 (queue), 531-566 (execute)
Access Admin only
Timelock 24 hours
FLAG OBSERVATION
Critical emergency function to recover funds
Can withdraw any ERC20 token (including the tracked token)
Can withdraw ETH from reward pool
24-hour timelock provides warning period
Could be used to drain the contract

manualBalanceUpdate(address, uint256)

Allows admin to manually set a user's tracked token balance.

ATTRIBUTE VALUE
Location Implementation:362-373
Access Admin only
FLAG OBSERVATION
Powerful admin function that can manipulate reward distribution
Bypasses external token contract query
Could be used to fix discrepancies or manipulate system
No validation that new balance matches actual token balance

cancelQueuedAction(bytes32)

Cancels a queued timelock action.

ATTRIBUTE VALUE
Location Implementation:192-200
Access Admin only

removeFromBlacklist(address)

Removes an address from the blacklist.

ATTRIBUTE VALUE
Location Implementation:233-241
Access Admin only

unpauseUserRewards(address)

Unpauses rewards for a specific user.

ATTRIBUTE VALUE
Location Implementation:223-231
Access Admin only

View Functions

Contract State Functions

FUNCTION RETURNS PURPOSE
initialized() bool Whether contract has been initialized
admin() address Current admin address
pendingAdmin() address Pending admin during transfer
paused() bool Whether contract is globally paused
rewardPool() uint256 Total ETH available for rewards
totalDistributed() uint256 Cumulative ETH distributed
participantCount() uint256 Number of registered participants

User State Functions

FUNCTION RETURNS PURPOSE
isRegistered(address) bool Whether address is registered
blacklisted(address) bool Whether address is blacklisted
operators(address) bool Whether address has operator role
totalClaimed(address) uint256 Total rewards claimed by address
participants(uint256) address Participant at specific index

Statistics Functions

FUNCTION RETURNS PURPOSE
getStats() Multiple Comprehensive contract statistics
pendingRewards(address) uint256 Pending reward amount for address
userStats(address) Multiple Share percentage, tracked balance, current balance
getParticipants(uint256, uint256) address[], uint256[] Paginated list of participants and balances