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.

The first set of examples shows how to build and send complex transactions in a single step, using the new createrawsendfrom API introduced in MultiChain 1.0 alpha 26. The second set uses a more traditional approach, building up the raw transactions stage-by-stage. While the second set is slower, it provides deeper insight into the structure of MultiChain transactions. In either case, after entering an API command in multichain-cli, you can see the exact form of the JSON-RPC request in the first line of the response.

One-step raw transactions (1.0 alpha 26 or later)

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}}}' '[{"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}}}' '[{"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

Stage-by-stage raw transactions

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 asset5 100 0.1
issue asset6 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 build a raw transaction which sends some of the newly created assets from the current holding address to these two addresses, along with some metadata. First let’s list the unspent outputs belonging to the holding address:

listunspent 0 9999 '[""]'

Look down this list for a transaction output containing 100 units of asset5 within its assets element. This is the first output we will spend.

Copy and paste the txid for asset5:
Copy and paste the vout for asset5:

Now look down that same list for a second transaction output containing 100 units of asset6. This is the second one we will spend.

Copy and paste the txid for asset6:
Copy and paste the vout for asset6:

You can verify these transaction outputs’ contents by calling:

gettxout
gettxout

Now let’s start building the raw transaction to send 20 units of asset5 and 30 units of asset6 to the first new address, and the reversed quantities to the second new address:

createrawtransaction '[{"txid":"","vout":},{"txid":"","vout":}]' '{"":{"asset5":20,"asset6":30},"":{"asset5":30,"asset6":20}}'

This should output a large hexadecimal blob, which contains the raw created transaction. You can view this transaction’s contents using:

decoderawtransaction [paste-hex-blob]

The vin array of the output shows the two inputs being spent, and the vout array shows the two outputs including their assets. However this transaction is not yet ready for signing, because its input contains 100 units of each issued asset, whereas its outputs only contain 50 units of each asset so far. Transactions which have unbalanced asset quantities between their inputs and outputs are not valid, so we need add a change output which returns the remaining units to the sender:

appendrawchange [paste-hex-blob]

This should output a longer hexadecimal blob, to which we’ll now add some metadata:

appendrawdata [paste-longer-hex-blob] 5554584f732046545721

This should output an even longer hex blob, which can be decoded using:

decoderawtransaction [paste-even-longer-hex-blob]

You should now see three elements in the vout array as well as a data field showing the metadata.

Now we can finally sign this transaction:

signrawtransaction [paste-even-longer-hex-blob]

The output should contain our final transaction in a yet even longer hexadecimal blob of text, alongside another field complete whose value is true. The signed transaction can be transmitted to the network:

sendrawtransaction [paste-final-hex-blob]

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 prepare an unspent transaction output for the issuing address, containing no assets. This will be used as the input for the issuance transaction, to provide proof that the issuance was authorized by an address with issue permissions:

preparelockunspentfrom 0

Copy and paste the txid displayed:
Copy and paste the vout displayed:

Now we’re going to prepare a raw transaction which creates a new asset and immediately sends units to the two new addresses:

createrawtransaction '[{"txid":"","vout":}]' '{"":{"issue":{"raw":2000}},"":{"issue":{"raw":3000}}}'

This should output a hexadecimal blob of data containing a raw transaction to issue 2000 raw units of the asset to the first address, and 3000 raw units to the second address. Now we need to add metadata to this transaction to give more information about the issuance, including the name asset7, the ratio of 10 raw units per display unit, the fact that it is open for further issuances, and other custom fields:

appendrawdata [paste-hex-blob] '{"name":"asset7","multiple":10,"open":true,"details":{"origin":"uk","stage":"one"}}'

This should output an longer hex blob, which we can now examine:

decoderawtransaction [paste-longer-hex-blob]

You should see three outputs – two containing the asset quantity to be issued and one with the metadata representing the asset details. Now we can sign this transaction:

signrawtransaction [paste-longer-hex-blob]

The output should contain our final transaction in a longer hexadecimal blob of text, alongside another field complete whose value is true. The signed transaction can be transmitted to the network:

sendrawtransaction [paste-final-hex-blob]

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 asset7

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. First, we prepare another input:

preparelockunspentfrom 0

Copy and paste the txid displayed:
Copy and paste the vout displayed:

Now we’re going to prepare a raw transaction which represents a follow-on issuance to the same two addresses:

createrawtransaction '[{"txid":"","vout":}]' '{"":{"issuemore":{"asset":"asset7","raw":500}},"":{"issuemore":{"asset":"asset7","raw":500}}}'

This should output a hexadecimal blob of data containing a raw transaction to issue 500 raw units of the asset to each of the two addresses. Now we need to add metadata to this transaction to add some custom fields to the follow-on issuance:

appendrawdata [paste-hex-blob] '{"details":{"origin":"us","stage":"two"}}'

This should output an longer hex blob, which we can now examine:

decoderawtransaction [paste-longer-hex-blob]

You should see three outputs – two containing the additional asset quantity to be issued and one with the metadata representing the details of the new issuance. Now we can sign this transaction:

signrawtransaction [paste-longer-hex-blob]

The output should contain our final transaction in a longer hexadecimal blob of text, alongside another field complete whose value is true. The signed transaction can be transmitted to the network:

sendrawtransaction [paste-final-hex-blob]

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 asset7 true

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

getaddressbalances 0
getaddressbalances 0

Publishing to streams

First let’s create two open streams (this requires the node to have an address with create permissions) and then subscribe to them:

create stream stream5 true
create stream stream6 true
subscribe stream5
subscribe stream6

Now let’s prepare an unspent transaction output to be used for the publishing transaction, containing no assets:

preparelockunspent 0

Copy and paste the txid displayed:
Copy and paste the vout displayed:

Now we start building a raw transaction which does not need any regular outputs:

createrawtransaction '[{"txid":"","vout":}]' '{}'

This should output a hexadecimal blob, which contains the raw created transaction. Let’s add the first stream item:

appendrawdata [paste-hex-blob] '{"for":"stream5","key":"key1","data":"4f6e65206974656d"}'

This should output a longer hexadecimal blob, to which we’ll add the item for the second stream:

appendrawdata [paste-longer-hex-blob] '{"for":"stream6","key":"key2","data":"416e6f74686572206974656d"}'

Note that it’s not possible to create multiple items for the same stream in one transaction. Now we can sign this transaction:

signrawtransaction [paste-even-longer-hex-blob]

The output contains the final transaction in an even longer hexadecimal blob, with a field complete whose value should be true. The signed transaction can be broadcast:

sendrawtransaction [paste-final-hex-blob]

You should now be able to see the published items:

liststreamitems stream5
liststreamitems stream6

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 prepare an unspent transaction output to be used for the stream creation, containing no assets:

preparelockunspentfrom 0

Copy and paste the txid displayed:
Copy and paste the vout displayed:

Now we start building a raw transaction which does not need any regular outputs:

createrawtransaction '[{"txid":"","vout":}]' '{}'

This should output a hexadecimal blob, which contains the raw created transaction. Let’s add metadata to create a stream:

appendrawdata [paste-hex-blob] '{"create":"stream","name":"stream7","open":false,"details":{"geo":"japan","origin":"BoJ"}}'

This should output a longer hex blob. Now we can sign this transaction:

signrawtransaction [paste-longer-hex-blob]

The output should contain the final signed transaction in a longer hexadecimal blob, alongside a complete value of true. This signed transaction can be broadcast:

sendrawtransaction [paste-final-hex-blob]

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

liststreams stream7
listpermissions stream7.*

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 prepare an unspent transaction output to be used for the stream permission change, containing no assets:

preparelockunspentfrom 0

Copy and paste the txid displayed:
Copy and paste the vout displayed:

Now we’ll build a raw transaction which grants the permission (see the next section for examples of the optional startblock and endblock parameters):

createrawtransaction '[{"txid":"","vout":}]' '{"":{"permissions":{"for":"stream7","type":"write"}}}'

This should output a hexadecimal blob, which contains the raw transaction for assigning the permissions. We can now sign this transaction:

signrawtransaction [paste-hex-blob]

The output should contain the final signed transaction in a longer hexadecimal blob, with a complete value of true. This signed transaction can be broadcast:

sendrawtransaction [paste-final-hex-blob]

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

listpermissions stream7.*
listpermissions stream7.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 prepare an unspent transaction output for the admin address, containing no assets. This will be used as the input for the permissions transaction, to provide proof that it was authorized by an address with admin permissions:

preparelockunspentfrom 0

Copy and paste the txid displayed:
Copy and paste the vout displayed:

Now we’re going to prepare a raw transaction which grants permanent connect and receive permissions to the first address, and temporary connect-only permissions to the second address:

createrawtransaction '[{"txid":"","vout":}]' '{"":{"permissions":{"type":"connect,receive"}},"":{"permissions":{"type":"connect","startblock":0,"endblock":10000}}}'

This should output a hexadecimal blob containing the raw transaction, which we can now examine:

decoderawtransaction [paste-hex-blob]

You should see two outputs containing the two addresses and the permissions to be assigned to them. Now we can sign this transaction:

signrawtransaction [paste-hex-blob]

The output should contain our final transaction in a longer hexadecimal blob of text, alongside another field complete whose value is true. The signed transaction can be transmitted to the network:

sendrawtransaction [paste-final-hex-blob]

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 revoke the receive permission that had been given to the first address, and grant it a send permission instead. First, let’s prepare another unspent transaction output for the admin address:

preparelockunspentfrom 0

Copy and paste the txid displayed:
Copy and paste the vout displayed:

Now we’re going to prepare a raw transaction which both revokes and grants the appropriate permissions. Note that a permission is revoked by “granting” it with a startblock and endblock of 0:

createrawtransaction '[{"txid":"","vout":}]' '{"":{"permissions":{"type":"receive","startblock":0,"endblock":0}},"":{"permissions":{"type":"send"}}}'

This should output a hexadecimal blob containing the raw transaction, which we can now examine:

decoderawtransaction [paste-hex-blob]

You should see two outputs containing the permissions assignments. Now we can sign this transaction:

signrawtransaction [paste-hex-blob]

The output should contain our final transaction in a longer hexadecimal blob of text, alongside another field complete whose value is true. The signed transaction can be transmitted to the network:

sendrawtransaction [paste-final-hex-blob]

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

listpermissions all