@secondlayer/stacks 2.6.0 → 2.8.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.
- package/README.md +70 -0
- package/dist/shared/{stacks-ffsv2t3t.js → stacks-1qmx9kt8.js} +2 -2
- package/dist/shared/{stacks-a9cn5ehj.js → stacks-cmyyp5c4.js} +2 -2
- package/dist/shared/{stacks-yb8xesdm.js → stacks-deprc4zq.js} +3 -3
- package/dist/shared/{stacks-hr5rg2et.js → stacks-jkykwc61.js} +2 -2
- package/dist/shared/{stacks-gxhznn3h.js → stacks-ttbq8emk.js} +54 -4
- package/dist/shared/stacks-ttbq8emk.js.map +15 -0
- package/dist/shared/{stacks-1wra341e.cjs → stacks-xmsms921.cjs} +53 -3
- package/dist/shared/stacks-xmsms921.cjs.map +15 -0
- package/dist/src/actions/index.d.cts +5 -0
- package/dist/src/actions/index.d.ts +5 -0
- package/dist/src/actions/index.js +5 -5
- package/dist/src/bns/index.d.cts +5 -0
- package/dist/src/bns/index.d.ts +5 -0
- package/dist/src/bns/index.js +3 -3
- package/dist/src/index.cjs +102 -1
- package/dist/src/index.cjs.map +5 -4
- package/dist/src/index.d.cts +150 -1
- package/dist/src/index.d.ts +150 -1
- package/dist/src/index.js +109 -6
- package/dist/src/index.js.map +5 -4
- package/dist/src/pox/index.d.cts +5 -0
- package/dist/src/pox/index.d.ts +5 -0
- package/dist/src/pox/index.js +3 -3
- package/dist/src/sbtc/index.d.cts +5 -0
- package/dist/src/sbtc/index.d.ts +5 -0
- package/dist/src/sbtc/index.js +3 -3
- package/dist/src/stackingdao/index.d.cts +5 -0
- package/dist/src/stackingdao/index.d.ts +5 -0
- package/dist/src/stackingdao/index.js +3 -3
- package/dist/src/subscriptions/index.d.cts +5 -0
- package/dist/src/subscriptions/index.d.ts +5 -0
- package/dist/src/tools/index.cjs +6 -2
- package/dist/src/tools/index.cjs.map +4 -4
- package/dist/src/tools/index.d.cts +5 -0
- package/dist/src/tools/index.d.ts +5 -0
- package/dist/src/tools/index.js +6 -2
- package/dist/src/tools/index.js.map +4 -4
- package/dist/src/x402/index.d.cts +5 -0
- package/dist/src/x402/index.d.ts +5 -0
- package/dist/src/x402/index.js +2 -2
- package/package.json +1 -1
- package/dist/shared/stacks-1wra341e.cjs.map +0 -15
- package/dist/shared/stacks-gxhznn3h.js.map +0 -15
- /package/dist/shared/{stacks-ffsv2t3t.js.map → stacks-1qmx9kt8.js.map} +0 -0
- /package/dist/shared/{stacks-a9cn5ehj.js.map → stacks-cmyyp5c4.js.map} +0 -0
- /package/dist/shared/{stacks-yb8xesdm.js.map → stacks-deprc4zq.js.map} +0 -0
- /package/dist/shared/{stacks-hr5rg2et.js.map → stacks-jkykwc61.js.map} +0 -0
package/README.md
CHANGED
|
@@ -43,6 +43,11 @@ These ship and work but get no further investment — they may be removed in a
|
|
|
43
43
|
future major. Prefer Hiro's maintained `@stacks/*` ecosystem for wallet-side
|
|
44
44
|
work; Secondlayer is a data-infrastructure company, not a wallet SDK vendor.
|
|
45
45
|
|
|
46
|
+
Nonce coordination (below) is the exception — it is supported and maintained:
|
|
47
|
+
it's mempool-aware (built on Secondlayer's data plane) and solves a real
|
|
48
|
+
multi-broadcast gap, which is why it lives here rather than being deferred to
|
|
49
|
+
`@stacks/*`.
|
|
50
|
+
|
|
46
51
|
| Module | Description |
|
|
47
52
|
|---|---|
|
|
48
53
|
| `@secondlayer/stacks/connect` | Wallet connection — browser extensions + `setProvider` |
|
|
@@ -52,6 +57,71 @@ work; Secondlayer is a data-infrastructure company, not a wallet SDK vendor.
|
|
|
52
57
|
| `@secondlayer/stacks/pox` | PoX stacking — solo and delegated |
|
|
53
58
|
| `@secondlayer/stacks/stackingdao` | StackingDAO liquid staking (STX/stSTX) |
|
|
54
59
|
|
|
60
|
+
## Nonce management
|
|
61
|
+
|
|
62
|
+
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.
|
|
63
|
+
|
|
64
|
+
Attach a nonce manager and the SDK hands out sequential nonces across rapid broadcasts:
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
import { createWalletClient, http, createNonceManager } from "@secondlayer/stacks";
|
|
68
|
+
import { mainnet } from "@secondlayer/stacks/chains";
|
|
69
|
+
import { privateKeyToAccount } from "@secondlayer/stacks/accounts";
|
|
70
|
+
|
|
71
|
+
const client = createWalletClient({
|
|
72
|
+
chain: mainnet,
|
|
73
|
+
transport: http(), // any node — no Secondlayer dependency
|
|
74
|
+
account: privateKeyToAccount(process.env.KEY!),
|
|
75
|
+
nonceManager: createNonceManager(), // jsonRpcSource + in-memory store
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// 20 back-to-back transfers → nonces n, n+1, …, n+19 — no collisions
|
|
79
|
+
await Promise.all(
|
|
80
|
+
recipients.map((to) => client.transferStx({ to, amount: 1000n })),
|
|
81
|
+
);
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Passing an explicit `nonce` always bypasses the manager. The defaults are node-agnostic and in-memory — zero external dependencies.
|
|
85
|
+
|
|
86
|
+
### Multiple processes / smart wallets
|
|
87
|
+
|
|
88
|
+
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:
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
import { createNonceManager, redisStore } from "@secondlayer/stacks";
|
|
92
|
+
|
|
93
|
+
const nonceManager = createNonceManager({
|
|
94
|
+
store: redisStore({ redis: new Bun.RedisClient(process.env.REDIS_URL!) }),
|
|
95
|
+
});
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
`postgresStore({ sql })` works the same way. Bring your own client — no global `Bun` reference, so the store stays runtime-agnostic.
|
|
99
|
+
|
|
100
|
+
### Mempool-aware sources (optional)
|
|
101
|
+
|
|
102
|
+
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`:
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
import {
|
|
106
|
+
createNonceManager,
|
|
107
|
+
indexSource,
|
|
108
|
+
startNonceReconciler,
|
|
109
|
+
} from "@secondlayer/stacks";
|
|
110
|
+
|
|
111
|
+
// indexSource() | hiroNonceSource({ baseUrl }) | mempoolAwareSource({ getPending })
|
|
112
|
+
const source = indexSource();
|
|
113
|
+
const nonceManager = createNonceManager({ source });
|
|
114
|
+
|
|
115
|
+
// Optional: periodically heal silently-dropped txs (run in ONE process)
|
|
116
|
+
const reconciler = startNonceReconciler(nonceManager, {
|
|
117
|
+
client,
|
|
118
|
+
addresses: [account.address],
|
|
119
|
+
source,
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Everything here is opt-in. With no `source`/`store`, the manager depends only on your node.
|
|
124
|
+
|
|
55
125
|
## WalletConnect v2
|
|
56
126
|
|
|
57
127
|
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.
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
estimateFee,
|
|
3
3
|
isProviderAccount,
|
|
4
4
|
resolveNonce
|
|
5
|
-
} from "./stacks-
|
|
5
|
+
} from "./stacks-ttbq8emk.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-
|
|
51
|
+
//# sourceMappingURL=stacks-1qmx9kt8.js.map
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
estimateFee,
|
|
4
4
|
isProviderAccount,
|
|
5
5
|
resolveNonce
|
|
6
|
-
} from "./stacks-
|
|
6
|
+
} from "./stacks-ttbq8emk.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-
|
|
96
|
+
//# sourceMappingURL=stacks-cmyyp5c4.js.map
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
readContract
|
|
3
|
-
} from "./stacks-
|
|
3
|
+
} from "./stacks-cmyyp5c4.js";
|
|
4
4
|
import {
|
|
5
5
|
broadcastWithNonceReset,
|
|
6
6
|
estimateFee,
|
|
7
7
|
isProviderAccount,
|
|
8
8
|
resolveNonce
|
|
9
|
-
} from "./stacks-
|
|
9
|
+
} from "./stacks-ttbq8emk.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-
|
|
312
|
+
//# sourceMappingURL=stacks-deprc4zq.js.map
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
callContract,
|
|
3
3
|
getMapEntry,
|
|
4
4
|
readContract
|
|
5
|
-
} from "./stacks-
|
|
5
|
+
} from "./stacks-cmyyp5c4.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-
|
|
134
|
+
//# sourceMappingURL=stacks-jkykwc61.js.map
|
|
@@ -32,7 +32,11 @@ async function getNonce(client, params) {
|
|
|
32
32
|
const data = await client.request(`/v2/accounts/${params.address}`, {
|
|
33
33
|
method: "GET"
|
|
34
34
|
});
|
|
35
|
-
|
|
35
|
+
const nonce = data?.nonce;
|
|
36
|
+
if (typeof nonce !== "number" && typeof nonce !== "string") {
|
|
37
|
+
throw new Error(`getNonce: unexpected /v2/accounts response for ${params.address} (missing numeric nonce)`);
|
|
38
|
+
}
|
|
39
|
+
return BigInt(nonce);
|
|
36
40
|
}
|
|
37
41
|
|
|
38
42
|
// src/errors/transaction.ts
|
|
@@ -106,6 +110,9 @@ function memoryStore() {
|
|
|
106
110
|
},
|
|
107
111
|
reset(key) {
|
|
108
112
|
next.delete(key);
|
|
113
|
+
},
|
|
114
|
+
peek(key) {
|
|
115
|
+
return next.get(key);
|
|
109
116
|
}
|
|
110
117
|
};
|
|
111
118
|
}
|
|
@@ -121,6 +128,9 @@ function createNonceManager(params = {}) {
|
|
|
121
128
|
},
|
|
122
129
|
reset({ client, address }) {
|
|
123
130
|
return store.reset(nonceKey(client, address));
|
|
131
|
+
},
|
|
132
|
+
async peek({ client, address }) {
|
|
133
|
+
return store.peek?.(nonceKey(client, address));
|
|
124
134
|
}
|
|
125
135
|
};
|
|
126
136
|
}
|
|
@@ -129,6 +139,46 @@ async function resolveNonce(client, address) {
|
|
|
129
139
|
return client.nonceManager.consume({ client, address });
|
|
130
140
|
return getNonce(client, { address });
|
|
131
141
|
}
|
|
142
|
+
async function reconcileNonce(manager, params) {
|
|
143
|
+
const { client, address, source } = params;
|
|
144
|
+
const downward = params.downward ?? true;
|
|
145
|
+
const authoritative = await source.get({ client, address });
|
|
146
|
+
const tracked = await manager.peek({ client, address });
|
|
147
|
+
if (tracked === undefined || authoritative === tracked) {
|
|
148
|
+
return { reset: false, authoritative, tracked };
|
|
149
|
+
}
|
|
150
|
+
if (authoritative < tracked && !downward) {
|
|
151
|
+
return { reset: false, authoritative, tracked };
|
|
152
|
+
}
|
|
153
|
+
await manager.reset({ client, address });
|
|
154
|
+
return { reset: true, authoritative, tracked };
|
|
155
|
+
}
|
|
156
|
+
function startNonceReconciler(manager, params) {
|
|
157
|
+
const { client, addresses, source } = params;
|
|
158
|
+
const intervalMs = params.intervalMs ?? 60000;
|
|
159
|
+
const tick = async () => {
|
|
160
|
+
for (const address of addresses) {
|
|
161
|
+
try {
|
|
162
|
+
const result = await reconcileNonce(manager, {
|
|
163
|
+
client,
|
|
164
|
+
address,
|
|
165
|
+
source,
|
|
166
|
+
downward: params.downward
|
|
167
|
+
});
|
|
168
|
+
params.onReconcile?.(address, result);
|
|
169
|
+
} catch (error) {
|
|
170
|
+
try {
|
|
171
|
+
params.onError?.(address, error);
|
|
172
|
+
} catch {}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
const timer = setInterval(tick, intervalMs);
|
|
177
|
+
timer.unref?.();
|
|
178
|
+
return {
|
|
179
|
+
stop: () => clearInterval(timer)
|
|
180
|
+
};
|
|
181
|
+
}
|
|
132
182
|
function isNonceConflictError(error) {
|
|
133
183
|
if (!(error instanceof BroadcastError))
|
|
134
184
|
return false;
|
|
@@ -154,7 +204,7 @@ function isProviderAccount(account) {
|
|
|
154
204
|
return account.type === "provider";
|
|
155
205
|
}
|
|
156
206
|
|
|
157
|
-
export { estimateFee, getNonce, TransactionError, BroadcastError, SerializationError, SigningError, sendTransaction, jsonRpcSource, memoryStore, createNonceManager, resolveNonce, isNonceConflictError, broadcastWithNonceReset, isProviderAccount };
|
|
207
|
+
export { estimateFee, getNonce, TransactionError, BroadcastError, SerializationError, SigningError, sendTransaction, jsonRpcSource, memoryStore, createNonceManager, resolveNonce, reconcileNonce, startNonceReconciler, isNonceConflictError, broadcastWithNonceReset, isProviderAccount };
|
|
158
208
|
|
|
159
|
-
//# debugId=
|
|
160
|
-
//# sourceMappingURL=stacks-
|
|
209
|
+
//# debugId=5FE30A330D92FC6964756E2164756E21
|
|
210
|
+
//# sourceMappingURL=stacks-ttbq8emk.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\tconst nonce = (data as { nonce?: unknown })?.nonce;\n\tif (typeof nonce !== \"number\" && typeof nonce !== \"string\") {\n\t\tthrow new Error(\n\t\t\t`getNonce: unexpected /v2/accounts response for ${params.address} (missing numeric nonce)`,\n\t\t);\n\t}\n\treturn BigInt(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\ttry {\n\t\t\t\t\tparams.onError?.(address, error);\n\t\t\t\t} catch {\n\t\t\t\t\t// A throwing onError callback must not abort the reconcile loop\n\t\t\t\t\t// or surface as an unhandled rejection on the interval timer.\n\t\t\t\t}\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": ";;;;;;;;;;;;;AAiBA,eAAsB,WAAW,CAChC,QACA,QAC2B;AAAA,EAC3B,MAAM,aAAa,WAAW,iBAAiB,OAAO,YAAY,OAAO,CAAC;AAAA,EAC1E,MAAM,QAAQ,WAAW,qBAAqB,OAAO,WAAW,CAAC;AAAA,EAEjE,MAAM,OAAO,MAAM,OAAO,QAAQ,wBAAwB;AAAA,IACzD,QAAQ;AAAA,IACR,MAAM;AAAA,MACL,eAAe,KAAK,KAAK,MAAM,SAAS,CAAC;AAAA,MACzC,qBAAqB,KAAK;AAAA,IAC3B;AAAA,EACD,CAAC;AAAA,EAGD,QAAQ,KAAK,eAAe,CAAC,GAAG,IAAI,CAAC,OAAY;AAAA,IAChD,SAAS,EAAE;AAAA,IACX,KAAK,EAAE;AAAA,EACR,EAAE;AAAA;;;ACzBH,eAAsB,QAAQ,CAC7B,QACA,QACkB;AAAA,EAClB,MAAM,OAAO,MAAM,OAAO,QAAQ,gBAAgB,OAAO,WAAW;AAAA,IACnE,QAAQ;AAAA,EACT,CAAC;AAAA,EACD,MAAM,QAAS,MAA8B;AAAA,EAC7C,IAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAAU;AAAA,IAC3D,MAAM,IAAI,MACT,kDAAkD,OAAO,iCAC1D;AAAA,EACD;AAAA,EACA,OAAO,OAAO,KAAK;AAAA;;;ACtBb,MAAM,yBAAyB,UAAU;AAAA,EACtC,OAAO;AACjB;AAAA;AAEO,MAAM,uBAAuB,UAAU;AAAA,EACpC,OAAO;AAAA,EAChB;AAAA,EACA;AAAA,EAEA,WAAW,CACV,SACA,SACC;AAAA,IACD,MAAM,SAAS,OAAO;AAAA,IACtB,KAAK,OAAO,SAAS;AAAA,IACrB,KAAK,SAAS,SAAS;AAAA;AAEzB;AAAA;AAEO,MAAM,2BAA2B,UAAU;AAAA,EACxC,OAAO;AACjB;AAAA;AAEO,MAAM,qBAAqB,UAAU;AAAA,EAClC,OAAO;AACjB;;;ACVA,eAAsB,eAAe,CACpC,QACA,QACiC;AAAA,EACjC,MAAM,MAAM,WAAW,qBAAqB,OAAO,WAAW,CAAC;AAAA,EAE/D,MAAM,OAA+B,EAAE,IAAI,IAAI;AAAA,EAC/C,IAAI,OAAO,YAAY;AAAA,IACtB,KAAK,aACJ,OAAO,OAAO,eAAe,WAC1B,OAAO,aACP,WAAW,OAAO,UAAU;AAAA,EACjC;AAAA,EAEA,MAAM,OAAO,MAAM,OAAO,QAAQ,oBAAoB;AAAA,IACrD,QAAQ;AAAA,IACR;AAAA,EACD,CAAC;AAAA,EAED,IAAI,KAAK,OAAO;AAAA,IACf,MAAM,IAAI,eAAe,KAAK,UAAU,KAAK,OAAO;AAAA,MACnD,QAAQ,KAAK;AAAA,IACd,CAAC;AAAA,EACF;AAAA,EAEA,MAAM,OACL,OAAO,SAAS,WACb,KAAK,QAAQ,MAAM,EAAE,IACpB,KAAK,QAAQ,iBAAiB,OAAO,WAAW;AAAA,EAErD,OAAO,EAAE,KAAK;AAAA;;;ACcR,SAAS,aAAa,GAAuB;AAAA,EACnD,OAAO;AAAA,IACN,KAAK,GAAG,QAAQ,cAAc,SAAS,QAAQ,EAAE,QAAQ,CAAC;AAAA,EAC3D;AAAA;AAUM,SAAS,WAAW,GAAe;AAAA,EACzC,MAAM,OAAO,IAAI;AAAA,EACjB,MAAM,QAAQ,IAAI;AAAA,EAElB,SAAS,QAAW,CAAC,KAAa,IAAkC;AAAA,IACnE,MAAM,OAAO,MAAM,IAAI,GAAG,KAAK,QAAQ,QAAQ;AAAA,IAG/C,MAAM,MAAM,KAAK,KAAK,IAAI,EAAE;AAAA,IAC5B,MAAM,IACL,KACA,IAAI,MAAM,MAAM,EAAE,CACnB;AAAA,IACA,OAAO;AAAA;AAAA,EAGR,OAAO;AAAA,IACN,OAAO,CAAC,KAAK,UAAU;AAAA,MACtB,OAAO,SAAS,KAAK,YAAY;AAAA,QAChC,IAAI,UAAU,KAAK,IAAI,GAAG;AAAA,QAC1B,IAAI,YAAY;AAAA,UAAW,UAAU,MAAM,SAAS;AAAA,QACpD,KAAK,IAAI,KAAK,UAAU,EAAE;AAAA,QAC1B,OAAO;AAAA,OACP;AAAA;AAAA,IAEF,KAAK,CAAC,KAAK;AAAA,MACV,KAAK,OAAO,GAAG;AAAA;AAAA,IAEhB,IAAI,CAAC,KAAK;AAAA,MACT,OAAO,KAAK,IAAI,GAAG;AAAA;AAAA,EAErB;AAAA;AAGD,SAAS,QAAQ,CAAC,QAAgB,SAAyB;AAAA,EAC1D,OAAO,GAAG,OAAO,OAAO,MAAM,YAAY;AAAA;AAUpC,SAAS,kBAAkB,CACjC,SAAmC,CAAC,GACrB;AAAA,EACf,MAAM,SAAS,OAAO,UAAU,cAAc;AAAA,EAC9C,MAAM,QAAQ,OAAO,SAAS,YAAY;AAAA,EAE1C,OAAO;AAAA,IACN,OAAO,GAAG,QAAQ,WAAW;AAAA,MAC5B,OAAO,MAAM,QAAQ,SAAS,QAAQ,OAAO,GAAG,MAC/C,OAAO,IAAI,EAAE,QAAQ,QAAQ,CAAC,CAC/B;AAAA;AAAA,IAED,KAAK,GAAG,QAAQ,WAAW;AAAA,MAC1B,OAAO,MAAM,MAAM,SAAS,QAAQ,OAAO,CAAC;AAAA;AAAA,SAEvC,KAAI,GAAG,QAAQ,WAAW;AAAA,MAC/B,OAAO,MAAM,OAAO,SAAS,QAAQ,OAAO,CAAC;AAAA;AAAA,EAE/C;AAAA;AAID,eAAsB,YAAY,CACjC,QACA,SACkB;AAAA,EAClB,IAAI,OAAO;AAAA,IACV,OAAO,OAAO,aAAa,QAAQ,EAAE,QAAQ,QAAQ,CAAC;AAAA,EACvD,OAAO,SAAS,QAAQ,EAAE,QAAQ,CAAC;AAAA;AAuCpC,eAAsB,cAAc,CACnC,SACA,QACgC;AAAA,EAChC,QAAQ,QAAQ,SAAS,WAAW;AAAA,EACpC,MAAM,WAAW,OAAO,YAAY;AAAA,EAEpC,MAAM,gBAAgB,MAAM,OAAO,IAAI,EAAE,QAAQ,QAAQ,CAAC;AAAA,EAC1D,MAAM,UAAU,MAAM,QAAQ,KAAK,EAAE,QAAQ,QAAQ,CAAC;AAAA,EAEtD,IAAI,YAAY,aAAa,kBAAkB,SAAS;AAAA,IACvD,OAAO,EAAE,OAAO,OAAO,eAAe,QAAQ;AAAA,EAC/C;AAAA,EACA,IAAI,gBAAgB,WAAW,CAAC,UAAU;AAAA,IACzC,OAAO,EAAE,OAAO,OAAO,eAAe,QAAQ;AAAA,EAC/C;AAAA,EAEA,MAAM,QAAQ,MAAM,EAAE,QAAQ,QAAQ,CAAC;AAAA,EACvC,OAAO,EAAE,OAAO,MAAM,eAAe,QAAQ;AAAA;AAyBvC,SAAS,oBAAoB,CACnC,SACA,QACuB;AAAA,EACvB,QAAQ,QAAQ,WAAW,WAAW;AAAA,EACtC,MAAM,aAAa,OAAO,cAAc;AAAA,EAExC,MAAM,OAAO,YAAY;AAAA,IACxB,WAAW,WAAW,WAAW;AAAA,MAChC,IAAI;AAAA,QACH,MAAM,SAAS,MAAM,eAAe,SAAS;AAAA,UAC5C;AAAA,UACA;AAAA,UACA;AAAA,UACA,UAAU,OAAO;AAAA,QAClB,CAAC;AAAA,QACD,OAAO,cAAc,SAAS,MAAM;AAAA,QACnC,OAAO,OAAO;AAAA,QACf,IAAI;AAAA,UACH,OAAO,UAAU,SAAS,KAAK;AAAA,UAC9B,MAAM;AAAA;AAAA,IAKV;AAAA;AAAA,EAGD,MAAM,QAAQ,YAAY,MAAM,UAAU;AAAA,EAEzC,MAAiC,QAAQ;AAAA,EAE1C,OAAO;AAAA,IACN,MAAM,MAAM,cAAc,KAAK;AAAA,EAChC;AAAA;AAIM,SAAS,oBAAoB,CAAC,OAAyB;AAAA,EAC7D,IAAI,EAAE,iBAAiB;AAAA,IAAiB,OAAO;AAAA,EAC/C,MAAM,WAAW,GAAG,MAAM,UAAU,MAAM,MAAM,UAAU,YAAY;AAAA,EACtE,OAAO,SAAS,SAAS,OAAO;AAAA;AAOjC,eAAsB,uBAAuB,CAC5C,QACA,QACkB;AAAA,EAClB,IAAI;AAAA,IACH,MAAM,SAAS,MAAM,gBAAgB,QAAQ;AAAA,MAC5C,aAAa,OAAO;AAAA,IACrB,CAAC;AAAA,IACD,OAAO,OAAO;AAAA,IACb,OAAO,OAAO;AAAA,IACf,IAAI,OAAO,gBAAgB,qBAAqB,KAAK,GAAG;AAAA,MACvD,MAAM,OAAO,aAAa,MAAM,EAAE,QAAQ,SAAS,OAAO,QAAQ,CAAC;AAAA,IACpE;AAAA,IACA,MAAM;AAAA;AAAA;;;AC/RD,SAAS,iBAAiB,CAChC,SAC6B;AAAA,EAC7B,OAAO,QAAQ,SAAS;AAAA;",
|
|
13
|
+
"debugId": "5FE30A330D92FC6964756E2164756E21",
|
|
14
|
+
"names": []
|
|
15
|
+
}
|
|
@@ -20,7 +20,11 @@ async function getNonce(client, params) {
|
|
|
20
20
|
const data = await client.request(`/v2/accounts/${params.address}`, {
|
|
21
21
|
method: "GET"
|
|
22
22
|
});
|
|
23
|
-
|
|
23
|
+
const nonce = data?.nonce;
|
|
24
|
+
if (typeof nonce !== "number" && typeof nonce !== "string") {
|
|
25
|
+
throw new Error(`getNonce: unexpected /v2/accounts response for ${params.address} (missing numeric nonce)`);
|
|
26
|
+
}
|
|
27
|
+
return BigInt(nonce);
|
|
24
28
|
}
|
|
25
29
|
|
|
26
30
|
// src/errors/transaction.ts
|
|
@@ -94,6 +98,9 @@ function memoryStore() {
|
|
|
94
98
|
},
|
|
95
99
|
reset(key) {
|
|
96
100
|
next.delete(key);
|
|
101
|
+
},
|
|
102
|
+
peek(key) {
|
|
103
|
+
return next.get(key);
|
|
97
104
|
}
|
|
98
105
|
};
|
|
99
106
|
}
|
|
@@ -109,6 +116,9 @@ function createNonceManager(params = {}) {
|
|
|
109
116
|
},
|
|
110
117
|
reset({ client, address }) {
|
|
111
118
|
return store.reset(nonceKey(client, address));
|
|
119
|
+
},
|
|
120
|
+
async peek({ client, address }) {
|
|
121
|
+
return store.peek?.(nonceKey(client, address));
|
|
112
122
|
}
|
|
113
123
|
};
|
|
114
124
|
}
|
|
@@ -117,6 +127,46 @@ async function resolveNonce(client, address) {
|
|
|
117
127
|
return client.nonceManager.consume({ client, address });
|
|
118
128
|
return getNonce(client, { address });
|
|
119
129
|
}
|
|
130
|
+
async function reconcileNonce(manager, params) {
|
|
131
|
+
const { client, address, source } = params;
|
|
132
|
+
const downward = params.downward ?? true;
|
|
133
|
+
const authoritative = await source.get({ client, address });
|
|
134
|
+
const tracked = await manager.peek({ client, address });
|
|
135
|
+
if (tracked === undefined || authoritative === tracked) {
|
|
136
|
+
return { reset: false, authoritative, tracked };
|
|
137
|
+
}
|
|
138
|
+
if (authoritative < tracked && !downward) {
|
|
139
|
+
return { reset: false, authoritative, tracked };
|
|
140
|
+
}
|
|
141
|
+
await manager.reset({ client, address });
|
|
142
|
+
return { reset: true, authoritative, tracked };
|
|
143
|
+
}
|
|
144
|
+
function startNonceReconciler(manager, params) {
|
|
145
|
+
const { client, addresses, source } = params;
|
|
146
|
+
const intervalMs = params.intervalMs ?? 60000;
|
|
147
|
+
const tick = async () => {
|
|
148
|
+
for (const address of addresses) {
|
|
149
|
+
try {
|
|
150
|
+
const result = await reconcileNonce(manager, {
|
|
151
|
+
client,
|
|
152
|
+
address,
|
|
153
|
+
source,
|
|
154
|
+
downward: params.downward
|
|
155
|
+
});
|
|
156
|
+
params.onReconcile?.(address, result);
|
|
157
|
+
} catch (error) {
|
|
158
|
+
try {
|
|
159
|
+
params.onError?.(address, error);
|
|
160
|
+
} catch {}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
const timer = setInterval(tick, intervalMs);
|
|
165
|
+
timer.unref?.();
|
|
166
|
+
return {
|
|
167
|
+
stop: () => clearInterval(timer)
|
|
168
|
+
};
|
|
169
|
+
}
|
|
120
170
|
function isNonceConflictError(error) {
|
|
121
171
|
if (!(error instanceof BroadcastError))
|
|
122
172
|
return false;
|
|
@@ -142,5 +192,5 @@ function isProviderAccount(account) {
|
|
|
142
192
|
return account.type === "provider";
|
|
143
193
|
}
|
|
144
194
|
|
|
145
|
-
//# debugId=
|
|
146
|
-
//# sourceMappingURL=stacks-
|
|
195
|
+
//# debugId=8EDE13AECCE4AEBA64756E2164756E21
|
|
196
|
+
//# sourceMappingURL=stacks-xmsms921.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\tconst nonce = (data as { nonce?: unknown })?.nonce;\n\tif (typeof nonce !== \"number\" && typeof nonce !== \"string\") {\n\t\tthrow new Error(\n\t\t\t`getNonce: unexpected /v2/accounts response for ${params.address} (missing numeric nonce)`,\n\t\t);\n\t}\n\treturn BigInt(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\ttry {\n\t\t\t\t\tparams.onError?.(address, error);\n\t\t\t\t} catch {\n\t\t\t\t\t// A throwing onError callback must not abort the reconcile loop\n\t\t\t\t\t// or surface as an unhandled rejection on the interval timer.\n\t\t\t\t}\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": ";AAiBA,eAAsB,WAAW,CAChC,QACA,QAC2B;AAAA,EAC3B,MAAM,aAAa,WAAW,iBAAiB,OAAO,YAAY,OAAO,CAAC;AAAA,EAC1E,MAAM,QAAQ,WAAW,qBAAqB,OAAO,WAAW,CAAC;AAAA,EAEjE,MAAM,OAAO,MAAM,OAAO,QAAQ,wBAAwB;AAAA,IACzD,QAAQ;AAAA,IACR,MAAM;AAAA,MACL,eAAe,KAAK,KAAK,MAAM,SAAS,CAAC;AAAA,MACzC,qBAAqB,KAAK;AAAA,IAC3B;AAAA,EACD,CAAC;AAAA,EAGD,QAAQ,KAAK,eAAe,CAAC,GAAG,IAAI,CAAC,OAAY;AAAA,IAChD,SAAS,EAAE;AAAA,IACX,KAAK,EAAE;AAAA,EACR,EAAE;AAAA;;;ACzBH,eAAsB,QAAQ,CAC7B,QACA,QACkB;AAAA,EAClB,MAAM,OAAO,MAAM,OAAO,QAAQ,gBAAgB,OAAO,WAAW;AAAA,IACnE,QAAQ;AAAA,EACT,CAAC;AAAA,EACD,MAAM,QAAS,MAA8B;AAAA,EAC7C,IAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAAU;AAAA,IAC3D,MAAM,IAAI,MACT,kDAAkD,OAAO,iCAC1D;AAAA,EACD;AAAA,EACA,OAAO,OAAO,KAAK;AAAA;;;ACtBb,MAAM,yBAAyB,UAAU;AAAA,EACtC,OAAO;AACjB;AAAA;AAEO,MAAM,uBAAuB,UAAU;AAAA,EACpC,OAAO;AAAA,EAChB;AAAA,EACA;AAAA,EAEA,WAAW,CACV,SACA,SACC;AAAA,IACD,MAAM,SAAS,OAAO;AAAA,IACtB,KAAK,OAAO,SAAS;AAAA,IACrB,KAAK,SAAS,SAAS;AAAA;AAEzB;AAAA;AAEO,MAAM,2BAA2B,UAAU;AAAA,EACxC,OAAO;AACjB;AAAA;AAEO,MAAM,qBAAqB,UAAU;AAAA,EAClC,OAAO;AACjB;;;ACVA,eAAsB,eAAe,CACpC,QACA,QACiC;AAAA,EACjC,MAAM,MAAM,WAAW,qBAAqB,OAAO,WAAW,CAAC;AAAA,EAE/D,MAAM,OAA+B,EAAE,IAAI,IAAI;AAAA,EAC/C,IAAI,OAAO,YAAY;AAAA,IACtB,KAAK,aACJ,OAAO,OAAO,eAAe,WAC1B,OAAO,aACP,WAAW,OAAO,UAAU;AAAA,EACjC;AAAA,EAEA,MAAM,OAAO,MAAM,OAAO,QAAQ,oBAAoB;AAAA,IACrD,QAAQ;AAAA,IACR;AAAA,EACD,CAAC;AAAA,EAED,IAAI,KAAK,OAAO;AAAA,IACf,MAAM,IAAI,eAAe,KAAK,UAAU,KAAK,OAAO;AAAA,MACnD,QAAQ,KAAK;AAAA,IACd,CAAC;AAAA,EACF;AAAA,EAEA,MAAM,OACL,OAAO,SAAS,WACb,KAAK,QAAQ,MAAM,EAAE,IACpB,KAAK,QAAQ,iBAAiB,OAAO,WAAW;AAAA,EAErD,OAAO,EAAE,KAAK;AAAA;;;ACcR,SAAS,aAAa,GAAuB;AAAA,EACnD,OAAO;AAAA,IACN,KAAK,GAAG,QAAQ,cAAc,SAAS,QAAQ,EAAE,QAAQ,CAAC;AAAA,EAC3D;AAAA;AAUM,SAAS,WAAW,GAAe;AAAA,EACzC,MAAM,OAAO,IAAI;AAAA,EACjB,MAAM,QAAQ,IAAI;AAAA,EAElB,SAAS,QAAW,CAAC,KAAa,IAAkC;AAAA,IACnE,MAAM,OAAO,MAAM,IAAI,GAAG,KAAK,QAAQ,QAAQ;AAAA,IAG/C,MAAM,MAAM,KAAK,KAAK,IAAI,EAAE;AAAA,IAC5B,MAAM,IACL,KACA,IAAI,MAAM,MAAM,EAAE,CACnB;AAAA,IACA,OAAO;AAAA;AAAA,EAGR,OAAO;AAAA,IACN,OAAO,CAAC,KAAK,UAAU;AAAA,MACtB,OAAO,SAAS,KAAK,YAAY;AAAA,QAChC,IAAI,UAAU,KAAK,IAAI,GAAG;AAAA,QAC1B,IAAI,YAAY;AAAA,UAAW,UAAU,MAAM,SAAS;AAAA,QACpD,KAAK,IAAI,KAAK,UAAU,EAAE;AAAA,QAC1B,OAAO;AAAA,OACP;AAAA;AAAA,IAEF,KAAK,CAAC,KAAK;AAAA,MACV,KAAK,OAAO,GAAG;AAAA;AAAA,IAEhB,IAAI,CAAC,KAAK;AAAA,MACT,OAAO,KAAK,IAAI,GAAG;AAAA;AAAA,EAErB;AAAA;AAGD,SAAS,QAAQ,CAAC,QAAgB,SAAyB;AAAA,EAC1D,OAAO,GAAG,OAAO,OAAO,MAAM,YAAY;AAAA;AAUpC,SAAS,kBAAkB,CACjC,SAAmC,CAAC,GACrB;AAAA,EACf,MAAM,SAAS,OAAO,UAAU,cAAc;AAAA,EAC9C,MAAM,QAAQ,OAAO,SAAS,YAAY;AAAA,EAE1C,OAAO;AAAA,IACN,OAAO,GAAG,QAAQ,WAAW;AAAA,MAC5B,OAAO,MAAM,QAAQ,SAAS,QAAQ,OAAO,GAAG,MAC/C,OAAO,IAAI,EAAE,QAAQ,QAAQ,CAAC,CAC/B;AAAA;AAAA,IAED,KAAK,GAAG,QAAQ,WAAW;AAAA,MAC1B,OAAO,MAAM,MAAM,SAAS,QAAQ,OAAO,CAAC;AAAA;AAAA,SAEvC,KAAI,GAAG,QAAQ,WAAW;AAAA,MAC/B,OAAO,MAAM,OAAO,SAAS,QAAQ,OAAO,CAAC;AAAA;AAAA,EAE/C;AAAA;AAID,eAAsB,YAAY,CACjC,QACA,SACkB;AAAA,EAClB,IAAI,OAAO;AAAA,IACV,OAAO,OAAO,aAAa,QAAQ,EAAE,QAAQ,QAAQ,CAAC;AAAA,EACvD,OAAO,SAAS,QAAQ,EAAE,QAAQ,CAAC;AAAA;AAuCpC,eAAsB,cAAc,CACnC,SACA,QACgC;AAAA,EAChC,QAAQ,QAAQ,SAAS,WAAW;AAAA,EACpC,MAAM,WAAW,OAAO,YAAY;AAAA,EAEpC,MAAM,gBAAgB,MAAM,OAAO,IAAI,EAAE,QAAQ,QAAQ,CAAC;AAAA,EAC1D,MAAM,UAAU,MAAM,QAAQ,KAAK,EAAE,QAAQ,QAAQ,CAAC;AAAA,EAEtD,IAAI,YAAY,aAAa,kBAAkB,SAAS;AAAA,IACvD,OAAO,EAAE,OAAO,OAAO,eAAe,QAAQ;AAAA,EAC/C;AAAA,EACA,IAAI,gBAAgB,WAAW,CAAC,UAAU;AAAA,IACzC,OAAO,EAAE,OAAO,OAAO,eAAe,QAAQ;AAAA,EAC/C;AAAA,EAEA,MAAM,QAAQ,MAAM,EAAE,QAAQ,QAAQ,CAAC;AAAA,EACvC,OAAO,EAAE,OAAO,MAAM,eAAe,QAAQ;AAAA;AAyBvC,SAAS,oBAAoB,CACnC,SACA,QACuB;AAAA,EACvB,QAAQ,QAAQ,WAAW,WAAW;AAAA,EACtC,MAAM,aAAa,OAAO,cAAc;AAAA,EAExC,MAAM,OAAO,YAAY;AAAA,IACxB,WAAW,WAAW,WAAW;AAAA,MAChC,IAAI;AAAA,QACH,MAAM,SAAS,MAAM,eAAe,SAAS;AAAA,UAC5C;AAAA,UACA;AAAA,UACA;AAAA,UACA,UAAU,OAAO;AAAA,QAClB,CAAC;AAAA,QACD,OAAO,cAAc,SAAS,MAAM;AAAA,QACnC,OAAO,OAAO;AAAA,QACf,IAAI;AAAA,UACH,OAAO,UAAU,SAAS,KAAK;AAAA,UAC9B,MAAM;AAAA;AAAA,IAKV;AAAA;AAAA,EAGD,MAAM,QAAQ,YAAY,MAAM,UAAU;AAAA,EAEzC,MAAiC,QAAQ;AAAA,EAE1C,OAAO;AAAA,IACN,MAAM,MAAM,cAAc,KAAK;AAAA,EAChC;AAAA;AAIM,SAAS,oBAAoB,CAAC,OAAyB;AAAA,EAC7D,IAAI,EAAE,iBAAiB;AAAA,IAAiB,OAAO;AAAA,EAC/C,MAAM,WAAW,GAAG,MAAM,UAAU,MAAM,MAAM,UAAU,YAAY;AAAA,EACtE,OAAO,SAAS,SAAS,OAAO;AAAA;AAOjC,eAAsB,uBAAuB,CAC5C,QACA,QACkB;AAAA,EAClB,IAAI;AAAA,IACH,MAAM,SAAS,MAAM,gBAAgB,QAAQ;AAAA,MAC5C,aAAa,OAAO;AAAA,IACrB,CAAC;AAAA,IACD,OAAO,OAAO;AAAA,IACb,OAAO,OAAO;AAAA,IACf,IAAI,OAAO,gBAAgB,qBAAqB,KAAK,GAAG;AAAA,MACvD,MAAM,OAAO,aAAa,MAAM,EAAE,QAAQ,SAAS,OAAO,QAAQ,CAAC;AAAA,IACpE;AAAA,IACA,MAAM;AAAA;AAAA;;;AC/RD,SAAS,iBAAiB,CAChC,SAC6B;AAAA,EAC7B,OAAO,QAAQ,SAAS;AAAA;",
|
|
13
|
+
"debugId": "8EDE13AECCE4AEBA64756E2164756E21",
|
|
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-
|
|
4
|
+
} from "../../shared/stacks-jkykwc61.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-
|
|
18
|
+
} from "../../shared/stacks-deprc4zq.js";
|
|
19
19
|
import {
|
|
20
20
|
callContract,
|
|
21
21
|
getMapEntry,
|
|
22
22
|
readContract
|
|
23
|
-
} from "../../shared/stacks-
|
|
23
|
+
} from "../../shared/stacks-cmyyp5c4.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-
|
|
34
|
+
} from "../../shared/stacks-1qmx9kt8.js";
|
|
35
35
|
import {
|
|
36
36
|
estimateFee,
|
|
37
37
|
getNonce,
|
|
38
38
|
isProviderAccount,
|
|
39
39
|
sendTransaction
|
|
40
|
-
} from "../../shared/stacks-
|
|
40
|
+
} from "../../shared/stacks-ttbq8emk.js";
|
|
41
41
|
import"../../shared/stacks-709tra19.js";
|
|
42
42
|
import"../../shared/stacks-g7ffp8aj.js";
|
|
43
43
|
import"../../shared/stacks-wqgepfab.js";
|
package/dist/src/bns/index.d.cts
CHANGED
|
@@ -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 = {
|
package/dist/src/bns/index.d.ts
CHANGED
|
@@ -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 = {
|
package/dist/src/bns/index.js
CHANGED
|
@@ -3,9 +3,9 @@ import"../../shared/stacks-kg1npstf.js";
|
|
|
3
3
|
import {
|
|
4
4
|
ContractResponseError,
|
|
5
5
|
getContract
|
|
6
|
-
} from "../../shared/stacks-
|
|
7
|
-
import"../../shared/stacks-
|
|
8
|
-
import"../../shared/stacks-
|
|
6
|
+
} from "../../shared/stacks-jkykwc61.js";
|
|
7
|
+
import"../../shared/stacks-cmyyp5c4.js";
|
|
8
|
+
import"../../shared/stacks-ttbq8emk.js";
|
|
9
9
|
import"../../shared/stacks-709tra19.js";
|
|
10
10
|
import"../../shared/stacks-g7ffp8aj.js";
|
|
11
11
|
import"../../shared/stacks-z53fwfcm.js";
|