Yield Farming in Bitcoin Cash - A practical guide

16 929
Avatar for p0oker
Written by
3 years ago

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:

  1. Create a SLP token with zero issuance

  2. Store the minting baton centrally temporarily to get the genesis TX id (token ID)

  3. Create a smart contract with 2 parameters, premiumPkh and tokenId

  4. 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.

31
$ 26.26
$ 8.43 from @TheRandomRewarder
$ 5.00 from @tula_s
$ 2.99 from @merc1er
+ 13
Sponsors of p0oker
empty
empty
empty
Avatar for p0oker
Written by
3 years ago

Comments

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.

$ 0.60
3 years ago

Yeah that's actually what I'm thinking about (not for flipstarter use case tho) The idea is I'm not sure if it's feasible to return the funds to multiple pledgers (one by one per demand) if all of them used the same contract. Do you think it's doable?

$ 0.00
3 years ago

Bch has a great contract. You said that there is not native wallet, so what is your opinion about wallets? Which one is good and safe?

$ 0.00
3 years ago

There will be native wallet support soon for this type of contract.

$ 0.00
3 years ago

Nice

$ 0.00
3 years ago

Nice

$ 0.00
3 years ago

Nice

$ 0.00
3 years ago

Well done research! I look forward to seeing what you do with it.

The token emission for the PSF tokens (https://PSFoundation.cash) is based on a simple logarithmic curve. I wonder if it would be possible to bake that in to the contract somehow? Maybe even a rough lookup table, if the math is too complex?

$ 0.11
3 years ago

Thanks! I will be working on emission soon because I also need it. Lack of multiplication in Bitcoin Script is a big problem and I guess these type of algos needs lots of math tricks there. The best variable to be utilized tho is block height IMO.

$ 0.00
3 years ago

If you know a yield farming DAPP that works on BCH let me know.

$ 0.00
3 years ago

Mmm, nice. Can I make a Proof of Stake token with this? I have been doing all bark and no bite lately on the MAZE telegram group, so it's best if I get to know the different kinds of smart contracts to use. MIST (and MAZE, BTCL, dSLP) use Spedn for their contracts, after all.

$ 0.00
3 years ago

What's your goal? To stake SLP and earn interest?

$ 0.00
3 years ago

Yeah, basically the plan is that when someone starts up the staking code/program, they get a small bonus from the total mined, then it's all staking SLP.

$ 0.00
3 years ago

You can but the issue is what they have to actually do to deserve the tokens? In Mist it is solving POW puzzles which is a bit inefficient. In my code, they pay BCH to mint. So you need to know what your code/program is actually supposed to do.

$ 0.00
3 years ago

Basically a token-vending contract :)

$ 0.11
3 years ago

Yeah I guess you can call it that however I think by replacing premium address from P2PKH to P2SH a lot of more interesting tasks could be done

$ 0.00
3 years ago