@dedot/api 0.0.1-next.d9aff57d.57 → 0.1.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.js +1 -1
- package/chaintypes/substrate/errors.js +1 -1
- package/chaintypes/substrate/events.js +1 -1
- package/chaintypes/substrate/index.js +1 -1
- package/chaintypes/substrate/json-rpc.d.ts +1 -1
- package/chaintypes/substrate/json-rpc.js +1 -1
- package/chaintypes/substrate/query.js +1 -1
- package/chaintypes/substrate/runtime.js +1 -1
- package/chaintypes/substrate/tx.d.ts +2 -2
- package/chaintypes/substrate/tx.js +1 -1
- package/chaintypes/substrate/types.d.ts +377 -377
- package/chaintypes/substrate/types.js +1 -1
- package/cjs/chaintypes/substrate/consts.js +1 -1
- package/cjs/chaintypes/substrate/errors.js +1 -1
- package/cjs/chaintypes/substrate/events.js +1 -1
- package/cjs/chaintypes/substrate/index.js +1 -1
- package/cjs/chaintypes/substrate/json-rpc.js +1 -1
- package/cjs/chaintypes/substrate/query.js +1 -1
- package/cjs/chaintypes/substrate/runtime.js +1 -1
- package/cjs/chaintypes/substrate/tx.js +1 -1
- package/cjs/chaintypes/substrate/types.js +1 -1
- package/cjs/client/BaseSubstrateClient.js +21 -0
- package/cjs/client/DedotClient.js +5 -4
- package/cjs/client/{Dedot.js → LegacyClient.js} +13 -9
- package/cjs/client/index.js +1 -1
- package/cjs/executor/ErrorExecutor.js +3 -3
- package/cjs/executor/EventExecutor.js +2 -2
- package/cjs/executor/StorageQueryExecutor.js +1 -1
- package/cjs/executor/TxExecutor.js +3 -3
- package/cjs/executor/v2/StorageQueryExecutorV2.js +7 -7
- package/cjs/extrinsic/extensions/known/ChargeAssetTxPayment.js +2 -2
- package/cjs/extrinsic/extensions/known/CheckMetadataHash.js +31 -0
- package/cjs/extrinsic/extensions/known/StorageWeightReclaim.js +10 -0
- package/cjs/extrinsic/extensions/known/index.js +4 -0
- package/cjs/extrinsic/submittable/BaseSubmittableExtrinsic.js +31 -1
- package/cjs/extrinsic/submittable/SubmittableExtrinsic.js +7 -4
- package/cjs/extrinsic/submittable/SubmittableExtrinsicV2.js +11 -11
- package/cjs/extrinsic/submittable/utils.js +66 -1
- package/cjs/storage/QueryableStorage.js +17 -17
- package/client/BaseSubstrateClient.d.ts +15 -9
- package/client/BaseSubstrateClient.js +22 -1
- package/client/DedotClient.d.ts +2 -2
- package/client/DedotClient.js +5 -4
- package/client/{Dedot.d.ts → LegacyClient.d.ts} +8 -7
- package/client/{Dedot.js → LegacyClient.js} +11 -7
- package/client/index.d.ts +1 -1
- package/client/index.js +1 -1
- package/executor/ErrorExecutor.js +3 -3
- package/executor/EventExecutor.js +2 -2
- package/executor/Executor.d.ts +12 -12
- package/executor/StorageQueryExecutor.js +1 -1
- package/executor/TxExecutor.js +3 -3
- package/executor/v2/StorageQueryExecutorV2.js +7 -7
- package/extrinsic/extensions/known/ChargeAssetTxPayment.js +2 -2
- package/extrinsic/extensions/known/CheckMetadataHash.d.ts +13 -0
- package/extrinsic/extensions/known/CheckMetadataHash.js +27 -0
- package/extrinsic/extensions/known/StorageWeightReclaim.d.ts +6 -0
- package/extrinsic/extensions/known/StorageWeightReclaim.js +6 -0
- package/extrinsic/extensions/known/index.js +4 -0
- package/extrinsic/submittable/BaseSubmittableExtrinsic.d.ts +2 -0
- package/extrinsic/submittable/BaseSubmittableExtrinsic.js +32 -2
- package/extrinsic/submittable/SubmittableExtrinsic.js +7 -4
- package/extrinsic/submittable/SubmittableExtrinsicV2.js +11 -11
- package/extrinsic/submittable/SubmittableResult.d.ts +4 -4
- package/extrinsic/submittable/utils.d.ts +10 -1
- package/extrinsic/submittable/utils.js +65 -1
- package/json-rpc/JsonRpcClient.d.ts +6 -5
- package/package.json +11 -11
- package/storage/QueryableStorage.js +17 -17
- package/types.d.ts +9 -1
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { assert, isHex } from '@dedot/utils';
|
|
2
|
+
import { SignedExtension } from '../SignedExtension.js';
|
|
3
|
+
/**
|
|
4
|
+
* @description Genesis hash check to provide replay protection between different networks.
|
|
5
|
+
*/
|
|
6
|
+
export class CheckMetadataHash extends SignedExtension {
|
|
7
|
+
async init() {
|
|
8
|
+
let metadataHash = this.payloadOptions.metadataHash;
|
|
9
|
+
if (metadataHash) {
|
|
10
|
+
assert(isHex(metadataHash), 'Metadata hash is not a valid hex string');
|
|
11
|
+
this.data = { mode: 'Enabled' };
|
|
12
|
+
this.additionalSigned = metadataHash;
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
this.data = { mode: 'Disabled' };
|
|
16
|
+
this.additionalSigned = undefined;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
toPayload() {
|
|
20
|
+
// Ref: https://github.com/paritytech/polkadot-sdk/blob/8dbe4ee80734bba6644c7e5f879a363ce7c0a19f/substrate/frame/metadata-hash-extension/src/lib.rs#L55-L58
|
|
21
|
+
let enabled = this.data.mode === 'Enabled';
|
|
22
|
+
return {
|
|
23
|
+
mode: enabled ? 1 : 0, // 0 -> disabled, 1 -> enabled
|
|
24
|
+
metadataHash: this.additionalSigned,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ChargeAssetTxPayment } from './ChargeAssetTxPayment.js';
|
|
2
2
|
import { ChargeTransactionPayment } from './ChargeTransactionPayment.js';
|
|
3
3
|
import { CheckGenesis } from './CheckGenesis.js';
|
|
4
|
+
import { CheckMetadataHash } from './CheckMetadataHash.js';
|
|
4
5
|
import { CheckMortality } from './CheckMortality.js';
|
|
5
6
|
import { CheckNonZeroSender } from './CheckNonZeroSender.js';
|
|
6
7
|
import { CheckNonce } from './CheckNonce.js';
|
|
@@ -8,6 +9,7 @@ import { CheckSpecVersion } from './CheckSpecVersion.js';
|
|
|
8
9
|
import { CheckTxVersion } from './CheckTxVersion.js';
|
|
9
10
|
import { CheckWeight } from './CheckWeight.js';
|
|
10
11
|
import { PrevalidateAttests } from './PrevalidateAttests.js';
|
|
12
|
+
import { StorageWeightReclaim } from './StorageWeightReclaim.js';
|
|
11
13
|
export const knownSignedExtensions = {
|
|
12
14
|
CheckNonZeroSender,
|
|
13
15
|
CheckSpecVersion,
|
|
@@ -19,4 +21,6 @@ export const knownSignedExtensions = {
|
|
|
19
21
|
ChargeTransactionPayment,
|
|
20
22
|
PrevalidateAttests,
|
|
21
23
|
ChargeAssetTxPayment,
|
|
24
|
+
CheckMetadataHash,
|
|
25
|
+
StorageWeightReclaim,
|
|
22
26
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { BlockHash, Extrinsic, Hash } from '@dedot/codecs';
|
|
2
2
|
import { AddressOrPair, Callback, IRuntimeTxCall, ISubmittableExtrinsic, ISubmittableResult, PayloadOptions, SignerOptions, TxPaymentInfo, Unsub } from '@dedot/types';
|
|
3
|
+
import { HexString } from '@dedot/utils';
|
|
3
4
|
import type { FrameSystemEventRecord } from '../../chaintypes/index.js';
|
|
4
5
|
import type { ISubstrateClient } from '../../types.js';
|
|
5
6
|
export declare abstract class BaseSubmittableExtrinsic extends Extrinsic implements ISubmittableExtrinsic {
|
|
@@ -14,4 +15,5 @@ export declare abstract class BaseSubmittableExtrinsic extends Extrinsic impleme
|
|
|
14
15
|
send(): Promise<Hash>;
|
|
15
16
|
send(callback: Callback): Promise<Unsub>;
|
|
16
17
|
protected getSystemEventsAt(hash: BlockHash): Promise<FrameSystemEventRecord[]>;
|
|
18
|
+
toHex(): HexString;
|
|
17
19
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { Extrinsic } from '@dedot/codecs';
|
|
2
|
-
import { isFunction, u8aToHex } from '@dedot/utils';
|
|
2
|
+
import { DedotError, isFunction, toHex, u8aToHex } from '@dedot/utils';
|
|
3
3
|
import { ExtraSignedExtension } from '../extensions/index.js';
|
|
4
4
|
import { fakeSigner } from './fakeSigner.js';
|
|
5
5
|
import { isKeyringPair, signRaw } from './utils.js';
|
|
6
6
|
export class BaseSubmittableExtrinsic extends Extrinsic {
|
|
7
7
|
api;
|
|
8
|
+
#alterTx;
|
|
8
9
|
constructor(api, call) {
|
|
9
10
|
super(api.registry, call);
|
|
10
11
|
this.api = api;
|
|
@@ -23,13 +24,14 @@ export class BaseSubmittableExtrinsic extends Extrinsic {
|
|
|
23
24
|
});
|
|
24
25
|
await extra.init();
|
|
25
26
|
const { signer } = options || {};
|
|
26
|
-
let signature;
|
|
27
|
+
let signature, alteredTx;
|
|
27
28
|
if (isKeyringPair(fromAccount)) {
|
|
28
29
|
signature = u8aToHex(signRaw(fromAccount, extra.toRawPayload(this.callHex).data));
|
|
29
30
|
}
|
|
30
31
|
else if (signer?.signPayload) {
|
|
31
32
|
const result = await signer.signPayload(extra.toPayload(this.callHex));
|
|
32
33
|
signature = result.signature;
|
|
34
|
+
alteredTx = result.signedTransaction;
|
|
33
35
|
}
|
|
34
36
|
else {
|
|
35
37
|
throw new Error('Signer not found. Cannot sign the extrinsic!');
|
|
@@ -41,6 +43,13 @@ export class BaseSubmittableExtrinsic extends Extrinsic {
|
|
|
41
43
|
signature: $Signature.tryDecode(signature),
|
|
42
44
|
extra: extra.data,
|
|
43
45
|
});
|
|
46
|
+
// If the tx payload are altered from signer
|
|
47
|
+
// We'll need to validate the altered tx
|
|
48
|
+
// and broadcast it instead of the original tx
|
|
49
|
+
if (alteredTx) {
|
|
50
|
+
this.#validateSignedTx(alteredTx);
|
|
51
|
+
this.#alterTx = toHex(alteredTx);
|
|
52
|
+
}
|
|
44
53
|
return this;
|
|
45
54
|
}
|
|
46
55
|
async signAndSend(fromAccount, partialOptions, maybeCallback) {
|
|
@@ -63,4 +72,25 @@ export class BaseSubmittableExtrinsic extends Extrinsic {
|
|
|
63
72
|
const atApi = (await this.api.at(hash));
|
|
64
73
|
return await atApi.query.system.events();
|
|
65
74
|
}
|
|
75
|
+
toHex() {
|
|
76
|
+
return this.#alterTx || super.toHex();
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Validate a raw signed transaction coming from signer
|
|
80
|
+
* We need to make sure the tx is signed and call-data is intact/not-changing
|
|
81
|
+
*
|
|
82
|
+
* @param tx
|
|
83
|
+
* @private
|
|
84
|
+
*/
|
|
85
|
+
#validateSignedTx(tx) {
|
|
86
|
+
const alteredTx = this.$Codec.tryDecode(tx);
|
|
87
|
+
// The alter tx should be signed
|
|
88
|
+
if (!alteredTx.signed) {
|
|
89
|
+
throw new DedotError('Altered transaction from signer is not signed');
|
|
90
|
+
}
|
|
91
|
+
// Signer's not allow the change the call data
|
|
92
|
+
if (alteredTx.callHex !== this.callHex) {
|
|
93
|
+
throw new DedotError('Call data does not match, signer is not allowed to change tx call data.');
|
|
94
|
+
}
|
|
95
|
+
}
|
|
66
96
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { assert, isHex } from '@dedot/utils';
|
|
2
2
|
import { BaseSubmittableExtrinsic } from './BaseSubmittableExtrinsic.js';
|
|
3
3
|
import { SubmittableResult } from './SubmittableResult.js';
|
|
4
|
+
import { toTxStatus } from './utils.js';
|
|
4
5
|
/**
|
|
5
6
|
* @name SubmittableExtrinsic
|
|
6
7
|
* @description A wrapper around an Extrinsic that exposes methods to sign, send, and other utility around Extrinsic.
|
|
@@ -19,19 +20,21 @@ export class SubmittableExtrinsic extends BaseSubmittableExtrinsic {
|
|
|
19
20
|
const txHex = this.toHex();
|
|
20
21
|
const txHash = this.hash;
|
|
21
22
|
if (isSubscription) {
|
|
22
|
-
return this.api.rpc.author_submitAndWatchExtrinsic(txHex, async (
|
|
23
|
-
if (
|
|
24
|
-
const blockHash =
|
|
23
|
+
return this.api.rpc.author_submitAndWatchExtrinsic(txHex, async (txStatus) => {
|
|
24
|
+
if (txStatus.type === 'InBlock' || txStatus.type === 'Finalized') {
|
|
25
|
+
const blockHash = txStatus.value;
|
|
25
26
|
const [signedBlock, blockEvents] = await Promise.all([
|
|
26
27
|
this.api.rpc.chain_getBlock(blockHash),
|
|
27
28
|
this.getSystemEventsAt(blockHash),
|
|
28
29
|
]);
|
|
29
30
|
const txIndex = signedBlock.block.extrinsics.indexOf(txHex);
|
|
30
31
|
assert(txIndex >= 0, 'Extrinsic not found!');
|
|
31
|
-
const events = blockEvents.filter(({ phase }) => phase.
|
|
32
|
+
const events = blockEvents.filter(({ phase }) => phase.type === 'ApplyExtrinsic' && phase.value === txIndex);
|
|
33
|
+
const status = toTxStatus(txStatus, txIndex);
|
|
32
34
|
return callback(new SubmittableResult({ status, txHash, events, txIndex }));
|
|
33
35
|
}
|
|
34
36
|
else {
|
|
37
|
+
const status = toTxStatus(txStatus);
|
|
35
38
|
return callback(new SubmittableResult({ status, txHash }));
|
|
36
39
|
}
|
|
37
40
|
});
|
|
@@ -25,10 +25,10 @@ export class SubmittableExtrinsicV2 extends BaseSubmittableExtrinsic {
|
|
|
25
25
|
};
|
|
26
26
|
const validation = await validateTx(finalizedHash);
|
|
27
27
|
if (validation.isOk) {
|
|
28
|
-
callback(new SubmittableResult({ status: {
|
|
28
|
+
callback(new SubmittableResult({ status: { type: 'Validated' }, txHash }));
|
|
29
29
|
}
|
|
30
30
|
else if (validation.isErr) {
|
|
31
|
-
throw new InvalidTxError(`Invalid Tx: ${validation.err.
|
|
31
|
+
throw new InvalidTxError(`Invalid Tx: ${validation.err.type} - ${validation.err.value.type}`, validation);
|
|
32
32
|
}
|
|
33
33
|
const checkTxIsOnChain = async (blockHash) => {
|
|
34
34
|
if (blockHash === finalizedHash)
|
|
@@ -39,7 +39,7 @@ export class SubmittableExtrinsicV2 extends BaseSubmittableExtrinsic {
|
|
|
39
39
|
return checkTxIsOnChain(api.chainHead.findBlock(blockHash).parent);
|
|
40
40
|
}
|
|
41
41
|
const events = await this.getSystemEventsAt(blockHash);
|
|
42
|
-
const txEvents = events.filter(({ phase }) => phase.
|
|
42
|
+
const txEvents = events.filter(({ phase }) => phase.type == 'ApplyExtrinsic' && phase.value === txIndex);
|
|
43
43
|
return {
|
|
44
44
|
blockHash,
|
|
45
45
|
index: txIndex,
|
|
@@ -85,7 +85,7 @@ export class SubmittableExtrinsicV2 extends BaseSubmittableExtrinsic {
|
|
|
85
85
|
if (txFound && bestChainChanged) {
|
|
86
86
|
txFound = undefined;
|
|
87
87
|
callback(new SubmittableResult({
|
|
88
|
-
status: {
|
|
88
|
+
status: { type: 'NoLongerInBestChain' },
|
|
89
89
|
txHash,
|
|
90
90
|
}));
|
|
91
91
|
}
|
|
@@ -98,7 +98,7 @@ export class SubmittableExtrinsicV2 extends BaseSubmittableExtrinsic {
|
|
|
98
98
|
txFound = inBlock;
|
|
99
99
|
const { index: txIndex, events, blockHash } = inBlock;
|
|
100
100
|
callback(new SubmittableResult({
|
|
101
|
-
status: {
|
|
101
|
+
status: { type: 'BestChainBlockIncluded', value: { blockHash, txIndex } },
|
|
102
102
|
txHash,
|
|
103
103
|
events,
|
|
104
104
|
txIndex,
|
|
@@ -131,7 +131,7 @@ export class SubmittableExtrinsicV2 extends BaseSubmittableExtrinsic {
|
|
|
131
131
|
if (inBlock) {
|
|
132
132
|
const { index: txIndex, events, blockHash } = inBlock;
|
|
133
133
|
callback(new SubmittableResult({
|
|
134
|
-
status: {
|
|
134
|
+
status: { type: 'Finalized', value: { blockHash, txIndex } },
|
|
135
135
|
txHash,
|
|
136
136
|
events,
|
|
137
137
|
txIndex,
|
|
@@ -145,8 +145,8 @@ export class SubmittableExtrinsicV2 extends BaseSubmittableExtrinsic {
|
|
|
145
145
|
return;
|
|
146
146
|
callback(new SubmittableResult({
|
|
147
147
|
status: {
|
|
148
|
-
|
|
149
|
-
value: { error: `Invalid Tx: ${validation.err.
|
|
148
|
+
type: 'Invalid',
|
|
149
|
+
value: { error: `Invalid Tx: ${validation.err.type} - ${validation.err.value.type}` },
|
|
150
150
|
},
|
|
151
151
|
txHash,
|
|
152
152
|
}));
|
|
@@ -155,7 +155,7 @@ export class SubmittableExtrinsicV2 extends BaseSubmittableExtrinsic {
|
|
|
155
155
|
};
|
|
156
156
|
stopBroadcastFn = await api.txBroadcaster.broadcastTx(txHex);
|
|
157
157
|
callback(new SubmittableResult({
|
|
158
|
-
status: {
|
|
158
|
+
status: { type: 'Broadcasting' },
|
|
159
159
|
txHash,
|
|
160
160
|
}));
|
|
161
161
|
const stopBestBlockTrackingFn = api.chainHead.on('bestBlock', checkBestBlockIncluded);
|
|
@@ -181,11 +181,11 @@ export class SubmittableExtrinsicV2 extends BaseSubmittableExtrinsic {
|
|
|
181
181
|
try {
|
|
182
182
|
// TODO handle timeout for this with the Drop status, just in-case we somehow can't find the tx in any block
|
|
183
183
|
const unsub = await this.#send(({ status, txHash }) => {
|
|
184
|
-
if (status.
|
|
184
|
+
if (status.type === 'BestChainBlockIncluded' || status.type === 'Finalized') {
|
|
185
185
|
defer.resolve(txHash);
|
|
186
186
|
unsub().catch(noop);
|
|
187
187
|
}
|
|
188
|
-
else if (status.
|
|
188
|
+
else if (status.type === 'Invalid' || status.type === 'Drop') {
|
|
189
189
|
defer.reject(new Error(status.value.error));
|
|
190
190
|
unsub().catch(noop);
|
|
191
191
|
}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import type { DispatchError, DispatchInfo, Hash } from '@dedot/codecs';
|
|
2
|
-
import type { IEventRecord, ISubmittableResult } from '@dedot/types';
|
|
2
|
+
import type { IEventRecord, ISubmittableResult, TxStatus } from '@dedot/types';
|
|
3
3
|
import type { FrameSystemEventRecord } from '../../chaintypes/index.js';
|
|
4
|
-
export interface SubmittableResultInputs<E extends IEventRecord = FrameSystemEventRecord
|
|
4
|
+
export interface SubmittableResultInputs<E extends IEventRecord = FrameSystemEventRecord> {
|
|
5
5
|
events?: E[];
|
|
6
6
|
status: TxStatus;
|
|
7
7
|
txHash: Hash;
|
|
8
8
|
txIndex?: number;
|
|
9
9
|
}
|
|
10
|
-
export declare class SubmittableResult<E extends IEventRecord = FrameSystemEventRecord
|
|
10
|
+
export declare class SubmittableResult<E extends IEventRecord = FrameSystemEventRecord> implements ISubmittableResult<E> {
|
|
11
11
|
status: TxStatus;
|
|
12
12
|
events: E[];
|
|
13
13
|
dispatchInfo?: DispatchInfo;
|
|
14
14
|
dispatchError?: DispatchError;
|
|
15
15
|
txHash: Hash;
|
|
16
16
|
txIndex?: number;
|
|
17
|
-
constructor({ events, status, txHash, txIndex }: SubmittableResultInputs<E
|
|
17
|
+
constructor({ events, status, txHash, txIndex }: SubmittableResultInputs<E>);
|
|
18
18
|
_extractDispatchInfo(): [DispatchInfo | undefined, DispatchError | undefined];
|
|
19
19
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { IKeyringPair } from '@polkadot/types/types';
|
|
2
|
-
import
|
|
2
|
+
import { TransactionStatus } from '@dedot/codecs';
|
|
3
|
+
import type { AddressOrPair, TxStatus } from '@dedot/types';
|
|
3
4
|
import { HexString } from '@dedot/utils';
|
|
4
5
|
export declare function isKeyringPair(account: AddressOrPair): account is IKeyringPair;
|
|
5
6
|
/**
|
|
@@ -8,3 +9,11 @@ export declare function isKeyringPair(account: AddressOrPair): account is IKeyri
|
|
|
8
9
|
* @param raw
|
|
9
10
|
*/
|
|
10
11
|
export declare function signRaw(signerPair: IKeyringPair, raw: HexString): Uint8Array;
|
|
12
|
+
/**
|
|
13
|
+
* Convert transaction status to transaction event
|
|
14
|
+
*
|
|
15
|
+
* Ref: https://github.com/paritytech/polkadot-sdk/blob/98a364fe6e7abf10819f5fddd3de0588f7c38700/substrate/client/rpc-spec-v2/src/transaction/transaction.rs#L132-L159
|
|
16
|
+
* @param txStatus
|
|
17
|
+
* @param txIndex
|
|
18
|
+
*/
|
|
19
|
+
export declare function toTxStatus(txStatus: TransactionStatus, txIndex?: number): TxStatus;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { blake2AsU8a, hexToU8a, isFunction } from '@dedot/utils';
|
|
1
|
+
import { assert, blake2AsU8a, hexToU8a, isFunction } from '@dedot/utils';
|
|
2
2
|
export function isKeyringPair(account) {
|
|
3
3
|
return isFunction(account.sign);
|
|
4
4
|
}
|
|
@@ -13,3 +13,67 @@ export function signRaw(signerPair, raw) {
|
|
|
13
13
|
const toSignRaw = u8a.length > 256 ? blake2AsU8a(u8a, 256) : u8a;
|
|
14
14
|
return signerPair.sign(toSignRaw, { withType: true });
|
|
15
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Convert transaction status to transaction event
|
|
18
|
+
*
|
|
19
|
+
* Ref: https://github.com/paritytech/polkadot-sdk/blob/98a364fe6e7abf10819f5fddd3de0588f7c38700/substrate/client/rpc-spec-v2/src/transaction/transaction.rs#L132-L159
|
|
20
|
+
* @param txStatus
|
|
21
|
+
* @param txIndex
|
|
22
|
+
*/
|
|
23
|
+
export function toTxStatus(txStatus, txIndex) {
|
|
24
|
+
switch (txStatus.type) {
|
|
25
|
+
case 'Ready':
|
|
26
|
+
case 'Future':
|
|
27
|
+
return { type: 'Validated' };
|
|
28
|
+
case 'Broadcast':
|
|
29
|
+
return { type: 'Broadcasting' };
|
|
30
|
+
case 'Retracted':
|
|
31
|
+
return { type: 'NoLongerInBestChain' };
|
|
32
|
+
case 'InBlock':
|
|
33
|
+
assert(txIndex, 'TxIndex is required');
|
|
34
|
+
return {
|
|
35
|
+
type: 'BestChainBlockIncluded',
|
|
36
|
+
value: {
|
|
37
|
+
blockHash: txStatus.value,
|
|
38
|
+
txIndex,
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
case 'Finalized':
|
|
42
|
+
assert(txIndex, 'TxIndex is required');
|
|
43
|
+
return {
|
|
44
|
+
type: 'Finalized',
|
|
45
|
+
value: {
|
|
46
|
+
blockHash: txStatus.value,
|
|
47
|
+
txIndex,
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
case 'FinalityTimeout':
|
|
51
|
+
return {
|
|
52
|
+
type: 'Drop',
|
|
53
|
+
value: {
|
|
54
|
+
error: 'Maximum number of finality watchers has been reached',
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
case 'Dropped':
|
|
58
|
+
return {
|
|
59
|
+
type: 'Drop',
|
|
60
|
+
value: {
|
|
61
|
+
error: 'Extrinsic dropped from the pool due to exceeding limits',
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
case 'Usurped':
|
|
65
|
+
return {
|
|
66
|
+
type: 'Invalid',
|
|
67
|
+
value: {
|
|
68
|
+
error: 'Extrinsic was rendered invalid by another extrinsic',
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
case 'Invalid':
|
|
72
|
+
return {
|
|
73
|
+
type: 'Invalid',
|
|
74
|
+
value: {
|
|
75
|
+
error: 'Extrinsic marked as invalid',
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { ConnectionStatus, JsonRpcProvider, ProviderEvent } from '@dedot/providers';
|
|
2
|
-
import type {
|
|
2
|
+
import type { RpcVersion, VersionedGenericSubstrateApi } 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
|
|
7
|
+
export declare class JsonRpcClient<ChainApi extends VersionedGenericSubstrateApi = SubstrateApi, // prettier-end-here
|
|
8
|
+
Events extends string = ProviderEvent> extends EventEmitter<Events> implements IJsonRpcClient<ChainApi[RpcVersion], Events> {
|
|
8
9
|
#private;
|
|
9
10
|
constructor(options: JsonRpcClientOptions | JsonRpcProvider);
|
|
10
11
|
/**
|
|
@@ -12,13 +13,13 @@ export declare class JsonRpcClient<ChainApi extends GenericSubstrateApi = Substr
|
|
|
12
13
|
*
|
|
13
14
|
* @param options
|
|
14
15
|
*/
|
|
15
|
-
static create<ChainApi extends
|
|
16
|
+
static create<ChainApi extends VersionedGenericSubstrateApi = SubstrateApi>(options: JsonRpcClientOptions | JsonRpcProvider): Promise<JsonRpcClient<ChainApi>>;
|
|
16
17
|
/**
|
|
17
18
|
* Alias for __JsonRpcClient.create__
|
|
18
19
|
*
|
|
19
20
|
* @param options
|
|
20
21
|
*/
|
|
21
|
-
static new<ChainApi extends
|
|
22
|
+
static new<ChainApi extends VersionedGenericSubstrateApi = SubstrateApi>(options: JsonRpcClientOptions | JsonRpcProvider): Promise<JsonRpcClient<ChainApi>>;
|
|
22
23
|
get options(): JsonRpcClientOptions;
|
|
23
24
|
/**
|
|
24
25
|
* @description Check connection status of the api instance
|
|
@@ -46,5 +47,5 @@ export declare class JsonRpcClient<ChainApi extends GenericSubstrateApi = Substr
|
|
|
46
47
|
* const result = await client.rpc.module_rpc_name();
|
|
47
48
|
* ```
|
|
48
49
|
*/
|
|
49
|
-
get rpc(): ChainApi['rpc'];
|
|
50
|
+
get rpc(): ChainApi[RpcVersion]['rpc'];
|
|
50
51
|
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dedot/api",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "A delightful JavaScript/TypeScript client for Polkadot & Substrate",
|
|
5
5
|
"author": "Thang X. Vu <thang@coongcrafts.io>",
|
|
6
|
-
"homepage": "https://github.com/dedotdev/dedot",
|
|
6
|
+
"homepage": "https://github.com/dedotdev/dedot/tree/main/packages/api",
|
|
7
7
|
"repository": {
|
|
8
8
|
"directory": "packages/api",
|
|
9
9
|
"type": "git",
|
|
@@ -13,13 +13,13 @@
|
|
|
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.1.0",
|
|
17
|
+
"@dedot/providers": "0.1.0",
|
|
18
|
+
"@dedot/runtime-specs": "0.1.0",
|
|
19
|
+
"@dedot/shape": "0.1.0",
|
|
20
|
+
"@dedot/storage": "0.1.0",
|
|
21
|
+
"@dedot/types": "0.1.0",
|
|
22
|
+
"@dedot/utils": "0.1.0"
|
|
23
23
|
},
|
|
24
24
|
"scripts": {
|
|
25
25
|
"build": "tsc --project tsconfig.build.json && tsc --project tsconfig.build.cjs.json",
|
|
@@ -46,9 +46,9 @@
|
|
|
46
46
|
},
|
|
47
47
|
"license": "Apache-2.0",
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@polkadot/types": "^
|
|
49
|
+
"@polkadot/types": "^12.2.1"
|
|
50
50
|
},
|
|
51
|
-
"gitHead": "
|
|
51
|
+
"gitHead": "c8220a4ab4b171fe04adb49759318bde865d7c17",
|
|
52
52
|
"module": "./index.js",
|
|
53
53
|
"types": "./index.d.ts"
|
|
54
54
|
}
|
|
@@ -36,14 +36,14 @@ export class QueryableStorage {
|
|
|
36
36
|
const storageItemHash = xxhashAsU8a(this.storageEntry.name, 128);
|
|
37
37
|
return concatU8a(palletNameHash, storageItemHash);
|
|
38
38
|
}
|
|
39
|
-
#getStorageMapInfo(
|
|
40
|
-
assert(type
|
|
41
|
-
const { hashers, keyTypeId } =
|
|
39
|
+
#getStorageMapInfo(storageType) {
|
|
40
|
+
assert(storageType.type === 'Map');
|
|
41
|
+
const { hashers, keyTypeId } = storageType.value;
|
|
42
42
|
let keyTypeIds = [keyTypeId];
|
|
43
43
|
if (hashers.length > 1) {
|
|
44
|
-
const {
|
|
45
|
-
assert(type
|
|
46
|
-
keyTypeIds =
|
|
44
|
+
const { typeDef } = this.registry.findType(keyTypeId);
|
|
45
|
+
assert(typeDef.type === 'Tuple', 'Key type should be a tuple!');
|
|
46
|
+
keyTypeIds = typeDef.value.fields;
|
|
47
47
|
}
|
|
48
48
|
return { hashers, keyTypeIds };
|
|
49
49
|
}
|
|
@@ -53,12 +53,12 @@ export class QueryableStorage {
|
|
|
53
53
|
* @param keyInput
|
|
54
54
|
*/
|
|
55
55
|
encodeKey(keyInput) {
|
|
56
|
-
const {
|
|
57
|
-
if (type
|
|
56
|
+
const { storageType } = this.storageEntry;
|
|
57
|
+
if (storageType.type === 'Plain') {
|
|
58
58
|
return this.prefixKey;
|
|
59
59
|
}
|
|
60
|
-
else if (type
|
|
61
|
-
const { hashers, keyTypeIds } = this.#getStorageMapInfo(
|
|
60
|
+
else if (storageType.type === 'Map') {
|
|
61
|
+
const { hashers, keyTypeIds } = this.#getStorageMapInfo(storageType);
|
|
62
62
|
const extractedInputs = this.#extractRequiredKeyInputs(keyInput, hashers.length);
|
|
63
63
|
const keyParts = keyTypeIds.map((keyId, index) => {
|
|
64
64
|
const input = extractedInputs[index];
|
|
@@ -68,7 +68,7 @@ export class QueryableStorage {
|
|
|
68
68
|
});
|
|
69
69
|
return u8aToHex(concatU8a(this.prefixKeyAsU8a, ...keyParts));
|
|
70
70
|
}
|
|
71
|
-
throw Error(`Invalid storage entry type: ${
|
|
71
|
+
throw Error(`Invalid storage entry type: ${JSON.stringify(storageType)}`);
|
|
72
72
|
}
|
|
73
73
|
/**
|
|
74
74
|
* Decode storage key to plain key input
|
|
@@ -77,16 +77,16 @@ export class QueryableStorage {
|
|
|
77
77
|
* @param key
|
|
78
78
|
*/
|
|
79
79
|
decodeKey(key) {
|
|
80
|
-
const {
|
|
81
|
-
if (type
|
|
80
|
+
const { storageType } = this.storageEntry;
|
|
81
|
+
if (storageType.type === 'Plain') {
|
|
82
82
|
return;
|
|
83
83
|
}
|
|
84
|
-
else if (type
|
|
84
|
+
else if (storageType.type === 'Map') {
|
|
85
85
|
const prefix = this.prefixKey;
|
|
86
86
|
if (!key.startsWith(prefix)) {
|
|
87
87
|
throw new Error(`Storage key does not match this storage entry (${this.palletName}.${this.storageItem})`);
|
|
88
88
|
}
|
|
89
|
-
const { hashers, keyTypeIds } = this.#getStorageMapInfo(
|
|
89
|
+
const { hashers, keyTypeIds } = this.#getStorageMapInfo(storageType);
|
|
90
90
|
let keyData = hexToU8a(hexAddPrefix(key.slice(prefix.length)));
|
|
91
91
|
const results = keyTypeIds.map((keyId, index) => {
|
|
92
92
|
const [hashLen, canDecode] = HASHER_INFO[hashers[index]];
|
|
@@ -101,7 +101,7 @@ export class QueryableStorage {
|
|
|
101
101
|
});
|
|
102
102
|
return hashers.length > 1 ? results : results[0];
|
|
103
103
|
}
|
|
104
|
-
throw Error(`Invalid storage entry type: ${
|
|
104
|
+
throw Error(`Invalid storage entry type: ${JSON.stringify(storageType)}`);
|
|
105
105
|
}
|
|
106
106
|
/**
|
|
107
107
|
* Decode raw/bytes storage data to plain value
|
|
@@ -109,7 +109,7 @@ export class QueryableStorage {
|
|
|
109
109
|
* @param raw
|
|
110
110
|
*/
|
|
111
111
|
decodeValue(raw) {
|
|
112
|
-
const { modifier,
|
|
112
|
+
const { modifier, storageType: { value: { valueTypeId }, }, default: defaultValue, } = this.storageEntry;
|
|
113
113
|
if (raw === null || raw === undefined) {
|
|
114
114
|
if (modifier === 'Optional') {
|
|
115
115
|
return undefined;
|
package/types.d.ts
CHANGED
|
@@ -56,7 +56,7 @@ export interface ApiOptions extends JsonRpcClientOptions {
|
|
|
56
56
|
*/
|
|
57
57
|
hasher?: HashFn;
|
|
58
58
|
}
|
|
59
|
-
export type ApiEvent = ProviderEvent | 'ready';
|
|
59
|
+
export type ApiEvent = ProviderEvent | 'ready' | 'runtimeUpgraded';
|
|
60
60
|
export interface SubstrateRuntimeVersion {
|
|
61
61
|
specName: string;
|
|
62
62
|
implName: string;
|
|
@@ -101,6 +101,14 @@ export interface ISubstrateClient<ChainApi extends GenericSubstrateApi = Generic
|
|
|
101
101
|
options: ApiOptions;
|
|
102
102
|
tx: ChainApi['tx'];
|
|
103
103
|
at<ChainApiAt extends GenericSubstrateApi = ChainApi>(hash: BlockHash): Promise<ISubstrateClientAt<ChainApiAt>>;
|
|
104
|
+
/**
|
|
105
|
+
* Get current version of the runtime
|
|
106
|
+
* This is similar to `.runtimeVersion` but also ensure
|
|
107
|
+
* the corresponding metadata of this runtime version is downloaded & setup.
|
|
108
|
+
*
|
|
109
|
+
* This is helpful when you want to check runtime version to prepare for runtime upgrade
|
|
110
|
+
*/
|
|
111
|
+
getRuntimeVersion(): Promise<SubstrateRuntimeVersion>;
|
|
104
112
|
}
|
|
105
113
|
/**
|
|
106
114
|
* A generic interface for broadcasting transactions
|