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:
create-ink-app
CLI (Coming soon)ink!athon
BoilerplateuseInkathon
Hooks & Utility Libraryzink!
Smart Contract Macros
Join the discussion in our Telegram Group 💬
Checkout our TypeDoc Documentation 📃
Important
If you are looking for a boilerplate to start your dApp project from scratch, checkout ink!athon.
- 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
- 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>
- 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()
At its core, this library serves as a wrapper for polkadot{.js}, potentially saving you over 100 lines of code. This includes:
- Utility functions for API initialization, connection, account management, balance checks, transfers, contract interactions, etc.
- React hooks & provider for easy access to all of the above, including:
useInkathon
– Main Hook responsible for connection, account management, etc.useBalance
usePSP22Balances
useContract
useRegisteredContract
(read more below)
- Contract interaction helper functions with automatic upfront gas estimation, including:
- Constants definitions for Substrate-based chains, wallets, and assets
- Works multichain with live & dynamic chain-switching out of the box
- Full contract-level type-safety with
typechain-polkadot
viauseRegisteredTypedContract
Note
Checkout our TypeDoc Documentation for more details.
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')
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')
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.
Within this repository:
- Vanilla React Example (
examples/react-ts
) - Vanilla CLI Scripts Example (
examples/scripts-ts
)
Live examples:
If you want to contribute, please read our Contributor Guidelines 🙏
Pre-requisites:
- Setup Node.js v18 (recommended via nvm)
- Install pnpm (recommended via Node.js Corepack)
- Clone this repository
# 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