Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add auto generated tfchain types to tfchain_client #3020

Merged
merged 8 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading