@dedot/api 1.0.4 → 1.2.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.
@@ -410,6 +410,9 @@ class BaseSubstrateClient extends index_js_2.JsonRpcClient {
410
410
  sendTx(tx, callback) {
411
411
  throw new Error('Unimplemented!');
412
412
  }
413
+ toTx(tx) {
414
+ throw new Error('Unimplemented!');
415
+ }
413
416
  get chainSpec() {
414
417
  throw new Error('Unimplemented!');
415
418
  }
@@ -394,6 +394,33 @@ class DedotClient {
394
394
  sendTx(tx, callback) {
395
395
  return this.#client.sendTx(tx, callback);
396
396
  }
397
+ /**
398
+ * Convert a transaction input into a submittable extrinsic
399
+ * with `sign`, `signAndSend`, `send`, and `paymentInfo` methods.
400
+ *
401
+ * @param tx - A hex-encoded extrinsic or runtime call, a Uint8Array of encoded bytes,
402
+ * an Extrinsic instance, or an IRuntimeTxCall object.
403
+ * For HexString/Uint8Array, it first tries to decode as a full extrinsic;
404
+ * if that fails, it falls back to decoding as a raw runtime call.
405
+ * @returns A submittable extrinsic instance
406
+ *
407
+ * @example
408
+ * ```typescript
409
+ * // From a raw hex extrinsic
410
+ * const submittable = client.toTx(rawTxHex);
411
+ *
412
+ * // From a runtime call object
413
+ * const submittable = client.toTx({ pallet: 'Balances', palletCall: { name: 'TransferKeepAlive', params: { dest, value } } });
414
+ *
415
+ * // Sign and send
416
+ * const unsub = await submittable.signAndSend(alice, (result) => {
417
+ * console.log('Status:', result.status);
418
+ * });
419
+ * ```
420
+ */
421
+ toTx(tx) {
422
+ return this.#client.toTx(tx);
423
+ }
397
424
  /**
398
425
  * Clear internal caches.
399
426
  *
@@ -360,5 +360,8 @@ class LegacyClient// prettier-end-here
360
360
  callback && callback(result);
361
361
  });
362
362
  }
363
+ toTx(tx) {
364
+ return SubmittableExtrinsic_js_1.SubmittableExtrinsic.fromTx(this, tx);
365
+ }
363
366
  }
364
367
  exports.LegacyClient = LegacyClient;
@@ -312,5 +312,8 @@ class V2Client// prettier-end-here
312
312
  callback && callback(result);
313
313
  });
314
314
  }
315
+ toTx(tx) {
316
+ return SubmittableExtrinsicV2_js_1.SubmittableExtrinsicV2.fromTx(this, tx);
317
+ }
315
318
  }
316
319
  exports.V2Client = V2Client;
@@ -13,9 +13,17 @@ exports.MORTAL_PERIOD = 12 * 60 * 1000;
13
13
  class CheckMortality extends SignedExtension_js_1.SignedExtension {
14
14
  #signingHeader;
15
15
  async init() {
16
- this.#signingHeader = await this.#getSigningHeader();
17
- this.data = { period: this.#calculateMortalLength(), current: BigInt(this.#signingHeader.number) };
18
- this.additionalSigned = this.#signingHeader.hash;
16
+ const mortality = this.payloadOptions.mortality;
17
+ if (mortality?.type === 'Immortal') {
18
+ this.data = { type: 'Immortal' };
19
+ this.additionalSigned = this.client.genesisHash;
20
+ }
21
+ else {
22
+ this.#signingHeader = await this.#getSigningHeader();
23
+ const period = mortality?.type === 'Mortal' ? BigInt(mortality.period) : this.#calculateMortalLength();
24
+ this.data = { period, current: BigInt(this.#signingHeader.number) };
25
+ this.additionalSigned = this.#signingHeader.hash;
26
+ }
19
27
  }
20
28
  async fromPayload(payload) {
21
29
  const { era, blockHash, blockNumber } = payload;
@@ -88,7 +96,7 @@ class CheckMortality extends SignedExtension_js_1.SignedExtension {
88
96
  return {
89
97
  era: (0, utils_1.u8aToHex)(this.$Data.tryEncode(this.data)),
90
98
  blockHash: this.additionalSigned,
91
- blockNumber: (0, utils_1.numberToHex)(this.#signingHeader.number),
99
+ blockNumber: (0, utils_1.numberToHex)(this.#signingHeader?.number ?? 0),
92
100
  };
93
101
  }
94
102
  }
@@ -50,7 +50,9 @@ class BaseSubmittableExtrinsic extends codecs_1.Extrinsic {
50
50
  return result;
51
51
  }
52
52
  async paymentInfo(account, options) {
53
- await this.sign(account, { ...options, signer: fakeSigner_js_1.fakeSigner });
53
+ if (!this.signed) {
54
+ await this.sign(account, { ...options, signer: fakeSigner_js_1.fakeSigner });
55
+ }
54
56
  const txU8a = this.toU8a();
55
57
  const api = this.client;
56
58
  return api.call.transactionPaymentApi.queryInfo(txU8a, txU8a.length);
@@ -11,14 +11,8 @@ const utils_js_1 = require("./utils.js");
11
11
  */
12
12
  class SubmittableExtrinsic extends BaseSubmittableExtrinsic_js_1.BaseSubmittableExtrinsic {
13
13
  static fromTx(client, tx) {
14
- let extrinsic;
15
- if ((0, utils_1.isHex)(tx)) {
16
- extrinsic = client.registry.$Extrinsic.tryDecode(tx);
17
- }
18
- else {
19
- extrinsic = tx;
20
- }
21
- return new SubmittableExtrinsic(client, extrinsic.call, extrinsic.preamble);
14
+ const { call, preamble } = (0, utils_js_1.resolveCallAndPreamble)(client.registry, tx);
15
+ return new SubmittableExtrinsic(client, call, preamble);
22
16
  }
23
17
  async dryRun(account, optionsOrHash) {
24
18
  const dryRunFn = this.client.rpc.system_dryRun;
@@ -17,14 +17,8 @@ class SubmittableExtrinsicV2 extends BaseSubmittableExtrinsic_js_1.BaseSubmittab
17
17
  this.client = client;
18
18
  }
19
19
  static fromTx(client, tx) {
20
- let extrinsic;
21
- if ((0, utils_1.isHex)(tx)) {
22
- extrinsic = client.registry.$Extrinsic.tryDecode(tx);
23
- }
24
- else {
25
- extrinsic = tx;
26
- }
27
- return new SubmittableExtrinsicV2(client, extrinsic.call, extrinsic.preamble);
20
+ const { call, preamble } = (0, utils_js_1.resolveCallAndPreamble)(client.registry, tx);
21
+ return new SubmittableExtrinsicV2(client, call, preamble);
28
22
  }
29
23
  async #send(callback) {
30
24
  const api = this.client;
@@ -1,8 +1,43 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.txDefer = exports.toTxStatus = exports.signRawMessage = exports.isKeyringPair = void 0;
3
+ exports.txDefer = exports.toTxStatus = exports.signRawMessage = exports.isKeyringPair = exports.resolveCallAndPreamble = void 0;
4
+ const codecs_1 = require("@dedot/codecs");
4
5
  const utils_1 = require("@dedot/utils");
5
6
  const errors_js_1 = require("./errors.js");
7
+ /**
8
+ * Check if a value is an IRuntimeTxCall object (has a 'pallet' property).
9
+ */
10
+ function isRuntimeTxCall(tx) {
11
+ return typeof tx === 'object' && tx !== null && 'pallet' in tx;
12
+ }
13
+ /**
14
+ * Resolve a transaction input into a call and optional preamble.
15
+ *
16
+ * Supports:
17
+ * - `Extrinsic` instance: extract call + preamble
18
+ * - `IRuntimeTxCall` object: use directly as call, no preamble
19
+ * - `HexString` or `Uint8Array`: try decode as extrinsic first, fallback to runtime call
20
+ */
21
+ function resolveCallAndPreamble(registry, tx) {
22
+ if (tx instanceof codecs_1.Extrinsic) {
23
+ return { call: tx.call, preamble: tx.preamble };
24
+ }
25
+ if (isRuntimeTxCall(tx)) {
26
+ return { call: tx };
27
+ }
28
+ // HexString or Uint8Array: try extrinsic decode first, fallback to runtime call
29
+ try {
30
+ const extrinsic = registry.$Extrinsic.tryDecode(tx);
31
+ return { call: extrinsic.call, preamble: extrinsic.preamble };
32
+ }
33
+ catch {
34
+ const { callTypeId } = registry.metadata.extrinsic;
35
+ const $RuntimeCall = registry.findCodec(callTypeId);
36
+ const call = $RuntimeCall.tryDecode(tx);
37
+ return { call };
38
+ }
39
+ }
40
+ exports.resolveCallAndPreamble = resolveCallAndPreamble;
6
41
  function isKeyringPair(account) {
7
42
  return (0, utils_1.isFunction)(account.sign);
8
43
  }
@@ -1,7 +1,7 @@
1
1
  import { BlockHash, Extrinsic, Hash, Metadata, PortableRegistry, RuntimeVersion } from '@dedot/codecs';
2
2
  import { type JsonRpcProvider } from '@dedot/providers';
3
3
  import { type IStorage } from '@dedot/storage';
4
- import { Callback, GenericStorageQuery, GenericSubstrateApi, InjectedSigner, ISubmittableResult, Query, QueryFnResult, RpcVersion, TxUnsub, Unsub } from '@dedot/types';
4
+ import { Callback, ChainSubmittableExtrinsic, GenericStorageQuery, GenericSubstrateApi, InjectedSigner, IRuntimeTxCall, ISubmittableResult, Query, QueryFnResult, RpcVersion, TxUnsub, Unsub } from '@dedot/types';
5
5
  import { Deferred, HexString, LRUCache } from '@dedot/utils';
6
6
  import type { SubstrateApi } from '../chaintypes/index.js';
7
7
  import { JsonRpcClient } from '../json-rpc/index.js';
@@ -133,6 +133,7 @@ export declare abstract class BaseSubstrateClient<ChainApi extends GenericSubstr
133
133
  }>): Promise<Unsub>;
134
134
  protected getStorageQuery(): BaseStorageQuery;
135
135
  sendTx(tx: HexString | Extrinsic, callback?: Callback<ISubmittableResult<ChainApi['types']['EventRecord']>>): TxUnsub;
136
+ toTx(tx: HexString | Uint8Array | Extrinsic | IRuntimeTxCall): ChainSubmittableExtrinsic<ChainApi>;
136
137
  get chainSpec(): IChainSpec;
137
138
  on<Event extends Events = Events>(event: Event, handler: EventHandlerFn<Event>): () => void;
138
139
  }
