@dcasegr/amm-client 0.39.0 → 0.41.1

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 CHANGED
@@ -40,28 +40,41 @@ exchange with another wallet, keeping what was read and quoted.
40
40
  The client (each an async function unless noted):
41
41
 
42
42
  - the exchange: `enabledList`, `registeredTokens`, `tokenBaseOf`, `hostedTokens` (the token list
43
- and ONE `GET /amm/stats`), `watchTokenPools` (the token's pools route as an event stream: the
44
- whole answer, then each `change` — `swap`, `deploy`, `close`, `rescind` — applied to it, one it
45
- cannot apply read again once; sync, returns the unsubscribe; 0.39.0: no host-wide stream),
43
+ and ONE `GET /amm/stats`), `tokenPools(tokenId)` (0.41.0: the token's pools route, a plain
44
+ read past the browser's cache), `watchPoolEvents(tokenId | "all", onEvent)` (0.41.0: the host's
45
+ pool event feed, `/@<token>/amm/events` or `<origin>/amm/events`; each message `{tokenId, …row}`,
46
+ a `/pools/history` row or a `revert`; signals for display, the pools route the truth; sync,
47
+ returns the unsubscribe; reconnect is the browser EventSource's),
46
48
  `claimStatus`, `isRoot`, `claimExchange`, `discoveryBase` (sync), `onDataChange` (sync);
47
- - history (0.39.0, plain GETs): `trades(tokenId, {from?, to?, limit?, before?, lp?})` →
48
- `{trades, next}`, `trade(tokenId, txid)` → a `Trade` or null, `candles(tokenId, {tf, from, to})`,
49
- `stats(tokenId)`, `statsAll({ids?})`, `holders(tokenId, {limit?, skip?})` → `{count, rows}`,
50
- `positionsAll(lpKeys)` (every enabled token's positions); amounts bigints, prices `{sats,
51
- tokens}` pairs of bigints (base units both);
49
+ - history (plain GETs; 0.40.0: by pool id, `poolId` = the pool's deploy outpoint `<txid>_<vout>`):
50
+ `trades(tokenId, {from?, to?, limit?, before?, pool?})` → `{trades, next}` (each row its
51
+ `poolId` and `payoutPkh`), `trade(tokenId, txid)` → a `Trade` or null, `candles(tokenId, {tf,
52
+ from, to, series?})` (`series` `fill`, the default, or `market`), `stats(tokenId)` /
53
+ `statsAll({ids?, fresh?})` (`price` = the midpoint of what a buy and a sell of 1% of the pooled sats
54
+ would pay now, `buyPrice`, `sellPrice`, `lastTradePrice`), `holders(tokenId, {limit?, skip?})` →
55
+ `{count, rows}`, `positionsAll(poolIds)`, `poolsAt(tokenId, t)` (every pool listed at `t`),
56
+ `poolHistory(tokenId, {from?, to?, pool?, limit?, after?})` → `{events, next}` (oldest first;
57
+ forward paging: `next` as `after`), `spendsAll(outpoints)` (the host's `/amm/spends`); amounts
58
+ bigints, prices `{sats, tokens}` pairs of bigints (base units both);
52
59
  - swap: `quoteSwap(request, poolsAnswer, {sym, dec})` (sync: the engine's plan over the pools the
53
- token's pools stream gave), `executeSwap(quote, {onProgress})`, `checkSwapAgain(leg)`,
54
- `walletSats`;
60
+ token's pools route gave, each pool with its validator's `minLegSats`; the quote's price and
61
+ impact from the engine's `priceOf`, each leg's own `fees`, `stage` = what Swap sets aside
62
+ (`amount`, `feeSats`: 0.40.2, exactly `maxSources` legs), `legMinerFeeSats`); the request's
63
+ `maxSources` (required, 0.40.2; replaces `allowPartial`) is the most pools the swap may draw on —
64
+ 1 is exactly one leg; the Open Exchange pages send 1 or 5,
65
+ `executeSwap(quote, {onProgress, signal})` (below), `walletSats`;
55
66
  - liquidity: `myPositions`, `validatorTerms`, `deployPosition({tokenId, tokens, sats})`,
56
67
  `closePosition({outpoint})`, `rebalancePosition({outpoint, tokens, sats})` (the old pool closed
57
68
  and a new one deployed in ONE wallet createAction);
58
- - your tokens: `myTokens`, `settleSwaps` (the silent pass over staged swap legs: the txids taken
59
- in), `moveBackTokens(tokenId)` (what it did: txid, amount, BEEF, submit), `sendTokens`;
69
+ - your tokens: `myTokens`, `settleSwaps` (the pass over the swap basket: a staged token output the
70
+ basket lacks filed from its action's description; then every row's spender, this wallet's legs
71
+ taken in: the txids), `swapBasketSats`, `moveBackTokens(tokenId)` (every row of the token and
72
+ every sats row: txid, amount, BEEF, submit), `moveBackStagedSats` (the sats alone), `sendTokens`;
60
73
  - settings (root): `deployBeef`, `enableToken`, `tokensToEnable`, `disableToken`, `defaults`,
61
74
  `setDefaultTerms`, `clearDefaultTerms`, `setDefaultMarket`, `clearDefaultMarket`, `tokenTerms`,
62
- `setTokenTerms`, `discoveryState`, `setDiscovery`.
75
+ `setTokenTerms` (0.40.0: the terms `{lpBps, validatorBps, commissionBps, minLegSats?}`), `discoveryState`, `setDiscovery`.
63
76
 
64
- Pure helpers beside it: `hostedFrom`, `applyPoolChange`, `parseChange`, `poolViews`, `poolFees`, `withLeg`, `hasTerms`,
77
+ Pure helpers beside it: `hostedFrom`, `parsePoolEventMessage`, `poolViews`, `poolFees`, `poolsWithMinimums`, `pairPrice`, `legCarrySats`, `hasTerms`,
65
78
  `enableCandidates`, `topicOf`, `lookupOf`, `ammLookupOf`, `walletDeployBeef`, `exchangeBase`,
66
79
  `tokenBase`; the types (`Quote`, `SwapResult`, `LegResult`, `Position`, `WalletToken`, …).
67
80
 
@@ -69,15 +82,19 @@ Pure helpers beside it: `hostedFrom`, `applyPoolChange`, `parseChange`, `poolVie
69
82
 
70
83
  An error of one of `CLIENT_ERROR_KINDS` is a `ClientError` with `kind` and the message the pages
71
84
  show: `stale_pool`, `fee_mismatch`, `quote_mismatch`, `slippage`, `pool_spent`, `user_rejected`,
72
- `no_answer`, `refused`, `network`. A swap leg that did not fill carries its `kind` beside its
73
- `error` text. `errorKind(e)` classifies any error; other errors stay plain `Error`s.
85
+ `no_answer`, `below_minimum` (0.40.0: under a validator's minimum leg; a quote no pool takes),
86
+ `refused`, `network`. `errorKind(e)` classifies any error; other errors stay plain `Error`s.
74
87
 
75
88
  ## The shared names
76
89
 
77
90
  What two sites must use to file identical wallet rows: `POOLS_BASKET` (`amm-pools`, the LP's
78
91
  position rows), `SWAP_BASKET` (`amm-swap`, what swap legs spend), `SWAP_PROTOCOL` (`[2, "amm
79
- swap"]`), `SWAP_KEY_PREFIX` + `swapKeyID` (the staged rows' keyIDs), `swapInstructions` /
80
- `swapSatsInstructions` (their customInstructions), `LP_KEY_PROTOCOL` (BRC-29) + `LP_KEY_MARK` +
92
+ swap"]`), `SWAP_KEY_PREFIX` + `newSwapKeyID` (a staged row's random keyID), `changeKeyID` (a leg's
93
+ change row: `amm-swap-<txid>.<vout>:change` of its first input of that kind), `SWAP_STAGE_LABEL`
94
+ (`amm-swap-stage`) + `SWAP_KEY_MARK` + `swapKeyDescription` / `swapKeyIdOfDescription` (a staged
95
+ token output's description naming its key), `legDerivation` (an order's payout, own commission and
96
+ last-leg change keys), `swapInstructions` / `swapSatsInstructions` (their customInstructions, a
97
+ change row's with `order`), `LP_KEY_PROTOCOL` (BRC-29) + `LP_KEY_MARK` +
81
98
  `lpKeyDescription` / `lpKeyIdOfDescription` (the deploy's pool output description naming the LP
82
99
  keyID), `POOL_TAG` / `POOL_OP` / `isPoolRow` / `poolCustomInstructions` (an `amm-pools` row),
83
100
  `POOL_DEPLOY_LABEL` (`amm-pool-deploy`), `SWAP_TTL_MS` (15 s), `transferPlanLabels` (the `p color
@@ -92,20 +109,36 @@ import { createClient, ClientError } from "@dcasegr/amm-client";
92
109
  const client = createClient({ origin: "https://swap.skein.nexus", wallet });
93
110
  const tokenId = "<txid>_0";
94
111
 
95
- // The token's pools route as an event stream: the pools a swap may use, the market.
96
- const stop = client.watchTokenPools(tokenId, async (pools) => {
97
- stop();
98
- const quote = client.quoteSwap({ tokenId, side: "buy", amountIn: 50_000n, maxSlippageBps: 50, allowPartial: false }, pools, { sym: "TOK", dec: 0 });
99
- try {
100
- const result = await client.executeSwap(quote, { onProgress: (p) => console.log(p.phase) });
101
- console.log(result.status, result.legs);
102
- } catch (e) {
103
- if (e instanceof ClientError && e.kind === "pool_spent") console.log("quote again");
104
- else throw e;
105
- }
106
- });
112
+ // The token's pools route: the pools a swap may use, the market (read again on a pool event).
113
+ const pools = await client.tokenPools(tokenId);
114
+ const quote = client.quoteSwap({ tokenId, side: "buy", amountIn: 50_000n, maxSlippageBps: 50, maxSources: 1 }, pools, { sym: "TOK", dec: 0 });
115
+ try {
116
+ const cancel = new AbortController();
117
+ const result = await client.executeSwap(quote, { signal: cancel.signal, onProgress: (p) => console.log(p.phase) });
118
+ console.log(result.status, result.stop, result.legs, result.returned);
119
+ } catch (e) {
120
+ if (e instanceof ClientError) console.log(e.kind, e.message);
121
+ else throw e;
122
+ }
107
123
  ```
108
124
 
125
+ `executeSwap` (0.40.0; 0.40.2: at most `maxSources` legs, the budget down by one per FILLED leg —
126
+ a refused or unanswered leg does not count, the last leg takes all that remains): ONE swap at a time. First the pass over the swap basket, then ONE wallet
127
+ action stages what `amm-swap` lacks of `quote.stage` (sats only: a plain createAction; a sell's
128
+ tokens: the module transfer). Then legs one at a time: the SERVER's pool list read fresh (0.41.0:
129
+ `GET /@<token>/amm/pools` before EACH leg; the client keeps no list of its own), the engine's
130
+ `nextLeg` over it (`minOut` = the quote's floor less what has filled), the pool's current output by
131
+ its id (`/pools/beef?pool=`), the staged rows that cover the leg (largest first), built, signed,
132
+ relayed; accepted → taken in (payout, own commission, change) before the next leg; refused
133
+ `pool_spent` → the list read again (the relaying host took the validator's state in before it
134
+ answered, 0.41.0); refused otherwise → that pool output excluded; no answer → the overlay
135
+ (a staged input spent: the leg landed), else sent once more, else raced on another pool. It stops
136
+ `filled | cancelled | floor | min | no_pool | fees`. Filled: the last leg's change went to the
137
+ wallet. Stopped early with rows left: `moveBack` runs itself (`result.returned`). Progress phases:
138
+ `staging`, `relaying` / `repricing` (the leg's pool, amounts and the legs filled so far),
139
+ `returning`, `done` / `failed`. The result: `{status, stop, legs: [{poolOutpoint, poolId,
140
+ amountIn, amountOut, txid}], totalIn, totalOut, unfilled, returned?}`.
141
+
109
142
  ## Build
110
143
 
111
144
  From skein-amm's `web/`: `npm ci` in `ui` and in `engine`, then `npm pack` here (the build
package/dist/client.d.ts CHANGED
@@ -15,22 +15,23 @@
15
15
  * (`hostedTokens`): each token's price, liquidity (TVL) and pool count; no host-wide stream.
16
16
  * - **History** (0.39.0, D1–D6): `trades`, `trade`, `candles`, `stats`, `statsAll`, `holders`,
17
17
  * `positionsAll` — plain GETs of the history routes (H1–H6, src/lib/overlay.ts).
18
- * - **Swap** (D11–D16): the token's pools route `GET /@<token>/amm/pools` held as an event stream
19
- * (`watchTokenPools`; 0.39.0, D7: the whole answer once, then one `change` per pool change,
20
- * applied to the held answer): the pools whose validator is beating and whose commission meets the
21
- * market's minimum (the host's filter), the market's commission key hash; a quote is the
22
- * matching engine's plan over that list (no request); a swap reads ONE `GET
23
- * /@<token>/amm/pools/beef?lp=` for its legs (freshness, the pools' BEEF), then each leg's relay
24
- * request (`amm.swap.submit`, held by the host until the relay rests; 15 s expiry); a lost answer
25
- * is "no answer yet" with "Check again" (`GET /@<token>/amm/swaps?id=`, once).
26
- * - **Liquidity** (D9, D23): the wallet's pool rows and deploy history, then ONE `GET
27
- * /@<token>/amm/positions?lp=` per token; a deploy the history has but the basket lacks is
28
- * filed then; Close and Rebalance read their pool's BEEF by LP key (`/pools/beef?lp=`); the
29
- * deploy's terms `GET /@<token>/amm/terms`.
18
+ * - **Swap** (D11–D16; 0.40.0; 0.41.0): the token's pools route `GET /@<token>/amm/pools`, a plain
19
+ * read (`tokenPools`): the pools whose validator is beating and whose commission meets the
20
+ * market's minimum (the host's filter), each validator's minimum leg, the market's commission key
21
+ * hash; a quote is the matching engine's plan over that list (no request); a swap (`executeSwap`)
22
+ * stages what the swap basket lacks by ONE wallet action, then per leg the pools route read fresh,
23
+ * ONE `GET /@<token>/amm/pools/beef?pool=` and the leg's relay request (`amm.swap.submit`, held by
24
+ * the host until the relay rests; 15 s expiry); no answer → the host's `GET /amm/spends`, once
25
+ * more, a race. The pool events (`watchPoolEvents`, 0.41.0: the host's feeds) are signals for
26
+ * display: a page reads the route again on one.
27
+ * - **Liquidity** (D9, D23; 0.40.0: by pool id): the wallet's pool rows and deploy history, then
28
+ * ONE `GET /@<token>/amm/positions?pool=` per token; a deploy the history has but the basket
29
+ * lacks is filed then; Close and Rebalance read their pool's BEEF by its id (`/pools/beef?pool=`);
30
+ * the deploy's terms `GET /@<token>/amm/terms`.
30
31
  * - **Your tokens** (D17, D18, D19, D24): the wallet's module and the swap basket; the token list
31
- * once and ONE discovery `GET /@discovery/1color/tokens?ids=` for held tokens the list lacks; a
32
- * silent pass over the swap basket's staged legs (src/wallet/swapPayouts.ts); Move back submits
33
- * at the host root.
32
+ * once and ONE discovery `GET /@discovery/1color/tokens?ids=` for held tokens the list lacks; the
33
+ * pass over the swap basket (0.40.0: ONE `GET /amm/spends` over every row,
34
+ * src/wallet/swapPayouts.ts); Move back submits at the host root.
34
35
  * - **Settings** (D20, D21): the claim card (`claimStatus`: swap's identity, the recipient of
35
36
  * root's messages), the token list once, discovery's list and ONE `?ids=` read; Enable's deploy
36
37
  * BEEF from the wallet's basket else `GET /@discovery/1color/<token>/deploy`.
@@ -42,14 +43,13 @@
42
43
  */
43
44
  import { type WalletInterface } from "@bsv/sdk";
44
45
  import { type Send1ColorResult } from "@1sat/actions";
45
- import { type PoolState, type Plan } from "@dcasegr/amm-engine";
46
- import { type Candle, type CandleTf, type Holders, type TokenPosition, type TokenStats, type Trade, type TradesPage, type LiveAnswer, type PoolRow, type PoolsAnswer, type SignedFetch } from "./lib/overlay.js";
46
+ import { type Leg, type PoolState, type Plan, type PricePair } from "@dcasegr/amm-engine";
47
+ import { type Candle, type CandleSeries, type CandleTf, type PoolAt, type PoolHistoryPage, type SpendAll, type Holders, type TokenPosition, type TokenStats, type Trade, type TradesPage, type PoolRow, type PoolsAnswer, type PoolEventMessage, type SignedFetch } from "./lib/overlay.js";
47
48
  import { type Defaults, type Discovery, type EnabledToken, type ListedToken } from "./lib/skein.js";
48
49
  import type { AuthFetchLike } from "./market/relay.js";
49
- import { type PreparedSwap } from "./market/swapAction.js";
50
50
  import { type MovedBack } from "./market/activeSwap.js";
51
51
  import { type PositionRow } from "./lp/positions.js";
52
- import { ClientError, type ClientErrorKind } from "./errors.js";
52
+ import { ClientError } from "./errors.js";
53
53
  /** A token id: the BRC-207 assetId `<txid>_<vout>`, `_0` included (src/lib/tokenId.ts). */
54
54
  export type TokenId = string;
55
55
  /** What a swap of 2% of the price costs: the sats a buy needs to move the marginal price up by `bps`. */
@@ -64,7 +64,10 @@ export interface HostedToken {
64
64
  dec: number;
65
65
  /** An image URL (a data: URL of the deploy's embedded icon, or an ORDFS URL). */
66
66
  icon?: string;
67
- /** Sats per whole token across the token's pools: what the next small swap pays. Null with no open pool. */
67
+ /**
68
+ * Sats per whole token (0.40.0: the stats' `price`, the midpoint of what a buy and a sell of 1% of
69
+ * the pooled sats would pay now). Null with no open pool.
70
+ */
68
71
  marginalPrice: number | null;
69
72
  depth: Depth | null;
70
73
  /** Number of open pools. */
@@ -81,6 +84,8 @@ export interface HostedToken {
81
84
  export interface PoolView {
82
85
  /** `<txid>.<vout>` */
83
86
  outpoint: string;
87
+ /** The pool's id (0.40.0): its deploy outpoint, `<txid>_<vout>`. */
88
+ poolId: string;
84
89
  tokenId: TokenId;
85
90
  sats: bigint;
86
91
  tokens: bigint;
@@ -99,11 +104,18 @@ export interface QuoteRequest {
99
104
  amountIn: bigint;
100
105
  /** Max slippage against the quoted amount out, basis points. */
101
106
  maxSlippageBps: number;
102
- allowPartial: boolean;
107
+ /**
108
+ * 0.40.2: the most pools the order may draw on, filled legs counted — a positive integer the
109
+ * caller always gives; the fee sats staged are for exactly that many legs. 1: exactly one leg
110
+ * for the whole amount. Replaces `allowPartial` (`false` was 1).
111
+ */
112
+ maxSources: number;
103
113
  }
104
114
  export interface QuoteLeg {
105
115
  /** The pool, `<txid>.<vout>`. */
106
116
  poolOutpoint: string;
117
+ /** The pool's id (0.40.0). */
118
+ poolId: string;
107
119
  amountIn: bigint;
108
120
  amountOut: bigint;
109
121
  /** Share of the amount in, basis points (the legs sum to 10000). */
@@ -114,37 +126,64 @@ export interface QuoteLeg {
114
126
  tokens: bigint;
115
127
  };
116
128
  validator: ValidatorRef;
129
+ /** The leg's own pool's fees (0.40.0: the fee line per leg). */
130
+ fees: Fees;
131
+ }
132
+ /** What Swap stages into the swap basket before its first leg (0.40.0): the swap amount exact, and the fee sats. */
133
+ export interface QuoteStage {
134
+ /** The swap amount: sats on a buy, token base units on a sell. */
135
+ amount: bigint;
136
+ /** The sats for the carriers and miner fees of `maxSources` legs (0.40.2). */
137
+ feeSats: bigint;
117
138
  }
118
139
  export interface Quote {
119
140
  request: QuoteRequest;
120
141
  legs: QuoteLeg[];
121
142
  amountOut: bigint;
122
- /** The least amount out the swap accepts: amountOut less max slippage. */
143
+ /** The least amount out the swap accepts (the floor): the route's amount out less max slippage. */
123
144
  minAmountOut: bigint;
124
145
  /** Sats per whole token this swap pays (fees included). */
125
146
  effectivePrice: number;
126
- /** Sats per whole token before the swap. */
147
+ /**
148
+ * Sats per whole token now (0.40.0: the engine's `priceOf` over the pools the page holds — what a
149
+ * buy of 1% of the pooled sats would pay on a buy, a sell of 1% of the pooled tokens on a sell).
150
+ */
127
151
  marginalPrice: number;
128
152
  /** |effective − marginal| / marginal, basis points. */
129
153
  impactBps: number;
130
- /** The validator's fees applied to every leg. */
131
- fees: Fees;
154
+ /** What Swap stages (0.40.0). */
155
+ stage: QuoteStage;
156
+ /** The miner fee estimate of one leg, sats. */
157
+ legMinerFeeSats: bigint;
132
158
  }
159
+ /** One leg of a swap that filled (0.40.0). */
133
160
  export interface LegResult {
161
+ /** The pool output it spent, `<txid>.<vout>`. */
134
162
  poolOutpoint: string;
135
- status: "filled" | "failed";
136
- txid?: string;
137
- error?: string;
138
- /** 0.31.1: the leg was refused `pool_spent`, repriced against the pool's newest state and sent again. */
139
- repriced?: true;
140
- /** 0.34.0 (D15): no answer yet — the swap's id, for "Check again" (`checkSwapAgain`). */
141
- checkId?: string;
142
- /** 0.38.0 (D13): the failure's kind, when it has one (`error` stays the text). */
143
- kind?: ClientErrorKind;
163
+ poolId: string;
164
+ amountIn: bigint;
165
+ amountOut: bigint;
166
+ txid: string;
144
167
  }
168
+ /** Why a swap stopped (0.40.0). */
169
+ export type SwapStop = "filled" | "cancelled" | "floor" | "min" | "no_pool" | "fees";
145
170
  export interface SwapResult {
171
+ /** "filled": every unit filled; "partial": some; "failed": none. */
146
172
  status: "filled" | "partial" | "failed";
173
+ stop: SwapStop;
174
+ /** The legs that filled, in order. */
147
175
  legs: LegResult[];
176
+ totalIn: bigint;
177
+ totalOut: bigint;
178
+ /** The swap amount not filled. */
179
+ unfilled: bigint;
180
+ /** What went back to the wallet when the swap stopped early (the Move back's), or why it did not. */
181
+ returned?: {
182
+ txid: string;
183
+ tokens: bigint;
184
+ } | {
185
+ error: string;
186
+ };
148
187
  }
149
188
  /** The validator's fees, basis points of the amount in. The LP accepts them; there is no fee input. */
150
189
  export interface Fees {
@@ -172,11 +211,17 @@ export interface ValidatorTerms {
172
211
  /** "this exchange's" when the validator is this skein. */
173
212
  isThisExchange: boolean;
174
213
  fees: Fees;
214
+ /** The validator's minimum leg, sats on the leg's sats side (0.40.0; 0: none). */
215
+ minLegSats: number;
175
216
  }
176
217
  /** One of the user's pools. A position is only deployed or closed (no add, no partial remove). */
177
218
  export interface Position {
178
219
  /** The pool, `<txid>.<vout>`. */
179
220
  outpoint: string;
221
+ /** The pool's id (0.40.0): its deploy outpoint, `<txid>_<vout>`. */
222
+ poolId: string;
223
+ /** The pool's swaps so far. */
224
+ swaps: number;
180
225
  tokenId: TokenId;
181
226
  sym: string;
182
227
  dec: number;
@@ -244,8 +289,6 @@ export interface WalletToken {
244
289
  outputs: number;
245
290
  /** Held in the exchange's active swap basket (`amm-swap`): spent by swap legs, or moved back. */
246
291
  inSwaps: bigint;
247
- /** Sats staged in `amm-swap` for the token's swap legs (0.29.6): spent by swap legs, or moved back. */
248
- swapSats: number;
249
292
  /** Registered on this exchange. */
250
293
  onExchange: boolean;
251
294
  }
@@ -265,9 +308,10 @@ export interface RegisteredToken {
265
308
  icon?: string;
266
309
  status: EnabledToken["status"];
267
310
  }
268
- export type { EnabledToken, Defaults, Discovery, PoolRow, PoolsAnswer, Candle, CandleTf, Holders, TokenPosition, TokenStats, Trade, TradesPage };
269
- export type { PoolChange, Price } from "./lib/overlay.js";
270
- export { applyPoolChange, parseChange } from "./lib/overlay.js";
311
+ export type { EnabledToken, Defaults, Discovery, PoolRow, PoolsAnswer, Candle, CandleSeries, CandleTf, Holders, PoolAt, PoolHistoryPage, SpendAll, TokenPosition, TokenStats, Trade, TradesPage };
312
+ export type { PoolEvent, PoolEventMessage, PoolRevert } from "./lib/overlay.js";
313
+ export type { Price } from "./lib/overlay.js";
314
+ export { parsePoolEventMessage } from "./lib/overlay.js";
271
315
  /** A token's symbol, decimals and icon, read off its deploy output. */
272
316
  export interface DeployMeta {
273
317
  sym?: string;
@@ -302,8 +346,19 @@ export declare function hostedFrom(list: EnabledToken[], stats: TokenStats[] | n
302
346
  export declare function poolViews(answer: PoolsAnswer | null, tokenId: TokenId): PoolView[];
303
347
  /** The fees a pool's own record names (D13: the Swap page's fee line), basis points. */
304
348
  export declare function poolFees(p: Pick<PoolState, "liquidityFeeBps" | "validationFeeBps" | "commissionBps">): Fees;
305
- /** A swap's result with one leg replaced (after "Check again"). */
306
- export declare function withLeg(r: SwapResult, leg: LegResult): SwapResult;
349
+ /**
350
+ * A pools answer's rows as the planner takes them (0.40.0): each pool with its validator's
351
+ * minimum leg (`validators[].minLegSats`, the validator's announced terms).
352
+ */
353
+ export declare function poolsWithMinimums(answer: PoolsAnswer): PoolRow[];
354
+ /** Sats per whole token of an exact pair (`sats` per `tokens` base units), 0 when `tokens` is 0. */
355
+ export declare function pairPrice(p: PricePair, dec: number): number;
356
+ /**
357
+ * A leg's sats beyond its amount in (0.40.0, the stage's fee sats): the miner fee estimate plus its
358
+ * 1-sat carriers — on a buy the token payout; on a sell the token fee and commission outputs that
359
+ * are not zero, and the token change.
360
+ */
361
+ export declare function legCarrySats(leg: Pick<Leg, "liquidityFee" | "validationFee" | "commission">, buy: boolean, minerFeeSats: bigint): bigint;
307
362
  /**
308
363
  * wallet-toolbox's `specOpWalletBalance` (`sdk.specOpWalletBalance`, @bsv/wallet-toolbox-client): the listOutputs "basket" of its
309
364
  * balance special operation. Written out, not imported: the client package exports it only inside its `sdk` namespace, which
@@ -342,18 +397,17 @@ export interface EnableCandidate {
342
397
  * instance's list (enabled or disabled) left out. Pure: the reads are `tokensToEnable`'s.
343
398
  */
344
399
  export declare function enableCandidates(listed: ListedToken[], walletIds: string[], onList: string[]): EnableCandidate[];
345
- /** The three fees root sets (basis points, integers 0 to 10 000). */
400
+ /** The three fees root sets (basis points, integers 0 to 10 000), and (0.40.0) the minimum leg in sats (absent or 0: none). */
346
401
  export interface TermsInput {
347
402
  lpBps: number;
348
403
  validatorBps: number;
349
404
  commissionBps: number;
405
+ minLegSats?: number;
350
406
  }
351
407
  /** What a quote was planned from: kept for its execution. */
352
408
  interface Planned {
353
409
  plan: Plan;
354
- pools: PoolRow[];
355
- live: LiveAnswer;
356
- market: PoolsAnswer["market"];
410
+ answer: PoolsAnswer;
357
411
  dec: number;
358
412
  sym: string;
359
413
  }
@@ -378,15 +432,31 @@ export interface ClientOptions {
378
432
  /** The wallet's identity key, when the caller has it (the claim's check). Default: read from the wallet when needed. */
379
433
  identityKey?: string | null;
380
434
  }
381
- /** Where a swap is (`executeSwap`'s `onProgress`, D12), in this order; `leg` the pool outpoint (`<txid>.<vout>`) of a leg event. */
435
+ /**
436
+ * Where a swap is (`executeSwap`'s `onProgress`, D12; 0.40.0): `staging` (what the swap basket
437
+ * lacks is staged), `relaying` (a leg sent: its pool outpoint `<txid>.<vout>` and amounts, and the
438
+ * legs filled so far), `repricing` (a leg refused `pool_spent`, the pool's row replaced),
439
+ * `returning` (a swap that stopped early moves its rows back), then `done` or `failed`.
440
+ */
382
441
  export type SwapProgress = {
383
442
  phase: "staging";
443
+ sats: bigint;
444
+ tokens: bigint;
384
445
  } | {
385
446
  phase: "relaying";
386
447
  leg: string;
448
+ amountIn: bigint;
449
+ amountOut: bigint;
450
+ filled: LegResult[];
387
451
  } | {
388
452
  phase: "repricing";
389
453
  leg: string;
454
+ amountIn: bigint;
455
+ amountOut: bigint;
456
+ filled: LegResult[];
457
+ } | {
458
+ phase: "returning";
459
+ filled: LegResult[];
390
460
  } | {
391
461
  phase: "done";
392
462
  result: SwapResult;
@@ -396,8 +466,10 @@ export type SwapProgress = {
396
466
  error?: ClientError | Error;
397
467
  };
398
468
  export interface SwapOptions {
399
- /** Called as the swap moves (D12): `staging` (the swap basket is filled for the legs), `relaying` (per leg), `repricing` (a leg refused `pool_spent`, re-quoted), then `done` (a leg filled) or `failed` (none did, or it threw). */
469
+ /** Called as the swap moves (see `SwapProgress`). */
400
470
  onProgress?: (p: SwapProgress) => void;
471
+ /** Aborted: the swap stops before its next leg (`cancelled`). */
472
+ signal?: AbortSignal;
401
473
  }
402
474
  /** What a client remembers between calls; shared by `withWallet`'s clients. */
403
475
  interface Shared {
@@ -407,12 +479,8 @@ interface Shared {
407
479
  claimRead: ClaimStatus | null;
408
480
  /** What each quote was planned from: kept for its execution. */
409
481
  planned: WeakMap<Quote, Planned>;
410
- /** The legs whose answer did not come: their prepared swap, for "Check again" (D15). */
411
- checks: Map<string, {
412
- prepared: PreparedSwap;
413
- base: string;
414
- af: Signed;
415
- }>;
482
+ /** A swap is running (0.40.0: one at a time). */
483
+ swapping: boolean;
416
484
  /** The positions last loaded, by the output a Close acts on (`<txid>.<vout>`): the wallet's row (its LP key) and the token. */
417
485
  loaded: Map<string, PositionRow>;
418
486
  /** `onDataChange`'s listeners. */
@@ -450,36 +518,47 @@ declare function makeClient(opts: ClientOptions, s: Shared): {
450
518
  isRoot: (identityKey: string | null) => Promise<boolean>;
451
519
  claimExchange: () => Promise<boolean>;
452
520
  hostedTokens: () => Promise<HostedToken[]>;
453
- watchTokenPools: (tokenId: TokenId, onAnswer: (a: PoolsAnswer) => void, onError?: (e: unknown) => void) => () => void;
521
+ tokenPools: (tokenId: string) => Promise<PoolsAnswer>;
522
+ watchPoolEvents: (tokenId: TokenId | "all", onEvent: (e: PoolEventMessage) => void, onError?: (e: unknown) => void) => () => void;
454
523
  trades: (tokenId: string, o?: {
455
524
  from?: number;
456
525
  to?: number;
457
526
  limit?: number;
458
527
  before?: string;
459
- lp?: string;
528
+ pool?: string;
460
529
  } | undefined) => Promise<TradesPage>;
461
530
  trade: (tokenId: string, txid: string) => Promise<Trade | null>;
462
531
  candles: (tokenId: string, o: {
463
532
  tf: CandleTf;
464
533
  from: number;
465
534
  to: number;
535
+ series?: CandleSeries;
466
536
  }) => Promise<Candle[]>;
537
+ poolsAt: (tokenId: string, t: number) => Promise<PoolAt[]>;
538
+ poolHistory: (tokenId: string, o?: {
539
+ from?: number;
540
+ to?: number;
541
+ pool?: string;
542
+ limit?: number;
543
+ after?: string;
544
+ } | undefined) => Promise<PoolHistoryPage>;
545
+ spendsAll: (outpoints: string[]) => Promise<SpendAll[]>;
467
546
  stats: (tokenId: string) => Promise<TokenStats>;
468
547
  statsAll: (o?: {
469
548
  ids?: TokenId[];
549
+ fresh?: boolean;
470
550
  } | undefined) => Promise<TokenStats[]>;
471
551
  holders: (tokenId: string, o?: {
472
552
  limit?: number;
473
553
  skip?: number;
474
554
  } | undefined) => Promise<Holders>;
475
- positionsAll: (lpKeys: string[]) => Promise<TokenPosition[]>;
555
+ positionsAll: (poolIds: string[]) => Promise<TokenPosition[]>;
476
556
  registeredTokens: () => Promise<RegisteredToken[]>;
477
557
  quoteSwap: (req: QuoteRequest, held: PoolsAnswer | null, meta: {
478
558
  sym: string;
479
559
  dec: number;
480
560
  }) => Quote;
481
561
  executeSwap: (quote: Quote, o?: SwapOptions) => Promise<SwapResult>;
482
- checkSwapAgain: (leg: LegResult) => Promise<LegResult>;
483
562
  walletSats: () => Promise<bigint>;
484
563
  myPositions: () => Promise<Position[]>;
485
564
  validatorTerms: (tokenId: string) => Promise<NoTerms | ValidatorTerms>;
@@ -488,6 +567,8 @@ declare function makeClient(opts: ClientOptions, s: Shared): {
488
567
  rebalancePosition: (req: RebalanceRequest) => Promise<RebalanceResult>;
489
568
  myTokens: () => Promise<WalletToken[]>;
490
569
  settleSwaps: () => Promise<string[]>;
570
+ swapBasketSats: () => Promise<number>;
571
+ moveBackStagedSats: () => Promise<MovedBack>;
491
572
  moveBackTokens: (tokenId: string) => Promise<MovedBack>;
492
573
  sendTokens: (tokenId: string, handle: string, amount: bigint, memo?: string | undefined) => Promise<Send1ColorResult>;
493
574
  deployBeef: (tokenId: string, wallet?: WalletInterface | null | undefined) => Promise<DeployFound>;
@@ -502,6 +583,7 @@ declare function makeClient(opts: ClientOptions, s: Shared): {
502
583
  lpFeeBps: number;
503
584
  validatorFeeBps: number;
504
585
  commissionBps: number;
586
+ minLegSats: number;
505
587
  } | null>;
506
588
  setTokenTerms: (tokenId: string, t: TermsInput | null) => Promise<void>;
507
589
  clearDefaultTerms: () => Promise<void>;
@@ -520,36 +602,47 @@ declare function makeClient(opts: ClientOptions, s: Shared): {
520
602
  isRoot: (identityKey: string | null) => Promise<boolean>;
521
603
  claimExchange: () => Promise<boolean>;
522
604
  hostedTokens: () => Promise<HostedToken[]>;
523
- watchTokenPools: (tokenId: TokenId, onAnswer: (a: PoolsAnswer) => void, onError?: (e: unknown) => void) => () => void;
605
+ tokenPools: (tokenId: string) => Promise<PoolsAnswer>;
606
+ watchPoolEvents: (tokenId: TokenId | "all", onEvent: (e: PoolEventMessage) => void, onError?: (e: unknown) => void) => () => void;
524
607
  trades: (tokenId: string, o?: {
525
608
  from?: number;
526
609
  to?: number;
527
610
  limit?: number;
528
611
  before?: string;
529
- lp?: string;
612
+ pool?: string;
530
613
  } | undefined) => Promise<TradesPage>;
531
614
  trade: (tokenId: string, txid: string) => Promise<Trade | null>;
532
615
  candles: (tokenId: string, o: {
533
616
  tf: CandleTf;
534
617
  from: number;
535
618
  to: number;
619
+ series?: CandleSeries;
536
620
  }) => Promise<Candle[]>;
621
+ poolsAt: (tokenId: string, t: number) => Promise<PoolAt[]>;
622
+ poolHistory: (tokenId: string, o?: {
623
+ from?: number;
624
+ to?: number;
625
+ pool?: string;
626
+ limit?: number;
627
+ after?: string;
628
+ } | undefined) => Promise<PoolHistoryPage>;
629
+ spendsAll: (outpoints: string[]) => Promise<SpendAll[]>;
537
630
  stats: (tokenId: string) => Promise<TokenStats>;
538
631
  statsAll: (o?: {
539
632
  ids?: TokenId[];
633
+ fresh?: boolean;
540
634
  } | undefined) => Promise<TokenStats[]>;
541
635
  holders: (tokenId: string, o?: {
542
636
  limit?: number;
543
637
  skip?: number;
544
638
  } | undefined) => Promise<Holders>;
545
- positionsAll: (lpKeys: string[]) => Promise<TokenPosition[]>;
639
+ positionsAll: (poolIds: string[]) => Promise<TokenPosition[]>;
546
640
  registeredTokens: () => Promise<RegisteredToken[]>;
547
641
  quoteSwap: (req: QuoteRequest, held: PoolsAnswer | null, meta: {
548
642
  sym: string;
549
643
  dec: number;
550
644
  }) => Quote;
551
645
  executeSwap: (quote: Quote, o?: SwapOptions) => Promise<SwapResult>;
552
- checkSwapAgain: (leg: LegResult) => Promise<LegResult>;
553
646
  walletSats: () => Promise<bigint>;
554
647
  myPositions: () => Promise<Position[]>;
555
648
  validatorTerms: (tokenId: string) => Promise<NoTerms | ValidatorTerms>;
@@ -558,6 +651,8 @@ declare function makeClient(opts: ClientOptions, s: Shared): {
558
651
  rebalancePosition: (req: RebalanceRequest) => Promise<RebalanceResult>;
559
652
  myTokens: () => Promise<WalletToken[]>;
560
653
  settleSwaps: () => Promise<string[]>;
654
+ swapBasketSats: () => Promise<number>;
655
+ moveBackStagedSats: () => Promise<MovedBack>;
561
656
  moveBackTokens: (tokenId: string) => Promise<MovedBack>;
562
657
  sendTokens: (tokenId: string, handle: string, amount: bigint, memo?: string | undefined) => Promise<Send1ColorResult>;
563
658
  deployBeef: (tokenId: string, wallet?: WalletInterface | null | undefined) => Promise<DeployFound>;
@@ -572,6 +667,7 @@ declare function makeClient(opts: ClientOptions, s: Shared): {
572
667
  lpFeeBps: number;
573
668
  validatorFeeBps: number;
574
669
  commissionBps: number;
670
+ minLegSats: number;
575
671
  } | null>;
576
672
  setTokenTerms: (tokenId: string, t: TermsInput | null) => Promise<void>;
577
673
  clearDefaultTerms: () => Promise<void>;