@dedot/api 0.8.1 → 0.9.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.
- package/cjs/client/BaseSubstrateClient.js +25 -1
- package/cjs/client/DedotClient.js +4 -0
- package/cjs/client/LegacyClient.js +4 -0
- package/cjs/executor/StorageQueryExecutor.js +8 -15
- package/cjs/executor/v2/StorageQueryExecutorV2.js +7 -33
- package/cjs/extrinsic/extensions/ExtraSignedExtension.js +24 -5
- package/cjs/extrinsic/extensions/FallbackSignedExtension.js +63 -0
- package/cjs/extrinsic/extensions/index.js +1 -0
- package/cjs/extrinsic/extensions/known/index.js +11 -8
- package/cjs/storage/BaseStorageQuery.js +27 -0
- package/cjs/storage/LegacyStorageQuery.js +69 -0
- package/cjs/storage/NewStorageQuery.js +85 -0
- package/cjs/storage/index.js +3 -0
- package/client/BaseSubstrateClient.d.ts +34 -1
- package/client/BaseSubstrateClient.js +25 -1
- package/client/DedotClient.d.ts +3 -1
- package/client/DedotClient.js +4 -0
- package/client/LegacyClient.d.ts +3 -1
- package/client/LegacyClient.js +4 -0
- package/executor/StorageQueryExecutor.d.ts +3 -2
- package/executor/StorageQueryExecutor.js +7 -14
- package/executor/v2/StorageQueryExecutorV2.d.ts +4 -6
- package/executor/v2/StorageQueryExecutorV2.js +7 -33
- package/extrinsic/extensions/ExtraSignedExtension.d.ts +6 -0
- package/extrinsic/extensions/ExtraSignedExtension.js +25 -6
- package/extrinsic/extensions/FallbackSignedExtension.d.ts +33 -0
- package/extrinsic/extensions/FallbackSignedExtension.js +58 -0
- package/extrinsic/extensions/index.d.ts +1 -0
- package/extrinsic/extensions/index.js +1 -0
- package/extrinsic/extensions/known/index.d.ts +11 -0
- package/extrinsic/extensions/known/index.js +11 -8
- package/package.json +10 -10
- package/storage/BaseStorageQuery.d.ts +41 -0
- package/storage/BaseStorageQuery.js +23 -0
- package/storage/LegacyStorageQuery.d.ts +35 -0
- package/storage/LegacyStorageQuery.js +65 -0
- package/storage/NewStorageQuery.d.ts +35 -0
- package/storage/NewStorageQuery.js +81 -0
- package/storage/index.d.ts +3 -0
- package/storage/index.js +3 -0
- package/types.d.ts +17 -1
- package/cjs/extrinsic/extensions/known/CheckNonZeroSender.js +0 -10
- package/cjs/extrinsic/extensions/known/CheckWeight.js +0 -10
- package/cjs/extrinsic/extensions/known/PrevalidateAttests.js +0 -11
- package/cjs/extrinsic/extensions/known/StorageWeightReclaim.js +0 -10
- package/extrinsic/extensions/known/CheckNonZeroSender.d.ts +0 -6
- package/extrinsic/extensions/known/CheckNonZeroSender.js +0 -6
- package/extrinsic/extensions/known/CheckWeight.d.ts +0 -6
- package/extrinsic/extensions/known/CheckWeight.js +0 -6
- package/extrinsic/extensions/known/PrevalidateAttests.d.ts +0 -7
- package/extrinsic/extensions/known/PrevalidateAttests.js +0 -7
- package/extrinsic/extensions/known/StorageWeightReclaim.d.ts +0 -6
- package/extrinsic/extensions/known/StorageWeightReclaim.js +0 -6
package/client/LegacyClient.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { BlockHash } from '@dedot/codecs';
|
|
2
2
|
import type { JsonRpcProvider } from '@dedot/providers';
|
|
3
|
-
import { GenericSubstrateApi, RpcLegacy, VersionedGenericSubstrateApi } from '@dedot/types';
|
|
3
|
+
import { GenericSubstrateApi, RpcLegacy, RpcVersion, VersionedGenericSubstrateApi } from '@dedot/types';
|
|
4
4
|
import type { SubstrateApi } from '../chaintypes/index.js';
|
|
5
|
+
import { BaseStorageQuery } from '../storage/index.js';
|
|
5
6
|
import type { ApiOptions, ISubstrateClientAt } from '../types.js';
|
|
6
7
|
import { BaseSubstrateClient } from './BaseSubstrateClient.js';
|
|
7
8
|
/**
|
|
@@ -129,4 +130,5 @@ export declare class LegacyClient<ChainApi extends VersionedGenericSubstrateApi
|
|
|
129
130
|
* @param hash
|
|
130
131
|
*/
|
|
131
132
|
at<ChainApiAt extends GenericSubstrateApi = ChainApi[RpcLegacy]>(hash: BlockHash): Promise<ISubstrateClientAt<ChainApiAt>>;
|
|
133
|
+
protected getStorageQuery(): BaseStorageQuery<RpcVersion>;
|
|
132
134
|
}
|
package/client/LegacyClient.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { PortableRegistry } from '@dedot/codecs';
|
|
2
2
|
import { ConstantExecutor, ErrorExecutor, EventExecutor, RuntimeApiExecutor, StorageQueryExecutor, TxExecutor, } from '../executor/index.js';
|
|
3
3
|
import { newProxyChain } from '../proxychain.js';
|
|
4
|
+
import { LegacyStorageQuery } from '../storage/index.js';
|
|
4
5
|
import { BaseSubstrateClient } from './BaseSubstrateClient.js';
|
|
5
6
|
const KEEP_ALIVE_INTERVAL = 10_000; // in ms
|
|
6
7
|
/**
|
|
@@ -247,4 +248,7 @@ export class LegacyClient// prettier-end-here
|
|
|
247
248
|
this.#apiAtCache[hash] = api;
|
|
248
249
|
return api;
|
|
249
250
|
}
|
|
251
|
+
getStorageQuery() {
|
|
252
|
+
return new LegacyStorageQuery(this);
|
|
253
|
+
}
|
|
250
254
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BlockHash, Option, StorageData, StorageKey } from '@dedot/codecs';
|
|
2
|
-
import type { AsyncMethod, Callback, GenericStorageQuery, GenericSubstrateApi, Unsub } from '@dedot/types';
|
|
3
|
-
import { QueryableStorage } from '../storage/
|
|
2
|
+
import type { AsyncMethod, Callback, GenericStorageQuery, GenericSubstrateApi, RpcVersion, Unsub } from '@dedot/types';
|
|
3
|
+
import { type BaseStorageQuery, QueryableStorage } from '../storage/index.js';
|
|
4
4
|
import { Executor } from './Executor.js';
|
|
5
5
|
/**
|
|
6
6
|
* @name StorageQueryExecutor
|
|
@@ -9,6 +9,7 @@ import { Executor } from './Executor.js';
|
|
|
9
9
|
export declare class StorageQueryExecutor<ChainApi extends GenericSubstrateApi = GenericSubstrateApi> extends Executor<ChainApi> {
|
|
10
10
|
doExecute(pallet: string, storage: string): GenericStorageQuery;
|
|
11
11
|
protected exposeStorageMapMethods(entry: QueryableStorage): Record<string, AsyncMethod>;
|
|
12
|
+
protected getStorageQuery(): BaseStorageQuery<RpcVersion>;
|
|
12
13
|
protected queryStorage(keys: StorageKey[], hash?: BlockHash): Promise<Record<StorageKey, Option<StorageData>>>;
|
|
13
14
|
protected subscribeStorage(keys: StorageKey[], callback: Callback<Array<StorageData | undefined>>): Promise<Unsub>;
|
|
14
15
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { assert, isFunction, isObject } from '@dedot/utils';
|
|
2
|
-
import { QueryableStorage } from '../storage/
|
|
2
|
+
import { LegacyStorageQuery, QueryableStorage } from '../storage/index.js';
|
|
3
3
|
import { Executor } from './Executor.js';
|
|
4
4
|
const DEFAULT_KEYS_PAGE_SIZE = 1000;
|
|
5
5
|
const DEFAULT_ENTRIES_PAGE_SIZE = 250;
|
|
@@ -98,22 +98,15 @@ export class StorageQueryExecutor extends Executor {
|
|
|
98
98
|
};
|
|
99
99
|
return { pagedKeys, pagedEntries };
|
|
100
100
|
}
|
|
101
|
+
getStorageQuery() {
|
|
102
|
+
return new LegacyStorageQuery(this.client);
|
|
103
|
+
}
|
|
101
104
|
async queryStorage(keys, hash) {
|
|
102
|
-
|
|
103
|
-
return changeSets[0].changes.reduce((o, [key, value]) => {
|
|
104
|
-
o[key] = value ?? undefined;
|
|
105
|
-
return o;
|
|
106
|
-
}, {});
|
|
105
|
+
return this.getStorageQuery().query(keys, hash);
|
|
107
106
|
}
|
|
108
107
|
subscribeStorage(keys, callback) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
changeSet.changes.forEach(([key, value]) => {
|
|
112
|
-
if (lastChanges[key] !== value) {
|
|
113
|
-
lastChanges[key] = value ?? undefined;
|
|
114
|
-
}
|
|
115
|
-
});
|
|
116
|
-
return callback(keys.map((key) => lastChanges[key]));
|
|
108
|
+
return this.getStorageQuery().subscribe(keys, (results) => {
|
|
109
|
+
callback(keys.map((key) => results[key]));
|
|
117
110
|
});
|
|
118
111
|
}
|
|
119
112
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { BlockHash
|
|
2
|
-
import type { AsyncMethod,
|
|
3
|
-
import { HexString } from '@dedot/utils';
|
|
1
|
+
import { BlockHash } from '@dedot/codecs';
|
|
2
|
+
import type { AsyncMethod, GenericSubstrateApi, RpcVersion } from '@dedot/types';
|
|
4
3
|
import { ChainHead } from '../../json-rpc/index.js';
|
|
5
|
-
import { QueryableStorage } from '../../storage/
|
|
4
|
+
import { type BaseStorageQuery, QueryableStorage } from '../../storage/index.js';
|
|
6
5
|
import { ISubstrateClientAt } from '../../types.js';
|
|
7
6
|
import { StorageQueryExecutor } from '../StorageQueryExecutor.js';
|
|
8
7
|
/**
|
|
@@ -12,6 +11,5 @@ export declare class StorageQueryExecutorV2<ChainApi extends GenericSubstrateApi
|
|
|
12
11
|
chainHead: ChainHead;
|
|
13
12
|
constructor(client: ISubstrateClientAt<ChainApi>, chainHead: ChainHead, atBlockHash?: BlockHash);
|
|
14
13
|
protected exposeStorageMapMethods(entry: QueryableStorage): Record<string, AsyncMethod>;
|
|
15
|
-
protected
|
|
16
|
-
protected subscribeStorage(keys: HexString[], callback: Callback<Array<StorageData | undefined>>): Promise<() => Promise<void>>;
|
|
14
|
+
protected getStorageQuery(): BaseStorageQuery<RpcVersion>;
|
|
17
15
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { assert } from '@dedot/utils';
|
|
2
|
+
import { NewStorageQuery } from '../../storage/index.js';
|
|
2
3
|
import { StorageQueryExecutor } from '../StorageQueryExecutor.js';
|
|
3
4
|
/**
|
|
4
5
|
* @name StorageQueryExecutorV2
|
|
@@ -28,38 +29,11 @@ export class StorageQueryExecutorV2 extends StorageQueryExecutor {
|
|
|
28
29
|
};
|
|
29
30
|
return { entries };
|
|
30
31
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
async subscribeStorage(keys, callback) {
|
|
39
|
-
let best = await this.chainHead.bestBlock();
|
|
40
|
-
let eventToListen = 'bestBlock';
|
|
41
|
-
// TODO subscribe to finalized data source
|
|
42
|
-
// initialHash = this.chainHead.finalizedHash;
|
|
43
|
-
// eventToListen = 'finalizedBlock';
|
|
44
|
-
const latestChanges = new Map();
|
|
45
|
-
const pull = async ({ hash }) => {
|
|
46
|
-
const results = await this.queryStorage(keys, hash);
|
|
47
|
-
let changed = false;
|
|
48
|
-
keys.forEach((key) => {
|
|
49
|
-
const newValue = results[key];
|
|
50
|
-
if (latestChanges.size > 0 && latestChanges.get(key) === newValue)
|
|
51
|
-
return;
|
|
52
|
-
changed = true;
|
|
53
|
-
latestChanges.set(key, newValue);
|
|
54
|
-
});
|
|
55
|
-
if (!changed)
|
|
56
|
-
return;
|
|
57
|
-
callback(keys.map((key) => latestChanges.get(key)));
|
|
58
|
-
};
|
|
59
|
-
await pull(best);
|
|
60
|
-
const unsub = this.chainHead.on(eventToListen, pull);
|
|
61
|
-
return async () => {
|
|
62
|
-
unsub();
|
|
63
|
-
};
|
|
32
|
+
getStorageQuery() {
|
|
33
|
+
// @ts-ignore little trick to make querying data client.at instance works here,
|
|
34
|
+
// TODO need to rethink about this
|
|
35
|
+
if (!this.client['chainHead'])
|
|
36
|
+
this.client['chainHead'] = this.chainHead;
|
|
37
|
+
return new NewStorageQuery(this.client);
|
|
64
38
|
}
|
|
65
39
|
}
|
|
@@ -9,6 +9,12 @@ export declare class ExtraSignedExtension extends SignedExtension<any[], any[]>
|
|
|
9
9
|
get $Data(): $.AnyShape;
|
|
10
10
|
get $AdditionalSigned(): $.AnyShape;
|
|
11
11
|
get $Payload(): $.AnyShape;
|
|
12
|
+
/**
|
|
13
|
+
* Check if the extension requires no external inputs (e.g: struct or tuple with empty types like `()` or `[]`)
|
|
14
|
+
* @param extDef - The definition of the signed extension
|
|
15
|
+
* @returns boolean
|
|
16
|
+
*/
|
|
17
|
+
private isRequireNoExternalInputs;
|
|
12
18
|
toPayload(call?: HexString): SignerPayloadJSON;
|
|
13
19
|
toRawPayload(call?: HexString): SignerPayloadRaw;
|
|
14
20
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as $ from '@dedot/shape';
|
|
2
|
-
import {
|
|
2
|
+
import { ensurePresence, u8aToHex } from '@dedot/utils';
|
|
3
3
|
import { SignedExtension } from './SignedExtension.js';
|
|
4
|
+
import { FallbackSignedExtension, isEmptyStructOrTuple } from './FallbackSignedExtension.js';
|
|
4
5
|
import { knownSignedExtensions } from './known/index.js';
|
|
5
6
|
export class ExtraSignedExtension extends SignedExtension {
|
|
6
7
|
#signedExtensions;
|
|
@@ -34,13 +35,31 @@ export class ExtraSignedExtension extends SignedExtension {
|
|
|
34
35
|
const { signedExtensions: userSignedExtensions = {} } = this.client.options;
|
|
35
36
|
const Extension = userSignedExtensions[extDef.ident] ||
|
|
36
37
|
knownSignedExtensions[extDef.ident];
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
if (Extension) {
|
|
39
|
+
return new Extension(this.client, {
|
|
40
|
+
...ensurePresence(this.options),
|
|
41
|
+
def: extDef,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
else if (this.isRequireNoExternalInputs(extDef)) {
|
|
45
|
+
return new FallbackSignedExtension(this.client, {
|
|
46
|
+
...ensurePresence(this.options),
|
|
47
|
+
def: extDef,
|
|
48
|
+
}, extDef.ident);
|
|
49
|
+
}
|
|
50
|
+
// For extensions that require input but aren't implemented, throw an error
|
|
51
|
+
throw new Error(`SignedExtension for ${extDef.ident} requires input but is not implemented`);
|
|
42
52
|
});
|
|
43
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Check if the extension requires no external inputs (e.g: struct or tuple with empty types like `()` or `[]`)
|
|
56
|
+
* @param extDef - The definition of the signed extension
|
|
57
|
+
* @returns boolean
|
|
58
|
+
*/
|
|
59
|
+
isRequireNoExternalInputs(extDef) {
|
|
60
|
+
return (isEmptyStructOrTuple(this.registry, extDef.typeId) &&
|
|
61
|
+
isEmptyStructOrTuple(this.registry, extDef.additionalSigned));
|
|
62
|
+
}
|
|
44
63
|
toPayload(call = '0x') {
|
|
45
64
|
const signedExtensions = this.#signedExtensions.map((se) => se.identifier);
|
|
46
65
|
const { version } = this.registry.metadata.extrinsic;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { PortableRegistry } from '@dedot/codecs';
|
|
2
|
+
import { SignerPayloadJSON } from '@dedot/types';
|
|
3
|
+
import { SignedExtension } from './SignedExtension.js';
|
|
4
|
+
import { ISubstrateClient } from '../../types.js';
|
|
5
|
+
/**
|
|
6
|
+
* A fallback signed extension that can be used for extensions
|
|
7
|
+
* that don't require external input.
|
|
8
|
+
*
|
|
9
|
+
* This extension is automatically used for:
|
|
10
|
+
* - Unknown extensions with empty struct or tuple types
|
|
11
|
+
* - Known extensions that don't require input, such as:
|
|
12
|
+
* - CheckNonZeroSender: Ensures sender is not the zero address
|
|
13
|
+
* - CheckWeight: Block resource (weight) limit check
|
|
14
|
+
* - PrevalidateAttests: Validates `attest` calls prior to execution
|
|
15
|
+
* - StorageWeightReclaim: Storage weight reclaim mechanism
|
|
16
|
+
*
|
|
17
|
+
* These extensions have empty struct or tuple types and don't need explicit implementation.
|
|
18
|
+
*/
|
|
19
|
+
export declare class FallbackSignedExtension extends SignedExtension {
|
|
20
|
+
private readonly extensionIdent;
|
|
21
|
+
constructor(client: ISubstrateClient, options: any, extensionIdent: string);
|
|
22
|
+
get identifier(): string;
|
|
23
|
+
init(): Promise<void>;
|
|
24
|
+
toPayload(): Partial<SignerPayloadJSON>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Checks if a type is an empty struct or tuple (doesn't require external input).
|
|
28
|
+
*
|
|
29
|
+
* @param registry The portable registry
|
|
30
|
+
* @param typeId The type ID to check
|
|
31
|
+
* @returns True if the type is an empty struct or tuple, false otherwise
|
|
32
|
+
*/
|
|
33
|
+
export declare function isEmptyStructOrTuple(registry: PortableRegistry, typeId: number): boolean;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { SignedExtension } from './SignedExtension.js';
|
|
2
|
+
/**
|
|
3
|
+
* A fallback signed extension that can be used for extensions
|
|
4
|
+
* that don't require external input.
|
|
5
|
+
*
|
|
6
|
+
* This extension is automatically used for:
|
|
7
|
+
* - Unknown extensions with empty struct or tuple types
|
|
8
|
+
* - Known extensions that don't require input, such as:
|
|
9
|
+
* - CheckNonZeroSender: Ensures sender is not the zero address
|
|
10
|
+
* - CheckWeight: Block resource (weight) limit check
|
|
11
|
+
* - PrevalidateAttests: Validates `attest` calls prior to execution
|
|
12
|
+
* - StorageWeightReclaim: Storage weight reclaim mechanism
|
|
13
|
+
*
|
|
14
|
+
* These extensions have empty struct or tuple types and don't need explicit implementation.
|
|
15
|
+
*/
|
|
16
|
+
export class FallbackSignedExtension extends SignedExtension {
|
|
17
|
+
extensionIdent;
|
|
18
|
+
constructor(client, options, extensionIdent) {
|
|
19
|
+
super(client, options);
|
|
20
|
+
this.extensionIdent = extensionIdent;
|
|
21
|
+
}
|
|
22
|
+
get identifier() {
|
|
23
|
+
return this.extensionIdent;
|
|
24
|
+
}
|
|
25
|
+
async init() {
|
|
26
|
+
// Initialize with empty data and additionalSigned
|
|
27
|
+
this.data = {};
|
|
28
|
+
this.additionalSigned = [];
|
|
29
|
+
}
|
|
30
|
+
toPayload() {
|
|
31
|
+
return {}; // No payload contribution
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Checks if a type is an empty struct or tuple (doesn't require external input).
|
|
36
|
+
*
|
|
37
|
+
* @param registry The portable registry
|
|
38
|
+
* @param typeId The type ID to check
|
|
39
|
+
* @returns True if the type is an empty struct or tuple, false otherwise
|
|
40
|
+
*/
|
|
41
|
+
export function isEmptyStructOrTuple(registry, typeId) {
|
|
42
|
+
try {
|
|
43
|
+
const type = registry.findType(typeId);
|
|
44
|
+
// Check if it's an empty struct
|
|
45
|
+
if (type.typeDef.type === 'Struct' && type.typeDef.value.fields.length === 0) {
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
// Check if it's an empty tuple
|
|
49
|
+
if (type.typeDef.type === 'Tuple' && type.typeDef.value.fields.length === 0) {
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
// Ignore errors
|
|
55
|
+
}
|
|
56
|
+
// All other cases (including errors) require input
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Known signed extensions that require external input.
|
|
3
|
+
*
|
|
4
|
+
* Note: Extensions that don't require external input are automatically handled by FallbackSignedExtension:
|
|
5
|
+
* - CheckNonZeroSender
|
|
6
|
+
* - CheckWeight
|
|
7
|
+
* - PrevalidateAttests
|
|
8
|
+
* - StorageWeightReclaim
|
|
9
|
+
*
|
|
10
|
+
* These extensions have empty struct or tuple types and don't need explicit implementation.
|
|
11
|
+
*/
|
|
1
12
|
import { ISignedExtension } from '../SignedExtension.js';
|
|
2
13
|
export type AnySignedExtension = new (...args: any[]) => ISignedExtension;
|
|
3
14
|
export declare const knownSignedExtensions: Record<string, AnySignedExtension>;
|
|
@@ -1,26 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Known signed extensions that require external input.
|
|
3
|
+
*
|
|
4
|
+
* Note: Extensions that don't require external input are automatically handled by FallbackSignedExtension:
|
|
5
|
+
* - CheckNonZeroSender
|
|
6
|
+
* - CheckWeight
|
|
7
|
+
* - PrevalidateAttests
|
|
8
|
+
* - StorageWeightReclaim
|
|
9
|
+
*
|
|
10
|
+
* These extensions have empty struct or tuple types and don't need explicit implementation.
|
|
11
|
+
*/
|
|
1
12
|
import { ChargeAssetTxPayment } from './ChargeAssetTxPayment.js';
|
|
2
13
|
import { ChargeTransactionPayment } from './ChargeTransactionPayment.js';
|
|
3
14
|
import { CheckGenesis } from './CheckGenesis.js';
|
|
4
15
|
import { CheckMetadataHash } from './CheckMetadataHash.js';
|
|
5
16
|
import { CheckMortality } from './CheckMortality.js';
|
|
6
|
-
import { CheckNonZeroSender } from './CheckNonZeroSender.js';
|
|
7
17
|
import { CheckNonce } from './CheckNonce.js';
|
|
8
18
|
import { CheckSpecVersion } from './CheckSpecVersion.js';
|
|
9
19
|
import { CheckTxVersion } from './CheckTxVersion.js';
|
|
10
|
-
import { CheckWeight } from './CheckWeight.js';
|
|
11
|
-
import { PrevalidateAttests } from './PrevalidateAttests.js';
|
|
12
|
-
import { StorageWeightReclaim } from './StorageWeightReclaim.js';
|
|
13
20
|
export const knownSignedExtensions = {
|
|
14
|
-
CheckNonZeroSender,
|
|
15
21
|
CheckSpecVersion,
|
|
16
22
|
CheckTxVersion,
|
|
17
23
|
CheckGenesis,
|
|
18
24
|
CheckMortality,
|
|
19
25
|
CheckNonce,
|
|
20
|
-
CheckWeight,
|
|
21
26
|
ChargeTransactionPayment,
|
|
22
|
-
PrevalidateAttests,
|
|
23
27
|
ChargeAssetTxPayment,
|
|
24
28
|
CheckMetadataHash,
|
|
25
|
-
StorageWeightReclaim,
|
|
26
29
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dedot/api",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "A delightful JavaScript/TypeScript client for Polkadot & Substrate",
|
|
5
5
|
"author": "Thang X. Vu <thang@coongcrafts.io>",
|
|
6
6
|
"homepage": "https://github.com/dedotdev/dedot/tree/main/packages/api",
|
|
@@ -13,18 +13,18 @@
|
|
|
13
13
|
"type": "module",
|
|
14
14
|
"sideEffects": false,
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@dedot/codecs": "0.
|
|
17
|
-
"@dedot/providers": "0.
|
|
18
|
-
"@dedot/runtime-specs": "0.
|
|
19
|
-
"@dedot/shape": "0.
|
|
20
|
-
"@dedot/storage": "0.
|
|
21
|
-
"@dedot/types": "0.
|
|
22
|
-
"@dedot/utils": "0.
|
|
16
|
+
"@dedot/codecs": "0.9.0",
|
|
17
|
+
"@dedot/providers": "0.9.0",
|
|
18
|
+
"@dedot/runtime-specs": "0.9.0",
|
|
19
|
+
"@dedot/shape": "0.9.0",
|
|
20
|
+
"@dedot/storage": "0.9.0",
|
|
21
|
+
"@dedot/types": "0.9.0",
|
|
22
|
+
"@dedot/utils": "0.9.0"
|
|
23
23
|
},
|
|
24
24
|
"scripts": {
|
|
25
25
|
"build": "tsc --project tsconfig.build.json && tsc --project tsconfig.build.cjs.json",
|
|
26
26
|
"clean": "rm -rf ./dist && rm -rf ./tsconfig.tsbuildinfo ./tsconfig.build.tsbuildinfo",
|
|
27
|
-
"test": "vitest --watch=false"
|
|
27
|
+
"test": "npx vitest --watch=false"
|
|
28
28
|
},
|
|
29
29
|
"exports": {
|
|
30
30
|
".": {
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"node": ">=18"
|
|
49
49
|
},
|
|
50
50
|
"license": "Apache-2.0",
|
|
51
|
-
"gitHead": "
|
|
51
|
+
"gitHead": "cebae55a3525e2c9bcdd70322027855a594a287d",
|
|
52
52
|
"module": "./index.js",
|
|
53
53
|
"types": "./index.d.ts"
|
|
54
54
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { BlockHash, StorageData, StorageKey } from '@dedot/codecs';
|
|
2
|
+
import type { Callback, RpcVersion, Unsub, VersionedGenericSubstrateApi } from '@dedot/types';
|
|
3
|
+
import type { SubstrateApi } from '../chaintypes/index.js';
|
|
4
|
+
import { BaseSubstrateClient } from '../client/BaseSubstrateClient.js';
|
|
5
|
+
/**
|
|
6
|
+
* @name BaseStorageQuery
|
|
7
|
+
* @description
|
|
8
|
+
* An abstract service that provides functionality for querying and subscribing to
|
|
9
|
+
* multiple storage items. This service is designed to be extended by version-specific
|
|
10
|
+
* implementations that handle the details of interacting with different JSON-RPC APIs.
|
|
11
|
+
*
|
|
12
|
+
* The service provides a simple interface for:
|
|
13
|
+
* - Querying multiple storage keys in a single call
|
|
14
|
+
* - Subscribing to changes in multiple storage keys
|
|
15
|
+
*
|
|
16
|
+
* This abstraction eliminates code duplication between different client implementations
|
|
17
|
+
* and provides a consistent interface for storage operations.
|
|
18
|
+
*/
|
|
19
|
+
export declare abstract class BaseStorageQuery<Rv extends RpcVersion, ChainApi extends VersionedGenericSubstrateApi = SubstrateApi, T extends BaseSubstrateClient<Rv, ChainApi> = BaseSubstrateClient<Rv, ChainApi>> {
|
|
20
|
+
protected client: T;
|
|
21
|
+
/**
|
|
22
|
+
* @param client - The substrate client instance
|
|
23
|
+
*/
|
|
24
|
+
constructor(client: T);
|
|
25
|
+
/**
|
|
26
|
+
* Query multiple storage items in a single call
|
|
27
|
+
*
|
|
28
|
+
* @param keys - Array of storage keys to query
|
|
29
|
+
* @param at - Optional block hash to query at
|
|
30
|
+
* @returns Promise resolving to a record mapping storage keys to their values
|
|
31
|
+
*/
|
|
32
|
+
abstract query(keys: StorageKey[], at?: BlockHash): Promise<Record<StorageKey, StorageData | undefined>>;
|
|
33
|
+
/**
|
|
34
|
+
* Subscribe to multiple storage items
|
|
35
|
+
*
|
|
36
|
+
* @param keys - Array of storage keys to subscribe to
|
|
37
|
+
* @param callback - Function to call when storage values change
|
|
38
|
+
* @returns Promise resolving to an unsubscribe function
|
|
39
|
+
*/
|
|
40
|
+
abstract subscribe(keys: StorageKey[], callback: Callback<Record<StorageKey, StorageData | undefined>>): Promise<Unsub>;
|
|
41
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @name BaseStorageQuery
|
|
3
|
+
* @description
|
|
4
|
+
* An abstract service that provides functionality for querying and subscribing to
|
|
5
|
+
* multiple storage items. This service is designed to be extended by version-specific
|
|
6
|
+
* implementations that handle the details of interacting with different JSON-RPC APIs.
|
|
7
|
+
*
|
|
8
|
+
* The service provides a simple interface for:
|
|
9
|
+
* - Querying multiple storage keys in a single call
|
|
10
|
+
* - Subscribing to changes in multiple storage keys
|
|
11
|
+
*
|
|
12
|
+
* This abstraction eliminates code duplication between different client implementations
|
|
13
|
+
* and provides a consistent interface for storage operations.
|
|
14
|
+
*/
|
|
15
|
+
export class BaseStorageQuery {
|
|
16
|
+
client;
|
|
17
|
+
/**
|
|
18
|
+
* @param client - The substrate client instance
|
|
19
|
+
*/
|
|
20
|
+
constructor(client) {
|
|
21
|
+
this.client = client;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { BlockHash, StorageData, StorageKey } from '@dedot/codecs';
|
|
2
|
+
import type { Callback, RpcLegacy, Unsub, VersionedGenericSubstrateApi } from '@dedot/types';
|
|
3
|
+
import type { SubstrateApi } from '../chaintypes/index.js';
|
|
4
|
+
import { LegacyClient } from '../client/LegacyClient.js';
|
|
5
|
+
import { BaseStorageQuery } from './BaseStorageQuery.js';
|
|
6
|
+
/**
|
|
7
|
+
* @name LegacyStorageQuery
|
|
8
|
+
* @description
|
|
9
|
+
* Implementation of BaseStorageQuery for the legacy JSON-RPC API (v1).
|
|
10
|
+
* This service handles storage queries using the state_queryStorageAt and
|
|
11
|
+
* state_subscribeStorage RPC methods.
|
|
12
|
+
*
|
|
13
|
+
* It provides:
|
|
14
|
+
* - One-time queries using state_queryStorageAt
|
|
15
|
+
* - Subscriptions using state_subscribeStorage
|
|
16
|
+
* - Efficient change tracking for subscriptions
|
|
17
|
+
*/
|
|
18
|
+
export declare class LegacyStorageQuery<ChainApi extends VersionedGenericSubstrateApi = SubstrateApi> extends BaseStorageQuery<RpcLegacy, ChainApi, LegacyClient<ChainApi>> {
|
|
19
|
+
/**
|
|
20
|
+
* Query multiple storage items in a single call using state_queryStorageAt
|
|
21
|
+
*
|
|
22
|
+
* @param keys - Array of storage keys to query
|
|
23
|
+
* @param at - Optional block hash to query at (defaults to current/best block)
|
|
24
|
+
* @returns Promise resolving to a record mapping storage keys to their values
|
|
25
|
+
*/
|
|
26
|
+
query(keys: StorageKey[], at?: BlockHash): Promise<Record<StorageKey, StorageData | undefined>>;
|
|
27
|
+
/**
|
|
28
|
+
* Subscribe to multiple storage items using state_subscribeStorage
|
|
29
|
+
*
|
|
30
|
+
* @param keys - Array of storage keys to subscribe to
|
|
31
|
+
* @param callback - Function to call when storage values change
|
|
32
|
+
* @returns Promise resolving to an unsubscribe function
|
|
33
|
+
*/
|
|
34
|
+
subscribe(keys: StorageKey[], callback: Callback<Record<StorageKey, StorageData | undefined>>): Promise<Unsub>;
|
|
35
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { BaseStorageQuery } from './BaseStorageQuery.js';
|
|
2
|
+
/**
|
|
3
|
+
* @name LegacyStorageQuery
|
|
4
|
+
* @description
|
|
5
|
+
* Implementation of BaseStorageQuery for the legacy JSON-RPC API (v1).
|
|
6
|
+
* This service handles storage queries using the state_queryStorageAt and
|
|
7
|
+
* state_subscribeStorage RPC methods.
|
|
8
|
+
*
|
|
9
|
+
* It provides:
|
|
10
|
+
* - One-time queries using state_queryStorageAt
|
|
11
|
+
* - Subscriptions using state_subscribeStorage
|
|
12
|
+
* - Efficient change tracking for subscriptions
|
|
13
|
+
*/
|
|
14
|
+
export class LegacyStorageQuery extends BaseStorageQuery {
|
|
15
|
+
/**
|
|
16
|
+
* Query multiple storage items in a single call using state_queryStorageAt
|
|
17
|
+
*
|
|
18
|
+
* @param keys - Array of storage keys to query
|
|
19
|
+
* @param at - Optional block hash to query at (defaults to current/best block)
|
|
20
|
+
* @returns Promise resolving to a record mapping storage keys to their values
|
|
21
|
+
*/
|
|
22
|
+
async query(keys, at) {
|
|
23
|
+
const client = this.client;
|
|
24
|
+
// Query storage at the specified block or current block
|
|
25
|
+
const changeSets = at
|
|
26
|
+
? await client.rpc.state_queryStorageAt(keys, at)
|
|
27
|
+
: await client.rpc.state_queryStorageAt(keys);
|
|
28
|
+
// Create a map of key -> value for easy lookup
|
|
29
|
+
const results = {};
|
|
30
|
+
// Initialize all keys with undefined
|
|
31
|
+
keys.forEach((key) => (results[key] = undefined));
|
|
32
|
+
// Update with actual values from the response
|
|
33
|
+
if (changeSets && changeSets.length > 0) {
|
|
34
|
+
changeSets[0].changes.forEach(([key, value]) => {
|
|
35
|
+
results[key] = value ?? undefined;
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return results;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Subscribe to multiple storage items using state_subscribeStorage
|
|
42
|
+
*
|
|
43
|
+
* @param keys - Array of storage keys to subscribe to
|
|
44
|
+
* @param callback - Function to call when storage values change
|
|
45
|
+
* @returns Promise resolving to an unsubscribe function
|
|
46
|
+
*/
|
|
47
|
+
async subscribe(keys, callback) {
|
|
48
|
+
// Track the latest changes for each key
|
|
49
|
+
const lastChanges = {};
|
|
50
|
+
// Initialize all keys with undefined
|
|
51
|
+
keys.forEach((key) => (lastChanges[key] = undefined));
|
|
52
|
+
// Subscribe to storage changes
|
|
53
|
+
const client = this.client;
|
|
54
|
+
return client.rpc.state_subscribeStorage(keys, (changeSet) => {
|
|
55
|
+
// Update the latest changes
|
|
56
|
+
changeSet.changes.forEach(([key, value]) => {
|
|
57
|
+
if (lastChanges[key] !== value) {
|
|
58
|
+
lastChanges[key] = value ?? undefined;
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
// Call the callback with the updated map
|
|
62
|
+
callback({ ...lastChanges });
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { BlockHash, StorageData, StorageKey } from '@dedot/codecs';
|
|
2
|
+
import type { Callback, RpcV2, Unsub, VersionedGenericSubstrateApi } from '@dedot/types';
|
|
3
|
+
import type { SubstrateApi } from '../chaintypes/index.js';
|
|
4
|
+
import { DedotClient } from '../client/DedotClient.js';
|
|
5
|
+
import { BaseStorageQuery } from './BaseStorageQuery.js';
|
|
6
|
+
/**
|
|
7
|
+
* @name NewStorageQuery
|
|
8
|
+
* @description
|
|
9
|
+
* Implementation of BaseStorageQuery for the new JSON-RPC API (v2).
|
|
10
|
+
* This service handles storage queries using the chainHead_storage RPC method
|
|
11
|
+
* and chainHead events for subscriptions.
|
|
12
|
+
*
|
|
13
|
+
* It provides:
|
|
14
|
+
* - One-time queries using chainHead_storage
|
|
15
|
+
* - Subscriptions using chainHead 'bestBlock' events
|
|
16
|
+
* - Efficient change detection for subscriptions
|
|
17
|
+
*/
|
|
18
|
+
export declare class NewStorageQuery<ChainApi extends VersionedGenericSubstrateApi = SubstrateApi> extends BaseStorageQuery<RpcV2, ChainApi, DedotClient<ChainApi>> {
|
|
19
|
+
/**
|
|
20
|
+
* Query multiple storage items in a single call using chainHead_storage
|
|
21
|
+
*
|
|
22
|
+
* @param keys - Array of storage keys to query
|
|
23
|
+
* @param at - Optional block hash to query at (defaults to best block)
|
|
24
|
+
* @returns Promise resolving to a record mapping storage keys to their values
|
|
25
|
+
*/
|
|
26
|
+
query(keys: StorageKey[], at?: BlockHash): Promise<Record<StorageKey, StorageData | undefined>>;
|
|
27
|
+
/**
|
|
28
|
+
* Subscribe to multiple storage items using chainHead 'bestBlock' events
|
|
29
|
+
*
|
|
30
|
+
* @param keys - Array of storage keys to subscribe to
|
|
31
|
+
* @param callback - Function to call when storage values change
|
|
32
|
+
* @returns Promise resolving to an unsubscribe function
|
|
33
|
+
*/
|
|
34
|
+
subscribe(keys: StorageKey[], callback: Callback<Record<StorageKey, StorageData | undefined>>): Promise<Unsub>;
|
|
35
|
+
}
|