@secondlayer/stacks 2.6.0 → 2.7.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.
Files changed (48) hide show
  1. package/README.md +65 -0
  2. package/dist/shared/{stacks-yb8xesdm.js → stacks-a48qj7ss.js} +3 -3
  3. package/dist/shared/{stacks-hr5rg2et.js → stacks-k96f5g1a.js} +2 -2
  4. package/dist/shared/{stacks-gxhznn3h.js → stacks-r3mqgw2d.js} +47 -3
  5. package/dist/shared/stacks-r3mqgw2d.js.map +15 -0
  6. package/dist/shared/{stacks-ffsv2t3t.js → stacks-s6v8k4j5.js} +2 -2
  7. package/dist/shared/{stacks-a9cn5ehj.js → stacks-txh6dadn.js} +2 -2
  8. package/dist/shared/{stacks-1wra341e.cjs → stacks-wb06pevp.cjs} +46 -2
  9. package/dist/shared/stacks-wb06pevp.cjs.map +15 -0
  10. package/dist/src/actions/index.d.cts +5 -0
  11. package/dist/src/actions/index.d.ts +5 -0
  12. package/dist/src/actions/index.js +5 -5
  13. package/dist/src/bns/index.d.cts +5 -0
  14. package/dist/src/bns/index.d.ts +5 -0
  15. package/dist/src/bns/index.js +3 -3
  16. package/dist/src/index.cjs +102 -1
  17. package/dist/src/index.cjs.map +5 -4
  18. package/dist/src/index.d.cts +150 -1
  19. package/dist/src/index.d.ts +150 -1
  20. package/dist/src/index.js +109 -6
  21. package/dist/src/index.js.map +5 -4
  22. package/dist/src/pox/index.d.cts +5 -0
  23. package/dist/src/pox/index.d.ts +5 -0
  24. package/dist/src/pox/index.js +3 -3
  25. package/dist/src/sbtc/index.d.cts +5 -0
  26. package/dist/src/sbtc/index.d.ts +5 -0
  27. package/dist/src/sbtc/index.js +3 -3
  28. package/dist/src/stackingdao/index.d.cts +5 -0
  29. package/dist/src/stackingdao/index.d.ts +5 -0
  30. package/dist/src/stackingdao/index.js +3 -3
  31. package/dist/src/subscriptions/index.d.cts +5 -0
  32. package/dist/src/subscriptions/index.d.ts +5 -0
  33. package/dist/src/tools/index.cjs +1 -1
  34. package/dist/src/tools/index.cjs.map +3 -3
  35. package/dist/src/tools/index.d.cts +5 -0
  36. package/dist/src/tools/index.d.ts +5 -0
  37. package/dist/src/tools/index.js +1 -1
  38. package/dist/src/tools/index.js.map +3 -3
  39. package/dist/src/x402/index.d.cts +5 -0
  40. package/dist/src/x402/index.d.ts +5 -0
  41. package/dist/src/x402/index.js +2 -2
  42. package/package.json +1 -1
  43. package/dist/shared/stacks-1wra341e.cjs.map +0 -15
  44. package/dist/shared/stacks-gxhznn3h.js.map +0 -15
  45. /package/dist/shared/{stacks-yb8xesdm.js.map → stacks-a48qj7ss.js.map} +0 -0
  46. /package/dist/shared/{stacks-hr5rg2et.js.map → stacks-k96f5g1a.js.map} +0 -0
  47. /package/dist/shared/{stacks-ffsv2t3t.js.map → stacks-s6v8k4j5.js.map} +0 -0
  48. /package/dist/shared/{stacks-a9cn5ehj.js.map → stacks-txh6dadn.js.map} +0 -0
package/README.md CHANGED
@@ -52,6 +52,71 @@ work; Secondlayer is a data-infrastructure company, not a wallet SDK vendor.
52
52
  | `@secondlayer/stacks/pox` | PoX stacking — solo and delegated |
53
53
  | `@secondlayer/stacks/stackingdao` | StackingDAO liquid staking (STX/stSTX) |
54
54
 
55
+ ## Nonce management
56
+
57
+ Stacks' `/v2/accounts` returns only the confirmed nonce — it ignores the mempool. Broadcasting several transactions from one account before the first confirms makes them reuse the same nonce, so every one after the first is rejected (`ConflictingNonceInMempool`). The usual workaround is tracking nonces by hand.
58
+
59
+ Attach a nonce manager and the SDK hands out sequential nonces across rapid broadcasts:
60
+
61
+ ```ts
62
+ import { createWalletClient, http, createNonceManager } from "@secondlayer/stacks";
63
+ import { mainnet } from "@secondlayer/stacks/chains";
64
+ import { privateKeyToAccount } from "@secondlayer/stacks/accounts";
65
+
66
+ const client = createWalletClient({
67
+ chain: mainnet,
68
+ transport: http(), // any node — no Secondlayer dependency
69
+ account: privateKeyToAccount(process.env.KEY!),
70
+ nonceManager: createNonceManager(), // jsonRpcSource + in-memory store
71
+ });
72
+
73
+ // 20 back-to-back transfers → nonces n, n+1, …, n+19 — no collisions
74
+ await Promise.all(
75
+ recipients.map((to) => client.transferStx({ to, amount: 1000n })),
76
+ );
77
+ ```
78
+
79
+ Passing an explicit `nonce` always bypasses the manager. The defaults are node-agnostic and in-memory — zero external dependencies.
80
+
81
+ ### Multiple processes / smart wallets
82
+
83
+ The in-memory store is single-process. Backends that sign from one key across multiple workers (smart-wallet-as-a-service) need a shared, durable store. The reservation is atomic in the datastore, so it doubles as the cross-process lock and survives restarts:
84
+
85
+ ```ts
86
+ import { createNonceManager, redisStore } from "@secondlayer/stacks";
87
+
88
+ const nonceManager = createNonceManager({
89
+ store: redisStore({ redis: new Bun.RedisClient(process.env.REDIS_URL!) }),
90
+ });
91
+ ```
92
+
93
+ `postgresStore({ sql })` works the same way. Bring your own client — no global `Bun` reference, so the store stays runtime-agnostic.
94
+
95
+ ### Mempool-aware sources (optional)
96
+
97
+ By default the floor is the node's confirmed nonce. To make it mempool-aware — and to auto-fill the freed nonce of a dropped transaction — swap the source. `indexSource` reads Secondlayer's mempool, `hiroNonceSource` reads Hiro's, or bring your own pending feed with `mempoolAwareSource`:
98
+
99
+ ```ts
100
+ import {
101
+ createNonceManager,
102
+ indexSource,
103
+ startNonceReconciler,
104
+ } from "@secondlayer/stacks";
105
+
106
+ // indexSource() | hiroNonceSource({ baseUrl }) | mempoolAwareSource({ getPending })
107
+ const source = indexSource();
108
+ const nonceManager = createNonceManager({ source });
109
+
110
+ // Optional: periodically heal silently-dropped txs (run in ONE process)
111
+ const reconciler = startNonceReconciler(nonceManager, {
112
+ client,
113
+ addresses: [account.address],
114
+ source,
115
+ });
116
+ ```
117
+
118
+ Everything here is opt-in. With no `source`/`store`, the manager depends only on your node.
119
+
55
120
  ## WalletConnect v2
56
121
 
57
122
  Native WC v2 implementation — X25519 ECDH, AES-256-GCM envelope encryption, Ed25519 JWT relay auth. Zero cost if you don't import it, tree-shakes completely.
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  readContract
3
- } from "./stacks-a9cn5ehj.js";
3
+ } from "./stacks-txh6dadn.js";
4
4
  import {
5
5
  broadcastWithNonceReset,
6
6
  estimateFee,
7
7
  isProviderAccount,
8
8
  resolveNonce
9
- } from "./stacks-gxhznn3h.js";
9
+ } from "./stacks-r3mqgw2d.js";
10
10
  import {
11
11
  BaseError
12
12
  } from "./stacks-709tra19.js";
