@talismn/scale 0.1.0 → 0.1.2

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.
@@ -1,6 +1,6 @@
1
1
  export { getDynamicBuilder, getLookupFn } from "@polkadot-api/metadata-builders";
2
- export type { V14, V15, V15Extrinsic, Codec, Binary } from "@polkadot-api/substrate-bindings";
2
+ export type { Codec, UnifiedMetadata } from "@polkadot-api/substrate-bindings";
3
+ export { decAnyMetadata, unifyMetadata, metadata } from "@polkadot-api/substrate-bindings";
3
4
  export { toHex, fromHex } from "@polkadot-api/utils";
4
5
  /** Constant: https://docs.substrate.io/build/application-development/#metadata-format */
5
6
  export declare const magicNumber = 1635018093;
6
- export { v14, v15, metadata } from "@polkadot-api/substrate-bindings";
@@ -0,0 +1,3 @@
1
+ export type Prettify<T> = {
2
+ [K in keyof T]: T[K];
3
+ } & {};
@@ -1,10 +1,11 @@
1
- import { V14, V15 } from "../papito";
2
- export type V14Type = V14["lookup"][0];
3
- export type V14Pallet = V14["pallets"][0];
4
- export type V14StorageItem = NonNullable<V14Pallet["storage"]>["items"][0];
5
- export type V15Type = V15["lookup"][0];
6
- export type V15Pallet = V15["pallets"][0];
7
- export type V15StorageItem = NonNullable<V15Pallet["storage"]>["items"][0];
1
+ import { Metadata } from "@polkadot-api/substrate-bindings";
2
+ export type MetadataType = SupportedMetadata["lookup"][number];
3
+ export type MetadataPallet = SupportedMetadata["pallets"][number];
4
+ export type MetadataStorageItem = NonNullable<MetadataPallet["storage"]>["items"][number];
5
+ type SupportedMetadata = Extract<Metadata["metadata"], {
6
+ tag: SupportedMetadataVersion;
7
+ }>["value"];
8
+ type SupportedMetadataVersion = "v14" | "v15" | "v16";
8
9
  /**
9
10
  * Converts a `Metadata` into a `MiniMetadata`.
10
11
  *
@@ -14,7 +15,12 @@ export type V15StorageItem = NonNullable<V15Pallet["storage"]>["items"][0];
14
15
  * E.g. if `palletsAndItems` is `{ pallet: "System", items: ["Account"] }`, then only the
15
16
  * types used in the `System.Account` storage query will remain inside of metadata.lookups.
16
17
  */
