@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.
- package/dist/declarations/src/papito.d.ts +2 -2
- package/dist/declarations/src/util/Prettify.d.ts +3 -0
- package/dist/declarations/src/util/compactMetadata.d.ts +14 -8
- package/dist/declarations/src/util/encodeMetadata.d.ts +2 -8
- package/dist/declarations/src/util/index.d.ts +0 -1
- package/dist/declarations/src/util/serdePapi.d.ts +2 -1
- package/dist/talismn-scale.cjs.dev.js +106 -134
- package/dist/talismn-scale.cjs.prod.js +106 -134
- package/dist/talismn-scale.esm.js +99 -126
- package/package.json +4 -4
- package/dist/declarations/src/util/decodeMetadata.d.ts +0 -13
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { getDynamicBuilder, getLookupFn } from "@polkadot-api/metadata-builders";
|
|
2
|
-
export type {
|
|
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";
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export type
|
|
3
|
-
export type
|
|
4
|
-
export type
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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: (
|
|
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 {
|
|
2
|
-
export declare const encodeMetadata: (
|
|
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;
|
|
@@ -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,
|
|
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 = (
|
|
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
|
|
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(
|
|
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
|
-
|
|
141
|
-
if ("
|
|
142
|
-
|
|
143
|
-
|
|
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
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
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, "
|
|
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
|
|
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, "
|
|
384
|
+
Object.defineProperty(exports, "unifyMetadata", {
|
|
416
385
|
enumerable: true,
|
|
417
|
-
get: function () { return substrateBindings.
|
|
386
|
+
get: function () { return substrateBindings.unifyMetadata; }
|
|
418
387
|
});
|
|
419
|
-
Object.defineProperty(exports, "
|
|
388
|
+
Object.defineProperty(exports, "fromHex", {
|
|
420
389
|
enumerable: true,
|
|
421
|
-
get: function () { return
|
|
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 = (
|
|
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
|
|
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(
|
|
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
|
-
|
|
141
|
-
if ("
|
|
142
|
-
|
|
143
|
-
|
|
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
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
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, "
|
|
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
|
|
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, "
|
|
384
|
+
Object.defineProperty(exports, "unifyMetadata", {
|
|
416
385
|
enumerable: true,
|
|
417
|
-
get: function () { return substrateBindings.
|
|
386
|
+
get: function () { return substrateBindings.unifyMetadata; }
|
|
418
387
|
});
|
|
419
|
-
Object.defineProperty(exports, "
|
|
388
|
+
Object.defineProperty(exports, "fromHex", {
|
|
420
389
|
enumerable: true,
|
|
421
|
-
get: function () { return
|
|
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,
|
|
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 = (
|
|
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
|
|
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(
|
|
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
|
-
|
|
137
|
-
if ("
|
|
138
|
-
|
|
139
|
-
|
|
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
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
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,
|
|
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.
|
|
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.
|
|
25
|
-
"@polkadot-api/substrate-bindings": "0.
|
|
26
|
-
"@polkadot-api/utils": "0.
|
|
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
|
-
});
|