Skip to content

Commit

Permalink
Merge pull request #3020 from threefoldtech/development_chainTypes
Browse files Browse the repository at this point in the history
Add auto generated tfchain types to tfchain_client
  • Loading branch information
0oM4R authored Jul 2, 2024
2 parents f32a697 + 8576aac commit 9b27d34
Show file tree
Hide file tree
Showing 22 changed files with 13,922 additions and 14 deletions.
86 changes: 86 additions & 0 deletions packages/tfchain_client/docs/generateTypes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Generating Chain Types

This guide covers the steps to generate chain types using `@polkadot/typegen` and how to use these generated types in this project.

## Process:

Inside tfchain_client directory run:

```bash
yarn generate-types -e <<CHAIN_URL>>
```
> replace `<<CHAIN_URL>>` with URL of the desired chain stack, e.g. `https://tfchain.dev.grid.tf/`
> This will update the metadata file `chainMeta.json`, generate types inside `interfaces/chain` and adjust the created types to be compatible with TypeScript compiler.
## Details:
- Generate a chain types requires `@polkadot/typegen` package of the same version as `@polkadot/api`.
### Generating
First we need to have chain metadata, to generate types based on it, this is done by running the following command:
```bash
curl -H "Content-Type: application/json" -d '{"id":"1", "jsonrpc":"2.0", "method": "state_getMetadata", "params":[]}' -o chainMeta.json <<CHAIN_URL>>
```
The result of this command will be `chainMeta.json` with a content like
```json
{ "jsonrpc": "2.0", "result": "0x6d6574610b6c185379737....", "id": 29 }
```
This file will be used in the following two commands:
- Generate defined chain types and lookup files using `polkadot-types-from-defs `
```bash
ts-node --skip-project node_modules/.bin/polkadot-types-from-defs --package @threefold/tfchain_client --input ./src/interfaces/chain --endpoint ./chainMeta.json
```
> Currently we don't have defined types but this command needed to crate the lookup files, for more details see the [documentation](https://polkadot.js.org/docs/api/start/typescript.user/#definitions)
- Generate types from the chain using `polkadot-types-from-chain`
```bash
ts-node --skip-project node_modules/.bin/polkadot-types-from-chain --endpoint ./chainMeta.json --output ./src/interfaces/chain
```
Now types are generated, but we need to let the compiler aware of the generated types, we can do that by add the following paths to `tsconfig-*.json` inside compilerOptions.paths add those lines:
```json
"@polkadot/types/lookup": ["src/interfaces/chain/types-lookup.ts"],
"@polkadot/api-augment*": ["src/interfaces/chain/augment-api.ts"]
```
Finally we need to export the generated types
in `src/interfaces/index.ts`
```ts
export * from "./chain/augment-api";
export * from "./chain/types-lookup";
export * from "./chain/lookup";
```
### Usage
We need to import the augmented definitions "somewhere" as documentation says, in our case we will import them in `src/client`.
```ts
import "./interfaces";
import "@polkadot/api-augment";
```
Now we can import any type anywhere in the client as follows:
```ts
// e.g SpRuntimeModuleError
import { SpRuntimeModuleError } from "@polkadot/types/lookup";
```
There are two blockers now from building the project:
1. As we don't have any defined types `src/interfaces/chain/types` is empty and will give an error while build, for now we just need to export an empty object on it so we add `export {}` to the file.
2. Types with reserved names:
In `src/interfaces/chain/augment-api-tx.ts` we have `createFarmingPolicy` and `updateFarmingPolicy` functions in tfgridmodule each of them contains parameter named `default` this is not acceptable on Typescript as it is a reserved word, so we could replace it with `_default`.
> All the previous steps are collected into `scripts/generateTypes.bash`
Now everything is ready to go
6 changes: 4 additions & 2 deletions packages/tfchain_client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"node-build": "tsc --build tsconfig-node.json",
"es6-build": "tsc --build tsconfig-es6.json",
"generate-docs": "typedoc --tsconfig tsconfig-es6.json src/index.ts --out docs/api",
"serve-docs": "http-server docs/api"
"serve-docs": "http-server docs/api",
"generate-types" : "bash ./scripts/generateTypes.bash"
},
"repository": {
"type": "git",
Expand Down Expand Up @@ -42,7 +43,8 @@
"npm-run-all": "^4.1.5",
"ts-node": "^10.9.1",
"typedoc": "^0.23.28",
"typescript": "^5.0.2"
"typescript": "^5.0.2",
"@polkadot/typegen": "^8.9.1"
},
"dependencies": {
"@polkadot/api": "^8.9.1",
Expand Down
49 changes: 49 additions & 0 deletions packages/tfchain_client/scripts/generateTypes.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
set -e
while getopts e: flag
do
case "${flag}" in
e) endpoint=${OPTARG};;
esac
done

