How to send a transaction to the network

Default transactions

The default modules already come with a set of default transactions out of the box, which can be sent to the blockchain application without writing any custom code.

Each transaction type is defined in a module. For more information about the different modules and their transaction assets, check out the respective module references:

Transaction formats

A transaction can be represented in different formats.

Below is an overview of all existing transaction formats and their use cases.

Buffer

The representation of the transaction binary data as a Buffer.

This format is used for applications-internal processes.

<Buffer 08 02 10 00 18 04 20 c0 84 3d 2a 20 51 33 af 79 44 ac f5 27 8b 03 10 a1 1c 06 13 4f 80 ab 45 46 d7 7d 1b 0e 02 7c 84 30 a7 d2 bb 92 32 2d 08 80 90 bc ... 107 more bytes>

Hex string

This is the hex string representation of the Buffer data.

It is sometimes used as an input or output format in the CLI when sending or creating transactions via the CLI (see Application CLI and Command line interface).

'08021000180420c0843d2a205133af7944acf5278b0310a11c06134f80ab4546d77d1b0e027c8430a7d2bb92322d088090bcfd0212149bd82e637d306533b1e1ad66e19ca0047faa1a6a1a0f4861707079206269727468646179213a4098a9ee2cde8354d014cfe6367d430be2713e102f37d92ab91f03db780407e5bf6d818a45c21c9f5518638dfc3c5365fc2d497b928e0b9d6337988df46a663a02'

Decoded object

The decoded transaction object.

Used as an input / output format for functions in Lisk Elements, for example the API client.

{
  moduleID: 2,
  assetID: 0,
  nonce: 4n,
  fee: 1000000n,
  senderPublicKey: <Buffer 51 33 af 79 44 ac f5 27 8b 03 10 a1 1c 06 13 4f 80 ab 45 46 d7 7d 1b 0e 02 7c 84 30 a7 d2 bb 92>,
  asset: {
    amount: 800000000n,
    recipientAddress: <Buffer 9b d8 2e 63 7d 30 65 33 b1 e1 ad 66 e1 9c a0 04 7f aa 1a 6a>,
    data: 'Happy birthday!'
  },
  signatures: [
    <Buffer 98 a9 ee 2c de 83 54 d0 14 cf e6 36 7d 43 0b e2 71 3e 10 2f 37 d9 2a b9 1f 03 db 78 04 07 e5 bf 6d 81 8a 45 c2 1c 9f 55 18 63 8d fc 3c 53 65 fc 2d 49 ... 14 more bytes>
  ],
  id: <Buffer 17 a0 90 44 15 f7 ad 9a 0e 30 5a e8 a4 34 53 24 3a 84 e2 af e1 76 08 3a 0a b3 3f b1 2e 3b bc 25>
}

JSON compatible object

A representation of the decoded transaction in a JSON compatible format.

For example, used for displaying the details of a transaction in the UI to the user.

{
  moduleID: 2,
  assetID: 0,
  nonce: '4',
  fee: '1000000',
  senderPublicKey: '5133af7944acf5278b0310a11c06134f80ab4546d77d1b0e027c8430a7d2bb92',
  signatures: [
    '98a9ee2cde8354d014cfe6367d430be2713e102f37d92ab91f03db780407e5bf6d818a45c21c9f5518638dfc3c5365fc2d497b928e0b9d6337988df46a663a02'
  ],
  asset: {
    amount: '800000000',
    recipientAddress: '9bd82e637d306533b1e1ad66e19ca0047faa1a6a',
    data: 'Happy birthday!'
  },
  id: '17a0904415f7ad9a0e305ae8a43453243a84e2afe176083a0ab33fb12e3bbc25'
}

How to create a transaction

For convenience, it is recommended to use the API client or the CLI to communicate to a node for creating and signing transactions.

In the case whereby a higher level of security is desired, it is possible to create the transaction in a completely stand-alone offline environment. Please check out the guide Creating transactions and signing them offline for more information.

Transaction properties

The properties of a transaction are described in detail in the Lisk Protocol on the Transactions page.

via API client

The API client allows connecting to a particular node API, and enables to get and post data to the node. It is part of the lisk-api-client package and is also included in the lisk-client and lisk-sdk packages.

An example script how to create a transaction object via the API client is described in the code snippet below:

