MIST: Mineable SLP Token
A mineable SLP token using a proof-of-work covenant contract
Last Updated: June 21, 2020
Abstract. SLP tokens are a lightweight implementation of colored coins on Bitcoin Cash. Typically token creators are in control of minting new tokens, although some limitations may be placed on maximum supply, this centralized control presents a problem for some digital token applications. Mist presents the notion of using mineable SLP tokens to address this problem with a Bitcoin script, allowing tokens to be mined using proof-of-work to help decentralize allocation of newly minted tokens.
Mist is an SLP token that can be generated by proof-of-work mining and is governed by a simple, but novel, Bitcoin script. The script is a stateful covenant contract that provides validation for an acceptable mining solution and a scheduled mining reward amount. A constant proof-of-work difficulty requirement coupled with
OP_CHECKLOCKTIMEVERIFY keeps Mist synchronized with the underlying blockchain block height. As far as we are aware, Mist is the first fully autonomous, decentralized, mineable token built on Bitcoin.
Prior to Mist, the process of minting new tokens was solely in the control of the token's creator. The novel concept of mining SLP tokens enables a Bitcoin based token to be decentralized with a permissionless mining reward process. Furthermore, the concept may be used for decentralized applications beyond the purpose of winning token rewards and may leverage a mining process to facilitate a number of interesting concepts, some of which are described below.
This project provides script contracts, a basic miner, and test code to facilitate mining for Mist and creating your own mineable SLP token. The supplied code should be considered to be unaudited and should be peer-reviewed prior to production use in your own project. The provided code and documentation should allow the concept of proof-of-work mineable SLP tokens to be improved and innovated upon by future works.
$ sha256sum mist_miner_0.0.2.zip 3d2f81218e6de83e125739e7341bb7d90e8968497666d258b1dba9753ada0286 mist_miner_0.0.2.zip
2. A Stateful Covenant Contract
Covenant contracts enforce specific constraints on a spending transaction's input and/or output values. These types of contracts have been studied extensively in the Bitcoin community and typically work through introspection of the spending transaction's pre-hash image (or “preimage”) which is validated by using both Bitcoin script opcodes
OP_CHECKDATASIG . A “stateful” covenant contract also has an internally managed state that is validated in the spending transaction and typically allows the user to propose changes to the contract's current state by pushing the new data into the scriptSig which the contract will validate and result in a new contract address. This is not a new concept and has been demonstrated previously by Tobias Ruck with his blockchain chess application. In this project, “token height” is the only internal state variable (a 32-bit signed integer).
The contract checks that a user supplied block height state has been properly incremented by a value of 1, and also checks that a user supplied mining solution produces a hash that contains 3 leading zeros when combined with the transaction's preimage (i.e., \(sha256(preimage + solution) = 0x000123...abc\)).
This project contains four versions of covenant contracts, however v1 was fully developed for the purpose of creating Mist. The remaining versions have been left for the purpose of experimentation, learning, and further exploration. We hope others to use this project to further explore the possibility of building trustless decentralized applications that use SLP tokens.
Here is a description of the various covenants contained in this project:
- v0: Produces a constant mining reward, constant hashing rate (difficulty = 2)
- v1: Produces a variable mining reward with 8 halving events, constant hashing rate (difficulty = 2), and has a CLTV set to 1 block so that SLP mining matches blocks
- v2: Same as v1 plus a Difficulty Adjustment Algorithm driven by baton value amount, higher BCH value on the baton results in higher mining difficulty
- v3: (Not completed) Same as v2 plus an additional dev fund p2sh output
3. Reward Schedule
Mist has a simple rewards emission schedule that decreases the mining reward amount every 4320 blocks (about 30 days). The reward amount is governed by the following snippet from
// calculate proper mintAmount based on current token height int divisor = (tokenHeight / halvingInterval) + 1; verify mintAmount == num2bin(initialMintAmount / divisor, 4);
tokenHeight- An internal counter state of mining events (similar to block height), no reward for 0 height
halvingInterval- The interval to trigger a reward reduction
divisor- The amount the initial reward is divided by
initialMintAmount- The initial reward amount, i.e., 400
mintAmount- The reward amount received by a successful miner
The reward will stop when the \(h\) counter overflows at token height
The Mist mining rewards will stop when the
tokenHeight state variable overflows at a value of 2,147,483,648 which would occur in the year 42,877 (or 40,857 years from now) if Mist miners continue to mine blocks and keep up with the underlying blockchain block height.
The circulating supply of Mist approaches 21 million over a very long period of time, but the supply will never reach that value. The following table summarizes the maximum possible circulating supply of Mist over time assuming mining is kept in sync with the underlying blockchain block height.
|Time After Genesis||Maximum Possible Circulating Supply|
|40,857 y||< 21,000,000|
4. Getting Started with SLP Mining
The v1 contract source code is located in the
spedn folder and can be re-compiled using the instructions found below, but this is not required. The v1 contract template has already been compiled and is stored in the variable named
MINER_COVENANT_V1 within the supplied
.env file for this repository to expedite the process of getting started with SLP mining.
To start mining you would:
- Setup Your Mining Address: Use the “Addresses” tab in Electron Cash SLP (View > Show Addresses) to choose a constant address to provide funding for the mining transaction fees. It may help if you add a label to the address so you can remember the proper address. Once you have selected the address you need to extract the private key WIF from the wallet and then copy that value to the
WIFvariable within this project's
.envfile. To locate the address WIF in Electron Cash SLP, right click on the address and select “Private key”.
- Transaction Fees: You'll need to pay the transaction fees associated with the transaction containing any mining rewards you win. To handle this we're going to pre-prepare some tiny low value UTXOs that can be consumed in the winning transactions. You can leverage the multiple BCH output feature of Electron Cash SLP to accomplish this (e.g., within the Send tab PayTo field paste the value
simpleledger:<address associated with WIF>, 0.00001870multiple times).
- Install Modules: Run
npm ito install the required npm modules and also
- Start Mining: Run
node ./src/minerto start mining.
5. Lessons Learned
During the building of this project there were a few useful things about script that we learned, and we have attached these as appendices, including:
- Appendix A: Some script compilers can leave a string of trailing
OP_NIP, and these operations can be optimized and reduced by up to almost 50% using the post-processing script provided in this project.
- Appendix B:
OP_CODESEPARATORwas used to develop v2 of the covenant contract in order to allow for larger script sizes. The usefulness of this opcode has been debated by the bitcoin community, and some have suggested the opcode has no purpose and should be removed entirely. During the experimental phases of this project we used this opcode to build larger covenant contracts which would have otherwise been impossible due to a transaction preimage exceeding 520-bytes.
6. Future Use Cases & Other Considerations
- Oracles and Decentralized Remote Control. Its possible an application's behavior could be controlled by data located in the scriptSig of the current mint baton location. This would allow for individuals to compete or vote for control of an application with proof-of-work mining.
- Random number generation (e.g., loot boxes or other games of chance). Mint mining can be used to generate a trail of trustless random numbers where miners are incentivised with rewards to mine random numbers honestly for players. The miners' reward to incentive them to mine honestly needs to be sufficiently higher than the amount related to the gaming wager amount or cost for the end user who will be utilizing the random number generated by the miners.
- Non-fungible token (NFT) generation. NFTs can be used in games such that their token ID defines their in-game attributes. Token IDs can be easily manipulated with grinding algorithms to modify the script sig of the NFT Genesis inputs. Mint mining can guard against this by requiring a sufficient amount of work to be generated before the NFT can be produced.
- Mining for BCH rewards instead of SLP. It is possible to lockup a BCH amount within the minting baton value and modify the covenant to control the amount of BCH rewarded at each SLP minting event.
- Difficulty adjustment. The v1 covenant script only used constant difficulty, which could be updated to be something like the v2 covenant script.
- Bitcoin Halving Behavior. The halving algorithm included in this project is not a true halving like Bitcoin. An additional state variable could be added to the contract in order to mimic the halving behavior of Bitcoin if that was desired.
- Use NFT Group. NFT1 Group could be mint mined but with the added benefit of being able to create NFTs from the minted token. This could be an additional mechanism leveraged by decentralized applications.
Appendix A: Optimize Your Nips
The current version of spedn results in long strings of
OP_NIP which is an inefficient way to clear the stack, and may cause you to exceed the 201 operation limitation. Instead of using many OP_NIPs we can use a combination of
OP_TOALTSTACK OP_2DROP ... OP_FROMALTSTACK and reduce the number of stack clearing operations almost by a factor of 2. A script for converting
OP_2DROP has been saved in the scripts folder.
$ node ./scripts/optimize_nips
$ node ./scripts/optimize_nips 0511111111110c2222222222222222222222220a33333333333333333333537982775479780128947f7755795279012c947f7501687f777678827758947f775679547f5a79547f7881547981788c887603e77e039f695e79040084d717527902a866968b965480885e79537f78517f76517f040000000055797e787e52797e54797e0113790117797eaa5b79817f75810088011779547f768100887881760400752b7da16976021027967601209f635c79528867760200049f635c7953886776030080009f635c795488675c795588686868011c79547f788178810088011379547f75815579789f63780222025279587994938867780222028868012179a8011a7988012079041976a9147e012379a97e0288ac7e0120790317a9147e55011f797e01207e011c797e0124797ea97e01877e170000000000000000396a04534c50000101044d494e5420011b797e030102087e5b797e52797e787eaa01197901207f7588011179b175ab012579012579ad012579828c7f75011e79a8012679ba7777777777777777777777777777777777777777777777777777777777777777777777777777 ba77
ba77 is used as a positional marker to tell the optimize_nips script where the string of
OP_NIP (0x77) begins. For different contracts replace
ba77 with the appropriate location marking the start of your series of
Appendix B: Using OP_CODESEPARATOR
OP_CODESEPARATOR was used in experimental script contracts v2 and v3 to overcome the script push limit of 520 bytes. These contracts result in a very large transaction preimage due to the large scriptCode part of the preimage. In these experimental scripts, we used
OP_CODESEPARATOR to circumvent the 520-byte limitation by reducing the size of scriptCode part of the preimage. Future work may benefit from the use of
OP_CODESEPARATOR because it allows scripts larger scripts otherwise limited by other components contained within the transaction preimage which must be pushed within scriptSig.
OP_CODESEPARATOR results in a truncated scriptCode value we were required us to use a “wrapped p2sh” as a final step to validate the sha256 of the base covenant contract template was being honored in the transaction output. This concept of a “wrapped p2sh” may be useful in future work to possibly overcome well-document concerns associated with p2sh collision attack on only 80-bits, however, this would need to be investigated further.