@scio-labs/use-inkathon

inkathon Devtooling Banner

useInkathon – React Hooks & Utility Library

License: GPL v3 Built with ink! TypeScript React

This library provides typesafe React hooks and utility functions that simplify the process of working with Substrate-based networks and ink! smart contracts. It abstracts away the complexities of polkadot{.js} but still lets you access the full power of the underlying API.

The project is part of a Scio Labs initiative to improve the developer experience in the ink! ecosystem and a proud member of the Aleph Zero EFP. 💜

Other projects include:

Join the discussion in our Telegram Group 💬

Checkout our TypeDoc Documentation 📃


  1. Getting started 🚀
  2. Features ✨
  3. Contract Registry 🗳️
    1. How it works
    2. Typed Contracts
  4. Examples 📚
  5. Package Development 🛠

Getting started 🚀

[!IMPORTANT]
If you are looking for a boilerplate to start your dApp project from scratch, checkout ink!athon.

  1. Go to your existing project and install the package from the npm registry:
pnpm add @scio-labs/use-inkathon
# or
npm install @scio-labs/use-inkathon
# or
yarn add @scio-labs/use-inkathon
  1. Wrap it around your app or parent component:
import { development, UseInkathonProvider } from '@scio-labs/use-inkathon'
<UseInkathonProvider appName="My dApp" defaultChain={development}>
<Component {...pageProps} />
</UseInkathonProvider>
  1. Use the primary useInkathon hook for connecting the wallet or accessing the API:
import { useInkathon } from '@scio-labs/use-inkathon'
const { api, connect, activeChain, activeAccount, … } = useInkathon()

Features ✨

At its core, this library serves as a wrapper for polkadot{.js}, potentially saving you over 100 lines of code. This includes:

[!NOTE]
Checkout our TypeDoc Documentation for more details.

Contract Registry 🗳️

Often when working with smart contracts in the frontend, you have to import the contract metadata multiple times across a project, then determine the matching deployment address for the active chain, and create a ContractPromise instance manually each time.

The idea of a Contract Registry is to define contract metadata & addresses only once and use them everywhere with a simple hook:

const { contract } = useRegisteredContract('greeter')

How it works

Start by defining an async getDeployments function that returns SubstrateDeployment[] metadata objects for each contract deployment on each chain.

[!NOTE]
Checkout an advanced example within the ink!athon boilerplate here where metadata is imported dynamically based on defined chains and contract identifiers.

import { alephzeroTestnet, SubstrateDeployment } from '@scio-labs/use-inkathon'

export const getDeployments = async (): Promise<SubstrateDeployment[]> => {
return [
{
contractId: 'greeter',
networkId: alephzeroTestnet.network,
abi: await import(`../deployments/metadata.json`),
address: '5HPwzKmJ6wgs18BEcLdH5P3mULnfnowvRzBtFcgQcwTLVwFc',
},
]
}

The function's result passed to the UseInkathonProvider provider:

<UseInkathonProvider
appName="My dApp"
defaultChain={alephzeroTestnet}
deployments={getDeployments()}
>
<Component {...pageProps} />
</UseInkathonProvider>

Then access the contract as above:

const { contract } = useRegisteredContract('greeter')

Typed Contracts

[!NOTE]
Make sure to also install @727-ventures/typechain-types, bn.js, and @types/bn.js as dependencies in your project. Find a complete setup & usage example in the ink!athon boilerplate.

If you are using typechain-polkadot to generate type-safe contracts, you can use the useRegisteredTypedContract hook instead:

import GreeterContract from '[…]/typed-contracts/contracts/greeter'

// …

const { typedContract } = useRegisteredTypedContract('greeter', GreeterContract)
const result = await typedContract.query.greet()

[!IMPORTANT]
Currently, only queries are supported until typechain-polkadot#138 is merged. Alternatively, we're considering switching to the prosopo/typechain-polkadot fork completely.

Examples 📚

Within this repository:

Live examples:

Package Development 🛠

If you want to contribute, please read our Contributor Guidelines 🙏

Pre-requisites:

# Install dependencies
pnpm i

# Enable pre-commit hooks
pnpm simple-git-hooks

# Run tsup in development mode (watching)
pnpm dev

# Run package compilation in parallel with vanilla React example
pnpm run dev:react-example

# Build the package
pnpm build
How to import a development version of this package locally?

Unfortunately, importing this package locally into other local projects requires some manual steps. You need to build & pack this package into a .tgz-build and then update this dependency in your other project. These steps must be repeated each time you make changes to this package.

# 1. [THIS PACKAGE] Generate a .tgz package of the build
pnpm tsup && pnpm pack

# 2. [OTHER PROJECT] Add it as a dependency in your other project like:
# `"@scio-labs/use-inkathon": "file:../scio-labs-use-inkathon-0.0.X.tgz"`
pnpm add ../use-inkathon/scio-labs-use-inkathon-0.0.X.tgz

# 3. [OTHER PROJECT] Subsequent updates can be done via
pnpm update @scio-labs/use-inkathon --force