Yield farming or liquidity mining is the newest trend in crypto, particularly introduced by Ethereum community and with the invention of Compound governance token and is considered the latest trend in DeFi. The basic idea is for participants in a protocol to mine tokens using their liquidity or generally investing on a specific platform.
This concept is new and is not used in many other cryptocurrency communities. I believe many people think performing that kind of functions is not feasible on Bitcoin Cash because the smart contracts on BCH are not as advanced as Ethereum. Even though that notion is true, the very act of minting a SLP token in a decentralized manner is already proven by projects like Mistcoin.
In this article I like to go in depth into the possibility of Yield Farming in Bitcoin Cash, the implementation and provide you a real sample transaction and Cash Script code that successfully minted a SLP token using an investment (called premium) without any centralized interference.
The Smart Contract
Bitcoin Cash smart contracts are inherently different from platforms like Ethereum. In Ethereum smart contracts are large, they can easily issue tokens and have full access to the state of the protocol. Bitcoin Cash smart contracts are stack based and very limited. However, they are more advanced than Bitcoin in the sense that developers can access the full data of the transaction and limit the inputs and outputs to specific parameters. These type of contracts are called Covenants. A detailed explanation of the differences between BCH and ETH smart contracts can be found in Rosco Kali's blog post.
SLP Minting Baton
Another element that requires for this type of transactions to work are SLP Minting Batons. Generally anytime someone creates a new SLP token, they can specify a Bitcoin Cash address to store the minting baton. Meaning that everyone who holds control of that address can issue new SLP tokens in the future.
Keeping this Baton in a normal BCH address is very dangerous and a centralized way to keep the supply of a SLP token. The owner of the SLP token have the authority to destroy that Baton to stop the issuance of the new tokens, however in order to do that they have to issue a large amount of tokens and keep them centrally for future use. SLP tokens like Spice or Sour are some of those examples.
Good news that there is a better way to do this as well. A SLP minting Baton can be sent to a smart contract which controls the issuance of the token and takes away any central control over the token. However, the smart contract should be able to provide conditions to prevent minting of the token by actors who did not provide sufficient value for that.
Transaction Details
Considering the elements discussed, we need to perform these actions to create the Yield Farming contract for users of a token:
Create a SLP token with zero issuance
Store the minting baton centrally temporarily to get the genesis TX id (token ID)
Create a smart contract with 2 parameters, premiumPkh and tokenId
Perform a mint transaction with zero issuance to move the Baton to the P2SH contract forever.
Now every party can spend this contract with an atomic transaction only and only if these conditions are met:
A minimum amount of BCH should be sent to premiumPkh ( a normal BCH address or another contract)
Minting baton should be sent back to the same contract
Enough BCH should be provided by the farmer to cover the transaction fees and the locked satoshis for the freshly minted tokens
If the transaction by the farmer (end user) is created according to the rules above, the user will end up creating new SLP tokens which will be sent to her address. Failure to do so, will fully reject the transaction and no BCH is lost in the process.
Here is an overview of how this transaction looks like:
You can view the above transaction here.
Smart Contract Implementation
Thanks to the efforts done by Rosco Kalis and the sponsors of the Cash Script (General Protocols and Bitcoin.com), this language is evolving to become the standard for BCH smart contracts. The new version of the Cash Script makes the process of working with Covenants pretty straightforward.
Here is the code to implement the smart contract described in this example. As you can see, there is no central key in the contract to control the issuance and it makes the contract reusable by everyone for an unlimited amount of time.
This contract is more like a proof of concept and lacks the edge cases like emission control, change addresses or proportional reward according to the premium. So with this contract, a person simply can send a minimum of 1000 satoshi to the premium address to mint 250 new tokens for herself.
contract Yield(bytes20 premiumPkh, bytes tokenIdHex) {
function farm(pubkey farmerPk, sig s, int premium) {
require(checkSig(s, farmerPk));
// minimum amount of premium to be paid in order to farm the yield
int minPremium = 1000;
int satsToBeMinted = 546;
int satsLockedInForBaton = 546;
int dust = 546;
require(premium >= minPremium);
bytes opReturnOut = new OutputNullData([
0x534c5000, // Lokad ID for SLP
0x01,
bytes('MINT'),
tokenIdHex,
0x03, // minting baton vout (very important to avoid burning the baton)
0x00000000000061A8 // 250 SLPs (considering 2 decimals)
]);
// minted token sent back to the farmer
bytes34 out1 = new OutputP2PKH(bytes8(satsToBeMinted), hash160(farmerPk));
// investment to the premium in order to farm
bytes34 out2 = new OutputP2PKH(bytes8(premium), premiumPkh);
// minting baton should be sent back to the contract
bytes32 out3 = new OutputP2SH(bytes8(satsLockedInForBaton), hash160(tx.bytecode));
require(hash256(opReturnOut + out1 + out2 + out3) == tx.hashOutputs);
}
}
Farming the Contract
Farming the contract should happen with inputs from the end-user + the Minting Baton input which is inside the smart contract. This address is reusable by anyone and can be used forever to mint tokens as long as the premium amount is paid (could be investment in another contract or just a one time payment).
Here is an example of how it should look like (in Node JS):
// Making the transaction to pay the premium and mint SLP to alice address using the minting baton
// stored in the smart contract
let tx = await contract.functions
.farm(alicePk, new SignatureTemplate(aliceKeyPair), premiumAmount)
.from(aliceUtxos)
.from(mintingBaton)
.withOpReturn([
"0x534c5000", // Lokad ID
"0x01", // Token type
"MINT", // Action
`0x${tokenId}`, // Token ID
"0x03", // Minting baton vout
"0x00000000000061A8", // mint 250 new tokens (considering 2 decimals)
])
.to(aliceBchAddr, 546) // freshly minted tokens
.to(premiumBchAddr, premiumAmount) // minimum 1000 sats premium is required
.to(contract.address, 546) // minting baton is sent back to contract
.withoutChange()
.send();
The codes demonstrated here are very new and not thoroughly tested or optimized. However the full implementation of this functionality, including the genesis of the token, moving the baton to smart contract and functional mint transaction is maintained in a repository in my Github. Fully open source under the MPL-2.0 license.
Use Cases
There are numerous use cases for this type of contract including but not limited to:
Reward tokens for other contracts (e.g DeFi, AnyHedge, etc)
Governance Token distribution
Decentralized token sales without custody
Loyalty tokens to a merchant's customers
Fundraiser without assurance contract (e.g GoFundMe )
Decentralized Exchange (requires an oracle for rates)
Conclusion
Thanks for following through the article. SLP and Bitcoin Cash smart contracts are amazing technologies and most of the advanced use cases from these technologies are still not utilized. Feel free to get the code, run it and explore the unlimited use cases that you can imagine to build on Bitcoin Cash.
The challenge of using these type of contracts in the wild is the type of transaction that should be constructed differently. There is no native wallet support for these transactions yet, however, if you are familiar with my other project Signup, one of the main plans in the roadmap of that wallet is bringing Bitcoin Cash smart contracts to the web and mainstream apps. Here is the article about Signup's release in case you missed it.
If you are interested to build a Yield Farming/Reward contract but don't have the required knowledge feel free to reach out to me at my Twitter. I would be happy to help you out.
So, if someone can make a separate contract that can:
1) forward funds to a recipient if a threshold is met (assurance part of the flipstarter model) 2) return funds to a pledger by burning the reward tokens and 3) send funds from the contract, back to the contract, to consolidate inputs
Then you might have a scalable and user-friendly basis for a replacement for flipstarter, that provides participation tokens by default. No more participation floors, but would still need either a wallet plugin to craft the transaction, or a coordinator to make the transaction and a new protocol for signing provided transactions.
Interesting.