@arkade-os/swap 0.0.2 → 0.0.4

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.
@@ -204,176 +204,11 @@ async function classifyOnchainHtlc(chain, input) {
204
204
  return { phase: "claimable", utxo: best };
205
205
  }
206
206
 
207
- // src/secrets.ts
208
- import { hex as hex2 } from "@scure/base";
209
- import { sha256 as sha2562 } from "@noble/hashes/sha2.js";
210
- import { randomBytes } from "@noble/hashes/utils.js";
211
- import { schnorr } from "@noble/curves/secp256k1.js";
212
- import {
213
- SingleKey,
214
- isHDAllocationCapable,
215
- isHDWalletCapable
216
- } from "@arkade-os/sdk";
217
- var RFQ_PREIMAGE_TAG = "Arkade-RFQ-Preimage-v1";
218
- function buildPreimageMessage(xonly, index) {
219
- if (xonly.length !== 32) {
220
- throw new Error(`x-only pubkey must be 32 bytes, got ${xonly.length}`);
221
- }
222
- if (!Number.isInteger(index) || index < 0 || index > 4294967295) {
223
- throw new Error(`index must be a u32, got ${index}`);
224
- }
225
- const tag = new TextEncoder().encode(RFQ_PREIMAGE_TAG);
226
- const message = new Uint8Array(tag.length + 32 + 4);
227
- message.set(tag, 0);
228
- message.set(xonly, tag.length);
229
- new DataView(message.buffer).setUint32(tag.length + 32, index, true);
230
- return message;
231
- }
232
- var PREIMAGE_INDEX = 0;
233
- async function deriveSwapSecrets(wallet) {
234
- if (!isHDAllocationCapable(wallet)) return void 0;
235
- const signingDescriptor = await wallet.getNextSigningDescriptor();
236
- if (!signingDescriptor) return void 0;
237
- return { derivable: true, signingDescriptor };
238
- }
239
- function randomSwapSecrets(opts = {}) {
240
- if (opts.preimage instanceof Uint8Array && opts.preimage.length !== 32) {
241
- throw new Error(`preimage must be 32 bytes, got ${opts.preimage.length}`);
242
- }
243
- const preimage = opts.preimage instanceof Uint8Array ? opts.preimage : opts.preimage ? randomBytes(32) : void 0;
244
- return {
245
- derivable: false,
246
- senderPrivateKey: schnorr.utils.randomSecretKey(),
247
- ...preimage ? { preimage } : {}
248
- };
249
- }
250
- function rfqSecretsToRecord(secrets) {
251
- if (secrets.derivable) {
252
- return {
253
- signingDescriptor: secrets.signingDescriptor,
254
- ...secrets.preimage ? { preimageHex: hex2.encode(secrets.preimage) } : {}
255
- };
256
- }
257
- return {
258
- fallbackSecrets: {
259
- version: 1,
260
- type: "stored",
261
- senderPrivateKeyHex: hex2.encode(secrets.senderPrivateKey),
262
- ...secrets.preimage ? { preimageHex: hex2.encode(secrets.preimage) } : {}
263
- }
264
- };
265
- }
266
- function rfqSecretsOfRecord(record) {
267
- if (record.signingDescriptor) {
268
- return {
269
- derivable: true,
270
- signingDescriptor: record.signingDescriptor,
271
- ...record.preimageHex ? { preimage: decodeHex32(record.preimageHex, "preimageHex") } : {}
272
- };
273
- }
274
- const fallback = record.fallbackSecrets;
275
- if (!fallback) return void 0;
276
- if (fallback.version !== 1 || fallback.type !== "stored") {
277
- throw new Error("unsupported RFQ fallback secrets record");
278
- }
279
- return {
280
- derivable: false,
281
- senderPrivateKey: decodeHex32(fallback.senderPrivateKeyHex, "senderPrivateKeyHex"),
282
- ...fallback.preimageHex ? { preimage: decodeHex32(fallback.preimageHex, "preimageHex") } : {}
283
- };
284
- }
285
- function decodeHex32(value, label) {
286
- const bytes = hex2.decode(value);
287
- if (bytes.length !== 32) {
288
- throw new Error(label + " must be 32 bytes, got " + bytes.length);
289
- }
290
- return bytes;
291
- }
292
- async function adoptSwapDescriptor(wallet, signingDescriptor) {
293
- if (!isHDAllocationCapable(wallet)) return;
294
- await wallet.advanceSigningDescriptorWatermark(signingDescriptor);
295
- }
296
- var RefundNotLocallyPossibleError = class extends Error {
297
- constructor(reason, message, options) {
298
- super(message, options);
299
- this.reason = reason;
300
- }
301
- reason;
302
- name = "RefundNotLocallyPossibleError";
303
- };
304
- async function senderIdentityForRfqSecrets(wallet, secrets) {
305
- if (!secrets.derivable) return SingleKey.fromPrivateKey(secrets.senderPrivateKey);
306
- const signer = isHDWalletCapable(wallet) ? await wallet.signerForDescriptor(secrets.signingDescriptor) : void 0;
307
- if (!signer || !isDeterministicSigner(signer)) {
308
- throw new RefundNotLocallyPossibleError(
309
- "foreign-descriptor",
310
- `this wallet cannot derive ${secrets.signingDescriptor}; the swap was created on another wallet`
311
- );
312
- }
313
- return signer;
314
- }
315
- async function senderIdentityForSwapRecord(wallet, record) {
316
- let secrets;
317
- try {
318
- secrets = rfqSecretsOfRecord(record);
319
- } catch (error) {
320
- throw new RefundNotLocallyPossibleError(
321
- "unreadable-secrets",
322
- error instanceof Error ? error.message : String(error),
323
- // the record's own diagnosis, kept for a caller that wants more
324
- // than the message
325
- { cause: error }
326
- );
327
- }
328
- if (!secrets) {
329
- throw new RefundNotLocallyPossibleError(
330
- "no-secrets",
331
- "this swap record carries no signing descriptor and no fallback secrets"
332
- );
333
- }
334
- return senderIdentityForRfqSecrets(wallet, secrets);
335
- }
336
- async function senderPubkeyForRfqSecrets(wallet, secrets) {
337
- if (!secrets.derivable) return schnorr.getPublicKey(secrets.senderPrivateKey);
338
- return (await senderIdentityForRfqSecrets(wallet, secrets)).xOnlyPublicKey();
339
- }
340
- function isDeterministicSigner(value) {
341
- if (typeof value !== "object" || value === null) return false;
342
- const v = value;
343
- return typeof v.signSchnorrDeterministic === "function" && typeof v.xOnlyPublicKey === "function";
344
- }
345
- async function derivePreimage(signer) {
346
- const xonly = await signer.xOnlyPublicKey();
347
- const message = buildPreimageMessage(xonly, PREIMAGE_INDEX);
348
- return sha2562(await signer.signSchnorrDeterministic(sha2562(message)));
349
- }
350
- async function preimageForRfqSecrets(wallet, secrets) {
351
- if (!secrets.derivable) {
352
- if (!secrets.preimage) throw new Error("this swap carries no stored preimage");
353
- return secrets.preimage;
354
- }
355
- if (secrets.preimage) return secrets.preimage;
356
- const signer = await senderIdentityForRfqSecrets(wallet, secrets);
357
- if (!isDeterministicSigner(signer)) {
358
- throw new Error(
359
- `wallet cannot sign deterministically for ${secrets.signingDescriptor}; its preimage is not derivable`
360
- );
361
- }
362
- try {
363
- return await derivePreimage(signer);
364
- } catch (cause) {
365
- throw new Error(
366
- `wallet cannot sign deterministically for ${secrets.signingDescriptor}; its preimage is not derivable`,
367
- { cause }
368
- );
369
- }
370
- }
371
-
372
207
  // src/claimPacket.ts
