@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.
@@ -55,10 +55,35 @@ class BaseSubmittableExtrinsic extends codecs_1.Extrinsic {
55
55
  }
56
56
  return this;
57
57
  }
58
- async signAndSend(fromAccount, partialOptions, maybeCallback) {
58
+ signAndSend(fromAccount, partialOptions, maybeCallback) {
59
59
  const [options, callback] = this.#normalizeOptions(partialOptions, maybeCallback);
60
- await this.sign(fromAccount, options);
61
- return this.send(callback);
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
- async send(callback) {
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
- return 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
- 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
- else {
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
- async send(callback) {
180
+ send(callback) {
180
181
  const isSubscription = !!callback;
181
- if (isSubscription) {
182
- return this.#send(callback);
183
- }
184
- else {
185
- const defer = (0, utils_1.deferred)();
186
- try {
187
- // TODO handle timeout for this with the Drop status, just in-case we somehow can't find the tx in any block
188
- const unsub = await this.#send(({ status, txHash }) => {
189
- if (status.type === 'BestChainBlockIncluded' || status.type === 'Finalized') {
190
- defer.resolve(txHash);
191
- unsub().catch(utils_1.noop);
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
- catch (e) {
200
- defer.reject(e);
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
- return defer.promise;
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);
@@ -63,8 +63,8 @@ export declare abstract class Executor<ChainApi extends GenericSubstrateApi = Ge
63
63
  } | {
64
64
  type: "BitSequence";
65
65
  value: {
66
- bitOrderType: number;
67
66
  bitStoreType: number;
67
+ bitOrderType: number;
68
68
  };
69
69
  };
70
70
  docs: string[];
@@ -1,5 +1,5 @@
1
- import { BlockHash, Extrinsic, Hash } from '@dedot/codecs';
2
- import { AddressOrPair, Callback, IRuntimeTxCall, ISubmittableExtrinsic, ISubmittableResult, PayloadOptions, SignerOptions, TxPaymentInfo, Unsub } from '@dedot/types';
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>): Promise<Hash>;
13
- signAndSend(account: AddressOrPair, callback: Callback<ISubmittableResult>): Promise<Unsub>;
14
- signAndSend(account: AddressOrPair, options: Partial<SignerOptions>, callback?: Callback<ISubmittableResult>): Promise<Unsub>;
15
- send(): Promise<Hash>;
16
- send(callback: Callback): Promise<Unsub>;
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
- async signAndSend(fromAccount, partialOptions, maybeCallback) {
55
+ signAndSend(fromAccount, partialOptions, maybeCallback) {
56
56
  const [options, callback] = this.#normalizeOptions(partialOptions, maybeCallback);
57
- await this.sign(fromAccount, options);
58
- return this.send(callback);
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, Hash } from '@dedot/codecs';
2
- import { AddressOrPair, Callback, DryRunResult, ISubmittableExtrinsicLegacy, ISubmittableResult, SignerOptions, Unsub } from '@dedot/types';
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(): Promise<Hash>;
11
- send(callback: Callback<ISubmittableResult>): Promise<Unsub>;
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
- async send(callback) {
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
- return 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
- 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
- else {
44
- return this.client.rpc.author_submitExtrinsic(txHex);
45
- }
53
+ return deferTx.promise;
46
54
  }
47
55
  }
@@ -1,5 +1,4 @@
1
- import type { Hash } from '@dedot/codecs';
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(): Promise<Hash>;
14
- send(callback: Callback): Promise<Unsub>;
12
+ send(): TxHash;
13
+ send(callback: Callback): TxUnsub;
15
14
  }
@@ -1,7 +1,8 @@
1
- import { AsyncQueue, deferred, noop } from '@dedot/utils';
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
- async send(callback) {
177
+ send(callback) {
177
178
  const isSubscription = !!callback;
178
- if (isSubscription) {
179
- return this.#send(callback);
180
- }
181
- else {
182
- const defer = deferred();
183
- try {
184
- // TODO handle timeout for this with the Drop status, just in-case we somehow can't find the tx in any block
185
- const unsub = await this.#send(({ status, txHash }) => {
186
- if (status.type === 'BestChainBlockIncluded' || status.type === 'Finalized') {
187
- defer.resolve(txHash);
188
- unsub().catch(noop);
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
- catch (e) {
197
- defer.reject(e);
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
- return defer.promise;
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
+ }
@@ -11,3 +11,11 @@ export class InvalidTxError extends DedotError {
11
11
  this.data = data;
12
12
  }
13
13
  }
14
+ export class RejectedTxError extends DedotError {
15
+ result;
16
+ name = 'RejectedTxError';
17
+ constructor(result) {
18
+ super();
19
+ this.result = result;
20
+ }
21
+ }
@@ -1,6 +1,6 @@
1
1
  import { TransactionStatus } from '@dedot/codecs';
2
- import type { AddressOrPair, IKeyringPair, TxStatus } from '@dedot/types';
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.9.6",
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.9.6",
17
- "@dedot/providers": "0.9.6",
18
- "@dedot/runtime-specs": "0.9.6",
19
- "@dedot/shape": "0.9.6",
20
- "@dedot/storage": "0.9.6",
21
- "@dedot/types": "0.9.6",
22
- "@dedot/utils": "0.9.6"
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": "5a205138e7221a742a863b854a8a03f298c19253",
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);