Looking for Parity Ethereum client? Get it here.

Light.js: How to Build Your Dapp on a Light Client

Image Amaury Martiny
Software developer @ Parity Technologies
November 20, 2018 in light.js, Parity Fether, Releases

This article introduces a new JavaScript library, light.js, which provides a set of high-level tools to build light-client-efficient Dapps. It is primarily aimed for Dapp developers looking for an alternative to web3.js.

Why build on top of a light client?

Running a full Ethereum node is laborious: it’s very challenging today to have end-users run full nodes on consumer laptops. As a result, Dapp developers rely on external services for their backend infrastructure. These services run at scale, but at the cost of centralizing node operators.

Light clients solve this problem. A light client is a special kind of Ethereum node that is, as suggested by its name, light. Concretely, this means:

  • low on resources usage: CPU, memory, storage, I/O operations…
  • embeddable: in a desktop application, on mobile, within a web app.
  • but still remains trustless.

If a Dapp is paired with its own light client to query state and make transactions, it does not need to rely on centralized infrastructures anymore. At Parity Technologies, we wish to embed light clients everywhere: in desktop and mobile apps, browser extensions, web apps… We believe light clients will play a key role in Ethereum mass adoption.

Amaury Martiny presenting light.js at the Parity & Polkadot Devcon meetup

Meet light.js

We have built over fifteen Dapps for our now-defunct Parity UI. When building these Dapps, we came across development patterns that were popping up again and again. For example, if we want to constantly show the latest balance of an ERC20 token for a particular address, we can do one of the following:

  • poll the chain every 5 seconds
  • do some smart-polling, e.g. make a new call only once the previous call has finished
  • listen to incoming blocks via pub/sub, and only make a call on new block
  • listen to state changes via pub/sub (Parity only, see the documentation)

These patterns appear often in the Dapps ecosystem, if you are a Dapp developer, chances are you are using one of them.

However, these are empirical patterns: they are well-known amongst Dapp developers, but are not always enforced.

The goal of light.js is simple:

  • pick the best pattern that works with light clients: listen to headers via pub/sub and make API calls on new header, while making sure that the amount of network calls is not excessive.
  • put it into a high-level library, so that Dapp developers use a simple API instead of following a supposedly well-known pattern.

Concretely, it means:

// Before, with web3.js

const contract = web3.eth.Contract(ABI, '0x00..ff');

async function updateBalance() {  
	const balance = await contract.methods.balanceOf('0xabc').call(); 
	console.log(balance);
}

// Dapp developer: "This should be light-client-friendly...
"web3.eth.subscribe('newBlockHeaders').on('data', updateBalance);

--- 

// Now, with light.js

import { makeContract } from '@parity/light.js';
// Dapp developer: "I'm sure this is light-client-friendly!"
makeContract(ABI, '0x00..ff')
	.balanceOf$('0xabc')
	.subscribe(console.log); // Logs the result when balance changes

High-level reactive programming

light.js is meant to be high-level: the Dapp developer calls a function and the library chooses the best pattern, handles caching, and does all the dirty work behind the scenes.

light.js; only exposes 10 high-level functions, amongst them:

  • query the balance: balanceOf$('0x123');
  • interact with contracts: makeContract(abi, contractAddress);
  • post a transaction: post$(myTx);
  • manage accounts: account$();
  • etc. (you can find the full list in the documentation)

We only expose ten functions, but they should cater to the needs of most Dapps today. For reference, we built a fully-featured Ethereum & ERC20 wallet on top of light.js, called Parity Fether. Based on feedback, we might of course add new functions—feel free to create an issue if you need one.

You might have noticed the $ sign behind the names of the functions. This is a JavaScript convention to represent Observables. Observables are a JavaScript structure that basically represents an ongoing asynchronous stream of data, ordered in time. Some examples that can be expressed in Observables:

  • clicks on a button
  • tweets on your Twitter feed
  • new blocks on the Ethereum blockchain

Data streams are an intuitive, high-level way to express changes happening on the Ethereum blockchain. The Observables in light.js fire when something changes, and the Dapp reacts to those changes. Moreover, Dapp developers can leverage the huge ecosystem around Observables to build complex Dapps with the basic ones provided by light.js.

To learn more about reactive programming, head towards our documentation.

Start hacking with light.js

The best way to start hacking with `light.js `is to:

An important thing to note is that while light.js is optimized for light clients, it will of course work with full nodes, local or remote. In particular, it works out-of-the-box if you have MetaMask installed:

import light, { balanceOf$ } from '@parity/light.js';

// Wait for web3.currentProvider to be injected
window.addEventListener('load', () => {
  // Tell light.js to use MetaMask provider
  light.setProvider(window.web3.currentProvider);

  balanceOf$('0x123').subscribe(console.log); // Logs the balance
});

Even if you can't embed a light-client in your app today for whatever reason, light.js works well with remote full nodes, so we do recommend light.js for any kind of Dapp. The day you decide to finally switch to a light client, you won’t have to change a single line of code.

If you are writing your Dapp with React, we also provide light.js-react, a tiny library to integrate light.js easily with React apps:

import * as React from 'react';
import { balanceOf$ } from '@parity/light.js';
import light from '@parity/light.js-react';

@light({
  myBalance: () => balanceOf$('0x123')
})
class MyComponent extends React.Component {
  render() {
    return (
      <div>
        The balance of "0x123" is {this.props.myBalance.toFormat(2)}.
      </div>
    );
  }
}

To see an example of how light.js is used in a real-world app, see how we built Parity Fether on top of it.

Next steps

light.js is a small step in the direction of our effort to promote the use of decentralised light clients. We would love to hear feedback from developers, so if you have questions or ideas about this library, make sure to post an issue on the Github repo: https://github.com/paritytech/js-libs/tree/master/packages/light.js.

More recent stories

November 09, 2018

Parity Fether alpha is here: a decentralised, light client-based wallet

Read More
October 30, 2018

Parity teams up with Zcash Foundation for Parity Zcash client

Read More
October 26, 2018

Launch a blockchain in minutes with Substrate, arriving November 2018

Read More

Join the discussion:

pic

Want to build the future of the web?

We're hiring »