@dedot/api 0.18.8 → 1.0.0

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.
Files changed (102) hide show
  1. package/chaintypes/substrate/consts.d.ts +2 -2
  2. package/chaintypes/substrate/consts.js +1 -0
  3. package/chaintypes/substrate/errors.d.ts +909 -909
  4. package/chaintypes/substrate/errors.js +1 -0
  5. package/chaintypes/substrate/events.d.ts +664 -664
  6. package/chaintypes/substrate/events.js +1 -0
  7. package/chaintypes/substrate/index.d.ts +13 -16
  8. package/chaintypes/substrate/index.js +1 -0
  9. package/chaintypes/substrate/json-rpc.d.ts +2 -2
  10. package/chaintypes/substrate/json-rpc.js +1 -0
  11. package/chaintypes/substrate/query.d.ts +509 -527
  12. package/chaintypes/substrate/query.js +1 -0
  13. package/chaintypes/substrate/runtime.d.ts +123 -123
  14. package/chaintypes/substrate/runtime.js +1 -0
  15. package/chaintypes/substrate/tx.d.ts +1311 -1311
  16. package/chaintypes/substrate/tx.js +1 -0
  17. package/chaintypes/substrate/types.js +1 -0
  18. package/chaintypes/substrate/view-functions.d.ts +2 -2
  19. package/chaintypes/substrate/view-functions.js +1 -0
  20. package/cjs/chaintypes/substrate/consts.js +1 -0
  21. package/cjs/chaintypes/substrate/errors.js +1 -0
  22. package/cjs/chaintypes/substrate/events.js +1 -0
  23. package/cjs/chaintypes/substrate/index.js +1 -0
  24. package/cjs/chaintypes/substrate/json-rpc.js +1 -0
  25. package/cjs/chaintypes/substrate/query.js +1 -0
  26. package/cjs/chaintypes/substrate/runtime.js +1 -0
  27. package/cjs/chaintypes/substrate/tx.js +1 -0
  28. package/cjs/chaintypes/substrate/types.js +1 -0
  29. package/cjs/chaintypes/substrate/view-functions.js +1 -0
  30. package/cjs/client/BaseSubstrateClient.js +45 -2
  31. package/cjs/client/DedotClient.js +356 -224
  32. package/cjs/client/LegacyClient.js +99 -23
  33. package/cjs/client/V2Client.js +316 -0
  34. package/cjs/client/explorer/LegacyBlockExplorer.js +263 -0
  35. package/cjs/client/explorer/V2BlockExplorer.js +74 -0
  36. package/cjs/client/explorer/index.js +18 -0
  37. package/cjs/client/utils.js +57 -0
  38. package/cjs/executor/EventExecutor.js +1 -0
  39. package/cjs/executor/RuntimeApiExecutor.js +49 -2
  40. package/cjs/executor/StorageQueryExecutor.js +114 -2
  41. package/cjs/executor/ViewFunctionExecutor.js +21 -2
  42. package/cjs/executor/v2/StorageQueryExecutorV2.js +7 -1
  43. package/cjs/executor/validation-helpers.js +181 -0
  44. package/cjs/extrinsic/submittable/BaseSubmittableExtrinsic.js +86 -2
  45. package/cjs/extrinsic/submittable/SubmittableExtrinsic.js +38 -16
  46. package/cjs/extrinsic/submittable/SubmittableExtrinsicV2.js +12 -2
  47. package/cjs/json-rpc/group/ChainHead/ChainHead.js +226 -21
  48. package/cjs/storage/QueryableStorage.js +1 -0
  49. package/client/BaseSubstrateClient.d.ts +34 -18
  50. package/client/BaseSubstrateClient.js +47 -4
  51. package/client/DedotClient.d.ts +346 -49
  52. package/client/DedotClient.js +356 -224
  53. package/client/LegacyClient.d.ts +22 -17
  54. package/client/LegacyClient.js +101 -25
  55. package/client/V2Client.d.ts +75 -0
  56. package/client/V2Client.js +312 -0
  57. package/client/explorer/LegacyBlockExplorer.d.ts +68 -0
  58. package/client/explorer/LegacyBlockExplorer.js +259 -0
  59. package/client/explorer/V2BlockExplorer.d.ts +40 -0
  60. package/client/explorer/V2BlockExplorer.js +70 -0
  61. package/client/explorer/index.d.ts +2 -0
  62. package/client/explorer/index.js +2 -0
  63. package/client/utils.d.ts +18 -0
  64. package/client/utils.js +52 -0
  65. package/executor/ConstantExecutor.d.ts +1 -2
  66. package/executor/ErrorExecutor.d.ts +2 -2
  67. package/executor/EventExecutor.d.ts +2 -2
  68. package/executor/EventExecutor.js +1 -0
  69. package/executor/Executor.d.ts +4 -5
  70. package/executor/RuntimeApiExecutor.d.ts +2 -2
  71. package/executor/RuntimeApiExecutor.js +27 -3
  72. package/executor/StorageQueryExecutor.d.ts +3 -2
  73. package/executor/StorageQueryExecutor.js +92 -3
  74. package/executor/TxExecutor.d.ts +2 -2
  75. package/executor/ViewFunctionExecutor.d.ts +2 -2
  76. package/executor/ViewFunctionExecutor.js +22 -3
  77. package/executor/v2/RuntimeApiExecutorV2.d.ts +2 -3
  78. package/executor/v2/StorageQueryExecutorV2.d.ts +3 -3
  79. package/executor/v2/StorageQueryExecutorV2.js +8 -2
  80. package/executor/v2/TxExecutorV2.d.ts +5 -5
  81. package/executor/v2/ViewFunctionExecutorV2.d.ts +2 -3
  82. package/executor/validation-helpers.d.ts +36 -0
  83. package/executor/validation-helpers.js +174 -0
  84. package/extrinsic/extensions/SignedExtension.d.ts +1 -1
  85. package/extrinsic/submittable/BaseSubmittableExtrinsic.d.ts +7 -3
  86. package/extrinsic/submittable/BaseSubmittableExtrinsic.js +64 -3
  87. package/extrinsic/submittable/SubmittableExtrinsic.d.ts +4 -1
  88. package/extrinsic/submittable/SubmittableExtrinsic.js +39 -17
  89. package/extrinsic/submittable/SubmittableExtrinsicV2.d.ts +6 -3
  90. package/extrinsic/submittable/SubmittableExtrinsicV2.js +13 -3
  91. package/json-rpc/JsonRpcClient.d.ts +6 -6
  92. package/json-rpc/group/Archive.d.ts +1 -1
  93. package/json-rpc/group/ChainHead/ChainHead.d.ts +18 -2
  94. package/json-rpc/group/ChainHead/ChainHead.js +226 -21
  95. package/json-rpc/group/ChainSpec.d.ts +3 -3
  96. package/json-rpc/group/Transaction.d.ts +1 -1
  97. package/json-rpc/group/TransactionWatch.d.ts +1 -1
  98. package/package.json +9 -9
  99. package/proxychain.d.ts +3 -4
  100. package/storage/NewStorageQuery.d.ts +3 -3
  101. package/storage/QueryableStorage.js +1 -0
  102. package/types.d.ts +94 -6