@@ -309,4 +309,4 @@ async function transferStx(client, params) {
309
309
  export { getAccountInfo, getBalance, getBlock, getBlockHeight, getContractAbi, multicall, SimulationError, simulateCall, simulateTransaction, deployContract, signMessage, signTransactionAction, transferStx };
310
310
 
311
311
  //# debugId=B8138CC37EDC138164756E2164756E21
312
- //# sourceMappingURL=stacks-yb8xesdm.js.map
312
+ //# sourceMappingURL=stacks-a48qj7ss.js.map
@@ -2,7 +2,7 @@ import {
2
2
  callContract,
3
3
  getMapEntry,
4
4
  readContract
5
- } from "./stacks-a9cn5ehj.js";
5
+ } from "./stacks-txh6dadn.js";
6
6
  import {
7
7
  clarityValueToJSUntyped,
8
8
  jsToClarityValue,
@@ -131,4 +131,4 @@ class ContractResponseError extends Error {
131
131
  export { getContract, ContractResponseError };
132
132
 
133
133
  //# debugId=C71C39F2B8094B6864756E2164756E21
134
- //# sourceMappingURL=stacks-hr5rg2et.js.map
134
+ //# sourceMappingURL=stacks-k96f5g1a.js.map
@@ -106,6 +106,9 @@ function memoryStore() {
106
106
  },
107
107
  reset(key) {
108
108
  next.delete(key);
109
+ },
110
+ peek(key) {
111
+ return next.get(key);
109
112
  }
110
113
  };
111
114
  }
@@ -121,6 +124,9 @@ function createNonceManager(params = {}) {
121
124
  },
122
125
  reset({ client, address }) {
123
126
  return store.reset(nonceKey(client, address));
127
+ },
128
+ async peek({ client, address }) {
129
+ return store.peek?.(nonceKey(client, address));
124
130
  }
125
131
  };
126
132
  }
@@ -129,6 +135,44 @@ async function resolveNonce(client, address) {
129
135
  return client.nonceManager.consume({ client, address });
130
136
  return getNonce(client, { address });
131
137
  }
