@dedot/cli 0.18.7 → 1.0.0-next.a0f8d41e.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,6 +7,8 @@ type Args = {
7
7
  subpath?: boolean;
8
8
  wasm?: string;
9
9
  metadata?: string;
10
+ at?: string;
11
+ specVersion?: number;
10
12
  };
11
13
  export declare const chaintypes: CommandModule<Args, Args>;
12
14
  export {};
@@ -1,13 +1,20 @@
1
- import { generateTypes, generateTypesFromEndpoint } from '@dedot/codegen';
1
+ import { DedotClient } from '@dedot/api';
2
+ import { generateTypes, generateTypesFromEndpoint, resolveBlockHash } from '@dedot/codegen';
3
+ import { WsProvider } from '@dedot/providers';
2
4
  import { stringCamelCase, stringPascalCase } from '@dedot/utils';
3
5
  import ora from 'ora';
4
6
  import * as path from 'path';
5
- import { parseMetadataFromRaw, parseMetadataFromWasm, parseStaticSubstrate } from './utils.js';
7
+ import { parseMetadataFromRaw, parseMetadataFromWasm, parseStaticSubstrate, findBlockFromSpecVersion, } from './utils.js';
8
+ const shortenHash = (hash, prefixLen = 6, suffixLen = 6) => {
9
+ if (hash.length <= prefixLen + suffixLen + 2)
10
+ return hash;
11
+ return `${hash.slice(0, prefixLen + 2)}...${hash.slice(-suffixLen)}`;
12
+ };
6
13
  export const chaintypes = {
7
14
  command: 'chaintypes',
8
15
  describe: 'Generate Types & APIs for Substrate-based chains',
9
16
  handler: async (yargs) => {
10
- const { wsUrl, wasm, metadata, output = '', chain = '', dts = true, subpath = true } = yargs;
17
+ let { wsUrl, wasm, metadata, output = '', chain = '', dts = true, subpath = true, at, specVersion } = yargs;
11
18
  const outDir = path.resolve(output);
12
19
  const extension = dts ? 'd.ts' : 'ts';
13
20
  const spinner = ora().start();
@@ -30,17 +37,67 @@ export const chaintypes = {
30
37
  parsedResult = await parseStaticSubstrate();
31
38
  spinner.succeed(`Parsed static substrate generic chaintypes`);
32
39
  }
40
+ spinner.start();
33
41
  if (parsedResult) {
34
42
  const { metadata, runtimeVersion, rpcMethods } = parsedResult;
35
43
  const chainName = chain || stringCamelCase(runtimeVersion.specName) || (shouldGenerateGenericTypes ? 'substrate' : 'local');
36
44
  spinner.text = `Generating ${stringPascalCase(chainName)} generic chaintypes`;
37
- generatedResult = await generateTypes(chainName, metadata.latest, rpcMethods, runtimeVersion, outDir, extension, subpath);
45
+ generatedResult = await generateTypes({
46
+ chain: chainName,
47
+ metadata: metadata.latest,
48
+ rpcMethods,
49
+ runtimeVersion,
50
+ outDir,
51
+ extension,
52
+ useSubPaths: subpath,
53
+ });
38
54
  spinner.succeed(`Generated ${stringPascalCase(chainName)} generic chaintypes`);
39
55
  }
40
56
  else {
41
- spinner.text = `Generating chaintypes via endpoint: ${wsUrl}`;
42
- generatedResult = await generateTypesFromEndpoint(chain, wsUrl, outDir, extension, subpath);
43
- spinner.succeed(`Generated chaintypes via endpoint: ${wsUrl}`);
57
+ // Create client once and reuse for both operations
58
+ spinner.text = `Connecting to network: ${wsUrl} ...`;
59
+ const client = await DedotClient.legacy(new WsProvider({ endpoint: wsUrl }));
60
+ spinner.succeed(`Connected to network: ${wsUrl}`);
61
+ try {
62
+ let blockNumber;
63
+ if (specVersion) {
64
+ spinner.start();
65
+ spinner.text = `Resolving block hash for spec version ${specVersion}...`;
66
+ const result = await findBlockFromSpecVersion(client, specVersion);
67
+ at = result.blockHash;
68
+ blockNumber = result.blockNumber;
69
+ spinner.succeed(`Resolved block hash ${shortenHash(at)} (#${blockNumber}) for spec version ${specVersion}`);
70
+ }
71
+ spinner.start();
72
+ let atText = '';
73
+ if (at) {
74
+ let blockHash;
75
+ if (blockNumber === undefined) {
76
+ // at was provided directly by user, resolve it to block hash
77
+ blockHash = await resolveBlockHash(client, at);
78
+ const header = await client.block.header(blockHash);
79
+ blockNumber = header?.number;
80
+ }
81
+ else {
82
+ // blockNumber is already set from spec resolution, at is the block hash
83
+ blockHash = at;
84
+ }
85
+ atText = ` at ${shortenHash(blockHash)} (#${blockNumber ?? 'unknown'})`;
86
+ }
87
+ spinner.text = `Generating chaintypes via endpoint: ${wsUrl}${atText}`;
88
+ generatedResult = await generateTypesFromEndpoint({
89
+ chain,
90
+ client,
91
+ outDir,
92
+ extension,
93
+ useSubPaths: subpath,
94
+ at,
95
+ });
96
+ spinner.succeed(`Generated chaintypes via endpoint: ${wsUrl}${atText}`);
97
+ }
98
+ finally {
99
+ await client.disconnect();
100
+ }
44
101
  }
45
102
  const { interfaceName, outputFolder } = generatedResult;
46
103
  console.log(` ➡ Output directory: file://${outputFolder}`);
@@ -60,6 +117,7 @@ export const chaintypes = {
60
117
  else {
61
118
  spinner.fail(`Failed to generate chaintypes via endpoint: ${wsUrl}`);
62
119
  }
120
+ console.error(`Error details: ${e.message}`);
63
121
  console.error(e);
64
122
  }
65
123
  spinner.stop();
@@ -102,6 +160,16 @@ export const chaintypes = {
102
160
  describe: 'Using subpath for shared packages (e.g: dedot/types)',
103
161
  alias: 's',
104
162
  default: true,
163
+ })
164
+ .option('at', {
165
+ type: 'string',
166
+ describe: 'Block hash or block number to generate chaintypes at',
167
+ alias: 'a',
168
+ })
169
+ .option('specVersion', {
170
+ type: 'number',
171
+ describe: 'Spec version to generate chaintypes at',
172
+ alias: 'x',
105
173
  })
106
174
  .check((argv) => {
107
175
  const inputs = ['wsUrl', 'wasm', 'metadata'];
@@ -112,6 +180,15 @@ export const chaintypes = {
112
180
  if (providedInputs.length === 0) {
113
181
  throw new Error(`Please provide one of the following options: ${inputs.join(', ')}`);
114
182
  }
183
+ if (argv.at && !argv.wsUrl) {
184
+ throw new Error('The --at option can only be used with --wsUrl');
185
+ }
186
+ if (argv.specVersion && !argv.wsUrl) {
187
+ throw new Error('The --specVersion option can only be used with --wsUrl');
188
+ }
189
+ if (argv.specVersion && argv.at) {
190
+ throw new Error('Please provide only one of the following options: --spec-version, --at');
191
+ }
115
192
  return true;
116
193
  });
117
194
  },
@@ -1,3 +1,4 @@
1
+ import { DedotClient } from '@dedot/api';
1
2
  import { Metadata, RuntimeVersion } from '@dedot/codecs';
2
3
  import { HexString } from '@dedot/utils';
3
4
  import { DecodedMetadataInfo, ParsedResult } from './types.js';
@@ -6,3 +7,7 @@ export declare const decodeMetadata: (metadata: HexString | Uint8Array) => Decod
6
7
  export declare const parseMetadataFromRaw: (metadataFile: string) => Promise<ParsedResult>;
7
8
  export declare const parseMetadataFromWasm: (runtimeFile: string) => Promise<ParsedResult>;
8
9
  export declare const parseStaticSubstrate: () => Promise<ParsedResult>;
10
+ export declare const findBlockFromSpecVersion: (client: DedotClient, specVersion: number) => Promise<{
11
+ blockHash: HexString;
12
+ blockNumber: number;
13
+ }>;
@@ -2,7 +2,7 @@ import { rpc } from '@polkadot/types-support/metadata/static-substrate';
2
2
  import staticSubstrate from '@polkadot/types-support/metadata/v15/substrate-hex';
3
3
  import { ConstantExecutor } from '@dedot/api';
4
4
  import { $Metadata, PortableRegistry, unwrapOpaqueMetadata } from '@dedot/codecs';
5
- import { hexToU8a, isHex } from '@dedot/utils';
5
+ import { assert, hexToU8a, isHex } from '@dedot/utils';
6
6
  import { getMetadataFromWasmRuntime } from '@dedot/wasm';
7
7
  import * as fs from 'fs';
8
8
  export const getRuntimeVersion = (metadata) => {
@@ -56,3 +56,28 @@ export const parseStaticSubstrate = async () => {
56
56
  rpcMethods: rpc.methods,
57
57
  };
58
58
  };
59
+ export const findBlockFromSpecVersion = async (client, specVersion) => {
60
+ const upperBound = client.runtimeVersion.specVersion;
61
+ const lowerBound = (await client.rpc.state_getRuntimeVersion(await client.rpc.chain_getBlockHash(0))).specVersion;
62
+ assert(specVersion >= lowerBound, `Specified specVersion ${specVersion} is lower than the earliest specVersion ${lowerBound} of the chain.`);
63
+ assert(specVersion <= upperBound, `Specified specVersion ${specVersion} is higher than the latest specVersion ${upperBound} of the chain at the current block.`);
64
+ let high = (await client.block.best()).number;
65
+ let low = 0;
66
+ while (low <= high) {
67
+ const mid = Math.floor((low + high) / 2);
68
+ const midBlockHash = await client.rpc.chain_getBlockHash(mid);
69
+ assert(midBlockHash, `Failed to get block hash at block number ${mid}`);
70
+ const midRuntimeVersion = await client.rpc.state_getRuntimeVersion(midBlockHash);
71
+ const midSpecVersion = midRuntimeVersion.specVersion;
72
+ if (midSpecVersion === specVersion) {
73
+ return { blockHash: midBlockHash, blockNumber: mid };
74
+ }
75
+ else if (midSpecVersion < specVersion) {
76
+ low = mid + 1;
77
+ }
78
+ else {
79
+ high = mid - 1;
80
+ }
81
+ }
82
+ assert(false, `Could not find a block with specVersion ${specVersion}.`);
83
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dedot/cli",
3
- "version": "0.18.7",
3
+ "version": "1.0.0-next.a0f8d41e.25+a0f8d41e",
4
4
  "author": "Thang X. Vu <thang@dedot.dev>",
5
5
  "homepage": "https://dedot.dev",
6
6
  "repository": {
@@ -22,11 +22,11 @@
22
22
  "test": "npx vitest --watch=false"
23
23
  },
24
24
  "dependencies": {
25
- "@dedot/api": "0.18.7",
26
- "@dedot/codecs": "0.18.7",
27
- "@dedot/codegen": "0.18.7",
25
+ "@dedot/api": "1.0.0-next.a0f8d41e.25+a0f8d41e",
26
+ "@dedot/codecs": "1.0.0-next.a0f8d41e.25+a0f8d41e",
27
+ "@dedot/codegen": "1.0.0-next.a0f8d41e.25+a0f8d41e",
28
28
  "@dedot/wasm": "^0.1.0",
29
- "@polkadot/types-support": "^16.4.6",
29
+ "@polkadot/types-support": "^16.5.3",
30
30
  "ora": "^8.2.0",
31
31
  "yargs": "^17.7.2"
32
32
  },
@@ -41,7 +41,7 @@
41
41
  "node": ">=18"
42
42
  },
43
43
  "license": "Apache-2.0",
44
- "gitHead": "07f47f75512087407e03f301fc18c2059b3f613a",
44
+ "gitHead": "a0f8d41e632a44c03ccc31ee77bcb7d19df936e9",
45
45
  "module": "./index.js",
46
46
  "types": "./index.d.ts"
47
47
  }