Contract Specs
Overview
OnchainPoints Contract is the heart of the ecosystem. It manages points, activities, and rewards. It also defines interfaces for other apps in the ecosystem to use Points issued through various activities.
Contract Details
- License: MIT
- Solidity Version: ^0.8.24
- Inheritance: Initializable, OwnableUpgradeable, UUPSUpgradeable, EIP712Upgradeable, ReentrancyGuardUpgradeable
- Source Code: OnchainPoints
Data Structures
Structs
Request
struct Request {
uint256 deadline;
string nonce;
uint256 amount;
}
Represents a spending request:
deadline
: Timestamp after which the request is invalid.nonce
: Unique identifier to prevent replay attacks.amount
: Amount of tokens to spend.
Activity
struct Activity {
string name;
uint256 lockupEndTimestamp;
uint256 createdAt;
}
Stores information about an activity:
name
: Name of the activity.lockupEndTimestamp
: When the lockup period for rewards ends.createdAt
: Timestamp of activity creation.
DelegatedRequest
struct DelegatedRequest {
uint256 deadline;
string nonce;
uint256 amount;
address owner;
}
Similar to Request
, but for delegated spending:
owner
: Address of the token owner for delegated spending.
Mappings
mapping(string => Activity) public activities;
mapping(string => mapping(address => bool)) public activityRewardsClaimed;
mapping(string => mapping(address => uint256)) public activityClaimAmount;
mapping(string => mapping(address => uint256)) public activityRemainingAmount;
mapping(string => mapping(address => bool)) public activityRewardsWithdrawn;
mapping(address => string[]) public userActivities;
mapping(address => uint256) public userBalance;
mapping(address => uint256) public depositedBalance;
mapping(address => uint256) public referenceUserBalance;
mapping(uint256 => mapping(address => uint256)) public dailySpendings;
mapping(address => bool) public authorizedAddresses;
mapping(address => bool) public adminAddresses;
mapping(address => mapping(bytes32 => bool)) public nonces;
mapping(address => mapping(address => uint256)) public allowances;
activities
: Stores all created activities.activityRewardsClaimed
: Tracks claimed rewards per activity and user.activityClaimAmount
: Amount of rewards claimed per activity and user.activityRemainingAmount
: Remaining locked rewards per activity and user.activityRewardsWithdrawn
: Tracks withdrawn rewards per activity and user.userActivities
: List of activities each user participated in.userBalance
: Current balance of each user.depositedBalance
: Amount of tokens deposited by each user.referenceUserBalance
: Reference balance for calculating spending limits.dailySpendings
: Tracks daily spending per user.authorizedAddresses
: Addresses authorized for certain operations.adminAddresses
: Addresses with admin privileges.nonces
: Tracks used nonces to prevent replay attacks.allowances
: Stores allowances for delegated spending.
State Variables
uint256[2] public maxDailySpendingNumDen;
uint256 public percentageToSendOnClaim;
uint256 public maxDailySpendingCap;
bool public isPaused;
address public stakingContractAddress;
uint256 public totalPointsIssued;
uint256 public remainingPoints;
maxDailySpendingNumDen
: Maximum daily spending limit as a fraction.percentageToSendOnClaim
: Percentage of rewards to send immediately on claim.maxDailySpendingCap
: Maximum cap for daily spending.isPaused
: Flag to pause/unpause the contract.stakingContractAddress
: Address of the associated staking contract.totalPointsIssued
: Total number of points issued.remainingPoints
: Number of unspent/unclaimed points.
Events
event ActivityCreated(string name);
event ActivityClaimed(string name, address user, uint256 amount);
event AuthorizedAddressUpdated(address authorizedAddress, bool allowed);
event BalanceUpdated(address user, uint256 amount);
event ReferenceBalanceUpdated(address user, uint256 amount);
event MaxSpendingUpdated(uint256[2] maxSpendingNumDen);
event TokenSpent(address user, uint256 amount, uint256 dayId);
event Approval(address indexed owner, address indexed spender, uint256 value);
event Deposited(address user, uint256 amount);
event Withdrawn(address user, uint256 amount);
event DepositedTokensSpent(address user, uint256 amount);
Each event captures important state changes or actions within the contract:
ActivityCreated
: When a new activity is created.ActivityClaimed
: When a user claims rewards for an activity.AuthorizedAddressUpdated
: When an address's authorization status changes.BalanceUpdated
: When a user's balance changes.ReferenceBalanceUpdated
: When a user's reference balance changes.MaxSpendingUpdated
: When the maximum daily spending limit is updated.TokenSpent
: When tokens are spent by a user.Approval
: When a delegated spending approval is made.Deposited
: When a user deposits tokens.Withdrawn
: When a user withdraws tokens.DepositedTokensSpent
: When deposited tokens are spent.
Function Signatures and Descriptions
initialize
function initialize(address initialOwner) initializer public
Initializes the contract, setting up the initial owner and EIP712 domain separator.
createActivity
function createActivity(string memory name, uint256 lockupDays) public onlyOwner
Creates a new activity with a specified lockup period. Only the owner can create activities.
claimActivityRewards
function claimActivityRewards(
address user,
uint256[] memory amounts,
string[] memory names,
uint8 v,
bytes32 r,
bytes32 s
) nonReentrant public
Allows users to claim rewards for completed activities. Requires a signature from an admin for verification.
withdrawRewards
function withdrawRewards(string[] memory names) nonReentrant public
Allows users to withdraw their rewards for specified activities after the lockup period.
spendToken
function spendToken(
Request calldata request,
bytes calldata signature
) external nonReentrant returns(address spender)
Allows users to spend their tokens based on a signed request. Typically used for interacting with other contracts in the ecosystem.
approve
function approve(address spender, uint256 amount) external
Approves a spender to spend a certain amount of tokens on behalf of the owner.
spendTokensOnBehalf
function spendTokensOnBehalf(
DelegatedRequest calldata request,
bytes calldata signature
) external nonReentrant
Allows spending tokens on behalf of another user, based on a signed delegated request.
deposit
function deposit() public payable
Allows users to deposit Ether into their account, increasing their balance.
withdraw
function withdraw(uint256 amount) public
Allows users to withdraw Ether from their account, decreasing their balance.
setMaxDailySpending
function setMaxDailySpending(uint256[2] memory _maxDailySpendingNumDen) public onlyOwner
Sets the maximum daily spending limit.
updatePercentageToSendOnClaim
function updatePercentageToSendOnClaim(uint256 _percentageToSendOnClaim) public onlyOwner
Updates the percentage of rewards to send immediately on claim.
updateAdminAddresses
function updateAdminAddresses(address[] memory _adminAddresses, bool[] memory _allowed) public onlyOwner
Updates the admin status for multiple addresses.
pause
function pause() public onlyOwner
Pauses the contract.
unpause
function unpause() public onlyOwner
Unpauses the contract.
setStakingContractAddress
function setStakingContractAddress(address _stakingContractAddress) public onlyOwner
Sets the address of the staking contract.
getTotalBalance
function getTotalBalance(address user) public view returns(uint256)
Returns the total balance of a user, including staking points.
feesWithdrawableBy
function feesWithdrawableBy(address account) public view returns (uint256)
Calculates fees withdrawable by an account.
withdrawFees
function withdrawFees(address account) public
Withdraws fees for an account.
getAvailableSpending
function getAvailableSpending(address spender) public view returns(uint256)
Calculates the available spending for a user.
emergencyWithdraw
function emergencyWithdraw() external onlyOwner
Allows the owner to withdraw all balance in case of emergency.
Interaction with Other Contracts
-
PredictionsOracle:
- Calls
spendToken
orspendTokensOnBehalf
when users buy positions using their OnchainPoints balance.
- Calls
-
Staking Contract:
- Interacts with the staking contract to check earned staking points and potentially auto-stake rewards.
Key Features and Considerations
- Activity and Reward System: Users participate in activities and claim rewards, subject to lockup periods.
- Signature-Based Spending: Uses EIP712 signatures for secure, off-chain approval of spending requests.
- Delegated Spending: Users can approve other addresses to spend tokens on their behalf.
- Daily Spending Limits: Implements configurable daily spending limits.
- Pausable Functionality: Can be paused by the owner in emergencies.
- Upgradability: Designed to be upgradeable using the UUPS pattern.
- Integration with Staking: Can interact with a separate staking contract for complex reward mechanisms.
Usage Examples
Creating an Activity and Claiming Rewards
// Owner creates a new activity
onchainPoints.createActivity("Daily Login", 7 days);
// Admin signs a message approving a reward claim
bytes32 message = keccak256(abi.encodePacked(userAddress, [100], ["Daily Login"]));
(uint8 v, bytes32 r, bytes32 s) = signMessage(adminPrivateKey, message);
// User claims the reward
onchainPoints.claimActivityRewards(userAddress, [100], ["Daily Login"], v, r, s);
// After lockup period, user withdraws rewards
onchainPoints.withdrawRewards(["Daily Login"]);
Spending Tokens in Prediction Market
// User wants to spend 100 tokens to buy a position
uint256 deadline = block.timestamp + 1 hour;
string memory nonce = "uniqueNonce123";
uint256 amount = 100;
// Create and sign the request
OnchainPoints.Request memory request = OnchainPoints.Request(deadline, nonce, amount);
bytes memory signature = signRequest(userPrivateKey, request);
// PredictionsOracle contract calls OnchainPoints to spend tokens
onchainPoints.spendToken(request, signature);
// PredictionsOracle then uses these tokens to buy a position in the market