138
+ async function reconcileNonce(manager, params) {
139
+ const { client, address, source } = params;
140
+ const downward = params.downward ?? true;
141
+ const authoritative = await source.get({ client, address });
142
+ const tracked = await manager.peek({ client, address });
143
+ if (tracked === undefined || authoritative === tracked) {
144
+ return { reset: false, authoritative, tracked };
145
+ }
146
+ if (authoritative < tracked && !downward) {
147
+ return { reset: false, authoritative, tracked };
148
+ }
149
+ await manager.reset({ client, address });
150
+ return { reset: true, authoritative, tracked };
151
+ }
152
+ function startNonceReconciler(manager, params) {
153
+ const { client, addresses, source } = params;
154
+ const intervalMs = params.intervalMs ?? 60000;
155
+ const tick = async () => {
156
+ for (const address of addresses) {
157
+ try {
158
+ const result = await reconcileNonce(manager, {
159
+ client,
160
+ address,
161
+ source,
162
+ downward: params.downward
163
+ });
164
+ params.onReconcile?.(address, result);
165
+ } catch (error) {
166
+ params.onError?.(address, error);
167
+ }
168
+ }
169
+ };
170
+ const timer = setInterval(tick, intervalMs);
171
+ timer.unref?.();
172
+ return {
173
+ stop: () => clearInterval(timer)
174
+ };
175
+ }
132
176
  function isNonceConflictError(error) {
133
177
  if (!(error instanceof BroadcastError))
134
178
  return false;
@@ -154,7 +198,7 @@ function isProviderAccount(account) {
154
198
  return account.type === "provider";
155
199
  }
156
200
 
157
- export { estimateFee, getNonce, TransactionError, BroadcastError, SerializationError, SigningError, sendTransaction, jsonRpcSource, memoryStore, createNonceManager, resolveNonce, isNonceConflictError, broadcastWithNonceReset, isProviderAccount };
201
+ export { estimateFee, getNonce, TransactionError, BroadcastError, SerializationError, SigningError, sendTransaction, jsonRpcSource, memoryStore, createNonceManager, resolveNonce, reconcileNonce, startNonceReconciler, isNonceConflictError, broadcastWithNonceReset, isProviderAccount };
158
202
 
159
- //# debugId=6924F3A2AFF3CC9E64756E2164756E21
160
- //# sourceMappingURL=stacks-gxhznn3h.js.map
203
+ //# debugId=201E1A3233967AC964756E2164756E21
204
+ //# sourceMappingURL=stacks-r3mqgw2d.js.map
@@ -0,0 +1,15 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/actions/public/estimateFee.ts", "../src/actions/public/getNonce.ts", "../src/errors/transaction.ts", "../src/actions/wallet/sendTransaction.ts", "../src/actions/wallet/nonceManager.ts", "../src/actions/wallet/utils.ts"],
4
+ "sourcesContent": [
5
+ "import type { Client } from \"../../clients/types.ts\";\nimport type { StacksTransaction } from \"../../transactions/types.ts\";\nimport {\n\tserializePayload,\n\tserializeTransaction,\n} from \"../../transactions/wire/serialize.ts\";\nimport { bytesToHex } from \"../../utils/encoding.ts\";\n\nexport type EstimateFeeParams = {\n\ttransaction: StacksTransaction;\n};\n\nexport type FeeEstimation = {\n\tfeeRate: number;\n\tfee: number;\n};\n\nexport async function estimateFee(\n\tclient: Client,\n\tparams: EstimateFeeParams,\n): Promise<FeeEstimation[]> {\n\tconst payloadHex = bytesToHex(serializePayload(params.transaction.payload));\n\tconst txHex = bytesToHex(serializeTransaction(params.transaction));\n\n\tconst data = await client.request(\"/v2/fees/transaction\", {\n\t\tmethod: \"POST\",\n\t\tbody: {\n\t\t\testimated_len: Math.ceil(txHex.length / 2),\n\t\t\ttransaction_payload: `0x${payloadHex}`,\n\t\t},\n\t});\n\n\t// biome-ignore lint/suspicious/noExplicitAny: interop boundary or dynamic-shape value where typing adds friction without runtime safety\n\treturn (data.estimations ?? []).map((e: any) => ({\n\t\tfeeRate: e.fee_rate,\n\t\tfee: e.fee,\n\t}));\n}\n",
6
+ "import type { Client } from \"../../clients/types.ts\";\n\nexport type GetNonceParams = {\n\taddress: string;\n};\n\nexport type GetNonceResult = {\n\tnonce: bigint;\n\tpossibleNextNonce: bigint;\n};\n\nexport async function getNonce(\n\tclient: Client,\n\tparams: GetNonceParams,\n): Promise<bigint> {\n\tconst data = await client.request(`/v2/accounts/${params.address}`, {\n\t\tmethod: \"GET\",\n\t});\n\treturn BigInt(data.nonce);\n}\n",
7
+ "import { BaseError } from \"./base.ts\";\n\nexport class TransactionError extends BaseError {\n\toverride name = \"TransactionError\";\n}\n\nexport class BroadcastError extends BaseError {\n\toverride name = \"BroadcastError\";\n\ttxid?: string;\n\treason?: string;\n\n\tconstructor(\n\t\tmessage: string,\n\t\toptions?: { cause?: Error; txid?: string; reason?: string },\n\t) {\n\t\tsuper(message, options);\n\t\tthis.txid = options?.txid;\n\t\tthis.reason = options?.reason;\n\t}\n}\n\nexport class SerializationError extends BaseError {\n\toverride name = \"SerializationError\";\n}\n\nexport class SigningError extends BaseError {\n\toverride name = \"SigningError\";\n}\n",
8
+ "import type { Client } from \"../../clients/types.ts\";\nimport { BroadcastError } from \"../../errors/transaction.ts\";\nimport { getTransactionId } from \"../../transactions/signer.ts\";\nimport type { StacksTransaction } from \"../../transactions/types.ts\";\nimport { serializeTransaction } from \"../../transactions/wire/serialize.ts\";\nimport { bytesToHex } from \"../../utils/encoding.ts\";\n\nexport type SendTransactionParams = {\n\ttransaction: StacksTransaction;\n\tattachment?: Uint8Array | string;\n};\n\nexport type SendTransactionResult = {\n\ttxid: string;\n};\n\n/** Broadcast a signed transaction to the network */\nexport async function sendTransaction(\n\tclient: Client,\n\tparams: SendTransactionParams,\n): Promise<SendTransactionResult> {\n\tconst hex = bytesToHex(serializeTransaction(params.transaction));\n\n\tconst body: Record<string, string> = { tx: hex };\n\tif (params.attachment) {\n\t\tbody.attachment =\n\t\t\ttypeof params.attachment === \"string\"\n\t\t\t\t? params.attachment\n\t\t\t\t: bytesToHex(params.attachment);\n\t}\n\n\tconst data = await client.request(\"/v2/transactions\", {\n\t\tmethod: \"POST\",\n\t\tbody,\n\t});\n\n\tif (data.error) {\n\t\tthrow new BroadcastError(data.reason ?? data.error, {\n\t\t\treason: data.reason,\n\t\t});\n\t}\n\n\tconst txid =\n\t\ttypeof data === \"string\"\n\t\t\t? data.replace(/\"/g, \"\")\n\t\t\t: (data.txid ?? getTransactionId(params.transaction));\n\n\treturn { txid };\n}\n",
9
+ "import type { Client } from \"../../clients/types.ts\";\nimport { BroadcastError } from \"../../errors/transaction.ts\";\nimport type { StacksTransaction } from \"../../transactions/types.ts\";\nimport { getNonce } from \"../public/getNonce.ts\";\nimport { sendTransaction } from \"./sendTransaction.ts\";\n\n/**\n * Provides the confirmed on-chain nonce floor for an address.\n *\n * The default {@link jsonRpcSource} reads the configured node's `/v2/accounts`\n * endpoint — node-agnostic, no Hiro dependency. Other sources (mempool-aware,\n * first-party Index) can be swapped in without touching the manager.\n */\nexport type NonceManagerSource = {\n\tget(params: { client: Client; address: string }): Promise<bigint>;\n};\n\n/**\n * Holds per-address allocation state and hands out the next nonce.\n *\n * `reserve` MUST be atomic per `key`: two concurrent reservations for the same\n * key must never return the same value. The in-memory {@link memoryStore}\n * serializes with a per-key promise chain; a persisted store (Redis `INCR`,\n * Postgres `SELECT ... FOR UPDATE`) becomes the cross-process lock for the\n * multi-builder / smart-wallet-as-a-service case.\n */\nexport type NonceStore = {\n\t/**\n\t * Reserve the next nonce for `key`. `getFloor` reads the confirmed on-chain\n\t * nonce; it is only invoked when the store has no tracked value (cold start\n\t * or after {@link NonceStore.reset}).\n\t */\n\treserve(key: string, getFloor: () => Promise<bigint>): Promise<bigint>;\n\t/** Forget tracked state for `key` so the next reserve re-syncs from the floor. */\n\treset(key: string): void | Promise<void>;\n\t/**\n\t * Return the next nonce that {@link NonceStore.reserve} would hand out for\n\t * `key` WITHOUT consuming it, or `undefined` if `key` is untracked. Used by\n\t * {@link reconcileNonce} to detect drift. Optional — stores that omit it\n\t * simply opt out of reconciliation.\n\t */\n\tpeek?(key: string): Promise<bigint | undefined> | bigint | undefined;\n};\n\n/** Allocates mempool-safe sequential nonces across rapid broadcasts from one account. */\nexport type NonceManager = {\n\tconsume(params: { client: Client; address: string }): Promise<bigint>;\n\treset(params: { client: Client; address: string }): void | Promise<void>;\n\t/** Next nonce that {@link NonceManager.consume} would return without consuming it, or `undefined` if untracked. */\n\tpeek(params: {\n\t\tclient: Client;\n\t\taddress: string;\n\t}): Promise<bigint | undefined>;\n};\n\nexport type CreateNonceManagerParams = {\n\tsource?: NonceManagerSource;\n\tstore?: NonceStore;\n};\n\n/** Confirmed-nonce source backed by the configured node's `/v2/accounts` RPC (no Hiro dependency). */\nexport function jsonRpcSource(): NonceManagerSource {\n\treturn {\n\t\tget: ({ client, address }) => getNonce(client, { address }),\n\t};\n}\n\n/**\n * In-memory, single-process store. Tracks the next nonce per key and serializes\n * concurrent reservations with a per-key promise chain.\n *\n * Correct only within one process — swap in a persisted store for multi-process\n * deployments that share a signing key.\n */\nexport function memoryStore(): NonceStore {\n\tconst next = new Map<string, bigint>();\n\tconst locks = new Map<string, Promise<unknown>>();\n\n\tfunction withLock<T>(key: string, fn: () => Promise<T>): Promise<T> {\n\t\tconst prev = locks.get(key) ?? Promise.resolve();\n\t\t// Chain onto the prior reservation regardless of how it settled, so a\n\t\t// rejected reserve never wedges the key.\n\t\tconst run = prev.then(fn, fn);\n\t\tlocks.set(\n\t\t\tkey,\n\t\t\trun.catch(() => {}),\n\t\t);\n\t\treturn run;\n\t}\n\n\treturn {\n\t\treserve(key, getFloor) {\n\t\t\treturn withLock(key, async () => {\n\t\t\t\tlet current = next.get(key);\n\t\t\t\tif (current === undefined) current = await getFloor();\n\t\t\t\tnext.set(key, current + 1n);\n\t\t\t\treturn current;\n\t\t\t});\n\t\t},\n\t\treset(key) {\n\t\t\tnext.delete(key);\n\t\t},\n\t\tpeek(key) {\n\t\t\treturn next.get(key);\n\t\t},\n\t};\n}\n\nfunction nonceKey(client: Client, address: string): string {\n\treturn `${client.chain?.id ?? \"stacks\"}:${address}`;\n}\n\n/**\n * Create a nonce manager that floors on a confirmed-nonce {@link NonceManagerSource}\n * and increments a {@link NonceStore} on every {@link NonceManager.consume}.\n *\n * Defaults to {@link jsonRpcSource} + {@link memoryStore} — node-agnostic,\n * single-process, zero external dependencies.\n */\nexport function createNonceManager(\n\tparams: CreateNonceManagerParams = {},\n): NonceManager {\n\tconst source = params.source ?? jsonRpcSource();\n\tconst store = params.store ?? memoryStore();\n\n\treturn {\n\t\tconsume({ client, address }) {\n\t\t\treturn store.reserve(nonceKey(client, address), () =>\n\t\t\t\tsource.get({ client, address }),\n\t\t\t);\n\t\t},\n\t\treset({ client, address }) {\n\t\t\treturn store.reset(nonceKey(client, address));\n\t\t},\n\t\tasync peek({ client, address }) {\n\t\t\treturn store.peek?.(nonceKey(client, address));\n\t\t},\n\t};\n}\n\n/** Resolve the next nonce via the client's nonce manager, falling back to a confirmed read. */\nexport async function resolveNonce(\n\tclient: Client,\n\taddress: string,\n): Promise<bigint> {\n\tif (client.nonceManager)\n\t\treturn client.nonceManager.consume({ client, address });\n\treturn getNonce(client, { address });\n}\n\nexport type ReconcileNonceParams = {\n\tclient: Client;\n\taddress: string;\n\t/** Authoritative (ideally mempool-aware) source to reconcile against. */\n\tsource: NonceManagerSource;\n\t/**\n\t * Allow resetting DOWNWARD when the source's next nonce is below what the\n\t * store tracks — i.e. a previously-allocated tx is no longer pending or\n\t * confirmed (dropped/GC'd), so its nonce should be reused. Default `true`.\n\t *\n\t * Downward resets rely on `source` being current: with a go-forward mempool\n\t * source that lags broadcast, run reconciliation on an interval comfortably\n\t * longer than mempool propagation so a still-missing tx is genuinely dropped.\n\t * Set `false` for upward-only reconciliation (always safe).\n\t */\n\tdownward?: boolean;\n};\n\nexport type ReconcileNonceResult = {\n\t/** Whether the manager was reset (drift detected). */\n\treset: boolean;\n\t/** Authoritative next nonce from `source`. */\n\tauthoritative: bigint;\n\t/** Next nonce the store tracked, or `undefined` if untracked. */\n\ttracked: bigint | undefined;\n};\n\n/**\n * Reconcile a tracked nonce against an authoritative source, healing silent\n * drift that produces no broadcast error (a dropped/GC'd mempool tx leaving the\n * counter overshot, or the chain advancing past the local view).\n *\n * When the source's next nonce differs from the tracked value, the manager is\n * {@link NonceManager.reset}; the next `consume` re-seeds from `source`. A no-op\n * if the store is untracked or does not implement `peek`.\n */\nexport async function reconcileNonce(\n\tmanager: NonceManager,\n\tparams: ReconcileNonceParams,\n): Promise<ReconcileNonceResult> {\n\tconst { client, address, source } = params;\n\tconst downward = params.downward ?? true;\n\n\tconst authoritative = await source.get({ client, address });\n\tconst tracked = await manager.peek({ client, address });\n\n\tif (tracked === undefined || authoritative === tracked) {\n\t\treturn { reset: false, authoritative, tracked };\n\t}\n\tif (authoritative < tracked && !downward) {\n\t\treturn { reset: false, authoritative, tracked };\n\t}\n\n\tawait manager.reset({ client, address });\n\treturn { reset: true, authoritative, tracked };\n}\n\nexport type StartNonceReconcilerParams = {\n\tclient: Client;\n\taddresses: string[];\n\tsource: NonceManagerSource;\n\t/** Reconcile interval in ms. Default 60_000. Keep well above mempool propagation. */\n\tintervalMs?: number;\n\tdownward?: boolean;\n\t/** Per-address callback after each reconcile (observability). */\n\tonReconcile?: (address: string, result: ReconcileNonceResult) => void;\n\t/** Per-address error callback; reconciliation continues on the next tick. */\n\tonError?: (address: string, error: unknown) => void;\n};\n\n/**\n * Run {@link reconcileNonce} on a timer for a set of addresses.\n *\n * SINGLE-WRITER: run this in exactly ONE process. With a shared persisted store,\n * a reconciler resetting the counter while other workers allocate is racy — keep\n * reconciliation on one designated process and let the others only allocate.\n *\n * Returns a handle; call `stop()` to clear the timer.\n */\nexport function startNonceReconciler(\n\tmanager: NonceManager,\n\tparams: StartNonceReconcilerParams,\n): { stop: () => void } {\n\tconst { client, addresses, source } = params;\n\tconst intervalMs = params.intervalMs ?? 60_000;\n\n\tconst tick = async () => {\n\t\tfor (const address of addresses) {\n\t\t\ttry {\n\t\t\t\tconst result = await reconcileNonce(manager, {\n\t\t\t\t\tclient,\n\t\t\t\t\taddress,\n\t\t\t\t\tsource,\n\t\t\t\t\tdownward: params.downward,\n\t\t\t\t});\n\t\t\t\tparams.onReconcile?.(address, result);\n\t\t\t} catch (error) {\n\t\t\t\tparams.onError?.(address, error);\n\t\t\t}\n\t\t}\n\t};\n\n\tconst timer = setInterval(tick, intervalMs);\n\t// Don't keep the event loop alive solely for reconciliation (Node/Bun).\n\t(timer as { unref?: () => void }).unref?.();\n\n\treturn {\n\t\tstop: () => clearInterval(timer),\n\t};\n}\n\n/** True when a broadcast was rejected for a nonce conflict (`ConflictingNonceInMempool`, `BadNonce`). */\nexport function isNonceConflictError(error: unknown): boolean {\n\tif (!(error instanceof BroadcastError)) return false;\n\tconst haystack = `${error.reason ?? \"\"} ${error.message}`.toLowerCase();\n\treturn haystack.includes(\"nonce\");\n}\n\n/**\n * Broadcast a signed transaction; on a nonce-conflict rejection, reset the\n * manager so the next build re-syncs to the confirmed floor.\n */\nexport async function broadcastWithNonceReset(\n\tclient: Client,\n\tparams: { transaction: StacksTransaction; address: string },\n): Promise<string> {\n\ttry {\n\t\tconst result = await sendTransaction(client, {\n\t\t\ttransaction: params.transaction,\n\t\t});\n\t\treturn result.txid;\n\t} catch (error) {\n\t\tif (client.nonceManager && isNonceConflictError(error)) {\n\t\t\tawait client.nonceManager.reset({ client, address: params.address });\n\t\t}\n\t\tthrow error;\n\t}\n}\n",
10
+ "import type { ProviderAccount } from \"../../accounts/types.ts\";\nimport type { Account } from \"../../clients/types.ts\";\n\nexport function isProviderAccount(\n\taccount: Account,\n): account is ProviderAccount {\n\treturn account.type === \"provider\";\n}\n"
11
+ ],
12
+ "mappings": "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",
13
+ "debugId": "201E1A3233967AC964756E2164756E21",
14
+ "names": []
15
+ }
@@ -2,7 +2,7 @@ import {
2
2
  estimateFee,
3
3
  isProviderAccount,
4
4
  resolveNonce
5
- } from "./stacks-gxhznn3h.js";
5
+ } from "./stacks-r3mqgw2d.js";
6
6
  import {
7
7
  AuthType,
8
8
  createSingleSigSpendingCondition,
@@ -48,4 +48,4 @@ async function sponsorTransaction(client, params) {
48
48
  export { sponsorTransaction };
49
49
 
50
50
  //# debugId=B5D2826EE8DC537B64756E2164756E21
51
- //# sourceMappingURL=stacks-ffsv2t3t.js.map
51
+ //# sourceMappingURL=stacks-s6v8k4j5.js.map
@@ -3,7 +3,7 @@ import {
3
3
  estimateFee,
4
4
  isProviderAccount,
5
5
  resolveNonce
6
- } from "./stacks-gxhznn3h.js";
6
+ } from "./stacks-r3mqgw2d.js";
7
7
  import {
8
8
  buildContractCall,
9
9
  signTransactionWithAccount
@@ -93,4 +93,4 @@ async function callContract(client, params) {
93
93
  export { getMapEntry, readContract, callContract };
94
94
 
95
95
  //# debugId=A951FF5E2E3C07E364756E2164756E21
96
- //# sourceMappingURL=stacks-a9cn5ehj.js.map
96
+ //# sourceMappingURL=stacks-txh6dadn.js.map
@@ -94,6 +94,9 @@ function memoryStore() {
94
94
  },
95
95
  reset(key) {
96
96
  next.delete(key);
97
+ },
98
+ peek(key) {
99
+ return next.get(key);
97
100
  }
98
101
  };
99
102
  }
@@ -109,6 +112,9 @@ function createNonceManager(params = {}) {
109
112
  },
110
113
  reset({ client, address }) {
111
114
  return store.reset(nonceKey(client, address));
115
+ },
116
+ async peek({ client, address }) {
117
+ return store.peek?.(nonceKey(client, address));
112
118
  }
113
119
  };
