Creating Custom Blockchain Transactions with the SDK — Introducing Lisk Bills
Tags: blockchain, javascript, node
Published: 2019-08-22 14:28:03

---
title: Creating Custom Blockchain Transactions with the SDK — Introducing Lisk Bills
published: true
description: Learn to create custom transactions with the Lisk SDK in JavaScript.
canonical_url: https://blog.lisk.io/creating-custom-blockchain-transactions-with-the-sdk-introducing-lisk-bills-a8398ae171fd
tags: blockchain, javascript, node, opensource
---

The [Lisk Bills webinar](https://www.youtube.com/watch?v=NYfUBXw4Tw0) is now live on our [YouTube channel](https://www.youtube.com/channel/UCuqpGfg_bOQ8Ja4pj811PWg). Subscribe for more educational developer content.

Lisk’s Alpha SDK Phase officially began in late July with the release of SDK 2.1.0. We decided what better way to showcase the potential of custom transactions than to create our own proof-of-concept (PoC) blockchain application. To explore the possibilities of custom transactions at their best, we decided to build an invoicing application and through this register two new custom transactions on our blockchain.

# Introduction to Custom Transactions
[Lisk SDK](https://lisk.io/sdk) allows you to define your own custom transaction types where you can implement the required logic for your blockchain use-case. The custom transaction types are an extension to the default set of transactions that is already part of the Lisk Protocol. You can read more about the predefined types [here](https://lisk.io/documentation/lisk-sdk/customize).

The beginning of the Alpha SDK phase of our [roadmap](https://lisk.io/roadmap) allows you to create your own proof-of-concept blockchain applications aligned with our architecture. This phase of our roadmap also allows us to get feedback on how the development experience can be improved via discussion on [our community channels](https://discordapp.com/channels/405002561775599619/405002561779793921).

# Custom Transactions to Grow the Lisk Ecosystem
Custom transactions offer great business value to the Lisk Ecosystem as they allow for a lot of creativity. We believe custom transactions are the “creative spark” for the Lisk Ecosystem to see a whole bunch of innovative projects being created. **We already see community members coming up with their own solutions ranging from hardware-utilizing rental bike tracking system, [Lisk.Bike](https://sites.google.com/view/liskbike), to the usage of our modular JavaScript library for an innovative take on a classic strategy game, [Lisk Tic-Tac-Toe](https://sidechainsolutions.io/articles/lisk-tictactoe).** Now is your time to get creative!

# Benefits of Custom Transactions
Every account object has the ability to store data in its `asset` field. Custom transactions make clever use of this. The use of the `asset` field allows for any type of stringified data to be passed to the transaction. This allows for greater flexibility and creativity when defining custom logic.

Besides that, every custom transaction can access and modify all account-related data and only read transaction-related data from the database. This allows for more advanced interactions between data and even between different custom transactions. For example, our PoC used the data from the _Invoice_ transaction to verify the validity of the _Payment_ transaction.

You can also create a token in the asset field with some basic transfer and verification logic. In the end, this is just another way of smart contract logic.

Let’s continue with exploring the technicals of our Lisk Bills PoC.

# Lisk Bills — Blockchain-Based Invoicing
![Lisk Bills Logo](https://thepracticaldev.s3.amazonaws.com/i/hu90nxfydpqno4nhrxhr.png)

As we like the _Keep it Simple and Stupid (KISS)_ approach, we have built a minimal frontend with React that uses the Lisk Alpha SDK to interact directly with your blockchain application. The PoC includes two actors, the client and the freelancer.

Imagine Alice (Freelancer) and Bob (Client). Bob is looking for a new logo for his website and decides to consult a freelancer. While looking for a good designer, he comes across Alice who offers some spectacular designs in her portfolio. Bob is so excited he decides to immediately employ Alice’s skillset.

A few days go by, and Alice returns the promised logo together with an invoice. **However, Bob is a big fan of blockchain technology as it helps to ease the settlement process. It often happens parties disagree about the agreed price, product, or even shipping terms. Bob, therefore, believes blockchain can help with recording all this information right from the beginning, so no disputes can occur and human error can be eliminated. The blockchain should act as proof for the invoice.**

For the above reason, Bob asks Alice to create the invoice via a Lisk custom transaction.

In order to do so, Alice first has to log in with her passphrase to the Lisk Bills application.

![Lisk Bills Sign In](https://thepracticaldev.s3.amazonaws.com/i/4l7z55w4zoz87xy52217.png)

# Custom Transaction 1: Invoice
Now Alice has been logged in, she can create an invoice. To create the custom invoice transaction, Alice has to input the following details:

- `Client` holds Bob’s Lisk address or business name.
- `RequestedAmount` holds the amount Bob is due to Alice.
- `Description` to describe the delivered design service.

![Lisk Bills Diagram Transactions](https://thepracticaldev.s3.amazonaws.com/i/oqy6jv1kaffzcq4yip2j.png)

The following data is stored in the asset field of the transaction. As this is a normal _BaseTransaction_, we can simply specify Bob’s Lisk address as the recipient for the transaction.

![Lisk Bills Send Invoice](https://thepracticaldev.s3.amazonaws.com/i/9etww6aha74oyurji1r0.png)

Before we dive into the technicals, make sure to **open or clone the [lisk-sdk-examples repository](https://github.com/LiskHQ/lisk-sdk-examples/tree/development/invoice)**. The code for both custom transactions can be found in _[invoice/transactions/invoice_transaction.js](https://github.com/LiskHQ/lisk-sdk-examples/blob/development/invoice/transactions/invoice_transaction.js)_ and _[invoice/transactions/payment_transaction.js](https://github.com/LiskHQ/lisk-sdk-examples/blob/development/invoice/transactions/payment_transaction.js)_.

# Technicals
First of all, let’s take a look at the class definition. The `InvoiceTransaction` extends the `BaseTransaction` which means it’s inheriting its properties. As the name suggests, `BaseTransaction` is the most basic interface for creating new transaction types. Other transaction types also exist in the system, later we will show an example of extending the `TransferTransaction` type.

When extending the `BaseTransaction` we can provide extra business logic for the following methods: _Prepare, Validate Asset, Apply Asset and Undo Asset_. You can find out more about these [methods in our documentation](https://github.com/LiskHQ/lisk-docs/blob/master/lisk-sdk/customize.md#prepare).

Also, pay attention to the static getter function for retrieving the type of the transaction. As an example, we have chosen `13` to be the type number for this transaction. Besides that, you can set the fee you want users to pay for using this transaction type. For now, we have set this to 1 LSK (10 to the 8th beddows).


```js
class InvoiceTransaction extends BaseTransaction {
  static get TYPE () {
	return 13;
  }
  
  static get FEE () {
	return `${10 ** 8}`;
  }

  ...
}

```

## Prepare
The prepare function is responsible for loading the required data used inside the `applyAsset()` and `undoAsset()` function. Here, we try to load the account data for the sender as we want to add data to his asset field in the `applyAsset()` function. This data will be loaded from the _StateStore_ object that provides access to data in the database.

We can cache the sender account like this by passing an array with filters.

```js
await store.account.cache([
	{
		address: this.senderId,
	},
]);
```

However, we actually don’t have to manually cache the data. We can simply call the parent method for the `prepare` function in the [abstract `BaseTransaction` class](https://github.com/LiskHQ/lisk-sdk/blob/development/elements/lisk-transactions/src/base_transaction.ts) which will by default cache the sender account to [deduct the fee in the apply step](https://github.com/LiskHQ/lisk-sdk/blob/development/elements/lisk-transactions/src/base_transaction.ts#L348).

```js
async prepare(store) {
	await super.prepare(store);
}
```

## Validate Asset
Before a transaction reaches the apply step it gets validated. Check the transaction’s asset correctness from the schema perspective (no access to `StateStore` here). You can invalidate the transaction by pushing an error into the result array.

```js
validateAsset() {
	const errors = [];
	if (!this.asset.client || typeof this.asset.client !== 'string') {
		errors.push(
			new TransactionError(
				'Invalid "asset.client" defined on transaction',
				this.id,
				'.asset.client',
				this.asset.client,
				'A string value',
			)
		);
	}
	if (!this.asset.requestedAmount || typeof this.asset.requestedAmount !== 'string') {
		errors.push(
			new TransactionError(
				'Invalid "asset.requestedAmount" defined on transaction',
				this.id,
				'.asset.requestedAmount',
				this.asset.requestedAmount,
				'A string value',
			)
		);
	}
	if (!this.asset.description || typeof this.asset.description !== 'string') {
		errors.push(
			new TransactionError(
				'Invalid "asset.description" defined on transaction',
				this.id,
				'.asset.description',
				this.asset.description,
				'A string value',
			)
		);
	}
	return errors;
}
```

## Apply Asset
As you can see, we finally use the loaded account which we put in the store during the `prepare` step. Next, we update the invoice count and record the ID of the invoice in an array with sent invoices. We will use this data in our frontend to display all invoices.

```js
applyAsset(store) {
	const sender = store.account.get(this.senderId);

	// Save invoice count and IDs
	sender.asset.invoiceCount = sender.asset.invoiceCount === undefined ? 1 : sender.asset.invoiceCount++;
	sender.asset.invoicesSent = sender.asset.invoicesSent === undefined ? [this.id] : [...sender.asset.invoicesSent, this.id];
	store.account.set(sender.address, sender);
	return [];
}
```

## Undo Asset
Do not underestimate the importance of the `undoAsset()` function. The _Undo_ function allows us to rollback to a previous blockchain state. Therefore, we should exactly tell our blockchain application how it should roll back changes.

The _Undo_ function is of most importance for the fork recovery mechanism. In case a fork occurs on a chain with tip B and we want to roll back to a common height in order to re-apply blocks up to the tip of chain A, we need the _Undo_ function to do the actual rollback to this common height.

For the invoice proof of concept, the code reduces the `invoiceCount` and removed the invoice ID from the `invoicesSent` array.

```js
undoAsset(store) {
	const sender = store.account.get(this.senderId);

	// Rollback invoice count and IDs
	sender.asset.invoiceCount = sender.asset.invoiceCount === 1 ? undefined : sender.asset.invoiceCount--;
	sender.asset.invoicesSent = sender.asset.invoicesSent.length === 1 
		? undefined 
		: sender.asset.invoicesSent.splice(
			sender.asset.invoicesSent.indexOf(this.id),
			1,
		);
	);
	store.account.set(sender.address, sender);
	return [];
}
```

Ok, we have explored the functions for the invoice transaction. Let’s move to the payment transaction.

# Custom Transaction 2: Payment
Now Bob has received the Invoice Transaction in his wallet, he decides to pay for the invoice. In order to fulfill the transaction, we would normally send a `TransferTransaction` which is natively supported by Lisk SDK.

However, doing so would make this a very boring tutorial. Therefore, Bob decides to use another custom transaction to showcase Lisk’s possibilities. This custom Payment Transaction holds logic to verify the transferred amount is at least equal to the `RequestedAmount`. Also, the transaction requires Bob to specify the ID of the invoice he wants to fulfill.

If the transferred amount is too low or the invoice ID just doesn’t exist, the transaction fails. Bob keeps his side of the agreement and sends the requested amount to Alice’s invoice ID. Bob even adds a tip for Alice’s great work.

![Lisk Bills Diagram Transactions](https://thepracticaldev.s3.amazonaws.com/i/oqy6jv1kaffzcq4yip2j.png)

This is how the UI implementation looks like for paying an invoice with our Lisk Bills application.

![Lisk Bills Pay Invoice](https://thepracticaldev.s3.amazonaws.com/i/5xgbuk2jfdv2z60gc5vu.png)

# Technicals
Again, let’s take a look at the class definition. The `PaymentTransaction` extends the `TransferTransaction` which means it’s inheriting its properties like a different fee and transfer-related verification checks. Also, pay attention to the static getter function for retrieving the type of the transaction. As we can not have identical transaction types, the `PaymentTransaction` has received type `14`.

```js
class PaymentTransaction extends TransferTransaction {

	static get TYPE () {
		return 14;
	}
  
  	...
}
```

Also, note we don’t define a static getter function for `FEE`. We didn’t implement it here as we don’t want to overwrite the `FEE` defined in the `TransferTransaction`. In short, we want to use the `0.1` fee defined in `TransferTransaction`.

## Prepare
The prepare function is responsible for loading the required data into the store to be used inside the `applyAsset()` and `undoAsset()` function. For the `PaymentTransaction`, we are loading the transaction that holds the invoice using the `ID` sent with `this.asset.data`.

```js
async prepare(store) {
	await super.prepare(store);
	await store.transaction.cache([
		{
			id: this.asset.data,
		},
	]);
}
```

## Validate Asset
As you might have noticed, we didn’t implement the `validateAsset()` function for the payment transaction. The only check we have to perform is validating if the sent number of tokens is at least equal to the requested number of tokens.

In order to validate this, we need access to the `StateStore` as we need to cache the invoice transaction. Because we can only perform static checks in the `validateAsset()` function that don’t use the `StateStore`, this check is [moved to the apply step](https://github.com/LiskHQ/lisk-sdk-examples/blob/development/invoice/transactions/payment_transaction.js#L20).

## Apply Asset
The `applyAsset()` function first tries to find the corresponding invoice transaction. If this transaction exists, we further check for the number of tokens transferred is at least equal to the requested amount in the invoice. If this check succeeds, the transaction gets applied.

```js
applyAsset(store) {
	const errors = super.applyAsset(store);

	const transaction = store.transaction.find(
		transaction => transaction.id === this.asset.data
	); // Find related invoice in transactions for invoiceID

	if (transaction) {
		if (this.amount.lt(transaction.asset.requestedAmount)) {
			errors.push(
				new TransactionError(
					'Paid amount is lower than amount stated on invoice',
					this.id,
					'.amount',
					transaction.requestedAmount,
					'Expected amount to be equal or greated than `requestedAmount`',
				)
			);
		}
	} else {
		errors.push(
			new TransactionError(
				'Invoice does not exist for ID',
				this.id,
				'.asset.invoiceID',
				this.asset.data,
				'Existing invoiceID registered as invoice transaction',
			)
		);
	}

	return errors;
}
```

## Undo Asset
No rollback logic is required for the undo step of the payment transaction. We do not modify any data in the store with the `set` method, so no need for defining undo steps to revert this data change.

However, do not forget to call `super.undoAsset(store)` as the _Undo_ step will make sure the fee Alice has paid gets returned to her account’s balance.

# How to Register Custom Transactions?
Ok, we have prepared both of our custom transactions. Bob and Alice are very happy to use both transactions in order to finalize their deal. However, we don’t know yet how to register these new transactions on our blockchain application.

The [invoice/index.js](https://github.com/LiskHQ/lisk-sdk-examples/blob/development/invoice/index.js) file holds the startup code for running your custom blockchain and also registers both transactions. It’s as simple as that!

```js
const { Application, genesisBlockDevnet, configDevnet } = require('lisk-sdk');
const { InvoiceTransaction, PaymentTransaction } = require('./transactions/index');

const app = new Application(genesisBlockDevnet, configDevnet);

app.registerTransaction(InvoiceTransaction);
app.registerTransaction(PaymentTransaction);

app
	.run()
	.then(() => app.logger.info('App started...'))
	.catch(error => {
		console.error('Faced error in application', error);
		process.exit(1);
	});
```

Ok, we are all done! At last, let’s take a brief look at the considerations regarding the use of custom transactions.

# Considerations of Using Custom Transactions
Currently, we expect users to run their own blockchain instance that registers their freshly created custom transaction.

**It took us a few weeks to build this prototype. We have deliberately kept it simple to act as a learning resource, and as inspiration for the community. It is not production-ready.**

# Conclusion
Lisk aims to allow for creativity within the blockchain industry by providing the ability to process data with custom business logic. This concept is very similar to smart contracts as they also hold custom business logic. We are pleased to introduce you to Lisk Bills as the first example of what is possible with our SDK.

We hope this freedom will spark a whole bunch of new innovative blockchain applications build on top of Lisk using the newly released Lisk Alpha SDK. Currently, we do not plan to support custom transactions on the Lisk mainnet but they are intended to be used inside your own blockchain application.

**Lisk is on a mission to enable you to create decentralized, efficient, and transparent blockchain applications. Join us:**

- [Lisk Discord](https://discord.gg/GA9DZmt)
- [SDK Page and Newsletter](http://lisk.io/sdk)
- [Lisk Research](https://research.lisk.io/)
- [Twitter](https://twitter.com/LiskHQ)