@@ -0,0 +1,263 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LegacyBlockExplorer = void 0;
4
+ const codecs_1 = require("@dedot/codecs");
5
+ const utils_1 = require("@dedot/utils");
6
+ /**
7
+ * @name LegacyBlockExplorer
8
+ * @description Block explorer implementation for LegacyClient using legacy JSON-RPC methods
9
+ * Optimized to share RPC subscriptions across multiple subscribers using Signal pattern
10
+ */
11
+ class LegacyBlockExplorer {
12
+ #client;
13
+ // Signals for block subscriptions
14
+ #bestBlockSignal;
15
+ #finalizedBlockSignal;
16
+ // Track RPC subscription cleanup functions
17
+ #bestBlockUnsub;
18
+ #finalizedBlockUnsub;
19
+ constructor(client) {
20
+ this.#client = client;
21
+ this.#bestBlockSignal = new utils_1.Signal();
22
+ this.#finalizedBlockSignal = new utils_1.Signal();
23
+ }
24
+ /**
25
+ * Convert PinnedBlock to BlockInfo format
26
+ */
27
+ toBlockInfo(header) {
28
+ return {
29
+ hash: header.hash || this.calculateBlockHash(header),
30
+ number: header.number,
31
+ parent: header.parentHash,
32
+ runtimeUpgraded: this.hasNewRuntime(header),
33
+ };
34
+ }
35
+ /**
36
+ * Fill missing blocks when a gap is detected
37
+ * Fetches and emits all missing blocks between lastNumber and currentNumber
38
+ */
39
+ async fillMissingBlocks(lastNumber, currentNumber, subject, blockType) {
40
+ // No gap if no previous block or current is next sequential block
41
+ if (lastNumber === undefined || currentNumber <= lastNumber + 1) {
42
+ return;
43
+ }
44
+ // Gap detected - backfill missing blocks
45
+ const gapSize = currentNumber - lastNumber - 1;
46
+ // Create list of missing block numbers
47
+ const missingNums = Array.from({ length: gapSize }, (_, i) => lastNumber + 1 + i);
48
+ try {
49
+ // Fetch all hashes in parallel
50
+ const hashes = await Promise.all(missingNums.map((num) => this.#client.rpc.chain_getBlockHash(num)));
51
+ // Fetch all headers in parallel
52
+ const headers = await Promise.all(hashes.map((hash) => this.#client.rpc.chain_getHeader(hash)));
53
+ // Emit blocks in order
54
+ for (let i = 0; i < missingNums.length; i++) {
55
+ const hash = hashes[i];
56
+ const header = headers[i];
57
+ if (hash && header) {
58
+ subject.next(this.toBlockInfo({ ...header, hash }));
59
+ }
60
+ }
61
+ }
62
+ catch (error) {
63
+ console.error(`Failed to backfill missing ${blockType} blocks:`, error);
64
+ // Continue despite backfill failure
65
+ }
66
+ }
67
+ /**
68
+ * Start the shared best block subscription if not already active
69
+ */
70
+ ensureBestBlockSubscription() {
71
+ if (this.#bestBlockUnsub) {
72
+ // Subscription already active
73
+ return;
74
+ }
75
+ // Use closure pattern to handle async subscription without race conditions
76
+ let done = false;
77
+ let unsub;
78
+ const blockQueue = new utils_1.AsyncQueue();
79
+ // Start RPC subscription (non-blocking)
80
+ this.#client.rpc
81
+ .chain_subscribeNewHeads((header) => {
82
+ if (done) {
83
+ // Unsubscribe was called before subscription completed
84
+ unsub && unsub();
85
+ return;
86
+ }
87
+ // Enqueue block processing to ensure sequential handling
88
+ blockQueue
89
+ .enqueue(async () => {
90
+ const currentHash = this.calculateBlockHash(header);
91
+ // Detect gaps in best block stream (due to reconnection)
92
+ const { number: lastNumber, hash: lastHash } = this.#bestBlockSignal.value || {};
93
+ if (lastHash === currentHash) {
94
+ return;
95
+ }
96
+ // Fill missing blocks if gap detected
97
+ await this.fillMissingBlocks(lastNumber, header.number, this.#bestBlockSignal, 'best');
98
+ // Emit current block
99
+ const blockInfo = this.toBlockInfo({ ...header, hash: currentHash });
100
+ this.#bestBlockSignal.next(blockInfo);
101
+ })
102
+ .catch((error) => {
103
+ console.error('Error processing best block:', error);
104
+ });
105
+ })
106
+ .then((rpcUnsub) => {
107
+ unsub = rpcUnsub;
108
+ });
109
+ // Immediately set unsub wrapper to prevent race conditions
110
+ this.#bestBlockUnsub = () => {
111
+ done = true;
112
+ blockQueue.cancel();
113
+ unsub && unsub().catch(utils_1.noop);
114
+ };
115
+ }
116
+ hasNewRuntime(header) {
117
+ return header.digest.logs.some((log) => log.type === 'RuntimeEnvironmentUpdated');
118
+ }
119
+ /**
120
+ * Start the shared finalized block subscription if not already active
121
+ */
122
+ ensureFinalizedBlockSubscription() {
123
+ if (this.#finalizedBlockUnsub) {
124
+ // Subscription already active
125
+ return;
126
+ }
127
+ // Use closure pattern to handle async subscription without race conditions
128
+ let done = false;
129
+ let unsub;
130
+ const blockQueue = new utils_1.AsyncQueue();
131
+ // Start RPC subscription (non-blocking)
132
+ this.#client.rpc
133
+ .chain_subscribeFinalizedHeads((header) => {
134
+ if (done) {
135
+ // Unsubscribe was called before subscription completed
136
+ unsub && unsub();
137
+ return;
138
+ }
139
+ // Enqueue block processing to ensure sequential handling
140
+ blockQueue
141
+ .enqueue(async () => {
142
+ // Detect gaps in finalized block stream (due to reconnection)
143
+ const lastNumber = this.#finalizedBlockSignal.value?.number;
144
+ if (lastNumber === header.number) {
145
+ return;
146
+ }
147
+ // Fill missing blocks if gap detected
148
+ await this.fillMissingBlocks(lastNumber, header.number, this.#finalizedBlockSignal, 'finalized');
149
+ // Emit current block
150
+ const blockInfo = this.toBlockInfo(header);
151
+ this.#finalizedBlockSignal.next(blockInfo);
152
+ })
153
+ .catch((error) => {
154
+ console.error('Error processing finalized block:', error);
155
+ });
156
+ })
157
+ .then((rpcUnsub) => {
158
+ unsub = rpcUnsub;
159
+ });
160
+ // Immediately set unsub wrapper to prevent race conditions
161
+ this.#finalizedBlockUnsub = () => {
162
+ done = true;
163
+ blockQueue.cancel();
164
+ unsub && unsub().catch(utils_1.noop);
165
+ };
166
+ }
167
+ /**
168
+ * Clean up best block subscription when no more listeners
169
+ */
170
+ cleanupBestBlockSubscription() {
171
+ if (this.#bestBlockSignal.listenerCount === 0 && this.#bestBlockUnsub) {
172
+ this.#bestBlockUnsub();
173
+ this.#bestBlockUnsub = undefined;
174
+ }
175
+ }
176
+ /**
177
+ * Clean up finalized block subscription when no more listeners
178
+ */
179
+ cleanupFinalizedBlockSubscription() {
180
+ if (this.#finalizedBlockSignal.listenerCount === 0 && this.#finalizedBlockUnsub) {
181
+ this.#finalizedBlockUnsub();
182
+ this.#finalizedBlockUnsub = undefined;
183
+ }
184
+ }
185
+ calculateBlockHash(header) {
186
+ return this.#client.registry.hashAsHex(codecs_1.$Header.tryEncode(header));
187
+ }
188
+ best(callback) {
189
+ if (callback) {
190
+ // Subscribe mode - use shared subscription
191
+ // Ensure RPC subscription is active (creates on first listener)
192
+ this.ensureBestBlockSubscription();
193
+ // Subscribe to subject (automatically emits current value if available)
194
+ const unsub = this.#bestBlockSignal.subscribe(callback);
195
+ // Return cleanup function
196
+ return () => {
197
+ unsub();
198
+ this.cleanupBestBlockSubscription();
199
+ };
200
+ }
201
+ else {
202
+ // One-time query - return cached value if available
203
+ if (this.#bestBlockSignal.value) {
204
+ return Promise.resolve(this.#bestBlockSignal.value);
205
+ }
206
+ // Fallback to RPC call if no cached value
207
+ return this.#client.rpc.chain_getHeader().then(async (header) => {
208
+ (0, utils_1.assert)(header, 'Header not found');
209
+ return {
210
+ hash: this.calculateBlockHash(header),
211
+ number: header.number,
212
+ parent: header.parentHash,
213
+ };
214
+ });
215
+ }
216
+ }
217
+ finalized(callback) {
218
+ if (callback) {
219
+ // Subscribe mode - use shared subscription
220
+ // Ensure RPC subscription is active (creates on first listener)
221
+ this.ensureFinalizedBlockSubscription();
222
+ // Subscribe to subject (automatically emits current value if available)
223
+ const unsub = this.#finalizedBlockSignal.subscribe(callback);
224
+ // Return cleanup function
225
+ return () => {
226
+ unsub();
227
+ this.cleanupFinalizedBlockSubscription();
228
+ };
229
+ }
230
+ else {
231
+ // One-time query - return cached value if available
232
+ if (this.#finalizedBlockSignal.value) {
233
+ return Promise.resolve(this.#finalizedBlockSignal.value);
234
+ }
235
+ // Fallback to RPC call if no cached value
236
+ return this.#client.rpc.chain_getFinalizedHead().then(async (hash) => {
237
+ const header = await this.header(hash);
238
+ return {
239
+ hash,
240
+ number: header.number,
241
+ parent: header.parentHash,
242
+ };
243
+ });
244
+ }
245
+ }
246
+ /**
247
+ * Get the header of a block by number or hash
248
+ */
249
+ async header(hash) {
250
+ const header = await this.#client.rpc.chain_getHeader(hash);
251
+ (0, utils_1.assert)(header, `Header not found for block ${hash}`);
252
+ return header;
253
+ }
254
+ /**
255
+ * Get the body (transactions) of a block by number or hash
256
+ */
257
+ async body(hash) {
258
+ const block = await this.#client.rpc.chain_getBlock(hash);
259
+ (0, utils_1.assert)(block, `Block not found for ${hash}`);
260
+ return block.block.extrinsics;
261
+ }
262
+ }
263
+ exports.LegacyBlockExplorer = LegacyBlockExplorer;
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.V2BlockExplorer = void 0;
4
+ const codecs_1 = require("@dedot/codecs");
5
+ const utils_1 = require("@dedot/utils");
6
+ /**
7
+ * @name V2BlockExplorer
8
+ * @description Block explorer implementation for V2Client using JSON-RPC v2 (ChainHead API)
9
+ */
10
+ class V2BlockExplorer {
11
+ #chainHead;
12
+ #archive;
13
+ constructor(client) {
14
+ this.#chainHead = client.chainHead;
15
+ this.#archive = client.archive;
16
+ }
17
+ /**
18
+ * Convert PinnedBlock to BlockInfo format
19
+ */
20
+ toBlockInfo(block) {
21
+ return {
22
+ hash: block.hash,
23
+ number: block.number,
24
+ parent: block.parent,
25
+ runtimeUpgraded: block.runtimeUpgraded === true,
26
+ };
27
+ }
28
+ best(callback) {
29
+ if (callback) {
30
+ // Subscribe mode
31
+ const handler = (block) => {
32
+ callback(this.toBlockInfo(block));
33
+ };
34
+ this.#chainHead.bestBlock().then((block) => {
35
+ handler(block);
36
+ });
37
+ return this.#chainHead.on('bestBlock', handler);
38
+ }
39
+ else {
40
+ // One-time query
41
+ return this.#chainHead.bestBlock().then((block) => this.toBlockInfo(block));
42
+ }
43
+ }
44
+ finalized(callback) {
45
+ if (callback) {
46
+ // Subscribe mode
47
+ const handler = (block) => {
48
+ callback(this.toBlockInfo(block));
49
+ };
50
+ this.#chainHead.finalizedBlock().then((block) => {
51
+ handler(block);
52
+ });
53
+ return this.#chainHead.on('finalizedBlock', handler);
54
+ }
55
+ else {
56
+ return this.#chainHead.finalizedBlock().then((block) => this.toBlockInfo(block));
57
+ }
58
+ }
59
+ /**
60
+ * Get the header of a block by number or hash
61
+ */
62
+ async header(hash) {
63
+ const rawHeader = await this.#chainHead.header(hash);
64
+ (0, utils_1.assert)(rawHeader, `Header not found for block ${hash}`);
65
+ return codecs_1.$Header.tryDecode(rawHeader);
66
+ }
67
+ /**
68
+ * Get the body (transactions) of a block by number or hash
69
+ */
70
+ async body(hash) {
71
+ return await this.#chainHead.body(hash);
72
+ }
73
+ }
74
+ exports.V2BlockExplorer = V2BlockExplorer;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./V2BlockExplorer.js"), exports);
18
+ __exportStar(require("./LegacyBlockExplorer.js"), exports);
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.detectHasherFromHeader = exports.detectHasherFromMetadata = void 0;
4
+ const codecs_1 = require("@dedot/codecs");
5
+ const utils_1 = require("@dedot/utils");
6
+ const HASHERS = {
7
+ BlakeTwo256: utils_1.blake2_256, // commonly used in polkadot-sdk based-chains
8
+ Keccak256: utils_1.keccak_256, // widely used in EVM-compatible chains, e.g: Hyperbridge
9
+ };
10
+ /**
11
+ * Detects the hasher from V16 metadata by looking at the System pallet's Hashing associated type
12
+ *
13
+ * @param metadata - The metadata to inspect
14
+ * @returns The detected HashFn or undefined if detection fails
15
+ */
16
+ function detectHasherFromMetadata(metadata) {
17
+ try {
18
+ const latest = metadata.latest;
19
+ // Find the System pallet
20
+ const systemPallet = latest.pallets.find((p) => p.name === 'System');
21
+ if (!systemPallet)
22
+ return undefined;
23
+ // Find the Hashing associated type
24
+ const hashingType = systemPallet.associatedTypes.find((t) => t.name === 'Hashing');
25
+ if (!hashingType)
26
+ return undefined;
27
+ // Get the type definition
28
+ const typeDef = latest.types[hashingType.typeId];
29
+ if (!typeDef)
30
+ return undefined;
31
+ // Get the hasher name from the type path (last element)
32
+ const hasherName = typeDef.path.at(-1);
33
+ if (!hasherName)
34
+ return undefined;
35
+ return HASHERS[hasherName];
36
+ }
37
+ catch { }
38
+ return undefined;
39
+ }
40
+ exports.detectHasherFromMetadata = detectHasherFromMetadata;
41
+ /**
42
+ * Detects the hasher by trying different hash functions on a block header
43
+ * and comparing the result with the expected block hash
44
+ *
45
+ * @param header - The block header to hash
46
+ * @param expectedHash - The expected block hash
47
+ * @returns The matching HashFn or undefined if no match is found
48
+ */
49
+ function detectHasherFromHeader(header, expectedHash) {
50
+ try {
51
+ const encodedHeader = codecs_1.$Header.tryEncode(header);
52
+ return Object.values(HASHERS).find((h) => (0, utils_1.u8aToHex)(h(encodedHeader)) === expectedHash);
53
+ }
54
+ catch { }
55
+ return undefined;
56
+ }
57
+ exports.detectHasherFromHeader = detectHasherFromHeader;
@@ -59,6 +59,7 @@ class EventExecutor extends Executor_js_1.Executor {
59
59
  palletIndex: targetPallet.index,
60
60
  };
