@dcasegr/amm-client 0.0.0-stage → 0.38.2

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 (121) hide show
  1. package/README.md +107 -2
  2. package/dist/client.d.ts +534 -0
  3. package/dist/client.js +1319 -0
  4. package/dist/errors.d.ts +17 -0
  5. package/dist/errors.js +75 -0
  6. package/dist/index.d.ts +51 -0
  7. package/dist/index.js +53 -0
  8. package/dist/lib/config.d.ts +42 -0
  9. package/dist/lib/config.js +64 -0
  10. package/dist/lib/keys.d.ts +42 -0
  11. package/dist/lib/keys.js +48 -0
  12. package/dist/lib/overlay.d.ts +190 -0
  13. package/dist/lib/overlay.js +302 -0
  14. package/dist/lib/skein.d.ts +82 -0
  15. package/dist/lib/skein.js +142 -0
  16. package/dist/lib/tokenId.d.ts +72 -0
  17. package/dist/lib/tokenId.js +121 -0
  18. package/dist/lp/amounts.d.ts +12 -0
  19. package/dist/lp/amounts.js +38 -0
  20. package/dist/lp/close.d.ts +90 -0
  21. package/dist/lp/close.js +140 -0
  22. package/dist/lp/images.d.ts +11 -0
  23. package/dist/lp/images.js +45 -0
  24. package/dist/lp/inventory.d.ts +68 -0
  25. package/dist/lp/inventory.js +84 -0
  26. package/dist/lp/poolDeploy.d.ts +220 -0
  27. package/dist/lp/poolDeploy.js +291 -0
  28. package/dist/lp/poolRows.d.ts +13 -0
  29. package/dist/lp/poolRows.js +19 -0
  30. package/dist/lp/positions.d.ts +81 -0
  31. package/dist/lp/positions.js +144 -0
  32. package/dist/lp/rebalance.d.ts +101 -0
  33. package/dist/lp/rebalance.js +168 -0
  34. package/dist/lp/wallet.d.ts +12 -0
  35. package/dist/lp/wallet.js +19 -0
  36. package/dist/market/activeSwap.d.ts +158 -0
  37. package/dist/market/activeSwap.js +320 -0
  38. package/dist/market/plan.d.ts +85 -0
  39. package/dist/market/plan.js +149 -0
  40. package/dist/market/prices.d.ts +13 -0
  41. package/dist/market/prices.js +14 -0
  42. package/dist/market/relay.d.ts +84 -0
  43. package/dist/market/relay.js +201 -0
  44. package/dist/market/swapAction.d.ts +306 -0
  45. package/dist/market/swapAction.js +508 -0
  46. package/dist/market/swapFlow.d.ts +58 -0
  47. package/dist/market/swapFlow.js +86 -0
  48. package/dist/market/view.d.ts +58 -0
  49. package/dist/market/view.js +63 -0
  50. package/dist/pool/artifact.d.ts +23 -0
  51. package/dist/pool/artifact.js +38 -0
  52. package/dist/pool/index.d.ts +8 -0
  53. package/dist/pool/index.js +8 -0
  54. package/dist/pool/oneColor.d.ts +19 -0
  55. package/dist/pool/oneColor.js +39 -0
  56. package/dist/pool/pool.artifact.json +5069 -0
  57. package/dist/pool/runar-ir-schema.d.ts +21 -0
  58. package/dist/pool/runar-ir-schema.js +18 -0
  59. package/dist/pool/template.d.ts +295 -0
  60. package/dist/pool/template.js +715 -0
  61. package/dist/vendor/runar/LICENSE +21 -0
  62. package/dist/vendor/runar/NOTICE +15 -0
  63. package/dist/vendor/runar/runar-ir-schema/src/abi-type-encoding.d.ts +42 -0
  64. package/dist/vendor/runar/runar-ir-schema/src/abi-type-encoding.js +53 -0
  65. package/dist/vendor/runar/runar-ir-schema/src/anf-ir.d.ts +221 -0
  66. package/dist/vendor/runar/runar-ir-schema/src/anf-ir.js +33 -0
  67. package/dist/vendor/runar/runar-ir-schema/src/artifact.d.ts +288 -0
  68. package/dist/vendor/runar/runar-ir-schema/src/artifact.js +8 -0
  69. package/dist/vendor/runar/runar-ir-schema/src/canonical-json.d.ts +43 -0
  70. package/dist/vendor/runar/runar-ir-schema/src/canonical-json.js +204 -0
  71. package/dist/vendor/runar/runar-ir-schema/src/input-limits.d.ts +89 -0
  72. package/dist/vendor/runar/runar-ir-schema/src/input-limits.js +100 -0
  73. package/dist/vendor/runar/runar-ir-schema/src/stack-ir.d.ts +118 -0
  74. package/dist/vendor/runar/runar-ir-schema/src/stack-ir.js +8 -0
  75. package/dist/vendor/runar/runar-ir-schema/src/state-layout.d.ts +56 -0
  76. package/dist/vendor/runar/runar-ir-schema/src/state-layout.js +145 -0
  77. package/dist/vendor/runar/runar-ir-schema/src/unknown-anf-kind-error.d.ts +18 -0
  78. package/dist/vendor/runar/runar-ir-schema/src/unknown-anf-kind-error.js +25 -0
  79. package/dist/vendor/runar/runar-sdk/src/anf-interpreter.d.ts +160 -0
  80. package/dist/vendor/runar/runar-sdk/src/anf-interpreter.js +1149 -0
  81. package/dist/vendor/runar/runar-sdk/src/calling.d.ts +98 -0
  82. package/dist/vendor/runar/runar-sdk/src/calling.js +209 -0
  83. package/dist/vendor/runar/runar-sdk/src/contract.d.ts +443 -0
  84. package/dist/vendor/runar/runar-sdk/src/contract.js +2516 -0
  85. package/dist/vendor/runar/runar-sdk/src/deployment.d.ts +36 -0
  86. package/dist/vendor/runar/runar-sdk/src/deployment.js +119 -0
  87. package/dist/vendor/runar/runar-sdk/src/errors.d.ts +46 -0
  88. package/dist/vendor/runar/runar-sdk/src/errors.js +59 -0
  89. package/dist/vendor/runar/runar-sdk/src/oppushtx.d.ts +23 -0
  90. package/dist/vendor/runar/runar-sdk/src/oppushtx.js +95 -0
  91. package/dist/vendor/runar/runar-sdk/src/ordinals/envelope.d.ts +31 -0
  92. package/dist/vendor/runar/runar-sdk/src/ordinals/envelope.js +272 -0
  93. package/dist/vendor/runar/runar-sdk/src/ordinals/types.d.ts +21 -0
  94. package/dist/vendor/runar/runar-sdk/src/ordinals/types.js +4 -0
  95. package/dist/vendor/runar/runar-sdk/src/providers/provider.d.ts +65 -0
  96. package/dist/vendor/runar/runar-sdk/src/providers/provider.js +59 -0
  97. package/dist/vendor/runar/runar-sdk/src/providers/wallet-provider.d.ts +94 -0
  98. package/dist/vendor/runar/runar-sdk/src/providers/wallet-provider.js +297 -0
  99. package/dist/vendor/runar/runar-sdk/src/script-utils.d.ts +54 -0
  100. package/dist/vendor/runar/runar-sdk/src/script-utils.js +252 -0
  101. package/dist/vendor/runar/runar-sdk/src/signers/signer.d.ts +17 -0
  102. package/dist/vendor/runar/runar-sdk/src/signers/signer.js +4 -0
  103. package/dist/vendor/runar/runar-sdk/src/spend-safety.d.ts +31 -0
  104. package/dist/vendor/runar/runar-sdk/src/spend-safety.js +35 -0
  105. package/dist/vendor/runar/runar-sdk/src/state.d.ts +54 -0
  106. package/dist/vendor/runar/runar-sdk/src/state.js +584 -0
  107. package/dist/vendor/runar/runar-sdk/src/types.d.ts +227 -0
  108. package/dist/vendor/runar/runar-sdk/src/types.js +4 -0
  109. package/dist/vendor/runar/runar-sdk/src/unsound-primitives.d.ts +30 -0
  110. package/dist/vendor/runar/runar-sdk/src/unsound-primitives.js +42 -0
  111. package/dist/vendor/runar/runar-sdk.d.ts +9 -0
  112. package/dist/vendor/runar/runar-sdk.js +8 -0
  113. package/dist/wallet/action.d.ts +28 -0
  114. package/dist/wallet/action.js +42 -0
  115. package/dist/wallet/brc29.d.ts +83 -0
  116. package/dist/wallet/brc29.js +80 -0
  117. package/dist/wallet/color.d.ts +110 -0
  118. package/dist/wallet/color.js +134 -0
  119. package/dist/wallet/swapPayouts.d.ts +35 -0
  120. package/dist/wallet/swapPayouts.js +146 -0
  121. package/package.json +39 -4
