Group Tokens CLI Example
login

Group Tokens CLI Example

Token functions are available via the “token” RPC command. Use

./bitcoin-cli help token

to get the following summary of available operations.


Token functions.
'new' creates a new token type. args: authorityAddress
'mint' creates new tokens. args: groupId address quantity
'melt' removes tokens from circulation. args: groupId quantity
'balance' reports quantity of this token. args: groupId [address]
'send' sends tokens to a new address. args: groupId address quantity [address quantity...]
'authority create' creates a new authority args: groupId address [mint melt nochild rescript]
'subgroup' translates a group and additional data into a subgroup identifier. args: groupId data

Arguments:
1. "groupId"     (string, required) the group identifier
2. "address"     (string, required) the destination address
3. "quantity"    (numeric, required) the quantity desired
4. "data"        (number, 0xhex, or string) binary data

You will notice throughout this example that this wallet is lacking in UX (user experience) features. For example, the group identifier is always used, rather than a human-understandable abbreviation (e.g. USDT). This kind of wallet-level feature is entirely possible with Group Tokens. However, I feel that the days where end-users use full node wallets is pretty much over, so for development efficiency I have not added UX features to this wallet.

Group Genesis

To create a new group, we need to first get an address that will hold the genesis authority:

$ ./bitcoin-cli getnewaddress
xnex:qpl4h9ll46qazxalefcvw2yag275px2u3vqxnvf629

Now let’s create a new group!

$ ./bitcoin-cli token new xnex:qpl4h9ll46qazxalefcvw2yag275px2u3vqxnvf629
{
  "groupIdentifier": "xnex:zv592wzzruave7ywtq4ah7w7zvr0mckn8de8dalfhq5n8j5u6gqqqh9me09rd",
  "transaction": "846f4372f4a96239d9d259c2edd819b6b2e2fd1728b3ae839a1caf8f25548fe2"
}

You can examine the resulting transaction on the blockchain here. For this and all subsequent references to the blockchain explorer, please look in the “scripts” and “JSON” tabs since these tabs present the transaction in greater detail.

You will see a transaction with a BCH input and change output, and the following “grouped” output:

285538421f3accf88e582bdbf9de1306fde2d33b7276f7e9b82933ca9cd20000 ee420000000000fc OP_GROUP
OP_DUP OP_HASH160 7f5b97ffae81d11bbfca70c7289d42bd40995c8b OP_EQUALVERIFY OP_CHECKSIG

You can see the grouped prefix " OP_GROUP" and the normal P2PKH constraint “OP_DUP…”

Token Mint

Now lets us create some tokens in that group. First we need a new address to hold those tokens:

$ ./bitcoin-cli getnewaddress
xnex:qqwmhn0vsl4zj4l6wehvrlz8mlvwz5kr9cuks8m6l7

Now, let us mint some tokens! We will pass the group identifier, the destination address, and the number of tokens to mint. This wallet will automatically find and spend the genesis authority, and will create a new child authority so that we do not lose any abilities.

$ ./bitcoin-cli token mint xnex:zv592wzzruave7ywtq4ah7w7zvr0mckn8de8dalfhq5n8j5u6gqqqh9me09rd xnex:qqwmhn0vsl4zj4l6wehvrlz8mlvwz5kr9cuks8m6l7 1000
be49d1c33a19a43a296477bc041e0d9d5eb7d048aab9a924ea78d164bc556630

The resulting transaction can be examined here.

The first input spends a group authority (in this case the genesis authority) and a new authority UTXO is created as the second output:

285538421f3accf88e582bdbf9de1306fde2d33b7276f7e9b82933ca9cd20000 00000000000000fc OP_GROUP 
OP_DUP OP_HASH160 6fe7ed25153d7eee43e2eb747e3ac35e8ad5f276 OP_EQUALVERIFY OP_CHECKSIG