114
120
  }
@@ -117,6 +123,44 @@ async function resolveNonce(client, address) {
117
123
  return client.nonceManager.consume({ client, address });
118
124
  return getNonce(client, { address });
119
125
  }
126
+ async function reconcileNonce(manager, params) {
127
+ const { client, address, source } = params;
128
+ const downward = params.downward ?? true;
129
+ const authoritative = await source.get({ client, address });
130
+ const tracked = await manager.peek({ client, address });
131
+ if (tracked === undefined || authoritative === tracked) {
132
+ return { reset: false, authoritative, tracked };
133
+ }
134
+ if (authoritative < tracked && !downward) {
135
+ return { reset: false, authoritative, tracked };
136
+ }
137
+ await manager.reset({ client, address });
138
+ return { reset: true, authoritative, tracked };
139
+ }
140
+ function startNonceReconciler(manager, params) {
141
+ const { client, addresses, source } = params;
142
+ const intervalMs = params.intervalMs ?? 60000;
143
+ const tick = async () => {
144
+ for (const address of addresses) {
145
+ try {
146
+ const result = await reconcileNonce(manager, {
147
+ client,
148
+ address,
149
+ source,
150
+ downward: params.downward
151
+ });
152
+ params.onReconcile?.(address, result);
153
+ } catch (error) {
154
+ params.onError?.(address, error);
155
+ }
156
+ }
157
+ };
158
+ const timer = setInterval(tick, intervalMs);
159
+ timer.unref?.();
160
+ return {
161
+ stop: () => clearInterval(timer)
162
+ };
163
+ }
120
164
  function isNonceConflictError(error) {
121
165
  if (!(error instanceof BroadcastError))
122
166
  return false;
@@ -142,5 +186,5 @@ function isProviderAccount(account) {
142
186
  return account.type === "provider";
143
187
  }
144
188
 
145
- //# debugId=2EE5DF005EA5A08464756E2164756E21
146
- //# sourceMappingURL=stacks-1wra341e.cjs.map
189
+ //# debugId=DB5D2C7E88D037B264756E2164756E21
190
+ //# sourceMappingURL=stacks-wb06pevp.cjs.map
@@ -0,0 +1,15 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/actions/public/estimateFee.ts", "../src/actions/public/getNonce.ts", "../src/errors/transaction.ts", "../src/actions/wallet/sendTransaction.ts", "../src/actions/wallet/nonceManager.ts", "../src/actions/wallet/utils.ts"],
4
+ "sourcesContent": [
5
+ "import type { Client } from \"../../clients/types.ts\";\nimport type { StacksTransaction } from \"../../transactions/types.ts\";\nimport {\n\tserializePayload,\n\tserializeTransaction,\n} from \"../../transactions/wire/serialize.ts\";\nimport { bytesToHex } from \"../../utils/encoding.ts\";\n\nexport type EstimateFeeParams = {\n\ttransaction: StacksTransaction;\n};\n\nexport type FeeEstimation = {\n\tfeeRate: number;\n\tfee: number;\n};\n\nexport async function estimateFee(\n\tclient: Client,\n\tparams: EstimateFeeParams,\n): Promise<FeeEstimation[]> {\n\tconst payloadHex = bytesToHex(serializePayload(params.transaction.payload));\n\tconst txHex = bytesToHex(serializeTransaction(params.transaction));\n\n\tconst data = await client.request(\"/v2/fees/transaction\", {\n\t\tmethod: \"POST\",\n\t\tbody: {\n\t\t\testimated_len: Math.ceil(txHex.length / 2),\n\t\t\ttransaction_payload: `0x${payloadHex}`,\n\t\t},\n\t});\n\n\t// biome-ignore lint/suspicious/noExplicitAny: interop boundary or dynamic-shape value where typing adds friction without runtime safety\n\treturn (data.estimations ?? []).map((e: any) => ({\n\t\tfeeRate: e.fee_rate,\n\t\tfee: e.fee,\n\t}));\n}\n",
6
+ "import type { Client } from \"../../clients/types.ts\";\n\nexport type GetNonceParams = {\n\taddress: string;\n};\n\nexport type GetNonceResult = {\n\tnonce: bigint;\n\tpossibleNextNonce: bigint;\n};\n\nexport async function getNonce(\n\tclient: Client,\n\tparams: GetNonceParams,\n): Promise<bigint> {\n\tconst data = await client.request(`/v2/accounts/${params.address}`, {\n\t\tmethod: \"GET\",\n\t});\n\treturn BigInt(data.nonce);\n}\n",
7
+ "import { BaseError } from \"./base.ts\";\n\nexport class TransactionError extends BaseError {\n\toverride name = \"TransactionError\";\n}\n\nexport class BroadcastError extends BaseError {\n\toverride name = \"BroadcastError\";\n\ttxid?: string;\n\treason?: string;\n\n\tconstructor(\n\t\tmessage: string,\n\t\toptions?: { cause?: Error; txid?: string; reason?: string },\n\t) {\n\t\tsuper(message, options);\n\t\tthis.txid = options?.txid;\n\t\tthis.reason = options?.reason;\n\t}\n}\n\nexport class SerializationError extends BaseError {\n\toverride name = \"SerializationError\";\n}\n\nexport class SigningError extends BaseError {\n\toverride name = \"SigningError\";\n}\n",
8
+ "import type { Client } from \"../../clients/types.ts\";\nimport { BroadcastError } from \"../../errors/transaction.ts\";\nimport { getTransactionId } from \"../../transactions/signer.ts\";\nimport type { StacksTransaction } from \"../../transactions/types.ts\";\nimport { serializeTransaction } from \"../../transactions/wire/serialize.ts\";\nimport { bytesToHex } from \"../../utils/encoding.ts\";\n\nexport type SendTransactionParams = {\n\ttransaction: StacksTransaction;\n\tattachment?: Uint8Array | string;\n};\n\nexport type SendTransactionResult = {\n\ttxid: string;\n};\n\n/** Broadcast a signed transaction to the network */\nexport async function sendTransaction(\n\tclient: Client,\n\tparams: SendTransactionParams,\n): Promise<SendTransactionResult> {\n\tconst hex = bytesToHex(serializeTransaction(params.transaction));\n\n\tconst body: Record<string, string> = { tx: hex };\n\tif (params.attachment) {\n\t\tbody.attachment =\n\t\t\ttypeof params.attachment === \"string\"\n\t\t\t\t? params.attachment\n\t\t\t\t: bytesToHex(params.attachment);\n\t}\n\n\tconst data = await client.request(\"/v2/transactions\", {\n\t\tmethod: \"POST\",\n\t\tbody,\n\t});\n\n\tif (data.error) {\n\t\tthrow new BroadcastError(data.reason ?? data.error, {\n\t\t\treason: data.reason,\n\t\t});\n\t}\n\n\tconst txid =\n\t\ttypeof data === \"string\"\n\t\t\t? data.replace(/\"/g, \"\")\n\t\t\t: (data.txid ?? getTransactionId(params.transaction));\n\n\treturn { txid };\n}\n",
9
+ "import type { Client } from \"../../clients/types.ts\";\nimport { BroadcastError } from \"../../errors/transaction.ts\";\nimport type { StacksTransaction } from \"../../transactions/types.ts\";\nimport { getNonce } from \"../public/getNonce.ts\";\nimport { sendTransaction } from \"./sendTransaction.ts\";\n\n/**\n * Provides the confirmed on-chain nonce floor for an address.\n *\n * The default {@link jsonRpcSource} reads the configured node's `/v2/accounts`\n * endpoint — node-agnostic, no Hiro dependency. Other sources (mempool-aware,\n * first-party Index) can be swapped in without touching the manager.\n */\nexport type NonceManagerSource = {\n\tget(params: { client: Client; address: string }): Promise<bigint>;\n};\n\n/**\n * Holds per-address allocation state and hands out the next nonce.\n *\n * `reserve` MUST be atomic per `key`: two concurrent reservations for the same\n * key must never return the same value. The in-memory {@link memoryStore}\n * serializes with a per-key promise chain; a persisted store (Redis `INCR`,\n * Postgres `SELECT ... FOR UPDATE`) becomes the cross-process lock for the\n * multi-builder / smart-wallet-as-a-service case.\n */\nexport type NonceStore = {\n\t/**\n\t * Reserve the next nonce for `key`. `getFloor` reads the confirmed on-chain\n\t * nonce; it is only invoked when the store has no tracked value (cold start\n\t * or after {@link NonceStore.reset}).\n\t */\n\treserve(key: string, getFloor: () => Promise<bigint>): Promise<bigint>;\n\t/** Forget tracked state for `key` so the next reserve re-syncs from the floor. */\n\treset(key: string): void | Promise<void>;\n\t/**\n\t * Return the next nonce that {@link NonceStore.reserve} would hand out for\n\t * `key` WITHOUT consuming it, or `undefined` if `key` is untracked. Used by\n\t * {@link reconcileNonce} to detect drift. Optional — stores that omit it\n\t * simply opt out of reconciliation.\n\t */\n\tpeek?(key: string): Promise<bigint | undefined> | bigint | undefined;\n};\n\n/** Allocates mempool-safe sequential nonces across rapid broadcasts from one account. */\nexport type NonceManager = {\n\tconsume(params: { client: Client; address: string }): Promise<bigint>;\n\treset(params: { client: Client; address: string }): void | Promise<void>;\n\t/** Next nonce that {@link NonceManager.consume} would return without consuming it, or `undefined` if untracked. */\n\tpeek(params: {\n\t\tclient: Client;\n\t\taddress: string;\n\t}): Promise<bigint | undefined>;\n};\n\nexport type CreateNonceManagerParams = {\n\tsource?: NonceManagerSource;\n\tstore?: NonceStore;\n};\n\n/** Confirmed-nonce source backed by the configured node's `/v2/accounts` RPC (no Hiro dependency). */\nexport function jsonRpcSource(): NonceManagerSource {\n\treturn {\n\t\tget: ({ client, address }) => getNonce(client, { address }),\n\t};\n}\n\n/**\n * In-memory, single-process store. Tracks the next nonce per key and serializes\n * concurrent reservations with a per-key promise chain.\n *\n * Correct only within one process — swap in a persisted store for multi-process\n * deployments that share a signing key.\n */\nexport function memoryStore(): NonceStore {\n\tconst next = new Map<string, bigint>();\n\tconst locks = new Map<string, Promise<unknown>>();\n\n\tfunction withLock<T>(key: string, fn: () => Promise<T>): Promise<T> {\n\t\tconst prev = locks.get(key) ?? Promise.resolve();\n\t\t// Chain onto the prior reservation regardless of how it settled, so a\n\t\t// rejected reserve never wedges the key.\n\t\tconst run = prev.then(fn, fn);\n\t\tlocks.set(\n\t\t\tkey,\n\t\t\trun.catch(() => {}),\n\t\t);\n\t\treturn run;\n\t}\n\n\treturn {\n\t\treserve(key, getFloor) {\n\t\t\treturn withLock(key, async () => {\n\t\t\t\tlet current = next.get(key);\n\t\t\t\tif (current === undefined) current = await getFloor();\n\t\t\t\tnext.set(key, current + 1n);\n\t\t\t\treturn current;\n\t\t\t});\n\t\t},\n\t\treset(key) {\n\t\t\tnext.delete(key);\n\t\t},\n\t\tpeek(key) {\n\t\t\treturn next.get(key);\n\t\t},\n\t};\n}\n\nfunction nonceKey(client: Client, address: string): string {\n\treturn `${client.chain?.id ?? \"stacks\"}:${address}`;\n}\n\n/**\n * Create a nonce manager that floors on a confirmed-nonce {@link NonceManagerSource}\n * and increments a {@link NonceStore} on every {@link NonceManager.consume}.\n *\n * Defaults to {@link jsonRpcSource} + {@link memoryStore} — node-agnostic,\n * single-process, zero external dependencies.\n */\nexport function createNonceManager(\n\tparams: CreateNonceManagerParams = {},\n): NonceManager {\n\tconst source = params.source ?? jsonRpcSource();\n\tconst store = params.store ?? memoryStore();\n\n\treturn {\n\t\tconsume({ client, address }) {\n\t\t\treturn store.reserve(nonceKey(client, address), () =>\n\t\t\t\tsource.get({ client, address }),\n\t\t\t);\n\t\t},\n\t\treset({ client, address }) {\n\t\t\treturn store.reset(nonceKey(client, address));\n\t\t},\n\t\tasync peek({ client, address }) {\n\t\t\treturn store.peek?.(nonceKey(client, address));\n\t\t},\n\t};\n}\n\n/** Resolve the next nonce via the client's nonce manager, falling back to a confirmed read. */\nexport async function resolveNonce(\n\tclient: Client,\n\taddress: string,\n): Promise<bigint> {\n\tif (client.nonceManager)\n\t\treturn client.nonceManager.consume({ client, address });\n\treturn getNonce(client, { address });\n}\n\nexport type ReconcileNonceParams = {\n\tclient: Client;\n\taddress: string;\n\t/** Authoritative (ideally mempool-aware) source to reconcile against. */\n\tsource: NonceManagerSource;\n\t/**\n\t * Allow resetting DOWNWARD when the source's next nonce is below what the\n\t * store tracks — i.e. a previously-allocated tx is no longer pending or\n\t * confirmed (dropped/GC'd), so its nonce should be reused. Default `true`.\n\t *\n\t * Downward resets rely on `source` being current: with a go-forward mempool\n\t * source that lags broadcast, run reconciliation on an interval comfortably\n\t * longer than mempool propagation so a still-missing tx is genuinely dropped.\n\t * Set `false` for upward-only reconciliation (always safe).\n\t */\n\tdownward?: boolean;\n};\n\nexport type ReconcileNonceResult = {\n\t/** Whether the manager was reset (drift detected). */\n\treset: boolean;\n\t/** Authoritative next nonce from `source`. */\n\tauthoritative: bigint;\n\t/** Next nonce the store tracked, or `undefined` if untracked. */\n\ttracked: bigint | undefined;\n};\n\n/**\n * Reconcile a tracked nonce against an authoritative source, healing silent\n * drift that produces no broadcast error (a dropped/GC'd mempool tx leaving the\n * counter overshot, or the chain advancing past the local view).\n *\n * When the source's next nonce differs from the tracked value, the manager is\n * {@link NonceManager.reset}; the next `consume` re-seeds from `source`. A no-op\n * if the store is untracked or does not implement `peek`.\n */\nexport async function reconcileNonce(\n\tmanager: NonceManager,\n\tparams: ReconcileNonceParams,\n): Promise<ReconcileNonceResult> {\n\tconst { client, address, source } = params;\n\tconst downward = params.downward ?? true;\n\n\tconst authoritative = await source.get({ client, address });\n\tconst tracked = await manager.peek({ client, address });\n\n\tif (tracked === undefined || authoritative === tracked) {\n\t\treturn { reset: false, authoritative, tracked };\n\t}\n\tif (authoritative < tracked && !downward) {\n\t\treturn { reset: false, authoritative, tracked };\n\t}\n\n\tawait manager.reset({ client, address });\n\treturn { reset: true, authoritative, tracked };\n}\n\nexport type StartNonceReconcilerParams = {\n\tclient: Client;\n\taddresses: string[];\n\tsource: NonceManagerSource;\n\t/** Reconcile interval in ms. Default 60_000. Keep well above mempool propagation. */\n\tintervalMs?: number;\n\tdownward?: boolean;\n\t/** Per-address callback after each reconcile (observability). */\n\tonReconcile?: (address: string, result: ReconcileNonceResult) => void;\n\t/** Per-address error callback; reconciliation continues on the next tick. */\n\tonError?: (address: string, error: unknown) => void;\n};\n\n/**\n * Run {@link reconcileNonce} on a timer for a set of addresses.\n *\n * SINGLE-WRITER: run this in exactly ONE process. With a shared persisted store,\n * a reconciler resetting the counter while other workers allocate is racy — keep\n * reconciliation on one designated process and let the others only allocate.\n *\n * Returns a handle; call `stop()` to clear the timer.\n */\nexport function startNonceReconciler(\n\tmanager: NonceManager,\n\tparams: StartNonceReconcilerParams,\n): { stop: () => void } {\n\tconst { client, addresses, source } = params;\n\tconst intervalMs = params.intervalMs ?? 60_000;\n\n\tconst tick = async () => {\n\t\tfor (const address of addresses) {\n\t\t\ttry {\n\t\t\t\tconst result = await reconcileNonce(manager, {\n\t\t\t\t\tclient,\n\t\t\t\t\taddress,\n\t\t\t\t\tsource,\n\t\t\t\t\tdownward: params.downward,\n\t\t\t\t});\n\t\t\t\tparams.onReconcile?.(address, result);\n\t\t\t} catch (error) {\n\t\t\t\tparams.onError?.(address, error);\n\t\t\t}\n\t\t}\n\t};\n\n\tconst timer = setInterval(tick, intervalMs);\n\t// Don't keep the event loop alive solely for reconciliation (Node/Bun).\n\t(timer as { unref?: () => void }).unref?.();\n\n\treturn {\n\t\tstop: () => clearInterval(timer),\n\t};\n}\n\n/** True when a broadcast was rejected for a nonce conflict (`ConflictingNonceInMempool`, `BadNonce`). */\nexport function isNonceConflictError(error: unknown): boolean {\n\tif (!(error instanceof BroadcastError)) return false;\n\tconst haystack = `${error.reason ?? \"\"} ${error.message}`.toLowerCase();\n\treturn haystack.includes(\"nonce\");\n}\n\n/**\n * Broadcast a signed transaction; on a nonce-conflict rejection, reset the\n * manager so the next build re-syncs to the confirmed floor.\n */\nexport async function broadcastWithNonceReset(\n\tclient: Client,\n\tparams: { transaction: StacksTransaction; address: string },\n): Promise<string> {\n\ttry {\n\t\tconst result = await sendTransaction(client, {\n\t\t\ttransaction: params.transaction,\n\t\t});\n\t\treturn result.txid;\n\t} catch (error) {\n\t\tif (client.nonceManager && isNonceConflictError(error)) {\n\t\t\tawait client.nonceManager.reset({ client, address: params.address });\n\t\t}\n\t\tthrow error;\n\t}\n}\n",
10
+ "import type { ProviderAccount } from \"../../accounts/types.ts\";\nimport type { Account } from \"../../clients/types.ts\";\n\nexport function isProviderAccount(\n\taccount: Account,\n): account is ProviderAccount {\n\treturn account.type === \"provider\";\n}\n"
11
+ ],
12
+ "mappings": "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",
13
+ "debugId": "DB5D2C7E88D037B264756E2164756E21",
14
+ "names": []
15
+ }
@@ -287,6 +287,11 @@ type NonceManager = {
287
287
  client: Client
288
288
  address: string
289
289
  }): void | Promise<void>
