Explore MultiChain’s low level interface for building transactions

As an alternative to high-level APIs such as send, issue, publish, create, grant and revoke, MultiChain’s raw transaction APIs provide more control over the creation and signing of blockchain transactions. There are several possible reasons for using raw transactions:

  • Control which unspent transaction outputs are used as inputs for a new transaction, instead of using MultiChain’s “coin selection” algorithm.
  • Send or issue assets to multiple recipients, create and publish to streams, and/or perform complex permission changes in a single transaction.
  • Store private keys and sign transactions outside MultiChain’s wallet, for example using a hardware device or “cold storage”. MultiChain transactions can be signed using any bitcoin-compatible device or library which doesn’t choke on OP_DROP and OP_RETURN metadata.

These MultiChain APIs are backward compatible with Bitcoin Core’s raw transaction APIs, while offering significant additional functionality. Some of this functionality is related to MultiChain’s native assets, data streams and permissions, but there are also new calls like appendrawchange and appendrawdata which can be useful for bitcoin-style blockchains.

The examples below assume that you already have a MultiChain blockchain up and running on at least one node, that it is not using a native currency (as per the defaults), and that your node has at least one address with admin, issue and create permissions. If you don’t have this available, follow the instructions in section 1 of the Getting Started guide and then run multichain-cli chain1 to enter interactive mode for your chain.

Sending assets

First let’s identify an address that can be used for issuing assets:

listpermissions issue

Copy and paste the displayed address here:

(If multiple addresses are displayed, use the getaddresses true command to see which addresses belong to the local wallet.)

Now let’s create two assets to be used for sending in transactions:

issue asset3 100 0.1
issue asset4 100 0.1

Now let’s create two new addresses for receiving these assets:

getnewaddress
getnewaddress

Copy and paste the first displayed address here:
Copy and paste the second displayed address here:

Now let’s grant these addresses receive and send permissions:

grant , receive,send

Now we’re going to send some of the newly created assets from the current holding address to these two addresses, along with some metadata:

createrawsendfrom '{"":{"asset3":20,"asset4":30},"":{"asset3":30,"asset4":20}}' '["5554584f732046545721"]' send

The output from this command should contain a regular looking transaction ID. You can now check the transfer was successful by checking the balances of the three addresses for the two new assets, which should be (50 and 50), (20 and 30) and (30 and 20) respectively:

getaddressbalances 0
getaddressbalances 0
getaddressbalances 0

In addition you can view the metadata within the transaction by retrieving it from the wallet and looking in the data element:

listwallettransactions 1

Issuing assets

Let’s begin by identifying an address that can be used for issuing assets:

listpermissions issue

Copy and paste the displayed address here:

(If multiple addresses are displayed, use the getaddresses true command to see which addresses belong to the local wallet.)

Now let’s create two new addresses for receiving these assets:

getnewaddress
getnewaddress

Copy and paste the first displayed address here:
Copy and paste the second displayed address here:

Now let’s grant these addresses receive and send permissions:

grant , receive,send

Now let’s create a transaction which issues a new asset using the appropriate address to these two new addresses, and includes information about the asset:

createrawsendfrom '{"":{"issue":{"raw":2000}},"":{"issue":{"raw":3000}}}' '[{"create":"asset","name":"asset8","multiple":10,"open":true,"details":{"origin":"uk","stage":"one"}}]' send

The output from this command should contain a regular looking transaction ID. You can now check the issuance was successful by getting information about the new asset created:

listassets asset8

In addition you can check that the two addresses received 200 and 300 units respectively:

getaddressbalances 0
getaddressbalances 0

Now we can perform a second issuance of the same asset, since it was created as open:

createrawsendfrom '{"":{"issuemore":{"asset":"asset8","raw":500}},"":{"issuemore":{"asset":"asset8","raw":500}}}' '[{"update":"asset8","details":{"origin":"us","stage":"two"}}]' send

The output from this command should contain a regular looking transaction ID. You can now check the issuance was successful by getting the full information about this asset:

listassets asset8 true

In addition you can check that the two addresses received an additional 50 units each:

getaddressbalances 0
getaddressbalances 0

Publishing to streams

Let’s begin by identifying an address that can be used for creating streams:

listpermissions create

Copy and paste the displayed address here:

(If multiple addresses are displayed, use the getaddresses true command to see which addresses belong to the local wallet.)

First let’s create two open streams and then subscribe to them:

createfrom stream stream3 true
createfrom stream stream4 true
subscribe '["stream3","stream4"]'

Now let’s send a single transaction that sends no assets but publishes two stream items simultaneously from the same address:

createrawsendfrom '{}' '[{"for":"stream3","key":"key1","data":"4f6e65206974656d"},{"for":"stream4","key":"key2","data":"416e6f74686572206974656d"}]' send

You should now be able to see the published items:

liststreamitems stream3
liststreamitems stream4

Creating streams and managing stream permissions

We begin by finding an address that has the create permissions required for creating streams:

listpermissions create

Copy and paste the displayed address here:

(If multiple addresses are displayed, use the getaddresses true command to see which addresses belong to the local wallet.)

Now let’s create the stream using data in a raw transaction with no other outputs:

createrawsendfrom '{}' '[{"create":"stream","name":"stream8","open":false,"details":{"geo":"japan","origin":"BoJ"}}]' send

A transaction ID should be output, and the stream should also now be visible:

liststreams stream8
listpermissions stream8.*

Note that the address which created the stream has admin, activate and write permissions. Now we’ll add write permissions for a new address to this stream. First, generate the new address:

getnewaddress

Copy and paste the displayed address here:

Now let’s grant stream write permissions for this address by sending a raw transaction:

createrawsendfrom '{"":{"permissions":{"for":"stream8","type":"write"}}}' '[]' send

A transaction ID should be output, and the new permission should now be visible:

listpermissions stream8.*
listpermissions stream8.write

Managing global permissions

Let’s begin by identifying an address that has the admin permissions required for changing the permissions of other addresses:

listpermissions admin

Copy and paste the displayed address here:

(If multiple addresses are displayed, use the getaddresses true command to see which addresses belong to the local wallet.)

Now let’s create two new addresses for receiving permissions changes:

getnewaddress
getnewaddress

Copy and paste the first displayed address here:
Copy and paste the second displayed address here:

Now let’s send a raw transaction which grants permanent connect and receive permissions to the first address, and temporary connect-only permissions to the second address:

createrawsendfrom '{"":{"permissions":{"type":"connect,receive"}},"":{"permissions":{"type":"connect","startblock":0,"endblock":10000}}}' '[]' send

The output from this command should contain a regular looking transaction ID. You can now check the permissions grant was successful:

listpermissions all ,

Now let’s send a raw transaction which revokes the receive permission that had been given to the first address, and grant it a send permission instead. Note that a permission is revoked by “granting” it with a startblock and endblock of 0:

createrawsendfrom '{"":{"permissions":{"type":"receive","startblock":0,"endblock":0}},"":{"permissions":{"type":"send"}}}' '[]' send

The output from this command should contain a regular looking transaction ID. You can now check the permissions change was successful:

listpermissions all