@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.
- package/chaintypes/substrate/consts.d.ts +2 -2
- package/chaintypes/substrate/consts.js +1 -0
- package/chaintypes/substrate/errors.d.ts +909 -909
- package/chaintypes/substrate/errors.js +1 -0
- package/chaintypes/substrate/events.d.ts +664 -664
- package/chaintypes/substrate/events.js +1 -0
- package/chaintypes/substrate/index.d.ts +13 -16
- package/chaintypes/substrate/index.js +1 -0
- package/chaintypes/substrate/json-rpc.d.ts +2 -2
- package/chaintypes/substrate/json-rpc.js +1 -0
- package/chaintypes/substrate/query.d.ts +509 -527
- package/chaintypes/substrate/query.js +1 -0
- package/chaintypes/substrate/runtime.d.ts +123 -123
- package/chaintypes/substrate/runtime.js +1 -0
- package/chaintypes/substrate/tx.d.ts +1311 -1311
- package/chaintypes/substrate/tx.js +1 -0
- package/chaintypes/substrate/types.js +1 -0
- package/chaintypes/substrate/view-functions.d.ts +2 -2
- package/chaintypes/substrate/view-functions.js +1 -0
- package/cjs/chaintypes/substrate/consts.js +1 -0
- package/cjs/chaintypes/substrate/errors.js +1 -0
- package/cjs/chaintypes/substrate/events.js +1 -0
- package/cjs/chaintypes/substrate/index.js +1 -0
- package/cjs/chaintypes/substrate/json-rpc.js +1 -0
- package/cjs/chaintypes/substrate/query.js +1 -0
- package/cjs/chaintypes/substrate/runtime.js +1 -0
- package/cjs/chaintypes/substrate/tx.js +1 -0
- package/cjs/chaintypes/substrate/types.js +1 -0
- package/cjs/chaintypes/substrate/view-functions.js +1 -0
- package/cjs/client/BaseSubstrateClient.js +45 -2
- package/cjs/client/DedotClient.js +356 -224
- package/cjs/client/LegacyClient.js +99 -23
- package/cjs/client/V2Client.js +316 -0
- package/cjs/client/explorer/LegacyBlockExplorer.js +263 -0
- package/cjs/client/explorer/V2BlockExplorer.js +74 -0
- package/cjs/client/explorer/index.js +18 -0
- package/cjs/client/utils.js +57 -0
- package/cjs/executor/EventExecutor.js +1 -0
- package/cjs/executor/RuntimeApiExecutor.js +49 -2
- package/cjs/executor/StorageQueryExecutor.js +114 -2
- package/cjs/executor/ViewFunctionExecutor.js +21 -2
- package/cjs/executor/v2/StorageQueryExecutorV2.js +7 -1
- package/cjs/executor/validation-helpers.js +181 -0
- package/cjs/extrinsic/submittable/BaseSubmittableExtrinsic.js +86 -2
- package/cjs/extrinsic/submittable/SubmittableExtrinsic.js +38 -16
- package/cjs/extrinsic/submittable/SubmittableExtrinsicV2.js +12 -2
- package/cjs/json-rpc/group/ChainHead/ChainHead.js +226 -21
- package/cjs/storage/QueryableStorage.js +1 -0
- package/client/BaseSubstrateClient.d.ts +34 -18
- package/client/BaseSubstrateClient.js +47 -4
- package/client/DedotClient.d.ts +346 -49
- package/client/DedotClient.js +356 -224
- package/client/LegacyClient.d.ts +22 -17
- package/client/LegacyClient.js +101 -25
- package/client/V2Client.d.ts +75 -0
- package/client/V2Client.js +312 -0
- package/client/explorer/LegacyBlockExplorer.d.ts +68 -0
- package/client/explorer/LegacyBlockExplorer.js +259 -0
- package/client/explorer/V2BlockExplorer.d.ts +40 -0
- package/client/explorer/V2BlockExplorer.js +70 -0
- package/client/explorer/index.d.ts +2 -0
- package/client/explorer/index.js +2 -0
- package/client/utils.d.ts +18 -0
- package/client/utils.js +52 -0
- package/executor/ConstantExecutor.d.ts +1 -2
- package/executor/ErrorExecutor.d.ts +2 -2
- package/executor/EventExecutor.d.ts +2 -2
- package/executor/EventExecutor.js +1 -0
- package/executor/Executor.d.ts +4 -5
- package/executor/RuntimeApiExecutor.d.ts +2 -2
- package/executor/RuntimeApiExecutor.js +27 -3
- package/executor/StorageQueryExecutor.d.ts +3 -2
- package/executor/StorageQueryExecutor.js +92 -3
- package/executor/TxExecutor.d.ts +2 -2
- package/executor/ViewFunctionExecutor.d.ts +2 -2
- package/executor/ViewFunctionExecutor.js +22 -3
- package/executor/v2/RuntimeApiExecutorV2.d.ts +2 -3
- package/executor/v2/StorageQueryExecutorV2.d.ts +3 -3
- package/executor/v2/StorageQueryExecutorV2.js +8 -2
- package/executor/v2/TxExecutorV2.d.ts +5 -5
- package/executor/v2/ViewFunctionExecutorV2.d.ts +2 -3
- package/executor/validation-helpers.d.ts +36 -0
- package/executor/validation-helpers.js +174 -0
- package/extrinsic/extensions/SignedExtension.d.ts +1 -1
- package/extrinsic/submittable/BaseSubmittableExtrinsic.d.ts +7 -3
- package/extrinsic/submittable/BaseSubmittableExtrinsic.js +64 -3
- package/extrinsic/submittable/SubmittableExtrinsic.d.ts +4 -1
- package/extrinsic/submittable/SubmittableExtrinsic.js +39 -17
- package/extrinsic/submittable/SubmittableExtrinsicV2.d.ts +6 -3
- package/extrinsic/submittable/SubmittableExtrinsicV2.js +13 -3
- package/json-rpc/JsonRpcClient.d.ts +6 -6
- package/json-rpc/group/Archive.d.ts +1 -1
- package/json-rpc/group/ChainHead/ChainHead.d.ts +18 -2
- package/json-rpc/group/ChainHead/ChainHead.js +226 -21
- package/json-rpc/group/ChainSpec.d.ts +3 -3
- package/json-rpc/group/Transaction.d.ts +1 -1
- package/json-rpc/group/TransactionWatch.d.ts +1 -1
- package/package.json +9 -9
- package/proxychain.d.ts +3 -4
- package/storage/NewStorageQuery.d.ts +3 -3
- package/storage/QueryableStorage.js +1 -0
- package/types.d.ts +94 -6
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { ApiCompatibilityError, isNumber } from '@dedot/utils';
|
|
2
|
+
/**
|
|
3
|
+
* Check if a codec is an Option type
|
|
4
|
+
*/
|
|
5
|
+
export function isOptionCodec(codec) {
|
|
6
|
+
try {
|
|
7
|
+
const metadata = codec?.metadata?.[0];
|
|
8
|
+
return metadata?.name === '$.option';
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Check if a parameter is optional (wrapped in Option)
|
|
16
|
+
*/
|
|
17
|
+
export function isOptionalParam(param, registry) {
|
|
18
|
+
// Check direct codec first
|
|
19
|
+
if (param.codec) {
|
|
20
|
+
return isOptionCodec(param.codec);
|
|
21
|
+
}
|
|
22
|
+
// Check via typeId using registry
|
|
23
|
+
if (isNumber(param.typeId)) {
|
|
24
|
+
try {
|
|
25
|
+
const type = registry.findType(param.typeId);
|
|
26
|
+
return type.typeDef.type === 'Enum' && type.path.join('::') === 'Option';
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
// ignore
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Pad args array with undefined for missing trailing optional parameters.
|
|
36
|
+
* This allows users to omit optional parameters at the end of the parameter list.
|
|
37
|
+
*/
|
|
38
|
+
export function padArgsForOptionalParams(args, params, registry) {
|
|
39
|
+
// If args already match params length, no padding needed
|
|
40
|
+
if (args.length === params.length) {
|
|
41
|
+
return args;
|
|
42
|
+
}
|
|
43
|
+
// If more args than params, validation will fail later
|
|
44
|
+
if (args.length > params.length) {
|
|
45
|
+
return args;
|
|
46
|
+
}
|
|
47
|
+
// Check that all missing parameters are optional
|
|
48
|
+
for (let i = args.length; i < params.length; i++) {
|
|
49
|
+
const param = params[i];
|
|
50
|
+
if (!isOptionalParam(param, registry)) {
|
|
51
|
+
// Required parameter is missing, let the validation fail naturally
|
|
52
|
+
return args;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// All missing parameters are optional, pad with undefined
|
|
56
|
+
return [...args, ...Array(params.length - args.length).fill(undefined)];
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Format a value for display in error messages
|
|
60
|
+
* Stringifies and truncates to 20 characters max
|
|
61
|
+
*/
|
|
62
|
+
function formatValue(value) {
|
|
63
|
+
try {
|
|
64
|
+
let str;
|
|
65
|
+
if (typeof value === 'string') {
|
|
66
|
+
str = JSON.stringify(value);
|
|
67
|
+
}
|
|
68
|
+
else if (typeof value === 'undefined') {
|
|
69
|
+
str = 'undefined';
|
|
70
|
+
}
|
|
71
|
+
else if (value === null) {
|
|
72
|
+
str = 'null';
|
|
73
|
+
}
|
|
74
|
+
else if (typeof value === 'bigint') {
|
|
75
|
+
str = `${value}n`;
|
|
76
|
+
}
|
|
77
|
+
else if (typeof value === 'object') {
|
|
78
|
+
// For objects/arrays, use JSON.stringify
|
|
79
|
+
str = JSON.stringify(value);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
str = String(value);
|
|
83
|
+
}
|
|
84
|
+
// Truncate to 20 characters
|
|
85
|
+
if (str.length > 20) {
|
|
86
|
+
return str.slice(0, 20) + '...';
|
|
87
|
+
}
|
|
88
|
+
return str;
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return '[complex value]';
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Build a comprehensive API compatibility error with detailed information
|
|
96
|
+
*/
|
|
97
|
+
export function buildCompatibilityError(originalError, params, args, context) {
|
|
98
|
+
const lines = [];
|
|
99
|
+
// Header
|
|
100
|
+
if (context.itemIndex !== undefined) {
|
|
101
|
+
lines.push(`API Compatibility Error: ${context.apiName} (item ${context.itemIndex})`);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
lines.push(`API Compatibility Error: ${context.apiName}`);
|
|
105
|
+
}
|
|
106
|
+
lines.push('');
|
|
107
|
+
// Check parameter count mismatch
|
|
108
|
+
if (args.length !== params.length) {
|
|
109
|
+
lines.push(`Expected ${params.length} parameter${params.length !== 1 ? 's' : ''} but received ${args.length}`);
|
|
110
|
+
lines.push('');
|
|
111
|
+
}
|
|
112
|
+
// Validate each parameter and report errors
|
|
113
|
+
const paramErrors = [];
|
|
114
|
+
const maxParams = Math.max(args.length, params.length);
|
|
115
|
+
for (let i = 0; i < maxParams; i++) {
|
|
116
|
+
const param = params[i];
|
|
117
|
+
const value = args[i];
|
|
118
|
+
if (!param) {
|
|
119
|
+
// Extra argument provided
|
|
120
|
+
paramErrors.push(` [${i}] (unexpected) - value: ${formatValue(value)}`);
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
if (value === undefined && i >= args.length) {
|
|
124
|
+
// Missing argument - check if it's actually optional
|
|
125
|
+
const isOptional = isOptionalParam(param, context.registry);
|
|
126
|
+
if (isOptional) {
|
|
127
|
+
paramErrors.push(` [${i}] ${param.name}: omitted (optional)`);
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
paramErrors.push(` [${i}] ${param.name}: ✗ required parameter missing - value: undefined`);
|
|
131
|
+
}
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
// Try to validate the parameter
|
|
135
|
+
try {
|
|
136
|
+
const $codec = findCodec(param, context.registry);
|
|
137
|
+
if ($codec) {
|
|
138
|
+
$codec.assert?.(value);
|
|
139
|
+
// Valid parameter
|
|
140
|
+
paramErrors.push(` [${i}] ${param.name}: ✓ valid`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
// Invalid parameter
|
|
145
|
+
paramErrors.push(` [${i}] ${param.name}: ✗ invalid input type - value: ${formatValue(value)}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
if (paramErrors.length > 0) {
|
|
149
|
+
lines.push('Parameters:');
|
|
150
|
+
lines.push(...paramErrors);
|
|
151
|
+
lines.push('');
|
|
152
|
+
}
|
|
153
|
+
// Add suggestion
|
|
154
|
+
lines.push('This may indicate your chaintypes definitions are outdated.');
|
|
155
|
+
lines.push('Consider regenerating chaintypes with:');
|
|
156
|
+
lines.push(' npx dedot chaintypes -w <your-chain-endpoint>');
|
|
157
|
+
return new ApiCompatibilityError(lines.join('\n'));
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Find codec for a parameter (internal helper)
|
|
161
|
+
*/
|
|
162
|
+
function findCodec(param, registry) {
|
|
163
|
+
if (param.codec)
|
|
164
|
+
return param.codec;
|
|
165
|
+
if (isNumber(param.typeId)) {
|
|
166
|
+
try {
|
|
167
|
+
return registry.findCodec(param.typeId);
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
// ignore
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return undefined;
|
|
174
|
+
}
|
|
@@ -35,7 +35,7 @@ export declare abstract class SignedExtension<Data extends any = {}, AdditionalS
|
|
|
35
35
|
typeId: number;
|
|
36
36
|
additionalSigned: number;
|
|
37
37
|
};
|
|
38
|
-
get payloadOptions(): Partial<PayloadOptions
|
|
38
|
+
get payloadOptions(): Partial<PayloadOptions<any>>;
|
|
39
39
|
toPayload(...args: any[]): Partial<SignerPayloadJSON>;
|
|
40
40
|
}
|
|
41
41
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BlockHash, Extrinsic } from '@dedot/codecs';
|
|
1
|
+
import { BlockHash, Extrinsic, Preamble } from '@dedot/codecs';
|
|
2
2
|
import { AddressOrPair, Callback, IRuntimeTxCall, ISubmittableExtrinsic, ISubmittableResult, PayloadOptions, SignerOptions, TxHash, TxPaymentInfo, TxUnsub } from '@dedot/types';
|
|
3
3
|
import { HexString } from '@dedot/utils';
|
|
4
4
|
import type { FrameSystemEventRecord } from '../../chaintypes/index.js';
|
|
@@ -9,8 +9,8 @@ interface TxHooks {
|
|
|
9
9
|
}
|
|
10
10
|
export declare abstract class BaseSubmittableExtrinsic extends Extrinsic implements ISubmittableExtrinsic {
|
|
11
11
|
#private;
|
|
12
|
-
readonly client: ISubstrateClient<any>;
|
|
13
|
-
constructor(client: ISubstrateClient<any>, call: IRuntimeTxCall);
|
|
12
|
+
readonly client: ISubstrateClient<any, any>;
|
|
13
|
+
constructor(client: ISubstrateClient<any, any>, call: IRuntimeTxCall, preamble?: Preamble);
|
|
14
14
|
withHooks(hooks: TxHooks): void;
|
|
15
15
|
protected transformTxResult<R extends ISubmittableResult = ISubmittableResult>(result: ISubmittableResult): R;
|
|
16
16
|
paymentInfo(account: AddressOrPair, options?: Partial<PayloadOptions>): Promise<TxPaymentInfo>;
|
|
@@ -21,6 +21,10 @@ export declare abstract class BaseSubmittableExtrinsic extends Extrinsic impleme
|
|
|
21
21
|
send(): TxHash;
|
|
22
22
|
send(callback: Callback): TxUnsub;
|
|
23
23
|
protected getSystemEventsAt(hash: BlockHash): Promise<FrameSystemEventRecord[]>;
|
|
24
|
+
/**
|
|
25
|
+
* Override callU8a to add transaction parameter validation before encoding
|
|
26
|
+
*/
|
|
27
|
+
get callU8a(): Uint8Array;
|
|
24
28
|
toU8a(): Uint8Array;
|
|
25
29
|
toHex(): HexString;
|
|
26
30
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Extrinsic } from '@dedot/codecs';
|
|
2
|
-
import
|
|
2
|
+
import * as $ from '@dedot/shape';
|
|
3
|
+
import { DedotError, hexToU8a, isFunction, stringCamelCase, toHex, u8aToHex } from '@dedot/utils';
|
|
4
|
+
import { buildCompatibilityError } from '../../executor/validation-helpers.js';
|
|
3
5
|
import { ExtraSignedExtension } from '../extensions/index.js';
|
|
4
6
|
import { fakeSigner } from './fakeSigner.js';
|
|
5
7
|
import { isKeyringPair, signRawMessage, txDefer } from './utils.js';
|
|
@@ -7,8 +9,8 @@ export class BaseSubmittableExtrinsic extends Extrinsic {
|
|
|
7
9
|
client;
|
|
8
10
|
#alterTx;
|
|
9
11
|
#hooks;
|
|
10
|
-
constructor(client, call) {
|
|
11
|
-
super(client.registry, call);
|
|
12
|
+
constructor(client, call, preamble) {
|
|
13
|
+
super(client.registry, call, preamble);
|
|
12
14
|
this.client = client;
|
|
13
15
|
}
|
|
14
16
|
withHooks(hooks) {
|
|
@@ -115,10 +117,69 @@ export class BaseSubmittableExtrinsic extends Extrinsic {
|
|
|
115
117
|
const atApi = (await this.client.at(hash));
|
|
116
118
|
return await atApi.query.system.events();
|
|
117
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* Override callU8a to add transaction parameter validation before encoding
|
|
122
|
+
*/
|
|
123
|
+
get callU8a() {
|
|
124
|
+
// Validate transaction parameters first
|
|
125
|
+
this.#validateTxParams();
|
|
126
|
+
// Then call parent implementation which does $RuntimeCall.assert and encoding
|
|
127
|
+
return super.callU8a;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Validate transaction parameters against their type definitions
|
|
131
|
+
* @private
|
|
132
|
+
*/
|
|
133
|
+
#validateTxParams() {
|
|
134
|
+
// Skip if palletCall is a string (flat enum, no params)
|
|
135
|
+
if (typeof this.call.palletCall === 'string')
|
|
136
|
+
return;
|
|
137
|
+
if (!this.call.palletCall?.name)
|
|
138
|
+
return;
|
|
139
|
+
// 1. Find pallet metadata
|
|
140
|
+
const palletName = this.call.pallet;
|
|
141
|
+
const pallet = this.registry.metadata.pallets.find((p) => stringCamelCase(p.name) === stringCamelCase(palletName));
|
|
142
|
+
if (!pallet?.calls)
|
|
143
|
+
return;
|
|
144
|
+
// 2. Get calls enum type definition
|
|
145
|
+
const callsType = this.registry.metadata.types[pallet.calls.typeId];
|
|
146
|
+
if (callsType.typeDef.type !== 'Enum')
|
|
147
|
+
return;
|
|
148
|
+
// 3. Find specific call definition
|
|
149
|
+
const callName = this.call.palletCall.name;
|
|
150
|
+
const callDef = callsType.typeDef.value.members.find((m) => stringCamelCase(m.name) === stringCamelCase(callName));
|
|
151
|
+
if (!callDef)
|
|
152
|
+
return;
|
|
153
|
+
// 4. Build param specs from field definitions
|
|
154
|
+
const paramSpecs = callDef.fields.map((f) => ({
|
|
155
|
+
name: stringCamelCase(f.name || ''),
|
|
156
|
+
typeId: f.typeId,
|
|
157
|
+
}));
|
|
158
|
+
// 5. Extract args in field order from params object
|
|
159
|
+
const params = this.call.palletCall.params || {};
|
|
160
|
+
const args = paramSpecs.map((spec) => params[spec.name]);
|
|
161
|
+
// 6. Validate with tuple codec
|
|
162
|
+
const $ParamsTuple = $.Tuple(...paramSpecs.map((spec) => this.registry.findCodec(spec.typeId)));
|
|
163
|
+
try {
|
|
164
|
+
$ParamsTuple.assert?.(args);
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
if (error instanceof $.ShapeAssertError) {
|
|
168
|
+
throw buildCompatibilityError(error, // --
|
|
169
|
+
paramSpecs, args, {
|
|
170
|
+
apiName: `${stringCamelCase(pallet.name)}.${stringCamelCase(callDef.name)}`,
|
|
171
|
+
registry: this.registry,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
throw error;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
118
177
|
toU8a() {
|
|
119
178
|
if (this.#alterTx) {
|
|
120
179
|
return hexToU8a(this.#alterTx);
|
|
121
180
|
}
|
|
181
|
+
// Validate transaction parameters before encoding
|
|
182
|
+
this.#validateTxParams();
|
|
122
183
|
return super.toU8a();
|
|
123
184
|
}
|
|
124
185
|
toHex() {
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import { BlockHash } from '@dedot/codecs';
|
|
1
|
+
import { BlockHash, Extrinsic } from '@dedot/codecs';
|
|
2
2
|
import { AddressOrPair, Callback, DryRunResult, ISubmittableExtrinsicLegacy, ISubmittableResult, SignerOptions, TxHash, TxUnsub } from '@dedot/types';
|
|
3
|
+
import { HexString } from '@dedot/utils';
|
|
4
|
+
import { LegacyClient } from '../../client/LegacyClient.js';
|
|
3
5
|
import { BaseSubmittableExtrinsic } from './BaseSubmittableExtrinsic.js';
|
|
4
6
|
/**
|
|
5
7
|
* @name SubmittableExtrinsic
|
|
6
8
|
* @description A wrapper around an Extrinsic that exposes methods to sign, send, and other utility around Extrinsic.
|
|
7
9
|
*/
|
|
8
10
|
export declare class SubmittableExtrinsic extends BaseSubmittableExtrinsic implements ISubmittableExtrinsicLegacy {
|
|
11
|
+
static fromTx(client: LegacyClient<any>, tx: HexString | Extrinsic): SubmittableExtrinsic;
|
|
9
12
|
dryRun(account: AddressOrPair, optionsOrHash?: Partial<SignerOptions> | BlockHash): Promise<DryRunResult>;
|
|
10
13
|
send(): TxHash;
|
|
11
14
|
send(callback: Callback<ISubmittableResult>): TxUnsub;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { assert, isHex } from '@dedot/utils';
|
|
1
|
+
import { assert, isHex, noop } from '@dedot/utils';
|
|
2
2
|
import { BaseSubmittableExtrinsic } from './BaseSubmittableExtrinsic.js';
|
|
3
3
|
import { SubmittableResult } from './SubmittableResult.js';
|
|
4
4
|
import { toTxStatus, txDefer } from './utils.js';
|
|
@@ -7,6 +7,16 @@ import { toTxStatus, txDefer } from './utils.js';
|
|
|
7
7
|
* @description A wrapper around an Extrinsic that exposes methods to sign, send, and other utility around Extrinsic.
|
|
8
8
|
*/
|
|
9
9
|
export class SubmittableExtrinsic extends BaseSubmittableExtrinsic {
|
|
10
|
+
static fromTx(client, tx) {
|
|
11
|
+
let extrinsic;
|
|
12
|
+
if (isHex(tx)) {
|
|
13
|
+
extrinsic = client.registry.$Extrinsic.tryDecode(tx);
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
extrinsic = tx;
|
|
17
|
+
}
|
|
18
|
+
return new SubmittableExtrinsic(client, extrinsic.call, extrinsic.preamble);
|
|
19
|
+
}
|
|
10
20
|
async dryRun(account, optionsOrHash) {
|
|
11
21
|
const dryRunFn = this.client.rpc.system_dryRun;
|
|
12
22
|
if (isHex(optionsOrHash)) {
|
|
@@ -20,7 +30,11 @@ export class SubmittableExtrinsic extends BaseSubmittableExtrinsic {
|
|
|
20
30
|
const txHex = this.toHex();
|
|
21
31
|
const txHash = this.hash;
|
|
22
32
|
const { deferTx, onTxProgress } = txDefer();
|
|
23
|
-
|
|
33
|
+
let unsub;
|
|
34
|
+
this.client.rpc
|
|
35
|
+
.author_submitAndWatchExtrinsic(txHex, async (txStatus) => {
|
|
36
|
+
let status;
|
|
37
|
+
let result;
|
|
24
38
|
if (txStatus.type === 'InBlock' || txStatus.type === 'Finalized') {
|
|
25
39
|
const blockHash = txStatus.value;
|
|
26
40
|
const [signedBlock, blockEvents] = await Promise.all([
|
|
@@ -31,25 +45,33 @@ export class SubmittableExtrinsic extends BaseSubmittableExtrinsic {
|
|
|
31
45
|
assert(txIndex >= 0, 'Extrinsic not found!');
|
|
32
46
|
const events = blockEvents.filter(({ phase }) => phase.type === 'ApplyExtrinsic' && phase.value === txIndex);
|
|
33
47
|
const blockNumber = signedBlock.block.header.number;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
onTxProgress(result);
|
|
37
|
-
!isSubscription && deferTx.resolve(txHash);
|
|
38
|
-
return callback?.(result);
|
|
48
|
+
status = toTxStatus(txStatus, { txIndex, blockNumber });
|
|
49
|
+
result = this.transformTxResult(new SubmittableResult({ status, txHash, events, txIndex }));
|
|
39
50
|
}
|
|
40
51
|
else {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
onTxProgress(result);
|
|
44
|
-
!isSubscription && deferTx.resolve(txHash);
|
|
45
|
-
return callback?.(result);
|
|
52
|
+
status = toTxStatus(txStatus);
|
|
53
|
+
result = this.transformTxResult(new SubmittableResult({ status, txHash }));
|
|
46
54
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
55
|
+
onTxProgress(result);
|
|
56
|
+
if (isSubscription) {
|
|
57
|
+
callback?.(result);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
deferTx.resolve(txHash);
|
|
61
|
+
}
|
|
62
|
+
if (status.type === 'Finalized' || // --
|
|
63
|
+
status.type === 'Invalid' ||
|
|
64
|
+
status.type === 'Drop') {
|
|
65
|
+
unsub?.().catch(noop);
|
|
66
|
+
}
|
|
67
|
+
})
|
|
68
|
+
.then((x) => {
|
|
69
|
+
unsub = x;
|
|
70
|
+
if (isSubscription) {
|
|
50
71
|
deferTx.resolve(x);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
.catch(deferTx.reject);
|
|
53
75
|
return deferTx.promise;
|
|
54
76
|
}
|
|
55
77
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { Extrinsic, Preamble } from '@dedot/codecs';
|
|
1
2
|
import { Callback, IRuntimeTxCall, TxHash, TxUnsub } from '@dedot/types';
|
|
2
|
-
import {
|
|
3
|
+
import { HexString } from '@dedot/utils';
|
|
4
|
+
import { V2Client } from '../../client/V2Client.js';
|
|
3
5
|
import { BaseSubmittableExtrinsic } from './BaseSubmittableExtrinsic.js';
|
|
4
6
|
/**
|
|
5
7
|
* @name SubmittableExtrinsicV2
|
|
@@ -7,8 +9,9 @@ import { BaseSubmittableExtrinsic } from './BaseSubmittableExtrinsic.js';
|
|
|
7
9
|
*/
|
|
8
10
|
export declare class SubmittableExtrinsicV2 extends BaseSubmittableExtrinsic {
|
|
9
11
|
#private;
|
|
10
|
-
client:
|
|
11
|
-
constructor(client:
|
|
12
|
+
client: V2Client<any>;
|
|
13
|
+
constructor(client: V2Client<any>, call: IRuntimeTxCall, preamble?: Preamble);
|
|
14
|
+
static fromTx(client: V2Client<any>, tx: HexString | Extrinsic): SubmittableExtrinsicV2;
|
|
12
15
|
send(): TxHash;
|
|
13
16
|
send(callback: Callback): TxUnsub;
|
|
14
17
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AsyncQueue, noop, waitFor } from '@dedot/utils';
|
|
1
|
+
import { AsyncQueue, isHex, noop, waitFor } from '@dedot/utils';
|
|
2
2
|
import { BaseSubmittableExtrinsic } from './BaseSubmittableExtrinsic.js';
|
|
3
3
|
import { SubmittableResult } from './SubmittableResult.js';
|
|
4
4
|
import { InvalidTxError } from './errors.js';
|
|
@@ -9,10 +9,20 @@ import { txDefer } from './utils.js';
|
|
|
9
9
|
*/
|
|
10
10
|
export class SubmittableExtrinsicV2 extends BaseSubmittableExtrinsic {
|
|
11
11
|
client;
|
|
12
|
-
constructor(client, call) {
|
|
13
|
-
super(client, call);
|
|
12
|
+
constructor(client, call, preamble) {
|
|
13
|
+
super(client, call, preamble);
|
|
14
14
|
this.client = client;
|
|
15
15
|
}
|
|
16
|
+
static fromTx(client, tx) {
|
|
17
|
+
let extrinsic;
|
|
18
|
+
if (isHex(tx)) {
|
|
19
|
+
extrinsic = client.registry.$Extrinsic.tryDecode(tx);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
extrinsic = tx;
|
|
23
|
+
}
|
|
24
|
+
return new SubmittableExtrinsicV2(client, extrinsic.call, extrinsic.preamble);
|
|
25
|
+
}
|
|
16
26
|
async #send(callback) {
|
|
17
27
|
const api = this.client;
|
|
18
28
|
const txHex = this.toHex();
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { ConnectionStatus, JsonRpcProvider, ProviderEvent } from '@dedot/providers';
|
|
2
|
-
import type {
|
|
2
|
+
import type { GenericSubstrateApi } from '@dedot/types';
|
|
3
3
|
import { EventEmitter } from '@dedot/utils';
|
|
4
4
|
import type { SubstrateApi } from '../chaintypes/index.js';
|
|
5
5
|
import type { IJsonRpcClient, JsonRpcClientOptions } from '../types.js';
|
|
6
6
|
export declare const isJsonRpcProvider: (provider: any) => provider is JsonRpcProvider;
|
|
7
|
-
export declare class JsonRpcClient<ChainApi extends
|
|
8
|
-
Events extends string = ProviderEvent> extends EventEmitter<Events> implements IJsonRpcClient<ChainApi
|
|
7
|
+
export declare class JsonRpcClient<ChainApi extends GenericSubstrateApi = SubstrateApi, // prettier-end-here
|
|
8
|
+
Events extends string = ProviderEvent> extends EventEmitter<Events> implements IJsonRpcClient<ChainApi, Events> {
|
|
9
9
|
#private;
|
|
10
10
|
constructor(options: JsonRpcClientOptions | JsonRpcProvider);
|
|
11
11
|
/**
|
|
@@ -13,13 +13,13 @@ Events extends string = ProviderEvent> extends EventEmitter<Events> implements I
|
|
|
13
13
|
*
|
|
14
14
|
* @param options
|
|
15
15
|
*/
|
|
16
|
-
static create<ChainApi extends
|
|
16
|
+
static create<ChainApi extends GenericSubstrateApi = SubstrateApi>(options: JsonRpcClientOptions | JsonRpcProvider): Promise<JsonRpcClient<ChainApi>>;
|
|
17
17
|
/**
|
|
18
18
|
* Alias for __JsonRpcClient.create__
|
|
19
19
|
*
|
|
20
20
|
* @param options
|
|
21
21
|
*/
|
|
22
|
-
static new<ChainApi extends
|
|
22
|
+
static new<ChainApi extends GenericSubstrateApi = SubstrateApi>(options: JsonRpcClientOptions | JsonRpcProvider): Promise<JsonRpcClient<ChainApi>>;
|
|
23
23
|
get options(): JsonRpcClientOptions;
|
|
24
24
|
/**
|
|
25
25
|
* @description Check connection status of the api instance
|
|
@@ -47,5 +47,5 @@ Events extends string = ProviderEvent> extends EventEmitter<Events> implements I
|
|
|
47
47
|
* const result = await client.rpc.module_rpc_name();
|
|
48
48
|
* ```
|
|
49
49
|
*/
|
|
50
|
-
get rpc(): ChainApi[
|
|
50
|
+
get rpc(): ChainApi['rpc'];
|
|
51
51
|
}
|
|
@@ -13,7 +13,7 @@ import { JsonRpcGroup, JsonRpcGroupOptions } from './JsonRpcGroup.js';
|
|
|
13
13
|
*/
|
|
14
14
|
export declare class Archive extends JsonRpcGroup {
|
|
15
15
|
#private;
|
|
16
|
-
constructor(client: IJsonRpcClient
|
|
16
|
+
constructor(client: IJsonRpcClient<any>, options?: Partial<JsonRpcGroupOptions>);
|
|
17
17
|
/**
|
|
18
18
|
* Retrieves the body (list of transactions) of a given block.
|
|
19
19
|
* Returns an array of strings containing the hexadecimal-encoded SCALE-codec-encoded
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { BlockHash, Option } from '@dedot/codecs';
|
|
2
2
|
import type { ChainHeadRuntimeVersion, OperationId, StorageQuery, StorageResult } from '@dedot/types/json-rpc';
|
|
3
|
+
import { HashFn } from '@dedot/utils';
|
|
3
4
|
import { Deferred, HexString } from '@dedot/utils';
|
|
4
5
|
import type { IJsonRpcClient } from '../../../types.js';
|
|
5
6
|
import { Archive } from '../Archive.js';
|
|
@@ -10,16 +11,22 @@ export type OperationHandler<T = any> = {
|
|
|
10
11
|
storageResults?: Array<StorageResult>;
|
|
11
12
|
hash: BlockHash;
|
|
12
13
|
};
|
|
14
|
+
export type PendingRequest<T = any> = {
|
|
15
|
+
method: string;
|
|
16
|
+
params: any[];
|
|
17
|
+
defer: Deferred<T>;
|
|
18
|
+
};
|
|
13
19
|
export type PinnedBlock = {
|
|
14
20
|
hash: BlockHash;
|
|
15
21
|
number: number;
|
|
16
22
|
parent: BlockHash;
|
|
17
23
|
runtime?: ChainHeadRuntimeVersion;
|
|
24
|
+
runtimeUpgraded?: boolean;
|
|
18
25
|
};
|
|
19
26
|
export type ChainHeadEvent = 'newBlock' | 'bestBlock' | 'finalizedBlock' | 'bestChainChanged';
|
|
20
27
|
export declare class ChainHead extends JsonRpcGroup<ChainHeadEvent> {
|
|
21
28
|
#private;
|
|
22
|
-
constructor(client: IJsonRpcClient
|
|
29
|
+
constructor(client: IJsonRpcClient<any>, options?: Partial<JsonRpcGroupOptions>);
|
|
23
30
|
/**
|
|
24
31
|
* Attach an Archive instance as fallback for operations that fail due to unpinned blocks.
|
|
25
32
|
* When a ChainHeadBlockNotPinnedError occurs, the operation will automatically fallback
|
|
@@ -29,12 +36,21 @@ export declare class ChainHead extends JsonRpcGroup<ChainHeadEvent> {
|
|
|
29
36
|
* @returns this ChainHead instance for method chaining
|
|
30
37
|
*/
|
|
31
38
|
withArchive(archive: Archive): this;
|
|
39
|
+
/**
|
|
40
|
+
* Override send() to track pending requests for retry on network disconnection
|
|
41
|
+
*/
|
|
42
|
+
send<T = any>(method: string, ...params: any[]): Promise<T>;
|
|
32
43
|
runtimeVersion(): Promise<ChainHeadRuntimeVersion>;
|
|
33
44
|
bestRuntimeVersion(): Promise<ChainHeadRuntimeVersion>;
|
|
34
45
|
finalizedHash(): Promise<BlockHash>;
|
|
35
46
|
bestHash(): Promise<BlockHash>;
|
|
36
47
|
bestBlock(): Promise<PinnedBlock>;
|
|
37
48
|
finalizedBlock(): Promise<PinnedBlock>;
|
|
49
|
+
/**
|
|
50
|
+
* Returns the detected hasher for the chain
|
|
51
|
+
* Returns undefined if detection failed (client should use default)
|
|
52
|
+
*/
|
|
53
|
+
hasher(): Promise<HashFn | undefined>;
|
|
38
54
|
findBlock(hash: BlockHash): PinnedBlock | undefined;
|
|
39
55
|
isPinned(hash: BlockHash): boolean;
|
|
40
56
|
/**
|
|
@@ -44,7 +60,7 @@ export declare class ChainHead extends JsonRpcGroup<ChainHeadEvent> {
|
|
|
44
60
|
/**
|
|
45
61
|
* chainHead_follow
|
|
46
62
|
*/
|
|
47
|
-
follow(): Promise<void>;
|
|
63
|
+
follow(force?: boolean): Promise<void>;
|
|
48
64
|
/**
|
|
49
65
|
* chainHead_body
|
|
50
66
|
*/
|