@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,220 @@
1
+ /**
2
+ * Creating a pool from a token in the wallet (skein-amm 0.13.0, David Case
3
+ * 2026-10-22, plans/validator-signoff §2): ONE wallet-built createAction,
4
+ * affirmed first by this skein's validator. The page holds no keys and names
5
+ * no token input: the wallet's BRC-207 module selects the token inputs and
6
+ * adds token change; every key and signature comes from the wallet.
7
+ *
8
+ * 1. The LP key: a BRC-29 key to self under a fresh random keyID
9
+ * (`newLpKey`: derivationPrefix base64("amm-lp"), derivationSuffix 16
10
+ * random bytes), kept in the position row and (0.29.4, David) in the
11
+ * pool output's description in the same createAction that makes the
12
+ * transaction: `AMM pool: <SYM> / BSV · amm-lp <the suffix's 16 bytes,
13
+ * hex>` (`lpKeyDescription`): the deploy history alone gives it back
14
+ * (`lpKeyIdOfDescription`; Recover and Positions read it first). Nothing
15
+ * is kept in the browser.
16
+ * 2. `amm.pool.terms` (the validator and its fees), then `amm.pool.affirm
17
+ * {pool, satoshis}`: the proposed pool output, its ValidatorPubKey,
18
+ * Nonce and Affirmation still to come (33 zero bytes, 32 zero bytes,
19
+ * empty) → `{validatorPubKey, nonce, signature}`. The page checks the
20
+ * key is the validator's child of the nonce and the signature affirms
21
+ * the pool (`PoolTemplate.affirmed`), then writes the three into the
22
+ * pool's state (`PoolTemplate.lockDeploy`).
23
+ * 3. `createAction`: outputs [the pool] (the deposit's tokens to a foreign
24
+ * script: a transfer in the `p color plan`, no `inputPositions`, no
25
+ * owned outputs), `randomizeOutputs: false`. The module selects the token
26
+ * inputs and adds the token change; the wallet funds the sats, signs and
27
+ * broadcasts; the module submits to `tm_color_<assetId>`. The page submits
28
+ * it there too (plain fetch, a repeat is harmless). The input BEEF of the
29
+ * module's own inputs is the module's (BRC-207 module 0.1.1; the
30
+ * validator-signoff record §10).
31
+ * 4. The position row: output 0 filed in the exchange's own basket
32
+ * `amm-pools` (basket insertion; customInstructions the LP key, the
33
+ * validator, its fees and its nonce).
34
+ *
35
+ * Keys:
36
+ * - LP key: as above (0.29.1: the pre-0.13.0 LP keys, keyed by the deploy's
37
+ * first token input or under `P1SAT_PROTOCOL`, are gone with layout 1).
38
+ * - Validator key: the anyone-child of the validator's identity keyed by
39
+ * the nonce (src/lib/keys.ts `deriveFirstValidatorPubKey`), a public
40
+ * derivation the page checks.
41
+ */
42
+ import { type WalletInterface, type WalletProtocol } from "@bsv/sdk";
43
+ import { type PoolArgs, type PoolFields } from "../pool/index.js";
44
+ import { type AuthFetchLike } from "../market/relay.js";
45
+ import { type HeldOutput } from "../wallet/color.js";
46
+ import { POOL_OP, POOL_TAG, isPoolRow } from "./poolRows.js";
47
+ export { POOL_OP, POOL_TAG, isPoolRow };
48
+ /** The validator a pool names: its identity key (compressed, lowercase hex). */
49
+ export interface ValidatorChoice {
50
+ identityKey: string;
51
+ }
52
+ /** The LP key's protocol: BRC-29 (see the module comment). */
53
+ export declare const LP_KEY_PROTOCOL: WalletProtocol;
54
+ /** `amm.pool.affirm` (amm-p2p, 0.11.0; 0.13.0: `{pool, satoshis}` → `{validatorPubKey, nonce, signature}`). */
55
+ export declare const POOL_AFFIRM_FN = "amm.pool.affirm";
56
+ /** The marker the deploy's pool output description ends with (0.29.4): ` · amm-lp <hex>`. */
57
+ export declare const LP_KEY_MARK = " \u00B7 amm-lp ";
58
+ /**
59
+ * The pool output's description in the deploy createAction (0.29.4, David Case 2026-11-02): the
60
+ * readable text as before (`AMM pool: <SYM> / BSV`, at most 50 characters) then ` · amm-lp ` and
61
+ * the LP keyID's derivationSuffix bytes in lowercase hex (16 bytes: 32 characters). The sdk takes
62
+ * up to 2000 bytes; the wallet's permissions manager stores it encrypted and decrypts it on the
63
+ * way out (listActions through the manager answers it verbatim).
64
+ */
65
+ export declare function lpKeyDescription(readable: string, keyID: string): string;
66
+ /** The LP keyID an output description names (`lpKeyDescription`), or null. */
67
+ export declare function lpKeyIdOfDescription(description: string | undefined): string | null;
68
+ /** A new pool's LP key derivation (0.13.0): derivationPrefix base64("amm-lp"), derivationSuffix 16 random bytes, base64. */
69
+ export declare function newLpDerivation(): {
70
+ derivationPrefix: string;
71
+ derivationSuffix: string;
72
+ };
73
+ /** A basket row as the wallet lists it. */
74
+ export interface BasketRow {
75
+ outpoint: string;
76
+ satoshis: number;
77
+ lockingScript?: string;
78
+ tags?: string[];
79
+ customInstructions?: string;
80
+ }
81
+ /** One of the wallet's own value outputs of a token, as the module holds it. */
82
+ export interface HeldValue {
83
+ /** `txid.vout` */
84
+ outpoint: string;
85
+ txid: string;
86
+ vout: number;
87
+ amount: bigint;
88
+ }
89
+ /** The wallet's available value outputs of `tokenId` (a fixed-supply deploy output among them), from `p color assets`: what the module selects from. */
90
+ export declare function valueOutputsOf(held: HeldOutput[], tokenId: string): HeldValue[];
91
+ export interface PoolDeployForm {
92
+ tokenId: string;
93
+ tokens: bigint;
94
+ sats: bigint;
95
+ lpFeeBps: bigint;
96
+ validatorFeeBps: bigint;
97
+ /** The relay's commission (the contract's CommissionBps), fixed at deploy. Default 0. */
98
+ commissionBps?: bigint;
99
+ lpPubKey: string;
100
+ /** The LP key's keyID (BRC-29, `newLpDerivation`). */
101
+ lpKeyId: string;
102
+ validator: ValidatorChoice;
103
+ dec?: number;
104
+ }
105
+ export interface PoolDeployPlan {
106
+ tokenId: string;
107
+ /** `tm_color_<assetId>`, `tm_color_<txid>_0`: the token's topic (BRC-207). */
108
+ topic: string;
109
+ args: PoolArgs;
110
+ /** The pool's state as proposed: its ValidatorPubKey (33 zero bytes), Nonce and Affirmation still to come. */
111
+ state: PoolFields;
112
+ /** Output 0's script as proposed, hex: what `amm.pool.affirm` is asked about. */
113
+ lockingScript: string;
114
+ lpKeyId: string;
115
+ sats: bigint;
116
+ /** Initial marginal price, sats per token (display units when `dec` is known). */
117
+ price: string;
118
+ }
119
+ export declare class PoolDeployError extends Error {
120
+ constructor(message: string);
121
+ }
122
+ /** A token with a 32-byte id (`<txid>_0`; `<txid>` / `<txid>.0` read the same) → the wire id (internal byte order), hex. */
123
+ export declare function assetIdHex(tokenId: string): string;
124
+ export declare function planPoolDeploy(f: PoolDeployForm): PoolDeployPlan;
125
+ /** A 1Color value output of `amount` to `pubKeyHash` (P2PKH), as Pool.runar.go's `tokenP2pkh` writes it. */
126
+ export declare function tokenP2pkhScript(tokenId: string, amount: bigint, pubKey: string): string;
127
+ /** customInstructions of a pool output the wallet holds as LP (`amm-pools`). */
128
+ export declare function poolCustomInstructions(o: {
129
+ tokenId: string;
130
+ sym?: string;
131
+ dec?: number;
132
+ protocolID: WalletProtocol;
133
+ keyID: string;
134
+ args: PoolArgs;
135
+ validatorIdentity: string;
136
+ /** The validator's nonce (0.13.0), hex; absent for a pool before it. */
137
+ nonce?: string;
138
+ }): string;
139
+ /** The validator's affirmation (0.13.0): its key, its nonce, its signature; and the pool's state with them. */
140
+ export interface Affirmation {
141
+ validatorPubKey: string;
142
+ nonce: string;
143
+ signature: string;
144
+ state: PoolFields;
145
+ lockingScript: string;
146
+ }
147
+ /**
148
+ * `amm.pool.affirm {pool, satoshis}` (docs/AMM.md "The deploy and the affirmation") →
149
+ * `{validatorPubKey, nonce, signature}`, checked before it is used: the key is the validator's
150
+ * child of the nonce, and the pool with the three in its state attests itself.
151
+ */
152
+ export declare function affirmPool(af: AuthFetchLike, base: string, plan: PoolDeployPlan): Promise<Affirmation>;
153
+ /** A new pool's LP key (0.13.0): a BRC-29 key to self under a fresh random keyID (`newLpDerivation`). */
154
+ export declare function newLpKey(wallet: WalletInterface): Promise<{
155
+ protocolID: WalletProtocol;
156
+ keyID: string;
157
+ publicKey: string;
158
+ }>;
159
+ export declare class DeployShapeError extends Error {
160
+ constructor(message: string);
161
+ }
162
+ /** How an output of ours is taken into a basket after the fact (`internalizeAction` basket insertion). */
163
+ export interface BasketFiling {
164
+ outputIndex: number;
165
+ basket: string;
166
+ tags: string[];
167
+ customInstructions: string;
168
+ }
169
+ export interface DeployPoolInput {
170
+ wallet: WalletInterface;
171
+ /** The wallet's BRC-104 client (`amm.pool.affirm` on `/call`). */
172
+ af: AuthFetchLike;
173
+ /** The AMM app's base URL. */
174
+ base: string;
175
+ tokenId: string;
176
+ tokens: bigint;
177
+ sats: bigint;
178
+ fees: {
179
+ lpFeeBps: bigint;
180
+ validatorFeeBps: bigint;
181
+ commissionBps: bigint;
182
+ };
183
+ validator: ValidatorChoice;
184
+ /** The wallet's held token outputs (`p color assets`). */
185
+ held: HeldOutput[];
186
+ meta?: {
187
+ sym?: string;
188
+ dec?: number;
189
+ };
190
+ /** The submit to this skein (default: `POST <base>/submit`, plain fetch). */
191
+ submit?: (topic: string, beef: number[]) => Promise<{
192
+ steak?: unknown;
193
+ }>;
194
+ }
195
+ export interface DeployedPool {
196
+ plan: PoolDeployPlan;
197
+ lpKey: {
198
+ protocolID: WalletProtocol;
199
+ keyID: string;
200
+ publicKey: string;
201
+ };
202
+ /** The validator's affirmation and the deployed pool's state. */
203
+ affirmation: Affirmation;
204
+ /** The createAction arguments the wallet was given. */
205
+ createArgs: Parameters<WalletInterface["createAction"]>[0];
206
+ txid: string;
207
+ /** The deploy as the wallet's AtomicBEEF. */
208
+ tx: number[];
209
+ /** `<txid>.0` */
210
+ outpoint: string;
211
+ /** The position row (`amm-pools`). */
212
+ filing: BasketFiling;
213
+ filed: boolean;
214
+ /** The page's own submit, in words (src/lp/close.ts `steakText`), or its error. */
215
+ submitted: string;
216
+ /** Filing or submit errors (the deploy itself is broadcast). */
217
+ errors: string[];
218
+ }
219
+ /** Steps 1-4 (see the module comment). Throws before the wallet's action exists; after it, errors are collected. */
220
+ export declare function deployPool(i: DeployPoolInput): Promise<DeployedPool>;
@@ -0,0 +1,291 @@
1
+ /**
2
+ * Creating a pool from a token in the wallet (skein-amm 0.13.0, David Case
3
+ * 2026-10-22, plans/validator-signoff §2): ONE wallet-built createAction,
4
+ * affirmed first by this skein's validator. The page holds no keys and names
5
+ * no token input: the wallet's BRC-207 module selects the token inputs and
6
+ * adds token change; every key and signature comes from the wallet.
7
+ *
8
+ * 1. The LP key: a BRC-29 key to self under a fresh random keyID
9
+ * (`newLpKey`: derivationPrefix base64("amm-lp"), derivationSuffix 16
10
+ * random bytes), kept in the position row and (0.29.4, David) in the
11
+ * pool output's description in the same createAction that makes the
12
+ * transaction: `AMM pool: <SYM> / BSV · amm-lp <the suffix's 16 bytes,
13
+ * hex>` (`lpKeyDescription`): the deploy history alone gives it back
14
+ * (`lpKeyIdOfDescription`; Recover and Positions read it first). Nothing
15
+ * is kept in the browser.
16
+ * 2. `amm.pool.terms` (the validator and its fees), then `amm.pool.affirm
17
+ * {pool, satoshis}`: the proposed pool output, its ValidatorPubKey,
18
+ * Nonce and Affirmation still to come (33 zero bytes, 32 zero bytes,
19
+ * empty) → `{validatorPubKey, nonce, signature}`. The page checks the
20
+ * key is the validator's child of the nonce and the signature affirms
21
+ * the pool (`PoolTemplate.affirmed`), then writes the three into the
22
+ * pool's state (`PoolTemplate.lockDeploy`).
23
+ * 3. `createAction`: outputs [the pool] (the deposit's tokens to a foreign
24
+ * script: a transfer in the `p color plan`, no `inputPositions`, no
25
+ * owned outputs), `randomizeOutputs: false`. The module selects the token
26
+ * inputs and adds the token change; the wallet funds the sats, signs and
27
+ * broadcasts; the module submits to `tm_color_<assetId>`. The page submits
28
+ * it there too (plain fetch, a repeat is harmless). The input BEEF of the
29
+ * module's own inputs is the module's (BRC-207 module 0.1.1; the
30
+ * validator-signoff record §10).
31
+ * 4. The position row: output 0 filed in the exchange's own basket
32
+ * `amm-pools` (basket insertion; customInstructions the LP key, the
33
+ * validator, its fees and its nonce).
34
+ *
35
+ * Keys:
36
+ * - LP key: as above (0.29.1: the pre-0.13.0 LP keys, keyed by the deploy's
37
+ * first token input or under `P1SAT_PROTOCOL`, are gone with layout 1).
38
+ * - Validator key: the anyone-child of the validator's identity keyed by
39
+ * the nonce (src/lib/keys.ts `deriveFirstValidatorPubKey`), a public
40
+ * derivation the page checks.
41
+ */
42
+ import { P2PKH, PublicKey, Transaction, Utils } from "@bsv/sdk";
43
+ import { PoolTemplate, RESCINDED_KEY, decodeOneColor, oneColorValuePrefix } from "../pool/index.js";
44
+ import { deriveFirstValidatorPubKey } from "../lib/keys.js";
45
+ import { priceOf } from "../market/view.js";
46
+ import { callApp, dagBytes, readBytes } from "../market/relay.js";
47
+ import { BRC29_PROTOCOL, brc29KeyID, randomBase64 } from "../wallet/brc29.js";
48
+ import { POOLS_BASKET, runTokenAction, transferPlanLabels } from "../wallet/color.js";
49
+ import { POOL_OP, POOL_TAG, isPoolRow } from "./poolRows.js";
50
+ import { parseOutpoint, parseTokenId, sdkTokenId, tokenIdOfWire, tokenIdText } from "../lib/tokenId.js";
51
+ import { submitToOverlay, steakText } from "./close.js";
52
+ export { POOL_OP, POOL_TAG, isPoolRow };
53
+ /** The LP key's protocol: BRC-29 (see the module comment). */
54
+ export const LP_KEY_PROTOCOL = BRC29_PROTOCOL;
55
+ const LP_DERIVATION_PREFIX = Utils.toBase64(Utils.toArray("amm-lp", "utf8"));
56
+ /** `amm.pool.affirm` (amm-p2p, 0.11.0; 0.13.0: `{pool, satoshis}` → `{validatorPubKey, nonce, signature}`). */
57
+ export const POOL_AFFIRM_FN = "amm.pool.affirm";
58
+ const toHex = (b) => Utils.toHex(Array.from(b));
59
+ function describe(text) {
60
+ return text.length <= 50 ? text : `${text.slice(0, 49)}…`;
61
+ }
62
+ /** The marker the deploy's pool output description ends with (0.29.4): ` · amm-lp <hex>`. */
63
+ export const LP_KEY_MARK = " · amm-lp ";
64
+ /**
65
+ * The pool output's description in the deploy createAction (0.29.4, David Case 2026-11-02): the
66
+ * readable text as before (`AMM pool: <SYM> / BSV`, at most 50 characters) then ` · amm-lp ` and
67
+ * the LP keyID's derivationSuffix bytes in lowercase hex (16 bytes: 32 characters). The sdk takes
68
+ * up to 2000 bytes; the wallet's permissions manager stores it encrypted and decrypts it on the
69
+ * way out (listActions through the manager answers it verbatim).
70
+ */
71
+ export function lpKeyDescription(readable, keyID) {
72
+ const suffix = keyID.split(" ")[1];
73
+ if (keyID.split(" ")[0] !== LP_DERIVATION_PREFIX || !suffix)
74
+ throw new PoolDeployError(`not a deploy LP keyID: ${keyID}`);
75
+ return `${readable}${LP_KEY_MARK}${toHex(Utils.toArray(suffix, "base64"))}`;
76
+ }
77
+ /** The LP keyID an output description names (`lpKeyDescription`), or null. */
78
+ export function lpKeyIdOfDescription(description) {
79
+ const m = / · amm-lp ([0-9a-f]{2,128})$/.exec(description ?? "");
80
+ if (!m || m[1].length % 2 !== 0)
81
+ return null;
82
+ return `${LP_DERIVATION_PREFIX} ${Utils.toBase64(Utils.toArray(m[1], "hex"))}`;
83
+ }
84
+ /** A new pool's LP key derivation (0.13.0): derivationPrefix base64("amm-lp"), derivationSuffix 16 random bytes, base64. */
85
+ export function newLpDerivation() {
86
+ return { derivationPrefix: LP_DERIVATION_PREFIX, derivationSuffix: randomBase64(16) };
87
+ }
88
+ /** The wallet's available value outputs of `tokenId` (a fixed-supply deploy output among them), from `p color assets`: what the module selects from. */
89
+ export function valueOutputsOf(held, tokenId) {
90
+ const want = tokenIdText(parseTokenId(tokenId) ?? { txid: "", vout: -1 });
91
+ const out = [];
92
+ for (const h of held) {
93
+ if (!h.available)
94
+ continue;
95
+ const op = parseOutpoint(h.outpoint);
96
+ if (!op)
97
+ continue;
98
+ // A pool output carries the same 1Color prefix; it is never a token input.
99
+ if (PoolTemplate.decode(h.lockingScript))
100
+ continue;
101
+ const t = decodeOneColor(Utils.toArray(h.lockingScript, "hex"));
102
+ if (!t || t.amount <= 0n)
103
+ continue;
104
+ const id = t.role === "deploy" ? tokenIdText(op) : t.role === "value" && t.idBytes ? tokenIdOfWire(t.idBytes) : null;
105
+ if (id !== want)
106
+ continue;
107
+ out.push({ outpoint: `${op.txid}.${op.vout}`, txid: op.txid, vout: op.vout, amount: t.amount });
108
+ }
109
+ return out;
110
+ }
111
+ export class PoolDeployError extends Error {
112
+ constructor(message) {
113
+ super(message);
114
+ this.name = "PoolDeployError";
115
+ }
116
+ }
117
+ /** A token with a 32-byte id (`<txid>_0`; `<txid>` / `<txid>.0` read the same) → the wire id (internal byte order), hex. */
118
+ export function assetIdHex(tokenId) {
119
+ const r = parseTokenId(tokenId);
120
+ if (!r || r.vout !== 0)
121
+ throw new PoolDeployError(`pools exist only for 1Color tokens with a 32-byte id (<txid>_0), not ${tokenId}`);
122
+ return toHex(Utils.toArray(r.txid, "hex").reverse());
123
+ }
124
+ export function planPoolDeploy(f) {
125
+ const assetId = assetIdHex(f.tokenId);
126
+ if (f.tokens <= 0n)
127
+ throw new PoolDeployError("the token deposit must be positive");
128
+ if (f.sats <= 0n || f.sats > BigInt(Number.MAX_SAFE_INTEGER))
129
+ throw new PoolDeployError("the sats deposit must be positive");
130
+ const commissionBps = f.commissionBps ?? 0n;
131
+ for (const [name, bps] of [["LP fee", f.lpFeeBps], ["validator fee", f.validatorFeeBps], ["commission", commissionBps]]) {
132
+ if (bps < 0n || bps >= 10000n)
133
+ throw new PoolDeployError(`${name}: 0-9999 bps`);
134
+ }
135
+ if (f.lpFeeBps + f.validatorFeeBps + commissionBps >= 10000n)
136
+ throw new PoolDeployError("the fees together must stay below 100%");
137
+ const args = { assetId, lpFeeBps: f.lpFeeBps, validatorFeeBps: f.validatorFeeBps, commissionBps };
138
+ const state = {
139
+ tokenReserve: f.tokens,
140
+ lpPubKey: PublicKey.fromString(f.lpPubKey).toString(),
141
+ validatorPubKey: RESCINDED_KEY, // to come: the validator's
142
+ validatorIdentity: PublicKey.fromString(f.validator.identityKey).toString(),
143
+ nonce: "00".repeat(32),
144
+ affirmation: "",
145
+ };
146
+ return {
147
+ tokenId: f.tokenId,
148
+ topic: `tm_color_${sdkTokenId(f.tokenId)}`,
149
+ args,
150
+ state,
151
+ lockingScript: PoolTemplate.lockDeploy(args, state).toHex(),
152
+ lpKeyId: f.lpKeyId,
153
+ sats: f.sats,
154
+ price: priceOf(f.sats, f.tokens, f.dec),
155
+ };
156
+ }
157
+ /** A 1Color value output of `amount` to `pubKeyHash` (P2PKH), as Pool.runar.go's `tokenP2pkh` writes it. */
158
+ export function tokenP2pkhScript(tokenId, amount, pubKey) {
159
+ const prefix = oneColorValuePrefix(Utils.toArray(assetIdHex(tokenId), "hex"), amount);
160
+ return toHex(prefix) + new P2PKH().lock(PublicKey.fromString(pubKey).toAddress()).toHex();
161
+ }
162
+ /** customInstructions of a pool output the wallet holds as LP (`amm-pools`). */
163
+ export function poolCustomInstructions(o) {
164
+ return JSON.stringify({
165
+ id: o.tokenId,
166
+ op: POOL_OP,
167
+ ...(o.sym ? { sym: o.sym } : {}),
168
+ ...(o.dec !== undefined ? { dec: String(o.dec) } : {}),
169
+ protocolID: o.protocolID,
170
+ keyID: o.keyID,
171
+ counterparty: "self",
172
+ amm: { role: "lp", validatorIdentity: o.validatorIdentity, lpFeeBps: String(o.args.lpFeeBps), validatorFeeBps: String(o.args.validatorFeeBps), commissionBps: String(o.args.commissionBps), ...(o.nonce ? { nonce: o.nonce } : {}) },
173
+ });
174
+ }
175
+ /**
176
+ * `amm.pool.affirm {pool, satoshis}` (docs/AMM.md "The deploy and the affirmation") →
177
+ * `{validatorPubKey, nonce, signature}`, checked before it is used: the key is the validator's
178
+ * child of the nonce, and the pool with the three in its state attests itself.
179
+ */
180
+ export async function affirmPool(af, base, plan) {
181
+ const r = (await callApp(af, base, POOL_AFFIRM_FN, {
182
+ pool: dagBytes(Utils.toArray(plan.lockingScript, "hex")),
183
+ satoshis: Number(plan.sats),
184
+ }));
185
+ const sig = readBytes(r?.signature);
186
+ const key = readBytes(r?.validatorPubKey);
187
+ const nonce = readBytes(r?.nonce);
188
+ if (!sig || sig.length === 0)
189
+ throw new PoolDeployError(`${POOL_AFFIRM_FN}: no signature in the answer`);
190
+ if (!key || key.length !== 33 || !nonce || nonce.length !== 32)
191
+ throw new PoolDeployError(`${POOL_AFFIRM_FN}: no validatorPubKey (33 bytes) and nonce (32 bytes) in the answer`);
192
+ const validatorPubKey = toHex(key);
193
+ if (deriveFirstValidatorPubKey(plan.state.validatorIdentity, toHex(nonce)) !== validatorPubKey)
194
+ throw new PoolDeployError(`${POOL_AFFIRM_FN}: the key is not the validator's child of its nonce`);
195
+ const state = { ...plan.state, validatorPubKey, nonce: toHex(nonce), affirmation: toHex(sig) };
196
+ const lockingScript = PoolTemplate.lockDeploy(plan.args, state).toHex();
197
+ if (!PoolTemplate.affirmed(lockingScript, plan.sats))
198
+ throw new PoolDeployError(`${POOL_AFFIRM_FN}: the signature does not affirm this pool (not the ValidatorPubKey's over its parameters)`);
199
+ return { validatorPubKey, nonce: toHex(nonce), signature: toHex(sig), state, lockingScript };
200
+ }
201
+ // ---------------------------------------------------------------------------
202
+ // The wallet sequence
203
+ // ---------------------------------------------------------------------------
204
+ /** A new pool's LP key (0.13.0): a BRC-29 key to self under a fresh random keyID (`newLpDerivation`). */
205
+ export async function newLpKey(wallet) {
206
+ const protocolID = LP_KEY_PROTOCOL;
207
+ const keyID = brc29KeyID(newLpDerivation());
208
+ const { publicKey } = await wallet.getPublicKey({ protocolID, keyID, counterparty: "self", forSelf: true });
209
+ return { protocolID, keyID, publicKey };
210
+ }
211
+ export class DeployShapeError extends Error {
212
+ constructor(message) {
213
+ super(message);
214
+ this.name = "DeployShapeError";
215
+ }
216
+ }
217
+ /** Steps 1-4 (see the module comment). Throws before the wallet's action exists; after it, errors are collected. */
218
+ export async function deployPool(i) {
219
+ const { wallet } = i;
220
+ const meta = i.meta ?? {};
221
+ const sdkId = sdkTokenId(i.tokenId);
222
+ assetIdHex(i.tokenId);
223
+ const held = valueOutputsOf(i.held, i.tokenId).reduce((a, o) => a + o.amount, 0n);
224
+ if (held < i.tokens)
225
+ throw new PoolDeployError(`Your wallet holds fewer than ${i.tokens} base units of that token`);
226
+ // 1. The LP key.
227
+ const lpKey = await newLpKey(wallet);
228
+ const plan = planPoolDeploy({
229
+ tokenId: i.tokenId,
230
+ tokens: i.tokens,
231
+ sats: i.sats,
232
+ ...i.fees,
233
+ lpPubKey: lpKey.publicKey,
234
+ lpKeyId: lpKey.keyID,
235
+ validator: i.validator,
236
+ ...(meta.dec !== undefined ? { dec: meta.dec } : {}),
237
+ });
238
+ // 2. The affirmation.
239
+ const affirmation = await affirmPool(i.af, i.base, plan);
240
+ const { lockingScript } = affirmation;
241
+ // 3. The deploy: the pool alone; the module selects the token inputs and adds their change.
242
+ const sym = meta.sym ?? "token";
243
+ const outputs = [{ lockingScript, satoshis: Number(plan.sats), outputDescription: lpKeyDescription(describe(`AMM pool: ${sym} / BSV`), lpKey.keyID) }];
244
+ const createArgs = {
245
+ description: describe(`AMM pool deploy: ${sym}`),
246
+ labels: [...transferPlanLabels(sdkId), "amm-pool-deploy"],
247
+ outputs,
248
+ options: { randomizeOutputs: false, acceptDelayedBroadcast: false },
249
+ };
250
+ const { txid, tx } = await runTokenAction(wallet, createArgs);
251
+ const out = {
252
+ plan,
253
+ lpKey,
254
+ affirmation,
255
+ createArgs,
256
+ txid,
257
+ tx,
258
+ outpoint: `${txid}.0`,
259
+ filing: {
260
+ outputIndex: 0,
261
+ basket: POOLS_BASKET,
262
+ tags: [POOL_TAG],
263
+ customInstructions: poolCustomInstructions({ tokenId: sdkId, ...meta, protocolID: lpKey.protocolID, keyID: lpKey.keyID, args: plan.args, validatorIdentity: plan.state.validatorIdentity, nonce: affirmation.nonce }),
264
+ },
265
+ filed: false,
266
+ submitted: "not submitted",
267
+ errors: [],
268
+ };
269
+ const final = Transaction.fromAtomicBEEF(tx);
270
+ if (final.outputs[0]?.lockingScript.toHex() !== lockingScript)
271
+ out.errors.push("the wallet's deploy has another output 0 than the affirmed pool");
272
+ // The page's own submit to this skein (the module submitted at the wallet's overlay).
273
+ try {
274
+ const submit = i.submit ?? ((topic, beef) => submitToOverlay(i.base, topic, beef));
275
+ out.submitted = steakText((await submit(plan.topic, tx)));
276
+ }
277
+ catch (err) {
278
+ out.submitted = "the submit failed";
279
+ out.errors.push(`submit: ${err instanceof Error ? err.message : String(err)}`);
280
+ }
281
+ // 4. The position row.
282
+ const row = { outputIndex: 0, protocol: "basket insertion", insertionRemittance: { basket: out.filing.basket, tags: out.filing.tags, customInstructions: out.filing.customInstructions } };
283
+ try {
284
+ const r = await wallet.internalizeAction({ tx, outputs: [row], description: describe(`AMM pool deploy: ${sym}`), labels: ["amm-pool-deploy"] });
285
+ out.filed = r.accepted;
286
+ }
287
+ catch (err) {
288
+ out.errors.push(`internalizeAction: ${err instanceof Error ? err.message : String(err)}`);
289
+ }
290
+ return out;
291
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * How this page files a pool output it holds as LP in the exchange's basket
3
+ * `amm-pools` (0.12.0; `bsv21` before): tag `amm-pool`, customInstructions
4
+ * `op: "amm-pool"` (src/lp/poolDeploy.ts). Such a row is not a token balance and
5
+ * not a token input: its script starts with a 1Color value prefix, but the
6
+ * lock behind it is the Pool contract, not P2PKH.
7
+ */
8
+ export declare const POOL_TAG = "amm-pool";
9
+ export declare const POOL_OP = "amm-pool";
10
+ export declare function isPoolRow(row: {
11
+ tags?: string[];
12
+ customInstructions?: string;
13
+ }): boolean;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * How this page files a pool output it holds as LP in the exchange's basket
3
+ * `amm-pools` (0.12.0; `bsv21` before): tag `amm-pool`, customInstructions
4
+ * `op: "amm-pool"` (src/lp/poolDeploy.ts). Such a row is not a token balance and
5
+ * not a token input: its script starts with a 1Color value prefix, but the
6
+ * lock behind it is the Pool contract, not P2PKH.
7
+ */
8
+ export const POOL_TAG = "amm-pool";
9
+ export const POOL_OP = "amm-pool";
10
+ export function isPoolRow(row) {
11
+ if (row.tags?.includes(POOL_TAG))
12
+ return true;
13
+ try {
14
+ return JSON.parse(row.customInstructions ?? "{}").op === POOL_OP;
15
+ }
16
+ catch {
17
+ return false;
18
+ }
19
+ }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * 0.34.0 (D9): the rows are read here; their pools' state and fees come from ONE `GET
3
+ * /@<token>/amm/positions?lp=k1,k2` per token (src/client.ts `myPositions`), not from
4
+ * `/spends` per row as below; the pool output's BEEF is read only when the LP acts (Close: `GET
5
+ * /@<token>/amm/pools/beef?lp=<its key>`).
6
+ *
7
+ * The connected wallet's positions (skein-amm 0.9.0, David Case 2026-10-09;
8
+ * 0.12.0: the rows in the exchange's basket `amm-pools`, no claim): the pool
9
+ * rows its deploys filed (op `amm-pool`, the LP key in their
10
+ * customInstructions), each read from the CHAIN STATE by outpoint —
11
+ * `GET <base>/spends` (amm-p2p reads.zig, the chain app's `spent` as the
12
+ * overlay reads it): the pool followed from the deploy's output to its
13
+ * current output (each swap's continuation), or closed (by the LP or by the
14
+ * validator, docs/AMM.md "The validator's Close").
15
+ *
16
+ * 0.29.3: the deploy HISTORY is the first source (`historyPoolRows`): 0.29.4,
17
+ * each `amm-pool-deploy` action's pool output names its LP keyID in its
18
+ * description (`… · amm-lp <hex>`) and its script is the pool (no
19
+ * customInstructions needed: BRC-100's listActions does not answer them). 0.28.0: the rows also come from the wallet's HISTORY (`historyPoolRows`):
20
+ * `listOutputs` answers spendable outputs only, so a pool output the wallet
21
+ * itself spent (the LP swapped against its own pool) left no row and the
22
+ * position vanished; the deploys' actions (label `amm-pool-deploy`) still
23
+ * carry the output filed in `amm-pools` with its customInstructions. Both
24
+ * sets, deduped by outpoint, are followed by `/spends` as before.
25
+ *
26
+ * The current output's BEEF comes from the token's 1Color lookup
27
+ * (0.20.1: BRC-207's `color-spendability` at `ls_color_<tokenId>`: the
28
+ * output if admitted and unspent, with its BEEF; `ls_color {txid,
29
+ * outputIndex}` until 0.19.0).
30
+ */
31
+ import { type WalletInterface, type WalletProtocol } from "@bsv/sdk";
32
+ import { type BasketRow } from "./poolDeploy.js";
33
+ /** The wallet key that is a pool's LpPubKey (a BRC-29 key to self, or a pre-BRC-29 1Sat key). */
34
+ export interface LpKeyRef {
35
+ protocolID: WalletProtocol;
36
+ keyID: string;
37
+ counterparty: string;
38
+ }
39
+ /** A pool row of the wallet: the deploy's pool output as filed. */
40
+ export interface PositionRow {
41
+ /** The deploy's pool output, `<txid>.<vout>`. */
42
+ deployOutpoint: string;
43
+ /** `<txid>_<vout>` */
44
+ tokenId: string;
45
+ sym?: string;
46
+ dec?: number;
47
+ lpKey: LpKeyRef;
48
+ validatorIdentity?: string;
49
+ /** 0.32.0: the pool's LpPubKey, from the filed output's script (the pool's state); what the LP fees are asked by. */
50
+ lpPubKey?: string;
51
+ }
52
+ /** The label a pool deploy gives its action (src/lp/poolDeploy.ts). */
53
+ export declare const POOL_DEPLOY_LABEL = "amm-pool-deploy";
54
+ /**
55
+ * The pool rows of the wallet's deploy actions (0.28.0): every output of an action labelled
56
+ * `amm-pool-deploy` filed in `amm-pools` as a pool row (tag `amm-pool` or op `amm-pool` in its
57
+ * customInstructions), spent or not. `listActions` with `includeOutputs` (and, where the wallet
58
+ * takes it, `includeCustomInstructions`), paged; a wallet that refuses the read: none.
59
+ */
60
+ export declare function historyPoolRows(wallet: WalletInterface): Promise<BasketRow[]>;
61
+ /** Rows deduped by outpoint (`<txid>.<vout>`), the first kept (the basket's before the history's). */
62
+ export declare function mergePoolRows(...sets: BasketRow[][]): BasketRow[];
63
+ /** The wallet's pool rows (`isPoolRow`). */
64
+ export declare function positionRowsOf(rows: BasketRow[]): PositionRow[];
65
+ /** One token's positions summed (0.32.0): the Liquidity page's line above the cards. */
66
+ export interface TokenFees {
67
+ tokenId: string;
68
+ sym: string;
69
+ dec: number;
70
+ positions: number;
71
+ sats: bigint;
72
+ tokens: bigint;
73
+ }
74
+ /** Positions (live and closed) summed per token, in the order each token first appears; fees not told count as 0. */
75
+ export declare function feesByToken(ps: {
76
+ tokenId: string;
77
+ sym: string;
78
+ dec: number;
79
+ feesEarnedSats?: bigint;
80
+ feesEarnedTokens?: bigint;
81
+ }[]): TokenFees[];