const { apiClient, cryptography, transactions } = require('@liskhq/lisk-client');
const RPC_ENDPOINT = 'ws://localhost:8080/ws';

let clientCache;

// Replace with the recipient address
const recipientAddress = "lskt8ovj2shbxrtno8xqqt7cnmzzygdkbt6brnvmj";
// Replace with the sender passphrase
const passphrase = "12 word mnemonic passphrase of an account with sufficient balance"

const getClient = async () => {
    if (!clientCache) {
        clientCache = await apiClient.createWSClient(RPC_ENDPOINT);
    }
    return clientCache;
};

getClient().then(async (client) => {
  const address = cryptography.getAddressFromBase32Address(recipientAddress);
  const tx = await client.transaction.create({
    moduleID: 2,
    assetID: 0,
    fee: BigInt(transactions.convertLSKToBeddows('0.01')),
    asset: {
        amount: BigInt(transactions.convertLSKToBeddows('8')),
        recipientAddress: address,
        data: 'Happy birthday!'
    }
  }, passphrase);


  console.log("Transaction object: ", tx);
});
Example output
Transaction object
{
  moduleID: 2,
  assetID: 0,
  fee: 1000000n,
  asset: {
    amount: 800000000n,
    recipientAddress: <Buffer 9b d8 2e 63 7d 30 65 33 b1 e1 ad 66 e1 9c a0 04 7f aa 1a 6a>,
    data: 'Happy birthday!'
  },
  nonce: 4n,
  senderPublicKey: <Buffer 51 33 af 79 44 ac f5 27 8b 03 10 a1 1c 06 13 4f 80 ab 45 46 d7 7d 1b 0e 02 7c 84 30 a7 d2 bb 92>,
  signatures: [
    <Buffer 98 a9 ee 2c de 83 54 d0 14 cf e6 36 7d 43 0b e2 71 3e 10 2f 37 d9 2a b9 1f 03 db 78 04 07 e5 bf 6d 81 8a 45 c2 1c 9f 55 18 63 8d fc 3c 53 65 fc 2d 49 ... 14 more bytes>
  ],
  id: <Buffer 17 a0 90 44 15 f7 ad 9a 0e 30 5a e8 a4 34 53 24 3a 84 e2 af e1 76 08 3a 0a b3 3f b1 2e 3b bc 25>
}

via CLI

Any running node can be used to create a sendable transaction object, see Application CLI and Command line interface.

An example for creating a transfer transaction with the Lisk Core CLI is displayed below:

$ lisk-core transaction:create 2 0 100000000
? Please enter: amount:  1000000000
? Please enter: recipientAddress:  ab0041a7d3f7b2c290b5b834d46bdc7b7eb85815
? Please enter: data:  send tokens
? Please enter passphrase:  [hidden]
? Please re-enter passphrase:  [hidden]

After all relevant information about the transaction is given, the already encoded transaction object is returned:

Example output
{"transaction":"0802100018022080c2d72f2a20e03c09bdc8c023d94cf66a5d352e6258380210d97d545abbf75668ea3736e3123229088094ebdc031214ab0041a7d3f7b2c290b5b834d46bdc7b7eb858151a0b73656e6420746f6b656e733a40faa2626d7306506b1999f48aa2f4b1ffdee01e641fa76d37a9d1d6fd8c225a81065c856ea625c52d138a7e3ba86b62913dc8e5aef8b5e307641ab66e0277a60b"}

To also see the decoded transaction object on creation, add the --json parameter:

Example
$ lisk-core transaction:create 2 0 100000000 --json --pretty
? Please enter: amount:  1000000000
? Please enter: recipientAddress:  ab0041a7d3f7b2c290b5b834d46bdc7b7eb85815
? Please enter: data:  send tokens
? Please enter passphrase:  [hidden]
? Please re-enter passphrase:  [hidden]
{
  "transaction": "0802100018022080c2d72f2a20e03c09bdc8c023d94cf66a5d352e6258380210d97d545abbf75668ea3736e3123229088094ebdc031214ab0041a7d3f7b2c290b5b834d46bdc7b7eb858151a0b73656e6420746f6b656e733a40faa2626d7306506b1999f48aa2f4b1ffdee01e641fa76d37a9d1d6fd8c225a81065c856ea625c52d138a7e3ba86b62913dc8e5aef8b5e307641ab66e0277a60b"
}
{
  "transaction": {
    "moduleID": 2,
    "assetID": 0,
    "nonce": "2",
    "fee": "100000000",
    "senderPublicKey": "e03c09bdc8c023d94cf66a5d352e6258380210d97d545abbf75668ea3736e312",
    "signatures": [
      "faa2626d7306506b1999f48aa2f4b1ffdee01e641fa76d37a9d1d6fd8c225a81065c856ea625c52d138a7e3ba86b62913dc8e5aef8b5e307641ab66e0277a60b"
    ],
    "asset": {
      "amount": "1000000000",
      "recipientAddress": "ab0041a7d3f7b2c290b5b834d46bdc7b7eb85815",
      "data": "send tokens"
    }
  }
}

