TreasureXRewards
Inherits: Initializable, AccessControlUpgradeable, PausableUpgradeable, ReentrancyGuardUpgradeable, ITreasureXRewards
Title: TreasureXRewards - Multi-Campaign Reward Claiming Contract
Author: ShareX Team
Upgradeable contract managing multiple reward campaigns, each with its own ERC20 token, claim window, and per-user allocations. Key Features:
- Multiple campaigns in a single contract
- Per-campaign ERC20 reward token
- Time-controlled claim windows per campaign
- Updatable per-user allocations
- Gas-optimized storage (1 slot per campaign config, 1 slot per user allocation)
State Variables
_campaignCount
Total number of campaigns created
uint256 private _campaignCount;
_campaigns
Campaign ID => config (1 slot per campaign)
mapping(uint256 campaignId => CampaignConfigInternal config) private _campaigns;
_campaignActive
Campaign ID => whether campaign is active
mapping(uint256 campaignId => bool active) private _campaignActive;
_allocations
Campaign ID => user address => allocation (1 slot per user per campaign)
mapping(uint256 campaignId => mapping(address user => UserAllocationInternal info)) private
_allocations;
_campaignTotalAllocated
Campaign ID => total allocated
mapping(uint256 campaignId => uint128 total) private _campaignTotalAllocated;
_campaignTotalClaimed
Campaign ID => total claimed
mapping(uint256 campaignId => uint128 total) private _campaignTotalClaimed;
__gap
Reserved storage gap for upgrades
uint256[44] private __gap;
Functions
validAddress
modifier validAddress(address addr);
validCampaign
modifier validCampaign(uint256 campaignId);
whenCampaignActive
modifier whenCampaignActive(uint256 campaignId);
whenClaimEnabled
Reason: Combined modifier checks both campaign active + time window in one call, saving gas vs two separate modifiers on the claim hot path.
modifier whenClaimEnabled(uint256 campaignId);
initialize
Initialize the rewards contract
function initialize(address admin_) external initializer validAddress(admin_);
Parameters
| Name | Type | Description |
|---|---|---|
admin_ | address | Admin address with DEFAULT_ADMIN_ROLE |
createCampaign
Create a new campaign with reward token and claim window
function createCampaign(address rewardToken, uint64 claimStartTime, uint64 claimEndTime)
external
override
onlyRole(DEFAULT_ADMIN_ROLE)
validAddress(rewardToken)
returns (uint256 campaignId);
Parameters
| Name | Type | Description |
|---|---|---|
rewardToken | address | ERC20 token address for rewards |
claimStartTime | uint64 | Timestamp when claims open |
claimEndTime | uint64 | Timestamp when claims close |
Returns
| Name | Type | Description |
|---|---|---|
campaignId | uint256 | The ID of the newly created campaign |
updateCampaignTime
Update claim window for a campaign
function updateCampaignTime(uint256 campaignId, uint64 claimStartTime, uint64 claimEndTime)
external
override
onlyRole(DEFAULT_ADMIN_ROLE)
validCampaign(campaignId);
Parameters
| Name | Type | Description |
|---|---|---|
campaignId | uint256 | The campaign to update |
claimStartTime | uint64 | New start timestamp |
claimEndTime | uint64 | New end timestamp |
setCampaignActive
Toggle campaign active status
function setCampaignActive(uint256 campaignId, bool active)
external
override
onlyRole(DEFAULT_ADMIN_ROLE)
validCampaign(campaignId);
Parameters
| Name | Type | Description |
|---|---|---|
campaignId | uint256 | The campaign to update |
active | bool | Whether the campaign should be active |
setAllocation
Set allocation for a single user in a campaign
function setAllocation(uint256 campaignId, address account, uint256 amount)
external
override
onlyRole(DEFAULT_ADMIN_ROLE)
validCampaign(campaignId)
validAddress(account);
Parameters
| Name | Type | Description |
|---|---|---|
campaignId | uint256 | The campaign ID |
account | address | The user address |
amount | uint256 | The allocation amount |
setAllocations
Set allocations for multiple users in a campaign
function setAllocations(
uint256 campaignId,
address[] calldata accounts,
uint256[] calldata amounts
) external override onlyRole(DEFAULT_ADMIN_ROLE) validCampaign(campaignId);
Parameters
| Name | Type | Description |
|---|---|---|
campaignId | uint256 | The campaign ID |
accounts | address[] | Array of user addresses |
amounts | uint256[] | Array of allocation amounts |
withdrawTokens
Withdraw tokens from a campaign
function withdrawTokens(uint256 campaignId, uint256 amount)
external
override
onlyRole(DEFAULT_ADMIN_ROLE)
validCampaign(campaignId)
nonReentrant;
Parameters
| Name | Type | Description |
|---|---|---|
campaignId | uint256 | The campaign ID |
amount | uint256 | Amount to withdraw |
pause
Pause the contract
function pause() external onlyRole(DEFAULT_ADMIN_ROLE);
unpause
Unpause the contract
function unpause() external onlyRole(DEFAULT_ADMIN_ROLE);
claim
Claim a specific amount from a campaign
function claim(uint256 campaignId, uint256 amount)
external
override
nonReentrant
whenNotPaused
validCampaign(campaignId)
whenClaimEnabled(campaignId);
Parameters
| Name | Type | Description |
|---|---|---|
campaignId | uint256 | The campaign ID |
amount | uint256 | Amount to claim |
claimAll
Claim all available tokens from a campaign
function claimAll(uint256 campaignId)
external
override
nonReentrant
whenNotPaused
validCampaign(campaignId)
whenClaimEnabled(campaignId);
Parameters
| Name | Type | Description |
|---|---|---|
campaignId | uint256 | The campaign ID |
getCampaign
Get campaign info
function getCampaign(uint256 campaignId)
external
view
override
validCampaign(campaignId)
returns (CampaignInfo memory info);
Parameters
| Name | Type | Description |
|---|---|---|
campaignId | uint256 | The campaign ID |
Returns
| Name | Type | Description |
|---|---|---|
info | CampaignInfo | CampaignInfo struct |
getCampaignCount
Get total number of campaigns
function getCampaignCount() external view override returns (uint256);
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | count The campaign count |
getAllocation
Get allocation info for a user in a campaign
function getAllocation(uint256 campaignId, address account)
external
view
override
validCampaign(campaignId)
returns (AllocationInfo memory info);
Parameters
| Name | Type | Description |
|---|---|---|
campaignId | uint256 | The campaign ID |
account | address | The user address |
Returns
| Name | Type | Description |
|---|---|---|
info | AllocationInfo | AllocationInfo struct |
getClaimableAmount
Get claimable amount for a user in a campaign
function getClaimableAmount(uint256 campaignId, address account)
external
view
override
validCampaign(campaignId)
returns (uint256);
Parameters
| Name | Type | Description |
|---|---|---|
campaignId | uint256 | The campaign ID |
account | address | The user address |
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | claimable Amount that can be claimed |
isCampaignClaimActive
Check if a campaign’s claim period is active
function isCampaignClaimActive(uint256 campaignId)
external
view
override
validCampaign(campaignId)
returns (bool);
Parameters
| Name | Type | Description |
|---|---|---|
campaignId | uint256 | The campaign ID |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bool | active True if claims are allowed |
_setAllocation
Set allocation for a user in a campaign
function _setAllocation(uint256 campaignId, address account, uint256 amount) internal;
_claim
Process a claim for a user in a campaign
function _claim(uint256 campaignId, address user, uint256 amount) internal;
_getClaimableAmount
Get claimable amount for a user in a campaign
function _getClaimableAmount(uint256 campaignId, address account)
internal
view
returns (uint256);
_isCampaignClaimActive
Check if campaign claim period is active (time-based only)
function _isCampaignClaimActive(uint256 campaignId) internal view returns (bool);
Structs
CampaignConfigInternal
Campaign config packed into 1 storage slot (29 bytes)
struct CampaignConfigInternal {
address rewardToken; // 20 bytes
uint64 claimStartTime; // 8 bytes
uint32 claimEndTimeOffset; // 4 bytes - offset from startTime in seconds
// Reason: Using offset saves 4 bytes vs storing full uint64,
// supports durations up to ~136 years which is sufficient
}
UserAllocationInternal
User allocation packed into 1 storage slot (32 bytes)
struct UserAllocationInternal {
uint128 allocated; // 16 bytes
uint128 claimed; // 16 bytes
}