290
+ /** Next nonce that {@link NonceManager.consume} would return without consuming it, or `undefined` if untracked. */
291
+ peek(params: {
292
+ client: Client
293
+ address: string
294
+ }): Promise<bigint | undefined>
290
295
  };
291
296
  /** Full chain descriptor used by clients and transports for network-aware operations. */
292
297
  type StacksChain = {
@@ -287,6 +287,11 @@ type NonceManager = {
287
287
  client: Client
288
288
  address: string
289
289
  }): void | Promise<void>
290
+ /** Next nonce that {@link NonceManager.consume} would return without consuming it, or `undefined` if untracked. */
291
+ peek(params: {
292
+ client: Client
293
+ address: string
294
+ }): Promise<bigint | undefined>
290
295
  };
291
296
  /** Full chain descriptor used by clients and transports for network-aware operations. */
292
297
  type StacksChain = {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  ContractResponseError,
3
3
  getContract
4
- } from "../../shared/stacks-hr5rg2et.js";
4
+ } from "../../shared/stacks-k96f5g1a.js";
5
5
  import {
6
6
  deployContract,
7
7
  getAccountInfo,
@@ -15,12 +15,12 @@ import {
15
15
  simulateCall,
16
16
  simulateTransaction,
17
17
  transferStx
18
- } from "../../shared/stacks-yb8xesdm.js";
18
+ } from "../../shared/stacks-a48qj7ss.js";
19
19
  import {
20
20
  callContract,
21
21
  getMapEntry,
22
22
  readContract
23
- } from "../../shared/stacks-a9cn5ehj.js";
23
+ } from "../../shared/stacks-txh6dadn.js";
24
24
  import {
25
25
  watchAddress,
26
26
  watchAddressBalance,
@@ -31,13 +31,13 @@ import {
31
31
  } from "../../shared/stacks-tjjnkt3r.js";
32
32
  import {
33
33
  sponsorTransaction
34
- } from "../../shared/stacks-ffsv2t3t.js";
34
+ } from "../../shared/stacks-s6v8k4j5.js";
35
35
  import {
36
36
  estimateFee,
37
37
  getNonce,
38
38
  isProviderAccount,
39
39
  sendTransaction
40
- } from "../../shared/stacks-gxhznn3h.js";
40
+ } from "../../shared/stacks-r3mqgw2d.js";
41
41
  import"../../shared/stacks-709tra19.js";
