@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.
- package/README.md +115 -83
- package/dist/{chunk-C5P7R7JT.js → chunk-DLM6BVTB.js} +80 -252
- package/dist/index.cjs +163 -303
- package/dist/index.d.cts +207 -22
- package/dist/index.d.ts +207 -22
- package/dist/index.js +95 -76
- package/dist/nostr.cjs +10 -14
- package/dist/nostr.d.cts +1 -2
- package/dist/nostr.d.ts +1 -2
- package/dist/nostr.js +2 -2
- package/dist/{rfq-CRgIOQ_y.d.cts → rfq-DjZlesr4.d.cts} +32 -352
- package/dist/{rfq-CRgIOQ_y.d.ts → rfq-DjZlesr4.d.ts} +32 -352
- 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,13 +283,18 @@ 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,
|
|
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
|
|
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 = () =>
|
|
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:
|
|
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:
|
|
532
|
-
...input.wantAsset && { want_asset:
|
|
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(
|
|
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,
|
|
590
|
+
async function requestLightningSend(wallet, arkServerUrl, transport, params) {
|
|
751
591
|
const rfqId = params.rfqId ?? newRfqId();
|
|
752
|
-
const secrets = await
|
|
753
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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:
|
|
672
|
+
payout_pubkey: hex3.encode(input.payoutPubkey),
|
|
834
673
|
refund_address: input.refundAddress,
|
|
835
|
-
client_refund_pubkey:
|
|
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:
|
|
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:
|
|
701
|
+
refund_pubkey: hex3.encode(input.refundPubkey),
|
|
863
702
|
payout_address: input.payoutAddress,
|
|
864
|
-
payout_pubkey:
|
|
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(
|
|
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(
|
|
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,
|
|
751
|
+
async function requestOnchainSend(wallet, arkServerUrl, transport, params) {
|
|
913
752
|
const rfqId = params.rfqId ?? newRfqId();
|
|
914
|
-
|
|
915
|
-
|
|
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
|
|
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
|
|
929
|
-
const
|
|
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(
|
|
951
|
-
emulatorPubkey: xOnly(
|
|
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:
|
|
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(
|
|
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(
|
|
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,
|
|
936
|
+
async function requestLightningReceive(wallet, arkServerUrl, transport, params) {
|
|
1103
937
|
const rfqId = params.rfqId ?? newRfqId();
|
|
1104
|
-
const secrets = await
|
|
1105
|
-
if (
|
|
938
|
+
const secrets = await provisionClaimSecret(wallet);
|
|
939
|
+
if (secrets.mustPersistPreimage) {
|
|
1106
940
|
console.warn(
|
|
1107
|
-
"[swap] this swap's preimage
|
|
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 =
|
|
1111
|
-
const paymentHash =
|
|
1112
|
-
const payoutPubkey =
|
|
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(
|
|
1139
|
-
emulatorPubkey: xOnly(
|
|
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:
|
|
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(
|
|
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(
|
|
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,
|
|
1054
|
+
async function requestOnchainReceive(wallet, arkServerUrl, transport, params) {
|
|
1217
1055
|
const rfqId = params.rfqId ?? newRfqId();
|
|
1218
|
-
const secrets = await
|
|
1219
|
-
if (
|
|
1056
|
+
const secrets = await provisionClaimSecret(wallet);
|
|
1057
|
+
if (secrets.mustPersistPreimage) {
|
|
1220
1058
|
console.warn(
|
|
1221
|
-
"[swap] this swap's preimage
|
|
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 =
|
|
1225
|
-
const paymentHash =
|
|
1226
|
-
const payoutPubkey =
|
|
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(
|
|
1255
|
-
emulatorPubkey: xOnly(
|
|
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:
|
|
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,
|