linkedin logogithub logo
September 6, 2021

Nervos: transactions with ckb-sdk

Key Points

At Rather Labs we exploring how to interact with Nervos blockchain, this is a third-generation blockchain that deploys multiple layers which combines security and decentralization on layer one and scalability on the sub-layers.

ckb-sdk is a JavaScript library that allows to sign and send transactions within the Nervos blockchain. Nervos is based on the concept of “cells” which is analog to the (unspent transactions output) UTXO system of Bitcoin. The “living cells” are used to generate transactions and to produce new cells. The cells can be employed generally by only one owner. The cells in the inputs of the transactions cannot be transferred anymore and they become “dead cells”. A Nervos node run two main programs:

  • CKB: This is the main CKB blockchain program that does the synchronization with the others nodes on the blockchain and can perform transaction validations and mine new blocks.
  • CKB-indexer: This acts as a database allowing the users to fetch the living cells from the blockchain quicker.

To create a transaction on the CKB blockchain, we need to:

  1. Fetch the living cells of a CKB account, from where we are going to transact the CKBs, using the CKB-indexer. It is required to have an access point to a public indexer or even to run a Testnet node locally.
  2. Transfer the tokens using the living cells from the account gotten from the previous step. For this, we are going to use the ckb-sdk library which enables us to sign and send the transactions.

To transfer CKBs create two accounts, one for sending CKBs and the other for receiving. Then use the CKB Testnet faucet to fill one of them with some CKBs. Check this page for generating new CKB addresses.

For fetching the living cells information from the blockchain we need the lock script that identifies the CKB accounts. Each CKB account has a unique lock script that can be obtained using the ckb-sdk-utils (part of ckb-sdk-core) package:

<pre><code>const ckbSdkUtils = require("@nervosnetwork/ckb-sdk-utils");
let address = "ckt1qyqycgdq0d5fpe9nqpf7j0l2n53lxmceqpas2shhaz";
let lockScript = ckbSdkUtils.addressToScript(address)

The lock script looks like this:

    codeHash: '0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8',  
    hashType: 'type',  
    args: '0x4c21a07b6890e4b30053e93fea9d23f36f19007b'

The first step is to fetch the living cells by doing an HTTP request to the indexer. In our case, we are running the ckb-indexer in our private node and it accepts the request with the “get_cells” method. The following code snippet prepares the data to send as an HTTP request and uses Axios to perform the request:

const indexerUrl = "http://localhost:3000"

let post_data = {
jsonrpc: "2.0", method: "get_cells",
params: [
"script": {
"code_hash": lockScript.codeHash,
"hash_type": lockScript.hashType,
"args": lockScript.args
"script_type": "lock"

let post_options = {headers: {'Content-Type': 'application/json'}};

let cells;, post_data, post_options)
.then((response) => {
cells = => {
return {
lock: {
codeHash: value.output.lock.code_hash,
hashType: value.output.lock.hash_type,
args: value.output.lock.args,
outPoint: {
txHash: value.out_point.tx_hash,
index: value.out_point.index,
capacity: value.output.capacity,
data: value.output_data,
.catch((error) => {
console.log("error:", error);

You will need to adapt the URL of the indexer indexerUrl to a public URL or the http://localhost:port if you are running a node locally.

Once the cells related to the sending CKB account have been fetched, it is time to sign and send the transaction. The most important parameters to consider in this part would be:

  • Sending address:fromAddress
  • Sending private key: addressPrivate
  • Receiving address: toAddress
  • Amount to send:capacity
  • Fee for the transaction: fee

const CKB = require('@nervosnetwork/ckb-sdk-core').default;

const signAndSend = async () => {
const ckb = new CKB(nodeUrl);
await ckb.loadDeps();
const rawTransaction = await ckb.generateRawTransaction({
fromAddress: address,
capacity: BigInt(99 * 1E8),//1E8 shannons = 1CKB, min 61E8 shannon = 61CKB
fee: BigInt(0.001 * 1E8),
safeMode: true,
deps: ckb.config.secp256k1Dep,

const signedTx = ckb.signTransaction(addressPrivate)(rawTransaction);
const realTxHash = await ckb.rpc.sendTransaction(signedTx)


These are the basic steps to perform a transaction, more advanced things like checking how many nodes confirm the transaction and checking the balances are also going to be covered in new articles.

Please check the full source code use for this article at the Rather Labs Github. Don’t miss the next articles coming where we are going to explain how to deploy and interact with User Defined Tokens (UDT) and how to work with Non-Fungible Tokens (NFT) on the Nervos Blockchain.

For this articled we have used the following NPM packages:

Thanks to Federico Caccia and Franco Scucchiero

Macarena López Morillo
Head of People
Get the Full Picture
For an in-depth understanding of this topic, don't miss out. Learn more here and elevate your knowledge.
right arrow

More articles

Web3 —
Blockchain Technical Partners

Uncover our Web3 creations and discover how we're redefining tomorrow.
Learn More