Understanding Ref Farming
Terminology
word
meaning
notes
Farm
A place to farming on
A farm has one seed and one reward
Seed
Farming-Token
User stakes seed to this contract to gain various reward token from all running farms using this seed
Reward
Reward-Token
A standard NEP-141 token that deposited to some farm as reward to farmers
SeedId
String
Token contract_id for ft token, token contract_id + "@" + inner_id for mft token
FarmId
String
SeedId + "#" + farm_index in that seed
RPS
Reward-Per-Seed
The key concept to distribute rewards between farmers in a farm, see next chapter for details
RR
Reward Round in num
The rewards are released by round, and round starts from 1, see next chapter for details
features
Multi-farming, staking one seed token can gain multiple rewards on multiple farms;
No freezing time when un-stake;
Both FT and multi-FT are supported as seed;
Logic
Basic Concept
Farmer deposit/stake Seed token to farming on all farms that accept that seed, and gains reward token back.
different farm can (not must) has different reward token.
Farm Creation
To create a farm, we should settle five params:
seed, which seed token this farm accepts;
reward, which reward token this farm gives;
when to start, in timestamp seconds, if 0 is given, then immediately starts when reward token deposits in;
round interval, each round lasts in block counts;
total reward per round;
And then transfer reward token into the farm using ft_transfer_call interface with farm_id
in msg field.
Reward Distribution
Every running farm would release reward per reward round. Those released reward would exist in a form of user_unclaimed_reward
for each user.
User has to explicit invoke claim
action to fetch those reward into his inner account, and invoke withdraw
to get those assets in inner account into his own near account. Although there are two txs here, the frontend could combine those actions to make it look like a one stop action.
Deep into reward distribution, it is calculated independently among farms and according to this logic:
user_unclaimed_reward = user_staked_seed * [RPS(farm) - RPS(user)]
where,
RPS(farm) = prev_RPS(farm) + to_be_distribute_reward / total_staked_seed
and,
RPS(user) = RPS(farm)
after user claims reward each time.
To figure out how many reward are waiting for distribution, we use RR to record the last distribution time. Then it turns to:
to_be_distribute_reward = reward_per_round * [RR(current) - RR(last)]
the RR, RPS(farm) and RPS(user) will be updated after following actions are invoked:
user claim reward;
user stake seed (imbed a user claim process);
user un-stake seed(imbed a user claim process);
Note: to get detailed implement of that distribution logic, please refer to the contract readme.
Farm status
Created, A farm that has been created but either no reward token is deposited in or start time is not reached;
Running, A farm that is in working and release reward per round;
Ended, A farm with all reward has been distributed (user may still have unclaimed reward);
Cleared, A farm that has ended and no unclaimed reward, can be removed from the contract. After removal, this farm is in this Cleared status. (You can never get this status from contract);
Storage Management
Each user would have a place to store his reward tokens balance, staked seed tokens balance, and last time RPS
for each farm he involves. So, user storage management is needed.
Although the frontend would take care all of the storage details for users, it is still not bad to understand the core logic behind, especially there is kind of post-pay style exists in our storage management.
Almost all NEAR contract require a pre-pay style to deal with the user storage cost. In that style, users do storage_register
and deposit a fixed storage fee before invoking any business interfaces.
But take our logic model into consideration, the pre-pay style couldn't have a 100 percent fit. Cause the user storage size would expand even shrink during farming. More involved farms more user storage needs, and even worse, farm management beyonds users scope. User couldn't know exactly how many storage he would need in advance.
So, we combine traditional storage strategy with kind of pre-pay amendment. When user does his first storage_register
, we require him to deposit a storage fee that can support 5 reward tokens, 5 seed tokens and 10 farms. And then, with the running of farming, if at some point the storage fee exceeds, we keep the farming going but disable user's critical calls, such as stake/un-stake seed, claim rewards. In those critical calls, we would notify user with insufficient storage msg through panic, In that case, user then need to add more storage fee through the same storage_register
interface with only_register
param set to false.
Complex eh? But no worry, as we said above, the frontend would take care all of this for you.
Last updated
Was this helpful?