@arkade-os/swap 0.0.1 → 0.0.3

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
@@ -16,7 +16,7 @@ Arkade Intents names two participants:
16
16
  contract, and tracks it to a fill or a cancellation.
17
17
  - **solver** — supplies inventory and pricing, and fills the funded contract by delivering
18
18
  `wantAmount` to the user's script over the covenant's `fulfill` path. Some specifications and
19
- repositories use *provider* or *market maker* as synonyms.
19
+ repositories use _provider_ or _market maker_ as synonyms.
20
20
 
21
21
  **`maker` and `taker` in this package name contract positions, not product roles.** The covenant
22
22
  programs bind `makerWP`, and the `Offer` type carries `makerPkScript` and `makerPublicKey`; those
@@ -25,14 +25,14 @@ identify the side that funds the swap and receives `wantAmount`. Read them as sc
25
25
  Arkade Intents documentation deliberately avoids maker and taker for the participants themselves.
26
26
  A resting maker order is firm once taken, and nothing here is: the user funds first, and if no
27
27
  solver fills, the deposit comes back through `cancelOffer` rather than through an executed trade.
28
- Naming the sides *user* and *solver* says who does what without borrowing a guarantee the contract
28
+ Naming the sides _user_ and _solver_ says who does what without borrowing a guarantee the contract
29
29
  does not make.
30
30
 
31
31
  ## Request for quote
32
32
 
33
33
  Every Arkade Intents route is request-for-quote: the user states an intent, receives the solver's
34
34
  terms as a quote, funds the contract it derives from those terms, and a solver fills it. This
35
- route is no exception — what is specific to it is *where the quote is resolved*. `quoteOffer`
35
+ route is no exception — what is specific to it is _where the quote is resolved_. `quoteOffer`
36
36
  prices the swap client-side from the market card the solver publishes: its price feed and its fee,
37
37
  the same two inputs a relay quote would carry. Same protocol, one fewer network hop, and a quote
38
38
  that is ready before the user finishes typing an amount.
@@ -52,7 +52,7 @@ with then.
52
52
 
53
53
  Every swap has the same two beats, on this route and on the cross-ledger corridors:
54
54
 
55
- 1. **Funding** — the user funds the contract it derived from the quote. Funding *is* acceptance;
55
+ 1. **Funding** — the user funds the contract it derived from the quote. Funding _is_ acceptance;
56
56
  there is no accept message to send, here or anywhere in Arkade Intents.
57
57
  2. **Fill, or cancel** — a solver fills by delivering the other side, or the user takes the
58
58
  deposit back.
@@ -90,8 +90,8 @@ funds an offer should keep cancelling within reach.
90
90
  6. **`rfq`** — the user side of quoted swaps: RFQ negotiation over HTTP or a
91
91
  relay, then non-interactive filling (see below). All four reference-solver corridors:
92
92
  `arkade:BTC -> lightning:BTC` and `arkade:BTC -> onchain:BTC` (send), `lightning:BTC ->
93
- arkade:BTC` and `onchain:BTC -> arkade:BTC` (receive), plus `arkade:BTC|asset ->
94
- arkade:BTC|asset` (quote, then take by funding an offer from layer 1).
93
+ arkade:BTC` and `onchain:BTC -> arkade:BTC` (receive), plus `arkade:BTC|asset ->
94
+ arkade:BTC|asset` (quote, then take by funding an offer from layer 1).
95
95
  7. **`onchainHtlc`** — the Bitcoin-L1 side of `arkade:BTC <-> onchain:BTC`: a NUMS-keyed taproot
96
96
  HTLC as pure local derivation (golden-pinned), claim/refund spend builders with signing as a
97
97
  callback, the injected `ChainSource` seam (the package holds no L1 backend and no keys),
@@ -113,11 +113,11 @@ the rest:
113
113
 
114
114
  ```ts
115
115
  // BTC -> asset
116
- const o = await createOffer(wallet, ARK, EMULATOR_PUBKEY, { wantAmount: 1000n, wantAsset });
116
+ const o = await createOffer(wallet, ARK, { wantAmount: 1000n, wantAsset });
117
117
  await wallet.send({ address: o.address, amount: 1000, extensions: [o.extension] });
118
118
 
119
119
  // asset -> BTC (the sats are the VTXO carrier for the asset)
