dedot 0.0.1-alpha.22

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 (100) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +245 -0
  3. package/cjs/client/Dedot.js +444 -0
  4. package/cjs/client/index.js +17 -0
  5. package/cjs/executor/ConstantExecutor.js +22 -0
  6. package/cjs/executor/ErrorExecutor.js +47 -0
  7. package/cjs/executor/EventExecutor.js +53 -0
  8. package/cjs/executor/Executor.js +39 -0
  9. package/cjs/executor/RpcExecutor.js +109 -0
  10. package/cjs/executor/RuntimeApiExecutor.js +93 -0
  11. package/cjs/executor/StorageQueryExecutor.js +33 -0
  12. package/cjs/executor/TxExecutor.js +153 -0
  13. package/cjs/executor/index.js +24 -0
  14. package/cjs/extrinsic/SubmittableResult.js +33 -0
  15. package/cjs/extrinsic/extensions/ExtraSignedExtension.js +65 -0
  16. package/cjs/extrinsic/extensions/SignedExtension.js +41 -0
  17. package/cjs/extrinsic/extensions/index.js +19 -0
  18. package/cjs/extrinsic/extensions/known/ChargeAssetTxPayment.js +44 -0
  19. package/cjs/extrinsic/extensions/known/ChargeTransactionPayment.js +16 -0
  20. package/cjs/extrinsic/extensions/known/CheckGenesis.js +19 -0
  21. package/cjs/extrinsic/extensions/known/CheckMortality.js +71 -0
  22. package/cjs/extrinsic/extensions/known/CheckNonZeroSender.js +10 -0
  23. package/cjs/extrinsic/extensions/known/CheckNonce.js +34 -0
  24. package/cjs/extrinsic/extensions/known/CheckSpecVersion.js +19 -0
  25. package/cjs/extrinsic/extensions/known/CheckTxVersion.js +19 -0
  26. package/cjs/extrinsic/extensions/known/CheckWeight.js +10 -0
  27. package/cjs/extrinsic/extensions/known/PrevalidateAttests.js +11 -0
  28. package/cjs/extrinsic/extensions/known/index.js +25 -0
  29. package/cjs/extrinsic/index.js +18 -0
  30. package/cjs/index.js +25 -0
  31. package/cjs/package.json +1 -0
  32. package/cjs/packageInfo.js +5 -0
  33. package/cjs/proxychain.js +20 -0
  34. package/cjs/storage/QueryableStorage.js +99 -0
  35. package/cjs/types.js +2 -0
  36. package/client/Dedot.d.ts +181 -0
  37. package/client/Dedot.js +440 -0
  38. package/client/index.d.ts +1 -0
  39. package/client/index.js +1 -0
  40. package/executor/ConstantExecutor.d.ts +11 -0
  41. package/executor/ConstantExecutor.js +18 -0
  42. package/executor/ErrorExecutor.d.ts +11 -0
  43. package/executor/ErrorExecutor.js +43 -0
  44. package/executor/EventExecutor.d.ts +11 -0
  45. package/executor/EventExecutor.js +49 -0
  46. package/executor/Executor.d.ts +150 -0
  47. package/executor/Executor.js +35 -0
  48. package/executor/RpcExecutor.d.ts +14 -0
  49. package/executor/RpcExecutor.js +105 -0
  50. package/executor/RuntimeApiExecutor.d.ts +9 -0
  51. package/executor/RuntimeApiExecutor.js +89 -0
  52. package/executor/StorageQueryExecutor.d.ts +10 -0
  53. package/executor/StorageQueryExecutor.js +29 -0
  54. package/executor/TxExecutor.d.ts +47 -0
  55. package/executor/TxExecutor.js +147 -0
  56. package/executor/index.d.ts +8 -0
  57. package/executor/index.js +8 -0
  58. package/extrinsic/SubmittableResult.d.ts +19 -0
  59. package/extrinsic/SubmittableResult.js +29 -0
  60. package/extrinsic/extensions/ExtraSignedExtension.d.ts +14 -0
  61. package/extrinsic/extensions/ExtraSignedExtension.js +61 -0
  62. package/extrinsic/extensions/SignedExtension.d.ts +40 -0
  63. package/extrinsic/extensions/SignedExtension.js +37 -0
  64. package/extrinsic/extensions/index.d.ts +3 -0
  65. package/extrinsic/extensions/index.js +3 -0
  66. package/extrinsic/extensions/known/ChargeAssetTxPayment.d.ts +14 -0
  67. package/extrinsic/extensions/known/ChargeAssetTxPayment.js +40 -0
  68. package/extrinsic/extensions/known/ChargeTransactionPayment.d.ts +6 -0
  69. package/extrinsic/extensions/known/ChargeTransactionPayment.js +12 -0
  70. package/extrinsic/extensions/known/CheckGenesis.d.ts +10 -0
  71. package/extrinsic/extensions/known/CheckGenesis.js +15 -0
  72. package/extrinsic/extensions/known/CheckMortality.d.ts +15 -0
  73. package/extrinsic/extensions/known/CheckMortality.js +67 -0
  74. package/extrinsic/extensions/known/CheckNonZeroSender.d.ts +6 -0
  75. package/extrinsic/extensions/known/CheckNonZeroSender.js +6 -0
  76. package/extrinsic/extensions/known/CheckNonce.d.ts +10 -0
  77. package/extrinsic/extensions/known/CheckNonce.js +30 -0
  78. package/extrinsic/extensions/known/CheckSpecVersion.d.ts +9 -0
  79. package/extrinsic/extensions/known/CheckSpecVersion.js +15 -0
  80. package/extrinsic/extensions/known/CheckTxVersion.d.ts +9 -0
  81. package/extrinsic/extensions/known/CheckTxVersion.js +15 -0
  82. package/extrinsic/extensions/known/CheckWeight.d.ts +6 -0
  83. package/extrinsic/extensions/known/CheckWeight.js +6 -0
  84. package/extrinsic/extensions/known/PrevalidateAttests.d.ts +7 -0
  85. package/extrinsic/extensions/known/PrevalidateAttests.js +7 -0
  86. package/extrinsic/extensions/known/index.d.ts +3 -0
  87. package/extrinsic/extensions/known/index.js +22 -0
  88. package/extrinsic/index.d.ts +2 -0
  89. package/extrinsic/index.js +2 -0
  90. package/index.d.ts +6 -0
  91. package/index.js +5 -0
  92. package/package.json +54 -0
  93. package/packageInfo.d.ts +4 -0
  94. package/packageInfo.js +3 -0
  95. package/proxychain.d.ts +7 -0
  96. package/proxychain.js +16 -0
  97. package/storage/QueryableStorage.d.ts +16 -0
  98. package/storage/QueryableStorage.js +95 -0
  99. package/types.d.ts +44 -0
  100. package/types.js +1 -0