42
42
  import"../../shared/stacks-g7ffp8aj.js";
43
43
  import"../../shared/stacks-wqgepfab.js";
@@ -37,6 +37,11 @@ type NonceManager = {
37
37
  client: Client
38
38
  address: string
39
39
  }): void | Promise<void>
40
+ /** Next nonce that {@link NonceManager.consume} would return without consuming it, or `undefined` if untracked. */
41
+ peek(params: {
42
+ client: Client
43
+ address: string
44
+ }): Promise<bigint | undefined>
40
45
  };
41
46
  /** Full chain descriptor used by clients and transports for network-aware operations. */
42
47
  type StacksChain = {
@@ -37,6 +37,11 @@ type NonceManager = {
37
37
  client: Client
38
38
  address: string
39
39
  }): void | Promise<void>
40
+ /** Next nonce that {@link NonceManager.consume} would return without consuming it, or `undefined` if untracked. */
41
+ peek(params: {
42
+ client: Client
43
+ address: string
44
+ }): Promise<bigint | undefined>
40
45
  };
41
46
  /** Full chain descriptor used by clients and transports for network-aware operations. */
42
47
  type StacksChain = {
@@ -3,9 +3,9 @@ import"../../shared/stacks-kg1npstf.js";
3
3
  import {
4
4
  ContractResponseError,
5
5
  getContract
6
- } from "../../shared/stacks-hr5rg2et.js";
7
- import"../../shared/stacks-a9cn5ehj.js";
8
- import"../../shared/stacks-gxhznn3h.js";
6
+ } from "../../shared/stacks-k96f5g1a.js";
7
+ import"../../shared/stacks-txh6dadn.js";
8
+ import"../../shared/stacks-r3mqgw2d.js";
9
9
  import"../../shared/stacks-709tra19.js";