373
208
  import { base64 } from "@scure/base";
374
209
  import { secp256k1 } from "@noble/curves/secp256k1.js";
375
210
  import { hkdf } from "@noble/hashes/hkdf.js";
376
- import { sha256 as sha2563 } from "@noble/hashes/sha2.js";
211
+ import { sha256 as sha2562 } from "@noble/hashes/sha2.js";
377
212
  var HKDF_INFO = new TextEncoder().encode("covclaimd/preimage/v1");
378
213
  async function sealClaimPacket(input) {
379
214
  return sealWithEntropy(
@@ -389,7 +224,7 @@ async function sealWithEntropy(input, ephemeralKey, nonce) {
389
224
  }
390
225
  const ephemeralPub = secp256k1.getPublicKey(ephemeralKey, true);
391
226
  const sharedX = secp256k1.getSharedSecret(ephemeralKey, input.covclaimdPubkey, true).subarray(1);
392
- const key = hkdf(sha2563, sharedX, ephemeralPub, HKDF_INFO, 32);
227
+ const key = hkdf(sha2562, sharedX, ephemeralPub, HKDF_INFO, 32);
393
228
  if (nonce.length !== 12) throw new Error("nonce must be 12 bytes");
394
229
  const aesKey = await crypto.subtle.importKey("raw", key, "AES-GCM", false, [
395
230
  "encrypt"
@@ -413,7 +248,7 @@ async function sealWithEntropy(input, ephemeralKey, nonce) {
413
248
  }
414
249
 
415
250
  // src/lockupContract.ts
416
- import { hex as hex3 } from "@scure/base";
251
+ import { hex as hex2 } from "@scure/base";
417
252
  import { VHTLCV2ContractHandler } from "@arkade-os/sdk";
418
253
  var SWAP_LOCKUP_CONTRACT_TYPE = "vhtlc-v2";
419
254
  var SWAP_LOCKUP_CONTRACT_LABEL = "Arkade RFQ swap lockup";
@@ -437,7 +272,7 @@ async function registerLockupContract(contracts, script, address) {
437
272
  await contracts.createContract({
438
273
  type: SWAP_LOCKUP_CONTRACT_TYPE,
439
274
  params: VHTLCV2ContractHandler.serializeParams(script.options),
440
- script: hex3.encode(script.pkScript),
275
+ script: hex2.encode(script.pkScript),
441
276
  address,
442
277
  label: SWAP_LOCKUP_CONTRACT_LABEL,
443
278
  metadata: { genericallySpendable: false, kind: SWAP_LOCKUP_CONTRACT_KIND }
@@ -448,13 +283,18 @@ async function registerLockupContract(contracts, script, address) {
448
283
  }
449
284
 
450
285
  // src/rfq.ts
451
- import { hex as hex4 } from "@scure/base";
286
+ import { hex as hex3 } from "@scure/base";
452
287
  import { ripemd160 as ripemd1602 } from "@noble/hashes/legacy.js";
453
288
  import {
454
289
  ArkAddress,
455
290
  RestArkProvider,
456
291
  VHTLC,
457
- getNetwork
292
+ getNetwork,
293
+ resolveEmulatorPubkey
294
+ } from "@arkade-os/sdk";
295
+ import {
296
+ provisionClaimSecret,
297
+ provisionRefundKey
458
298
  } from "@arkade-os/sdk";
459
299
  var xOnly = (key, label) => {
460
300
  if (key.length === 32) return key;
@@ -465,7 +305,7 @@ var xOnly = (key, label) => {
465
305
  };
466
306
  var solverHex = (value, field) => {
467
307
  try {
468
- return hex4.decode(value);
308
+ return hex3.decode(value);
469
309
  } catch {
470
310
  throw new Error(`solver sent malformed hex for ${field}`);
471
311
  }
@@ -500,7 +340,7 @@ var AddressMismatch = class extends Error {
500
340
  this.quoted = quoted;
501
341
  }
502
342
  };
503
- var newRfqId = () => hex4.encode(crypto.getRandomValues(new Uint8Array(32)));
343
+ var newRfqId = () => hex3.encode(crypto.getRandomValues(new Uint8Array(32)));
504
344
  var lightningSendRequest = (input) => ({
505
345
  v: 1,
506
346
  type: "rfq_request",
@@ -510,7 +350,7 @@ var lightningSendRequest = (input) => ({
510
350
  profile: {
511
351
  invoice: input.invoice,
512
352
  refund_address: input.refundAddress,
513
- client_refund_pubkey: hex4.encode(input.senderPubkey)
353
+ client_refund_pubkey: hex3.encode(input.senderPubkey)
514
354
  }
515
355
  });
516
356
  var arkadeSwapRequest = (input) => {
@@ -528,8 +368,8 @@ var arkadeSwapRequest = (input) => {
528
368
  amount_side: input.amountSide,
529
369
  amount: input.amount,
530
370
  profile: {
531
- ...input.offerAsset && { offer_asset: hex4.encode(input.offerAsset.serialize()) },
532
- ...input.wantAsset && { want_asset: hex4.encode(input.wantAsset.serialize()) }
371
+ ...input.offerAsset && { offer_asset: hex3.encode(input.offerAsset.serialize()) },
372
+ ...input.wantAsset && { want_asset: hex3.encode(input.wantAsset.serialize()) }
533
373
  }
534
374
  };
535
375
  };
@@ -730,7 +570,7 @@ function lightningSendVtxoScript(params) {
730
570
  sender: params.senderPubkey,
731
571
  receiver: params.solverPubkey,
732
572
  server: params.serverPubkey,
733
- preimageHash: ripemd1602(hex4.decode(params.paymentHash)),
573
+ preimageHash: ripemd1602(hex3.decode(params.paymentHash)),
734
574
  refundLocktime: BigInt(params.refundLocktime),
735
575
  unilateralClaimDelay: seconds(params.claimDelay),
736
576
  unilateralRefundDelay: seconds(unilateralRefundDelay(params.claimDelay)),
@@ -747,15 +587,10 @@ function lightningSendVtxoScript(params) {
747
587
  }
748
588
  });
749
589
  }
750
- async function requestLightningSend(wallet, arkServerUrl, emulatorPubkey, transport, params) {
590
+ async function requestLightningSend(wallet, arkServerUrl, transport, params) {
751
591
  const rfqId = params.rfqId ?? newRfqId();
752
- const secrets = await deriveSwapSecrets(wallet) ?? randomSwapSecrets();
753
- if (!secrets.derivable) {
754
- console.warn(
755
- "[swap] wallet cannot allocate an HD descriptor: the sender key is random and MUST be persisted before funding"
756
- );
757
- }
758
- const senderPubkey = await senderPubkeyForRfqSecrets(wallet, secrets);
592
+ const secrets = await provisionRefundKey(wallet);
593
+ const senderPubkey = secrets.pubkey;
759
594
  const [info, refundAddress] = await Promise.all([
760
595
  new RestArkProvider(arkServerUrl).getInfo(),
761
596
  wallet.getAddress()
@@ -780,19 +615,23 @@ async function requestLightningSend(wallet, arkServerUrl, emulatorPubkey, transp
780
615
  `quote from_amount ${quote.from_amount} is below the invoice amount \u2014 a negative spread is not a quote`
781
616
  );
782
617
  }
783
- const serverPubkey = xOnly(hex4.decode(info.signerPubkey), "ark signer key");
618
+ const serverPubkey = xOnly(hex3.decode(info.signerPubkey), "ark signer key");
619
+ const network = getNetwork(info.network);
784
620
  const script = lightningSendVtxoScript({
785
- solverPubkey: xOnly(hex4.decode(quote.solver_pubkey), "solver key"),
621
+ solverPubkey: xOnly(hex3.decode(quote.solver_pubkey), "solver key"),
786
622
  refundLocktime: quote.refund_locktime,
787
623
  serverPubkey,
788
624
  paymentHash: params.invoice.paymentHash,
789
625
  claimDelay: unilateralClaimDelay(Number(info.unilateralExitDelay)),
790
- emulatorPubkey: xOnly(emulatorPubkey, "emulator pubkey"),
626
+ emulatorPubkey: xOnly(
627
+ hex3.decode(resolveEmulatorPubkey(network, params.emulatorPubkey)),
628
+ "emulator signer key"
629
+ ),
791
630
  senderPubkey,
792
631
  receiverPkScript: solverHex(receiverPkScriptHex, "profile.receiver_pk_script"),
793
632
  refundPkScript: ArkAddress.decode(refundAddress).pkScript
794
633
  });
795
- const address = script.address(getNetwork(info.network).hrp, serverPubkey).encode();
634
+ const address = script.address(network.hrp, serverPubkey).encode();
796
635
  verifyLockupAddress(quote, address);
797
636
  assertFundable({
798
637
  quote,
@@ -830,9 +669,9 @@ var onchainSendRequest = (input) => ({
830
669
  amount: input.amount,
831
670
  profile: {
832
671
  payment_hash: input.paymentHash,
833
- payout_pubkey: hex4.encode(input.payoutPubkey),
672
+ payout_pubkey: hex3.encode(input.payoutPubkey),
834
673
  refund_address: input.refundAddress,
835
- client_refund_pubkey: hex4.encode(input.senderPubkey)
674
+ client_refund_pubkey: hex3.encode(input.senderPubkey)
836
675
  }
837
676
  });
838
677
  var lightningReceiveRequest = (input) => ({
@@ -845,7 +684,7 @@ var lightningReceiveRequest = (input) => ({
845
684
  profile: {
846
685
  payment_hash: input.paymentHash,
847
686
  payout_address: input.payoutAddress,
848
- payout_pubkey: hex4.encode(input.payoutPubkey),
687
+ payout_pubkey: hex3.encode(input.payoutPubkey),
849
688
  claim_packet: input.claimPacket
850
689
  }
851
690
  });
@@ -859,9 +698,9 @@ var onchainReceiveRequest = (input) => ({
859
698
  profile: {
860
699
  payment_hash: input.paymentHash,
861
700
  claim_packet: input.claimPacket,
862
- refund_pubkey: hex4.encode(input.refundPubkey),
701
+ refund_pubkey: hex3.encode(input.refundPubkey),
863
702
  payout_address: input.payoutAddress,
864
- payout_pubkey: hex4.encode(input.payoutPubkey)
703
+ payout_pubkey: hex3.encode(input.payoutPubkey)
865
704
  }
866
705
  });
867
706
  function deriveOnchainSend(input) {
@@ -877,7 +716,7 @@ function deriveOnchainSend(input) {
877
716
  throw new Error("onchain-send quote is missing a binding field");
878
717
  }
879
718
  const script = lightningSendVtxoScript({
880
- solverPubkey: xOnly(hex4.decode(quote.solver_pubkey), "solver key"),
719
+ solverPubkey: xOnly(hex3.decode(quote.solver_pubkey), "solver key"),
881
720
  refundLocktime,
882
721
  serverPubkey: input.serverPubkey,
883
722
  paymentHash: input.paymentHash,
@@ -893,7 +732,7 @@ function deriveOnchainSend(input) {
893
732
  {
894
733
  paymentHash: input.paymentHash,
895
734
  claimKey: input.payoutPubkey,
896
- refundKey: xOnly(hex4.decode(htlcPubkey), "solver L1 htlc key"),
735
+ refundKey: xOnly(hex3.decode(htlcPubkey), "solver L1 htlc key"),
897
736
  refundLocktime: htlcLocktime
898
737
  },
899
738
  input.l1Network
@@ -909,25 +748,16 @@ function deriveOnchainSend(input) {
909
748
  minConfirmations
910
749
  };
911
750
  }
912
- async function requestOnchainSend(wallet, arkServerUrl, emulatorPubkey, transport, params) {
751
+ async function requestOnchainSend(wallet, arkServerUrl, transport, params) {
913
752
  const rfqId = params.rfqId ?? newRfqId();
914
- if (params.preimage && params.preimage.length !== 32) {
915
- throw new Error(`preimage must be 32 bytes, got ${params.preimage.length}`);
916
- }
917
- const derivedSecrets = await deriveSwapSecrets(wallet);
918
- const secrets = derivedSecrets ? params.preimage ? { ...derivedSecrets, preimage: params.preimage } : derivedSecrets : randomSwapSecrets({ preimage: params.preimage ?? true });
919
- if (!secrets.derivable) {
920
- console.warn(
921
- params.preimage ? "[swap] this swap's sender key is random; the supplied preimage and sender key MUST be persisted before funding" : "[swap] this swap's preimage and sender key are random and MUST be persisted before funding"
922
- );
923
- } else if (params.preimage) {
753
+ const secrets = await provisionClaimSecret(wallet, { preimage: params.preimage });
754
+ if (secrets.mustPersistPreimage) {
924
755
  console.warn(
925
- "[swap] this swap's preimage was supplied by the caller and MUST be persisted with the signing descriptor before funding"
756
+ "[swap] this swap's preimage cannot be re-derived from the seed and MUST be persisted with the record before funding"
926
757
  );
927
758
  }
928
- const preimage = await preimageForRfqSecrets(wallet, secrets);
929
- const paymentHash = paymentHashOf(preimage);
930
- const senderPubkey = await senderPubkeyForRfqSecrets(wallet, secrets);
759
+ const paymentHash = hex3.encode(secrets.paymentHash);
760
+ const senderPubkey = secrets.pubkey;
931
761
  const [info, refundAddress] = await Promise.all([
932
762
  new RestArkProvider(arkServerUrl).getInfo(),
933
763
  wallet.getAddress()
@@ -943,14 +773,18 @@ async function requestOnchainSend(wallet, arkServerUrl, emulatorPubkey, transpor
943
773
  amountSide: params.amountSide
944
774
  })
945
775
  );
776
+ const network = getNetwork(info.network);
946
777
  const derived = deriveOnchainSend({
947
778
  quote,
948
779
  paymentHash,
949
780
  payoutPubkey: params.payoutPubkey,
950
- serverPubkey: xOnly(hex4.decode(info.signerPubkey), "ark signer key"),
951
- emulatorPubkey: xOnly(emulatorPubkey, "emulator pubkey"),
781
+ serverPubkey: xOnly(hex3.decode(info.signerPubkey), "ark signer key"),
782
+ emulatorPubkey: xOnly(
783
+ hex3.decode(resolveEmulatorPubkey(network, params.emulatorPubkey)),
784
+ "emulator signer key"
785
+ ),
952
786
  claimDelay: unilateralClaimDelay(Number(info.unilateralExitDelay)),
953
- hrp: getNetwork(info.network).hrp,
787
+ hrp: network.hrp,
954
788
  l1Network: l1NetworkFromArk(info.network),
955
789
  refundAddress,
956
790
  senderPubkey
@@ -1058,7 +892,7 @@ function receiveVtxoScript(params) {
1058
892
  sender: params.solverPubkey,
1059
893
  receiver: params.payoutPubkey,
1060
894
  server: params.serverPubkey,
1061
- preimageHash: ripemd1602(hex4.decode(params.paymentHash)),
895
+ preimageHash: ripemd1602(hex3.decode(params.paymentHash)),
1062
896
  refundLocktime: BigInt(params.refundLocktime),
1063
897
  unilateralClaimDelay: seconds(params.claimDelay),
1064
898
  unilateralRefundDelay: seconds(unilateralRefundDelay(params.claimDelay)),
@@ -1085,7 +919,7 @@ function deriveLightningReceive(input) {
1085
919
  throw new Error("lightning-receive quote is missing a binding field");
1086
920
  }
1087
921
  const script = receiveVtxoScript({
1088
- solverPubkey: xOnly(hex4.decode(quote.solver_pubkey), "solver key"),
922
+ solverPubkey: xOnly(hex3.decode(quote.solver_pubkey), "solver key"),
1089
923
  refundLocktime,
1090
924
  serverPubkey: input.serverPubkey,
1091
925
  paymentHash: input.paymentHash,
@@ -1099,17 +933,17 @@ function deriveLightningReceive(input) {
1099
933
  verifyLockupAddress(quote, address);
1100
934
  return { address, swapPkScript: script.pkScript, script, invoice, refundLocktime };
1101
935
  }
1102
- async function requestLightningReceive(wallet, arkServerUrl, emulatorPubkey, transport, params) {
936
+ async function requestLightningReceive(wallet, arkServerUrl, transport, params) {
1103
937
  const rfqId = params.rfqId ?? newRfqId();
1104
- const secrets = await deriveSwapSecrets(wallet) ?? randomSwapSecrets({ preimage: true });
1105
- if (!secrets.derivable) {
938
+ const secrets = await provisionClaimSecret(wallet);
939
+ if (secrets.mustPersistPreimage) {
1106
940
  console.warn(
1107
- "[swap] this swap's preimage and payout key are random and MUST be persisted before paying"
941
+ "[swap] this swap's preimage cannot be re-derived from the seed and MUST be persisted with the record before paying"
1108
942
  );
1109
943
  }
1110
- const preimage = await preimageForRfqSecrets(wallet, secrets);
1111
- const paymentHash = paymentHashOf(preimage);
1112
- const payoutPubkey = await senderPubkeyForRfqSecrets(wallet, secrets);
944
+ const preimage = secrets.preimage;
945
+ const paymentHash = hex3.encode(secrets.paymentHash);
946
+ const payoutPubkey = secrets.pubkey;
1113
947
  const [info, payoutAddress] = await Promise.all([
1114
948
  new RestArkProvider(arkServerUrl).getInfo(),
1115
949
  wallet.getAddress()
@@ -1130,15 +964,19 @@ async function requestLightningReceive(wallet, arkServerUrl, emulatorPubkey, tra
1130
964
  })
1131
965
  );
1132
966
  assertQuotedAmount(quote, params.amountSide, params.amount);
967
+ const network = getNetwork(info.network);
1133
968
  const derived = deriveLightningReceive({
1134
969
  quote,
1135
970
  paymentHash,
1136
971
  payoutPubkey,
1137
972
  payoutAddress,
1138
- serverPubkey: xOnly(hex4.decode(info.signerPubkey), "ark signer key"),
1139
- emulatorPubkey: xOnly(emulatorPubkey, "emulator pubkey"),
973
+ serverPubkey: xOnly(hex3.decode(info.signerPubkey), "ark signer key"),
974
+ emulatorPubkey: xOnly(
975
+ hex3.decode(resolveEmulatorPubkey(network, params.emulatorPubkey)),
976
+ "emulator signer key"
977
+ ),
1140
978
  claimDelay: unilateralClaimDelay(Number(info.unilateralExitDelay)),
1141
- hrp: getNetwork(info.network).hrp
979
+ hrp: network.hrp
1142
980
  });
1143
981
  const now = Math.floor(Date.now() / 1e3);
1144
982
  const { payDeadline } = verifyReceiveInvoice({
@@ -1181,7 +1019,7 @@ function deriveOnchainReceive(input) {
1181
1019
  throw new Error("onchain-receive quote is missing a binding field");
1182
1020
  }
1183
1021
  const script = receiveVtxoScript({
1184
- solverPubkey: xOnly(hex4.decode(quote.solver_pubkey), "solver key"),
1022
+ solverPubkey: xOnly(hex3.decode(quote.solver_pubkey), "solver key"),
1185
1023
  refundLocktime,
1186
1024
  serverPubkey: input.serverPubkey,
1187
1025
  paymentHash: input.paymentHash,
@@ -1196,7 +1034,7 @@ function deriveOnchainReceive(input) {
1196
1034
  const htlc = onchainHtlcScript(
1197
1035
  {
1198
1036
  paymentHash: input.paymentHash,
1199
- claimKey: xOnly(hex4.decode(claimPubkey), "solver L1 claim key"),
1037
+ claimKey: xOnly(hex3.decode(claimPubkey), "solver L1 claim key"),
1200
1038
  refundKey: input.refundPubkey,
1201
1039
  refundLocktime: htlcLocktime
1202
1040
  },
@@ -1213,17 +1051,17 @@ function deriveOnchainReceive(input) {
1213
1051
  minConfirmations
1214
1052
  };
1215
1053
  }
1216
- async function requestOnchainReceive(wallet, arkServerUrl, emulatorPubkey, transport, params) {
1054
+ async function requestOnchainReceive(wallet, arkServerUrl, transport, params) {
1217
1055
  const rfqId = params.rfqId ?? newRfqId();
1218
- const secrets = await deriveSwapSecrets(wallet) ?? randomSwapSecrets({ preimage: true });
1219
- if (!secrets.derivable) {
1056
+ const secrets = await provisionClaimSecret(wallet);
1057
+ if (secrets.mustPersistPreimage) {
1220
1058
  console.warn(
1221
- "[swap] this swap's preimage and payout key are random and MUST be persisted before funding"
1059
+ "[swap] this swap's preimage cannot be re-derived from the seed and MUST be persisted with the record before funding"
1222
1060
  );
1223
1061
  }
1224
- const preimage = await preimageForRfqSecrets(wallet, secrets);
1225
- const paymentHash = paymentHashOf(preimage);
1226
- const payoutPubkey = await senderPubkeyForRfqSecrets(wallet, secrets);
1062
+ const preimage = secrets.preimage;
1063
+ const paymentHash = hex3.encode(secrets.paymentHash);
1064
+ const payoutPubkey = secrets.pubkey;
1227
1065
  const [info, payoutAddress] = await Promise.all([
1228
1066
  new RestArkProvider(arkServerUrl).getInfo(),
1229
1067
  wallet.getAddress()
@@ -1245,16 +1083,20 @@ async function requestOnchainReceive(wallet, arkServerUrl, emulatorPubkey, trans
1245
1083
  })
1246
1084
  );
1247
1085
  assertQuotedAmount(quote, params.amountSide, params.amount);
1086
+ const network = getNetwork(info.network);
1248
1087
  const derived = deriveOnchainReceive({
1249
1088
  quote,
1250
1089
  paymentHash,
1251
1090
  payoutPubkey,
1252
1091
  payoutAddress,
1253
1092
  refundPubkey: params.refundPubkey,
1254
- serverPubkey: xOnly(hex4.decode(info.signerPubkey), "ark signer key"),
1255
- emulatorPubkey: xOnly(emulatorPubkey, "emulator pubkey"),
1093
+ serverPubkey: xOnly(hex3.decode(info.signerPubkey), "ark signer key"),
1094
+ emulatorPubkey: xOnly(
1095
+ hex3.decode(resolveEmulatorPubkey(network, params.emulatorPubkey)),
1096
+ "emulator signer key"
1097
+ ),
1256
1098
  claimDelay: unilateralClaimDelay(Number(info.unilateralExitDelay)),
1257
- hrp: getNetwork(info.network).hrp,
1099
+ hrp: network.hrp,
1258
1100
  l1Network: l1NetworkFromArk(info.network)
1259
1101
  });
1260
1102
  assertFundable({
@@ -1301,20 +1143,6 @@ export {
1301
1143
  awaitOnchainFill,
1302
1144
  claimOnchainFill,
1303
1145
  classifyOnchainHtlc,
1304
- RFQ_PREIMAGE_TAG,
1305
- buildPreimageMessage,
1306
- deriveSwapSecrets,
1307
- randomSwapSecrets,
1308
- rfqSecretsToRecord,
1309
- rfqSecretsOfRecord,
1310
- adoptSwapDescriptor,
1311
- RefundNotLocallyPossibleError,
1312
- senderIdentityForRfqSecrets,
1313
- senderIdentityForSwapRecord,
1314
- senderPubkeyForRfqSecrets,
1315
- isDeterministicSigner,
1316
- derivePreimage,
1317
- preimageForRfqSecrets,
1318
1146
  sealClaimPacket,
1319
1147
  SWAP_LOCKUP_CONTRACT_TYPE,
1320
1148
  SWAP_LOCKUP_CONTRACT_LABEL,