Package for generating TypeScript definitions & runtime code for Polkadot smart contracts.
In your project install this package:
npm i -D @dpowxconsensus/typechain-polkadot
Now you can use it to generate TS definitions & runtime code for Polkadot smart contracts. To use typechain-polkadot.
Note, that ink! contracts generate two files:
metadata.json
and<contract-name>.contract
. You need to provide both of them to typechain-polkadot, and renamemetadata.json
to<contract-name>.json
.
Typechain can be used in two ways:
- As a CLI tool
- As a library
After installing the package, you can use it as a CLI tool. To use it, run the following command:
npx @dpowxconsensus/typechain-polkadot --input path/to/abis --output path/to/output
In this namespace you can find all the functions that are related to building extrinsics.
const tx = contract.buildExtrinsic.<methodName>(...args, options);
tx.signAndSend(account, (result) => {
// Handle result
});
Used to deploy contracts, using different constructors.
Let's deploy the following contract:
#![cfg_attr(not(feature = "std"), no_std)]
#![feature(min_specialization)]
#[openbrush::contract]
pub mod my_psp22 {
// imports from openbrush
use openbrush::contracts::psp22::*;
use openbrush::traits::Storage;
#[ink(storage)]
#[derive(Default, Storage)]
pub struct Contract {
#[storage_field]
psp22: psp22::Data,
}
// Section contains default implementation without any modifications
impl PSP22 for Contract {}
impl Contract {
#[ink(constructor)]
pub fn new(initial_supply: Balance) -> Self {
let mut _instance = Self::default();
_instance._mint_to(_instance.env().caller(), initial_supply).expect("Should mint");
_instance
}
}
}
This contract has a constructor new
with one argument initial_supply
.
To deploy this contract, you need to use the following code:
// Import here Constructors and Contract classes
// Here we are creating an instance of the Constructors class, which is used to deploy contracts,
// Constructors is typechain-generated class that contains all the constructors of the contract
const factory = new Constructors(api, UserAlice);
// You can access to the different constructors using the name of the constructor, here we will use "new"
const {result, address} = await factory.new('10', {});
// Here we are creating an instance of the Contract class, which is used to interact with the deployed contract
contract = new Contract(address, UserAlice, api);
Contract is the main namespace for interacting with contracts. It contains all the functions that are related to contracts.
const contract = new Contract(
address,
signer,
nativeAPI,
)
contract.name() // get the name of the contract
contract.address() // get the address of the contract
contract.abi() // get the abi of the contract
contract.<namespace>.<functionName>(...args, options) // call a function from a namespace
// namespace can be tx, query, events, etc.
contract.withSigner(signer)
// change the signer of the contract in the current context,
// basically it will create a new contract with the new signer
contract.withAddress(address)
// change the address of the contract in the current context,
// basically it will create a new contract with the new address
// useful for proxy contracts
contract.withAPI(api)
// change the api of the contract in the current context
// basically it will create a new contract with the new api
Utility file. Contains all info about types. It's used in runtime to parse return values from contracts.
This namespace contains both tx and query methods.
contract.mixedMethods.<functionName>(...args, options)
This namepsace contains all query methods
const result = contract.query.<functionName>(...args, options)
console.log(result.value)
You can also use it to get errors from contracts
try {
await contract.withSigner(UserBob).query.transfer(UserAlice.address, '10', []);
} catch ({ _err }) {
console.log(_err);
}
console.log
{ insufficientBalance: null }
This namespace is used send transactions.
const result = await contract.tx.<functionName>(...args, options)
You can also use typechain-polkadot as a library. To use it, you need to import it in your code:
import {Typechain} from '@dpowxconsensus/typechain-polkadot/src/types/typechain';
import {testPathPatternToRegExp} from "jest-util";
const typechain = new Typechain();
typechain.loadDefaultPlugins();
typechain.run(
pathToInput,
pathToOutput
)
Typechain-polkadot uses plugins to generate code. By default, it uses the following plugins:
- build-extrinsic docs
- constructors docs
- contract docs
- data docs
- events docs
- events-types docs
- mixed-methods docs
- query docs
- tx-sign-and-send docs
You can also create your own plugins to add some custom logic to the typechain-polkadot. To do this, you need to create a class that implements the TypechainPlugin
interface:
import {TypechainPlugin} from '@dpowxconsensus/typechain-polkadot/src/types/interfaces';
import {Abi} from "@polkadot/api-contract";
/**
* generates a contract file
*
* @param abi - The ABI of the contract
* @param fileName - The name of the file to write to
* @param absPathToOutput - The absolute path to the output directory
* @param absPathToABIs - The absolute path to the ABIs directory
*/
function generate(abi: Abi, fileName: string, absPathToOutput: string, absPathToABIs: string) {
console.log('Hello World!');
}
export default class HelloWorldPlugin implements TypechainPlugin {
name: string = 'HelloWorld';
outputDir: string = 'HelloWorld';
generate(abi: Abi, fileName: string, absPathToABIs: string, absPathToOutput: string): void {
generate(abi, fileName, absPathToOutput, absPathToABIs);
}
}
Then you need to add your plugin to the list of plugins:
typechain.loadPlugins(new MyPlugin());
Or you can load them via cli:
npx @dpowxconsensus/typechain-polkadot --input path/to/abis --output path/to/output --plugins ./plugins-directory
Note: if you're using the cli, every plugin should end with
.plugin.ts
and have default export of the plugin itself.
Also you can use loadPluginsFromFiles
method to load plugins from files:
typechain.loadPluginsFromFiles(
'./plugins-directory'
)
You can find an example of plugins usage in the examples directory.