if [ -n "$endpoint" ]; then
echo "Generating meta data from $endpoint";
else
echo "endpoint url is required, please use -e flag";
exit 1
fi


outputFile="chainMeta.json"
echo "meta destination file: '$outputFile'"

generateDefs="ts-node --skip-project node_modules/.bin/polkadot-types-from-defs --package @threefold/tfchain_client --input ./src/interfaces/chain --endpoint ./chainMeta.json"
generateMeta="ts-node --skip-project node_modules/.bin/polkadot-types-from-chain --endpoint ./chainMeta.json --output ./src/interfaces/chain"

err=$(curl -H "Content-Type: application/json" -d '{"id":"1", "jsonrpc":"2.0", "method": "state_getMetadata", "params":[]}' -o $outputFile $endpoint 2>&1)

if [[ $? -ne 0 ]]; then
echo "Failed to fetch chain metadata due to error: '$err'"
fi

echo "updating node modules.."
yarn

echo "Generating chain types.."
${generateDefs} && ${generateMeta}


echo "Adjusting files..."

if [ -f "./src/interfaces/chain/types.ts" ] && ! grep -q export "./src/interfaces/chain/types.ts"; then
echo "export {}" >> ./src/interfaces/chain/types.ts
fi

stringToReplace="default: bool | boolean | Uint8Array,"
stringToBeReplaced="_default: bool | boolean | Uint8Array,"
if [ -f "./src/interfaces/chain/augment-api-tx.ts" ]; then
sed -i "s#$stringToReplace#$stringToBeReplaced#g" src/interfaces/chain/augment-api-tx.ts
fi

echo "Success!"
exit 0
3 changes: 3 additions & 0 deletions packages/tfchain_client/src/client.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import "./interfaces";
import "@polkadot/api-augment";

import { ApiPromise, WsProvider } from "@polkadot/api";
import { Signer } from "@polkadot/api/types";
import { SubmittableExtrinsic } from "@polkadot/api-base/types";
Expand Down
212 changes: 212 additions & 0 deletions packages/tfchain_client/src/interfaces/chain/augment-api-consts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
// Auto-generated via `yarn polkadot-types-from-chain`, do not edit
/* eslint-disable */

// import type lookup before we augment - in some environments
// this is required to allow for ambient/previous definitions
import "@polkadot/api-base/types/consts";

import type { ApiTypes, AugmentedConst } from "@polkadot/api-base/types";
import type { u128, u16, u32, u64, u8 } from "@polkadot/types-codec";
import type { Codec } from "@polkadot/types-codec/types";
import type {
FrameSystemLimitsBlockLength,
FrameSystemLimitsBlockWeights,
SpVersionRuntimeVersion,
SpWeightsRuntimeDbWeight,
SpWeightsWeightV2Weight,
} from "@polkadot/types/lookup";

export type __AugmentedConst<ApiType extends ApiTypes> = AugmentedConst<ApiType>;

