Skip to main content

Regen Farm Smart Contract Guide

GIVeconomy is a collection of audited smart contracts which work together to provide capabilities, including: token streaming, airdropping, and various types of farming. Contracts and scripts can be found at the Giveth giv-token-contracts repository.

Contracts

Streaming

The streaming allows any rewards (e.g. airdrop, liquidity mining reward, ...) to be released gradually across a given time span instead of the whole sum moving immediately to the end user's wallet. To achieve that, every reward payment to users will be an allocate on stream instead of a traditional transfer/safeTransfer.

Each instance of a Stream is deployed with these configuration parameters:

  • Total Tokens: Total amount of tokens that will be distributed over the stream period
  • Start Time: The time stamp that the stream begins
  • Duration: Total duration of the stream. At the end of stream 100% of tokens are released and can be claimed by recipients.
  • Cliff Period: The length of an initial period after the start of the stream. During this period, only the intitial percentage of the stream can be claimed and not more.
  • Initial Percentage: The percentage of immediately claimable rewards during the Cliff Period

The TokenDistro is the smart contract which has implemented the streaming feature. Any eligible smart contract or eligible user can call allocate method on the TokenDistro to add to the recipient's balance of their stream. Eligible contracts or users who can call allocate should have the DISTRIBUTOR role for the TokenDistro smart contract. They are called Distributors. Each Distributor has a balance that they can distribute. Therefore, on each allocation the allocated amount sent is decreased from the distributor's balance and is added to recipient's balance.

A percentage of the allocated amount is claimable immediately, and the remaining percent goes into increasing recipient's stream flowrate. The flowrate is an expression of how many tokens become claimable from their stream over a weekly period. Over time, a greater percentage of the recipient's balance will be claimable immediately following the continued expansion of the stream.

Air Drop

The initial token distribution can be done by the MerkleDistro smart contract. It utilizes Merkle Tree theory and each eligible recipient should provide its own unique proof data to claim their air drop. The air drop value actually will be allocated by calling allocate on TokenDistro and will be added to user's stream balance.

Each instance of MerkleDistro is deployed with these configuration parameters:

  • Merkle Tree Root: The key of the merkle tree root (read blow).
  • Token Distro Address: The address of the deployed TokenDistro instance.

In order to deploy the MerkleDistro smart contract, the deployer must generate a merkle tree. The value of root will be used on the smart contract at deployment time, and the whole tree data is needed to obtain each user unique path to root. In giv-token-contracts repo, there is a script to generate merkle tree data.

ts-node scripts/generate-merkle-root.ts --input <airdrop json file path> --output <output file path>

A JSON format of the airdrop data is not easy to generate for everyone, an airdrop json file can be generated by a separate script from a CSV file, which is a more convenient format.

ts-node scripts/csv2json.ts <airdrop csv list path> <airdrop json file path>

Farming

Giveth uses the UnipoolTokenDistro, a derivative of the Unipool smart contract, for farming purposes. The difference is that UnipoolTokenDistro pays stakers' rewards by calling allocate method on the TokenDistro(stream) instead of transferring real tokens to the recipient's address.

Generally, the Unipool contract rewards stakers based on the liquidity they have staked. The liquidity token is named uni deposited by stakers, and can be any token such as native token (e.g. GIV, FOX, ...) or a LP token obtained by staking in a pool (e.g. UniswapV2, SushiSwap, HoneySwap, ...).

The Unipool reward amount is set by calling the notifyRewardAmount(uint256 reward) method by the rewardDistribution. rewardDistribution can be set by the owner role and in the deployment script, deployer set its own address as rewardDistribution by default. Each time this method is called, the Unipool will set to disperse rewards in the duration length period to stakers. Therefore, the reward distributor need to regularly call notifyRewardAmount to keep a positive reward rate, and adjust the reward rate as it can be different on each round. Each instance of the UnipoolTokenDistro is deployed with these configuration parameters:

  • TokenDistro Address: The address of deployed TokenDistro instance.
  • Uni Token Address: The liquidity token address
  • Duration: Each rewarding program round length

Deployment

Deployment of a stream with farms and an airdrop is complicated and would be error prone to be done manually. Therefore, giv-token-contracts has scripts to make it easier. Most of these scripts are tailored for GIVeconomy use cases.

However, a script is ready for DAOs to deploy their own stream (tokenDistro) and farming programs (Unipools). The script can be found in the path deployments/regenFarms/1_regenFarm.ts. The script reads the deployment configuration from deployments/regenFarms/config.ts file. The configuration format in config.ts is as below:

const config: IRegenConfig = {
alreadyDeployedTokenDistroAddress: "",
newTokenDistroParams: {
startTime: <start time timestamp>
cliffPeriod: <cliff time duration seconds>
duration: <duration seconds>
initialPercentage: <percentage number, like 20_00>, // two decimals of precision, 20_00 means 20%
tokenAddress: <Reward token address>
totalTokens: <Total number of tokens to distribute limit>, // In ether format
cancelable: <boolean>, // whether admins can cancel an allocation
},
unipools: {
<Key>: {
uniTokenAddress: <unit token address>,
lmDuration: <unipool reward round duration seconds>
rewardAmount: <Unipool balance on token distro>, // Number of tokens it can allocate
},
...
},
};

To deploy via script these environmental variables should be set:

  • INFURA_PROJECT_ID: When the network is not xDai (Gnosis-Chain)
  • PRIVATE_KEY: The private key of deployer account, used when network is not xDAI (Gnosis-Chain)
  • PRIVATE_KEY_XDAI: The private key of deployer account, used when network is xDAI (Gnosis-Chain)

The script can be run by this command

HARDHAT_NETWORK=<network e.g. xDAI, mainnet, kovan> ts-node deployments/regenFarms/1_regenFarm.ts