@@ -0,0 +1,440 @@
1
+ import { HttpProvider, WsProvider } from '@polkadot/rpc-provider';
2
+ import { $Metadata, CodecRegistry } from '@dedot/codecs';
3
+ import { ConstantExecutor, ErrorExecutor, EventExecutor, RpcExecutor, RuntimeApiExecutor, StorageQueryExecutor, TxExecutor, } from '../executor';
4
+ import { newProxyChain } from '../proxychain';
5
+ import { ensurePresence } from '@dedot/utils';
6
+ import localforage from 'localforage';
7
+ import { hexAddPrefix, u8aToHex } from '@polkadot/util';
8
+ export const KEEP_ALIVE_INTERVAL = 10_000; // in ms
9
+ export const CATCH_ALL_METADATA_KEY = `RAW_META/ALL`;
10
+ export const SUPPORTED_METADATA_VERSIONS = [15, 14];
11
+ /**
12
+ * @name Dedot
13
+ * @description Promised-based API Client for Polkadot & Substrate
14
+ *
15
+ * ### Initialize API instance and interact with substrate-based network
16
+ * ```typescript
17
+ * import { Dedot } from 'dedot';
18
+ * import { PolkadotApi } from '@dedot/chaintypes/polkadot';
19
+ *
20
+ * const run = async () => {
21
+ * const api = await Dedot.new<PolkadotApi>('wss://rpc.polkadot.io');
22
+ *
23
+ * // Call rpc `state_getMetadata` to fetch raw scale-encoded metadata and decode it.
24
+ * const metadata = await api.rpc.state.getMetadata();
25
+ * console.log('Metadata:', metadata);
26
+ *
27
+ * // Query on-chain storage
28
+ * const address = '14...';
29
+ * const balance = await api.query.system.account(address);
30
+ * console.log('Balance:', balance);
31
+ *
32
+ *
33
+ * // Subscribe to on-chain storage changes
34
+ * const unsub = await api.query.system.number((blockNumber) => {
35
+ * console.log(`Current block number: ${blockNumber}`);
36
+ * });
37
+ *
38
+ * // Get pallet constants
39
+ * const ss58Prefix = api.consts.system.ss58Prefix;
40
+ * console.log('Polkadot ss58Prefix:', ss58Prefix)
41
+ *
42
+ * // await unsub();
43
+ * // await api.disconnect();
44
+ * }
45
+ *
46
+ * run().catch(console.error);
47
+ * ```
48
+ */
49
+ export class Dedot {
50
+ #provider;
51
+ #registry;
52
+ #options;
53
+ #metadata;
54
+ #metadataLatest;
55
+ #genesisHash;
56
+ #runtimeVersion;
57
+ #chainProperties;
58
+ #runtimeChain;
59
+ #localCache;
60
+ #runtimeSubscriptionUnsub;
61
+ #healthTimer;
62
+ /**
63
+ * Use factory methods (`create`, `new`) to create `Dedot` instances.
64
+ *
65
+ * @param options
66
+ * @protected
67
+ */
68
+ constructor(options) {
69
+ this.#options = this.#normalizeOptions(options);
70
+ this.#provider = this.#getProvider();
71
+ this.#registry = new CodecRegistry();
72
+ }
73
+ /**
74
+ * Factory method to create a new Dedot instance
75
+ *
76
+ * @param options
77
+ */
78
+ static async create(options) {
79
+ const api = new Dedot(options);
80
+ if (api.provider instanceof WsProvider) {
81
+ await api.provider.isReady;
82
+ }
83
+ await api.init();
84
+ return api;
85
+ }
86
+ /**
87
+ * Alias for __Dedot.create__
88
+ * @param options
89
+ */
90
+ static async new(options) {
91
+ return Dedot.create(options);
92
+ }
93
+ /**
94
+ * Initialize APIs before usage
95
+ */
96
+ async init() {
97
+ await this.#initializeLocalCache();
98
+ // Fetching node information
99
+ let [genesisHash, runtimeVersion, chainName, chainProps, metadata] = await Promise.all([
100
+ this.rpc.chain.getBlockHash(0),
101
+ this.rpc.state.getRuntimeVersion(),
102
+ this.rpc.system.chain(),
103
+ this.rpc.system.properties(),
104
+ (await this.#shouldLoadPreloadMetadata()) ? this.#fetchMetadata() : Promise.resolve(undefined),
105
+ ]);
106
+ this.#genesisHash = genesisHash;
107
+ this.#runtimeVersion = runtimeVersion;
108
+ this.#chainProperties = chainProps;
109
+ this.#runtimeChain = chainName;
110
+ await this.#setupMetadata(metadata);
111
+ this.#subscribeUpdates();
112
+ }
113
+ async #initializeLocalCache() {
114
+ // Initialize local cache
115
+ if (this.#options.cacheMetadata) {
116
+ try {
117
+ // TODO add a custom driver to support nodejs
118
+ this.#localCache = localforage.createInstance({
119
+ driver: [localforage.INDEXEDDB, localforage.LOCALSTORAGE],
120
+ name: 'DedotCache',
121
+ storeName: 'LocalCache',
122
+ });
123
+ // Verify the storage is working
124
+ await this.#localCache.setItem('testKey', 'testValue');
125
+ await this.#localCache.removeItem('testKey');
126
+ }
127
+ catch (e) {
128
+ this.#localCache = undefined;
129
+ this.#options.cacheMetadata = false;
130
+ console.error('Cannot initialize local cache in this environment, disable metadata caching');
131
+ }
132
+ }
133
+ }
134
+ async #setupMetadata(preloadMetadata) {
135
+ let metadata = preloadMetadata;
136
+ const metadataKey = this.currentMetadataKey;
137
+ const optMetadataBundles = this.#options.metadata;
138
+ let shouldUpdateCache = !!metadata;
139
+ if (optMetadataBundles && !metadata) {
140
+ const optRawMetadata = optMetadataBundles[CATCH_ALL_METADATA_KEY] || optMetadataBundles[metadataKey];
141
+ if (optRawMetadata) {
142
+ metadata = $Metadata.tryDecode(optRawMetadata);
143
+ }
144
+ }
145
+ try {
146
+ if (this.#localCache && this.#options.cacheMetadata) {
147
+ if (!metadata) {
148
+ try {
149
+ const cachedRawMetadata = await this.#localCache.getItem(metadataKey);
150
+ if (cachedRawMetadata) {
151
+ metadata = $Metadata.tryDecode(cachedRawMetadata);
152
+ }
153
+ }
154
+ catch (e) {
155
+ console.error('Cannot decode raw metadata, try fetching fresh metadata from chain.', e);
156
+ }
157
+ }
158
+ }
159
+ }
160
+ finally {
161
+ if (!metadata) {
162
+ metadata = await this.#fetchMetadata();
163
+ if (this.#options.cacheMetadata)
164
+ shouldUpdateCache = true;
165
+ }
166
+ }
167
+ if (shouldUpdateCache && this.#localCache) {
168
+ await this.#localCache.setItem(metadataKey, u8aToHex($Metadata.tryEncode(metadata)));
169
+ }
170
+ if (!metadata) {
171
+ throw new Error('Cannot load metadata');
172
+ }
173
+ this.setMetadata(metadata);
174
+ }
175
+ async #fetchMetadata() {
176
+ // It makes sense to call metadata.metadataVersions to fetch the list of supported metadata versions first
177
+ // But for now, this approach could potentially help save/reduce one rpc call to the server in case the node support v15
178
+ // Question: Why not having a `metadata.metadataLatest` to fetch the latest version?
179
+ for (const version of SUPPORTED_METADATA_VERSIONS) {
180
+ try {
181
+ const rawMetadata = await this.call.metadata.metadataAtVersion(version);
182
+ if (!rawMetadata)
183
+ continue;
184
+ return $Metadata.tryDecode(rawMetadata);
185
+ }
186
+ catch { }
187
+ }
188
+ try {
189
+ return $Metadata.tryDecode(await this.call.metadata.metadata());
190
+ }
191
+ catch {
192
+ return await this.rpc.state.getMetadata();
193
+ }
194
+ }
195
+ #subscribeRuntimeUpgrades() {
196
+ // Disable runtime upgrades subscriptions if using a catch all metadata
197
+ if (this.#runtimeSubscriptionUnsub || !this.hasSubscriptions || this.hasCatchAllMetadata) {
198
+ return;
199
+ }
200
+ this.rpc.state
201
+ .subscribeRuntimeVersion(async (runtimeVersion) => {
202
+ if (runtimeVersion.specVersion !== this.#runtimeVersion?.specVersion) {
203
+ this.#runtimeVersion = runtimeVersion;
204
+ const newMetadata = await this.#fetchMetadata();
205
+ await this.#setupMetadata(newMetadata);
206
+ }
207
+ })
208
+ .then((unsub) => {
209
+ this.#runtimeSubscriptionUnsub = unsub;
210
+ });
211
+ }
212
+ #subscribeHealth() {
213
+ this.#unsubscribeHealth();
214
+ this.#healthTimer = setInterval(() => {
215
+ this.rpc.system.health().catch(console.error);
216
+ }, KEEP_ALIVE_INTERVAL);
217
+ }
218
+ #unsubscribeHealth() {
219
+ if (!this.#healthTimer) {
220
+ return;
221
+ }
222
+ clearInterval(this.#healthTimer);
223
+ this.#healthTimer = undefined;
224
+ }
225
+ async #unsubscribeRuntimeUpdates() {
226
+ if (!this.#runtimeSubscriptionUnsub) {
227
+ return;
228
+ }
229
+ await this.#runtimeSubscriptionUnsub();
230
+ this.#runtimeSubscriptionUnsub = undefined;
231
+ }
232
+ #subscribeUpdates() {
233
+ this.#subscribeRuntimeUpgrades();
234
+ this.#subscribeHealth();
235
+ }
236
+ async #unsubscribeUpdates() {
237
+ await this.#unsubscribeRuntimeUpdates();
238
+ this.#unsubscribeHealth();
239
+ }
240
+ async #shouldLoadPreloadMetadata() {
241
+ if (this.#options.metadata && Object.keys(this.#options.metadata).length) {
242
+ return false;
243
+ }
244
+ if (!this.#options.cacheMetadata || !this.#localCache) {
245
+ return true;
246
+ }
247
+ // TODO improve this
248
+ const keys = await this.#localCache.keys();
249
+ return !keys.some((k) => k.startsWith('RAW_META/'));
250
+ }
251
+ #normalizeOptions(options) {
252
+ if (typeof options === 'string') {
253
+ return { endpoint: options };
254
+ }
255
+ else {
256
+ let { metadata } = options;
257
+ if (metadata && typeof metadata === 'string') {
258
+ metadata = {
259
+ [CATCH_ALL_METADATA_KEY]: hexAddPrefix(metadata),
260
+ };
261
+ }
262
+ return { ...options, metadata };
263
+ }
264
+ }
265
+ #getProvider() {
266
+ const { provider, endpoint } = this.#options;
267
+ if (provider)
268
+ return provider;
269
+ if (endpoint) {
270
+ if (endpoint.startsWith('ws://') || endpoint.startsWith('wss://')) {
271
+ return new WsProvider(endpoint);
272
+ }
273
+ else if (endpoint.startsWith('http://') || endpoint.startsWith('https://')) {
274
+ return new HttpProvider(endpoint);
275
+ }
276
+ else {
277
+ throw new Error('Invalid network endpoint, a valid endpoint should start with `wss://`, `ws://`, `https://` or `http://`');
278
+ }
279
+ }
280
+ // TODO support light-client
281
+ return new WsProvider();
282
+ }
283
+ /**
284
+ * @description Entry-point for executing RPCs to blockchain node.
285
+ *
286
+ * ```typescript
287
+ * // Subscribe to new heads
288
+ * api.rpc.chain.subscribeNewHeads((header) => {
289
+ * console.log(header);
290
+ * });
291
+ *
292
+ * // Execute arbitrary rpc method: `module_rpc_name`
293
+ * const result = await api.rpc.module.rpc_name();
294
+ * ```
295
+ */
296
+ get rpc() {
297
+ // TODO add executable carrier to support calling arbitrary rpc methods via api.rpc(<method>)
298
+ return newProxyChain({ executor: new RpcExecutor(this) });
299
+ }
300
+ /**
301
+ * @description Entry-point for inspecting constants (parameter types) for all pallets (modules).
302
+ *
303
+ * ```typescript
304
+ * const ss58Prefix = api.consts.system.ss58Prefix;
305
+ * console.log('ss58Prefix:', ss58Prefix)
306
+ * ```
307
+ */
308
+ get consts() {
309
+ return newProxyChain({ executor: new ConstantExecutor(this) });
310
+ }
311
+ /**
312
+ * @description Entry-point for executing query to on-chain storage.
313
+ *
314
+ * ```typescript
315
+ * const balance = await api.query.system.account(<address>);
316
+ * console.log('Balance:', balance);
317
+ * ```
318
+ */
319
+ get query() {
320
+ return newProxyChain({ executor: new StorageQueryExecutor(this) });
321
+ }
322
+ queryAt(blockHash) {
323
+ return newProxyChain({ executor: new StorageQueryExecutor(this, blockHash) });
324
+ }
325
+ /**
326
+ * @description Entry-point for inspecting errors from metadata
327
+ */
328
+ get errors() {
329
+ return newProxyChain({ executor: new ErrorExecutor(this) });
330
+ }
331
+ /**
332
+ * @description Entry-point for inspecting events from metadata
333
+ */
334
+ get events() {
335
+ return newProxyChain({ executor: new EventExecutor(this) });
336
+ }
337
+ get call() {
338
+ return newProxyChain({ executor: new RuntimeApiExecutor(this) });
339
+ }
340
+ callAt(blockHash) {
341
+ return newProxyChain({ executor: new RuntimeApiExecutor(this, blockHash) });
342
+ }
343
+ get tx() {
344
+ return newProxyChain({ executor: new TxExecutor(this) });
345
+ }
346
+ /**
347
+ * @description Current provider for api connection
348
+ */
349
+ get provider() {
350
+ return this.#provider;
351
+ }
352
+ /**
353
+ * @description Codec registry
354
+ */
355
+ get registry() {
356
+ return this.#registry;
357
+ }
358
+ /**
359
+ * @description Check if metadata is present
360
+ */
361
+ get hasMetadata() {
362
+ return !!this.#metadata && !!this.#metadataLatest;
363
+ }
364
+ get metadata() {
365
+ return ensurePresence(this.#metadata);
366
+ }
367
+ get metadataLatest() {
368
+ return ensurePresence(this.#metadataLatest);
369
+ }
370
+ /**
371
+ * Setup metadata for
372
+ * @param metadata
373
+ */
374
+ setMetadata(metadata) {
375
+ this.#metadata = metadata;
376
+ this.#metadataLatest = metadata.latest;
377
+ this.registry.setMetadata(this.#metadataLatest);
378
+ }
379
+ /**
380
+ * @description Disconnect to blockchain node
381
+ */
382
+ async disconnect() {
383
+ await this.#unsubscribeUpdates();
384
+ await this.#provider.disconnect();
385
+ }
386
+ /**
387
+ * @description Clear local cache
388
+ */
389
+ async clearCache() {
390
+ await this.#localCache?.clear();
391
+ }
392
+ /**
393
+ * @description Check if current provider can make subscription request (e.: via WebSocket)
394
+ */
395
+ get hasSubscriptions() {
396
+ return this.provider.hasSubscriptions;
397
+ }
398
+ /**
399
+ * @description Check if it's connected to the blockchain node
400
+ */
401
+ get isConnected() {
402
+ return this.provider.isConnected;
403
+ }
404
+ /**
405
+ * @description Check if the api instance is using a catch-all metadata
406
+ */
407
+ get hasCatchAllMetadata() {
408
+ return !!this.#options.metadata && !!this.#options.metadata[CATCH_ALL_METADATA_KEY];
409
+ }
410
+ get currentMetadataKey() {
411
+ return `RAW_META/${this.#genesisHash || '0x'}/${this.#runtimeVersion?.specVersion || '---'}`;
412
+ }
413
+ /**
414
+ * @description Genesis hash of connected blockchain node
415
+ */
416
+ get genesisHash() {
417
+ return this.#genesisHash;
418
+ }
419
+ /**
420
+ * @description Runtime version of connected blockchain node
421
+ */
422
+ get runtimeVersion() {
423
+ return this.#runtimeVersion;
424
+ }
425
+ /**
426
+ * @description Chain properties of connected blockchain node
427
+ */
428
+ get chainProperties() {
429
+ return this.#chainProperties;
430
+ }
431
+ /**
432
+ * @description Runtime chain name of connected blockchain node
433
+ */
434
+ get runtimeChain() {
435
+ return this.#runtimeChain;
436
+ }
437
+ get options() {
438
+ return this.#options;
439
+ }
440
+ }
@@ -0,0 +1 @@
1
+ export * from './Dedot';
@@ -0,0 +1 @@
1
+ export * from './Dedot';
@@ -0,0 +1,11 @@
1
+ import type { SubstrateApi } from '@dedot/chaintypes';
2
+ import { GenericSubstrateApi } from '@dedot/types';
3
+ import { Executor } from './Executor';
4
+ /**
5
+ * @name ConstantExecutor
6
+ *
7
+ * Find & decode the constant value from metadata
8
+ */
9
+ export declare class ConstantExecutor<ChainApi extends GenericSubstrateApi = SubstrateApi> extends Executor<ChainApi> {
10
+ execute(pallet: string, constantName: string): unknown;
11
+ }
@@ -0,0 +1,18 @@
1
+ import { stringCamelCase } from '@polkadot/util';
2
+ import { Executor } from './Executor';
3
+ /**
4
+ * @name ConstantExecutor
5
+ *
6
+ * Find & decode the constant value from metadata
7
+ */
8
+ export class ConstantExecutor extends Executor {
9
+ execute(pallet, constantName) {
10
+ const targetPallet = this.getPallet(pallet);
11
+ const constantDef = targetPallet.constants.find((one) => stringCamelCase(one.name) === constantName);
12
+ if (!constantDef) {
13
+ throw new Error(`Constant ${constantName} not found in pallet ${pallet}`);
14
+ }
15
+ const $codec = this.registry.findPortableCodec(constantDef.typeId);
16
+ return $codec.tryDecode(constantDef.value);
17
+ }
18
+ }
@@ -0,0 +1,11 @@
1
+ import { GenericPalletError, GenericSubstrateApi } from '@dedot/types';
2
+ import { SubstrateApi } from '@dedot/chaintypes';
3
+ import { Executor } from './Executor';
4
+ /**
5
+ * @name ErrorExecutor
6
+ * @description Find pallet error information from metadata
7
+ */
8
+ export declare class ErrorExecutor<ChainApi extends GenericSubstrateApi = SubstrateApi> extends Executor<ChainApi> {
9
+ #private;
10
+ execute(pallet: string, errorName: string): GenericPalletError;
11
+ }
@@ -0,0 +1,43 @@
1
+ import { Executor } from './Executor';
2
+ import { assert } from '@dedot/utils';
3
+ import { hexToU8a, isHex, isNumber, isObject, stringPascalCase } from '@polkadot/util';
4
+ /**
5
+ * @name ErrorExecutor
6
+ * @description Find pallet error information from metadata
7
+ */
8
+ export class ErrorExecutor extends Executor {
9
+ execute(pallet, errorName) {
10
+ const targetPallet = this.getPallet(pallet);
11
+ const errorTypeId = targetPallet.error;
12
+ assert(errorTypeId, `Not found error with id ${errorTypeId} in pallet ${pallet}`);
13
+ const errorDef = this.#getErrorDef(errorTypeId, errorName);
14
+ return {
15
+ meta: {
16
+ ...errorDef,
17
+ pallet: targetPallet.name,
18
+ palletIndex: targetPallet.index,
19
+ },
20
+ is: (errorInfo) => {
21
+ if (isObject(errorInfo) && errorInfo.tag === 'Module') {
22
+ errorInfo = errorInfo.value;
23
+ }
24
+ if (isObject(errorInfo) && isNumber(errorInfo.index) && isHex(errorInfo.error)) {
25
+ return errorInfo.index === targetPallet.index && hexToU8a(errorInfo.error)[0] === errorDef.index;
26
+ }
27
+ return false;
28
+ },
29
+ };
30
+ }
31
+ #getErrorDef(errorTypeId, errorName) {
32
+ const def = this.metadata.types[errorTypeId];
33
+ assert(def, `Error def not found for id ${errorTypeId}`);
34
+ const { tag, value } = def.type;
35
+ assert(tag === 'Enum', `Error type should be an enum, found: ${tag}`);
36
+ const errorDef = value.members.find(({ name }) => stringPascalCase(name) === errorName);
37
+ assert(errorDef, `Error def not found for ${errorName}`);
38
+ return {
39
+ ...errorDef,
40
+ fieldCodecs: errorDef.fields.map(({ typeId }) => this.registry.findPortableCodec(typeId)),
41
+ };
42
+ }
43
+ }
@@ -0,0 +1,11 @@
1
+ import { GenericPalletEvent, GenericSubstrateApi } from '@dedot/types';
2
+ import { SubstrateApi } from '@dedot/chaintypes';
3
+ import { Executor } from './Executor';
4
+ /**
5
+ * @name EventExecutor
6
+ * @description Find pallet event information from metadata
7
+ */
8
+ export declare class EventExecutor<ChainApi extends GenericSubstrateApi = SubstrateApi> extends Executor<ChainApi> {
9
+ #private;
10
+ execute(pallet: string, errorName: string): GenericPalletEvent<string, string>;
11
+ }
@@ -0,0 +1,49 @@
1
+ import { Executor } from './Executor';
2
+ import { stringCamelCase, stringPascalCase } from '@polkadot/util';
3
+ import { assert } from '@dedot/utils';
4
+ /**
5
+ * @name EventExecutor
6
+ * @description Find pallet event information from metadata
7
+ */
8
+ export class EventExecutor extends Executor {
9
+ execute(pallet, errorName) {
10
+ const targetPallet = this.getPallet(pallet);
11
+ const eventTypeId = targetPallet.event;
12
+ assert(eventTypeId, `Not found event with id ${eventTypeId} in pallet ${pallet}`);
13
+ const eventDef = this.#getEventDef(eventTypeId, errorName);
14
+ const is = (event) => {
15
+ const palletCheck = stringCamelCase(event.pallet) === pallet;
16
+ if (typeof event.palletEvent === 'string') {
17
+ return palletCheck && stringPascalCase(event.palletEvent) === errorName;
18
+ }
19
+ else if (typeof event.palletEvent === 'object') {
20
+ return palletCheck && stringPascalCase(event.palletEvent.name) === errorName;
21
+ }
22
+ return false;
23
+ };
24
+ const as = (event) => {
25
+ return is(event) ? event : undefined;
26
+ };
27
+ return {
28
+ is,
29
+ as,
30
+ meta: {
31
+ ...eventDef,
32
+ pallet: targetPallet.name,
33
+ palletIndex: targetPallet.index,
34
+ },
35
+ };
36
+ }
37
+ #getEventDef(eventTypeId, errorName) {
38
+ const def = this.metadata.types[eventTypeId];
39
+ assert(def, `Event def not found for id ${eventTypeId}`);
40
+ const { tag, value } = def.type;
41
+ assert(tag === 'Enum', `Event type should be an enum, found: ${tag}`);
42
+ const eventDef = value.members.find(({ name }) => stringPascalCase(name) === errorName);
43
+ assert(eventDef, `Event def not found for ${errorName}`);
44
+ return {
45
+ ...eventDef,
46
+ fieldCodecs: eventDef.fields.map(({ typeId }) => this.registry.findPortableCodec(typeId)),
47
+ };
48
+ }
49
+ }