@arkade-os/swap 0.0.3 → 0.0.5
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 +189 -54
- package/dist/{chunk-HLMMA3LJ.js → chunk-Q4FAYBXS.js} +60 -247
- package/dist/index.cjs +212 -301
- package/dist/index.d.cts +283 -10
- package/dist/index.d.ts +283 -10
- package/dist/index.js +150 -69
- package/dist/nostr.cjs +21 -14
- package/dist/nostr.d.cts +14 -3
- package/dist/nostr.d.ts +14 -3
- package/dist/nostr.js +10 -2
- package/dist/{rfq-CCAFoFtR.d.cts → rfq-BH2yvo3O.d.cts} +50 -335
- package/dist/{rfq-CCAFoFtR.d.ts → rfq-BH2yvo3O.d.ts} +50 -335
- package/package.json +2 -2
|
@@ -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
|
|
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(
|
|
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
|
|
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:
|
|
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,7 +283,7 @@ async function registerLockupContract(contracts, script, address) {
|
|
|
448
283
|
}
|
|
449
284
|
|
|
450
285
|
// src/rfq.ts
|
|
451
|
-
import { hex as
|
|
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,
|
|
@@ -457,6 +292,10 @@ import {
|
|
|
457
292
|
getNetwork,
|
|
458
293
|
resolveEmulatorPubkey
|
|
459
294
|
} from "@arkade-os/sdk";
|
|
295
|
+
import {
|
|
296
|
+
provisionClaimSecret,
|
|
297
|
+
provisionRefundKey
|
|
298
|
+
} from "@arkade-os/sdk";
|
|
460
299
|
var xOnly = (key, label) => {
|
|
461
300
|
if (key.length === 32) return key;
|
|
462
301
|
if (key.length !== 33 || key[0] !== 2 && key[0] !== 3) {
|
|
@@ -466,7 +305,7 @@ var xOnly = (key, label) => {
|
|
|
466
305
|
};
|
|
467
306
|
var solverHex = (value, field) => {
|
|
468
307
|
try {
|
|
469
|
-
return
|
|
308
|
+
return hex3.decode(value);
|
|
470
309
|
} catch {
|
|
471
310
|
throw new Error(`solver sent malformed hex for ${field}`);
|
|
472
311
|
}
|
|
@@ -501,7 +340,7 @@ var AddressMismatch = class extends Error {
|
|
|
501
340
|
this.quoted = quoted;
|
|
502
341
|
}
|
|
503
342
|
};
|
|
504
|
-
var newRfqId = () =>
|
|
343
|
+
var newRfqId = () => hex3.encode(crypto.getRandomValues(new Uint8Array(32)));
|
|
505
344
|
var lightningSendRequest = (input) => ({
|
|
506
345
|
v: 1,
|
|
507
346
|
type: "rfq_request",
|
|
@@ -511,7 +350,7 @@ var lightningSendRequest = (input) => ({
|
|
|
511
350
|
profile: {
|
|
512
351
|
invoice: input.invoice,
|
|
513
352
|
refund_address: input.refundAddress,
|
|
514
|
-
client_refund_pubkey:
|
|
353
|
+
client_refund_pubkey: hex3.encode(input.senderPubkey)
|
|
515
354
|
}
|
|
516
355
|
});
|
|
517
356
|
var arkadeSwapRequest = (input) => {
|
|
@@ -529,8 +368,8 @@ var arkadeSwapRequest = (input) => {
|
|
|
529
368
|
amount_side: input.amountSide,
|
|
530
369
|
amount: input.amount,
|
|
531
370
|
profile: {
|
|
532
|
-
...input.offerAsset && { offer_asset:
|
|
533
|
-
...input.wantAsset && { want_asset:
|
|
371
|
+
...input.offerAsset && { offer_asset: hex3.encode(input.offerAsset.serialize()) },
|
|
372
|
+
...input.wantAsset && { want_asset: hex3.encode(input.wantAsset.serialize()) }
|
|
534
373
|
}
|
|
535
374
|
};
|
|
536
375
|
};
|
|
@@ -707,21 +546,22 @@ var relayTransport = (relayUrl, options) => {
|
|
|
707
546
|
};
|
|
708
547
|
};
|
|
709
548
|
var SEQUENCE_GRANULARITY_SECONDS = 512;
|
|
549
|
+
var SOLO_REFUND_HEADROOM_SECONDS = 8 * SEQUENCE_GRANULARITY_SECONDS;
|
|
710
550
|
var unilateralClaimDelay = (serverExitDelaySeconds) => {
|
|
711
551
|
if (!Number.isFinite(serverExitDelaySeconds) || serverExitDelaySeconds < SEQUENCE_GRANULARITY_SECONDS) {
|
|
712
552
|
throw new Error(
|
|
713
553
|
`server exit delay must be at least ${SEQUENCE_GRANULARITY_SECONDS}s of seconds, got ${serverExitDelaySeconds}`
|
|
714
554
|
);
|
|
715
555
|
}
|
|
716
|
-
if (serverExitDelaySeconds >
|
|
556
|
+
if (serverExitDelaySeconds > 65535 * SEQUENCE_GRANULARITY_SECONDS - SOLO_REFUND_HEADROOM_SECONDS) {
|
|
717
557
|
throw new Error(
|
|
718
|
-
`server exit delay ${serverExitDelaySeconds}s exceeds what BIP68 can encode once the
|
|
558
|
+
`server exit delay ${serverExitDelaySeconds}s exceeds what BIP68 can encode once the solo refund's headroom is stacked above it`
|
|
719
559
|
);
|
|
720
560
|
}
|
|
721
561
|
return Math.ceil(serverExitDelaySeconds / SEQUENCE_GRANULARITY_SECONDS) * SEQUENCE_GRANULARITY_SECONDS;
|
|
722
562
|
};
|
|
723
|
-
var unilateralRefundDelay = (claimDelay) => claimDelay
|
|
724
|
-
var unilateralRefundWithoutReceiverDelay = (claimDelay) => claimDelay +
|
|
563
|
+
var unilateralRefundDelay = (claimDelay) => claimDelay;
|
|
564
|
+
var unilateralRefundWithoutReceiverDelay = (claimDelay) => claimDelay + SOLO_REFUND_HEADROOM_SECONDS;
|
|
725
565
|
function lightningSendVtxoScript(params) {
|
|
726
566
|
const seconds = (value) => ({
|
|
727
567
|
type: "seconds",
|
|
@@ -731,7 +571,7 @@ function lightningSendVtxoScript(params) {
|
|
|
731
571
|
sender: params.senderPubkey,
|
|
732
572
|
receiver: params.solverPubkey,
|
|
733
573
|
server: params.serverPubkey,
|
|
734
|
-
preimageHash: ripemd1602(
|
|
574
|
+
preimageHash: ripemd1602(hex3.decode(params.paymentHash)),
|
|
735
575
|
refundLocktime: BigInt(params.refundLocktime),
|
|
736
576
|
unilateralClaimDelay: seconds(params.claimDelay),
|
|
737
577
|
unilateralRefundDelay: seconds(unilateralRefundDelay(params.claimDelay)),
|
|
@@ -750,13 +590,8 @@ function lightningSendVtxoScript(params) {
|
|
|
750
590
|
}
|
|
751
591
|
async function requestLightningSend(wallet, arkServerUrl, transport, params) {
|
|
752
592
|
const rfqId = params.rfqId ?? newRfqId();
|
|
753
|
-
const secrets = await
|
|
754
|
-
|
|
755
|
-
console.warn(
|
|
756
|
-
"[swap] wallet cannot allocate an HD descriptor: the sender key is random and MUST be persisted before funding"
|
|
757
|
-
);
|
|
758
|
-
}
|
|
759
|
-
const senderPubkey = await senderPubkeyForRfqSecrets(wallet, secrets);
|
|
593
|
+
const secrets = await provisionRefundKey(wallet);
|
|
594
|
+
const senderPubkey = secrets.pubkey;
|
|
760
595
|
const [info, refundAddress] = await Promise.all([
|
|
761
596
|
new RestArkProvider(arkServerUrl).getInfo(),
|
|
762
597
|
wallet.getAddress()
|
|
@@ -781,16 +616,16 @@ async function requestLightningSend(wallet, arkServerUrl, transport, params) {
|
|
|
781
616
|
`quote from_amount ${quote.from_amount} is below the invoice amount \u2014 a negative spread is not a quote`
|
|
782
617
|
);
|
|
783
618
|
}
|
|
784
|
-
const serverPubkey = xOnly(
|
|
619
|
+
const serverPubkey = xOnly(hex3.decode(info.signerPubkey), "ark signer key");
|
|
785
620
|
const network = getNetwork(info.network);
|
|
786
621
|
const script = lightningSendVtxoScript({
|
|
787
|
-
solverPubkey: xOnly(
|
|
622
|
+
solverPubkey: xOnly(hex3.decode(quote.solver_pubkey), "solver key"),
|
|
788
623
|
refundLocktime: quote.refund_locktime,
|
|
789
624
|
serverPubkey,
|
|
790
625
|
paymentHash: params.invoice.paymentHash,
|
|
791
626
|
claimDelay: unilateralClaimDelay(Number(info.unilateralExitDelay)),
|
|
792
627
|
emulatorPubkey: xOnly(
|
|
793
|
-
|
|
628
|
+
hex3.decode(resolveEmulatorPubkey(network, params.emulatorPubkey)),
|
|
794
629
|
"emulator signer key"
|
|
795
630
|
),
|
|
796
631
|
senderPubkey,
|
|
@@ -835,9 +670,9 @@ var onchainSendRequest = (input) => ({
|
|
|
835
670
|
amount: input.amount,
|
|
836
671
|
profile: {
|
|
837
672
|
payment_hash: input.paymentHash,
|
|
838
|
-
payout_pubkey:
|
|
673
|
+
payout_pubkey: hex3.encode(input.payoutPubkey),
|
|
839
674
|
refund_address: input.refundAddress,
|
|
840
|
-
client_refund_pubkey:
|
|
675
|
+
client_refund_pubkey: hex3.encode(input.senderPubkey)
|
|
841
676
|
}
|
|
842
677
|
});
|
|
843
678
|
var lightningReceiveRequest = (input) => ({
|
|
@@ -850,7 +685,7 @@ var lightningReceiveRequest = (input) => ({
|
|
|
850
685
|
profile: {
|
|
851
686
|
payment_hash: input.paymentHash,
|
|
852
687
|
payout_address: input.payoutAddress,
|
|
853
|
-
payout_pubkey:
|
|
688
|
+
payout_pubkey: hex3.encode(input.payoutPubkey),
|
|
854
689
|
claim_packet: input.claimPacket
|
|
855
690
|
}
|
|
856
691
|
});
|
|
@@ -864,9 +699,9 @@ var onchainReceiveRequest = (input) => ({
|
|
|
864
699
|
profile: {
|
|
865
700
|
payment_hash: input.paymentHash,
|
|
866
701
|
claim_packet: input.claimPacket,
|
|
867
|
-
refund_pubkey:
|
|
702
|
+
refund_pubkey: hex3.encode(input.refundPubkey),
|
|
868
703
|
payout_address: input.payoutAddress,
|
|
869
|
-
payout_pubkey:
|
|
704
|
+
payout_pubkey: hex3.encode(input.payoutPubkey)
|
|
870
705
|
}
|
|
871
706
|
});
|
|
872
707
|
function deriveOnchainSend(input) {
|
|
@@ -882,7 +717,7 @@ function deriveOnchainSend(input) {
|
|
|
882
717
|
throw new Error("onchain-send quote is missing a binding field");
|
|
883
718
|
}
|
|
884
719
|
const script = lightningSendVtxoScript({
|
|
885
|
-
solverPubkey: xOnly(
|
|
720
|
+
solverPubkey: xOnly(hex3.decode(quote.solver_pubkey), "solver key"),
|
|
886
721
|
refundLocktime,
|
|
887
722
|
serverPubkey: input.serverPubkey,
|
|
888
723
|
paymentHash: input.paymentHash,
|
|
@@ -898,7 +733,7 @@ function deriveOnchainSend(input) {
|
|
|
898
733
|
{
|
|
899
734
|
paymentHash: input.paymentHash,
|
|
900
735
|
claimKey: input.payoutPubkey,
|
|
901
|
-
refundKey: xOnly(
|
|
736
|
+
refundKey: xOnly(hex3.decode(htlcPubkey), "solver L1 htlc key"),
|
|
902
737
|
refundLocktime: htlcLocktime
|
|
903
738
|
},
|
|
904
739
|
input.l1Network
|
|
@@ -916,23 +751,14 @@ function deriveOnchainSend(input) {
|
|
|
916
751
|
}
|
|
917
752
|
async function requestOnchainSend(wallet, arkServerUrl, transport, params) {
|
|
918
753
|
const rfqId = params.rfqId ?? newRfqId();
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
}
|
|
922
|
-
const derivedSecrets = await deriveSwapSecrets(wallet);
|
|
923
|
-
const secrets = derivedSecrets ? params.preimage ? { ...derivedSecrets, preimage: params.preimage } : derivedSecrets : randomSwapSecrets({ preimage: params.preimage ?? true });
|
|
924
|
-
if (!secrets.derivable) {
|
|
925
|
-
console.warn(
|
|
926
|
-
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"
|
|
927
|
-
);
|
|
928
|
-
} else if (params.preimage) {
|
|
754
|
+
const secrets = await provisionClaimSecret(wallet, { preimage: params.preimage });
|
|
755
|
+
if (secrets.mustPersistPreimage) {
|
|
929
756
|
console.warn(
|
|
930
|
-
"[swap] this swap's preimage
|
|
757
|
+
"[swap] this swap's preimage cannot be re-derived from the seed and MUST be persisted with the record before funding"
|
|
931
758
|
);
|
|
932
759
|
}
|
|
933
|
-
const
|
|
934
|
-
const
|
|
935
|
-
const senderPubkey = await senderPubkeyForRfqSecrets(wallet, secrets);
|
|
760
|
+
const paymentHash = hex3.encode(secrets.paymentHash);
|
|
761
|
+
const senderPubkey = secrets.pubkey;
|
|
936
762
|
const [info, refundAddress] = await Promise.all([
|
|
937
763
|
new RestArkProvider(arkServerUrl).getInfo(),
|
|
938
764
|
wallet.getAddress()
|
|
@@ -953,9 +779,9 @@ async function requestOnchainSend(wallet, arkServerUrl, transport, params) {
|
|
|
953
779
|
quote,
|
|
954
780
|
paymentHash,
|
|
955
781
|
payoutPubkey: params.payoutPubkey,
|
|
956
|
-
serverPubkey: xOnly(
|
|
782
|
+
serverPubkey: xOnly(hex3.decode(info.signerPubkey), "ark signer key"),
|
|
957
783
|
emulatorPubkey: xOnly(
|
|
958
|
-
|
|
784
|
+
hex3.decode(resolveEmulatorPubkey(network, params.emulatorPubkey)),
|
|
959
785
|
"emulator signer key"
|
|
960
786
|
),
|
|
961
787
|
claimDelay: unilateralClaimDelay(Number(info.unilateralExitDelay)),
|
|
@@ -1067,7 +893,7 @@ function receiveVtxoScript(params) {
|
|
|
1067
893
|
sender: params.solverPubkey,
|
|
1068
894
|
receiver: params.payoutPubkey,
|
|
1069
895
|
server: params.serverPubkey,
|
|
1070
|
-
preimageHash: ripemd1602(
|
|
896
|
+
preimageHash: ripemd1602(hex3.decode(params.paymentHash)),
|
|
1071
897
|
refundLocktime: BigInt(params.refundLocktime),
|
|
1072
898
|
unilateralClaimDelay: seconds(params.claimDelay),
|
|
1073
899
|
unilateralRefundDelay: seconds(unilateralRefundDelay(params.claimDelay)),
|
|
@@ -1094,7 +920,7 @@ function deriveLightningReceive(input) {
|
|
|
1094
920
|
throw new Error("lightning-receive quote is missing a binding field");
|
|
1095
921
|
}
|
|
1096
922
|
const script = receiveVtxoScript({
|
|
1097
|
-
solverPubkey: xOnly(
|
|
923
|
+
solverPubkey: xOnly(hex3.decode(quote.solver_pubkey), "solver key"),
|
|
1098
924
|
refundLocktime,
|
|
1099
925
|
serverPubkey: input.serverPubkey,
|
|
1100
926
|
paymentHash: input.paymentHash,
|
|
@@ -1110,15 +936,15 @@ function deriveLightningReceive(input) {
|
|
|
1110
936
|
}
|
|
1111
937
|
async function requestLightningReceive(wallet, arkServerUrl, transport, params) {
|
|
1112
938
|
const rfqId = params.rfqId ?? newRfqId();
|
|
1113
|
-
const secrets = await
|
|
1114
|
-
if (
|
|
939
|
+
const secrets = await provisionClaimSecret(wallet);
|
|
940
|
+
if (secrets.mustPersistPreimage) {
|
|
1115
941
|
console.warn(
|
|
1116
|
-
"[swap] this swap's preimage
|
|
942
|
+
"[swap] this swap's preimage cannot be re-derived from the seed and MUST be persisted with the record before paying"
|
|
1117
943
|
);
|
|
1118
944
|
}
|
|
1119
|
-
const preimage =
|
|
1120
|
-
const paymentHash =
|
|
1121
|
-
const payoutPubkey =
|
|
945
|
+
const preimage = secrets.preimage;
|
|
946
|
+
const paymentHash = hex3.encode(secrets.paymentHash);
|
|
947
|
+
const payoutPubkey = secrets.pubkey;
|
|
1122
948
|
const [info, payoutAddress] = await Promise.all([
|
|
1123
949
|
new RestArkProvider(arkServerUrl).getInfo(),
|
|
1124
950
|
wallet.getAddress()
|
|
@@ -1145,9 +971,9 @@ async function requestLightningReceive(wallet, arkServerUrl, transport, params)
|
|
|
1145
971
|
paymentHash,
|
|
1146
972
|
payoutPubkey,
|
|
1147
973
|
payoutAddress,
|
|
1148
|
-
serverPubkey: xOnly(
|
|
974
|
+
serverPubkey: xOnly(hex3.decode(info.signerPubkey), "ark signer key"),
|
|
1149
975
|
emulatorPubkey: xOnly(
|
|
1150
|
-
|
|
976
|
+
hex3.decode(resolveEmulatorPubkey(network, params.emulatorPubkey)),
|
|
1151
977
|
"emulator signer key"
|
|
1152
978
|
),
|
|
1153
979
|
claimDelay: unilateralClaimDelay(Number(info.unilateralExitDelay)),
|
|
@@ -1194,7 +1020,7 @@ function deriveOnchainReceive(input) {
|
|
|
1194
1020
|
throw new Error("onchain-receive quote is missing a binding field");
|
|
1195
1021
|
}
|
|
1196
1022
|
const script = receiveVtxoScript({
|
|
1197
|
-
solverPubkey: xOnly(
|
|
1023
|
+
solverPubkey: xOnly(hex3.decode(quote.solver_pubkey), "solver key"),
|
|
1198
1024
|
refundLocktime,
|
|
1199
1025
|
serverPubkey: input.serverPubkey,
|
|
1200
1026
|
paymentHash: input.paymentHash,
|
|
@@ -1209,7 +1035,7 @@ function deriveOnchainReceive(input) {
|
|
|
1209
1035
|
const htlc = onchainHtlcScript(
|
|
1210
1036
|
{
|
|
1211
1037
|
paymentHash: input.paymentHash,
|
|
1212
|
-
claimKey: xOnly(
|
|
1038
|
+
claimKey: xOnly(hex3.decode(claimPubkey), "solver L1 claim key"),
|
|
1213
1039
|
refundKey: input.refundPubkey,
|
|
1214
1040
|
refundLocktime: htlcLocktime
|
|
1215
1041
|
},
|
|
@@ -1228,15 +1054,15 @@ function deriveOnchainReceive(input) {
|
|
|
1228
1054
|
}
|
|
1229
1055
|
async function requestOnchainReceive(wallet, arkServerUrl, transport, params) {
|
|
1230
1056
|
const rfqId = params.rfqId ?? newRfqId();
|
|
1231
|
-
const secrets = await
|
|
1232
|
-
if (
|
|
1057
|
+
const secrets = await provisionClaimSecret(wallet);
|
|
1058
|
+
if (secrets.mustPersistPreimage) {
|
|
1233
1059
|
console.warn(
|
|
1234
|
-
"[swap] this swap's preimage
|
|
1060
|
+
"[swap] this swap's preimage cannot be re-derived from the seed and MUST be persisted with the record before funding"
|
|
1235
1061
|
);
|
|
1236
1062
|
}
|
|
1237
|
-
const preimage =
|
|
1238
|
-
const paymentHash =
|
|
1239
|
-
const payoutPubkey =
|
|
1063
|
+
const preimage = secrets.preimage;
|
|
1064
|
+
const paymentHash = hex3.encode(secrets.paymentHash);
|
|
1065
|
+
const payoutPubkey = secrets.pubkey;
|
|
1240
1066
|
const [info, payoutAddress] = await Promise.all([
|
|
1241
1067
|
new RestArkProvider(arkServerUrl).getInfo(),
|
|
1242
1068
|
wallet.getAddress()
|
|
@@ -1265,9 +1091,9 @@ async function requestOnchainReceive(wallet, arkServerUrl, transport, params) {
|
|
|
1265
1091
|
payoutPubkey,
|
|
1266
1092
|
payoutAddress,
|
|
1267
1093
|
refundPubkey: params.refundPubkey,
|
|
1268
|
-
serverPubkey: xOnly(
|
|
1094
|
+
serverPubkey: xOnly(hex3.decode(info.signerPubkey), "ark signer key"),
|
|
1269
1095
|
emulatorPubkey: xOnly(
|
|
1270
|
-
|
|
1096
|
+
hex3.decode(resolveEmulatorPubkey(network, params.emulatorPubkey)),
|
|
1271
1097
|
"emulator signer key"
|
|
1272
1098
|
),
|
|
1273
1099
|
claimDelay: unilateralClaimDelay(Number(info.unilateralExitDelay)),
|
|
@@ -1318,20 +1144,6 @@ export {
|
|
|
1318
1144
|
awaitOnchainFill,
|
|
1319
1145
|
claimOnchainFill,
|
|
1320
1146
|
classifyOnchainHtlc,
|
|
1321
|
-
RFQ_PREIMAGE_TAG,
|
|
1322
|
-
buildPreimageMessage,
|
|
1323
|
-
deriveSwapSecrets,
|
|
1324
|
-
randomSwapSecrets,
|
|
1325
|
-
rfqSecretsToRecord,
|
|
1326
|
-
rfqSecretsOfRecord,
|
|
1327
|
-
adoptSwapDescriptor,
|
|
1328
|
-
RefundNotLocallyPossibleError,
|
|
1329
|
-
senderIdentityForRfqSecrets,
|
|
1330
|
-
senderIdentityForSwapRecord,
|
|
1331
|
-
senderPubkeyForRfqSecrets,
|
|
1332
|
-
isDeterministicSigner,
|
|
1333
|
-
derivePreimage,
|
|
1334
|
-
preimageForRfqSecrets,
|
|
1335
1147
|
sealClaimPacket,
|
|
1336
1148
|
SWAP_LOCKUP_CONTRACT_TYPE,
|
|
1337
1149
|
SWAP_LOCKUP_CONTRACT_LABEL,
|
|
@@ -1358,6 +1170,7 @@ export {
|
|
|
1358
1170
|
assertFundable,
|
|
1359
1171
|
httpTransport,
|
|
1360
1172
|
relayTransport,
|
|
1173
|
+
SOLO_REFUND_HEADROOM_SECONDS,
|
|
1361
1174
|
unilateralClaimDelay,
|
|
1362
1175
|
unilateralRefundDelay,
|
|
1363
1176
|
unilateralRefundWithoutReceiverDelay,
|