10
10
  import"../../shared/stacks-g7ffp8aj.js";
11
11
  import"../../shared/stacks-z53fwfcm.js";
@@ -4,22 +4,28 @@ __export(exports_src, {
4
4
  webSocket: () => webSocket,
5
5
  walletActions: () => walletActions,
6
6
  testnet: () => testnet,
7
+ startNonceReconciler: () => startNonceReconciler,
7
8
  resolveNonce: () => resolveNonce,
8
9
  redisStore: () => redisStore,
10
+ reconcileNonce: () => reconcileNonce,
9
11
  publicActions: () => publicActions,
10
12
  providerToAccount: () => providerToAccount,
11
13
  postgresStore: () => postgresStore,
12
14
  parseStx: () => parseStx,
13
15
  on: () => exports_on,
16
+ nextFreeNonce: () => nextFreeNonce,
14
17
  multisigActions: () => multisigActions,
15
18
  mocknet: () => mocknet,
19
+ mempoolAwareSource: () => mempoolAwareSource,
16
20
  memoryStore: () => memoryStore,
17
21
  mainnet: () => mainnet,
18
22
  jsonRpcSource: () => jsonRpcSource,
19
23
  isValidAddress: () => isValidAddress,
20
24
  isNonceConflictError: () => isNonceConflictError,
21
25
  isAddressEqual: () => isAddressEqual,
26
+ indexSource: () => indexSource,
22
27
  http: () => http,
28
+ hiroNonceSource: () => hiroNonceSource,
23
29
  getContractAddress: () => getContractAddress,
24
30
  formatStx: () => formatStx,
25
31
  fallback: () => fallback,
@@ -266,6 +272,10 @@ function redisStore(params) {
266
272
  },
267
273
  async reset(key) {
268
274
  await redis.send("DEL", [prefix + key]);
275
+ },
276
+ async peek(key) {
277
+ const v = await redis.send("GET", [prefix + key]);
278
+ return v == null ? undefined : BigInt(v);
269
279
  }
270
280
  };
271
281
  }
