Farming
TokenFarm is designed to implement a smart contract-based farming distribution incentive system. Its primary functions include user staking and unstaking of Yield Tokens, and accessing system rewards.
Contract Functions:
Users can stake
Yield Token
(YT, ERC20 Token) acquired by providing liquidity to the fund pool to participate in mining and receive rewards.Users can deposit multiple mining orders, with each staking order calculating earnings separately. Different terms will have different earnings multipliers.
After each day, earnings continue to accrue for each order until the staked assets are withdrawn voluntarily.
Earnings are divided into two parts: the first part comes from block rewards, and the second part comes from earnings generated by the Position Token business.
Main Variables:
TOKEN:
Address of the token used for earnings distribution.lpToken:
Contract address of the staked asset.tokenPerBlock:
Number of tokens produced per block on average.proTotal:
Total number of product orders.startBlock:
Block at which mining begins.lastRewardBlock:
Last updated block for rewards.accTokenPerShare:
Accumulated token rewards per share.accDividendPerShare:
Accumulated dividend rewards per share.totalPower:
Total computing power.totalDividend:
Accumulated dividend funds.
Structures:
Product:
Defines the product cycle duration and multiplier.Order:
Defines the ID, participation amount, computing power, and order time.UserInfo:
Defines the user's computing power, staked amount, earned rewards, pending rewards, reward debts, and other information.
Events:
Deposit:
Triggered when a user stakes their assets.Withdraw:
Triggered when a user withdraws their earnings.
Functions:
initialize()
:
Initialize the basic parameters of the contract.pendingToken()
:
Check the pending rewards waiting to be claimed by the user.updatePool()
:
Update the total hash power and the accumulated rewards per share.deposit()
:
Allow users to deposit staked tokens for mining participation.withdraw()
:
Allow users to withdraw their earnings.harvestOrderPrincipal()
:
Allow users to withdraw their principal amount.getAllProducts()
:
Retrieve information about all products within the system.argInfo()
:
Retrieve aggregated information such as a user's staked assets, authorized limits, pending rewards, etc.getUserOrders()
:
Retrieve a user's current and historical orders.intoFee()
:
Increase Farming2 dividend rewards for the "market contract" address.getToken()
:
Return the address of the reward token.getLpToken()
:
Return the address of the LP token used for mining.getUserInfo()
:
Return detailed information about a specified user.getMultiplier()
:
Calculate the reward multiplier based on the block range.
Security and Upgradability:
Use the
SafeMath library
to prevent integer overflow.Use the
SafeERC20 library
to safely handle ERC20 tokens.
Contract behaviors
Hashrate
Hashrate is a critical concept that determines a user's share in mining activities and the amount of rewards they qualify to receive. Hashrate can be understood as a weighted representation of the assets a user stakes, influencing the distribution ratio of rewards. In the contract logic, each order receives a separate hashrate value based on the periodic hashrate multiplier. The sum of hashrates from all orders represents the user's effective hashrate.
Concept of Hashrate:
Hashrate represents the contribution of a user to a mining pool.
The more assets a user stakes, the higher their hashrate, which corresponds to a larger share of rewards they can receive.
Hashrate is also associated with specific multipliers, meaning different products and deposit options offer varying hashrate multipliers.
Hashrate decreases only when a user releases their staked orders.
The role of hashrate in business logic:
Reward Calculation: Hashrate is used to calculate the amount of rewards a user should receive. The contract allocates rewards based on the proportion of a user's hashrate to the total hashrate.
Updating Total Hashrate:
Reward Debt Management: Each user's UserInfo structure includes a rewardDebt field, which tracks the rewards accumulated by the user since the last update. Hashrate plays a crucial role in calculating this rewardDebt for the user.
Here's the translation for the concepts you provided:
Order Hashrate: In the Order structure, the power field represents the hashrate of each order.
User Hashrate:
In the UserInfo structure, the power field represents the current total hashrate of the user.Reward Debt Update:
In the deposit and _withdraw functions, the user's rewardDebt is updated based on their hashrate and the accumulated rewards per share (accTokenPerShare).Reward Distribution:
In the pendingToken function, the user's pending rewards are calculated based on their hashrate and the accumulated rewards per share.Total Hashrate Maintenance:
In the deposit and harvestOrderPrincipal functions, the total hashrate (totalPower) increases or decreases accordingly as users deposit or withdraw assets.
User Deposit Process
When a user initiates a deposit operation in the smart contract, the following sequence of events occurs:
Calling the deposit function: The user begins the deposit process by calling the deposit function and providing the
product ID (_pid)
and theamount (_amount)
they wish to stake.Updating pool rewards: The contract first calls the updatePool function to ensure all reward variables are up to date, which affects the calculation of user rewards.
Checking user's existing balance: If the user had a previous balance, the contract calculates and transfers their pending rewards to their earnings balance.
Transferring user's staked tokens: The user's YT tokens are transferred from their account to the contract's address. This is achieved by calling
IERC20(lpToken)
.safeTransferFrom.Creating a new order: A new order is created for the user, including the product ID, staked amount, calculated hashrate, and the current block timestamp.
Updating user's hashrate and reward debt: The user's total hashrate is updated based on the hashrate of the new order, and their reward
debt (rewardDebt)
is updated. This debt is the product of the user's hashrate and the accumulated rewards per share.Updating total hashrate and user's stake amount: The contract updates the total hashrate
(totalPower)
and the user's stakeamount (amount)
based on the hashrate and staked amount of the new order.Triggering Deposit event: Finally, the contract triggers a Deposit event, recording the user's address, product ID, and staked amount for on-chain tracking.
Profit Calculation
In the TokenFarm smart contract, calculating a user's profits involves several key steps and variables. Here is the detailed process of calculating user profits:
Basis of Profit Calculation
Accumulated Token
Per Share (accTokenPerShare)
: This is a dynamically changing value that represents the accumulated token rewards per share (or per unit of LP tokens staked) since the start of mining. This value is updated with each new block and is linked to the total hashrate (totalPower).User Hashrate (power)
The user's hashrate is calculated based on the amount of LP tokens they stake and the hashrate multiplier associated with the specific product. Hashrate determines the basis for calculating rewards for the user.
User Reward Debt (rewardDebt)
Each user's UserInfo structure includes a rewardDebt field, which records the user's accrued reward debt since the last update. This value is the product of the user's staked amount and accTokenPerShare.
rewardDebt
rewardDebt is influenced by the user's staked hashrate and the duration of staking. When users stake funds in the Farming pool, their account records a rewardDebt. This value increases over time as rewards accumulate. When users remove funds from the pool or claim earnings, their rewardDebt is calculated against the current amount of reward tokens per liquidity unit in the pool to determine the amount of rewards they should receive.
Specifically, rewardDebt is a snapshot value recorded when the user stakes, representing the portion of reward tokens each liquidity token should receive. When users wish to withdraw their rewards, the system calculates the difference between the current reward token amount per hashrate share (tracked by accTokenPerShare) and the user's
rewardDebt
. This difference is the user's unclaimedreward
.Calculating Pending Rewards (pendingToken)
The user's pending rewards are calculated using the pendingToken function, which considers the user's hashrate and the changes in accTokenPerShare since the last update.
Updating and Claiming Rewards
When users
deposit (deposit)
or claimrewards (_withdraw)
, the contract calls the updatePool function to update accTokenPerShare and lastRewardBlock.The user's rewardDebt is recalculated based on their current hashrate and the updated accTokenPerShare.
Specific Calculation Steps
Updating Pool Rewards:
multiplier = getMultiplier(lastRewardBlock, block.number); tokenReward = multiplier × tokenPerBlock; accTokenPerShare = accTokenPerShare + (tokenReward × 1e12 / totalPower)
;Calculating User Pending Rewards:
pending = (user.power × accTokenPerShare / 1e12) - user.rewardDebt
;Updating User Reward Debt:
user.rewardDebt = user.power × accTokenPerShare / 1e12
;Claiming Rewards: Users claim rewards by calling the withdraw function, which triggers the _withdraw internal function. Their earnings balance increases by their pending
rewards (pending).
Their rewardDebt is updated to reflect the new reward status.
Example of Hashrate and Profit Calculation in the Contract
Where:
tokenReward
is the token reward generated per block.totalPower
is the total hashrate of LP tokens staked by all users.1e12
is a precision factor used to maintain accuracy in calculations. It ensures that there is enough precision even when large amounts of tokens are distributed, and prevents exceeding the maximum value of theuint256
type.
Where:
userPower
is the current hashrate of the user.accTokenPerShare
is the accumulated reward per share.userRewardDebt
is the reward debt recorded for the user at the last reward claim.
Interface
Last updated