61
61
  return {
62
+ // @ts-ignore
62
63
  is,
63
64
  find,
64
65
  filter,
@@ -1,9 +1,34 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  Object.defineProperty(exports, "__esModule", { value: true });
3
26
  exports.RuntimeApiExecutor = exports.FallbackRuntimeApiSpecs = exports.FallbackRuntimeApis = void 0;
4
27
  const runtime_specs_1 = require("@dedot/runtime-specs");
28
+ const $ = __importStar(require("@dedot/shape"));
5
29
  const utils_1 = require("@dedot/utils");
6
30
  const Executor_js_1 = require("./Executor.js");
31
+ const validation_helpers_js_1 = require("./validation-helpers.js");
7
32
  exports.FallbackRuntimeApis = { '0x37e397fc7c91f5e4': 2 };
8
33
  exports.FallbackRuntimeApiSpecs = { Metadata: runtime_specs_1.Metadata };
9
34
  /**
@@ -22,8 +47,30 @@ class RuntimeApiExecutor extends Executor_js_1.Executor {
22
47
  (0, utils_1.assert)(callSpec, new utils_1.UnknownApiError(`Runtime api spec not found for ${callName}`));
23
48
  const callFn = async (...args) => {
24
49
  const { params } = callSpec;
25
- const formattedInputs = params.map((param, index) => this.tryEncode(param, args[index]));
26
- const bytes = (0, utils_1.u8aToHex)((0, utils_1.concatU8a)(...formattedInputs));
50
+ // Pad args with undefined for missing trailing optional parameters
51
+ const withCodecs = params.every((p) => !!p.codec);
52
+ const paddedArgs = (0, validation_helpers_js_1.padArgsForOptionalParams)(args, params, withCodecs
53
+ ? {} // intentional trick to pass-by client initialization
54
+ : this.registry);
55
+ const $ParamsTuple = $.Tuple(...params.map((param) => this.#findCodec(param, // --
56
+ `Codec not found for param ${param.name}`)));
57
+ // Enhanced validation with detailed error messages
58
+ try {
59
+ $ParamsTuple.assert?.(paddedArgs);
60
+ }
61
+ catch (error) {
62
+ // Enhance Shape assertion errors with detailed compatibility information
63
+ if (error instanceof $.ShapeAssertError) {
64
+ throw (0, validation_helpers_js_1.buildCompatibilityError)(error, // --
65
+ params, args, {
66
+ apiName: `${runtimeApi}.${method}`,
67
+ registry: this.registry,
68
+ });
69
+ }
70
+ throw error;
71
+ }
72
+ const formattedInputs = $ParamsTuple.tryEncode(paddedArgs);
73
+ const bytes = (0, utils_1.u8aToHex)(formattedInputs);
27
74
  const callParams = {
28
75
  func: callName,
29
76
  params: bytes,
@@ -1,9 +1,34 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  Object.defineProperty(exports, "__esModule", { value: true });
3
26
  exports.StorageQueryExecutor = void 0;
27
+ const $ = __importStar(require("@dedot/shape"));
4
28
  const utils_1 = require("@dedot/utils");
5
29
  const index_js_1 = require("../storage/index.js");
6
30
  const Executor_js_1 = require("./Executor.js");
31
+ const validation_helpers_js_1 = require("./validation-helpers.js");
7
32
  const DEFAULT_KEYS_PAGE_SIZE = 1000;
8
33
  const DEFAULT_ENTRIES_PAGE_SIZE = 250;
9
34
  /**
@@ -32,6 +57,8 @@ class StorageQueryExecutor extends Executor_js_1.Executor {
32
57
  };
33
58
  const queryFn = async (...args) => {
34
59
  const [inArgs, callback] = extractArgs(args);
60
+ // Validate storage inputs before encoding
61
+ this.#validateStorageInputs(entry, inArgs.at(0));
35
62
  const encodedKey = entry.encodeKey(inArgs.at(0));
36
63
  // if a callback is passed, make a storage subscription and return an unsub function
37
64
  if (callback) {
@@ -58,6 +85,10 @@ class StorageQueryExecutor extends Executor_js_1.Executor {
58
85
  const [inArgs, callback] = extractArgs(args);
59
86
  const multiArgs = inArgs.at(0);
60
87
  (0, utils_1.assert)(Array.isArray(multiArgs), 'First param for multi query should be an array');
88
+ // Validate each argument before encoding
89
+ multiArgs.forEach((arg, index) => {
90
+ this.#validateStorageInputs(entry, arg, index);
91
+ });
61
92
  const encodedKeys = multiArgs.map((arg) => entry.encodeKey(arg));
62
93
  // if a callback is passed, make a storage subscription and return an unsub function
63
94
  if (callback) {
@@ -79,7 +110,7 @@ class StorageQueryExecutor extends Executor_js_1.Executor {
79
110
  exposeStorageMapMethods(entry) {
80
111
  const rawKeys = async (partialInput, pagination) => {
81
112
  const pageSize = pagination?.pageSize || DEFAULT_KEYS_PAGE_SIZE;
82
- const startKey = pagination?.startKey || entry.prefixKey;
113
+ const startKey = pagination?.startKey;
83
114
  return await this.client.rpc.state_getKeysPaged(entry.encodeKey(partialInput, true), pageSize, startKey, this.atBlockHash);
84
115
  };
85
116
  const extractArgs = (args) => {
@@ -99,7 +130,88 @@ class StorageQueryExecutor extends Executor_js_1.Executor {
99
130
  const storageMap = await this.queryStorage(storageKeys, this.atBlockHash);
100
131
  return storageKeys.map((key) => [entry.decodeKey(key), entry.decodeValue(storageMap[key])]);
101
132
  };
102
- return { pagedKeys, pagedEntries };
133
+ const entries = async (...args) => {
134
+ const [inArgs] = extractArgs(args);
135
+ const allEntries = [];
136
+ let startKey;
137
+ while (true) {
138
+ const pagination = {
139
+ pageSize: DEFAULT_ENTRIES_PAGE_SIZE,
140
+ ...(startKey ? { startKey } : {}),
141
+ };
142
+ const storageKeys = await rawKeys(inArgs, pagination);
143
+ if (storageKeys.length === 0)
144
+ break;
145
+ const storageMap = await this.queryStorage(storageKeys, this.atBlockHash);
146
+ const pageEntries = storageKeys.map((key) => [
147
+ entry.decodeKey(key),
148
+ entry.decodeValue(storageMap[key]),
149
+ ]);
150
+ allEntries.push(...pageEntries);
151
+ if (storageKeys.length < DEFAULT_ENTRIES_PAGE_SIZE)
152
+ break;
153
+ startKey = storageKeys[storageKeys.length - 1];
154
+ }
155
+ return allEntries;
156
+ };
157
+ return { entries, pagedKeys, pagedEntries };
158
+ }
159
+ /**
160
+ * Validate storage query inputs before encoding
161
+ * @param entry - QueryableStorage instance
162
+ * @param keyInput - Input keys to validate
163
+ * @param itemIndex - Optional index for multi query error messages
164
+ */
165
+ #validateStorageInputs(entry, keyInput, itemIndex) {
166
+ const { storageType } = entry.storageEntry;
167
+ // Plain storage doesn't require validation
168
+ if (storageType.type === 'Plain') {
169
+ return;
170
+ }
171
+ if (storageType.type === 'Map') {
172
+ const { hashers, keyTypeId } = storageType.value;
173
+ const requiredKeys = hashers.length;
174
+ // Extract keyTypeIds for multi-key storage
175
+ let keyTypeIds = [keyTypeId];
176
+ if (hashers.length > 1) {
177
+ const { typeDef } = this.registry.findType(keyTypeId);
178
+ (0, utils_1.assert)(typeDef.type === 'Tuple', 'Key type should be a tuple!');
179
+ keyTypeIds = typeDef.value.fields;
180
+ }
181
+ // Normalize input to array format
182
+ let keys;
183
+ if (requiredKeys === 1) {
184
+ // Single key: accept both single value or array
185
+ keys = Array.isArray(keyInput) ? keyInput : [keyInput];
186
+ }
187
+ else {
188
+ // Multiple keys: must be array
189
+ (0, utils_1.assert)(Array.isArray(keyInput), 'Multi-key storage requires array input');
190
+ keys = keyInput;
191
+ }
192
+ // Build parameter specs for error messages
193
+ const paramSpecs = keyTypeIds.map((typeId, index) => ({
194
+ name: `key${index}`,
195
+ typeId,
196
+ }));
197
+ // Create tuple codec for validation
198
+ const $ParamsTuple = $.Tuple(...keyTypeIds.map((id) => this.registry.findCodec(id)));
199
+ // Validate inputs
200
+ try {
201
+ $ParamsTuple.assert?.(keys);
202
+ }
203
+ catch (error) {
204
+ if (error instanceof $.ShapeAssertError) {
205
+ throw (0, validation_helpers_js_1.buildCompatibilityError)(error, // -
206
+ paramSpecs, keys, {
207
+ apiName: `${(0, utils_1.stringCamelCase)(entry.pallet.name)}.${(0, utils_1.stringCamelCase)(entry.storageEntry.name)}`,
208
+ registry: this.registry,
209
+ itemIndex,
210
+ });
211
+ }
212
+ throw error;
213
+ }
214
+ }
103
215
  }