@@ -296,6 +306,97 @@ function postgresStore(params) {
296
306
  async reset(key) {
297
307
  await ensureTable();
298
308
  await sql`DELETE FROM stacks_nonce_state WHERE key = ${key}`;
309
+ },
310
+ async peek(key) {
311
+ await ensureTable();
312
+ const rows = await sql`SELECT next FROM stacks_nonce_state WHERE key = ${key}`;
313
+ const row = rows[0];
314
+ return row ? BigInt(String(row.next)) : undefined;
315
+ }
316
+ };
317
+ }
318
+ // src/actions/wallet/nonceSources.ts
319
+ function resolveFetch(fetchImpl) {
320
+ const f = fetchImpl ?? globalThis.fetch;
321
+ if (!f)
322
+ throw new Error("No fetch implementation available; pass `fetchImpl`");
323
+ return f;
324
+ }
325
+ function nextFreeNonce(confirmed, pending) {
326
+ const taken = new Set(pending.filter((n2) => n2 >= confirmed).map((n2) => n2.toString()));
327
+ let n = confirmed;
328
+ while (taken.has(n.toString()))
329
+ n += 1n;
330
+ return n;
331
+ }
332
+ function mempoolAwareSource(params) {
333
+ const getConfirmed = params.getConfirmed ?? (({ client, address }) => getNonce(client, { address }));
334
+ return {
335
+ async get({ client, address }) {
336
+ const confirmed = await getConfirmed({ client, address });
337
+ let pending = [];
338
+ try {
339
+ pending = await params.getPending({ client, address });
340
+ } catch {
341
+ return confirmed;
342
+ }
343
+ return nextFreeNonce(confirmed, pending);
344
+ }
345
+ };
346
+ }
347
+ function indexSource(params = {}) {
348
+ const baseUrl = (params.baseUrl ?? "https://api.secondlayer.tools").replace(/\/$/, "");
349
+ const fetchImpl = resolveFetch(params.fetchImpl);
350
+ const maxPages = params.maxPages ?? 10;
351
+ return mempoolAwareSource({
352
+ getConfirmed: params.getConfirmed,
353
+ async getPending({ address }) {
354
+ const out = [];
355
+ let cursor;
356
+ let pages = 0;
357
+ do {
358
+ const url = new URL(`${baseUrl}/v1/index/mempool`);
359
+ url.searchParams.set("sender", address);
360
+ url.searchParams.set("limit", "200");
361
+ if (cursor)
362
+ url.searchParams.set("from_cursor", cursor);
363
+ const res = await fetchImpl(url, {
364
+ headers: params.apiKey ? { authorization: `Bearer ${params.apiKey}` } : undefined
365
+ });
366
+ if (!res.ok) {
367
+ throw new Error(`indexSource: /v1/index/mempool ${res.status}`);
368
+ }
369
+ const data = await res.json();
370
+ for (const tx of data.mempool ?? []) {
371
+ if (tx.nonce != null)
372
+ out.push(BigInt(tx.nonce));
373
+ }
374
+ cursor = data.next_cursor ?? undefined;
375
+ pages += 1;
376
+ } while (cursor && pages < maxPages);
377
+ if (cursor) {
378
+ console.warn(`indexSource: stopped paging mempool for ${address} after ${maxPages} pages; pending set may be incomplete`);
379
+ }
380
+ return out;
381
+ }
382
+ });
383
+ }
384
+ function hiroNonceSource(params) {
385
+ const baseUrl = params.baseUrl.replace(/\/$/, "");
386
+ const fetchImpl = resolveFetch(params.fetchImpl);
387
+ return {
388
+ async get({ address }) {
389
+ const res = await fetchImpl(`${baseUrl}/extended/v1/address/${address}/nonces`, {
390
+ headers: params.apiKey ? { "x-api-key": params.apiKey } : undefined
391
+ });
392
+ if (!res.ok) {
393
+ throw new Error(`hiroNonceSource: /nonces ${res.status}`);
394
+ }
395
+ const data = await res.json();
396
+ const missing = (data.detected_missing_nonces ?? []).map((n) => BigInt(n)).sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
397
+ if (missing[0] !== undefined)
398
+ return missing[0];
399
+ return BigInt(data.possible_next_nonce ?? 0);
299
400
  }
300
401
  };
301
402
  }
@@ -717,5 +818,5 @@ class ReadOnlyCallError extends BaseError {
717
818
  name = "ReadOnlyCallError";
718
819
  }
719
820
 
720
- //# debugId=6ED05F818443D6E764756E2164756E21
821
+ //# debugId=FF2669570662824964756E2164756E21
721
822
  //# sourceMappingURL=index.cjs.map