@@ -0,0 +1,201 @@
1
+ /**
2
+ * The marketplace relay (docs/notes.md, "Marketplace relay"): the user's own
3
+ * skein instance takes the funding and swap transactions and carries them to
4
+ * the pool's validator, so the browser needs no libp2p. Two functions on the
5
+ * AMM app's box, hosted by programs/amm-p2p:
6
+ *
7
+ * amm.swap.terms (reads) {} → {commissionPkh: bytes(20) | null, minCommissionBps}
8
+ * amm.swap.submit (writes) {funding, swap, pool, validator, peerId, expires} → the record
9
+ * (0.34.0, D15: the host holds the request until the relay thread
10
+ * rests, so the answer is the settled record; past the host's bound,
11
+ * 503: no answer yet)
12
+ * amm.swap.status (reads) {id} → the record (0.34.0: the pages read it plain, `GET
13
+ * <base>/swaps?id=`, src/lib/overlay.ts `readSwap`, behind "Check again")
14
+ *
15
+ * commissionPkh the address the relay takes the pool's commission at
16
+ * (Swap's `commissionPkh`; 0.16.0: hash160 of the instance's
17
+ * own derived key, no config); null when the instance names
18
+ * none, in which case a pool with a nonzero CommissionBps pays
19
+ * the commission to the taker's own key
20
+ * (src/market/swapAction.ts, "the commission")
21
+ * minCommissionBps this market's minimum commission (0.16.0: the record
22
+ * root sets, `amm/market`; absent or unset, 0): a listing
23
+ * preference, the pools the Swap page lists, not a rule
24
+ *
25
+ * funding bytes: the funding transaction as the wallet's AtomicBEEF (its
26
+ * ancestry with it: the validator's overlay verifies the unproven
27
+ * funding against parents in the BEEF); 0.29.0: the transaction
28
+ * of the leg's `amm-swap` sats output, the swap's input 1
29
+ * swap bytes: the raw swap, the validator's slot `OP_0`
30
+ * pool text `<txid>_<vout>`; validator bytes(33); expires unix ms
31
+ * peerId text: the validator's libp2p peer ID, from the pools route's row
32
+ * (`validatorPeerId`, 0.34.0: the host joined it from the beat): the
33
+ * relay dials it (or, when it is the relay's own node, hands the
34
+ * swap to its own validator program); it looks at no liveness
35
+ *
36
+ * record (programs/amm-p2p relay.zig `Record.answer`; id = sha256 of the swap, hex):
37
+ * {id, status: "pending" | "accepted" | "refused" | "timeout" | "failed", pool, expires, …,
38
+ * tx?, txid? accepted: the validator's signed swap
39
+ * reason?, detail?, refused / timeout / failed
40
+ * poolState?} refused: the pool's current state (the validator's)
41
+ * "failed" is the relay's transport failure (retryable by submitting again):
42
+ * the validator may or may not have the swap, so the page treats it as no
43
+ * answer, not as a refusal.
44
+ *
45
+ * Transport: the app's `/call` route (skein docs/APPS.md §4): `POST
46
+ * <VITE_AMM_OVERLAY>/call`, JSON body `{fn, args}`, answer `{fn, result}`
47
+ * (200) or `{fn, error: {code, message}}` (400 bad-request / bad-args, 403
48
+ * not-admitted, 404 unknown-fn, 409 read-only, 500 failed). The route is
49
+ * BRC-104 authenticated: the caller must be admitted to the app's box, so
50
+ * both calls go through the wallet-backed AuthFetch (src/wallet/authFetch.ts).
51
+ *
52
+ * Bytes in `args` are DAG-JSON bytes (`{"/": {"bytes": "<base64, unpadded>"}}`),
53
+ * how skein reads JSON bodies (docs/MESSAGES.md "The messagebox"); answers are
54
+ * read as DAG-JSON bytes, hex or a byte array.
55
+ */
56
+ import { Utils } from "@bsv/sdk";
57
+ export const SWAP_SUBMIT_FN = "amm.swap.submit";
58
+ export const SWAP_STATUS_FN = "amm.swap.status";
59
+ export const SWAP_TERMS_FN = "amm.swap.terms";
60
+ export class RelayError extends Error {
61
+ code;
62
+ httpStatus;
63
+ constructor(code, message, httpStatus) {
64
+ super(`${code}: ${message}`);
65
+ this.code = code;
66
+ this.httpStatus = httpStatus;
67
+ this.name = "RelayError";
68
+ }
69
+ }
70
+ export function dagBytes(bytes) {
71
+ return { "/": { bytes: Utils.toBase64(bytes).replace(/=+$/, "") } };
72
+ }
73
+ /** DAG-JSON bytes, hex, or a byte array → bytes; null otherwise. */
74
+ export function readBytes(x) {
75
+ if (Array.isArray(x) && x.every((b) => Number.isInteger(b) && b >= 0 && b < 256))
76
+ return x;
77
+ if (typeof x === "string" && /^([0-9a-f]{2})+$/i.test(x))
78
+ return Utils.toArray(x, "hex");
79
+ const b = x?.["/"]?.bytes;
80
+ if (typeof b === "string") {
81
+ const padded = b + "=".repeat((4 - (b.length % 4)) % 4);
82
+ return Utils.toArray(padded, "base64");
83
+ }
84
+ return null;
85
+ }
86
+ export function callUrl(base) {
87
+ return `${base.replace(/\/+$/, "")}/call`;
88
+ }
89
+ export function submitBody(s) {
90
+ return {
91
+ fn: SWAP_SUBMIT_FN,
92
+ args: { funding: dagBytes(s.funding), swap: dagBytes(s.swap), pool: s.pool, validator: dagBytes(Utils.toArray(s.validator, "hex")), peerId: s.peerId, expires: s.expires },
93
+ };
94
+ }
95
+ /** One `{fn, args}` call on the app's `/call` route. Throws `RelayError` on an error answer. */
96
+ export async function callApp(af, base, fn, args) {
97
+ const res = await af.fetch(callUrl(base), {
98
+ method: "POST",
99
+ headers: { "content-type": "application/json" },
100
+ body: JSON.stringify({ fn, args }),
101
+ });
102
+ const text = await res.text();
103
+ let answer = null;
104
+ try {
105
+ answer = JSON.parse(text);
106
+ }
107
+ catch {
108
+ /* not JSON */
109
+ }
110
+ if (res.status === 200 && answer && "result" in answer)
111
+ return answer.result;
112
+ const e = answer?.error;
113
+ throw new RelayError(typeof e?.code === "string" ? e.code : `HTTP ${res.status}`, typeof e?.message === "string" ? e.message : text.slice(0, 200), res.status);
114
+ }
115
+ /**
116
+ * A refusal's pool, as the validator writes it (messages.zig poolValue:
117
+ * `lpFeeBps`, `validatorFeeBps`, `validatorIdentity`) or as the lookup does
118
+ * (the engine's names), into the engine's PoolState. A closed pool, or one
119
+ * missing a field, is undefined: nothing left to re-price.
120
+ */
121
+ export function toPoolState(raw) {
122
+ if (!raw || typeof raw !== "object")
123
+ return undefined;
124
+ const p = raw;
125
+ if (p.closed)
126
+ return undefined;
127
+ const num = (...ks) => ks.map((k) => p[k]).find((v) => typeof v === "number" || typeof v === "string");
128
+ const outpoint = p.outpoint;
129
+ const bsv = num("bsvReserve");
130
+ const tokens = num("tokenReserve");
131
+ const lp = num("liquidityFeeBps", "lpFeeBps");
132
+ const val = num("validationFeeBps", "validatorFeeBps");
133
+ const comm = num("commissionBps");
134
+ const rawId = p.validatorIdentityKey ?? p.validatorIdentity;
135
+ const idBytes = typeof rawId === "string" ? null : readBytes(rawId);
136
+ const identity = typeof rawId === "string" ? rawId : idBytes?.length === 33 ? Utils.toHex(idBytes) : undefined;
137
+ if (typeof outpoint !== "string" || bsv === undefined || tokens === undefined || lp === undefined || val === undefined || typeof identity !== "string") {
138
+ return undefined;
139
+ }
140
+ return {
141
+ outpoint,
142
+ bsvReserve: BigInt(bsv),
143
+ tokenReserve: BigInt(tokens),
144
+ liquidityFeeBps: BigInt(lp),
145
+ validationFeeBps: BigInt(val),
146
+ commissionBps: BigInt((comm ?? 0)),
147
+ validatorIdentityKey: identity,
148
+ };
149
+ }
150
+ export function parseSwapRecord(x) {
151
+ const r = x;
152
+ const id = r?.id ?? r?.swapId;
153
+ const status = r?.status ?? r?.state;
154
+ if (!r || typeof id !== "string")
155
+ throw new Error(`relay: not a swap record: ${JSON.stringify(x)?.slice(0, 200)}`);
156
+ switch (status) {
157
+ case "pending":
158
+ case "timeout":
159
+ return { id, status };
160
+ case "failed":
161
+ return { id, status, reason: (typeof r.reason === "string" ? r.reason : "failed") + (typeof r.detail === "string" && r.detail ? `: ${r.detail}` : "") };
162
+ case "accepted": {
163
+ const tx = readBytes(r.tx);
164
+ if (!tx || typeof r.txid !== "string")
165
+ throw new Error("relay: accepted without tx / txid");
166
+ return { id, status, tx, txid: r.txid };
167
+ }
168
+ case "refused": {
169
+ const pool = toPoolState(r.poolState ?? (typeof r.pool === "object" ? r.pool : undefined));
170
+ const reason = (typeof r.reason === "string" ? r.reason : "refused") + (typeof r.detail === "string" && r.detail ? `: ${r.detail}` : "");
171
+ return pool ? { id, status, reason, pool } : { id, status, reason };
172
+ }
173
+ default:
174
+ throw new Error(`relay: unknown swap status ${JSON.stringify(status)}`);
175
+ }
176
+ }
177
+ /** `amm.swap.terms`'s answer: `commissionPkh` as DAG-JSON bytes (or hex, or a byte array) of 20 bytes, or null / absent; `minCommissionBps` an integer 0 to 10 000, absent 0 (0.16.0). */
178
+ export function parseSwapTerms(x) {
179
+ const r = x;
180
+ if (!r || typeof r !== "object")
181
+ throw new Error(`relay: not swap terms: ${JSON.stringify(x)?.slice(0, 200)}`);
182
+ const m = r.minCommissionBps ?? 0;
183
+ if (typeof m !== "number" || !Number.isInteger(m) || m < 0 || m > 10_000)
184
+ throw new Error("relay: minCommissionBps is not an integer, 0 to 10000");
185
+ if (r.commissionPkh === null || r.commissionPkh === undefined)
186
+ return { commissionPkh: null, minCommissionBps: m };
187
+ const b = readBytes(r.commissionPkh);
188
+ if (!b || b.length !== 20)
189
+ throw new Error("relay: commissionPkh is not 20 bytes");
190
+ return { commissionPkh: Utils.toHex(b), minCommissionBps: m };
191
+ }
192
+ export async function swapTerms(af, base) {
193
+ return parseSwapTerms(await callApp(af, base, SWAP_TERMS_FN, {}));
194
+ }
195
+ export async function submitSwap(af, base, s) {
196
+ const { fn, args } = submitBody(s);
197
+ return parseSwapRecord(await callApp(af, base, fn, args));
198
+ }
199
+ export async function swapStatus(af, base, id) {
200
+ return parseSwapRecord(await callApp(af, base, SWAP_STATUS_FN, { id }));
201
+ }
@@ -0,0 +1,306 @@
1
+ /**
2
+ * One swap leg through the user's BRC-100 wallet (docs/notes.md, "Swap
3
+ * funding and signing"). The page holds no keys: every key and signature
4
+ * comes from the wallet (`getPublicKey`, `createAction`, `createSignature`).
5
+ *
6
+ * 1. `planSwapLeg` (`PoolTemplate.planSwap`): the outputs the contract
7
+ * requires (pool, payout, LP fee, validator fee, commission) and the
8
+ * method arguments. The commission goes to the relay's `amm.swap.terms`
9
+ * address; when the relay names none and the pool's CommissionBps is
10
+ * nonzero, to a key of the taker's own (see "the commission" below). The
11
+ * leg's sats are exact: what the contract's outputs take beyond the
12
+ * pool's and the token inputs' sats (amount in + 1 sat per 1Color output
13
+ * the taker pays for), plus the miner fee of the final swap
14
+ * (`swapFunding`). Sized with placeholder addresses: the payout keys
15
+ * (and the taker's own commission key) are derived at step 3 from the
16
+ * leg's first staged input (`legDerivation`, 0.29.1), not random.
17
+ * 2. **The leg's inputs** (0.29.0, David Case 2026-11-02): every one an
18
+ * output of the active swap basket `amm-swap` (src/market/activeSwap.ts):
19
+ * ONE sats output of exactly that amount (`SatsInput`) and, token → sats,
20
+ * the token outputs carrying exactly the amount in (`TokenInput`), staged
21
+ * there by one wallet send before the legs (no funding transaction, no
22
+ * `1sat-deposit`).
23
+ * 3. **Swap transaction**, built here (`prepareSwap`): inputs pool
24
+ * (`callUnlock`, the validator's slot `OP_0`, `_changeAmount = 0`), the
25
+ * sats output, the token outputs; outputs exactly the contract's, no
26
+ * change. The sats and token inputs are signed with `createSignature`
27
+ * (SIGHASH_ALL|FORKID over the BIP-143 sighash computed here, under the
28
+ * key each input's customInstructions name) and every input but the
29
+ * pool's is checked with `Spend`.
30
+ * 4. The relay (src/market/relay.ts) carries it to the validator, with the
31
+ * sats output's transaction as the swap's funding transaction (its
32
+ * AtomicBEEF, from the wallet).
33
+ * 5. Accepted: `completeSwap` internalizes the payout (sats: BRC-29 wallet
34
+ * payment; tokens, 0.12.0: the output is locked to a BRC-207 module
35
+ * receiving key whose sender is the pool's validator, taken in with a
36
+ * basket insertion into `p color <assetTag>` and the receipt,
37
+ * src/wallet/color.ts), and the commission when it is the taker's own
38
+ * (same two forms). No relinquishOutput (0.29.0): the wallet marks the
39
+ * `amm-swap` outputs the swap spends spent when it takes the swap in.
40
+ * Refused / timed out: nothing to undo; the leg's outputs stay in
41
+ * `amm-swap` for a later swap.
42
+ */
43
+ import { Beef, Transaction, UnlockingScript, type WalletInterface, type WalletProtocol } from "@bsv/sdk";
44
+ import type { Direction, Leg, PoolState } from "@dcasegr/amm-engine";
45
+ import { type CallPlan, type PoolUtxo } from "../pool/index.js";
46
+ import type { LookupOutput } from "../lib/overlay.js";
47
+ import { type Brc29Payout } from "../wallet/brc29.js";
48
+ import { type ColorReceipt } from "../wallet/color.js";
49
+ /** A P2PKH unlocking script's upper bound: push(DER ≤ 72 + sighash byte) + push(33-byte key). */
50
+ export declare const P2PKH_UNLOCK_LENGTH = 108;
51
+ /**
52
+ * How long the relay may take (the swap's `expires`): 15 s (0.34.0, D15, David Case 2026-11-04;
53
+ * was 120 s, a 10-05 builder number): the held submit returns inside it.
54
+ */
55
+ export declare const SWAP_TTL_MS = 15000;
56
+ export declare class LegShapeError extends Error {
57
+ constructor(message: string);
58
+ }
59
+ /** An `amm-swap` basket output the wallet can sign: a 1Color value output of the token, with its key. */
60
+ export interface TokenInput {
61
+ /** `txid.vout` (BRC-100 outpoint form). */
62
+ outpoint: string;
63
+ txid: string;
64
+ vout: number;
65
+ satoshis: number;
66
+ lockingScript: string;
67
+ amount: bigint;
68
+ protocolID: WalletProtocol;
69
+ keyID: string;
70
+ counterparty: string;
71
+ }
72
+ /** The token's 32-byte wire id (internal byte order) for a token with a 32-byte id (`<txid>_0`; `<txid>` and `<txid>.0` read the same). */
73
+ export declare function assetIdOf(tokenId: string): string;
74
+ /**
75
+ * The basket rows usable as token inputs for `tokenId`: 1Color value outputs
76
+ * with this 32-byte id (the pool template counts only those) whose
77
+ * customInstructions name the key (protocolID, keyID).
78
+ */
79
+ export declare function tokenInputsOf(rows: {
80
+ outpoint: string;
81
+ satoshis: number;
82
+ lockingScript?: string;
83
+ tags?: string[];
84
+ customInstructions?: string;
85
+ }[], tokenId: string): TokenInput[];
86
+ /**
87
+ * Token outputs summing to exactly `amount`, or null. The pool contract has
88
+ * no token change output (Pool.runar.go Swap: the token inputs are the
89
+ * amountIn), so an inexact selection cannot be spent into a swap. Fewest
90
+ * outputs first; a bounded search.
91
+ */
92
+ export declare function selectExactTokenInputs(candidates: TokenInput[], amount: bigint): TokenInput[] | null;
93
+ /** An `amm-swap` sats output (customInstructions `{sats: true, assetId, protocolID, keyID, counterparty}`): a plain P2PKH to an "amm swap" key. */
94
+ export interface SatsInput {
95
+ /** `txid.vout` */
96
+ outpoint: string;
97
+ txid: string;
98
+ vout: number;
99
+ satoshis: number;
100
+ lockingScript: string;
101
+ protocolID: WalletProtocol;
102
+ keyID: string;
103
+ counterparty: string;
104
+ /** The token whose swap staged it (`<txid>_<vout>`, 0.29.1), when its row names one. */
105
+ assetId?: string;
106
+ }
107
+ /** The basket rows usable as a leg's sats: plain P2PKH outputs whose customInstructions say `sats: true` and name the key. */
108
+ export declare function satsInputsOf(rows: {
109
+ outpoint: string;
110
+ satoshis: number;
111
+ lockingScript?: string;
112
+ customInstructions?: string;
113
+ }[]): SatsInput[];
114
+ /** The sats twin of `selectExactTokenInputs`: one output of exactly `satoshis` (the leg has no change), or null. */
115
+ export declare function selectExactSatsInput(candidates: SatsInput[], satoshis: number): SatsInput | null;
116
+ /** The pool output from the lookup's BEEF, as the template's PoolUtxo. */
117
+ export declare function poolUtxoFrom(poolOutput: LookupOutput): PoolUtxo;
118
+ /**
119
+ * A P2PKH (or 1Color-on-P2PKH) input signed by the wallet: BIP-143 over
120
+ * the finished transaction under `scope` (ALL|FORKID), `createSignature` with `hashToDirectlySign`
121
+ * (1sat-sdk's `signP2PKHInputWallet`).
122
+ */
123
+ export declare function signP2pkhWithWallet(wallet: WalletInterface, tx: Transaction, inputIndex: number, src: {
124
+ satoshis: number;
125
+ lockingScript: string;
126
+ protocolID: WalletProtocol;
127
+ keyID: string;
128
+ counterparty: string;
129
+ }, scope?: number): Promise<UnlockingScript>;
130
+ /**
131
+ * The final swap's size in bytes: the pool input at `maxCallUnlockLength`
132
+ * (validator's signature in), `takerInputs` P2PKH inputs (the sats, tokens)
133
+ * at 108 bytes of unlocking script, the contract's outputs, no change.
134
+ */
135
+ export declare function swapTxSize(plan: CallPlan, takerInputs: number): number;
136
+ export interface SwapFunding {
137
+ /** The leg's sats output's exact amount (0.29.0: an `amm-swap` output). */
138
+ satoshis: number;
139
+ /** What the contract's outputs take beyond the pool's and the token inputs' sats. */
140
+ outputs: number;
141
+ fee: number;
142
+ size: number;
143
+ satsPerKb: number;
144
+ }
145
+ /**
146
+ * The leg's exact sats: Σ contract outputs − pool sats − token inputs' sats
147
+ * (sats in: amount in + 1 for the token payout, the fees and the commission
148
+ * being part of amount in; tokens in: 1 per 1Color fee or commission output
149
+ * − the token inputs' sats), plus
150
+ * ceil(size × rate / 1000) for the final swap.
151
+ */
152
+ export declare function swapFunding(plan: CallPlan, tokenInputs: {
153
+ satoshis: number;
154
+ }[], satsPerKb: number): SwapFunding;
155
+ export interface PlanLegInput {
156
+ wallet: WalletInterface;
157
+ /** `<txid>_0` (src/lib/tokenId.ts). */
158
+ tokenId: string;
159
+ meta?: {
160
+ sym?: string;
161
+ dec?: number;
162
+ };
163
+ direction: Direction;
164
+ leg: Leg;
165
+ pool: PoolState;
166
+ /** The lookup's `{outpoint, beef: true}` answer for `leg.outpoint`. */
167
+ poolOutput: LookupOutput;
168
+ /**
169
+ * The relay's commission address (`amm.swap.terms`, hash160 hex), or null
170
+ * when the relay names none: a pool with a nonzero CommissionBps then pays
171
+ * the commission to a fresh key of the taker's own.
172
+ */
173
+ commissionPkh: string | null;
174
+ /**
175
+ * token → sats: the token inputs carrying exactly `leg.amountIn`, or (0.29.0) what they will be
176
+ * once staged: one output of 1 sat per leg (`sendToSwapBasket`). Their count and sats size the
177
+ * leg's sats.
178
+ */
179
+ tokenInputs?: Pick<TokenInput, "satoshis" | "amount">[];
180
+ /** sats per 1000 bytes (`VITE_FEE_RATE`). */
181
+ satsPerKb: number;
182
+ }
183
+ /** Step 1: the leg's plan (placeholder addresses) and exact sats (`funding.satoshis`: the `amm-swap` sats output the leg spends). */
184
+ export interface PlannedLeg {
185
+ /** The pool outpoint `<txid>_<vout>`. */
186
+ pool: string;
187
+ validator: string;
188
+ bsvIn: boolean;
189
+ poolUtxo: PoolUtxo;
190
+ /** Sized with placeholder payout and commission addresses (prepareSwap re-plans with the derived keys). */
191
+ plan: CallPlan;
192
+ funding: SwapFunding;
193
+ commissionAmount: bigint;
194
+ commissionTo: SwapCommission["to"];
195
+ }
196
+ export interface PrepareSwapInput extends PlanLegInput {
197
+ /** token → sats: `amm-swap` outputs carrying exactly `leg.amountIn`. */
198
+ tokenInputs?: TokenInput[];
199
+ /** The leg's `amm-swap` sats output: exactly the planned `funding.satoshis` (0.29.0). */
200
+ satsInput: SatsInput;
201
+ /** The swap basket's source transactions: the sats and token inputs' (default: `amm-swap`'s, from the wallet). */
202
+ holdingBeef?: Beef;
203
+ /** Step 1 already done (`planSwapLeg` over the same input); planned here when absent. */
204
+ planned?: PlannedLeg;
205
+ now?: number;
206
+ ttlMs?: number;
207
+ }
208
+ export type SwapPayout = {
209
+ kind: "color";
210
+ outputIndex: number;
211
+ satoshis: number;
212
+ lockingScript: string;
213
+ receipt: ColorReceipt;
214
+ } | ({
215
+ kind: "brc29";
216
+ } & Brc29Payout);
217
+ export interface PreparedSwap {
218
+ /** The pool outpoint `<txid>_<vout>`. */
219
+ pool: string;
220
+ validator: string;
221
+ expires: number;
222
+ plan: CallPlan;
223
+ funding: SwapFunding & {
224
+ /** The leg's `amm-swap` sats output (input 1). */
225
+ input: SatsInput;
226
+ /** Its transaction as the wallet's AtomicBEEF: the swap's funding transaction, what the relay is sent. */
227
+ atomicBeef: number[];
228
+ txid: string;
229
+ /** `txid.vout` */
230
+ outpoint: string;
231
+ };
232
+ /** Every input signed except the pool's validator slot. */
233
+ swap: Transaction;
234
+ tokenInputs: TokenInput[];
235
+ payout: SwapPayout;
236
+ commission: SwapCommission;
237
+ }
238
+ /** The leg's commission (the pool's CommissionBps of amount in, in the input asset). */
239
+ export interface SwapCommission {
240
+ /** 0 when the pool's CommissionBps is 0: no output. */
241
+ amount: bigint;
242
+ /** Swap's `commissionPkh` (pushed even when there is no output). */
243
+ pkh: string;
244
+ /** "relay": the relay's address; "own": the taker's key, internalized with the payout; "none": no output. */
245
+ to: "relay" | "own" | "none";
246
+ /** "own" only: the wallet's record of the commission output. */
247
+ payout?: SwapPayout;
248
+ }
249
+ /** BRC-29 / BRC-207 derivationPrefix of a leg's payout (0.29.1): base64 of the UTF-8 text "amm swap". */
250
+ export declare const LEG_PAYOUT_PREFIX: string;
251
+ /** derivationPrefix of the taker's own commission output (0.29.1): base64 of "amm swap commission". */
252
+ export declare const LEG_COMMISSION_PREFIX: string;
253
+ /**
254
+ * The derivation of a leg's payout keys (0.29.1, David Case 2026-11-02: deterministic from what
255
+ * the leg spends). `keyInput` is the leg's first staged `amm-swap` input, `<txid>.<vout>` (txid in
256
+ * display hex, lowercase): tokens in, its first token input (the swap's input 2); sats in, its sats
257
+ * input (input 1). derivationSuffix = base64(sha256(UTF-8 of that text)); derivationPrefix
258
+ * `LEG_PAYOUT_PREFIX` for the payout, `LEG_COMMISSION_PREFIX` for the taker's own commission. The
259
+ * same pair keys the BRC-29 payment (keyID "<prefix> <suffix>", sender the user) and the BRC-207
260
+ * receipt (`p color <assetTag> <prefixHex> <suffixHex>`, sender the pool's validator). A staged
261
+ * output is spent by one transaction only, so the keys are the leg's alone.
262
+ */
263
+ export declare function legDerivation(keyInput: string, which: "payout" | "commission"): {
264
+ derivationPrefix: string;
265
+ derivationSuffix: string;
266
+ };
267
+ /** The leg's key input in a swap transaction (see `legDerivation`): input 2 when it spends tokens, else input 1. */
268
+ export declare function legKeyInputOf(swap: Transaction, bsvIn: boolean): string;
269
+ /**
270
+ * Step 1 (see the module comment): the leg's plan and exact sats, sized with placeholder payout
271
+ * and commission addresses (20 bytes each: the sizes are the same). No wallet call: the payout
272
+ * keys are derived at step 3 from the leg's staged input (`legDerivation`). Throws
273
+ * `PoolBuildError` / `LegShapeError`.
274
+ */
275
+ export declare function planSwapLeg(i: PlanLegInput): Promise<PlannedLeg>;
276
+ /** Steps 1 (unless `planned` is given) and 3 (see the module comment). Throws `PoolBuildError` / `LegShapeError`; the wallet is left as it was. */
277
+ export declare function prepareSwap(i: PrepareSwapInput): Promise<PreparedSwap>;
278
+ /** @bsv/sdk's `Spend` over input `n` of `tx` (its source output from `sourceTransaction`). */
279
+ export declare function spendValid(tx: Transaction, n: number): boolean;
280
+ /**
281
+ * The validator's final transaction, checked against ours: same inputs (in
282
+ * order, the taker's unlocking scripts unchanged), same outputs; only input
283
+ * 0's unlocking script (the validator's slot) differs. Its inputs get our
284
+ * source transactions, so it serializes as AtomicBEEF.
285
+ */
286
+ export declare function finalSwapOf(p: PreparedSwap, raw: number[], txid?: string): Transaction;
287
+ /**
288
+ * A validator-signed pool call checked against the one we built (`ours`):
289
+ * same inputs in order with our unlocking scripts on every input but the
290
+ * pool's (input 0), same outputs. Shared by the swap and AddLiquidity.
291
+ */
292
+ export declare function finalCallOf(ours: Transaction, raw: number[], txid: string | undefined, what: string): Transaction;
293
+ export interface CompletedSwap {
294
+ txid: string;
295
+ internalized: boolean;
296
+ /** Internalize errors (the swap itself is final). */
297
+ errors: string[];
298
+ }
299
+ /**
300
+ * Accepted: the wallet takes the payout in (`internalizeAction`). No
301
+ * relinquishOutput (0.29.0, David Case 2026-11-02: "Anything we internalize
302
+ * should relinquish outputs itself"): taking the swap in marks the wallet's
303
+ * outputs it spends — the `amm-swap` sats and token inputs — spent
304
+ * (wallet-toolbox `markUserInputsSpent`).
305
+ */
306
+ export declare function completeSwap(wallet: WalletInterface, p: PreparedSwap, raw: number[], txid?: string): Promise<CompletedSwap>;