@dedot/api 0.9.6 → 0.10.1-next.b29d4eee.6
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/extrinsic/submittable/BaseSubmittableExtrinsic.js +28 -3
- package/cjs/extrinsic/submittable/SubmittableExtrinsic.js +30 -22
- package/cjs/extrinsic/submittable/SubmittableExtrinsicV2.js +31 -22
- package/cjs/extrinsic/submittable/errors.js +10 -1
- package/cjs/extrinsic/submittable/utils.js +39 -1
- package/cjs/test.js +29 -0
- package/executor/Executor.d.ts +1 -1
- package/extrinsic/submittable/BaseSubmittableExtrinsic.d.ts +7 -7
- package/extrinsic/submittable/BaseSubmittableExtrinsic.js +29 -4
- package/extrinsic/submittable/SubmittableExtrinsic.d.ts +4 -4
- package/extrinsic/submittable/SubmittableExtrinsic.js +31 -23
- package/extrinsic/submittable/SubmittableExtrinsicV2.d.ts +3 -4
- package/extrinsic/submittable/SubmittableExtrinsicV2.js +32 -23
- package/extrinsic/submittable/errors.d.ts +6 -0
- package/extrinsic/submittable/errors.js +8 -0
- package/extrinsic/submittable/utils.d.ts +8 -2
- package/extrinsic/submittable/utils.js +38 -1
- package/package.json +9 -9
- package/test.d.ts +1 -0
- package/test.js +24 -0
|
@@ -55,10 +55,35 @@ class BaseSubmittableExtrinsic extends codecs_1.Extrinsic {
|
|
|
55
55
|
}
|
|
56
56
|
return this;
|
|
57
57
|
}
|
|
58
|
-
|
|
58
|
+
signAndSend(fromAccount, partialOptions, maybeCallback) {
|
|
59
59
|
const [options, callback] = this.#normalizeOptions(partialOptions, maybeCallback);
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
const { deferTx, deferFinalized, deferBestChainBlockIncluded, onTxProgress } = (0, utils_js_1.txDefer)();
|
|
61
|
+
this.sign(fromAccount, options)
|
|
62
|
+
.then(() => {
|
|
63
|
+
const deferSend = this.send(callback);
|
|
64
|
+
deferSend
|
|
65
|
+
.then(deferTx.resolve) // --
|
|
66
|
+
.catch(deferTx.reject);
|
|
67
|
+
deferSend
|
|
68
|
+
.untilBestChainBlockIncluded() //--
|
|
69
|
+
.then((r) => {
|
|
70
|
+
onTxProgress(r);
|
|
71
|
+
})
|
|
72
|
+
.catch((e) => {
|
|
73
|
+
deferBestChainBlockIncluded()?.reject(e);
|
|
74
|
+
});
|
|
75
|
+
deferSend
|
|
76
|
+
.untilFinalized() //--
|
|
77
|
+
.then((r) => {
|
|
78
|
+
onTxProgress(r);
|
|
79
|
+
})
|
|
80
|
+
.catch((e) => {
|
|
81
|
+
deferBestChainBlockIncluded()?.reject(e);
|
|
82
|
+
deferFinalized()?.reject(e);
|
|
83
|
+
});
|
|
84
|
+
})
|
|
85
|
+
.catch(deferTx.reject);
|
|
86
|
+
return deferTx.promise;
|
|
62
87
|
}
|
|
63
88
|
#normalizeOptions(partialOptions, callback) {
|
|
64
89
|
if ((0, utils_1.isFunction)(partialOptions)) {
|
|
@@ -18,34 +18,42 @@ class SubmittableExtrinsic extends BaseSubmittableExtrinsic_js_1.BaseSubmittable
|
|
|
18
18
|
await this.sign(account, optionsOrHash);
|
|
19
19
|
return dryRunFn(this.toHex());
|
|
20
20
|
}
|
|
21
|
-
|
|
21
|
+
send(callback) {
|
|
22
22
|
const isSubscription = !!callback;
|
|
23
23
|
const txHex = this.toHex();
|
|
24
24
|
const txHash = this.hash;
|
|
25
|
+
const { deferTx, onTxProgress } = (0, utils_js_1.txDefer)();
|
|
26
|
+
const unsub = this.client.rpc.author_submitAndWatchExtrinsic(txHex, async (txStatus) => {
|
|
27
|
+
if (txStatus.type === 'InBlock' || txStatus.type === 'Finalized') {
|
|
28
|
+
const blockHash = txStatus.value;
|
|
29
|
+
const [signedBlock, blockEvents] = await Promise.all([
|
|
30
|
+
this.client.rpc.chain_getBlock(blockHash),
|
|
31
|
+
this.getSystemEventsAt(blockHash),
|
|
32
|
+
]);
|
|
33
|
+
const txIndex = signedBlock.block.extrinsics.indexOf(txHex);
|
|
34
|
+
(0, utils_1.assert)(txIndex >= 0, 'Extrinsic not found!');
|
|
35
|
+
const events = blockEvents.filter(({ phase }) => phase.type === 'ApplyExtrinsic' && phase.value === txIndex);
|
|
36
|
+
const blockNumber = signedBlock.block.header.number;
|
|
37
|
+
const status = (0, utils_js_1.toTxStatus)(txStatus, { txIndex, blockNumber });
|
|
38
|
+
const result = new SubmittableResult_js_1.SubmittableResult({ status, txHash, events, txIndex });
|
|
39
|
+
onTxProgress(result);
|
|
40
|
+
!isSubscription && deferTx.resolve(txHash);
|
|
41
|
+
return callback?.(result);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
const status = (0, utils_js_1.toTxStatus)(txStatus);
|
|
45
|
+
const result = new SubmittableResult_js_1.SubmittableResult({ status, txHash });
|
|
46
|
+
onTxProgress(result);
|
|
47
|
+
!isSubscription && deferTx.resolve(txHash);
|
|
48
|
+
return callback?.(new SubmittableResult_js_1.SubmittableResult({ status, txHash }));
|
|
49
|
+
}
|
|
50
|
+
});
|
|
25
51
|
if (isSubscription) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const blockHash = txStatus.value;
|
|
29
|
-
const [signedBlock, blockEvents] = await Promise.all([
|
|
30
|
-
this.client.rpc.chain_getBlock(blockHash),
|
|
31
|
-
this.getSystemEventsAt(blockHash),
|
|
32
|
-
]);
|
|
33
|
-
const txIndex = signedBlock.block.extrinsics.indexOf(txHex);
|
|
34
|
-
(0, utils_1.assert)(txIndex >= 0, 'Extrinsic not found!');
|
|
35
|
-
const events = blockEvents.filter(({ phase }) => phase.type === 'ApplyExtrinsic' && phase.value === txIndex);
|
|
36
|
-
const blockNumber = signedBlock.block.header.number;
|
|
37
|
-
const status = (0, utils_js_1.toTxStatus)(txStatus, { txIndex, blockNumber });
|
|
38
|
-
return callback(new SubmittableResult_js_1.SubmittableResult({ status, txHash, events, txIndex }));
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
const status = (0, utils_js_1.toTxStatus)(txStatus);
|
|
42
|
-
return callback(new SubmittableResult_js_1.SubmittableResult({ status, txHash }));
|
|
43
|
-
}
|
|
52
|
+
unsub.then((x) => {
|
|
53
|
+
deferTx.resolve(x);
|
|
44
54
|
});
|
|
45
55
|
}
|
|
46
|
-
|
|
47
|
-
return this.client.rpc.author_submitExtrinsic(txHex);
|
|
48
|
-
}
|
|
56
|
+
return deferTx.promise;
|
|
49
57
|
}
|
|
50
58
|
}
|
|
51
59
|
exports.SubmittableExtrinsic = SubmittableExtrinsic;
|
|
@@ -5,6 +5,7 @@ const utils_1 = require("@dedot/utils");
|
|
|
5
5
|
const BaseSubmittableExtrinsic_js_1 = require("./BaseSubmittableExtrinsic.js");
|
|
6
6
|
const SubmittableResult_js_1 = require("./SubmittableResult.js");
|
|
7
7
|
const errors_js_1 = require("./errors.js");
|
|
8
|
+
const utils_js_1 = require("./utils.js");
|
|
8
9
|
/**
|
|
9
10
|
* @name SubmittableExtrinsicV2
|
|
10
11
|
* @description Submittable extrinsic based on JSON-RPC v2
|
|
@@ -176,31 +177,39 @@ class SubmittableExtrinsicV2 extends BaseSubmittableExtrinsic_js_1.BaseSubmittab
|
|
|
176
177
|
};
|
|
177
178
|
return txUnsub;
|
|
178
179
|
}
|
|
179
|
-
|
|
180
|
+
send(callback) {
|
|
180
181
|
const isSubscription = !!callback;
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
else if (status.type === 'Invalid' || status.type === 'Drop') {
|
|
194
|
-
defer.reject(new Error(status.value.error));
|
|
195
|
-
unsub().catch(utils_1.noop);
|
|
196
|
-
}
|
|
197
|
-
});
|
|
182
|
+
const { deferTx, onTxProgress } = (0, utils_js_1.txDefer)();
|
|
183
|
+
// TODO handle timeout for this with the Drop status,
|
|
184
|
+
// just in-case we somehow can't find the tx in any block
|
|
185
|
+
let unsub;
|
|
186
|
+
this.#send((result) => {
|
|
187
|
+
onTxProgress(result);
|
|
188
|
+
if (isSubscription) {
|
|
189
|
+
try {
|
|
190
|
+
callback?.(result);
|
|
191
|
+
}
|
|
192
|
+
catch { }
|
|
193
|
+
return;
|
|
198
194
|
}
|
|
199
|
-
|
|
200
|
-
|
|
195
|
+
const { status, txHash } = result;
|
|
196
|
+
if (status.type === 'BestChainBlockIncluded' ||
|
|
197
|
+
status.type === 'Finalized' ||
|
|
198
|
+
status.type === 'Invalid' ||
|
|
199
|
+
status.type === 'Drop') {
|
|
200
|
+
deferTx.resolve(txHash);
|
|
201
|
+
// Unsub the subscription if we're at the final states
|
|
202
|
+
if (status.type !== 'BestChainBlockIncluded') {
|
|
203
|
+
unsub?.().catch(utils_1.noop);
|
|
204
|
+
}
|
|
201
205
|
}
|
|
202
|
-
|
|
203
|
-
|
|
206
|
+
})
|
|
207
|
+
.then((x) => {
|
|
208
|
+
unsub = x;
|
|
209
|
+
isSubscription && deferTx.resolve(unsub);
|
|
210
|
+
})
|
|
211
|
+
.catch(deferTx.reject);
|
|
212
|
+
return deferTx.promise;
|
|
204
213
|
}
|
|
205
214
|
}
|
|
206
215
|
exports.SubmittableExtrinsicV2 = SubmittableExtrinsicV2;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.InvalidTxError = void 0;
|
|
3
|
+
exports.RejectedTxError = exports.InvalidTxError = void 0;
|
|
4
4
|
const utils_1 = require("@dedot/utils");
|
|
5
5
|
/**
|
|
6
6
|
* This throws out if the extrinsic is invalid
|
|
@@ -15,3 +15,12 @@ class InvalidTxError extends utils_1.DedotError {
|
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
exports.InvalidTxError = InvalidTxError;
|
|
18
|
+
class RejectedTxError extends utils_1.DedotError {
|
|
19
|
+
result;
|
|
20
|
+
name = 'RejectedTxError';
|
|
21
|
+
constructor(result) {
|
|
22
|
+
super();
|
|
23
|
+
this.result = result;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.RejectedTxError = RejectedTxError;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.toTxStatus = exports.signRaw = exports.isKeyringPair = void 0;
|
|
3
|
+
exports.txDefer = exports.toTxStatus = exports.signRaw = exports.isKeyringPair = void 0;
|
|
4
4
|
const utils_1 = require("@dedot/utils");
|
|
5
|
+
const errors_js_1 = require("./errors.js");
|
|
5
6
|
function isKeyringPair(account) {
|
|
6
7
|
return (0, utils_1.isFunction)(account.sign);
|
|
7
8
|
}
|
|
@@ -83,3 +84,40 @@ function toTxStatus(txStatus, txInfo) {
|
|
|
83
84
|
}
|
|
84
85
|
}
|
|
85
86
|
exports.toTxStatus = toTxStatus;
|
|
87
|
+
function txDefer() {
|
|
88
|
+
const deferTx = (0, utils_1.deferred)();
|
|
89
|
+
let deferFinalized;
|
|
90
|
+
let deferBestChainBlockIncluded;
|
|
91
|
+
Object.assign(deferTx.promise, {
|
|
92
|
+
untilFinalized: () => {
|
|
93
|
+
deferFinalized = (0, utils_1.deferred)();
|
|
94
|
+
return deferFinalized.promise;
|
|
95
|
+
},
|
|
96
|
+
untilBestChainBlockIncluded: () => {
|
|
97
|
+
deferBestChainBlockIncluded = (0, utils_1.deferred)();
|
|
98
|
+
return deferBestChainBlockIncluded.promise;
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
const onTxProgress = (result) => {
|
|
102
|
+
const { status } = result;
|
|
103
|
+
if (status.type === 'BestChainBlockIncluded') {
|
|
104
|
+
deferBestChainBlockIncluded?.resolve(result);
|
|
105
|
+
}
|
|
106
|
+
else if (status.type === 'Finalized') {
|
|
107
|
+
deferBestChainBlockIncluded?.resolve(result);
|
|
108
|
+
deferFinalized?.resolve(result);
|
|
109
|
+
}
|
|
110
|
+
else if (status.type === 'Invalid' || status.type === 'Drop') {
|
|
111
|
+
const e = new errors_js_1.RejectedTxError(result);
|
|
112
|
+
deferBestChainBlockIncluded?.reject(e);
|
|
113
|
+
deferFinalized?.reject(e);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
return {
|
|
117
|
+
deferTx,
|
|
118
|
+
deferFinalized: () => deferFinalized,
|
|
119
|
+
deferBestChainBlockIncluded: () => deferBestChainBlockIncluded,
|
|
120
|
+
onTxProgress,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
exports.txDefer = txDefer;
|
package/cjs/test.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const keyring_1 = __importDefault(require("@polkadot/keyring"));
|
|
7
|
+
const util_crypto_1 = require("@polkadot/util-crypto");
|
|
8
|
+
const providers_1 = require("@dedot/providers");
|
|
9
|
+
const index_js_1 = require("./client/index.js");
|
|
10
|
+
const run = async () => {
|
|
11
|
+
await (0, util_crypto_1.cryptoWaitReady)();
|
|
12
|
+
const alice = new keyring_1.default({ type: 'sr25519' }).addFromUri('//Alice');
|
|
13
|
+
const client = await index_js_1.LegacyClient.new(new providers_1.WsProvider('wss://westend-rpc.polkadot.io'));
|
|
14
|
+
// const client = await DedotClient.new(new WsProvider('wss://westend-rpc.polkadot.io'));
|
|
15
|
+
console.log('connected');
|
|
16
|
+
const result = await client.tx.system
|
|
17
|
+
.remarkWithEvent('Hello dedot') // prettier-end-here
|
|
18
|
+
.signAndSend(alice)
|
|
19
|
+
.untilFinalized();
|
|
20
|
+
// const tx = client.tx.system.remarkWithEvent('Hello dedot'); // prettier-end-here
|
|
21
|
+
//
|
|
22
|
+
// await tx.sign(alice);
|
|
23
|
+
//
|
|
24
|
+
// const result = await tx.send();
|
|
25
|
+
console.log('print result');
|
|
26
|
+
console.log(result);
|
|
27
|
+
await client.disconnect();
|
|
28
|
+
};
|
|
29
|
+
run().catch(console.error);
|
package/executor/Executor.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BlockHash, Extrinsic
|
|
2
|
-
import { AddressOrPair, Callback, IRuntimeTxCall, ISubmittableExtrinsic, ISubmittableResult, PayloadOptions, SignerOptions, TxPaymentInfo,
|
|
1
|
+
import { BlockHash, Extrinsic } from '@dedot/codecs';
|
|
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';
|
|
5
5
|
import type { ISubstrateClient } from '../../types.js';
|
|
@@ -9,11 +9,11 @@ export declare abstract class BaseSubmittableExtrinsic extends Extrinsic impleme
|
|
|
9
9
|
constructor(client: ISubstrateClient, call: IRuntimeTxCall);
|
|
10
10
|
paymentInfo(account: AddressOrPair, options?: Partial<PayloadOptions>): Promise<TxPaymentInfo>;
|
|
11
11
|
sign(fromAccount: AddressOrPair, options?: Partial<SignerOptions>): Promise<this>;
|
|
12
|
-
signAndSend(account: AddressOrPair, options?: Partial<SignerOptions>):
|
|
13
|
-
signAndSend(account: AddressOrPair, callback: Callback<ISubmittableResult>):
|
|
14
|
-
signAndSend(account: AddressOrPair, options: Partial<SignerOptions>, callback?: Callback<ISubmittableResult>):
|
|
15
|
-
send():
|
|
16
|
-
send(callback: Callback):
|
|
12
|
+
signAndSend(account: AddressOrPair, options?: Partial<SignerOptions>): TxHash;
|
|
13
|
+
signAndSend(account: AddressOrPair, callback: Callback<ISubmittableResult>): TxUnsub;
|
|
14
|
+
signAndSend(account: AddressOrPair, options: Partial<SignerOptions>, callback?: Callback<ISubmittableResult>): TxUnsub;
|
|
15
|
+
send(): TxHash;
|
|
16
|
+
send(callback: Callback): TxUnsub;
|
|
17
17
|
protected getSystemEventsAt(hash: BlockHash): Promise<FrameSystemEventRecord[]>;
|
|
18
18
|
toHex(): HexString;
|
|
19
19
|
}
|
|
@@ -2,7 +2,7 @@ import { Extrinsic } from '@dedot/codecs';
|
|
|
2
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
|
-
import { isKeyringPair, signRaw } from './utils.js';
|
|
5
|
+
import { isKeyringPair, signRaw, txDefer } from './utils.js';
|
|
6
6
|
export class BaseSubmittableExtrinsic extends Extrinsic {
|
|
7
7
|
client;
|
|
8
8
|
#alterTx;
|
|
@@ -52,10 +52,35 @@ export class BaseSubmittableExtrinsic extends Extrinsic {
|
|
|
52
52
|
}
|
|
53
53
|
return this;
|
|
54
54
|
}
|
|
55
|
-
|
|
55
|
+
signAndSend(fromAccount, partialOptions, maybeCallback) {
|
|
56
56
|
const [options, callback] = this.#normalizeOptions(partialOptions, maybeCallback);
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
const { deferTx, deferFinalized, deferBestChainBlockIncluded, onTxProgress } = txDefer();
|
|
58
|
+
this.sign(fromAccount, options)
|
|
59
|
+
.then(() => {
|
|
60
|
+
const deferSend = this.send(callback);
|
|
61
|
+
deferSend
|
|
62
|
+
.then(deferTx.resolve) // --
|
|
63
|
+
.catch(deferTx.reject);
|
|
64
|
+
deferSend
|
|
65
|
+
.untilBestChainBlockIncluded() //--
|
|
66
|
+
.then((r) => {
|
|
67
|
+
onTxProgress(r);
|
|
68
|
+
})
|
|
69
|
+
.catch((e) => {
|
|
70
|
+
deferBestChainBlockIncluded()?.reject(e);
|
|
71
|
+
});
|
|
72
|
+
deferSend
|
|
73
|
+
.untilFinalized() //--
|
|
74
|
+
.then((r) => {
|
|
75
|
+
onTxProgress(r);
|
|
76
|
+
})
|
|
77
|
+
.catch((e) => {
|
|
78
|
+
deferBestChainBlockIncluded()?.reject(e);
|
|
79
|
+
deferFinalized()?.reject(e);
|
|
80
|
+
});
|
|
81
|
+
})
|
|
82
|
+
.catch(deferTx.reject);
|
|
83
|
+
return deferTx.promise;
|
|
59
84
|
}
|
|
60
85
|
#normalizeOptions(partialOptions, callback) {
|
|
61
86
|
if (isFunction(partialOptions)) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BlockHash
|
|
2
|
-
import { AddressOrPair, Callback, DryRunResult, ISubmittableExtrinsicLegacy, ISubmittableResult, SignerOptions,
|
|
1
|
+
import { BlockHash } from '@dedot/codecs';
|
|
2
|
+
import { AddressOrPair, Callback, DryRunResult, ISubmittableExtrinsicLegacy, ISubmittableResult, SignerOptions, TxHash, TxUnsub } from '@dedot/types';
|
|
3
3
|
import { BaseSubmittableExtrinsic } from './BaseSubmittableExtrinsic.js';
|
|
4
4
|
/**
|
|
5
5
|
* @name SubmittableExtrinsic
|
|
@@ -7,6 +7,6 @@ import { BaseSubmittableExtrinsic } from './BaseSubmittableExtrinsic.js';
|
|
|
7
7
|
*/
|
|
8
8
|
export declare class SubmittableExtrinsic extends BaseSubmittableExtrinsic implements ISubmittableExtrinsicLegacy {
|
|
9
9
|
dryRun(account: AddressOrPair, optionsOrHash?: Partial<SignerOptions> | BlockHash): Promise<DryRunResult>;
|
|
10
|
-
send():
|
|
11
|
-
send(callback: Callback<ISubmittableResult>):
|
|
10
|
+
send(): TxHash;
|
|
11
|
+
send(callback: Callback<ISubmittableResult>): TxUnsub;
|
|
12
12
|
}
|
|
@@ -1,7 +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
|
+
import { toTxStatus, txDefer } from './utils.js';
|
|
5
5
|
/**
|
|
6
6
|
* @name SubmittableExtrinsic
|
|
7
7
|
* @description A wrapper around an Extrinsic that exposes methods to sign, send, and other utility around Extrinsic.
|
|
@@ -15,33 +15,41 @@ export class SubmittableExtrinsic extends BaseSubmittableExtrinsic {
|
|
|
15
15
|
await this.sign(account, optionsOrHash);
|
|
16
16
|
return dryRunFn(this.toHex());
|
|
17
17
|
}
|
|
18
|
-
|
|
18
|
+
send(callback) {
|
|
19
19
|
const isSubscription = !!callback;
|
|
20
20
|
const txHex = this.toHex();
|
|
21
21
|
const txHash = this.hash;
|
|
22
|
+
const { deferTx, onTxProgress } = txDefer();
|
|
23
|
+
const unsub = this.client.rpc.author_submitAndWatchExtrinsic(txHex, async (txStatus) => {
|
|
24
|
+
if (txStatus.type === 'InBlock' || txStatus.type === 'Finalized') {
|
|
25
|
+
const blockHash = txStatus.value;
|
|
26
|
+
const [signedBlock, blockEvents] = await Promise.all([
|
|
27
|
+
this.client.rpc.chain_getBlock(blockHash),
|
|
28
|
+
this.getSystemEventsAt(blockHash),
|
|
29
|
+
]);
|
|
30
|
+
const txIndex = signedBlock.block.extrinsics.indexOf(txHex);
|
|
31
|
+
assert(txIndex >= 0, 'Extrinsic not found!');
|
|
32
|
+
const events = blockEvents.filter(({ phase }) => phase.type === 'ApplyExtrinsic' && phase.value === txIndex);
|
|
33
|
+
const blockNumber = signedBlock.block.header.number;
|
|
34
|
+
const status = toTxStatus(txStatus, { txIndex, blockNumber });
|
|
35
|
+
const result = new SubmittableResult({ status, txHash, events, txIndex });
|
|
36
|
+
onTxProgress(result);
|
|
37
|
+
!isSubscription && deferTx.resolve(txHash);
|
|
38
|
+
return callback?.(result);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
const status = toTxStatus(txStatus);
|
|
42
|
+
const result = new SubmittableResult({ status, txHash });
|
|
43
|
+
onTxProgress(result);
|
|
44
|
+
!isSubscription && deferTx.resolve(txHash);
|
|
45
|
+
return callback?.(new SubmittableResult({ status, txHash }));
|
|
46
|
+
}
|
|
47
|
+
});
|
|
22
48
|
if (isSubscription) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const blockHash = txStatus.value;
|
|
26
|
-
const [signedBlock, blockEvents] = await Promise.all([
|
|
27
|
-
this.client.rpc.chain_getBlock(blockHash),
|
|
28
|
-
this.getSystemEventsAt(blockHash),
|
|
29
|
-
]);
|
|
30
|
-
const txIndex = signedBlock.block.extrinsics.indexOf(txHex);
|
|
31
|
-
assert(txIndex >= 0, 'Extrinsic not found!');
|
|
32
|
-
const events = blockEvents.filter(({ phase }) => phase.type === 'ApplyExtrinsic' && phase.value === txIndex);
|
|
33
|
-
const blockNumber = signedBlock.block.header.number;
|
|
34
|
-
const status = toTxStatus(txStatus, { txIndex, blockNumber });
|
|
35
|
-
return callback(new SubmittableResult({ status, txHash, events, txIndex }));
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
const status = toTxStatus(txStatus);
|
|
39
|
-
return callback(new SubmittableResult({ status, txHash }));
|
|
40
|
-
}
|
|
49
|
+
unsub.then((x) => {
|
|
50
|
+
deferTx.resolve(x);
|
|
41
51
|
});
|
|
42
52
|
}
|
|
43
|
-
|
|
44
|
-
return this.client.rpc.author_submitExtrinsic(txHex);
|
|
45
|
-
}
|
|
53
|
+
return deferTx.promise;
|
|
46
54
|
}
|
|
47
55
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import type { Callback, IRuntimeTxCall, Unsub } from '@dedot/types';
|
|
1
|
+
import { Callback, IRuntimeTxCall, TxHash, TxUnsub } from '@dedot/types';
|
|
3
2
|
import { DedotClient } from '../../client/index.js';
|
|
4
3
|
import { BaseSubmittableExtrinsic } from './BaseSubmittableExtrinsic.js';
|
|
5
4
|
/**
|
|
@@ -10,6 +9,6 @@ export declare class SubmittableExtrinsicV2 extends BaseSubmittableExtrinsic {
|
|
|
10
9
|
#private;
|
|
11
10
|
client: DedotClient;
|
|
12
11
|
constructor(client: DedotClient, call: IRuntimeTxCall);
|
|
13
|
-
send():
|
|
14
|
-
send(callback: Callback):
|
|
12
|
+
send(): TxHash;
|
|
13
|
+
send(callback: Callback): TxUnsub;
|
|
15
14
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { AsyncQueue,
|
|
1
|
+
import { AsyncQueue, noop } from '@dedot/utils';
|
|
2
2
|
import { BaseSubmittableExtrinsic } from './BaseSubmittableExtrinsic.js';
|
|
3
3
|
import { SubmittableResult } from './SubmittableResult.js';
|
|
4
4
|
import { InvalidTxError } from './errors.js';
|
|
5
|
+
import { txDefer } from './utils.js';
|
|
5
6
|
/**
|
|
6
7
|
* @name SubmittableExtrinsicV2
|
|
7
8
|
* @description Submittable extrinsic based on JSON-RPC v2
|
|
@@ -173,30 +174,38 @@ export class SubmittableExtrinsicV2 extends BaseSubmittableExtrinsic {
|
|
|
173
174
|
};
|
|
174
175
|
return txUnsub;
|
|
175
176
|
}
|
|
176
|
-
|
|
177
|
+
send(callback) {
|
|
177
178
|
const isSubscription = !!callback;
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
else if (status.type === 'Invalid' || status.type === 'Drop') {
|
|
191
|
-
defer.reject(new Error(status.value.error));
|
|
192
|
-
unsub().catch(noop);
|
|
193
|
-
}
|
|
194
|
-
});
|
|
179
|
+
const { deferTx, onTxProgress } = txDefer();
|
|
180
|
+
// TODO handle timeout for this with the Drop status,
|
|
181
|
+
// just in-case we somehow can't find the tx in any block
|
|
182
|
+
let unsub;
|
|
183
|
+
this.#send((result) => {
|
|
184
|
+
onTxProgress(result);
|
|
185
|
+
if (isSubscription) {
|
|
186
|
+
try {
|
|
187
|
+
callback?.(result);
|
|
188
|
+
}
|
|
189
|
+
catch { }
|
|
190
|
+
return;
|
|
195
191
|
}
|
|
196
|
-
|
|
197
|
-
|
|
192
|
+
const { status, txHash } = result;
|
|
193
|
+
if (status.type === 'BestChainBlockIncluded' ||
|
|
194
|
+
status.type === 'Finalized' ||
|
|
195
|
+
status.type === 'Invalid' ||
|
|
196
|
+
status.type === 'Drop') {
|
|
197
|
+
deferTx.resolve(txHash);
|
|
198
|
+
// Unsub the subscription if we're at the final states
|
|
199
|
+
if (status.type !== 'BestChainBlockIncluded') {
|
|
200
|
+
unsub?.().catch(noop);
|
|
201
|
+
}
|
|
198
202
|
}
|
|
199
|
-
|
|
200
|
-
|
|
203
|
+
})
|
|
204
|
+
.then((x) => {
|
|
205
|
+
unsub = x;
|
|
206
|
+
isSubscription && deferTx.resolve(unsub);
|
|
207
|
+
})
|
|
208
|
+
.catch(deferTx.reject);
|
|
209
|
+
return deferTx.promise;
|
|
201
210
|
}
|
|
202
211
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Result } from '@dedot/codecs';
|
|
2
|
+
import { ISubmittableResult } from '@dedot/types';
|
|
2
3
|
import { DedotError } from '@dedot/utils';
|
|
3
4
|
import type { SpRuntimeTransactionValidityTransactionValidityError, SpRuntimeTransactionValidityValidTransaction } from '../../chaintypes/index.js';
|
|
4
5
|
/**
|
|
@@ -10,3 +11,8 @@ export declare class InvalidTxError extends DedotError {
|
|
|
10
11
|
name: string;
|
|
11
12
|
constructor(message: string, data: Result<SpRuntimeTransactionValidityValidTransaction, SpRuntimeTransactionValidityTransactionValidityError>);
|
|
12
13
|
}
|
|
14
|
+
export declare class RejectedTxError extends DedotError {
|
|
15
|
+
result: ISubmittableResult;
|
|
16
|
+
name: string;
|
|
17
|
+
constructor(result: ISubmittableResult);
|
|
18
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { TransactionStatus } from '@dedot/codecs';
|
|
2
|
-
import
|
|
3
|
-
import { HexString } from '@dedot/utils';
|
|
2
|
+
import { AddressOrPair, IKeyringPair, ISubmittableResult, TxStatus, Unsub } from '@dedot/types';
|
|
3
|
+
import { Deferred, HexString } from '@dedot/utils';
|
|
4
4
|
export declare function isKeyringPair(account: AddressOrPair): account is IKeyringPair;
|
|
5
5
|
/**
|
|
6
6
|
* Sign a raw message
|
|
@@ -20,4 +20,10 @@ type TxInfo = {
|
|
|
20
20
|
* @param txInfo
|
|
21
21
|
*/
|
|
22
22
|
export declare function toTxStatus(txStatus: TransactionStatus, txInfo?: TxInfo): TxStatus;
|
|
23
|
+
export declare function txDefer(): {
|
|
24
|
+
deferTx: Deferred<`0x${string}` | Unsub>;
|
|
25
|
+
deferFinalized: () => Deferred<ISubmittableResult<import("@dedot/types").IEventRecord<import("@dedot/types").IRuntimeEvent, `0x${string}`>>> | undefined;
|
|
26
|
+
deferBestChainBlockIncluded: () => Deferred<ISubmittableResult<import("@dedot/types").IEventRecord<import("@dedot/types").IRuntimeEvent, `0x${string}`>>> | undefined;
|
|
27
|
+
onTxProgress: (result: ISubmittableResult) => void;
|
|
28
|
+
};
|
|
23
29
|
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { assert, blake2AsU8a, hexToU8a, isFunction } from '@dedot/utils';
|
|
1
|
+
import { assert, blake2AsU8a, deferred, hexToU8a, isFunction } from '@dedot/utils';
|
|
2
|
+
import { RejectedTxError } from './errors.js';
|
|
2
3
|
export function isKeyringPair(account) {
|
|
3
4
|
return isFunction(account.sign);
|
|
4
5
|
}
|
|
@@ -77,3 +78,39 @@ export function toTxStatus(txStatus, txInfo) {
|
|
|
77
78
|
};
|
|
78
79
|
}
|
|
79
80
|
}
|
|
81
|
+
export function txDefer() {
|
|
82
|
+
const deferTx = deferred();
|
|
83
|
+
let deferFinalized;
|
|
84
|
+
let deferBestChainBlockIncluded;
|
|
85
|
+
Object.assign(deferTx.promise, {
|
|
86
|
+
untilFinalized: () => {
|
|
87
|
+
deferFinalized = deferred();
|
|
88
|
+
return deferFinalized.promise;
|
|
89
|
+
},
|
|
90
|
+
untilBestChainBlockIncluded: () => {
|
|
91
|
+
deferBestChainBlockIncluded = deferred();
|
|
92
|
+
return deferBestChainBlockIncluded.promise;
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
const onTxProgress = (result) => {
|
|
96
|
+
const { status } = result;
|
|
97
|
+
if (status.type === 'BestChainBlockIncluded') {
|
|
98
|
+
deferBestChainBlockIncluded?.resolve(result);
|
|
99
|
+
}
|
|
100
|
+
else if (status.type === 'Finalized') {
|
|
101
|
+
deferBestChainBlockIncluded?.resolve(result);
|
|
102
|
+
deferFinalized?.resolve(result);
|
|
103
|
+
}
|
|
104
|
+
else if (status.type === 'Invalid' || status.type === 'Drop') {
|
|
105
|
+
const e = new RejectedTxError(result);
|
|
106
|
+
deferBestChainBlockIncluded?.reject(e);
|
|
107
|
+
deferFinalized?.reject(e);
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
return {
|
|
111
|
+
deferTx,
|
|
112
|
+
deferFinalized: () => deferFinalized,
|
|
113
|
+
deferBestChainBlockIncluded: () => deferBestChainBlockIncluded,
|
|
114
|
+
onTxProgress,
|
|
115
|
+
};
|
|
116
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dedot/api",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.1-next.b29d4eee.6+b29d4eee",
|
|
4
4
|
"description": "A delightful JavaScript/TypeScript client for Polkadot & Substrate",
|
|
5
5
|
"author": "Thang X. Vu <thang@dedot.dev>",
|
|
6
6
|
"homepage": "https://dedot.dev",
|
|
@@ -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.10.1-next.b29d4eee.6+b29d4eee",
|
|
17
|
+
"@dedot/providers": "0.10.1-next.b29d4eee.6+b29d4eee",
|
|
18
|
+
"@dedot/runtime-specs": "0.10.1-next.b29d4eee.6+b29d4eee",
|
|
19
|
+
"@dedot/shape": "0.10.1-next.b29d4eee.6+b29d4eee",
|
|
20
|
+
"@dedot/storage": "0.10.1-next.b29d4eee.6+b29d4eee",
|
|
21
|
+
"@dedot/types": "0.10.1-next.b29d4eee.6+b29d4eee",
|
|
22
|
+
"@dedot/utils": "0.10.1-next.b29d4eee.6+b29d4eee"
|
|
23
23
|
},
|
|
24
24
|
"scripts": {
|
|
25
25
|
"build": "tsc --project tsconfig.build.json && tsc --project tsconfig.build.cjs.json",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"node": ">=18"
|
|
49
49
|
},
|
|
50
50
|
"license": "Apache-2.0",
|
|
51
|
-
"gitHead": "
|
|
51
|
+
"gitHead": "b29d4eee0d9f5481bf90dc872dae50a72ad693af",
|
|
52
52
|
"module": "./index.js",
|
|
53
53
|
"types": "./index.d.ts"
|
|
54
54
|
}
|
package/test.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/test.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import Keyring from '@polkadot/keyring';
|
|
2
|
+
import { cryptoWaitReady } from '@polkadot/util-crypto';
|
|
3
|
+
import { WsProvider } from '@dedot/providers';
|
|
4
|
+
import { LegacyClient } from './client/index.js';
|
|
5
|
+
const run = async () => {
|
|
6
|
+
await cryptoWaitReady();
|
|
7
|
+
const alice = new Keyring({ type: 'sr25519' }).addFromUri('//Alice');
|
|
8
|
+
const client = await LegacyClient.new(new WsProvider('wss://westend-rpc.polkadot.io'));
|
|
9
|
+
// const client = await DedotClient.new(new WsProvider('wss://westend-rpc.polkadot.io'));
|
|
10
|
+
console.log('connected');
|
|
11
|
+
const result = await client.tx.system
|
|
12
|
+
.remarkWithEvent('Hello dedot') // prettier-end-here
|
|
13
|
+
.signAndSend(alice)
|
|
14
|
+
.untilFinalized();
|
|
15
|
+
// const tx = client.tx.system.remarkWithEvent('Hello dedot'); // prettier-end-here
|
|
16
|
+
//
|
|
17
|
+
// await tx.sign(alice);
|
|
18
|
+
//
|
|
19
|
+
// const result = await tx.send();
|
|
20
|
+
console.log('print result');
|
|
21
|
+
console.log(result);
|
|
22
|
+
await client.disconnect();
|
|
23
|
+
};
|
|
24
|
+
run().catch(console.error);
|