17
- export declare const compactMetadata: (metadata: V15 | V14, palletsAndItems: Array<{
18
+ export declare const compactMetadata: (anyMetadata: Metadata, palletsAndItems?: Array<{
18
19
  pallet: string;
20
+ constants?: string[];
19
21
  items: string[];
22
+ }>, runtimeApisAndMethods?: Array<{
23
+ runtimeApi: string;
24
+ methods: string[];
20
25
  }>, extraKeepTypes?: number[]) => void;
26
+ export {};
@@ -1,8 +1,2 @@
1
- import { V14, V15 } from "@polkadot-api/substrate-bindings";
2
- export declare const encodeMetadata: ({ metadata, tag, }: {
3
- metadata: V15;
4
- tag: "v15";
5
- } | {
6
- metadata: V14;
7
- tag: "v14";
8
- }) => string;
1
+ import { Metadata } from "@polkadot-api/substrate-bindings";
2
+ export declare const encodeMetadata: (metadata: Metadata) => string;
@@ -1,5 +1,4 @@
1
1
  export * from "./compactMetadata";
2
- export * from "./decodeMetadata";
3
2
  export * from "./decodeScale";
4
3
  export * from "./encodeMetadata";
5
4
  export * from "./encodeStateKey";
@@ -26,4 +26,5 @@
26
26
  * Output: `Enum("Stellar", { code: Binary.fromText("TZS"), issuer: Binary.fromHex("0x34c94b2a4ba9e8b57b22547dcbb30f443c4cb02da3829a89aa1bd4780e4466ba") })`
27
27
  */
28
28
  export declare const papiParse: <T = unknown>(text: string | T) => T;
29
- export declare const papiStringify: (value: any, space?: string | number) => string;
29
+ export declare const papiStringify: (value: any, // eslint-disable-line @typescript-eslint/no-explicit-any
30
+ space?: string | number) => string;
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  var metadataBuilders = require('@polkadot-api/metadata-builders');
4
- var utils = require('@polkadot-api/utils');
5
4
  var substrateBindings = require('@polkadot-api/substrate-bindings');
5
+ var utils = require('@polkadot-api/utils');
6
6
  var anylogger = require('anylogger');
7
7
  var scaleTs = require('scale-ts');
8
8
 
@@ -14,55 +14,7 @@ var anylogger__default = /*#__PURE__*/_interopDefault(anylogger);
14
14
  const magicNumber = 1635018093;
15
15
 
16
16
  var packageJson = {
17
- name: "@talismn/scale",
18
- version: "0.1.0",
19
- author: "Talisman",
20
- homepage: "https://talisman.xyz",
21
- license: "GPL-3.0-or-later",
22
- publishConfig: {
23
- access: "public"
24
- },
25
- repository: {
26
- directory: "packages/scale",
27
- type: "git",
28
- url: "https://github.com/talismansociety/talisman.git"
29
- },
30
- main: "dist/talismn-scale.cjs.js",
31
- module: "dist/talismn-scale.esm.js",
32
- files: [
33
- "/dist"
34
- ],
35
- engines: {
36
- node: ">=18"
37
- },
38
- scripts: {
39
- test: "jest",
40
- lint: "eslint src --max-warnings 0",
41
- clean: "rm -rf dist .turbo node_modules"
42
- },
43
- dependencies: {
44
- "@polkadot-api/metadata-builders": "0.9.1",
45
- "@polkadot-api/substrate-bindings": "0.9.3",
46
- "@polkadot-api/utils": "0.1.2",
47
- anylogger: "^1.0.11",
48
- "scale-ts": "^1.6.1"
49
- },
50
- devDependencies: {
51
- "@talismn/eslint-config": "workspace:*",
52
- "@talismn/tsconfig": "workspace:*",
53
- "@types/jest": "^29.5.14",
54
- eslint: "^8.57.1",
55
- jest: "^29.7",
56
- "ts-jest": "^29.2.5",
57
- typescript: "^5.6.3"
58
- },
59
- eslintConfig: {
60
- root: true,
61
- "extends": [
62
- "@talismn/eslint-config/base"
63
- ]
64
- }
65
- };
17
+ name: "@talismn/scale"};
66
18
 
67
19
  var log = anylogger__default.default(packageJson.name);
68
20
 
@@ -75,7 +27,10 @@ var log = anylogger__default.default(packageJson.name);
75
27
  * E.g. if `palletsAndItems` is `{ pallet: "System", items: ["Account"] }`, then only the
76
28
  * types used in the `System.Account` storage query will remain inside of metadata.lookups.
77
29
  */
78
- const compactMetadata = (metadata, palletsAndItems, extraKeepTypes) => {
30
+ const compactMetadata = (anyMetadata, palletsAndItems = [], runtimeApisAndMethods = [], extraKeepTypes = []) => {
31
+ if (!isCompactableMetadata(anyMetadata)) throw new Error(`Metadata version ${anyMetadata.metadata.tag} not supported in compactMetadata`);
32
+ const metadata = anyMetadata.metadata.value;
33
+
79
34
  // remove pallets we don't care about
80
35
  metadata.pallets = metadata.pallets.filter(pallet =>
81
36
  // keep this pallet if it's listed in `palletsAndItems`
@@ -84,8 +39,9 @@ const compactMetadata = (metadata, palletsAndItems, extraKeepTypes) => {
84
39
  }) => pallet.name === palletName));
85
40
 
86
41
  // remove fields we don't care about from each pallet, and extract types for each storage item we care about
87
- const items = palletsAndItems.flatMap(({
42
+ const palletsKeepTypes = palletsAndItems.flatMap(({
88
43
  pallet: palletName,
44
+ constants: constantNames,
89
45
  items: itemNames
90
46
  }) => {
91
47
  const pallet = metadata.pallets.find(pallet => pallet.name === palletName);
@@ -96,7 +52,7 @@ const compactMetadata = (metadata, palletsAndItems, extraKeepTypes) => {
96
52
 
97
53
  // remove pallet fields we don't care about
98
54
  pallet.calls = undefined;
99
- pallet.constants = [];
55
+ pallet.constants = constantNames ? pallet.constants.filter(constant => constantNames.includes(constant.name)) : [];
100
56
  // v15 (NOT v14) has docs
101
57
  if ("docs" in pallet) pallet.docs = [];
102
58
  pallet.errors = undefined;
@@ -105,19 +61,54 @@ const compactMetadata = (metadata, palletsAndItems, extraKeepTypes) => {
105
61
 
106
62
  // filter and extract storage items we care about
107
63
  pallet.storage.items = pallet.storage.items.filter(item => itemNames.some(itemName => item.name === itemName));
108
- return pallet.storage.items;
64
+ return [...pallet.storage.items.flatMap(item => [
65
+ // each type can be either "Plain" or "Map"
66
+ // if it's "Plain" we only need to get the value type
67
+ // if it's a "Map" we want to keep both the key AND the value types
68
+ item.type.tag === "plain" && item.type.value, item.type.tag === "map" && item.type.value.key, item.type.tag === "map" && item.type.value.value]).filter(type => typeof type === "number"), ...pallet.constants.flatMap(constant => constant.type)];
109
69
  });
110
70
 
71
+ // remove runtime apis we don't care about
72
+ let runtimeApisKeepTypes = [];
73
+ if ("apis" in metadata) {
74
+ // metadata is v15 (NOT v14)
75
+
76
+ // keep this api if it's listed in `runtimeApisAndMethods`
77
+ metadata.apis = metadata.apis.filter(runtimeApi => runtimeApisAndMethods.some(({
78
+ runtimeApi: runtimeApiName
79
+ }) => runtimeApi.name === runtimeApiName));
80
+
81
+ // remove methods we don't care about from each runtime api, and extract types for each call's params and result
82
+ runtimeApisKeepTypes = runtimeApisAndMethods.flatMap(({
83
+ runtimeApi: runtimeApiName,
84
+ methods: methodNames
85
+ }) => {
86
+ const runtimeApi = metadata.apis.find(runtimeApi => runtimeApi.name === runtimeApiName);
87
+ if (!runtimeApi) {
88
+ log.debug("Failed to find runtimeApi", runtimeApiName);
89
+ return [];
90
+ }
91
+
92
+ // remove runtime fields we don't care about
93
+ runtimeApi.docs = [];
94
+ if (!runtimeApi.methods) return [];
95
+
96
+ // filter and extract methods we care about
97
+ runtimeApi.methods = runtimeApi.methods.filter(method => methodNames.some(methodName => method.name === methodName));
98
+ return runtimeApi.methods.flatMap(method => [
99
+ // each method has an array of input types (for the params)
100
+ ...method.inputs.map(input => input.type),
101
+ // and one output type (for the result)
102
+ method.output]);
103
+ });
104
+ }
105
+
111
106
  // this is a set of type ids which we plan to keep in our compacted metadata
112
107
  // anything not in this set will be deleted
113
108
  // we start off with just the types of the state calls we plan to make,
114
109
  // then we run those types through a function (addDependentTypes) which will also include
115
110
  // all of the types which those types depend on - recursively
116
- const keepTypes = new Set(items.flatMap(item => [
117
- // each type can be either "Plain" or "Map"
118
- // if it's "Plain" we only need to get the value type
119
- // if it's a "Map" we want to keep both the key AND the value types
120
- item.type.tag === "plain" && item.type.value, item.type.tag === "map" && item.type.value.key, item.type.tag === "map" && item.type.value.value]).filter(type => typeof type === "number"));
111
+ const keepTypes = new Set([...palletsKeepTypes, ...runtimeApisKeepTypes]);
121
112
  extraKeepTypes?.forEach(type => keepTypes.add(type));
122
113
 
123
114
  // recursively find all the types which our keepTypes depend on and add them to the keepTypes set
@@ -136,20 +127,11 @@ const compactMetadata = (metadata, palletsAndItems, extraKeepTypes) => {
136
127
  return newTypeId ?? 0;
137
128
  };
138
129
  remapTypeIds(metadata, getNewTypeId);
139
-
140
- // ditch the remaining data we don't need to keep in a miniMetata
141
- if ("apis" in metadata) {
142
- // metadata is v15 (NOT v14)
143
- metadata.apis = [];
144
- }
145
- if ("address" in metadata.extrinsic) {
146
- // metadata is v15 (NOT v14)
147
- metadata.extrinsic.address = 0;
148
- metadata.extrinsic.call = 0;
149
- metadata.extrinsic.extra = 0;
150
- metadata.extrinsic.signature = 0;
151
- }
152
- metadata.extrinsic.signedExtensions = [];
130
+ if ("address" in metadata.extrinsic) metadata.extrinsic.address = 0;
131
+ if ("call" in metadata.extrinsic) metadata.extrinsic.call = 0;
132
+ if ("signature" in metadata.extrinsic) metadata.extrinsic.signature = 0;
133
+ if ("extra" in metadata.extrinsic) metadata.extrinsic.extra = 0;
134
+ if ("signedExtensions" in metadata.extrinsic) metadata.extrinsic.signedExtensions = [];
153
135
  if ("outerEnums" in metadata) {
154
136
  // metadata is v15 (NOT v14)
155
137
  metadata.outerEnums.call = 0;
@@ -157,6 +139,16 @@ const compactMetadata = (metadata, palletsAndItems, extraKeepTypes) => {
157
139
  metadata.outerEnums.event = 0;
158
140
  }
159
141
  };
142
+ const isCompactableMetadata = metadata => {
143
+ switch (metadata.metadata.tag) {
144
+ case "v14":
145
+ case "v15":
146
+ case "v16":
147
+ return true;
148
+ default:
149
+ return false;
150
+ }
151
+ };
160
152
  const addDependentTypes = (metadataTysMap, keepTypes, types,
161
153
  // Prevent stack overflow when a type references itself
162
154
  addedTypes = new Set()) => {
@@ -208,6 +200,7 @@ addedTypes = new Set()) => {
208
200
  const remapTypeIds = (metadata, getNewTypeId) => {
209
201
  remapLookupTypeIds(metadata, getNewTypeId);
210
202
  remapStorageTypeIds(metadata, getNewTypeId);
203
+ remapRuntimeApisTypeIds(metadata, getNewTypeId);
211
204
  };
212
205
  const remapLookupTypeIds = (metadata, getNewTypeId) => {
213
206
  for (const type of metadata.lookup) {
@@ -270,79 +263,59 @@ const remapStorageTypeIds = (metadata, getNewTypeId) => {
270
263
  item.type.value.value = getNewTypeId(item.type.value.value);
271
264
  }
272
265
  }
266
+ for (const constant of pallet.constants ?? []) {
267
+ constant.type = getNewTypeId(constant.type);
268
+ }
273
269
  }
274
270
  };
275
-
276
- /**
277
- * Extracts the `version` u8 from a SCALE-encoded metadata blob and returns it as a `number`.
278
- *
279
- * Only reads the first 40 bytes of the blob.
280
- */
281
- const getMetadataVersion = metadataRpc => {
282
- try {
283
- return scaleTs.Struct({
284
- magicNumber: scaleTs.u32,
285
- version: scaleTs.u8
286
- }).dec(metadataRpc).version;
287
- } catch {
288
- return 0;
271
+ const remapRuntimeApisTypeIds = (metadata, getNewTypeId) => {
272
+ for (const runtimeApi of metadata.apis) {
273
+ for (const method of runtimeApi.methods ?? []) {
274
+ for (const input of method.inputs) {
275
+ input.type = getNewTypeId(input.type);
276
+ }
277
+ method.output = getNewTypeId(method.output);
278
+ }
289
279
  }
290
280
  };
291
281
 
292
- const decodeMetadata = metadataRpc => {
293
- const metadataVersion = getMetadataVersion(metadataRpc);
294
- if (metadataVersion !== 15 && metadataVersion !== 14) return {
295
- metadataVersion
296
- };
297
- const decoded = substrateBindings.metadata.dec(metadataRpc);
298
- if (decoded.metadata.tag === "v15") return {
299
- metadataVersion,
300
- metadata: decoded.metadata.value,
301
- tag: decoded.metadata.tag
302
- };
303
- if (decoded.metadata.tag === "v14") return {
304
- metadataVersion,
305
- metadata: decoded.metadata.value,
306
- tag: decoded.metadata.tag
307
- };
308
- return {
309
- metadataVersion
310
- };
311
- };
312
-
313
282
  const decodeScale = (scaleCoder, change, error) => {
314
283
  if (change === null) return null;
315
284
  try {
316
- return scaleCoder?.dec(change) ?? null;
285
+ return scaleCoder?.value?.dec(change) ?? null;
317
286
  } catch (cause) {
318
287
  log.warn(error ?? `Failed to decode ${change}`, cause);
319
288
  return null;
320
289
  }
321
290
  };
322
291
 
323
- const encodeMetadata = ({
324
- metadata,
325
- tag
326
- }) => utils.toHex(substrateBindings.metadata.enc({
327
- magicNumber,
328
- metadata: tag === "v15" ? {
329
- tag,
330
- value: metadata
331
- } : {
332
- tag,
333
- value: metadata
334
- }
335
- }));
292
+ const encodeMetadata = metadata => utils.toHex(substrateBindings.metadata.enc(metadata));
336
293
 
337
294
  const encodeStateKey = (scaleCoder, error, ...args) => {
338
295
  try {
339
- return scaleCoder?.enc(...args);
296
+ return scaleCoder?.keys?.enc(...args);
340
297
  } catch (cause) {
341
298
  log.warn(error ?? `Failed to encode stateKey ${JSON.stringify(args)}`, cause);
342
299
  return;
343
300
  }
344
301
  };
345
302
 
303
+ /**
304
+ * Extracts the `version` u8 from a SCALE-encoded metadata blob and returns it as a `number`.
305
+ *
306
+ * Only reads the first 40 bytes of the blob.
307
+ */
308
+ const getMetadataVersion = metadataRpc => {
309
+ try {
310
+ return scaleTs.Struct({
311
+ magicNumber: scaleTs.u32,
312
+ version: scaleTs.u8
313
+ }).dec(metadataRpc).version;
314
+ } catch {
315
+ return 0;
316
+ }
317
+ };
318
+
346
319
  /**
347
320
  * For the substrate-tokens (and other) modules, we configure the `onChainId` field in chaindata to tell the module how to query each token.
348
321
  * These queries are made to the tokens pallet.
@@ -400,28 +373,27 @@ Object.defineProperty(exports, "getLookupFn", {
400
373
  enumerable: true,
401
374
  get: function () { return metadataBuilders.getLookupFn; }
402
375
  });
403
- Object.defineProperty(exports, "fromHex", {
404
- enumerable: true,
405
- get: function () { return utils.fromHex; }
406
- });
407
- Object.defineProperty(exports, "toHex", {
376
+ Object.defineProperty(exports, "decAnyMetadata", {
408
377
  enumerable: true,
409
- get: function () { return utils.toHex; }
378
+ get: function () { return substrateBindings.decAnyMetadata; }
410
379
  });
411
380
  Object.defineProperty(exports, "metadata", {
412
381
  enumerable: true,
413
382
  get: function () { return substrateBindings.metadata; }
414
383
  });
415
- Object.defineProperty(exports, "v14", {
384
+ Object.defineProperty(exports, "unifyMetadata", {
416
385
  enumerable: true,
417
- get: function () { return substrateBindings.v14; }
386
+ get: function () { return substrateBindings.unifyMetadata; }
418
387
  });
419
- Object.defineProperty(exports, "v15", {
388
+ Object.defineProperty(exports, "fromHex", {
420
389
  enumerable: true,
421
- get: function () { return substrateBindings.v15; }
390
+ get: function () { return utils.fromHex; }
391
+ });
392
+ Object.defineProperty(exports, "toHex", {
393
+ enumerable: true,
394
+ get: function () { return utils.toHex; }
422
395
  });
423
396
  exports.compactMetadata = compactMetadata;
424
- exports.decodeMetadata = decodeMetadata;
425
397
  exports.decodeScale = decodeScale;
426
398
  exports.encodeMetadata = encodeMetadata;
427
399
  exports.encodeStateKey = encodeStateKey;
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  var metadataBuilders = require('@polkadot-api/metadata-builders');
4
- var utils = require('@polkadot-api/utils');
5
4
  var substrateBindings = require('@polkadot-api/substrate-bindings');
5
+ var utils = require('@polkadot-api/utils');
6
6
  var anylogger = require('anylogger');
7
7
  var scaleTs = require('scale-ts');
8
8
 
@@ -14,55 +14,7 @@ var anylogger__default = /*#__PURE__*/_interopDefault(anylogger);
14
14
  const magicNumber = 1635018093;
15
15
 
16
16
  var packageJson = {
17
- name: "@talismn/scale",
18
- version: "0.1.0",
19
- author: "Talisman",
20
- homepage: "https://talisman.xyz",
21
- license: "GPL-3.0-or-later",
22
- publishConfig: {
23
- access: "public"
24
- },
25
- repository: {
26
- directory: "packages/scale",
27
- type: "git",
28
- url: "https://github.com/talismansociety/talisman.git"
29
- },
30
- main: "dist/talismn-scale.cjs.js",
31
- module: "dist/talismn-scale.esm.js",
32
- files: [
33
- "/dist"
34
- ],
35
- engines: {
36
- node: ">=18"
37
- },
38
- scripts: {
39
- test: "jest",
40
- lint: "eslint src --max-warnings 0",
41
- clean: "rm -rf dist .turbo node_modules"
42
- },
43
- dependencies: {
44
- "@polkadot-api/metadata-builders": "0.9.1",
45
- "@polkadot-api/substrate-bindings": "0.9.3",
46
- "@polkadot-api/utils": "0.1.2",
47
- anylogger: "^1.0.11",
48
- "scale-ts": "^1.6.1"
49
- },
50
- devDependencies: {
51
- "@talismn/eslint-config": "workspace:*",
52
- "@talismn/tsconfig": "workspace:*",
53
- "@types/jest": "^29.5.14",
54
- eslint: "^8.57.1",
55
- jest: "^29.7",
56
- "ts-jest": "^29.2.5",
57
- typescript: "^5.6.3"
58
- },
59
- eslintConfig: {
60
- root: true,
61
- "extends": [
62
- "@talismn/eslint-config/base"
63
- ]
64
- }
65
- };
17
+ name: "@talismn/scale"};
66
18
 
67
19
  var log = anylogger__default.default(packageJson.name);
68
20
 
@@ -75,7 +27,10 @@ var log = anylogger__default.default(packageJson.name);
75
27
  * E.g. if `palletsAndItems` is `{ pallet: "System", items: ["Account"] }`, then only the
76
28
  * types used in the `System.Account` storage query will remain inside of metadata.lookups.
77
29
  */
78
- const compactMetadata = (metadata, palletsAndItems, extraKeepTypes) => {
30
+ const compactMetadata = (anyMetadata, palletsAndItems = [], runtimeApisAndMethods = [], extraKeepTypes = []) => {
31
+ if (!isCompactableMetadata(anyMetadata)) throw new Error(`Metadata version ${anyMetadata.metadata.tag} not supported in compactMetadata`);
32
+ const metadata = anyMetadata.metadata.value;
33
+
79
34
  // remove pallets we don't care about
80
35
  metadata.pallets = metadata.pallets.filter(pallet =>
81
36
  // keep this pallet if it's listed in `palletsAndItems`
@@ -84,8 +39,9 @@ const compactMetadata = (metadata, palletsAndItems, extraKeepTypes) => {
84
39
  }) => pallet.name === palletName));
85
40
 
86
41
  // remove fields we don't care about from each pallet, and extract types for each storage item we care about
87
- const items = palletsAndItems.flatMap(({
42
+ const palletsKeepTypes = palletsAndItems.flatMap(({
88
43
  pallet: palletName,
44
+ constants: constantNames,
89
45
  items: itemNames
90
46
  }) => {
91
47
  const pallet = metadata.pallets.find(pallet => pallet.name === palletName);
@@ -96,7 +52,7 @@ const compactMetadata = (metadata, palletsAndItems, extraKeepTypes) => {
96
52
 
97
53
  // remove pallet fields we don't care about
98
54
  pallet.calls = undefined;
99
- pallet.constants = [];
55
+ pallet.constants = constantNames ? pallet.constants.filter(constant => constantNames.includes(constant.name)) : [];
100
56
  // v15 (NOT v14) has docs
101
57
  if ("docs" in pallet) pallet.docs = [];
102
58
  pallet.errors = undefined;
@@ -105,19 +61,54 @@ const compactMetadata = (metadata, palletsAndItems, extraKeepTypes) => {
105
61
 
106
62
  // filter and extract storage items we care about
107
63
  pallet.storage.items = pallet.storage.items.filter(item => itemNames.some(itemName => item.name === itemName));
108
- return pallet.storage.items;
64
+ return [...pallet.storage.items.flatMap(item => [
65
+ // each type can be either "Plain" or "Map"
66
+ // if it's "Plain" we only need to get the value type
67
+ // if it's a "Map" we want to keep both the key AND the value types
68
+ item.type.tag === "plain" && item.type.value, item.type.tag === "map" && item.type.value.key, item.type.tag === "map" && item.type.value.value]).filter(type => typeof type === "number"), ...pallet.constants.flatMap(constant => constant.type)];
109
69
  });
110
70
 
71
+ // remove runtime apis we don't care about
72
+ let runtimeApisKeepTypes = [];
73
+ if ("apis" in metadata) {
74
+ // metadata is v15 (NOT v14)
75
+
76
+ // keep this api if it's listed in `runtimeApisAndMethods`
77
+ metadata.apis = metadata.apis.filter(runtimeApi => runtimeApisAndMethods.some(({
78
+ runtimeApi: runtimeApiName
79
+ }) => runtimeApi.name === runtimeApiName));
80
+
81
+ // remove methods we don't care about from each runtime api, and extract types for each call's params and result
82
+ runtimeApisKeepTypes = runtimeApisAndMethods.flatMap(({
83
+ runtimeApi: runtimeApiName,
84
+ methods: methodNames
85
+ }) => {
86
+ const runtimeApi = metadata.apis.find(runtimeApi => runtimeApi.name === runtimeApiName);
87
+ if (!runtimeApi) {
88
+ log.debug("Failed to find runtimeApi", runtimeApiName);
89
+ return [];
90
+ }
91
+
92
+ // remove runtime fields we don't care about
93
+ runtimeApi.docs = [];
94
+ if (!runtimeApi.methods) return [];
95
+
96
+ // filter and extract methods we care about
97
+ runtimeApi.methods = runtimeApi.methods.filter(method => methodNames.some(methodName => method.name === methodName));
98
+ return runtimeApi.methods.flatMap(method => [
99
+ // each method has an array of input types (for the params)
100
+ ...method.inputs.map(input => input.type),
101
+ // and one output type (for the result)
102
+ method.output]);
103
+ });
104
+ }
105
+
111
106
  // this is a set of type ids which we plan to keep in our compacted metadata
112
107
  // anything not in this set will be deleted
113
108
  // we start off with just the types of the state calls we plan to make,
114
109
  // then we run those types through a function (addDependentTypes) which will also include
115
110
  // all of the types which those types depend on - recursively
116
- const keepTypes = new Set(items.flatMap(item => [
117
- // each type can be either "Plain" or "Map"
118
- // if it's "Plain" we only need to get the value type
119
- // if it's a "Map" we want to keep both the key AND the value types
120
- item.type.tag === "plain" && item.type.value, item.type.tag === "map" && item.type.value.key, item.type.tag === "map" && item.type.value.value]).filter(type => typeof type === "number"));
111
+ const keepTypes = new Set([...palletsKeepTypes, ...runtimeApisKeepTypes]);
121
112
  extraKeepTypes?.forEach(type => keepTypes.add(type));
122
113
 
123
114
  // recursively find all the types which our keepTypes depend on and add them to the keepTypes set
@@ -136,20 +127,11 @@ const compactMetadata = (metadata, palletsAndItems, extraKeepTypes) => {
136
127
  return newTypeId ?? 0;
137
128
  };
138
129
  remapTypeIds(metadata, getNewTypeId);
139
-
140
- // ditch the remaining data we don't need to keep in a miniMetata
141
- if ("apis" in metadata) {
142
- // metadata is v15 (NOT v14)
143
- metadata.apis = [];
144
- }
145
- if ("address" in metadata.extrinsic) {
146
- // metadata is v15 (NOT v14)
147
- metadata.extrinsic.address = 0;
148
- metadata.extrinsic.call = 0;
149
- metadata.extrinsic.extra = 0;
150
- metadata.extrinsic.signature = 0;
151
- }
152
- metadata.extrinsic.signedExtensions = [];
130
+ if ("address" in metadata.extrinsic) metadata.extrinsic.address = 0;
131
+ if ("call" in metadata.extrinsic) metadata.extrinsic.call = 0;
132
+ if ("signature" in metadata.extrinsic) metadata.extrinsic.signature = 0;
133
+ if ("extra" in metadata.extrinsic) metadata.extrinsic.extra = 0;
134
+ if ("signedExtensions" in metadata.extrinsic) metadata.extrinsic.signedExtensions = [];
153
135
  if ("outerEnums" in metadata) {
154
136
  // metadata is v15 (NOT v14)
155
137
  metadata.outerEnums.call = 0;
@@ -157,6 +139,16 @@ const compactMetadata = (metadata, palletsAndItems, extraKeepTypes) => {
157
139
  metadata.outerEnums.event = 0;
158
140
  }
159
141
  };
142
+ const isCompactableMetadata = metadata => {
143
+ switch (metadata.metadata.tag) {
144
+ case "v14":
145
+ case "v15":
146
+ case "v16":
147
+ return true;
148
+ default:
149
+ return false;
150
+ }
151
+ };
160
152
  const addDependentTypes = (metadataTysMap, keepTypes, types,
161
153
  // Prevent stack overflow when a type references itself
162
154
  addedTypes = new Set()) => {
@@ -208,6 +200,7 @@ addedTypes = new Set()) => {
208
200
  const remapTypeIds = (metadata, getNewTypeId) => {
209
201
  remapLookupTypeIds(metadata, getNewTypeId);
210
202
  remapStorageTypeIds(metadata, getNewTypeId);
203
+ remapRuntimeApisTypeIds(metadata, getNewTypeId);
211
204
  };
212
205
  const remapLookupTypeIds = (metadata, getNewTypeId) => {
213
206
  for (const type of metadata.lookup) {
@@ -270,79 +263,59 @@ const remapStorageTypeIds = (metadata, getNewTypeId) => {
270
263
  item.type.value.value = getNewTypeId(item.type.value.value);
271
264
  }
272
265
  }
266
+ for (const constant of pallet.constants ?? []) {
267
+ constant.type = getNewTypeId(constant.type);
268
+ }
273
269
  }
274
270
  };
275
-
276
- /**
277
- * Extracts the `version` u8 from a SCALE-encoded metadata blob and returns it as a `number`.
278
- *
279
- * Only reads the first 40 bytes of the blob.
280
- */
281
- const getMetadataVersion = metadataRpc => {
282
- try {
283
- return scaleTs.Struct({
284
- magicNumber: scaleTs.u32,
285
- version: scaleTs.u8
286
- }).dec(metadataRpc).version;
287
- } catch {
288
- return 0;
271
+ const remapRuntimeApisTypeIds = (metadata, getNewTypeId) => {
272
+ for (const runtimeApi of metadata.apis) {
273
+ for (const method of runtimeApi.methods ?? []) {
274
+ for (const input of method.inputs) {
275
+ input.type = getNewTypeId(input.type);
276
+ }
277
+ method.output = getNewTypeId(method.output);
278
+ }
289
279
  }
290
280
  };
291
281
 
292
- const decodeMetadata = metadataRpc => {
293
- const metadataVersion = getMetadataVersion(metadataRpc);
294
- if (metadataVersion !== 15 && metadataVersion !== 14) return {
295
- metadataVersion
296
- };
297
- const decoded = substrateBindings.metadata.dec(metadataRpc);
298
- if (decoded.metadata.tag === "v15") return {
299
- metadataVersion,
300
- metadata: decoded.metadata.value,
301
- tag: decoded.metadata.tag
302
- };
303
- if (decoded.metadata.tag === "v14") return {
304
- metadataVersion,
305
- metadata: decoded.metadata.value,
306
- tag: decoded.metadata.tag
307
- };
308
- return {
309
- metadataVersion
310
- };
311
- };
312
-
313
282
  const decodeScale = (scaleCoder, change, error) => {
314
283
  if (change === null) return null;
315
284
  try {
316
- return scaleCoder?.dec(change) ?? null;
285
+ return scaleCoder?.value?.dec(change) ?? null;
317
286
  } catch (cause) {
318
287
  log.warn(error ?? `Failed to decode ${change}`, cause);
319
288
  return null;
320
289
  }
321
290
  };
322
291
 
323
- const encodeMetadata = ({
324
- metadata,
325
- tag
326
- }) => utils.toHex(substrateBindings.metadata.enc({
327
- magicNumber,
328
- metadata: tag === "v15" ? {
329
- tag,
330
- value: metadata
331
- } : {
332
- tag,
333
- value: metadata
334
- }
335
- }));
292
+ const encodeMetadata = metadata => utils.toHex(substrateBindings.metadata.enc(metadata));
336
293
 
337
294
  const encodeStateKey = (scaleCoder, error, ...args) => {
338
295
  try {
339
- return scaleCoder?.enc(...args);
296
+ return scaleCoder?.keys?.enc(...args);
340
297
  } catch (cause) {
341
298
  log.warn(error ?? `Failed to encode stateKey ${JSON.stringify(args)}`, cause);
342
299
  return;
343
300
  }
344
301
  };
345
302
 
303
+ /**
304
+ * Extracts the `version` u8 from a SCALE-encoded metadata blob and returns it as a `number`.
305
+ *
306
+ * Only reads the first 40 bytes of the blob.
307
+ */
308
+ const getMetadataVersion = metadataRpc => {
309
+ try {
310
+ return scaleTs.Struct({
311
+ magicNumber: scaleTs.u32,
312
+ version: scaleTs.u8
313
+ }).dec(metadataRpc).version;
314
+ } catch {
315
+ return 0;
316
+ }
317
+ };
318
+
346
319
  /**
347
320
  * For the substrate-tokens (and other) modules, we configure the `onChainId` field in chaindata to tell the module how to query each token.
348
321
  * These queries are made to the tokens pallet.
@@ -400,28 +373,27 @@ Object.defineProperty(exports, "getLookupFn", {
400
373
  enumerable: true,
401
374
  get: function () { return metadataBuilders.getLookupFn; }
402
375
  });
403
- Object.defineProperty(exports, "fromHex", {
404
- enumerable: true,
405
- get: function () { return utils.fromHex; }
406
- });
407
- Object.defineProperty(exports, "toHex", {
376
+ Object.defineProperty(exports, "decAnyMetadata", {
408
377
  enumerable: true,
409
- get: function () { return utils.toHex; }
378
+ get: function () { return substrateBindings.decAnyMetadata; }
410
379
  });
411
380
  Object.defineProperty(exports, "metadata", {
412
381
  enumerable: true,
413
382
  get: function () { return substrateBindings.metadata; }
414
383
  });
415
- Object.defineProperty(exports, "v14", {
384
+ Object.defineProperty(exports, "unifyMetadata", {
416
385
  enumerable: true,
417
- get: function () { return substrateBindings.v14; }
386
+ get: function () { return substrateBindings.unifyMetadata; }
418
387
  });
419
- Object.defineProperty(exports, "v15", {
388
+ Object.defineProperty(exports, "fromHex", {
420
389
  enumerable: true,
421
- get: function () { return substrateBindings.v15; }
390
+ get: function () { return utils.fromHex; }
391
+ });
392
+ Object.defineProperty(exports, "toHex", {
393
+ enumerable: true,
394
+ get: function () { return utils.toHex; }
422
395
  });
423
396
  exports.compactMetadata = compactMetadata;
424
- exports.decodeMetadata = decodeMetadata;
425
397
  exports.decodeScale = decodeScale;
426
398
  exports.encodeMetadata = encodeMetadata;
427
399
  exports.encodeStateKey = encodeStateKey;
@@ -1,64 +1,16 @@
1
1
  export { getDynamicBuilder, getLookupFn } from '@polkadot-api/metadata-builders';
2
+ import { metadata, Binary } from '@polkadot-api/substrate-bindings';
3
+ export { decAnyMetadata, metadata, unifyMetadata } from '@polkadot-api/substrate-bindings';
2
4
  import { toHex } from '@polkadot-api/utils';
3
5
  export { fromHex, toHex } from '@polkadot-api/utils';
4
- import { metadata, Binary } from '@polkadot-api/substrate-bindings';
5
- export { metadata, v14, v15 } from '@polkadot-api/substrate-bindings';
6
6
  import anylogger from 'anylogger';
7
- import { Struct, u32, u8 } from 'scale-ts';
7
+ import { Struct, u8, u32 } from 'scale-ts';
8
8
 
9
9
  /** Constant: https://docs.substrate.io/build/application-development/#metadata-format */
10
10
  const magicNumber = 1635018093;
11
11
 
12
12
  var packageJson = {
13
- name: "@talismn/scale",
14
- version: "0.1.0",
15
- author: "Talisman",
16
- homepage: "https://talisman.xyz",
17
- license: "GPL-3.0-or-later",
18
- publishConfig: {
19
- access: "public"
20
- },
21
- repository: {
22
- directory: "packages/scale",
23
- type: "git",
24
- url: "https://github.com/talismansociety/talisman.git"
25
- },
26
- main: "dist/talismn-scale.cjs.js",
27
- module: "dist/talismn-scale.esm.js",
28
- files: [
29
- "/dist"
30
- ],
31
- engines: {
32
- node: ">=18"
33
- },
34
- scripts: {
35
- test: "jest",
36
- lint: "eslint src --max-warnings 0",
37
- clean: "rm -rf dist .turbo node_modules"
38
- },
39
- dependencies: {
40
- "@polkadot-api/metadata-builders": "0.9.1",
41
- "@polkadot-api/substrate-bindings": "0.9.3",
42
- "@polkadot-api/utils": "0.1.2",
43
- anylogger: "^1.0.11",
44
- "scale-ts": "^1.6.1"
45
- },
46
- devDependencies: {
47
- "@talismn/eslint-config": "workspace:*",
48
- "@talismn/tsconfig": "workspace:*",
49
- "@types/jest": "^29.5.14",
50
- eslint: "^8.57.1",
51
- jest: "^29.7",
52
- "ts-jest": "^29.2.5",
53
- typescript: "^5.6.3"
54
- },
55
- eslintConfig: {
56
- root: true,
57
- "extends": [
58
- "@talismn/eslint-config/base"
59
- ]
60
- }
61
- };
13
+ name: "@talismn/scale"};
62
14
 
63
15
  var log = anylogger(packageJson.name);
64
16
 
@@ -71,7 +23,10 @@ var log = anylogger(packageJson.name);
71
23
  * E.g. if `palletsAndItems` is `{ pallet: "System", items: ["Account"] }`, then only the
72
24
  * types used in the `System.Account` storage query will remain inside of metadata.lookups.
73
25
  */
74
- const compactMetadata = (metadata, palletsAndItems, extraKeepTypes) => {
26
+ const compactMetadata = (anyMetadata, palletsAndItems = [], runtimeApisAndMethods = [], extraKeepTypes = []) => {
27
+ if (!isCompactableMetadata(anyMetadata)) throw new Error(`Metadata version ${anyMetadata.metadata.tag} not supported in compactMetadata`);
28
+ const metadata = anyMetadata.metadata.value;
29
+
75
30
  // remove pallets we don't care about
76
31
  metadata.pallets = metadata.pallets.filter(pallet =>
77
32
  // keep this pallet if it's listed in `palletsAndItems`
@@ -80,8 +35,9 @@ const compactMetadata = (metadata, palletsAndItems, extraKeepTypes) => {
80
35
  }) => pallet.name === palletName));
81
36
 
82
37
  // remove fields we don't care about from each pallet, and extract types for each storage item we care about
83
- const items = palletsAndItems.flatMap(({
38
+ const palletsKeepTypes = palletsAndItems.flatMap(({
84
39
  pallet: palletName,
40
+ constants: constantNames,
85
41
  items: itemNames
86
42
  }) => {
87
43
  const pallet = metadata.pallets.find(pallet => pallet.name === palletName);
@@ -92,7 +48,7 @@ const compactMetadata = (metadata, palletsAndItems, extraKeepTypes) => {
92
48
 
93
49
  // remove pallet fields we don't care about
94
50
  pallet.calls = undefined;
95
- pallet.constants = [];
51
+ pallet.constants = constantNames ? pallet.constants.filter(constant => constantNames.includes(constant.name)) : [];
96
52
  // v15 (NOT v14) has docs
97
53
  if ("docs" in pallet) pallet.docs = [];
98
54
  pallet.errors = undefined;
@@ -101,19 +57,54 @@ const compactMetadata = (metadata, palletsAndItems, extraKeepTypes) => {
101
57
 
102
58
  // filter and extract storage items we care about
103
59
  pallet.storage.items = pallet.storage.items.filter(item => itemNames.some(itemName => item.name === itemName));
104
- return pallet.storage.items;
60
+ return [...pallet.storage.items.flatMap(item => [
61
+ // each type can be either "Plain" or "Map"
62
+ // if it's "Plain" we only need to get the value type
63
+ // if it's a "Map" we want to keep both the key AND the value types
64
+ item.type.tag === "plain" && item.type.value, item.type.tag === "map" && item.type.value.key, item.type.tag === "map" && item.type.value.value]).filter(type => typeof type === "number"), ...pallet.constants.flatMap(constant => constant.type)];
105
65
  });
106
66
 
67
+ // remove runtime apis we don't care about
68
+ let runtimeApisKeepTypes = [];
69
+ if ("apis" in metadata) {
70
+ // metadata is v15 (NOT v14)
71
+
72
+ // keep this api if it's listed in `runtimeApisAndMethods`
73
+ metadata.apis = metadata.apis.filter(runtimeApi => runtimeApisAndMethods.some(({
74
+ runtimeApi: runtimeApiName
75
+ }) => runtimeApi.name === runtimeApiName));
76
+
77
+ // remove methods we don't care about from each runtime api, and extract types for each call's params and result
78
+ runtimeApisKeepTypes = runtimeApisAndMethods.flatMap(({
79
+ runtimeApi: runtimeApiName,
80
+ methods: methodNames
81
+ }) => {
82
+ const runtimeApi = metadata.apis.find(runtimeApi => runtimeApi.name === runtimeApiName);
83
+ if (!runtimeApi) {
84
+ log.debug("Failed to find runtimeApi", runtimeApiName);
85
+ return [];
86
+ }
87
+
88
+ // remove runtime fields we don't care about
89
+ runtimeApi.docs = [];
90
+ if (!runtimeApi.methods) return [];
91
+
92
+ // filter and extract methods we care about
93
+ runtimeApi.methods = runtimeApi.methods.filter(method => methodNames.some(methodName => method.name === methodName));
94
+ return runtimeApi.methods.flatMap(method => [
95
+ // each method has an array of input types (for the params)
96
+ ...method.inputs.map(input => input.type),
97
+ // and one output type (for the result)
98
+ method.output]);
99
+ });
100
+ }
101
+
107
102
  // this is a set of type ids which we plan to keep in our compacted metadata
108
103
  // anything not in this set will be deleted
109
104
  // we start off with just the types of the state calls we plan to make,
110
105
  // then we run those types through a function (addDependentTypes) which will also include
111
106
  // all of the types which those types depend on - recursively
112
- const keepTypes = new Set(items.flatMap(item => [
113
- // each type can be either "Plain" or "Map"
114
- // if it's "Plain" we only need to get the value type
115
- // if it's a "Map" we want to keep both the key AND the value types
116
- item.type.tag === "plain" && item.type.value, item.type.tag === "map" && item.type.value.key, item.type.tag === "map" && item.type.value.value]).filter(type => typeof type === "number"));
107
+ const keepTypes = new Set([...palletsKeepTypes, ...runtimeApisKeepTypes]);
117
108
  extraKeepTypes?.forEach(type => keepTypes.add(type));
118
109
 
119
110
  // recursively find all the types which our keepTypes depend on and add them to the keepTypes set
@@ -132,20 +123,11 @@ const compactMetadata = (metadata, palletsAndItems, extraKeepTypes) => {
132
123
  return newTypeId ?? 0;
133
124
  };
134
125
  remapTypeIds(metadata, getNewTypeId);
135
-
136
- // ditch the remaining data we don't need to keep in a miniMetata
137
- if ("apis" in metadata) {
138
- // metadata is v15 (NOT v14)
139
- metadata.apis = [];
140
- }
141
- if ("address" in metadata.extrinsic) {
142
- // metadata is v15 (NOT v14)
143
- metadata.extrinsic.address = 0;
144
- metadata.extrinsic.call = 0;
145
- metadata.extrinsic.extra = 0;
146
- metadata.extrinsic.signature = 0;
147
- }
148
- metadata.extrinsic.signedExtensions = [];
126
+ if ("address" in metadata.extrinsic) metadata.extrinsic.address = 0;
127
+ if ("call" in metadata.extrinsic) metadata.extrinsic.call = 0;
128
+ if ("signature" in metadata.extrinsic) metadata.extrinsic.signature = 0;
129
+ if ("extra" in metadata.extrinsic) metadata.extrinsic.extra = 0;
130
+ if ("signedExtensions" in metadata.extrinsic) metadata.extrinsic.signedExtensions = [];
149
131
  if ("outerEnums" in metadata) {
150
132
  // metadata is v15 (NOT v14)
151
133
  metadata.outerEnums.call = 0;
@@ -153,6 +135,16 @@ const compactMetadata = (metadata, palletsAndItems, extraKeepTypes) => {
153
135
  metadata.outerEnums.event = 0;
154
136
  }
155
137
  };
138
+ const isCompactableMetadata = metadata => {
139
+ switch (metadata.metadata.tag) {
140
+ case "v14":
141
+ case "v15":
142
+ case "v16":
143
+ return true;
144
+ default:
145
+ return false;
146
+ }
147
+ };
156
148
  const addDependentTypes = (metadataTysMap, keepTypes, types,
157
149
  // Prevent stack overflow when a type references itself
158
150
  addedTypes = new Set()) => {
@@ -204,6 +196,7 @@ addedTypes = new Set()) => {
204
196
  const remapTypeIds = (metadata, getNewTypeId) => {
205
197
  remapLookupTypeIds(metadata, getNewTypeId);
206
198
  remapStorageTypeIds(metadata, getNewTypeId);
199
+ remapRuntimeApisTypeIds(metadata, getNewTypeId);
207
200
  };
208
201
  const remapLookupTypeIds = (metadata, getNewTypeId) => {
209
202
  for (const type of metadata.lookup) {
@@ -266,79 +259,59 @@ const remapStorageTypeIds = (metadata, getNewTypeId) => {
266
259
  item.type.value.value = getNewTypeId(item.type.value.value);
267
260
  }
268
261
  }
262
+ for (const constant of pallet.constants ?? []) {
263
+ constant.type = getNewTypeId(constant.type);
264
+ }
269
265
  }
270
266
  };
271
-
272
- /**
273
- * Extracts the `version` u8 from a SCALE-encoded metadata blob and returns it as a `number`.
274
- *
275
- * Only reads the first 40 bytes of the blob.
276
- */
277
- const getMetadataVersion = metadataRpc => {
278
- try {
279
- return Struct({
280
- magicNumber: u32,
281
- version: u8
282
- }).dec(metadataRpc).version;
283
- } catch {
284
- return 0;
267
+ const remapRuntimeApisTypeIds = (metadata, getNewTypeId) => {
268
+ for (const runtimeApi of metadata.apis) {
269
+ for (const method of runtimeApi.methods ?? []) {
270
+ for (const input of method.inputs) {
271
+ input.type = getNewTypeId(input.type);
272
+ }
273
+ method.output = getNewTypeId(method.output);
274
+ }
285
275
  }
286
276
  };
287
277
 
288
- const decodeMetadata = metadataRpc => {
289
- const metadataVersion = getMetadataVersion(metadataRpc);
290
- if (metadataVersion !== 15 && metadataVersion !== 14) return {
291
- metadataVersion
292
- };
293
- const decoded = metadata.dec(metadataRpc);
294
- if (decoded.metadata.tag === "v15") return {
295
- metadataVersion,
296
- metadata: decoded.metadata.value,
297
- tag: decoded.metadata.tag
298
- };
299
- if (decoded.metadata.tag === "v14") return {
300
- metadataVersion,
301
- metadata: decoded.metadata.value,
302
- tag: decoded.metadata.tag
303
- };
304
- return {
305
- metadataVersion
306
- };
307
- };
308
-
309
278
  const decodeScale = (scaleCoder, change, error) => {
310
279
  if (change === null) return null;
311
280
  try {
312
- return scaleCoder?.dec(change) ?? null;
281
+ return scaleCoder?.value?.dec(change) ?? null;
313
282
  } catch (cause) {
314
283
  log.warn(error ?? `Failed to decode ${change}`, cause);
315
284
  return null;
316
285
  }
317
286
  };
318
287
 
319
- const encodeMetadata = ({
320
- metadata: metadata$1,
321
- tag
322
- }) => toHex(metadata.enc({
323
- magicNumber,
324
- metadata: tag === "v15" ? {
325
- tag,
326
- value: metadata$1
327
- } : {
328
- tag,
329
- value: metadata$1
330
- }
331
- }));
288
+ const encodeMetadata = metadata$1 => toHex(metadata.enc(metadata$1));
332
289
 
333
290
  const encodeStateKey = (scaleCoder, error, ...args) => {
334
291
  try {
335
- return scaleCoder?.enc(...args);
292
+ return scaleCoder?.keys?.enc(...args);
336
293
  } catch (cause) {
337
294
  log.warn(error ?? `Failed to encode stateKey ${JSON.stringify(args)}`, cause);
338
295
  return;
339
296
  }
340
297
  };
341
298
 
299
+ /**
300
+ * Extracts the `version` u8 from a SCALE-encoded metadata blob and returns it as a `number`.
301
+ *
302
+ * Only reads the first 40 bytes of the blob.
303
+ */
304
+ const getMetadataVersion = metadataRpc => {
305
+ try {
306
+ return Struct({
307
+ magicNumber: u32,
308
+ version: u8
309
+ }).dec(metadataRpc).version;
310
+ } catch {
311
+ return 0;
312
+ }
313
+ };
314
+
342
315
  /**
343
316
  * For the substrate-tokens (and other) modules, we configure the `onChainId` field in chaindata to tell the module how to query each token.
344
317
  * These queries are made to the tokens pallet.
@@ -388,4 +361,4 @@ const papiStringify = (value, space) => {
388
361
  return JSON.stringify(value, replacer, space);
389
362
  };
390
363
 
391
- export { compactMetadata, decodeMetadata, decodeScale, encodeMetadata, encodeStateKey, getMetadataVersion, magicNumber, papiParse, papiStringify };
364
+ export { compactMetadata, decodeScale, encodeMetadata, encodeStateKey, getMetadataVersion, magicNumber, papiParse, papiStringify };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@talismn/scale",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "author": "Talisman",
5
5
  "homepage": "https://talisman.xyz",
6
6
  "license": "GPL-3.0-or-later",
@@ -21,9 +21,9 @@
21
21
  "node": ">=18"
22
22
  },
23
23
  "dependencies": {
24
- "@polkadot-api/metadata-builders": "0.9.1",
25
- "@polkadot-api/substrate-bindings": "0.9.3",
26
- "@polkadot-api/utils": "0.1.2",
24
+ "@polkadot-api/metadata-builders": "0.12.2",
25
+ "@polkadot-api/substrate-bindings": "0.14.0",
26
+ "@polkadot-api/utils": "0.2.0",
27
27
  "anylogger": "^1.0.11",
28
28
  "scale-ts": "^1.6.1"
29
29
  },
@@ -1,13 +0,0 @@
1
- import { V14, V15 } from "@polkadot-api/substrate-bindings";
2
- export declare const decodeMetadata: (metadataRpc: string) => {
3
- metadataVersion: number;
4
- } & ({
5
- metadata: V15;
6
- tag: "v15";
7
- } | {
8
- metadata: V14;
9
- tag: "v14";
10
- } | {
11
- metadata?: undefined;
12
- tag?: undefined;
13
- });