As with the Genesis transaction this output comprises the group prefix and a normal p2pkh suffix.
You can quickly see that this is an authority because second data item (the “quantity or flags” field) has its most significant little endian bit set (recall that the last byte, 0xfc, is the MSB in little endian format).

The first output is the result of the mint operation. Please view it in the JSON tab:

            "value": 0.00000546,
            "n": 0,
            "scriptPubKey": {
                "asm": "285538421f3accf88e582bdbf9de1306fde2d33b7276f7e9b82933ca9cd20000 1000 OP_GROUP OP_DUP OP_HASH160 1dbbcdec87ea2957fa766ec1fc47dfd8e152c32e OP_EQUALVERIFY OP_CHECKSIG",
                ...

You can see in the group prefix of the scriptPubKey field that the quantity minted is 1000 tokens. Note that this output is also carrying 546 satoshis of BCH. This is the BCH “dust” limit. Any grouped output must not only pay transaction fees but also must meet the minimum quantity of BCH allowed in a UTXO. This is a spam-prevention measure, and also encourages valueless tokens to be consolidated and melted to recover their residual BCH. Every grouped output, whether it be a genesis, authority or regular token holder MUST meet the minimum BCH dust limit, but for brevity I will not call further attention to this feature.

Token Balance

We can now ask the wallet for our balance in tokens.

$ ./bitcoin-cli token balance xnex:zv592wzzruave7ywtq4ah7w7zvr0mckn8de8dalfhq5n8j5u6gqqqh9me09rd xnex:qqwmhn0vsl4zj4l6wehvrlz8mlvwz5kr9cuks8m6l7
1000

This showed the balance on the passed address (2nd parameter). To find the total token balance across all wallet addresses, do not pass the address.

Since this is a read-only operation on wallet, there is no corresponding activity to show in the explorer.

Sending Tokens

First let’s create yet-another unique address to receive the tokens (of course, we can reuse addresses if desired, but let’s follow best practices here).

./bitcoin-cli getnewaddress
xnex:qz0dvvfmudmls6lz0ptatt74y0ym5a55ay46he9alm

Now let’s perform a send!

$ ./bitcoin-cli token send xnex:zv592wzzruave7ywtq4ah7w7zvr0mckn8de8dalfhq5n8j5u6gqqqh9me09rd xnex:qz0dvvfmudmls6lz0ptatt74y0ym5a55ay46he9alm 100
8a35dd4b1751e37c94d0d53959104710c3d9a3edf6bc90eda075ca23b7961b56

In the explorer this operation looks like this.

Note that we had to spend some BCH (input 1) and produced change (output 2). We needed some BCH to pay for the transaction fee! You may point out that it is inefficient to spend a BCH input and create a change output just to cover the transaction fee for a token transaction. I think that’s debatable. Its like telling a store that its inefficient and time consuming to buy a $1 stick of gum so they ought to give them away for free. In other words, THAT’s the part of the transaction that is most important to the miners.

However, there is another option (which this wallet does not implement). Earlier we discussed how every grouped UTXO must also carry a minimum BCH “dust”. But a grouped UTXO MAY carry more BCH than the minimum dust. Let’s say we had previously loaded input 0 with 2000 satoshis and 1000 tokens, rather than 547 satoshis and 1000 tokens. In that case, BCH fees (and the BCH dust for new grouped UTXOs) could be extracted from the spent grouped UTXO. Of course, if you send someone tokens with a lot of extra BCH, you are giving them free money. So there will be some balance between convenience and cost.

Moving away from the BCH, note that we spent a single grouped input (0 – no authority needed to transfer) to 2 grouped outputs (0 and 1). Looking at those outputs, you can see that we paid 100 tokens to our destination address and paid 900 tokens to ourselves in change:

#0
285538421f3accf88e582bdbf9de1306fde2d33b7276f7e9b82933ca9cd20000 100 OP_GROUP
OP_DUP OP_HASH160 9ed6313be377f86be27857d5afd523c9ba7694e9 OP_EQUALVERIFY OP_CHECKSIG

#1
285538421f3accf88e582bdbf9de1306fde2d33b7276f7e9b82933ca9cd20000 900 OP_GROUP
OP_DUP OP_HASH160 4b63077af6c60e516ce242097f0e05a80b451375 OP_EQUALVERIFY OP_CHECKSIG

This RPC call sent 1 group (type) of tokens to 1 destination, with change. Although this wallet’s simple command line API does not allow complex behavior to be specified, rest assured that with Group Tokenization it is possible to split and consolidate token UTXOs, to send tokens from multiple groups to multiple destinations in the same transaction, to contain both BCH and multi-group token sends, and to locate the various UTXOs that accomplish this at any output index. This versatility of functionality is essential for smart contract operations. To take a baby step down that road, note that a transaction that moves multiple tokens and BCH simultaneously may constitute an atomic exchange of the involved items between multiple people. The ease with which this is accomplished hints at the power of the native tokenization architecture underlying Group Tokens.

Authority Creation

We already have an authority that can execute all group functions, so we can split that to create a melt only authority at the address xnex:qqzl8sr6kzfylmfy4ytaj3ecnldjhfrpny4gjkvg7y as follows:

$ ./bitcoin-cli token authority create xnex:zv592wzzruave7ywtq4ah7w7zvr0mckn8de8dalfhq5n8j5u6gqqqh9me09rd xnex:qqzl8sr6kzfylmfy4ytaj3ecnldjhfrpny4gjkvg7y melt
744285838d6cc98058ed536010271644aee5b43f5cb3b009f633e59eed9c7b38

Again in the explorer it look like this.

Note the two authority outputs that were created. The first recreates our original authority for future use. The second is the new melt-only authority.

#0
285538421f3accf88e582bdbf9de1306fde2d33b7276f7e9b82933ca9cd20000 00000000000000fc OP_GROUP
OP_DUP OP_HASH160 e2852723bf31365305d3c83bfeefd23c81d9918b OP_EQUALVERIFY OP_CHECKSIG
#1
285538421f3accf88e582bdbf9de1306fde2d33b7276f7e9b82933ca9cd20000 00000000000000b0 OP_GROUP
OP_DUP OP_HASH160 05f3c07ab0924fed24a917d947389fdb2ba46199 OP_EQUALVERIFY OP_CHECKSIG

Authority bits 0xb0 is binary b1011,0000 or the AUTHORITY, MELT, and BATON bits set. So this output is an authority that can melt tokens and create additional melt authorities.

Melting Tokens

Ok lets melt!

The operation:

./bitcoin-cli token melt xnex:zv592wzzruave7ywtq4ah7w7zvr0mckn8de8dalfhq5n8j5u6gqqqh9me09rd 500
fc5ea9e22347bfc8d75f8dcb6d881afeb6c4e7fc833eadd7bd340419c06347e8

looks like this.

By clicking input 2 to see the parent transaction, you can see that the wallet chose to spend the full authority (0xfc) UTXO rather than the melt-only one we previously created (this wallet was implemented to just choose the first authority that fulfills the required function).

You can also see that it spent both the 100 token UTXO (input 0) and then the 900 token UTXO (input 1), without realizing that it could have ignored the 100 token input and just used the 900.

So, this wallet’s UTXO selection code could be optimized, both for authorities and token quantities. But regardless of that inefficiency, note that the output only consists of 500 tokens. The melt worked.

Running a quick balance returns the correct value:

$ ./bitcoin-cli token balance xnex:zv592wzzruave7ywtq4ah7w7zvr0mckn8de8dalfhq5n8j5u6gqqqh9me09rd
500

Fin

This article covered the basic RPC and CLI token wallet operations in the Bitcoin Unlimited NextChain branch of bitcoind. I hope it gives you a sense of how Group tokenization works in practice and how these operations turn into simple-to-understand transactions.