@@ -406,6 +406,9 @@ export class BaseSubstrateClient extends JsonRpcClient {
406
406
  sendTx(tx, callback) {
407
407
  throw new Error('Unimplemented!');
408
408
  }
409
+ toTx(tx) {
410
+ throw new Error('Unimplemented!');
411
+ }
409
412
  get chainSpec() {
410
413
  throw new Error('Unimplemented!');
411
414
  }
@@ -1,6 +1,6 @@
1
1
  import { type Extrinsic, Metadata, PortableRegistry } from '@dedot/codecs';
2
2
  import { ConnectionStatus, JsonRpcProvider } from '@dedot/providers';
3
- import { Callback, GenericStorageQuery, GenericSubstrateApi, InjectedSigner, ISubmittableResult, Query, QueryFnResult, RpcVersion, TxUnsub, Unsub } from '@dedot/types';
3
+ import { Callback, ChainSubmittableExtrinsic, GenericStorageQuery, GenericSubstrateApi, InjectedSigner, IRuntimeTxCall, ISubmittableResult, Query, QueryFnResult, RpcVersion, TxUnsub, Unsub } from '@dedot/types';
4
4
  import { HexString } from '@dedot/utils';
5
5
  import { SubstrateApi } from '../chaintypes/index.js';
6
6
  import { ApiEvent, ApiOptions, BlockExplorer, ISubstrateClient, ISubstrateClientAt, SubstrateRuntimeVersion, IChainSpec, type EventHandlerFn } from '../types.js';
@@ -359,6 +359,31 @@ export declare class DedotClient<ChainApi extends GenericSubstrateApi = Substrat
359
359
  * ```
360
360
  */
361
361
  sendTx(tx: HexString | Extrinsic, callback?: Callback<ISubmittableResult<ChainApi['types']['EventRecord']>>): TxUnsub;
362
+ /**
363
+ * Convert a transaction input into a submittable extrinsic
364
+ * with `sign`, `signAndSend`, `send`, and `paymentInfo` methods.
365
+ *
366
+ * @param tx - A hex-encoded extrinsic or runtime call, a Uint8Array of encoded bytes,
367
+ * an Extrinsic instance, or an IRuntimeTxCall object.
368
+ * For HexString/Uint8Array, it first tries to decode as a full extrinsic;
369
+ * if that fails, it falls back to decoding as a raw runtime call.
370
+ * @returns A submittable extrinsic instance
371
+ *
372
+ * @example
373
+ * ```typescript
374
+ * // From a raw hex extrinsic
375
+ * const submittable = client.toTx(rawTxHex);
376
+ *
377
+ * // From a runtime call object
378
+ * const submittable = client.toTx({ pallet: 'Balances', palletCall: { name: 'TransferKeepAlive', params: { dest, value } } });
379
+ *
380
+ * // Sign and send
381
+ * const unsub = await submittable.signAndSend(alice, (result) => {
382
+ * console.log('Status:', result.status);
383
+ * });
384
+ * ```
385
+ */
386
+ toTx(tx: HexString | Uint8Array | Extrinsic | IRuntimeTxCall): ChainSubmittableExtrinsic<ChainApi>;
362
387
  /**
363
388
  * Clear internal caches.
364
389
  *
@@ -391,6 +391,33 @@ export class DedotClient {
391
391
  sendTx(tx, callback) {
392
392
  return this.#client.sendTx(tx, callback);
393
393
  }
394
+ /**
395
+ * Convert a transaction input into a submittable extrinsic
396
+ * with `sign`, `signAndSend`, `send`, and `paymentInfo` methods.
397
+ *
398
+ * @param tx - A hex-encoded extrinsic or runtime call, a Uint8Array of encoded bytes,
399
+ * an Extrinsic instance, or an IRuntimeTxCall object.
400
+ * For HexString/Uint8Array, it first tries to decode as a full extrinsic;
401
+ * if that fails, it falls back to decoding as a raw runtime call.
402
+ * @returns A submittable extrinsic instance
403
+ *
404
+ * @example
405
+ * ```typescript
406
+ * // From a raw hex extrinsic
407
+ * const submittable = client.toTx(rawTxHex);
408
+ *
409
+ * // From a runtime call object
410
+ * const submittable = client.toTx({ pallet: 'Balances', palletCall: { name: 'TransferKeepAlive', params: { dest, value } } });
411
+ *
412
+ * // Sign and send
413
+ * const unsub = await submittable.signAndSend(alice, (result) => {
414
+ * console.log('Status:', result.status);
415
+ * });
416
+ * ```
417
+ */
418
+ toTx(tx) {
419
+ return this.#client.toTx(tx);
420
+ }
394
421
  /**
395
422
  * Clear internal caches.
396
423
  *
@@ -1,6 +1,6 @@
1
1
  import { BlockHash, type Extrinsic, Metadata } from '@dedot/codecs';
2
2
  import type { JsonRpcProvider } from '@dedot/providers';
3
- import { Callback, GenericSubstrateApi, ISubmittableResult, TxUnsub } from '@dedot/types';
3
+ import { Callback, ChainSubmittableExtrinsic, GenericSubstrateApi, IRuntimeTxCall, ISubmittableResult, TxUnsub } from '@dedot/types';
4
4
  import { HexString } from '@dedot/utils';
5
5
  import type { SubstrateApi } from '../chaintypes/index.js';
6
6
  import { BaseStorageQuery } from '../storage/index.js';
@@ -137,4 +137,5 @@ export declare class LegacyClient<ChainApi extends GenericSubstrateApi = Substra
137
137
  at<ChainApiAt extends GenericSubstrateApi = ChainApi>(hash: BlockHash): Promise<ISubstrateClientAt<ChainApiAt>>;
138
138
  protected getStorageQuery(): BaseStorageQuery;
139
139
  sendTx(tx: HexString | Extrinsic, callback?: Callback<ISubmittableResult<ChainApi['types']['EventRecord']>>): TxUnsub;
140
+ toTx(tx: HexString | Uint8Array | Extrinsic | IRuntimeTxCall): ChainSubmittableExtrinsic<ChainApi>;
140
141
  }
@@ -357,4 +357,7 @@ export class LegacyClient// prettier-end-here
357
357
  callback && callback(result);
358
358
  });
359
359
  }
360
+ toTx(tx) {
361
+ return SubmittableExtrinsic.fromTx(this, tx);
362
+ }
360
363
  }
@@ -1,6 +1,6 @@
1
1
  import { BlockHash, type Extrinsic, Metadata } from '@dedot/codecs';
2
2
  import type { JsonRpcProvider } from '@dedot/providers';
3
- import { Callback, GenericSubstrateApi, ISubmittableResult, TxUnsub } from '@dedot/types';
3
+ import { Callback, ChainSubmittableExtrinsic, GenericSubstrateApi, IRuntimeTxCall, ISubmittableResult, TxUnsub } from '@dedot/types';
4
4
  import { HexString } from '@dedot/utils';
5
5
  import type { SubstrateApi } from '../chaintypes/index.js';
6
6
  import { Archive, ChainHead, ChainSpec, PinnedBlock } from '../json-rpc/index.js';
@@ -72,4 +72,5 @@ export declare class V2Client<ChainApi extends GenericSubstrateApi = SubstrateAp
72
72
  at<ChainApiAt extends GenericSubstrateApi = ChainApi>(hash: BlockHash): Promise<ISubstrateClientAt<ChainApiAt>>;
73
73
  protected getStorageQuery(): BaseStorageQuery;
74
74
  sendTx(tx: HexString | Extrinsic, callback?: Callback<ISubmittableResult<ChainApi['types']['EventRecord']>>): TxUnsub;
75
+ toTx(tx: HexString | Uint8Array | Extrinsic | IRuntimeTxCall): ChainSubmittableExtrinsic<ChainApi>;
75
76
  }
@@ -309,4 +309,7 @@ export class V2Client// prettier-end-here
309
309
  callback && callback(result);
310
310
  });
311
311
  }
312
+ toTx(tx) {
313
+ return SubmittableExtrinsicV2.fromTx(this, tx);
314
+ }
312
315
  }
@@ -10,9 +10,17 @@ export const MORTAL_PERIOD = 12 * 60 * 1000;
10
10
  export class CheckMortality extends SignedExtension {
11
11
  #signingHeader;
12
12
  async init() {
13
- this.#signingHeader = await this.#getSigningHeader();
14
- this.data = { period: this.#calculateMortalLength(), current: BigInt(this.#signingHeader.number) };
15
- this.additionalSigned = this.#signingHeader.hash;
13
+ const mortality = this.payloadOptions.mortality;
14
+ if (mortality?.type === 'Immortal') {
15
+ this.data = { type: 'Immortal' };
16
+ this.additionalSigned = this.client.genesisHash;
17
+ }
18
+ else {
19
+ this.#signingHeader = await this.#getSigningHeader();
20
+ const period = mortality?.type === 'Mortal' ? BigInt(mortality.period) : this.#calculateMortalLength();
21
+ this.data = { period, current: BigInt(this.#signingHeader.number) };
22
+ this.additionalSigned = this.#signingHeader.hash;
23
+ }
16
24
  }
17
25
  async fromPayload(payload) {
18
26
  const { era, blockHash, blockNumber } = payload;
@@ -85,7 +93,7 @@ export class CheckMortality extends SignedExtension {
85
93
  return {
86
94
  era: u8aToHex(this.$Data.tryEncode(this.data)),
87
95
  blockHash: this.additionalSigned,
88
- blockNumber: numberToHex(this.#signingHeader.number),
96
+ blockNumber: numberToHex(this.#signingHeader?.number ?? 0),
89
97
  };
90
98
  }
91
99
  }
@@ -24,7 +24,9 @@ export class BaseSubmittableExtrinsic extends Extrinsic {
24
24
  return result;
25
25
  }
26
26
  async paymentInfo(account, options) {
27
- await this.sign(account, { ...options, signer: fakeSigner });
27
+ if (!this.signed) {
28
+ await this.sign(account, { ...options, signer: fakeSigner });
29
+ }
28
30
  const txU8a = this.toU8a();
29
31
  const api = this.client;
30
32
  return api.call.transactionPaymentApi.queryInfo(txU8a, txU8a.length);
@@ -1,5 +1,5 @@
1
1
  import { BlockHash, Extrinsic } from '@dedot/codecs';
2
- import { AddressOrPair, Callback, DryRunResult, ISubmittableExtrinsicLegacy, ISubmittableResult, SignerOptions, TxHash, TxUnsub } from '@dedot/types';
2
+ import { AddressOrPair, Callback, DryRunResult, IRuntimeTxCall, ISubmittableExtrinsicLegacy, ISubmittableResult, SignerOptions, TxHash, TxUnsub } from '@dedot/types';
3
3
  import { HexString } from '@dedot/utils';
4
4
  import { LegacyClient } from '../../client/LegacyClient.js';
5
5
  import { BaseSubmittableExtrinsic } from './BaseSubmittableExtrinsic.js';
@@ -8,7 +8,7 @@ import { BaseSubmittableExtrinsic } from './BaseSubmittableExtrinsic.js';
8
8
  * @description A wrapper around an Extrinsic that exposes methods to sign, send, and other utility around Extrinsic.
9
9
  */
10
10
  export declare class SubmittableExtrinsic extends BaseSubmittableExtrinsic implements ISubmittableExtrinsicLegacy {
11
- static fromTx(client: LegacyClient<any>, tx: HexString | Extrinsic): SubmittableExtrinsic;
11
+ static fromTx(client: LegacyClient<any>, tx: HexString | Uint8Array | Extrinsic | IRuntimeTxCall): SubmittableExtrinsic;
12
12
  dryRun(account: AddressOrPair, optionsOrHash?: Partial<SignerOptions> | BlockHash): Promise<DryRunResult>;
13
13
  send(): TxHash;
14
14
  send(callback: Callback<ISubmittableResult>): TxUnsub;
@@ -1,21 +1,15 @@
1
1
  import { assert, isHex, noop } from '@dedot/utils';
2
2
  import { BaseSubmittableExtrinsic } from './BaseSubmittableExtrinsic.js';
3
3
  import { SubmittableResult } from './SubmittableResult.js';
4
- import { toTxStatus, txDefer } from './utils.js';
4
+ import { resolveCallAndPreamble, 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.
8
8
  */
9
9
  export class SubmittableExtrinsic extends BaseSubmittableExtrinsic {
10
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);
11
+ const { call, preamble } = resolveCallAndPreamble(client.registry, tx);
12
+ return new SubmittableExtrinsic(client, call, preamble);
19
13
  }
20
14
  async dryRun(account, optionsOrHash) {
21
15
  const dryRunFn = this.client.rpc.system_dryRun;
@@ -11,7 +11,7 @@ export declare class SubmittableExtrinsicV2 extends BaseSubmittableExtrinsic {
11
11
  #private;
12
12
  client: V2Client<any>;
13
13
  constructor(client: V2Client<any>, call: IRuntimeTxCall, preamble?: Preamble);
14
- static fromTx(client: V2Client<any>, tx: HexString | Extrinsic): SubmittableExtrinsicV2;
14
+ static fromTx(client: V2Client<any>, tx: HexString | Uint8Array | Extrinsic | IRuntimeTxCall): SubmittableExtrinsicV2;
15
15
  send(): TxHash;
16
16
  send(callback: Callback<ISubmittableResult>): TxUnsub;
17
17
  }
@@ -1,8 +1,8 @@
1
- import { AsyncQueue, isHex, noop, waitFor } from '@dedot/utils';
1
+ import { AsyncQueue, 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';
5
- import { txDefer } from './utils.js';
5
+ import { resolveCallAndPreamble, txDefer } from './utils.js';
6
6
  /**
7
7
  * @name SubmittableExtrinsicV2
8
8
  * @description Submittable extrinsic based on JSON-RPC v2
@@ -14,14 +14,8 @@ export class SubmittableExtrinsicV2 extends BaseSubmittableExtrinsic {
14
14
  this.client = client;
15
15
  }
16
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);
17
+ const { call, preamble } = resolveCallAndPreamble(client.registry, tx);
18
+ return new SubmittableExtrinsicV2(client, call, preamble);
25
19
  }
26
20
  async #send(callback) {
27
21
  const api = this.client;
@@ -1,6 +1,18 @@
1
- import { TransactionStatus } from '@dedot/codecs';
2
- import { AddressOrPair, IKeyringPair, ISubmittableResult, TxStatus, Unsub } from '@dedot/types';
1
+ import { Extrinsic, Preamble, PortableRegistry, TransactionStatus } from '@dedot/codecs';
2
+ import { AddressOrPair, IKeyringPair, IRuntimeTxCall, ISubmittableResult, TxStatus, Unsub } from '@dedot/types';
3
3
  import { Deferred, HexString } from '@dedot/utils';
4
+ /**
5
+ * Resolve a transaction input into a call and optional preamble.
6
+ *
7
+ * Supports:
8
+ * - `Extrinsic` instance: extract call + preamble
9
+ * - `IRuntimeTxCall` object: use directly as call, no preamble
10
+ * - `HexString` or `Uint8Array`: try decode as extrinsic first, fallback to runtime call
11
+ */
12
+ export declare function resolveCallAndPreamble(registry: PortableRegistry, tx: HexString | Uint8Array | Extrinsic | IRuntimeTxCall): {
13
+ call: IRuntimeTxCall;
14
+ preamble?: Preamble;
15
+ };
4
16
  export declare function isKeyringPair(account: AddressOrPair): account is IKeyringPair;
5
17
  /**
6
18
  * Sign a raw message
@@ -1,5 +1,39 @@
1
+ import { Extrinsic } from '@dedot/codecs';
1
2
  import { assert, blake2AsU8a, deferred, hexToU8a, isFunction } from '@dedot/utils';
2
3
  import { RejectedTxError } from './errors.js';
4
+ /**
5
+ * Check if a value is an IRuntimeTxCall object (has a 'pallet' property).
6
+ */
7
+ function isRuntimeTxCall(tx) {
8
+ return typeof tx === 'object' && tx !== null && 'pallet' in tx;
9
+ }
10
+ /**
11
+ * Resolve a transaction input into a call and optional preamble.
12
+ *
13
+ * Supports:
14
+ * - `Extrinsic` instance: extract call + preamble
15
+ * - `IRuntimeTxCall` object: use directly as call, no preamble
16
+ * - `HexString` or `Uint8Array`: try decode as extrinsic first, fallback to runtime call
17
+ */
18
+ export function resolveCallAndPreamble(registry, tx) {
19
+ if (tx instanceof Extrinsic) {
20
+ return { call: tx.call, preamble: tx.preamble };
21
+ }
22
+ if (isRuntimeTxCall(tx)) {
23
+ return { call: tx };
24
+ }
25
+ // HexString or Uint8Array: try extrinsic decode first, fallback to runtime call
26
+ try {
27
+ const extrinsic = registry.$Extrinsic.tryDecode(tx);
28
+ return { call: extrinsic.call, preamble: extrinsic.preamble };
29
+ }
30
+ catch {
31
+ const { callTypeId } = registry.metadata.extrinsic;
32
+ const $RuntimeCall = registry.findCodec(callTypeId);
33
+ const call = $RuntimeCall.tryDecode(tx);
34
+ return { call };
35
+ }
36
+ }
3
37
  export function isKeyringPair(account) {
4
38
  return isFunction(account.sign);
5
39
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dedot/api",
3
- "version": "1.0.4",
3
+ "version": "1.2.0",
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": "1.0.4",
17
- "@dedot/providers": "1.0.4",
18
- "@dedot/runtime-specs": "1.0.4",
19
- "@dedot/shape": "1.0.4",
20
- "@dedot/storage": "1.0.4",
21
- "@dedot/types": "1.0.4",
22
- "@dedot/utils": "1.0.4"
16
+ "@dedot/codecs": "^1.2.0",
17
+ "@dedot/providers": "^1.2.0",
18
+ "@dedot/runtime-specs": "^1.2.0",
19
+ "@dedot/shape": "^1.2.0",
20
+ "@dedot/storage": "^1.2.0",
21
+ "@dedot/types": "^1.2.0",
22
+ "@dedot/utils": "^1.2.0"
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": "ad52d3d391c858c058f356dd13f279ea223a0f5f",
51
+ "gitHead": "d0da366e311d33389d0fd1b9e9435c1d61da5799",
52
52
  "module": "./index.js",
53
53
  "types": "./index.d.ts"
54
54
  }
package/types.d.ts CHANGED
@@ -2,7 +2,7 @@ import { BlockHash, Extrinsic, Hash, Header, Metadata, PortableRegistry } from '
2
2
  import type { ConnectionStatus, JsonRpcProvider, ProviderEvent } from '@dedot/providers';
3
3
  import type { AnyShape } from '@dedot/shape';
4
4
  import type { IStorage } from '@dedot/storage';
5
- import { Callback, GenericStorageQuery, GenericSubstrateApi, InjectedSigner, ISubmittableResult, Query, QueryFnResult, RpcVersion, RuntimeApiName, RuntimeApiSpec, TxUnsub, Unsub } from '@dedot/types';
5
+ import { Callback, ChainSubmittableExtrinsic, GenericStorageQuery, GenericSubstrateApi, InjectedSigner, IRuntimeTxCall, ISubmittableResult, Query, QueryFnResult, RpcVersion, RuntimeApiName, RuntimeApiSpec, TxUnsub, Unsub } from '@dedot/types';
6
6
  import { Properties } from '@dedot/types/json-rpc';
7
7
  import type { HashFn, HexString, IEventEmitter } from '@dedot/utils';
8
8
  import type { SubstrateApi } from './chaintypes/index.js';
@@ -225,6 +225,37 @@ Events extends string = ApiEvent> extends IJsonRpcClient<ChainApi, Events>, IGen
225
225
  * console.log('Transaction finalized:', result);
226
226
  */
227
227
  sendTx(tx: HexString | Extrinsic, callback?: Callback<ISubmittableResult<ChainApi['types']['EventRecord']>>): TxUnsub;
228
+ /**
229
+ * Convert a transaction input into a submittable extrinsic
230
+ * with `sign`, `signAndSend`, `send`, and `paymentInfo` methods.
231
+ *
232
+ * @param tx - A hex-encoded extrinsic or runtime call, a Uint8Array of encoded bytes,
233
+ * an Extrinsic instance, or an IRuntimeTxCall object.
234
+ * For HexString/Uint8Array, it first tries to decode as a full extrinsic;
235
+ * if that fails, it falls back to decoding as a raw runtime call.
236
+ * @returns A submittable extrinsic instance
237
+ *
238
+ * @example
239
+ * ```typescript
240
+ * // From a raw hex extrinsic
241
+ * const submittable = client.toTx(rawTxHex);
242
+ *
243
+ * // From a runtime call hex (encoded call data)
244
+ * const submittable = client.toTx(runtimeCallHex);
245
+ *
246
+ * // From a Uint8Array
247
+ * const submittable = client.toTx(callBytes);
248
+ *
249
+ * // From a runtime call object
250
+ * const submittable = client.toTx({ pallet: 'Balances', palletCall: { name: 'TransferKeepAlive', params: { dest, value } } });
251
+ *
252
+ * // Sign and send
253
+ * const unsub = await submittable.signAndSend(alice, (result) => {
254
+ * console.log('Status:', result.status);
255
+ * });
256
+ * ```
257
+ */
258
+ toTx(tx: HexString | Uint8Array | Extrinsic | IRuntimeTxCall): ChainSubmittableExtrinsic<ChainApi>;
228
259
  /**
229
260
  * Query multiple storage items in a single call or subscribe to multiple storage items
230
261
  *