mainnet.cash - SLP wallet
Hey guys, in the previous article we have created our own in-browser bitcoin cash wallet using the mainnet.cash library. Today we will add the Simple Ledger Protocol (SLP) support to it. https://read.cash/@pat/mainnetcash-getting-started-a75b2fc6 SLP tokens in BCH are similar to ERC-20 tokens in Ethereum. These can be treated as valuable bits of information - very similar to Bitcoin Cash itself - floating on top of the blockchain, forming its second layer. If you are interested in what the SLP tokens are and how exactly do they work, consider visiting the https://simpleledger.cash and http://slp.dev. So let's start programming right away and duplicae the UI we have created for BCH and rename the HTML element ids and titles to have `slp` in their names, so we have no ambiguity. The result is this snippet, placed right after the BCH wallet's closing `div`: <div style="margin: 30px; flex: 50%;"> <h1>Simple ledger tokens</h1> <div>Wallet balance: <span id="slpBalance"></span></div> <div>Wallet balance USD: <span id="slpBalanceUSD"></span></div> <div>Deposit address: <span id="slpDepositAddr"></span></div> <div>Deposit QR: <img id="slpDepositQr"/></div> <div> <button type="button" id="getSlp">Get testnet slp tokens</button> </div> <div> Send to slp address <input id="slpSendAddr"></input> <input type="button" id="slpSend" value="Send SLP"></input> <input type="button" id="slpSendMax" value="Send All SLP Tokens"></input> </div> </div>
Now let's render the missing information in our SLP wallet by calling its SLP functions. For this we need to declare the `tokenId` of the token we will be working with. const tokenId = "132731d90ac4c88a79d55eae2ad92709b415de886329e958cf35fdd81ba34c15"; `tokenId` is a 64 character long string. In fact it is a transaction hash in which the token first *appeared* on the blockchain. The `tokenId = "1327..."` you see here is the `tokenId` of our `Mainnet coin` which we created for testing purposes beforehand. Working with SLP tokens requires precise knowledge of the token id. Knowing the token name `Mainnet coin` or its ticker `MNC` is not enough, since anyone can create a token with the same name and ticker and fool us about its identity. Now let’s duplicate the code in the `run()` function and start adapting it. First let's get the token balance of our wallet and update the UI: const slpBalance = await wallet.slp.getBalance(tokenId); document.querySelector('#slpBalance').innerText = `${slpBalance.value} ${slpBalance.ticker}`; document.querySelector('#slpBalanceUSD').innerText = `???`; This code looks familiar, doesn’t it? We access all the functions of an SLP wallet with a `wallet.slp` accessor. We have designed both wallet interfaces to be as close as it can get. Most notable difference is that you have to supply the `tokenId` everywhere in the function calls. Note, that we do not know the USD-MNC conversion rate, hence the `???` USD value. Watching the balance is similar to the BCH code: wallet.slp.watchBalance((slpBalance) => { document.querySelector('#slpBalance').innerText = `${slpBalance.value} ${slpBalance.ticker}`; document.querySelector('#slpBalanceUSD').innerText = `???`; }, tokenId); Let's now get the deposit address and deposit QR Code in the SLP format with the `slptest:` prefix (`simpleledger:` on the main network): const slpAddr = await wallet.slp.getDepositAddress(); document.querySelector('#slpDepositAddr').innerText = slpAddr; const slpQr = await wallet.slp.getDepositQr(); document.querySelector('#slpDepositQr').src = slpQr.src;
This is how the UI of our SLP wallet looks like now. Very similar to that of the BCH wallet. Now lets animate the last three buttons remaining: "Get testnet slp tokens", "Send SLP" and "Send All SLP Tokens". Getting the testnet `Mainnet coin` tokens from the faucet is very similar to BCH: document.querySelector('#getSlp').addEventListener("click", async () => { await wallet.getTestnetSlp(tokenId); }); Sending the tokens requires the knowledge of an SLP address of your counterparty and the `tokenId` which you want to send. // send some document.querySelector('#slpSend').addEventListener("click", async () => { const addr = document.querySelector('#slpSendAddr').value; await wallet.slp.send([{slpaddr: addr, value: 1, tokenId: tokenId}]); alert('Sent 1 slp to ' + addr); }); // send all document.querySelector('#slpSendMax').addEventListener("click", async () => { const addr = document.querySelector('#slpSendAddr').value; await wallet.slp.sendMax(addr); alert('Sent all slp funds to ' + addr); }); *Important notice:* getting the tokens from the faucet does not cost you anything. But the tokens will turn to be a dead weight if you don't have any spare BCH in your wallet. This marginal amount of BCH is required to pay the miners to move your tokens: compare to the Ethereum gas. So before trying to move the tokens, ensure you have claimed some BCH into your wallet too! Our resulting UI will look like this after claiming from both faucets and moving the tokens:
Note that our BCH balance is down by about 1000 sats. This is about ~4x larger than your usual transaction fee. Reason for that lays in fact that SLP transactions require a special non-monetary output which contains the information about the token movements. But don't be worried about all these complex matters - mainnet.cash library takes care of building these outputs and ensuring that your tokens will not get burned. This concludes our second tutorial article. Next time we will port our wallets to use the mainnet.cash REST server which will do the weightlifting for us, making our web page leaner. Be sure to check out our **web site** and **library documentation**. You can ask any questions in our **telegram group**. The source code of this tutorial is available on github. https://mainnet.cash https://mainnet.cash/tutorial/ https://github.com/mainnet-cash/mainnet-tutorial/blob/master/3.tutorial.slp.html Cheers, pat for mainnet.cash team.
8 comments
Hey pat, you are giving really important info about mainnetcash. I think it's a bit complex to me but I'll check you posts when I need to use it ^^
Sorry to hear it is complex to digest. I've tried to use no dependencies and use only basic things in this tutorial. How can we improve in your opinion?
You explained perfectly dear but the whole proceess is a bit complex. People should spend some time to comprehend it :)
Sono informazioni molto importanti ma un po' complessa però
Nice thanks
Today I tested sending and receiving SLP. It works well. I have many tokens on the memo wallet that I cannot send (e.g. BCH tokens or MIS tokens). I get an error message in memo. I tried to send BCH tokens with mainnet.cash. Something amazing happened. Instead of BCH tokens, WSB tokens were sent. Then I tried the same thing with MIS tokens. The same thing happened. WSB tokens were sent.
Very interesting! Can you elaborate on it in an issue over here https://github.com/mainnet-cash/mainnet-js/issues ? Also, I have discovered an issue with nft tokens today, so try to avoid sending them with the lib.
I will do it. I've noticed my BCH token and MIS token are burned.