120
- const o = await createOffer(wallet, ARK, EMULATOR_PUBKEY, { wantAmount: 1000n, offerAsset });
120
+ const o = await createOffer(wallet, ARK, { wantAmount: 1000n, offerAsset });
121
121
  await wallet.send({
122
122
  address: o.address,
123
123
  amount: 500,
@@ -126,10 +126,11 @@ await wallet.send({
126
126
  });
127
127
  ```
128
128
 
129
- `EMULATOR_PUBKEY` is the covenant co-signer's x-only key the solver's deployment, not yours.
130
- `createOffer` does not fetch or verify it: clients have no network path to the emulator, only the
131
- solver and covclaimd do. Obtain it out of band, before calling `createOffer`, from the solver's
132
- signed registry/corridor card and check it against whatever value you independently trust.
129
+ The covenant co-signer ("emulator") key defaults to the SDK's per-network pin, resolved from the
130
+ network the Ark server reports never fetched from the emulator itself. Pass
131
+ `params.emulatorPubkey` (33-byte compressed hex, the same contract as `Arkade.connect`'s option)
132
+ to override it for a self-hosted emulator, an unpinned network (signet, testnet), or a key
133
+ rotation the SDK hasn't shipped yet.
133
134
 
134
135
  ### What `createOffer` gives you back
135
136
 
@@ -232,15 +233,9 @@ message anywhere: **acceptance is funding**.
232
233
  import { httpTransport, requestLightningSend } from "@arkade-os/swap";
233
234
 
234
235
  // invoice facts from YOUR OWN decoder — the module takes facts, not a decoder
235
- const swap = await requestLightningSend(
236
- wallet,
237
- arkServerUrl,
238
- emulatorPubkey,
239
- httpTransport(solverUrl),
240
- {
241
- invoice: { raw: bolt11, paymentHash, amountSats, expiresAt },
242
- },
243
- );
236
+ const swap = await requestLightningSend(wallet, arkServerUrl, httpTransport(solverUrl), {
237
+ invoice: { raw: bolt11, paymentHash, amountSats, expiresAt },
238
+ });
244
239
  // quote verified against the LOCAL derivation and gated; now fund and go offline:
245
240
  await wallet.send({ address: swap.address, amount: swap.fundAmount });
246
241
  ```
@@ -256,10 +251,8 @@ which the manager can only poll and cannot retire the row when the swap ends.
256
251
  The trust model is the offer side's, applied to quotes: only `solver_pubkey`,
257
252
  `refund_locktime`, `valid_until` and the amounts are used from a quote; every other contract
258
253
  parameter is the trader's own data, and anything address-shaped from the solver is compare-only
259
- (`AddressMismatch` means refuse-to-fund). `emulatorPubkey` is neither: it is not fetched or
260
- verified by this library at all — clients have no network path to the emulator, only the solver
261
- and covclaimd do — so it must arrive already obtained out of band, from the solver's signed
262
- registry/corridor card, and already checked against whatever value you independently trust.
254
+ (`AddressMismatch` means refuse-to-fund). The emulator key is neither: as above, it is a
255
+ per-network pin inside the SDK, not solver data.
263
256
  Refusals carry a closed reason set (`SwapRefusal`); unknown reasons are a generic decline. The
264
257
  `swap-lightning-send.program.json` bytes are frozen the same way the offer programs are — a
265
258
  golden test pins the compiled leaves and scriptPubKey to the reference solver's exact script.
@@ -314,13 +307,11 @@ import {
314
307
  rfqSecretsToRecord,
315
308
  } from "@arkade-os/swap";
316
309
 
317
- const swap = await requestOnchainSend(
318
- wallet,
319
- arkServerUrl,
320
- emulatorPubkey,
321
- httpTransport(solverUrl),
322
- { amount: 100_000, amountSide: "to", payoutPubkey },
323
- );
310
+ const swap = await requestOnchainSend(wallet, arkServerUrl, httpTransport(solverUrl), {
311
+ amount: 100_000,
312
+ amountSide: "to",
313
+ payoutPubkey,
314
+ });
324
315
  // Persist the record, including secrets, BEFORE funding. This must succeed:
325
316
  // if addAssetSwap throws, do not call wallet.send.
326
317
  await addAssetSwap(repository, {
@@ -377,7 +368,7 @@ against the quote's compare-only addresses → gate. `requestLightningReceive` r
377
368
  hold invoice to pay; `requestOnchainReceive` returns the L1 HTLC to fund — the payment/broadcast
378
369
  itself is the trader's own wallet's job, exactly as on the send corridors.
379
370
 
380
- The invoice on the lightning-receive leg is the *solver's*, so the SDK owns the comparison rather
371
+ The invoice on the lightning-receive leg is the _solver's_, so the SDK owns the comparison rather
381
372
  than taking the caller's facts about it: `requestLightningReceive` requires a `decodeInvoice`
382
373
  callback (no BOLT11 dependency is added) and `verifyReceiveInvoice` binds the decoded invoice to
383
374
  this swap's `H` and to `quote.from_amount` — an invoice on another payment hash is the one attack
@@ -403,11 +394,11 @@ implementation and marked provisional (`TODO(claim-packet-vectors)`).
403
394
 
404
395
  `RfqSwapManager` drives the lightning-receive leg too, as `kind: "lightning_receive"` records
405
396
  carrying `expectedAmount` and wired to a `claimLockup` callback (`pushClaim`, with `expectedAmount`
406
- and `partiallyClaimed` passed through — the manager's value check decides *when* to act, the inner
397
+ and `partiallyClaimed` passed through — the manager's value check decides _when_ to act, the inner
407
398
  one decides whether `P` is published). Nothing is asked of the solver: the reference solver's
408
399
  `rfq_status_request` consults neither receive store, so a status poll answers `unknown` for every
409
400
  one of these swaps and chain observation is the only workable design. States mean what they do on
410
- the send legs with the roles swapped — `settled` is *our own* claim landing, matched by a
401
+ the send legs with the roles swapped — `settled` is _our own_ claim landing, matched by a
411
402
  hash-verified preimage spend rather than by the txid we submitted, so a claim that lands without us
412
403
  still counts; `claimed` is a local belief and not terminal; and **`refunded` is a loss**, the solver
413
404
  having taken back a lockup we failed to claim. A lockup funded below `expectedAmount` is reported
@@ -471,7 +462,7 @@ alone will not compile against the fallback. A caller-supplied preimage on an HD
471
462
  `signingDescriptor` for the sender key and stores only `preimageHex` as secret material.
472
463
 
473
464
  Each swap **allocates** its own descriptor rather than peeking at the current one: two swaps sharing
474
- a descriptor derive the *identical* preimage, so one solver learning its own preimage would learn the
465
+ a descriptor derive the _identical_ preimage, so one solver learning its own preimage would learn the
475
466
  other swap's. On restore, `adoptSwapDescriptor` moves the wallet's watermark past a restored record's
476
467
  index so it cannot be handed out twice.
477
468
 
@@ -486,7 +477,7 @@ too little public quote data to rediscover, so the record remains required.
486
477
 
487
478
  **Gap-limit interaction:** every swap request — including one whose quote is refused — consumes one
488
479
  index from the wallet's receive stream, and a swap index never becomes a funded receive contract,
489
- so it looks *unused* to a seed-only `restore()` gap scan. Many consecutive swap allocations between
480
+ so it looks _unused_ to a seed-only `restore()` gap scan. Many consecutive swap allocations between
490
481
  two funded receive indices can therefore exceed the scan's `gapLimit` (default 20) and stop it
491
482
  before later-funded addresses are found. Keep the swap repository in backups (restore then adopts
492
483
  each record's descriptor via `adoptSwapDescriptor`), or raise `gapLimit` on seed-only restores
@@ -454,7 +454,8 @@ import {
454
454
  ArkAddress,
455
455
  RestArkProvider,
456
456
  VHTLC,
457
- getNetwork
457
+ getNetwork,
458
+ resolveEmulatorPubkey
458
459
  } from "@arkade-os/sdk";
459
460
  var xOnly = (key, label) => {
460
461
  if (key.length === 32) return key;
@@ -747,7 +748,7 @@ function lightningSendVtxoScript(params) {
747
748
  }
748
749
  });
749
750
  }
750
- async function requestLightningSend(wallet, arkServerUrl, emulatorPubkey, transport, params) {
751
+ async function requestLightningSend(wallet, arkServerUrl, transport, params) {
751
752
  const rfqId = params.rfqId ?? newRfqId();
752
753
  const secrets = await deriveSwapSecrets(wallet) ?? randomSwapSecrets();
753
754
  if (!secrets.derivable) {
@@ -781,18 +782,22 @@ async function requestLightningSend(wallet, arkServerUrl, emulatorPubkey, transp
781
782
  );
782
783
  }
783
784
  const serverPubkey = xOnly(hex4.decode(info.signerPubkey), "ark signer key");
785
+ const network = getNetwork(info.network);
784
786
  const script = lightningSendVtxoScript({
785
787
  solverPubkey: xOnly(hex4.decode(quote.solver_pubkey), "solver key"),
786
788
  refundLocktime: quote.refund_locktime,
787
789
  serverPubkey,
788
790
  paymentHash: params.invoice.paymentHash,
789
791
  claimDelay: unilateralClaimDelay(Number(info.unilateralExitDelay)),
790
- emulatorPubkey: xOnly(emulatorPubkey, "emulator pubkey"),
792
+ emulatorPubkey: xOnly(
793
+ hex4.decode(resolveEmulatorPubkey(network, params.emulatorPubkey)),
794
+ "emulator signer key"
795
+ ),
791
796
  senderPubkey,
792
797
  receiverPkScript: solverHex(receiverPkScriptHex, "profile.receiver_pk_script"),
793
798
  refundPkScript: ArkAddress.decode(refundAddress).pkScript
794
799
  });
795
- const address = script.address(getNetwork(info.network).hrp, serverPubkey).encode();
800
+ const address = script.address(network.hrp, serverPubkey).encode();
796
801
  verifyLockupAddress(quote, address);
797
802
  assertFundable({
798
803
  quote,
@@ -909,7 +914,7 @@ function deriveOnchainSend(input) {
909
914
  minConfirmations
910
915
  };
911
916
  }
912
- async function requestOnchainSend(wallet, arkServerUrl, emulatorPubkey, transport, params) {
917
+ async function requestOnchainSend(wallet, arkServerUrl, transport, params) {
913
918
  const rfqId = params.rfqId ?? newRfqId();
914
919
  if (params.preimage && params.preimage.length !== 32) {
915
920
  throw new Error(`preimage must be 32 bytes, got ${params.preimage.length}`);
@@ -943,14 +948,18 @@ async function requestOnchainSend(wallet, arkServerUrl, emulatorPubkey, transpor
943
948
  amountSide: params.amountSide
944
949
  })
945
950
  );
951
+ const network = getNetwork(info.network);
946
952
  const derived = deriveOnchainSend({
947
953
  quote,
948
954
  paymentHash,
949
955
  payoutPubkey: params.payoutPubkey,
950
956
  serverPubkey: xOnly(hex4.decode(info.signerPubkey), "ark signer key"),
951
- emulatorPubkey: xOnly(emulatorPubkey, "emulator pubkey"),
957
+ emulatorPubkey: xOnly(
958
+ hex4.decode(resolveEmulatorPubkey(network, params.emulatorPubkey)),
959
+ "emulator signer key"
960
+ ),
952
961
  claimDelay: unilateralClaimDelay(Number(info.unilateralExitDelay)),
953
- hrp: getNetwork(info.network).hrp,
962
+ hrp: network.hrp,
954
963
  l1Network: l1NetworkFromArk(info.network),
955
964
  refundAddress,
956
965
  senderPubkey
@@ -1099,7 +1108,7 @@ function deriveLightningReceive(input) {
1099
1108
  verifyLockupAddress(quote, address);
1100
1109
  return { address, swapPkScript: script.pkScript, script, invoice, refundLocktime };
1101
1110
  }
1102
- async function requestLightningReceive(wallet, arkServerUrl, emulatorPubkey, transport, params) {
1111
+ async function requestLightningReceive(wallet, arkServerUrl, transport, params) {
1103
1112
  const rfqId = params.rfqId ?? newRfqId();
1104
1113
  const secrets = await deriveSwapSecrets(wallet) ?? randomSwapSecrets({ preimage: true });
1105
1114
  if (!secrets.derivable) {
@@ -1130,15 +1139,19 @@ async function requestLightningReceive(wallet, arkServerUrl, emulatorPubkey, tra
1130
1139
  })
1131
1140
  );
1132
1141
  assertQuotedAmount(quote, params.amountSide, params.amount);
1142
+ const network = getNetwork(info.network);
1133
1143
  const derived = deriveLightningReceive({
1134
1144
  quote,
1135
1145
  paymentHash,
1136
1146
  payoutPubkey,
1137
1147
  payoutAddress,
1138
1148
  serverPubkey: xOnly(hex4.decode(info.signerPubkey), "ark signer key"),
1139
- emulatorPubkey: xOnly(emulatorPubkey, "emulator pubkey"),
1149
+ emulatorPubkey: xOnly(
1150
+ hex4.decode(resolveEmulatorPubkey(network, params.emulatorPubkey)),
1151
+ "emulator signer key"
1152
+ ),
1140
1153
  claimDelay: unilateralClaimDelay(Number(info.unilateralExitDelay)),
1141
- hrp: getNetwork(info.network).hrp
1154
+ hrp: network.hrp
1142
1155
  });
1143
1156
  const now = Math.floor(Date.now() / 1e3);
1144
1157
  const { payDeadline } = verifyReceiveInvoice({
@@ -1213,7 +1226,7 @@ function deriveOnchainReceive(input) {
1213
1226
  minConfirmations
1214
1227
  };
1215
1228
  }
1216
- async function requestOnchainReceive(wallet, arkServerUrl, emulatorPubkey, transport, params) {
1229
+ async function requestOnchainReceive(wallet, arkServerUrl, transport, params) {
1217
1230
  const rfqId = params.rfqId ?? newRfqId();
1218
1231
  const secrets = await deriveSwapSecrets(wallet) ?? randomSwapSecrets({ preimage: true });
1219
1232
  if (!secrets.derivable) {
@@ -1245,6 +1258,7 @@ async function requestOnchainReceive(wallet, arkServerUrl, emulatorPubkey, trans
1245
1258
  })
1246
1259
  );
1247
1260
  assertQuotedAmount(quote, params.amountSide, params.amount);
1261
+ const network = getNetwork(info.network);
1248
1262
  const derived = deriveOnchainReceive({
1249
1263
  quote,
1250
1264
  paymentHash,
@@ -1252,9 +1266,12 @@ async function requestOnchainReceive(wallet, arkServerUrl, emulatorPubkey, trans
1252
1266
  payoutAddress,
1253
1267
  refundPubkey: params.refundPubkey,
1254
1268
  serverPubkey: xOnly(hex4.decode(info.signerPubkey), "ark signer key"),
1255
- emulatorPubkey: xOnly(emulatorPubkey, "emulator pubkey"),
1269
+ emulatorPubkey: xOnly(
1270
+ hex4.decode(resolveEmulatorPubkey(network, params.emulatorPubkey)),
1271
+ "emulator signer key"
1272
+ ),
1256
1273
  claimDelay: unilateralClaimDelay(Number(info.unilateralExitDelay)),
1257
- hrp: getNetwork(info.network).hrp,
1274
+ hrp: network.hrp,
1258
1275
  l1Network: l1NetworkFromArk(info.network)
1259
1276
  });
1260
1277
  assertFundable({
package/dist/index.cjs CHANGED
@@ -380,14 +380,6 @@ var FIELDS = {
380
380
  offerAsset: { tag: 11, width: void 0 }
381
381
  };
382
382
  var NAMES = Object.fromEntries(Object.entries(FIELDS).map(([k, f]) => [f.tag, k]));
383
- var XONLY_LEN = 32;
384
- var xOnly = (key, label) => {
385
- if (key.length === XONLY_LEN) return key;
386
- if (key.length !== 33 || key[0] !== 2 && key[0] !== 3) {
387
- throw new Error(`${label} is not a compressed or x-only public key`);
388
- }
389
- return key.slice(1);
390
- };
391
383
  function tlv(type, value) {
392
384
  if (value.length > 65535) throw new Error("TLV value exceeds the u16 length field");
393
385
  return (0, import_utils.concatBytes)(Uint8Array.of(type, value.length >> 8 & 255, value.length & 255), value);
@@ -489,7 +481,7 @@ async function registerOfferContract(wallet, arkServerUrl, network, binding, ser
489
481
  });
490
482
  await promoteOfferContract(contractManager, import_base.hex.encode(expectedPkScript));
491
483
  }
492
- async function createOffer(wallet, arkServerUrl, emulatorPubkey, params) {
484
+ async function createOffer(wallet, arkServerUrl, params) {
493
485
  if (Boolean(params.wantAsset) === Boolean(params.offerAsset)) {
494
486
  throw new Error("set exactly one of wantAsset (BTC->asset) or offerAsset (asset->BTC)");
495
487
  }
@@ -498,8 +490,11 @@ async function createOffer(wallet, arkServerUrl, emulatorPubkey, params) {
498
490
  wallet.getAddress(),
499
491
  wallet.identity.xOnlyPublicKey()
500
492
  ]);
501
- const serverPubKey = xOnly(import_base.hex.decode(info.signerPubkey), "ark signer key");
502
- const emuKey = xOnly(emulatorPubkey, "emulator pubkey");
493
+ const serverPubKey = import_base.hex.decode((0, import_sdk.toXOnlySignerHex)(info.signerPubkey));
494
+ const network = (0, import_sdk.getNetwork)(info.network);
495
+ const emuKey = import_base.hex.decode(
496
+ (0, import_sdk.toXOnlySignerHex)((0, import_sdk.resolveEmulatorPubkey)(network, params.emulatorPubkey))
497
+ );
503
498
  const binding = {
504
499
  wantAmount: params.wantAmount,
505
500
  wantAsset: params.wantAsset,
@@ -524,7 +519,7 @@ async function createOffer(wallet, arkServerUrl, emulatorPubkey, params) {
524
519
  extension: { type: OFFER_PACKET_TYPE, payload },
525
520
  // VtxoScript.address owns address construction; assembling an ArkAddress
526
521
  // from tweakedPublicKey here would silently miss any future step it gains
527
- address: script.address((0, import_sdk.getNetwork)(info.network).hrp, serverPubKey).encode(),
522
+ address: script.address(network.hrp, serverPubKey).encode(),
528
523
  swapPkScript: script.pkScript
529
524
  };
530
525
  }
@@ -1541,7 +1536,7 @@ async function registerLockupContract(contracts, script, address) {
1541
1536
  }
1542
1537
 
1543
1538
  // src/rfq.ts
1544
- var xOnly2 = (key, label) => {
1539
+ var xOnly = (key, label) => {
1545
1540
  if (key.length === 32) return key;
1546
1541
  if (key.length !== 33 || key[0] !== 2 && key[0] !== 3) {
1547
1542
  throw new Error(`${label} is not a compressed or x-only public key`);
@@ -1832,7 +1827,7 @@ function lightningSendVtxoScript(params) {
1832
1827
  }
1833
1828
  });
1834
1829
  }
1835
- async function requestLightningSend(wallet, arkServerUrl, emulatorPubkey, transport, params) {
1830
+ async function requestLightningSend(wallet, arkServerUrl, transport, params) {
1836
1831
  const rfqId = params.rfqId ?? newRfqId();
1837
1832
  const secrets = await deriveSwapSecrets(wallet) ?? randomSwapSecrets();
1838
1833
  if (!secrets.derivable) {
@@ -1865,19 +1860,23 @@ async function requestLightningSend(wallet, arkServerUrl, emulatorPubkey, transp
1865
1860
  `quote from_amount ${quote.from_amount} is below the invoice amount \u2014 a negative spread is not a quote`
1866
1861
  );
1867
1862
  }
1868
- const serverPubkey = xOnly2(import_base8.hex.decode(info.signerPubkey), "ark signer key");
1863
+ const serverPubkey = xOnly(import_base8.hex.decode(info.signerPubkey), "ark signer key");
1864
+ const network = (0, import_sdk8.getNetwork)(info.network);
1869
1865
  const script = lightningSendVtxoScript({
1870
- solverPubkey: xOnly2(import_base8.hex.decode(quote.solver_pubkey), "solver key"),
1866
+ solverPubkey: xOnly(import_base8.hex.decode(quote.solver_pubkey), "solver key"),
1871
1867
  refundLocktime: quote.refund_locktime,
1872
1868
  serverPubkey,
1873
1869
  paymentHash: params.invoice.paymentHash,
1874
1870
  claimDelay: unilateralClaimDelay(Number(info.unilateralExitDelay)),
1875
- emulatorPubkey: xOnly2(emulatorPubkey, "emulator pubkey"),
1871
+ emulatorPubkey: xOnly(
1872
+ import_base8.hex.decode((0, import_sdk8.resolveEmulatorPubkey)(network, params.emulatorPubkey)),
1873
+ "emulator signer key"
1874
+ ),
1876
1875
  senderPubkey,
1877
1876
  receiverPkScript: solverHex(receiverPkScriptHex, "profile.receiver_pk_script"),
1878
1877
  refundPkScript: import_sdk8.ArkAddress.decode(refundAddress).pkScript
1879
1878
  });
1880
- const address = script.address((0, import_sdk8.getNetwork)(info.network).hrp, serverPubkey).encode();
1879
+ const address = script.address(network.hrp, serverPubkey).encode();
1881
1880
  verifyLockupAddress(quote, address);
1882
1881
  assertFundable({
1883
1882
  quote,
@@ -1962,7 +1961,7 @@ function deriveOnchainSend(input) {
1962
1961
  throw new Error("onchain-send quote is missing a binding field");
1963
1962
  }
1964
1963
  const script = lightningSendVtxoScript({
1965
- solverPubkey: xOnly2(import_base8.hex.decode(quote.solver_pubkey), "solver key"),
1964
+ solverPubkey: xOnly(import_base8.hex.decode(quote.solver_pubkey), "solver key"),
1966
1965
  refundLocktime,
1967
1966
  serverPubkey: input.serverPubkey,
1968
1967
  paymentHash: input.paymentHash,
@@ -1978,7 +1977,7 @@ function deriveOnchainSend(input) {
1978
1977
  {
1979
1978
  paymentHash: input.paymentHash,
1980
1979
  claimKey: input.payoutPubkey,
1981
- refundKey: xOnly2(import_base8.hex.decode(htlcPubkey), "solver L1 htlc key"),
1980
+ refundKey: xOnly(import_base8.hex.decode(htlcPubkey), "solver L1 htlc key"),
1982
1981
  refundLocktime: htlcLocktime
1983
1982
  },
1984
1983
  input.l1Network
@@ -1994,7 +1993,7 @@ function deriveOnchainSend(input) {
1994
1993
  minConfirmations
1995
1994
  };
1996
1995
  }
1997
- async function requestOnchainSend(wallet, arkServerUrl, emulatorPubkey, transport, params) {
1996
+ async function requestOnchainSend(wallet, arkServerUrl, transport, params) {
1998
1997
  const rfqId = params.rfqId ?? newRfqId();
1999
1998
  if (params.preimage && params.preimage.length !== 32) {
2000
1999
  throw new Error(`preimage must be 32 bytes, got ${params.preimage.length}`);
@@ -2028,14 +2027,18 @@ async function requestOnchainSend(wallet, arkServerUrl, emulatorPubkey, transpor
2028
2027
  amountSide: params.amountSide
2029
2028
  })
2030
2029
  );
2030
+ const network = (0, import_sdk8.getNetwork)(info.network);
2031
2031
  const derived = deriveOnchainSend({
2032
2032
  quote,
2033
2033
  paymentHash,
2034
2034
  payoutPubkey: params.payoutPubkey,
2035
- serverPubkey: xOnly2(import_base8.hex.decode(info.signerPubkey), "ark signer key"),
2036
- emulatorPubkey: xOnly2(emulatorPubkey, "emulator pubkey"),
2035
+ serverPubkey: xOnly(import_base8.hex.decode(info.signerPubkey), "ark signer key"),
2036
+ emulatorPubkey: xOnly(
2037
+ import_base8.hex.decode((0, import_sdk8.resolveEmulatorPubkey)(network, params.emulatorPubkey)),
2038
+ "emulator signer key"
2039
+ ),
2037
2040
  claimDelay: unilateralClaimDelay(Number(info.unilateralExitDelay)),
2038
- hrp: (0, import_sdk8.getNetwork)(info.network).hrp,
2041
+ hrp: network.hrp,
2039
2042
  l1Network: l1NetworkFromArk(info.network),
2040
2043
  refundAddress,
2041
2044
  senderPubkey
@@ -2170,7 +2173,7 @@ function deriveLightningReceive(input) {
2170
2173
  throw new Error("lightning-receive quote is missing a binding field");
2171
2174
  }
2172
2175
  const script = receiveVtxoScript({
2173
- solverPubkey: xOnly2(import_base8.hex.decode(quote.solver_pubkey), "solver key"),
2176
+ solverPubkey: xOnly(import_base8.hex.decode(quote.solver_pubkey), "solver key"),
2174
2177
  refundLocktime,
2175
2178
  serverPubkey: input.serverPubkey,
2176
2179
  paymentHash: input.paymentHash,
@@ -2184,7 +2187,7 @@ function deriveLightningReceive(input) {
2184
2187
  verifyLockupAddress(quote, address);
2185
2188
  return { address, swapPkScript: script.pkScript, script, invoice, refundLocktime };
2186
2189
  }
2187
- async function requestLightningReceive(wallet, arkServerUrl, emulatorPubkey, transport, params) {
2190
+ async function requestLightningReceive(wallet, arkServerUrl, transport, params) {
2188
2191
  const rfqId = params.rfqId ?? newRfqId();
2189
2192
  const secrets = await deriveSwapSecrets(wallet) ?? randomSwapSecrets({ preimage: true });
2190
2193
  if (!secrets.derivable) {
@@ -2215,15 +2218,19 @@ async function requestLightningReceive(wallet, arkServerUrl, emulatorPubkey, tra
2215
2218
  })
2216
2219
  );
2217
2220
  assertQuotedAmount(quote, params.amountSide, params.amount);
2221
+ const network = (0, import_sdk8.getNetwork)(info.network);
2218
2222
  const derived = deriveLightningReceive({
2219
2223
  quote,
2220
2224
  paymentHash,
2221
2225
  payoutPubkey,
2222
2226
  payoutAddress,
2223
- serverPubkey: xOnly2(import_base8.hex.decode(info.signerPubkey), "ark signer key"),
2224
- emulatorPubkey: xOnly2(emulatorPubkey, "emulator pubkey"),
2227
+ serverPubkey: xOnly(import_base8.hex.decode(info.signerPubkey), "ark signer key"),
2228
+ emulatorPubkey: xOnly(
2229
+ import_base8.hex.decode((0, import_sdk8.resolveEmulatorPubkey)(network, params.emulatorPubkey)),
2230
+ "emulator signer key"
2231
+ ),
2225
2232
  claimDelay: unilateralClaimDelay(Number(info.unilateralExitDelay)),
2226
- hrp: (0, import_sdk8.getNetwork)(info.network).hrp
2233
+ hrp: network.hrp
2227
2234
  });
2228
2235
  const now = Math.floor(Date.now() / 1e3);
2229
2236
  const { payDeadline } = verifyReceiveInvoice({
@@ -2266,7 +2273,7 @@ function deriveOnchainReceive(input) {
2266
2273
  throw new Error("onchain-receive quote is missing a binding field");
2267
2274
  }
2268
2275
  const script = receiveVtxoScript({
2269
- solverPubkey: xOnly2(import_base8.hex.decode(quote.solver_pubkey), "solver key"),
2276
+ solverPubkey: xOnly(import_base8.hex.decode(quote.solver_pubkey), "solver key"),
2270
2277
  refundLocktime,
2271
2278
  serverPubkey: input.serverPubkey,
2272
2279
  paymentHash: input.paymentHash,
@@ -2281,7 +2288,7 @@ function deriveOnchainReceive(input) {
2281
2288
  const htlc = onchainHtlcScript(
2282
2289
  {
2283
2290
  paymentHash: input.paymentHash,
2284
- claimKey: xOnly2(import_base8.hex.decode(claimPubkey), "solver L1 claim key"),
2291
+ claimKey: xOnly(import_base8.hex.decode(claimPubkey), "solver L1 claim key"),
2285
2292
  refundKey: input.refundPubkey,
2286
2293
  refundLocktime: htlcLocktime
2287
2294
  },
@@ -2298,7 +2305,7 @@ function deriveOnchainReceive(input) {
2298
2305
  minConfirmations
2299
2306
  };
2300
2307
  }
2301
- async function requestOnchainReceive(wallet, arkServerUrl, emulatorPubkey, transport, params) {
2308
+ async function requestOnchainReceive(wallet, arkServerUrl, transport, params) {
2302
2309
  const rfqId = params.rfqId ?? newRfqId();
2303
2310
  const secrets = await deriveSwapSecrets(wallet) ?? randomSwapSecrets({ preimage: true });
2304
2311
  if (!secrets.derivable) {
@@ -2330,16 +2337,20 @@ async function requestOnchainReceive(wallet, arkServerUrl, emulatorPubkey, trans
2330
2337
  })
2331
2338
  );
2332
2339
  assertQuotedAmount(quote, params.amountSide, params.amount);
2340
+ const network = (0, import_sdk8.getNetwork)(info.network);
2333
2341
  const derived = deriveOnchainReceive({
2334
2342
  quote,
2335
2343
  paymentHash,
2336
2344
  payoutPubkey,
2337
2345
  payoutAddress,
2338
2346
  refundPubkey: params.refundPubkey,
2339
- serverPubkey: xOnly2(import_base8.hex.decode(info.signerPubkey), "ark signer key"),
2340
- emulatorPubkey: xOnly2(emulatorPubkey, "emulator pubkey"),
2347
+ serverPubkey: xOnly(import_base8.hex.decode(info.signerPubkey), "ark signer key"),
2348
+ emulatorPubkey: xOnly(
2349
+ import_base8.hex.decode((0, import_sdk8.resolveEmulatorPubkey)(network, params.emulatorPubkey)),
2350
+ "emulator signer key"
2351
+ ),
2341
2352
  claimDelay: unilateralClaimDelay(Number(info.unilateralExitDelay)),
2342
- hrp: (0, import_sdk8.getNetwork)(info.network).hrp,
2353
+ hrp: network.hrp,
2343
2354
  l1Network: l1NetworkFromArk(info.network)
2344
2355
  });
2345
2356
  assertFundable({
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { asset, IWallet, arkade, RestIndexerProvider, Transaction, IContractManager, RestArkProvider, VHTLC, Identity } from '@arkade-os/sdk';
2
- import { A as AssetSwapRepository, a as AssetSwap, M as MarketsCacheEntry, R as RfqStatus, b as RfqTransport, O as OnchainHtlc, C as ChainSource, c as ChainUtxo, d as OnchainHtlcPhase } from './rfq-CRgIOQ_y.cjs';
3
- export { e as ARKADE_ASSET, f as ARKADE_BTC, g as AddressMismatch, h as AssetSwapFallbackSecrets, i as AssetSwapStatus, B as BTC_ASSET_ID, D as DerivedSwapSecrets, j as DeterministicSigner, H as HtlcUtxo, I as InMemoryAssetSwapRepository, k as InvoiceFacts, L as LIGHTNING_BTC, l as LIGHTNING_RECEIVE_PAIR, m as LIGHTNING_SEND_PAIR, n as MAX_MIN_CONFIRMATIONS, o as MIN_CLAIM_WINDOW_SECONDS, p as MIN_HEADROOM_SECONDS, q as ONCHAIN_BTC, r as ONCHAIN_CLAIM_MARGIN_SECONDS, s as ONCHAIN_DUST_SATS, t as ONCHAIN_ORDER_MARGIN_SECONDS, u as ONCHAIN_RECEIVE_PAIR, v as ONCHAIN_SECONDS_PER_BLOCK, w as ONCHAIN_SEND_PAIR, x as OnchainHtlcParams, y as OnchainNetwork, z as RFQ_PREIMAGE_TAG, E as RFQ_TERMINAL_STATES, F as RefundBlockedReason, G as RefundNotLocallyPossibleError, J as RelaySocket, K as RfqQuote, N as RfqRefusalReason, S as StoredSwapSecrets, P as SwapRefusal, Q as SwapSecrets, T as addAssetSwap, U as adoptSwapDescriptor, V as arkadeSwapRequest, W as assertFundable, X as assertReceivable, Y as awaitOnchainFill, Z as buildHtlcClaim, _ as buildHtlcRefund, $ as buildPreimageMessage, a0 as claimOnchainFill, a1 as classifyOnchainHtlc, a2 as deriveLightningReceive, a3 as deriveOnchainReceive, a4 as deriveOnchainSend, a5 as derivePreimage, a6 as deriveSwapSecrets, a7 as extractPreimage, a8 as getAssetSwaps, a9 as getAssetSwapsOrThrow, aa as httpTransport, ab as isDeterministicSigner, ac as lightningReceiveRequest, ad as lightningSendRequest, ae as lightningSendVtxoScript, af as newPreimage, ag as newRfqId, ah as offerTermsFromQuote, ai as onchainHtlcScript, aj as onchainReceiveRequest, ak as onchainSendRequest, al as paymentHashOf, am as preimageForRfqSecrets, an as randomSwapSecrets, ao as receiveVtxoScript, ap as relayTransport, aq as requestLightningReceive, ar as requestLightningSend, as as requestOnchainReceive, at as requestOnchainSend, au as rfqPair, av as rfqSecretsOfRecord, aw as rfqSecretsToRecord, ax as senderIdentityForRfqSecrets, ay as senderIdentityForSwapRecord, az as senderPubkeyForRfqSecrets, aA as unilateralClaimDelay, aB as unilateralRefundDelay, aC as unilateralRefundWithoutReceiverDelay, aD as updateAssetSwap, aE as updateAssetSwapBestEffort, aF as verifyLockupAddress, aG as verifyReceiveInvoice } from './rfq-CRgIOQ_y.cjs';
2
+ import { A as AssetSwapRepository, a as AssetSwap, M as MarketsCacheEntry, R as RfqStatus, b as RfqTransport, O as OnchainHtlc, C as ChainSource, c as ChainUtxo, d as OnchainHtlcPhase } from './rfq-CCAFoFtR.cjs';
3
+ export { e as ARKADE_ASSET, f as ARKADE_BTC, g as AddressMismatch, h as AssetSwapFallbackSecrets, i as AssetSwapStatus, B as BTC_ASSET_ID, D as DerivedSwapSecrets, j as DeterministicSigner, H as HtlcUtxo, I as InMemoryAssetSwapRepository, k as InvoiceFacts, L as LIGHTNING_BTC, l as LIGHTNING_RECEIVE_PAIR, m as LIGHTNING_SEND_PAIR, n as MAX_MIN_CONFIRMATIONS, o as MIN_CLAIM_WINDOW_SECONDS, p as MIN_HEADROOM_SECONDS, q as ONCHAIN_BTC, r as ONCHAIN_CLAIM_MARGIN_SECONDS, s as ONCHAIN_DUST_SATS, t as ONCHAIN_ORDER_MARGIN_SECONDS, u as ONCHAIN_RECEIVE_PAIR, v as ONCHAIN_SECONDS_PER_BLOCK, w as ONCHAIN_SEND_PAIR, x as OnchainHtlcParams, y as OnchainNetwork, z as RFQ_PREIMAGE_TAG, E as RFQ_TERMINAL_STATES, F as RefundBlockedReason, G as RefundNotLocallyPossibleError, J as RelaySocket, K as RfqQuote, N as RfqRefusalReason, S as StoredSwapSecrets, P as SwapRefusal, Q as SwapSecrets, T as addAssetSwap, U as adoptSwapDescriptor, V as arkadeSwapRequest, W as assertFundable, X as assertReceivable, Y as awaitOnchainFill, Z as buildHtlcClaim, _ as buildHtlcRefund, $ as buildPreimageMessage, a0 as claimOnchainFill, a1 as classifyOnchainHtlc, a2 as deriveLightningReceive, a3 as deriveOnchainReceive, a4 as deriveOnchainSend, a5 as derivePreimage, a6 as deriveSwapSecrets, a7 as extractPreimage, a8 as getAssetSwaps, a9 as getAssetSwapsOrThrow, aa as httpTransport, ab as isDeterministicSigner, ac as lightningReceiveRequest, ad as lightningSendRequest, ae as lightningSendVtxoScript, af as newPreimage, ag as newRfqId, ah as offerTermsFromQuote, ai as onchainHtlcScript, aj as onchainReceiveRequest, ak as onchainSendRequest, al as paymentHashOf, am as preimageForRfqSecrets, an as randomSwapSecrets, ao as receiveVtxoScript, ap as relayTransport, aq as requestLightningReceive, ar as requestLightningSend, as as requestOnchainReceive, at as requestOnchainSend, au as rfqPair, av as rfqSecretsOfRecord, aw as rfqSecretsToRecord, ax as senderIdentityForRfqSecrets, ay as senderIdentityForSwapRecord, az as senderPubkeyForRfqSecrets, aA as unilateralClaimDelay, aB as unilateralRefundDelay, aC as unilateralRefundWithoutReceiverDelay, aD as updateAssetSwap, aE as updateAssetSwapBestEffort, aF as verifyLockupAddress, aG as verifyReceiveInvoice } from './rfq-CCAFoFtR.cjs';
4
4
  import { Network, LocalCardInput, DiscoveredMarket, Side, OfferPlan } from '@arkade-os/solver-discovery';
5
5
 
6
6
  /** The contracts — pure data, shared verbatim with any other implementation. */
@@ -38,11 +38,11 @@ declare function decodeOffer(data: Uint8Array): Offer;
38
38
  * you deposit, embedding the returned extension, and the solver does the rest:
39
39
  *
40
40
  * // BTC -> asset
41
- * const o = await createOffer(wallet, ARK, EMULATOR_PUBKEY, { wantAmount: 1000n, wantAsset })
41
+ * const o = await createOffer(wallet, ARK, { wantAmount: 1000n, wantAsset })
42
42
  * await wallet.send({ address: o.address, amount: 1000, extensions: [o.extension] })
43
43
  *
44
44
  * // asset -> BTC (the sats are the VTXO carrier for the asset)
45
- * const o = await createOffer(wallet, ARK, EMULATOR_PUBKEY, { wantAmount: 1000n, offerAsset })
45
+ * const o = await createOffer(wallet, ARK, { wantAmount: 1000n, offerAsset })
46
46
  * await wallet.send({ address: o.address, amount: 500,
47
47
  * assets: [{ assetId, amount: 1000n }],
48
48
  * extensions: [o.extension] })
@@ -55,20 +55,13 @@ declare function decodeOffer(data: Uint8Array): Offer;
55
55
  * and be retried, where the same failure after `wallet.send` would leave a
56
56
  * funded deposit unwatched with no way to notice.
57
57
  */
58
- declare function createOffer(wallet: IWallet, arkServerUrl: string,
59
- /** Covenant co-signer (emulator) x-only key — the SOLVER's deployment,
60
- * not the user's. This library does NOT fetch or verify it: clients
61
- * have no network path to the emulator, only the solver and covclaimd
62
- * do. The caller must obtain this out-of-band, before calling this
63
- * function, from the solver's signed registry/corridor card (its
64
- * `emulator_pubkey`, added in arkade-os/solver-registry#18) or an
65
- * equivalent source it
66
- * independently trusts, and is responsible for having checked it
67
- * against that trusted value itself. */
68
- emulatorPubkey: Uint8Array, params: {
58
+ declare function createOffer(wallet: IWallet, arkServerUrl: string, params: {
69
59
  wantAmount: bigint;
70
60
  wantAsset?: asset.AssetId;
71
61
  offerAsset?: asset.AssetId;
62
+ /** Co-signer key override (33-byte compressed hex); see
63
+ * {@link resolveEmulatorPubkey}. */
64
+ emulatorPubkey?: string;
72
65
  }): Promise<{
73
66
  /** The encoded offer, hex. **Persist this** — it is the only input
74
67
  * `cancelOffer` needs to rebuild the covenant, and the restore scan reads
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { asset, IWallet, arkade, RestIndexerProvider, Transaction, IContractManager, RestArkProvider, VHTLC, Identity } from '@arkade-os/sdk';
2
- import { A as AssetSwapRepository, a as AssetSwap, M as MarketsCacheEntry, R as RfqStatus, b as RfqTransport, O as OnchainHtlc, C as ChainSource, c as ChainUtxo, d as OnchainHtlcPhase } from './rfq-CRgIOQ_y.js';
3
- export { e as ARKADE_ASSET, f as ARKADE_BTC, g as AddressMismatch, h as AssetSwapFallbackSecrets, i as AssetSwapStatus, B as BTC_ASSET_ID, D as DerivedSwapSecrets, j as DeterministicSigner, H as HtlcUtxo, I as InMemoryAssetSwapRepository, k as InvoiceFacts, L as LIGHTNING_BTC, l as LIGHTNING_RECEIVE_PAIR, m as LIGHTNING_SEND_PAIR, n as MAX_MIN_CONFIRMATIONS, o as MIN_CLAIM_WINDOW_SECONDS, p as MIN_HEADROOM_SECONDS, q as ONCHAIN_BTC, r as ONCHAIN_CLAIM_MARGIN_SECONDS, s as ONCHAIN_DUST_SATS, t as ONCHAIN_ORDER_MARGIN_SECONDS, u as ONCHAIN_RECEIVE_PAIR, v as ONCHAIN_SECONDS_PER_BLOCK, w as ONCHAIN_SEND_PAIR, x as OnchainHtlcParams, y as OnchainNetwork, z as RFQ_PREIMAGE_TAG, E as RFQ_TERMINAL_STATES, F as RefundBlockedReason, G as RefundNotLocallyPossibleError, J as RelaySocket, K as RfqQuote, N as RfqRefusalReason, S as StoredSwapSecrets, P as SwapRefusal, Q as SwapSecrets, T as addAssetSwap, U as adoptSwapDescriptor, V as arkadeSwapRequest, W as assertFundable, X as assertReceivable, Y as awaitOnchainFill, Z as buildHtlcClaim, _ as buildHtlcRefund, $ as buildPreimageMessage, a0 as claimOnchainFill, a1 as classifyOnchainHtlc, a2 as deriveLightningReceive, a3 as deriveOnchainReceive, a4 as deriveOnchainSend, a5 as derivePreimage, a6 as deriveSwapSecrets, a7 as extractPreimage, a8 as getAssetSwaps, a9 as getAssetSwapsOrThrow, aa as httpTransport, ab as isDeterministicSigner, ac as lightningReceiveRequest, ad as lightningSendRequest, ae as lightningSendVtxoScript, af as newPreimage, ag as newRfqId, ah as offerTermsFromQuote, ai as onchainHtlcScript, aj as onchainReceiveRequest, ak as onchainSendRequest, al as paymentHashOf, am as preimageForRfqSecrets, an as randomSwapSecrets, ao as receiveVtxoScript, ap as relayTransport, aq as requestLightningReceive, ar as requestLightningSend, as as requestOnchainReceive, at as requestOnchainSend, au as rfqPair, av as rfqSecretsOfRecord, aw as rfqSecretsToRecord, ax as senderIdentityForRfqSecrets, ay as senderIdentityForSwapRecord, az as senderPubkeyForRfqSecrets, aA as unilateralClaimDelay, aB as unilateralRefundDelay, aC as unilateralRefundWithoutReceiverDelay, aD as updateAssetSwap, aE as updateAssetSwapBestEffort, aF as verifyLockupAddress, aG as verifyReceiveInvoice } from './rfq-CRgIOQ_y.js';
2
+ import { A as AssetSwapRepository, a as AssetSwap, M as MarketsCacheEntry, R as RfqStatus, b as RfqTransport, O as OnchainHtlc, C as ChainSource, c as ChainUtxo, d as OnchainHtlcPhase } from './rfq-CCAFoFtR.js';
3
+ export { e as ARKADE_ASSET, f as ARKADE_BTC, g as AddressMismatch, h as AssetSwapFallbackSecrets, i as AssetSwapStatus, B as BTC_ASSET_ID, D as DerivedSwapSecrets, j as DeterministicSigner, H as HtlcUtxo, I as InMemoryAssetSwapRepository, k as InvoiceFacts, L as LIGHTNING_BTC, l as LIGHTNING_RECEIVE_PAIR, m as LIGHTNING_SEND_PAIR, n as MAX_MIN_CONFIRMATIONS, o as MIN_CLAIM_WINDOW_SECONDS, p as MIN_HEADROOM_SECONDS, q as ONCHAIN_BTC, r as ONCHAIN_CLAIM_MARGIN_SECONDS, s as ONCHAIN_DUST_SATS, t as ONCHAIN_ORDER_MARGIN_SECONDS, u as ONCHAIN_RECEIVE_PAIR, v as ONCHAIN_SECONDS_PER_BLOCK, w as ONCHAIN_SEND_PAIR, x as OnchainHtlcParams, y as OnchainNetwork, z as RFQ_PREIMAGE_TAG, E as RFQ_TERMINAL_STATES, F as RefundBlockedReason, G as RefundNotLocallyPossibleError, J as RelaySocket, K as RfqQuote, N as RfqRefusalReason, S as StoredSwapSecrets, P as SwapRefusal, Q as SwapSecrets, T as addAssetSwap, U as adoptSwapDescriptor, V as arkadeSwapRequest, W as assertFundable, X as assertReceivable, Y as awaitOnchainFill, Z as buildHtlcClaim, _ as buildHtlcRefund, $ as buildPreimageMessage, a0 as claimOnchainFill, a1 as classifyOnchainHtlc, a2 as deriveLightningReceive, a3 as deriveOnchainReceive, a4 as deriveOnchainSend, a5 as derivePreimage, a6 as deriveSwapSecrets, a7 as extractPreimage, a8 as getAssetSwaps, a9 as getAssetSwapsOrThrow, aa as httpTransport, ab as isDeterministicSigner, ac as lightningReceiveRequest, ad as lightningSendRequest, ae as lightningSendVtxoScript, af as newPreimage, ag as newRfqId, ah as offerTermsFromQuote, ai as onchainHtlcScript, aj as onchainReceiveRequest, ak as onchainSendRequest, al as paymentHashOf, am as preimageForRfqSecrets, an as randomSwapSecrets, ao as receiveVtxoScript, ap as relayTransport, aq as requestLightningReceive, ar as requestLightningSend, as as requestOnchainReceive, at as requestOnchainSend, au as rfqPair, av as rfqSecretsOfRecord, aw as rfqSecretsToRecord, ax as senderIdentityForRfqSecrets, ay as senderIdentityForSwapRecord, az as senderPubkeyForRfqSecrets, aA as unilateralClaimDelay, aB as unilateralRefundDelay, aC as unilateralRefundWithoutReceiverDelay, aD as updateAssetSwap, aE as updateAssetSwapBestEffort, aF as verifyLockupAddress, aG as verifyReceiveInvoice } from './rfq-CCAFoFtR.js';
4
4
  import { Network, LocalCardInput, DiscoveredMarket, Side, OfferPlan } from '@arkade-os/solver-discovery';
5
5
 
6
6
  /** The contracts — pure data, shared verbatim with any other implementation. */
@@ -38,11 +38,11 @@ declare function decodeOffer(data: Uint8Array): Offer;
38
38
  * you deposit, embedding the returned extension, and the solver does the rest:
39
39
  *
40
40
  * // BTC -> asset
41
- * const o = await createOffer(wallet, ARK, EMULATOR_PUBKEY, { wantAmount: 1000n, wantAsset })
41
+ * const o = await createOffer(wallet, ARK, { wantAmount: 1000n, wantAsset })
42
42
  * await wallet.send({ address: o.address, amount: 1000, extensions: [o.extension] })
43
43
  *
44
44
  * // asset -> BTC (the sats are the VTXO carrier for the asset)
45
- * const o = await createOffer(wallet, ARK, EMULATOR_PUBKEY, { wantAmount: 1000n, offerAsset })
45
+ * const o = await createOffer(wallet, ARK, { wantAmount: 1000n, offerAsset })
46
46
  * await wallet.send({ address: o.address, amount: 500,
47
47
  * assets: [{ assetId, amount: 1000n }],
48
48
  * extensions: [o.extension] })
@@ -55,20 +55,13 @@ declare function decodeOffer(data: Uint8Array): Offer;
55
55
  * and be retried, where the same failure after `wallet.send` would leave a
56
56
  * funded deposit unwatched with no way to notice.
57
57
  */
58
- declare function createOffer(wallet: IWallet, arkServerUrl: string,
59
- /** Covenant co-signer (emulator) x-only key — the SOLVER's deployment,
60
- * not the user's. This library does NOT fetch or verify it: clients
61
- * have no network path to the emulator, only the solver and covclaimd
62
- * do. The caller must obtain this out-of-band, before calling this
63
- * function, from the solver's signed registry/corridor card (its
64
- * `emulator_pubkey`, added in arkade-os/solver-registry#18) or an
65
- * equivalent source it
66
- * independently trusts, and is responsible for having checked it
67
- * against that trusted value itself. */
68
- emulatorPubkey: Uint8Array, params: {
58
+ declare function createOffer(wallet: IWallet, arkServerUrl: string, params: {
69
59
  wantAmount: bigint;
70
60
  wantAsset?: asset.AssetId;
71
61
  offerAsset?: asset.AssetId;
62
+ /** Co-signer key override (33-byte compressed hex); see
63
+ * {@link resolveEmulatorPubkey}. */
64
+ emulatorPubkey?: string;
72
65
  }): Promise<{
73
66
  /** The encoded offer, hex. **Persist this** — it is the only input
74
67
  * `cancelOffer` needs to rebuild the covenant, and the restore scan reads
package/dist/index.js CHANGED
@@ -72,7 +72,7 @@ import {
72
72
  unilateralRefundWithoutReceiverDelay,
73
73
  verifyLockupAddress,
74
74
  verifyReceiveInvoice
75
- } from "./chunk-C5P7R7JT.js";
75
+ } from "./chunk-HLMMA3LJ.js";
76
76
 
77
77
  // src/offer.ts
78
78
  import { hex } from "@scure/base";
@@ -83,7 +83,9 @@ import {
83
83
  RestIndexerProvider,
84
84
  arkade,
85
85
  asset,
86
- getNetwork
86
+ getNetwork,
87
+ resolveEmulatorPubkey,
88
+ toXOnlySignerHex
87
89
  } from "@arkade-os/sdk";
88
90
 
89
91
  // src/swap-want-asset.program.json
@@ -311,14 +313,6 @@ var FIELDS = {
311
313
  offerAsset: { tag: 11, width: void 0 }
312
314
  };
313
315
  var NAMES = Object.fromEntries(Object.entries(FIELDS).map(([k, f]) => [f.tag, k]));
314
- var XONLY_LEN = 32;
315
- var xOnly = (key, label) => {
316
- if (key.length === XONLY_LEN) return key;
317
- if (key.length !== 33 || key[0] !== 2 && key[0] !== 3) {
318
- throw new Error(`${label} is not a compressed or x-only public key`);
319
- }
320
- return key.slice(1);
321
- };
322
316
  function tlv(type, value) {
323
317
  if (value.length > 65535) throw new Error("TLV value exceeds the u16 length field");
324
318
  return concatBytes(Uint8Array.of(type, value.length >> 8 & 255, value.length & 255), value);
@@ -420,7 +414,7 @@ async function registerOfferContract(wallet, arkServerUrl, network, binding, ser
420
414
  });
421
415
  await promoteOfferContract(contractManager, hex.encode(expectedPkScript));
422
416
  }
423
- async function createOffer(wallet, arkServerUrl, emulatorPubkey, params) {
417
+ async function createOffer(wallet, arkServerUrl, params) {
424
418
  if (Boolean(params.wantAsset) === Boolean(params.offerAsset)) {
425
419
  throw new Error("set exactly one of wantAsset (BTC->asset) or offerAsset (asset->BTC)");
426
420
  }
@@ -429,8 +423,11 @@ async function createOffer(wallet, arkServerUrl, emulatorPubkey, params) {
429
423
  wallet.getAddress(),
430
424
  wallet.identity.xOnlyPublicKey()
431
425
  ]);
432
- const serverPubKey = xOnly(hex.decode(info.signerPubkey), "ark signer key");
433
- const emuKey = xOnly(emulatorPubkey, "emulator pubkey");
426
+ const serverPubKey = hex.decode(toXOnlySignerHex(info.signerPubkey));
427
+ const network = getNetwork(info.network);
428
+ const emuKey = hex.decode(
429
+ toXOnlySignerHex(resolveEmulatorPubkey(network, params.emulatorPubkey))
430
+ );
434
431
  const binding = {
435
432
  wantAmount: params.wantAmount,
436
433
  wantAsset: params.wantAsset,
@@ -455,7 +452,7 @@ async function createOffer(wallet, arkServerUrl, emulatorPubkey, params) {
455
452
  extension: { type: OFFER_PACKET_TYPE, payload },
456
453
  // VtxoScript.address owns address construction; assembling an ArkAddress
457
454
  // from tweakedPublicKey here would silently miss any future step it gains
458
- address: script.address(getNetwork(info.network).hrp, serverPubKey).encode(),
455
+ address: script.address(network.hrp, serverPubKey).encode(),
459
456
  swapPkScript: script.pkScript
460
457
  };
461
458
  }
package/dist/nostr.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { b as RfqTransport } from './rfq-CRgIOQ_y.cjs';
1
+ import { b as RfqTransport } from './rfq-CCAFoFtR.cjs';
2
2
  import { SimplePool } from 'nostr-tools';
3
3
  import '@arkade-os/sdk';
4
4
  import '@arkade-os/solver-discovery';
package/dist/nostr.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { b as RfqTransport } from './rfq-CRgIOQ_y.js';
1
+ import { b as RfqTransport } from './rfq-CCAFoFtR.js';
2
2
  import { SimplePool } from 'nostr-tools';
3
3
  import '@arkade-os/sdk';
4
4
  import '@arkade-os/solver-discovery';
package/dist/nostr.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  SwapRefusal
3
- } from "./chunk-C5P7R7JT.js";
3
+ } from "./chunk-HLMMA3LJ.js";
4
4
 
5
5
  // src/nostr.ts
6
6
  import {
@@ -706,10 +706,7 @@ declare function lightningSendVtxoScript(params: {
706
706
  * {@link unilateralRefundDelay} and {@link unilateralRefundWithoutReceiverDelay}
707
707
  * derive from this same value — one rounding, shared across all three tiers. */
708
708
  claimDelay: number;
709
- /** Emulator x-only key the SOLVER's deployment, not the trader's own.
710
- * Not fetched here or anywhere in this package; see {@link
711
- * requestLightningSend}'s `emulatorPubkey` parameter for where it comes
712
- * from and why. */
709
+ /** Emulator x-only key (32 bytes). */
713
710
  emulatorPubkey: Uint8Array;
714
711
  /** Where a refund must pay: the trader's P2TR pkScript (34 bytes). Also
715
712
  * `nonInteractiveRefund`'s covenant destination. */
@@ -765,21 +762,12 @@ interface InvoiceFacts {
765
762
  * cooperation, not just infrastructure uptime, so losing the key with an
766
763
  * unwilling solver is a total loss.
767
764
  */
768
- declare function requestLightningSend(wallet: IWallet, arkServerUrl: string,
769
- /** Covenant co-signer (emulator) x-only key — the SOLVER's deployment,
770
- * not the trader's. This library does NOT fetch or verify it: clients
771
- * have no network path to the emulator, only the solver and covclaimd
772
- * do. The caller must obtain this out-of-band, before calling this
773
- * function, from the solver's signed registry/corridor card (its
774
- * `emulator_pubkey`, added in arkade-os/solver-registry#18) or an
775
- * equivalent source it
776
- * independently trusts, and is responsible for having checked it against
777
- * that trusted value itself — the same never-trust-only-compare rule as
778
- * {@link verifyLockupAddress}, just applied by the caller instead of
779
- * here, because there is nothing in this module to derive it against. */
780
- emulatorPubkey: Uint8Array, transport: RfqTransport, params: {
765
+ declare function requestLightningSend(wallet: IWallet, arkServerUrl: string, transport: RfqTransport, params: {
781
766
  invoice: InvoiceFacts;
782
767
  rfqId?: string;
768
+ /** Co-signer key override (33-byte compressed hex); see
769
+ * {@link resolveEmulatorPubkey}. */
770
+ emulatorPubkey?: string;
783
771
  }): Promise<{
784
772
  rfqId: string;
785
773
  quote: RfqQuote;
@@ -925,10 +913,7 @@ declare function deriveOnchainSend(input: {
925
913
  * `claimOnchainFill`) before `htlc.refundLocktime`. Missing that window
926
914
  * forfeits the fill and falls back to the Arkade covenant refund.
927
915
  */
928
- declare function requestOnchainSend(wallet: IWallet, arkServerUrl: string,
929
- /** Covenant co-signer (emulator) x-only key — same parameter, same
930
- * caller obligation, as {@link requestLightningSend}'s. */
931
- emulatorPubkey: Uint8Array, transport: RfqTransport, params: {
916
+ declare function requestOnchainSend(wallet: IWallet, arkServerUrl: string, transport: RfqTransport, params: {
932
917
  amount: number;
933
918
  amountSide: "from" | "to";
934
919
  /** User's x-only L1 key that will claim the HTLC. */
@@ -936,6 +921,9 @@ emulatorPubkey: Uint8Array, transport: RfqTransport, params: {
936
921
  /** Optional caller-owned P. Persist it with the returned secrets before funding. */
937
922
  preimage?: Uint8Array;
938
923
  rfqId?: string;
924
+ /** Co-signer key override (33-byte compressed hex); see
925
+ * {@link resolveEmulatorPubkey}. */
926
+ emulatorPubkey?: string;
939
927
  }): Promise<{
940
928
  rfqId: string;
941
929
  quote: RfqQuote;
@@ -1101,12 +1089,12 @@ declare function deriveLightningReceive(input: {
1101
1089
  * Pay before `invoiceExpiresAt`: the hold-invoice window is minutes, not the
1102
1090
  * quote's `valid_until`.
1103
1091
  */
1104
- declare function requestLightningReceive(wallet: IWallet, arkServerUrl: string,
1105
- /** Covenant co-signer (emulator) x-only key — same parameter, same
1106
- * caller obligation, as {@link requestLightningSend}'s. */
1107
- emulatorPubkey: Uint8Array, transport: RfqTransport, params: {
1092
+ declare function requestLightningReceive(wallet: IWallet, arkServerUrl: string, transport: RfqTransport, params: {
1108
1093
  amount: number;
1109
1094
  amountSide: "from" | "to";
1095
+ /** Co-signer key override (33-byte compressed hex); see
1096
+ * {@link resolveEmulatorPubkey}. */
1097
+ emulatorPubkey?: string;
1110
1098
  /** covclaimd's 33-byte compressed pubkey (from its own info endpoint)
1111
1099
  * — the claim packet seals to it and only it can ever read `P` early. */
1112
1100
  covclaimdPubkey: Uint8Array;
@@ -1186,12 +1174,12 @@ declare function deriveOnchainReceive(input: {
1186
1174
  * `refundPubkey`) opens at `htlc.refundLocktime` — `buildHtlcRefund` takes it
1187
1175
  * back from there.
1188
1176
  */
1189
- declare function requestOnchainReceive(wallet: IWallet, arkServerUrl: string,
1190
- /** Covenant co-signer (emulator) x-only key — same parameter, same
1191
- * caller obligation, as {@link requestLightningSend}'s. */
1192
- emulatorPubkey: Uint8Array, transport: RfqTransport, params: {
1177
+ declare function requestOnchainReceive(wallet: IWallet, arkServerUrl: string, transport: RfqTransport, params: {
1193
1178
  amount: number;
1194
1179
  amountSide: "from" | "to";
1180
+ /** Co-signer key override (33-byte compressed hex); see
1181
+ * {@link resolveEmulatorPubkey}. */
1182
+ emulatorPubkey?: string;
1195
1183
  /** Trader's x-only L1 key for the HTLC's refund leaf. */
1196
1184
  refundPubkey: Uint8Array;
1197
1185
  /** covclaimd's 33-byte compressed pubkey — see {@link requestLightningReceive}. */
@@ -706,10 +706,7 @@ declare function lightningSendVtxoScript(params: {
706
706
  * {@link unilateralRefundDelay} and {@link unilateralRefundWithoutReceiverDelay}
707
707
  * derive from this same value — one rounding, shared across all three tiers. */
708
708
  claimDelay: number;
709
- /** Emulator x-only key the SOLVER's deployment, not the trader's own.
710
- * Not fetched here or anywhere in this package; see {@link
711
- * requestLightningSend}'s `emulatorPubkey` parameter for where it comes
712
- * from and why. */
709
+ /** Emulator x-only key (32 bytes). */
713
710
  emulatorPubkey: Uint8Array;
714
711
  /** Where a refund must pay: the trader's P2TR pkScript (34 bytes). Also
715
712
  * `nonInteractiveRefund`'s covenant destination. */
@@ -765,21 +762,12 @@ interface InvoiceFacts {
765
762
  * cooperation, not just infrastructure uptime, so losing the key with an
766
763
  * unwilling solver is a total loss.
767
764
  */
768
- declare function requestLightningSend(wallet: IWallet, arkServerUrl: string,
769
- /** Covenant co-signer (emulator) x-only key — the SOLVER's deployment,
770
- * not the trader's. This library does NOT fetch or verify it: clients
771
- * have no network path to the emulator, only the solver and covclaimd
772
- * do. The caller must obtain this out-of-band, before calling this
773
- * function, from the solver's signed registry/corridor card (its
774
- * `emulator_pubkey`, added in arkade-os/solver-registry#18) or an
775
- * equivalent source it
776
- * independently trusts, and is responsible for having checked it against
777
- * that trusted value itself — the same never-trust-only-compare rule as
778
- * {@link verifyLockupAddress}, just applied by the caller instead of
779
- * here, because there is nothing in this module to derive it against. */
780
- emulatorPubkey: Uint8Array, transport: RfqTransport, params: {
765
+ declare function requestLightningSend(wallet: IWallet, arkServerUrl: string, transport: RfqTransport, params: {
781
766
  invoice: InvoiceFacts;
782
767
  rfqId?: string;
768
+ /** Co-signer key override (33-byte compressed hex); see
769
+ * {@link resolveEmulatorPubkey}. */
770
+ emulatorPubkey?: string;
783
771
  }): Promise<{
784
772
  rfqId: string;
785
773
  quote: RfqQuote;
@@ -925,10 +913,7 @@ declare function deriveOnchainSend(input: {
925
913
  * `claimOnchainFill`) before `htlc.refundLocktime`. Missing that window
926
914
  * forfeits the fill and falls back to the Arkade covenant refund.
927
915
  */
928
- declare function requestOnchainSend(wallet: IWallet, arkServerUrl: string,
929
- /** Covenant co-signer (emulator) x-only key — same parameter, same
930
- * caller obligation, as {@link requestLightningSend}'s. */
931
- emulatorPubkey: Uint8Array, transport: RfqTransport, params: {
916
+ declare function requestOnchainSend(wallet: IWallet, arkServerUrl: string, transport: RfqTransport, params: {
932
917
  amount: number;
933
918
  amountSide: "from" | "to";
934
919
  /** User's x-only L1 key that will claim the HTLC. */
@@ -936,6 +921,9 @@ emulatorPubkey: Uint8Array, transport: RfqTransport, params: {
936
921
  /** Optional caller-owned P. Persist it with the returned secrets before funding. */
937
922
  preimage?: Uint8Array;
938
923
  rfqId?: string;
924
+ /** Co-signer key override (33-byte compressed hex); see
925
+ * {@link resolveEmulatorPubkey}. */
926
+ emulatorPubkey?: string;
939
927
  }): Promise<{
940
928
  rfqId: string;
941
929
  quote: RfqQuote;
@@ -1101,12 +1089,12 @@ declare function deriveLightningReceive(input: {
1101
1089
  * Pay before `invoiceExpiresAt`: the hold-invoice window is minutes, not the
1102
1090
  * quote's `valid_until`.
1103
1091
  */
1104
- declare function requestLightningReceive(wallet: IWallet, arkServerUrl: string,
1105
- /** Covenant co-signer (emulator) x-only key — same parameter, same
1106
- * caller obligation, as {@link requestLightningSend}'s. */
1107
- emulatorPubkey: Uint8Array, transport: RfqTransport, params: {
1092
+ declare function requestLightningReceive(wallet: IWallet, arkServerUrl: string, transport: RfqTransport, params: {
1108
1093
  amount: number;
1109
1094
  amountSide: "from" | "to";
1095
+ /** Co-signer key override (33-byte compressed hex); see
1096
+ * {@link resolveEmulatorPubkey}. */
1097
+ emulatorPubkey?: string;
1110
1098
  /** covclaimd's 33-byte compressed pubkey (from its own info endpoint)
1111
1099
  * — the claim packet seals to it and only it can ever read `P` early. */
1112
1100
  covclaimdPubkey: Uint8Array;
@@ -1186,12 +1174,12 @@ declare function deriveOnchainReceive(input: {
1186
1174
  * `refundPubkey`) opens at `htlc.refundLocktime` — `buildHtlcRefund` takes it
1187
1175
  * back from there.
1188
1176
  */
1189
- declare function requestOnchainReceive(wallet: IWallet, arkServerUrl: string,
1190
- /** Covenant co-signer (emulator) x-only key — same parameter, same
1191
- * caller obligation, as {@link requestLightningSend}'s. */
1192
- emulatorPubkey: Uint8Array, transport: RfqTransport, params: {
1177
+ declare function requestOnchainReceive(wallet: IWallet, arkServerUrl: string, transport: RfqTransport, params: {
1193
1178
  amount: number;
1194
1179
  amountSide: "from" | "to";
1180
+ /** Co-signer key override (33-byte compressed hex); see
1181
+ * {@link resolveEmulatorPubkey}. */
1182
+ emulatorPubkey?: string;
1195
1183
  /** Trader's x-only L1 key for the HTLC's refund leaf. */
1196
1184
  refundPubkey: Uint8Array;
1197
1185
  /** covclaimd's 33-byte compressed pubkey — see {@link requestLightningReceive}. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arkade-os/swap",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "type": "module",
5
5
  "description": "Client-side Arkade Intents asset swaps: discover markets, quote, create/track/cancel offers, restore from chain.",
6
6
  "repository": {
@@ -49,7 +49,7 @@
49
49
  "@noble/hashes": "2.0.1",
50
50
  "@scure/base": "2.0.0",
51
51
  "@scure/btc-signer": "2.0.1",
52
- "@arkade-os/sdk": "0.4.58"
52
+ "@arkade-os/sdk": "0.4.60"
53
53
  },
54
54
  "peerDependencies": {
55
55
  "nostr-tools": "^2.12.0"