@polkadot-apps/tx 0.2.5 → 0.2.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.
Files changed (2) hide show
  1. package/README.md +259 -0
  2. package/package.json +4 -3
package/README.md ADDED
@@ -0,0 +1,259 @@
1
+ # @polkadot-apps/tx
2
+
3
+ Transaction submission, lifecycle watching, and dev signers for Polkadot chains.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pnpm add @polkadot-apps/tx
9
+ ```
10
+
11
+ **Peer dependency**: `polkadot-api` must be installed in your project.
12
+
13
+ ```bash
14
+ pnpm add polkadot-api
15
+ ```
16
+
17
+ ## Quick start
18
+
19
+ ```typescript
20
+ import { submitAndWatch, createDevSigner } from "@polkadot-apps/tx";
21
+
22
+ const signer = createDevSigner("Alice");
23
+
24
+ const result = await submitAndWatch(tx, signer, {
25
+ waitFor: "finalized",
26
+ onStatus: (status) => console.log(status),
27
+ });
28
+
29
+ console.log(result.txHash, result.ok);
30
+ ```
31
+
32
+ ## Transaction lifecycle
33
+
34
+ `submitAndWatch` drives a transaction through its full lifecycle: signing, broadcasting, block inclusion, and optional finalization. You choose when to resolve the returned promise with the `waitFor` option.
35
+
36
+ ```typescript
37
+ import { submitAndWatch } from "@polkadot-apps/tx";
38
+
39
+ const result = await submitAndWatch(tx, signer, {
40
+ waitFor: "best-block", // resolve at best-block inclusion (default)
41
+ timeoutMs: 300_000, // 5-minute timeout (default)
42
+ mortalityPeriod: 256, // ~43 minutes on Polkadot (default)
43
+ onStatus: (status) => {
44
+ // "signing" -> "broadcasting" -> "in-block" -> "finalized"
45
+ updateUI(status);
46
+ },
47
+ });
48
+
49
+ if (!result.ok) {
50
+ console.error("Dispatch failed:", result.dispatchError);
51
+ }
52
+ ```
53
+
54
+ The function accepts both raw PAPI transactions and Ink SDK `AsyncTransaction` wrappers. Ink SDK wrappers are resolved automatically via the `.waited` promise.
55
+
56
+ ## Dev signers
57
+
58
+ Create signers from the well-known Substrate dev mnemonic for local testing. All keys derive at `//Name` using sr25519.
59
+
60
+ ```typescript
61
+ import { createDevSigner, getDevPublicKey } from "@polkadot-apps/tx";
62
+
63
+ const alice = createDevSigner("Alice");
64
+ const bobPubKey = getDevPublicKey("Bob"); // Uint8Array (32 bytes)
65
+ ```
66
+
67
+ Available names: `"Alice"`, `"Bob"`, `"Charlie"`, `"Dave"`, `"Eve"`, `"Ferdie"`.
68
+
69
+ ## Dry-run and weight buffers
70
+
71
+ Extract a submittable transaction from an Ink SDK dry-run result and apply a safety buffer to weight estimates before submission.
72
+
73
+ ```typescript
74
+ import { extractTransaction, applyWeightBuffer } from "@polkadot-apps/tx";
75
+
76
+ const dryRunResult = await contract.query.myMethod(args);
77
+ const tx = extractTransaction(dryRunResult);
78
+
79
+ const buffered = applyWeightBuffer(dryRunResult.weight_required, {
80
+ bufferPercent: 25, // default: 25%
81
+ });
82
+ ```
83
+
84
+ ## Account mapping
85
+
86
+ Map an SS58 address to an H160 address on Asset Hub. The operation is idempotent -- it returns `null` when the account is already mapped.
87
+
88
+ ```typescript
89
+ import { ensureAccountMapped, isAccountMapped } from "@polkadot-apps/tx";
90
+
91
+ const mapped = await isAccountMapped(address, checker);
92
+
93
+ if (!mapped) {
94
+ const result = await ensureAccountMapped(address, signer, checker, api);
95
+ // result is TxResult or null (if already mapped)
96
+ }
97
+ ```
98
+
99
+ ## Retry logic
100
+
101
+ `withRetry` wraps any async function with exponential backoff and jitter. It does **not** retry `TxDispatchError`, `TxSigningRejectedError`, or `TxTimeoutError` -- these represent terminal conditions that retrying cannot fix.
102
+
103
+ ```typescript
104
+ import { withRetry, calculateDelay } from "@polkadot-apps/tx";
105
+
106
+ const result = await withRetry(() => submitAndWatch(tx, signer), {
107
+ maxAttempts: 3, // total attempts including the first (default)
108
+ baseDelayMs: 1_000, // initial backoff (default)
109
+ maxDelayMs: 15_000, // backoff cap (default)
110
+ });
111
+
112
+ // Calculate delay directly for custom retry strategies
113
+ const delay = calculateDelay(2, 1_000, 15_000);
114
+ ```
115
+
116
+ ## Error handling
117
+
118
+ All errors extend a common `TxError` base class. Use the specific error types and utility functions to handle failures precisely.
119
+
120
+ ```typescript
121
+ import {
122
+ TxTimeoutError,
123
+ TxDispatchError,
124
+ TxSigningRejectedError,
125
+ TxDryRunError,
126
+ TxAccountMappingError,
127
+ formatDispatchError,
128
+ formatDryRunError,
129
+ isSigningRejection,
130
+ } from "@polkadot-apps/tx";
131
+
132
+ try {
133
+ await submitAndWatch(tx, signer);
134
+ } catch (error) {
135
+ if (isSigningRejection(error)) {
136
+ console.log("User cancelled signing");
137
+ } else if (error instanceof TxDispatchError) {
138
+ console.error(error.formatted, error.dispatchError);
139
+ } else if (error instanceof TxTimeoutError) {
140
+ console.error(`Timed out after ${error.timeoutMs}ms`);
141
+ } else if (error instanceof TxDryRunError) {
142
+ console.error(error.formatted, error.revertReason);
143
+ }
144
+ }
145
+ ```
146
+
147
+ ## API
148
+
149
+ ### `submitAndWatch(tx, signer, options?): Promise<TxResult>`
150
+
151
+ Submit a transaction and watch its lifecycle through to inclusion or finalization.
152
+
153
+ | Parameter | Type | Description |
154
+ |-----------|------|-------------|
155
+ | `tx` | `SubmittableTransaction` | Transaction with `signSubmitAndWatch`. Raw PAPI or Ink SDK. |
156
+ | `signer` | `PolkadotSigner` | Signer from a wallet, Host API, or `createDevSigner`. |
157
+ | `options` | `SubmitOptions` | Optional. See below. |
158
+
159
+ **Throws**: `TxTimeoutError`, `TxDispatchError`, `TxSigningRejectedError`.
160
+
161
+ ### `createDevSigner(name): PolkadotSigner`
162
+
163
+ Create a signer from the well-known dev mnemonic at `//Name` (sr25519).
164
+
165
+ | Parameter | Type | Description |
166
+ |-----------|------|-------------|
167
+ | `name` | `DevAccountName` | One of `"Alice"`, `"Bob"`, `"Charlie"`, `"Dave"`, `"Eve"`, `"Ferdie"`. |
168
+
169
+ ### `getDevPublicKey(name): Uint8Array`
170
+
171
+ Return the 32-byte public key for a dev account.
172
+
173
+ ### `withRetry<T>(fn, options?): Promise<T>`
174
+
175
+ Retry an async function with exponential backoff and jitter. Does not retry `TxDispatchError`, `TxSigningRejectedError`, or `TxTimeoutError`.
176
+
177
+ | Parameter | Type | Description |
178
+ |-----------|------|-------------|
179
+ | `fn` | `() => Promise<T>` | Async function to retry. |
180
+ | `options` | `RetryOptions` | Optional retry configuration. |
181
+
182
+ ### `calculateDelay(attempt, baseDelayMs, maxDelayMs): number`
183
+
184
+ Compute the backoff delay for a given attempt number, with jitter.
185
+
186
+ ### `extractTransaction(result): SubmittableTransaction`
187
+
188
+ Extract a submittable transaction from an Ink SDK dry-run result.
189
+
190
+ ### `applyWeightBuffer(weight, options?): Weight`
191
+
192
+ Apply a percentage safety buffer to a weight estimate. Default buffer is 25%.
193
+
194
+ ### `ensureAccountMapped(address, signer, checker, api, options?): Promise<TxResult | null>`
195
+
196
+ Map an SS58 address to H160 on Asset Hub. Returns `null` if the account is already mapped.
197
+
198
+ ### `isAccountMapped(address, checker): Promise<boolean>`
199
+
200
+ Check whether an SS58 address is already mapped to an H160 address.
201
+
202
+ ### Error utilities
203
+
204
+ | Function | Signature | Description |
205
+ |----------|-----------|-------------|
206
+ | `formatDispatchError` | `(result) => string` | Format a dispatch error into a readable string. |
207
+ | `formatDryRunError` | `(result) => string` | Format a dry-run error into a readable string. |
208
+ | `isSigningRejection` | `(error) => boolean` | Check if an error is a signing rejection. |
209
+
210
+ ## Types
211
+
212
+ ```typescript
213
+ type TxStatus = "signing" | "broadcasting" | "in-block" | "finalized" | "error";
214
+
215
+ type WaitFor = "best-block" | "finalized";
216
+
217
+ interface TxResult {
218
+ txHash: string;
219
+ ok: boolean;
220
+ block: { hash: string; number: number; index: number };
221
+ events: unknown[];
222
+ dispatchError?: unknown;
223
+ }
224
+
225
+ interface SubmitOptions {
226
+ waitFor?: WaitFor; // default: "best-block"
227
+ timeoutMs?: number; // default: 300_000
228
+ mortalityPeriod?: number; // default: 256
229
+ onStatus?: (status: TxStatus) => void;
230
+ }
231
+
232
+ interface RetryOptions {
233
+ maxAttempts?: number; // default: 3
234
+ baseDelayMs?: number; // default: 1_000
235
+ maxDelayMs?: number; // default: 15_000
236
+ }
237
+
238
+ type DevAccountName = "Alice" | "Bob" | "Charlie" | "Dave" | "Eve" | "Ferdie";
239
+
240
+ interface Weight {
241
+ ref_time: bigint;
242
+ proof_size: bigint;
243
+ }
244
+ ```
245
+
246
+ ### Error classes
247
+
248
+ | Class | Extends | Key properties |
249
+ |-------|---------|---------------|
250
+ | `TxError` | `Error` | Base class for all tx errors. |
251
+ | `TxTimeoutError` | `TxError` | `timeoutMs: number` |
252
+ | `TxDispatchError` | `TxError` | `dispatchError: unknown`, `formatted: string` |
253
+ | `TxSigningRejectedError` | `TxError` | User rejected signing. |
254
+ | `TxDryRunError` | `TxError` | `raw: unknown`, `formatted: string`, `revertReason?: string` |
255
+ | `TxAccountMappingError` | `TxError` | Account mapping failed. |
256
+
257
+ ## License
258
+
259
+ Apache-2.0
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@polkadot-apps/tx",
3
- "version": "0.2.5",
3
+ "description": "Transaction submission, lifecycle watching, and dev signers for Polkadot chains",
4
+ "version": "0.2.6",
4
5
  "type": "module",
5
6
  "main": "./dist/index.js",
6
7
  "types": "./dist/index.d.ts",
@@ -19,8 +20,8 @@
19
20
  "dependencies": {
20
21
  "polkadot-api": "^1.23.3",
21
22
  "@polkadot-labs/hdkd-helpers": "^0.0.27",
22
- "@polkadot-apps/keys": "0.3.2",
23
- "@polkadot-apps/logger": "0.1.3"
23
+ "@polkadot-apps/keys": "0.3.3",
24
+ "@polkadot-apps/logger": "0.1.4"
24
25
  },
25
26
  "devDependencies": {
26
27
  "typescript": "^5.9.3"