declare module "@polkadot/api-base/types/consts" {
interface AugmentedConsts<ApiType extends ApiTypes> {
balances: {
/**
* The minimum amount required to keep an account open. MUST BE GREATER THAN ZERO!
*
* If you *really* need it to be zero, you can enable the feature `insecure_zero_ed` for
* this pallet. However, you do so at your own risk: this will open up a major DoS vector.
* In case you have multiple sources of provider references, you may also get unexpected
* behaviour if you set this to zero.
*
* Bottom line: Do yourself a favour and make it at least one!
**/
existentialDeposit: u128 & AugmentedConst<ApiType>;
/**
* The maximum number of individual freeze locks that can exist on an account at any time.
**/
maxFreezes: u32 & AugmentedConst<ApiType>;
/**
* The maximum number of holds that can exist on an account at any time.
**/
maxHolds: u32 & AugmentedConst<ApiType>;
/**
* The maximum number of locks that should exist on an account.
* Not strictly enforced, but used for weight estimation.
**/
maxLocks: u32 & AugmentedConst<ApiType>;
/**
* The maximum number of named reserves that can exist on an account.
**/
maxReserves: u32 & AugmentedConst<ApiType>;
/**
* Generic const
**/
[key: string]: Codec;
};
council: {
/**
* The maximum weight of a dispatch call that can be proposed and executed.
**/
maxProposalWeight: SpWeightsWeightV2Weight & AugmentedConst<ApiType>;
/**
* Generic const
**/
[key: string]: Codec;
};
grandpa: {
/**
* Max Authorities in use
**/
maxAuthorities: u32 & AugmentedConst<ApiType>;
/**
* The maximum number of entries to keep in the set id to session index mapping.
*
* Since the `SetIdSession` map is only used for validating equivocations this
* value should relate to the bonding duration of whatever staking system is
* being used (if any). If equivocation handling is not enabled then this value
* can be zero.
**/
maxSetIdSessionEntries: u64 & AugmentedConst<ApiType>;
/**
* Generic const
**/
[key: string]: Codec;
};
scheduler: {
/**
* The maximum weight that may be scheduled per block for any dispatchables.
**/
maximumWeight: SpWeightsWeightV2Weight & AugmentedConst<ApiType>;
/**
* The maximum number of scheduled calls in the queue for a single block.
*
* NOTE:
* + Dependent pallets' benchmarks might require a higher limit for the setting. Set a
* higher limit under `runtime-benchmarks` feature.
**/
maxScheduledPerBlock: u32 & AugmentedConst<ApiType>;
/**
* Generic const
**/
[key: string]: Codec;
};
smartContractModule: {
maxDeploymentDataLength: u32 & AugmentedConst<ApiType>;
maxNameContractNameLength: u32 & AugmentedConst<ApiType>;
maxNodeContractPublicIps: u32 & AugmentedConst<ApiType>;
/**
* Generic const
**/
[key: string]: Codec;
};
system: {
/**
* Maximum number of block number to block hash mappings to keep (oldest pruned first).
**/
blockHashCount: u32 & AugmentedConst<ApiType>;
/**
* The maximum length of a block (in bytes).
**/
blockLength: FrameSystemLimitsBlockLength & AugmentedConst<ApiType>;
/**
* Block & extrinsics weights: base values and limits.
**/
blockWeights: FrameSystemLimitsBlockWeights & AugmentedConst<ApiType>;
/**
* The weight of runtime database operations the runtime can invoke.
**/
dbWeight: SpWeightsRuntimeDbWeight & AugmentedConst<ApiType>;
/**
* The designated SS58 prefix of this chain.
*
* This replaces the "ss58Format" property declared in the chain spec. Reason is
* that the runtime should know about the prefix in order to make use of it as
* an identifier of the chain.
**/
ss58Prefix: u16 & AugmentedConst<ApiType>;
/**
* Get the chain's current version.
**/
version: SpVersionRuntimeVersion & AugmentedConst<ApiType>;
/**
* Generic const
**/
[key: string]: Codec;
};
tfgridModule: {
maxFarmNameLength: u32 & AugmentedConst<ApiType>;
maxFarmPublicIps: u32 & AugmentedConst<ApiType>;
maxInterfaceIpsLength: u32 & AugmentedConst<ApiType>;
maxInterfacesLength: u32 & AugmentedConst<ApiType>;
timestampHintDrift: u64 & AugmentedConst<ApiType>;
/**
* Generic const
**/
[key: string]: Codec;
};
timestamp: {
/**
* The minimum period between blocks. Beware that this is different to the *expected*
* period that the block production apparatus provides. Your chosen consensus system will
* generally work with this to determine a sensible block time. e.g. For Aura, it will be
* double this period on default settings.
**/
minimumPeriod: u64 & AugmentedConst<ApiType>;
/**
* Generic const
**/
[key: string]: Codec;
};
transactionPayment: {
/**
* A fee mulitplier for `Operational` extrinsics to compute "virtual tip" to boost their
* `priority`
*
* This value is multipled by the `final_fee` to obtain a "virtual tip" that is later
* added to a tip component in regular `priority` calculations.
* It means that a `Normal` transaction can front-run a similarly-sized `Operational`
* extrinsic (with no tip), by including a tip value greater than the virtual tip.
*
* ```rust,ignore
* // For `Normal`
* let priority = priority_calc(tip);
*
* // For `Operational`
* let virtual_tip = (inclusion_fee + tip) * OperationalFeeMultiplier;
* let priority = priority_calc(tip + virtual_tip);
* ```
*
* Note that since we use `final_fee` the multiplier applies also to the regular `tip`
* sent with the transaction. So, not only does the transaction get a priority bump based
* on the `inclusion_fee`, but we also amplify the impact of tips applied to `Operational`
* transactions.
**/
operationalFeeMultiplier: u8 & AugmentedConst<ApiType>;
/**
* Generic const
**/
[key: string]: Codec;
};
utility: {
/**
* The limit on the number of batched calls.
**/
batchedCallsLimit: u32 & AugmentedConst<ApiType>;
/**
* Generic const
**/
[key: string]: Codec;
};
} // AugmentedConsts
} // declare module
Loading

0 comments on commit 9b27d34

Please sign in to comment.