It was an amazing weekend participating in Bitcoin Cash DevCon III, exploring Bitcoin Cash ecosystem and SLP Token standards. As all our team is concerned about privacy in blockchain, we have built SLP.Cocktail: the platform for decentralized SLP СoinОoins. And now we are happy to share our experience and show how you can make some delicious “cocktails” on your own!
What does SLP stand for?
It’s quite unfair to start our journey with mysterious abbreviations. So, let’s fix it.
SLP means Simple Ledger Protocol and is a developing standard protocol for issuing and managing tokens on the Bitcoin Cash blockchain. It uses a restricted form of bitcoin script after the OP_RETURN to encode token metadata and denote operations. Thus, token operations are part of the transaction but their interpretation is performed off-chain according to SLP consensus.
Every asset is described by a token type and unique token id. So far, only type 1 is defined in the specification and 3 more are reserved.
There are 2 subtypes for type 1:
- Token Type 1: a fungible asset, interchangeable tokens, similar to ERC20 on Ethereum or FA1.2 on Tezos.
- NFT 1: a non-fungible asset, “unique” tokens, similar to ERC721.
For our cocktails, tokens of type 1 are the key ingredient.
What is Coinjoin?
Coinjoin is an approach of combining inputs and output from different addresses to increase privacy and to complicate the determination of connections between senders and recipients.
Bitcoin Cash transaction contains a set of inputs and a set of outputs that are not linked to each other. That’s why if users cooperate and join their UTXO and agree about common outputs set it’s hard to say whom the output was proposed by.
Imagine we have a secret present ceremony during our party: everybody brings presents in similar boxes and the receiver’s name inside, gifts are collected on the table, and at the end of the party the host reads the labels and gives out the presents to their recipients. As simple as never.
Prepare our kitchen
Before we actually proceed to making conjoins let’s make sure that all ingredients are at hand:
- 2 installed dependencies;
- 1 SLP token;
- 2 accounts funded with BCH and the same SLP tokens.
1. Install Dependencies
npm i @psf/bch-js slpjs
For coinjoins itself only
@psf/bch-js is needed. It works both in Node.js and browser. Other dependencies are used to prepare and fund accounts.
2. Create Accounts
Create a new HD wallet. Note: we specify the derivation path used by Electron, Exodus and Coinomi wallets.
Store account info in the separate file:
Check out the full code here. We need at least two accounts.
2. Fund accounts with BCH
Request some tokens to both accounts from faucet https://faucet.fullstack.cash/.
3. Create new SLP token
We will use
bchjs as on the previous step so it should be prepared in advance.
Configure our future token info
Import issuer account:
Fetch and chose the smallest utxo that is enough to cover the transaction fee.
Create a new transaction and add fetched utxo as the only input:
Add transaction outputs. According to SLP Token Type 1 specification, the output 0 should contain op_return script with new token details and shouldn’t bring any tokens, the second output brings the minted SLP, the third specifies the minting baton and the last one sends BCH change to the user.
Then we simply sign it:
And broadcast it to the network:
The transaction’s id (
txidStr) will become the new token’s id. The full code can be found here.
4. Send SLP tokens to the second account
The process is quite similar to creating the genesis transaction. But this time, we should distinguish BCH and SLP utxo and use them separately:
We use both the smallest suitable BCH utxo and all SLP token utxo as inputs:
We generate op_return script with updated token data and place in ScriptPubKey of the first output. The next output is sent to SLP token recipient so that they can spend it, the third one belongs to sender and contains his SLP change( if it is needed) and the last one carries the BCH change.
And in the end, we need to sign all the inputs:
The full code can be found here.
Congrats! It was just a warm-up and now we are ready for the real job.
Shake it, boy
At this point in time, the key steps of the transaction lifecycle should be clear. If you skip the previous section it would be better to have a quick look at it before.
We can split the process of making coinJoin on 3 steps:
- preparing transaction body;
- signing by each participant;
Let’s look at each step separately.
1. Prepare transaction body
All participants should provide their inputs and desirable outputs. For every sender we collect
tokenUtxo , add one BCH utxo to pay fees and all SLP utxo related to sent SLP token(similar to what we have done in the genesis and send transactions).
According to the SLP specification, the outputs order matters. The first output should be op_return script, the next 1-19 outputs can be used for SLP tokens transaction and all others can be used for other purposes. That why we can’t add outputs during the iteration and mix op_return scripts, slp transfers and bch changes rather collect them and add after.
"@psf/bch-js” package doesn’t support the creation of op_return scripts that send tokens to more than one address(+ change transfer) that’s why we implement it manually:
Eventually, all the outputs can be added in the proper order: op_return script, SLP transfers to recipients, SLP changes. BCH changes.
2. Sign transaction
Every user signs their inputs:
Nothing new about it. When the transaction is ready it’s time to notify the network:
That’s it: coins are mixed and only senders are sure about the real sender-receiver pairs. Cocktail is ready, cheers!
Check out the full code here.
Let’s the party begin
If the home-made cocktails are not for you, come into our bar and taste our specialty SLP Cocktail. WebRTC, used to match peers and maintain their communication, is our secret ingredient, simplicity and pretty UI are the most demanded desserts in our menu tonight. Join us!