104
216
  getStorageQuery() {
105
217
  return new index_js_1.LegacyStorageQuery(this.client);
@@ -27,6 +27,7 @@ exports.ViewFunctionExecutor = void 0;
27
27
  const $ = __importStar(require("@dedot/shape"));
28
28
  const utils_1 = require("@dedot/utils");
29
29
  const Executor_js_1 = require("./Executor.js");
30
+ const validation_helpers_js_1 = require("./validation-helpers.js");
30
31
  const RUNTIME_API_NAME = 'RuntimeViewFunction';
31
32
  const METHOD_NAME = 'execute_view_function';
32
33
  /**
@@ -40,8 +41,26 @@ class ViewFunctionExecutor extends Executor_js_1.Executor {
40
41
  (0, utils_1.assert)(viewFunctionDef, new utils_1.UnknownApiError(`View function not found: ${pallet}.${viewFunction}`));
41
42
  const callFn = async (...args) => {
42
43
  const { inputs, id, output } = viewFunctionDef;
43
- const formattedInputs = inputs.map(({ typeId }, index) => this.registry.findCodec(typeId).tryEncode(args[index]));
44
- const bytes = (0, utils_1.u8aToHex)((0, utils_1.concatU8a)(id, $.Vec($.u8).tryEncode((0, utils_1.concatU8a)(...formattedInputs))));
44
+ // Pad args with undefined for missing trailing optional parameters
45
+ const paddedArgs = (0, validation_helpers_js_1.padArgsForOptionalParams)(args, inputs, this.registry);
46
+ const $ParamsTuple = $.Tuple(...inputs.map((param) => this.registry.findCodec(param.typeId)));
47
+ // Enhanced validation with detailed error messages
48
+ try {
49
+ $ParamsTuple.assert?.(paddedArgs);
50
+ }
51
+ catch (error) {
52
+ // Enhance Shape assertion errors with detailed compatibility information
53
+ if (error instanceof $.ShapeAssertError) {
54
+ throw (0, validation_helpers_js_1.buildCompatibilityError)(error, // --
55
+ inputs, args, {
56
+ apiName: `${pallet}.${viewFunction}`,
57
+ registry: this.registry,
58
+ });
59
+ }
60
+ throw error;
61
+ }
62
+ const formattedInputs = $ParamsTuple.tryEncode(paddedArgs);
63
+ const bytes = (0, utils_1.u8aToHex)((0, utils_1.concatU8a)(id, $.Vec($.u8).tryEncode(formattedInputs)));
45
64
  const func = `${RUNTIME_API_NAME}_${METHOD_NAME}`;
46
65
  const callParams = {
47
66
  func,