diff --git a/README.md b/README.md index c9ee9e6..235511a 100644 --- a/README.md +++ b/README.md @@ -26,8 +26,9 @@ Other projects include: 1. [Getting started 🚀](#getting-started-) 2. [Features ✨](#features-) -3. [Contract Registry 🗳️](#contract-registry-️) +3. [Contract Registry 🗳️](#contract-registry-️%EF%B8%8F) 1. [How it works](#how-it-works) + 2. [Typed Contracts](#typed-contracts) 4. [Examples 📚](#examples-) 5. [Package Development 🛠](#package-development-) @@ -87,6 +88,7 @@ At its core, this library serves as a **wrapper for polkadot{.js}, potentially s - [`decodeOutput`](https://scio-labs.github.io/use-inkathon/functions/decodeOutput.html) - 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`](https://github.com/Brushfam/typechain-polkadot) via [`useRegisteredTypedContract`](https://scio-labs.github.io/use-inkathon/functions/useRegisteredTypedContract.html) > [!NOTE] > Checkout our [TypeDoc Documentation](https://scio-labs.github.io/use-inkathon/) for more details. @@ -141,6 +143,25 @@ 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`](https://github.com/scio-labs/inkathon). + +If you are using [`typechain-polkadot`](https://github.com/Brushfam/typechain-polkadot) to generate type-safe contracts, you can use the `useRegisteredTypedContract` hook instead: + +```ts +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](https://github.com/Brushfam/typechain-polkadot/pull/138) is merged. Alternatively, we're considering switching to the [`prosopo/typechain-polkadot`](https://github.com/prosopo/typechain-polkadot) fork completely. + ## Examples 📚 Within this repository: diff --git a/package.json b/package.json index 31df804..058ecd1 100644 --- a/package.json +++ b/package.json @@ -83,6 +83,7 @@ "@polkadot/api": ">=10", "@polkadot/api-contract": ">=10", "@polkadot/extension-inject": ">=0.46", + "@polkadot/keyring": ">=10", "@polkadot/types": ">=10", "@polkadot/util": ">=10", "@polkadot/util-crypto": ">=10", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 161eb6f..7bbdf60 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,6 +20,9 @@ importers: '@polkadot/extension-inject': specifier: '>=0.46' version: 0.46.6(@polkadot/api@10.11.1)(@polkadot/util@12.6.1) + '@polkadot/keyring': + specifier: '>=10' + version: 12.6.1(@polkadot/util-crypto@12.6.1)(@polkadot/util@12.6.1) '@polkadot/types': specifier: '>=10' version: 10.11.1 diff --git a/src/hooks/index.ts b/src/hooks/index.ts index fcc4041..6ebbdae 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -3,4 +3,5 @@ export * from './useBalance' export * from './useContract' export * from './usePSP22Balances' export * from './useRegisteredContract' +export * from './useRegisteredTypedContract' // @endindex diff --git a/src/hooks/useRegisteredContract.ts b/src/hooks/useRegisteredContract.ts index 6e565d4..0de25ac 100644 --- a/src/hooks/useRegisteredContract.ts +++ b/src/hooks/useRegisteredContract.ts @@ -4,8 +4,8 @@ import { useContract } from './useContract' /** * React Hook that returns a `ContractPromise` object configured with - * the active api & chain as well as the given deployment contract id - * which is looked up from the deployments registry. + * the active api & chain with the given deployment contract id which + * is looked up from the deployments registry. */ export const useRegisteredContract = (contractId: string, networkId?: string) => { const { deployments, activeChain } = useInkathon() diff --git a/src/hooks/useRegisteredTypedContract.ts b/src/hooks/useRegisteredTypedContract.ts new file mode 100644 index 0000000..de86d25 --- /dev/null +++ b/src/hooks/useRegisteredTypedContract.ts @@ -0,0 +1,37 @@ +import { useRegisteredContract } from '@/hooks/useRegisteredContract' +import { useInkathon } from '@/provider' +import { TypechainContractConstructor } from '@/types' +import { useEffect, useState } from 'react' + +/** + * React Hook that returns a type-safe contract object by `typechain-polkadot`, + * configured with the active api & chain for the given deployment contract id + * which is looked up from the deployments registry. + */ +export const useRegisteredTypedContract = ( + contractId: string, + Contract: TypechainContractConstructor, + networkId?: string, +) => { + const { api, activeAccount } = useInkathon() + const registeredContract = useRegisteredContract(contractId, networkId) + + const [typedContract, setTypedContract] = useState(undefined) + useEffect(() => { + if (!registeredContract?.address || !activeAccount?.address || !api) { + setTypedContract(undefined) + return + } + + // IMPORTANT: Right now, only KeyringPair is supported as signer, but as we don't have + // those anyways in the frontend, we can alreaday start using the new API. + const typedContract = new Contract( + registeredContract.address.toString(), + activeAccount.address as any, + api, + ) + setTypedContract(typedContract) + }, [registeredContract?.address, activeAccount?.address]) + + return { ...registeredContract, typedContract } +} diff --git a/src/types/TypechainContractConstructor.ts b/src/types/TypechainContractConstructor.ts new file mode 100644 index 0000000..fc04b8e --- /dev/null +++ b/src/types/TypechainContractConstructor.ts @@ -0,0 +1,8 @@ +import { ApiPromise } from '@polkadot/api' +import { KeyringPair } from '@polkadot/keyring/types' + +export type TypechainContractConstructor = new ( + address: string, + signer: KeyringPair, + nativeAPI: ApiPromise, +) => T diff --git a/src/types/index.ts b/src/types/index.ts index 30603f3..7b09f40 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -4,5 +4,6 @@ export * from './DeployedContract' export * from './SubstrateChain' export * from './SubstrateDeployment' export * from './SubstrateWallet' +export * from './TypechainContractConstructor' export * from './UseInkathonProviderContext' // @endindex