How to send the transaction

In case it is desired to have the transaction in a different format before sending, there are functions available to conveniently convert the transaction between the different formats, see Decoding & encoding data for more information.

With Lisk Service

How to send transactions to a Lisk node via Lisk Service.

An existing transaction as hex string can be posted to a Lisk node via the Lisk Service either by using its HTTP or WebSocket APIs.

Via Lisk Service HTTP API

cURL is one of the tools that can be used to send HTTP API requests to Lisk Service:

curl -X POST -H "Content-Type: application/json" \
-d '{"transaction": "0802100018022080c2d72f2a20e03c09bdc8c023d94cf66a5d352e6258380210d97d545abbf75668ea3736e3123229088094ebdc031214ab0041a7d3f7b2c290b5b834d46bdc7b7eb858151a0b73656e6420746f6b656e733a40faa2626d7306506b1999f48aa2f4b1ffdee01e641fa76d37a9d1d6fd8c225a81065c856ea625c52d138a7e3ba86b62913dc8e5aef8b5e307641ab66e0277a60b"}' \
"http://localhost:9901/api/v2/transactions"

For more information, check out the Mainnet HTTP API (Lisk Service) reference.

The following response will be displayed, if the transaction was posted successfully.

{
  "message":"Transaction payload was successfully passed to the network node",
  "transactionId":"8a503843942e7d47ba0bef83fe735d26381f32a6ca6c96fb1cde902315f6220c"
}

Via Lisk Service WebSocket API

If you prefer to use the RPC WebSocket API of Lisk Service to post transactions, this can be achieved for example by writing a small JS script, and using the API client of the socket.io-client package:

// 1. Require the dependencies
const io = require('socket.io-client'); // The socket.io client
const jsome = require('jsome'); // Prettifies the JSON output

jsome.params.colored = true;

// Use local Service node
const WS_RPC_ENDPOINT = 'ws://localhost:9901/rpc-v2';
//Use public Service node
//const WS_RPC_ENDPOINT = "wss://service.lisk.com/rpc-v2";

// 2. Connect to Lisk Service via WebSockets
const socket = io(WS_RPC_ENDPOINT, {
  forceNew: true,
  transports: ['websocket']
});

// 3. Emit the remote procedure call
socket.emit('request', {
  jsonrpc: '2.0',
  method: 'post.transactions',
  payload: {"transaction":"08021000180d2080c2d72f2a200fe9a3f1a21b5530f27f87a414b549e79a940bf24fdf2b2f05e7f22aeeecc86a32270880c2d72f12144fd8cc4e27a3489b57ed986efe3d327d3de40d921a0a73656e6420746f6b656e3a4069242925e0e377906364fe6c2eed67f419dfc1a757f73e848ff2f1ff97477f90263487d20aedf538edffe2ce5b3e7601a8528e5cd63845272e9d79c294a6590a"}
},
  answer => {
    // console.log(answer);
    jsome(answer);
    process.exit(0);
});

For more information, check out the RPC endpoints (Lisk Service) reference.

With the application / node

Via the application CLI

Any running node with an enabled API can be used to send a transaction object, see Application CLI and Command line interface.

An example for sending a transfer transaction with the Lisk Core CLI is displayed below:

$ lisk-core transaction:send 0802100018022080c2d72f2a20e03c09bdc8c023d94cf66a5d352e6258380210d97d545abbf75668ea3736e3123229088094ebdc031214ab0041a7d3f7b2c290b5b834d46bdc7b7eb858151a0b73656e6420746f6b656e733a40faa2626d7306506b1999f48aa2f4b1ffdee01e641fa76d37a9d1d6fd8c225a81065c856ea625c52d138a7e3ba86b62913dc8e5aef8b5e307641ab66e0277a60b

