Liquidity mining is one of the hottest topics in decentralized finance. Liquidity generally refers to the assets in an ecosystem. In the case of governance protocols, liquidity also represents your piece of the governance pie, so to speak. In this tutorial, I will review how I constructed a liquidity mine for a cryptocurrency project and how you may replicate. I managed to narrow it down to 3 simple steps anyone can follow.
STEP ZERO: PLANNING STAGE
The benefit of providing a liquidity mine is this foregoes the need for an ICO, where tokens are purchased directly from the project, which is subject to regulatory intervention. Ultimately, there should be a reason why you are utilizing this method to distribute tokens and you should consider the following before you jump into coding the smart contract itself. Some considerations you may have are as follows:
- Distribution Method: consider whether you will be minting tokens or whether there will be another functionality you utilize to distribute tokens.
- Inflation Rate: at what rate will your token be introduced into the ecosystem and for how long?
- Utility: while this is not apparent in the contract itself, you should ask yourself what is the purpose of the token you are creating?
In order to build a liquidity mine you need to first determine whether your mine will be minting or transferring tokens as a reward to miners. In the case of the DAO, we wanted to ensure we eliminate the possibility of minting additional tokens, thus I had to come up with a way to transfer tokens from the contract itself to the users of the dApp. Ordinarily, as is the case with Sushi, for example, one would mint the tokens as this is how the tokens are made available to the ecosystem. Given the historical roots of the project I created this mine for (as the response to an unfortunate rug pull by CBDAO), we wanted to remove all doubt entirely, which is why we decidedly eliminated the mint function from the ERC20 contract. Let’s get into the steps I followed to implement the smart contract that will lay the foundation for the Treasury Fund, launching December 22nd, 2020.
STEP ONE: IMPORT LIBRARIES
IERC20.sol returns key aspects of the smart contract, for example, we use the transferFrom function to transfer (address sender, address recipient, uint256 amount). SafeERC20.sol functions wrap amount ERC20 native functions that throw on failure (i.e. when the return is false). Your contract may inherent this functionality by simply including the line: “using SafeERC20 for IERC20”. EnumerableSet.sol enables you to store unique values, which is a handy tool in solidity, as you will see later in this article. SafeMath.sol enables Solidity to throw an error in the case of overflow, eliminating an entire class of bugs. Ownable.sol is a contract module which provides a basic access control mechanism where the owner may be granted access to a suite of functions inaccessible by others via the modifier ‘onlyOwner’.
STEP TWO: DECLARE KEY VARIABLES
You are welcome to declare however many variables are relevant for your project. In the case of the DAO, we are utilizing the Liquidity Mine as both a means to distribute the DAO governance tokens, but also as the launchpad for the the DAO Treasury fund. As such, we include uint256 taxRate to represent the rate at which the pool is taxed. Please note that due to the nature of Solidity, I had to get creative with this number, so it is not as simple as tax rate = 0.02, as Solidity does not cooperate with decimals. As such, the taxRate = 50 and we simply divide the value being deposited by 50 to acquire 2%. This is true for any integer n.
Since every liquidity mining operation is unique, I left out a few lines as they consist of declaring a myriad of variables that may or may not be relevant to your project.
STEP THREE: DESIGN KEY FUNCTIONS
Time to get to the functionality of the contract, which is stored in, you guessed it — your functions. Let’s explore a few options for you to consider using the sample code snippet from the the DAO Liquidity Mining Smart Contract: GovTreasurer.sol. Line 175 declares a function and names it “deposit”, which stores two input variables: Pool ID and Amount. The Pool ID corresponds to the pool selected by the user whereas the Amount corresponds to the amount of tokens the user is elected to deposit. Do not be fooled, this contract is unlike your typical deposit function as it is designed to acquire a tax of 2% on deposit, as discussed before. As such, there is a new variable declared on line 179: uint256 taxedAmount, which corresponds to the amount that is taxed, such that taxedAmount = 2% of deposit amount. This new variable is used 4 times in the function, as a deduction from the amount deposited to the smart contract (line 189), as the amount sent to the DAO treasury (line 190), as an update to the amount the user is owed back upon withdraw (line 191), and as a deduction from the amount that is emitted from the Deposit event (line 195). Altogether, this function enables the desired effect. Get creative and design a function of your own.