Via the HTTP API for Lisk nodes

If the HTTP API plugin is enabled on a node, it is possible to send the transaction to the node via an HTTP request:

curl -X 'POST' \
  'https://mainnet.lisk.com/api/transactions' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "moduleID": 2,
  "assetID": 0,
  "fee": "1000000",
  "nonce": "1",
  "senderPublicKey": "5133af7944acf5278b0310a11c06134f80ab4546d77d1b0e027c8430a7d2bb92",
  "asset": {
      "amount": "1000000000",
      "recipientAddress": "ab0041a7d3f7b2c290b5b834d46bdc7b7eb85815",
      "data": "send tokens"
    },
  "signatures": [
    "faa2626d7306506b1999f48aa2f4b1ffdee01e641fa76d37a9d1d6fd8c225a81065c856ea625c52d138a7e3ba86b62913dc8e5aef8b5e307641ab66e0277a60b"
  ]
}'

For more information, check out the HTTP API for Lisk nodes reference.

Via Lisk API client

A full example how to create and send a transaction via the API client is described in the code snippet below:

const { apiClient, cryptography, transactions } = require('@liskhq/lisk-client');
const RPC_ENDPOINT = 'ws://localhost:8080/ws';

let clientCache;

// Replace with the recipient address
const recipientAddress = "lskt8ovj2shbxrtno8xqqt7cnmzzygdkbt6brnvmj";
// Replace with the sender passphrase
const passphrase = "12 word mnemonic passphrase of an account with sufficient balance"

const getClient = async () => {
    if (!clientCache) {
        clientCache = await apiClient.createWSClient(RPC_ENDPOINT);
    }
    return clientCache;
};

getClient().then(async (client) => {
  const address = cryptography.getAddressFromBase32Address(recipientAddress);
  const tx = await client.transaction.create({
    moduleID: 2,
    assetID: 0,
    fee: BigInt(transactions.convertLSKToBeddows('0.01')),
    asset: {
        amount: BigInt(transactions.convertLSKToBeddows('8')),
        recipientAddress: address,
        data: 'Happy birthday!'
    }
  }, passphrase);

  console.log("Transaction object: ", tx);
  console.log("Transaction as JSON compatible object: ", client.transaction.toJSON(tx));
  console.log("Transaction binary: ", client.transaction.encode(tx).toString('hex'));
  const res = await client.transaction.send(tx);
  console.log(res);
  process.exit(0);
});
Example Response
{
  transactionId: '80f93e2540ceb9112ea900ee6c966c6de372c83a935bddb7c396e823ac4bc4eb'
}

By invoking the action app:postTransaction

If the RPC API for Lisk nodes is enabled on a node, it is possible to send a transaction via WebSockets or IPC, depending on which protocol is enabled in the config.

const { apiClient, cryptography, transactions } = require('@liskhq/lisk-client');
let clientCache;
const nodeAPIURL = 'ws://localhost:8080/ws';
// Replace with the recipient address
const recipientAddress = "lskt8ovj2shbxrtno8xqqt7cnmzzygdkbt6brnvmj";
// Replace with the sender passphrase
const passphrase = "12 word mnemonic passphrase of an account with sufficient balance"

const getClient = async () => {
	if (!clientCache) {
		clientCache = await apiClient.createWSClient(nodeAPIURL);
	}
	return clientCache;
};

getClient().then(async (client) => {
    const address = cryptography.getAddressFromBase32Address(recipientAddress);
    const tx = await client.transaction.create({
        moduleID: 2,
        assetID: 0,
        fee: BigInt(transactions.convertLSKToBeddows('0.01')),
        asset: {
            amount: BigInt(transactions.convertLSKToBeddows('8')),
            recipientAddress: address,
            data: 'Happy birthday!'
        }
    }, passphrase);

	client.invoke("app:postTransaction", {
		transaction: client.transaction.encode(tx).toString('hex')
	}).then(res => {
		console.log("Response: ", res);
		process.exit(0);
	});
});
Example output
Response:  {
  transactionId: 'dc041582c69b788d68f6b904bddadda5a52eb5e3b054087c74a80940f7f80210'
}