@atomiqlabs/sdk 8.3.6 → 8.4.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/dist/bitcoin/wallet/BitcoinWallet.d.ts +3 -2
- package/dist/bitcoin/wallet/BitcoinWallet.js +15 -1
- package/dist/bitcoin/wallet/SingleAddressBitcoinWallet.d.ts +25 -3
- package/dist/bitcoin/wallet/SingleAddressBitcoinWallet.js +51 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/intermediaries/apis/IntermediaryAPI.d.ts +2 -0
- package/dist/intermediaries/apis/IntermediaryAPI.js +2 -0
- package/dist/swapper/Swapper.d.ts +2 -1
- package/dist/swapper/Swapper.js +4 -3
- package/dist/swaps/ISwap.d.ts +34 -0
- package/dist/swaps/ISwap.js +10 -0
- package/dist/swaps/escrow_swaps/IEscrowSwap.d.ts +12 -0
- package/dist/swaps/escrow_swaps/IEscrowSwap.js +18 -0
- package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.d.ts +54 -4
- package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.js +72 -8
- package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.d.ts +4 -1
- package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.js +23 -4
- package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.d.ts +89 -3
- package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.js +118 -5
- package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.d.ts +2 -0
- package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.js +30 -4
- package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.d.ts +48 -3
- package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.js +69 -4
- package/dist/swaps/escrow_swaps/tobtc/IToBTCSwap.d.ts +40 -2
- package/dist/swaps/escrow_swaps/tobtc/IToBTCSwap.js +72 -2
- package/dist/swaps/spv_swaps/SpvFromBTCSwap.d.ts +51 -1
- package/dist/swaps/spv_swaps/SpvFromBTCSwap.js +71 -3
- package/dist/swaps/trusted/ln/LnForGasSwap.d.ts +28 -2
- package/dist/swaps/trusted/ln/LnForGasSwap.js +39 -1
- package/dist/swaps/trusted/onchain/OnchainForGasSwap.d.ts +28 -3
- package/dist/swaps/trusted/onchain/OnchainForGasSwap.js +44 -1
- package/dist/types/SwapStateInfo.d.ts +5 -0
- package/dist/types/SwapStateInfo.js +2 -0
- package/dist/types/lnurl/LNURLPay.d.ts +0 -1
- package/dist/types/lnurl/LNURLPay.js +0 -1
- package/dist/types/lnurl/LNURLWithdraw.d.ts +0 -1
- package/dist/types/lnurl/LNURLWithdraw.js +0 -1
- package/package.json +3 -1
- package/src/bitcoin/wallet/BitcoinWallet.ts +21 -4
- package/src/bitcoin/wallet/SingleAddressBitcoinWallet.ts +60 -5
- package/src/index.ts +1 -0
- package/src/intermediaries/apis/IntermediaryAPI.ts +5 -1
- package/src/swapper/Swapper.ts +5 -2
- package/src/swaps/ISwap.ts +45 -0
- package/src/swaps/escrow_swaps/IEscrowSwap.ts +20 -0
- package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNSwap.ts +86 -11
- package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.ts +28 -3
- package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.ts +137 -9
- package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.ts +35 -4
- package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCSwap.ts +83 -6
- package/src/swaps/escrow_swaps/tobtc/IToBTCSwap.ts +77 -4
- package/src/swaps/spv_swaps/SpvFromBTCSwap.ts +90 -4
- package/src/swaps/trusted/ln/LnForGasSwap.ts +51 -3
- package/src/swaps/trusted/onchain/OnchainForGasSwap.ts +58 -3
- package/src/types/SwapStateInfo.ts +6 -0
- package/src/types/lnurl/LNURLPay.ts +0 -1
- package/src/types/lnurl/LNURLWithdraw.ts +0 -1
|
@@ -40,22 +40,67 @@ import {
|
|
|
40
40
|
serializePriceInfoType
|
|
41
41
|
} from "../../../../types/PriceInfoType";
|
|
42
42
|
import {sha256} from "@noble/hashes/sha2";
|
|
43
|
+
import {SwapExecutionAction} from "../../../../types/SwapExecutionAction";
|
|
43
44
|
|
|
44
45
|
/**
|
|
45
46
|
* State enum for FromBTCLNAuto swaps
|
|
46
47
|
* @category Swaps/Lightning → Smart chain
|
|
47
48
|
*/
|
|
48
49
|
export enum FromBTCLNAutoSwapState {
|
|
50
|
+
/**
|
|
51
|
+
* Swap has failed as the user didn't settle the HTLC on the destination before expiration
|
|
52
|
+
*/
|
|
49
53
|
FAILED = -4,
|
|
54
|
+
/**
|
|
55
|
+
* Swap has expired for good and there is no way how it can be executed anymore
|
|
56
|
+
*/
|
|
50
57
|
QUOTE_EXPIRED = -3,
|
|
58
|
+
/**
|
|
59
|
+
* A swap is almost expired, and it should be presented to the user as expired, though
|
|
60
|
+
* there is still a chance that it will be processed
|
|
61
|
+
*/
|
|
51
62
|
QUOTE_SOFT_EXPIRED = -2,
|
|
63
|
+
/**
|
|
64
|
+
* Swap HTLC on the destination chain has expired, it is not safe anymore to settle (claim) the
|
|
65
|
+
* swap on the destination smart chain.
|
|
66
|
+
*/
|
|
52
67
|
EXPIRED = -1,
|
|
68
|
+
/**
|
|
69
|
+
* Swap quote was created, use {@link FromBTCLNAutoSwap.getAddress} or {@link FromBTCLNAutoSwap.getHyperlink}
|
|
70
|
+
* to get the bolt11 lightning network invoice to pay to initiate the swap, then use the
|
|
71
|
+
* {@link FromBTCLNAutoSwap.waitForPayment} to wait till the lightning network payment is received
|
|
72
|
+
* by the intermediary (LP) and the destination HTLC escrow is created
|
|
73
|
+
*/
|
|
53
74
|
PR_CREATED = 0,
|
|
75
|
+
/**
|
|
76
|
+
* Lightning network payment has been received by the intermediary (LP), but the destination chain
|
|
77
|
+
* HTLC escrow hasn't been created yet. Use {@link FromBTCLNAutoSwap.waitForPayment} to continue waiting
|
|
78
|
+
* till the destination HTLC escrow is created.
|
|
79
|
+
*/
|
|
54
80
|
PR_PAID = 1,
|
|
81
|
+
/**
|
|
82
|
+
* Swap escrow HTLC has been created on the destination chain, wait for automatic settlement by the watchtowers
|
|
83
|
+
* using the {@link FromBTCLNAutoSwap.waitTillClaimed} function or settle manually using the
|
|
84
|
+
* {@link FromBTCLNAutoSwap.claim} or {@link FromBTCLNAutoSwap.txsClaim} function.
|
|
85
|
+
*/
|
|
55
86
|
CLAIM_COMMITED = 2,
|
|
87
|
+
/**
|
|
88
|
+
* Swap successfully settled and funds received on the destination chain
|
|
89
|
+
*/
|
|
56
90
|
CLAIM_CLAIMED = 3
|
|
57
91
|
}
|
|
58
92
|
|
|
93
|
+
const FromBTCLNAutoSwapStateDescription = {
|
|
94
|
+
[FromBTCLNAutoSwapState.FAILED]: "Swap has failed as the user didn't settle the HTLC on the destination before expiration",
|
|
95
|
+
[FromBTCLNAutoSwapState.QUOTE_EXPIRED]: "Swap has expired for good and there is no way how it can be executed anymore",
|
|
96
|
+
[FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED]: "A swap is expired, though there is still a chance that it will be processed",
|
|
97
|
+
[FromBTCLNAutoSwapState.EXPIRED]: "Swap HTLC on the destination chain has expired, it is not safe anymore to settle (claim) the swap on the destination smart chain.",
|
|
98
|
+
[FromBTCLNAutoSwapState.PR_CREATED]: "Swap quote was created, pay the bolt11 lightning network invoice to initiate the swap, then wait till the lightning network payment is received by the intermediary (LP) and the destination HTLC escrow is created",
|
|
99
|
+
[FromBTCLNAutoSwapState.PR_PAID]: "Lightning network payment has been received by the intermediary (LP), but the destination chain HTLC escrow hasn't been created yet. Continue waiting till the destination HTLC escrow is created.",
|
|
100
|
+
[FromBTCLNAutoSwapState.CLAIM_COMMITED]: "Swap escrow HTLC has been created on the destination chain, wait for automatic settlement by the watchtowers or settle manually.",
|
|
101
|
+
[FromBTCLNAutoSwapState.CLAIM_CLAIMED]: "Swap successfully settled and funds received on the destination chain"
|
|
102
|
+
};
|
|
103
|
+
|
|
59
104
|
export type FromBTCLNAutoSwapInit<T extends SwapData> = IEscrowSwapInit<T> & {
|
|
60
105
|
pr?: string,
|
|
61
106
|
secret?: string,
|
|
@@ -100,6 +145,14 @@ export class FromBTCLNAutoSwap<T extends ChainType = ChainType>
|
|
|
100
145
|
implements IAddressSwap, ISwapWithGasDrop<T>, IClaimableSwap<T, FromBTCLNAutoDefinition<T>, FromBTCLNAutoSwapState> {
|
|
101
146
|
|
|
102
147
|
protected readonly TYPE: SwapType.FROM_BTCLN_AUTO = SwapType.FROM_BTCLN_AUTO;
|
|
148
|
+
/**
|
|
149
|
+
* @internal
|
|
150
|
+
*/
|
|
151
|
+
protected readonly swapStateName = (state: number) => FromBTCLNAutoSwapState[state];
|
|
152
|
+
/**
|
|
153
|
+
* @internal
|
|
154
|
+
*/
|
|
155
|
+
protected readonly swapStateDescription = FromBTCLNAutoSwapStateDescription;
|
|
103
156
|
/**
|
|
104
157
|
* @internal
|
|
105
158
|
*/
|
|
@@ -109,6 +162,12 @@ export class FromBTCLNAutoSwap<T extends ChainType = ChainType>
|
|
|
109
162
|
*/
|
|
110
163
|
protected readonly inputToken: BtcToken<true> = BitcoinTokens.BTCLN;
|
|
111
164
|
|
|
165
|
+
/**
|
|
166
|
+
* Timestamp at which the HTLC was commited on the smart chain side
|
|
167
|
+
* @internal
|
|
168
|
+
*/
|
|
169
|
+
_commitedAt?: number;
|
|
170
|
+
|
|
112
171
|
private readonly lnurlFailSignal: AbortController = new AbortController();
|
|
113
172
|
private readonly usesClaimHashAsId: boolean;
|
|
114
173
|
private readonly initialSwapData: T["Data"];
|
|
@@ -135,7 +194,7 @@ export class FromBTCLNAutoSwap<T extends ChainType = ChainType>
|
|
|
135
194
|
private lnurlCallback?: string;
|
|
136
195
|
private prPosted?: boolean = false;
|
|
137
196
|
|
|
138
|
-
private broadcastTickCounter: number = 0
|
|
197
|
+
private broadcastTickCounter: number = 0
|
|
139
198
|
|
|
140
199
|
/**
|
|
141
200
|
* Sets the LNURL data for the swap
|
|
@@ -188,6 +247,7 @@ export class FromBTCLNAutoSwap<T extends ChainType = ChainType>
|
|
|
188
247
|
|
|
189
248
|
this._commitTxId = initOrObject.commitTxId;
|
|
190
249
|
this._claimTxId = initOrObject.claimTxId;
|
|
250
|
+
this._commitedAt = initOrObject.commitedAt;
|
|
191
251
|
|
|
192
252
|
this.lnurl = initOrObject.lnurl;
|
|
193
253
|
this.lnurlK1 = initOrObject.lnurlK1;
|
|
@@ -410,6 +470,16 @@ export class FromBTCLNAutoSwap<T extends ChainType = ChainType>
|
|
|
410
470
|
return this._state===FromBTCLNAutoSwapState.FAILED || this._state===FromBTCLNAutoSwapState.EXPIRED;
|
|
411
471
|
}
|
|
412
472
|
|
|
473
|
+
/**
|
|
474
|
+
* @inheritDoc
|
|
475
|
+
*/
|
|
476
|
+
isInProgress(): boolean {
|
|
477
|
+
return (this._state===FromBTCLNAutoSwapState.PR_CREATED && this.initiated) ||
|
|
478
|
+
(this._state===FromBTCLNAutoSwapState.QUOTE_SOFT_EXPIRED && this.initiated) ||
|
|
479
|
+
this._state===FromBTCLNAutoSwapState.PR_PAID ||
|
|
480
|
+
this._state===FromBTCLNAutoSwapState.CLAIM_COMMITED;
|
|
481
|
+
}
|
|
482
|
+
|
|
413
483
|
/**
|
|
414
484
|
* @inheritDoc
|
|
415
485
|
*/
|
|
@@ -662,6 +732,25 @@ export class FromBTCLNAutoSwap<T extends ChainType = ChainType>
|
|
|
662
732
|
return this.getSwapData().getClaimHash()===claimHash;
|
|
663
733
|
}
|
|
664
734
|
|
|
735
|
+
/**
|
|
736
|
+
* Sets the secret preimage for the swap, in case it is not known already
|
|
737
|
+
*
|
|
738
|
+
* @param secret Secret preimage that matches the expected payment hash
|
|
739
|
+
*
|
|
740
|
+
* @throws {Error} If an invalid secret preimage is provided
|
|
741
|
+
*/
|
|
742
|
+
setSecretPreimage(secret: string) {
|
|
743
|
+
if(!this.isValidSecretPreimage(secret)) throw new Error("Invalid secret preimage provided, hash doesn't match!");
|
|
744
|
+
this.secret = secret;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
/**
|
|
748
|
+
* Returns whether the secret preimage for this swap is known
|
|
749
|
+
*/
|
|
750
|
+
hasSecretPreimage(): boolean {
|
|
751
|
+
return this.secret != null;
|
|
752
|
+
}
|
|
753
|
+
|
|
665
754
|
|
|
666
755
|
//////////////////////////////
|
|
667
756
|
//// Execution
|
|
@@ -672,8 +761,8 @@ export class FromBTCLNAutoSwap<T extends ChainType = ChainType>
|
|
|
672
761
|
* @param walletOrLnurlWithdraw Bitcoin lightning wallet to use to pay the lightning network invoice, or an LNURL-withdraw
|
|
673
762
|
* link, wallet is not required and the LN invoice can be paid externally as well (just pass null or undefined here)
|
|
674
763
|
* @param callbacks Callbacks to track the progress of the swap
|
|
675
|
-
* @param options Optional options for the swap like
|
|
676
|
-
* @param secret A swap secret to broadcast to watchtowers, generally only needed if the swap
|
|
764
|
+
* @param options Optional options for the swap like AbortSignal, and timeouts/intervals
|
|
765
|
+
* @param options.secret A swap secret to broadcast to watchtowers, generally only needed if the swap
|
|
677
766
|
* was recovered from on-chain data, or the pre-image was generated outside the SDK
|
|
678
767
|
*
|
|
679
768
|
* @returns {boolean} Whether a swap was settled automatically by swap watchtowers or requires manual claim by the
|
|
@@ -688,9 +777,9 @@ export class FromBTCLNAutoSwap<T extends ChainType = ChainType>
|
|
|
688
777
|
options?: {
|
|
689
778
|
abortSignal?: AbortSignal,
|
|
690
779
|
lightningTxCheckIntervalSeconds?: number,
|
|
691
|
-
maxWaitTillAutomaticSettlementSeconds?: number
|
|
692
|
-
|
|
693
|
-
|
|
780
|
+
maxWaitTillAutomaticSettlementSeconds?: number,
|
|
781
|
+
secret?: string
|
|
782
|
+
}
|
|
694
783
|
): Promise<boolean> {
|
|
695
784
|
if(this._state===FromBTCLNAutoSwapState.FAILED) throw new Error("Swap failed!");
|
|
696
785
|
if(this._state===FromBTCLNAutoSwapState.EXPIRED) throw new Error("Swap HTLC expired!");
|
|
@@ -725,9 +814,9 @@ export class FromBTCLNAutoSwap<T extends ChainType = ChainType>
|
|
|
725
814
|
if((this._state as FromBTCLNAutoSwapState)===FromBTCLNAutoSwapState.CLAIM_CLAIMED) return true;
|
|
726
815
|
|
|
727
816
|
if(this._state===FromBTCLNAutoSwapState.CLAIM_COMMITED) {
|
|
728
|
-
if(this.secret==null && secret==null)
|
|
817
|
+
if(this.secret==null && options?.secret==null)
|
|
729
818
|
throw new Error("Tried to wait till settlement, but no secret pre-image is known, please pass the secret pre-image as an argument!");
|
|
730
|
-
const success = await this.waitTillClaimed(options?.maxWaitTillAutomaticSettlementSeconds ?? 60, options?.abortSignal, secret);
|
|
819
|
+
const success = await this.waitTillClaimed(options?.maxWaitTillAutomaticSettlementSeconds ?? 60, options?.abortSignal, options?.secret);
|
|
731
820
|
if (success && callbacks?.onSwapSettled != null) callbacks.onSwapSettled(this.getOutputTxId()!);
|
|
732
821
|
return success;
|
|
733
822
|
}
|
|
@@ -760,6 +849,42 @@ export class FromBTCLNAutoSwap<T extends ChainType = ChainType>
|
|
|
760
849
|
throw new Error("Invalid swap state to obtain execution txns, required PR_CREATED");
|
|
761
850
|
}
|
|
762
851
|
|
|
852
|
+
/**
|
|
853
|
+
*
|
|
854
|
+
* @param options.manualSettlementSmartChainSigner Optional smart chain signer to create a manual claim (settlement) transaction
|
|
855
|
+
* @param options.maxWaitTillAutomaticSettlementSeconds Maximum time to wait for an automatic settlement after
|
|
856
|
+
* the bitcoin transaction is confirmed (defaults to 60 seconds)
|
|
857
|
+
* @param options.secret A swap secret to broadcast to watchtowers, generally only needed if the swap
|
|
858
|
+
* was recovered from on-chain data, or the pre-image was generated outside the SDK
|
|
859
|
+
*/
|
|
860
|
+
async getCurrentActions(options?: {
|
|
861
|
+
manualSettlementSmartChainSigner?: string | T["Signer"] | T["NativeSigner"],
|
|
862
|
+
maxWaitTillAutomaticSettlementSeconds?: number,
|
|
863
|
+
secret?: string
|
|
864
|
+
}): Promise<SwapExecutionAction<T>[]> {
|
|
865
|
+
if(options?.secret!=null) this.setSecretPreimage(options.secret);
|
|
866
|
+
if (this._state === FromBTCLNAutoSwapState.PR_CREATED) {
|
|
867
|
+
try {
|
|
868
|
+
return await this.txsExecute();
|
|
869
|
+
} catch (e) {}
|
|
870
|
+
}
|
|
871
|
+
if(this.isClaimable()) {
|
|
872
|
+
if(
|
|
873
|
+
this._commitedAt==null ||
|
|
874
|
+
options?.maxWaitTillAutomaticSettlementSeconds===0 ||
|
|
875
|
+
(Date.now() - this._commitedAt) > (options?.maxWaitTillAutomaticSettlementSeconds ?? 60)*1000
|
|
876
|
+
) {
|
|
877
|
+
return [{
|
|
878
|
+
name: "Claim" as const,
|
|
879
|
+
description: "Manually settle (claim) the swap on the destination smart chain",
|
|
880
|
+
chain: this.chainIdentifier,
|
|
881
|
+
txs: await this.txsClaim(options?.manualSettlementSmartChainSigner)
|
|
882
|
+
}];
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
return [];
|
|
886
|
+
}
|
|
887
|
+
|
|
763
888
|
|
|
764
889
|
//////////////////////////////
|
|
765
890
|
//// Payment
|
|
@@ -993,6 +1118,7 @@ export class FromBTCLNAutoSwap<T extends ChainType = ChainType>
|
|
|
993
1118
|
if(
|
|
994
1119
|
this._state===FromBTCLNAutoSwapState.PR_PAID
|
|
995
1120
|
) {
|
|
1121
|
+
this._commitedAt ??= Date.now();
|
|
996
1122
|
await this._saveAndEmit(FromBTCLNAutoSwapState.CLAIM_COMMITED);
|
|
997
1123
|
}
|
|
998
1124
|
|
|
@@ -1207,6 +1333,7 @@ export class FromBTCLNAutoSwap<T extends ChainType = ChainType>
|
|
|
1207
1333
|
data: this._data==null ? null : this._data.serialize(),
|
|
1208
1334
|
commitTxId: this._commitTxId,
|
|
1209
1335
|
claimTxId: this._claimTxId,
|
|
1336
|
+
commitedAt: this._commitedAt,
|
|
1210
1337
|
btcAmountSwap: this.btcAmountSwap==null ? null : this.btcAmountSwap.toString(10),
|
|
1211
1338
|
btcAmountGas: this.btcAmountGas==null ? null : this.btcAmountGas.toString(10),
|
|
1212
1339
|
gasSwapFeeBtc: this.gasSwapFeeBtc==null ? null : this.gasSwapFeeBtc.toString(10),
|
|
@@ -1355,6 +1482,7 @@ export class FromBTCLNAutoSwap<T extends ChainType = ChainType>
|
|
|
1355
1482
|
return true;
|
|
1356
1483
|
case SwapCommitStateType.COMMITED:
|
|
1357
1484
|
if(this._state!==FromBTCLNAutoSwapState.CLAIM_COMMITED && this._state!==FromBTCLNAutoSwapState.EXPIRED) {
|
|
1485
|
+
this._commitedAt ??= Date.now();
|
|
1358
1486
|
this._state = FromBTCLNAutoSwapState.CLAIM_COMMITED;
|
|
1359
1487
|
return true;
|
|
1360
1488
|
}
|
|
@@ -1440,4 +1568,4 @@ export class FromBTCLNAutoSwap<T extends ChainType = ChainType>
|
|
|
1440
1568
|
}
|
|
1441
1569
|
}
|
|
1442
1570
|
|
|
1443
|
-
}
|
|
1571
|
+
}
|
|
@@ -37,6 +37,8 @@ import {AllOptional} from "../../../../utils/TypeUtils";
|
|
|
37
37
|
import {sha256} from "@noble/hashes/sha2";
|
|
38
38
|
|
|
39
39
|
export type FromBTCLNAutoOptions = {
|
|
40
|
+
paymentHash?: Buffer,
|
|
41
|
+
description?: string,
|
|
40
42
|
descriptionHash?: Buffer,
|
|
41
43
|
unsafeSkipLnNodeCheck?: boolean,
|
|
42
44
|
gasAmount?: bigint,
|
|
@@ -167,6 +169,7 @@ export class FromBTCLNAutoWrapper<
|
|
|
167
169
|
}
|
|
168
170
|
|
|
169
171
|
swap._commitTxId = event.meta?.txId;
|
|
172
|
+
swap._commitedAt ??= Date.now();
|
|
170
173
|
swap._state = FromBTCLNAutoSwapState.CLAIM_COMMITED;
|
|
171
174
|
swap._broadcastSecret().catch(e => {
|
|
172
175
|
this.logger.error("processEventInitialize("+swap.getId()+"): Error when broadcasting swap secret: ", e);
|
|
@@ -257,7 +260,7 @@ export class FromBTCLNAutoWrapper<
|
|
|
257
260
|
resp: FromBTCLNAutoResponseType,
|
|
258
261
|
amountData: AmountData,
|
|
259
262
|
lp: Intermediary,
|
|
260
|
-
options: {gasAmount: bigint, descriptionHash?: Buffer},
|
|
263
|
+
options: {gasAmount: bigint, description?: string, descriptionHash?: Buffer},
|
|
261
264
|
decodedPr: PaymentRequestObject & {tagsObject: TagsObject},
|
|
262
265
|
paymentHash: Buffer,
|
|
263
266
|
claimerBounty: bigint
|
|
@@ -267,6 +270,9 @@ export class FromBTCLNAutoWrapper<
|
|
|
267
270
|
if(options.descriptionHash!=null && decodedPr.tagsObject.purpose_commit_hash!==options.descriptionHash.toString("hex"))
|
|
268
271
|
throw new IntermediaryError("Invalid pr returned - description hash");
|
|
269
272
|
|
|
273
|
+
if(options.description!=null && decodedPr.tagsObject.description!==options.description)
|
|
274
|
+
throw new IntermediaryError("Invalid pr returned - description");
|
|
275
|
+
|
|
270
276
|
if(
|
|
271
277
|
decodedPr.tagsObject.payment_hash==null ||
|
|
272
278
|
!Buffer.from(decodedPr.tagsObject.payment_hash, "hex").equals(paymentHash)
|
|
@@ -317,20 +323,36 @@ export class FromBTCLNAutoWrapper<
|
|
|
317
323
|
quote: Promise<FromBTCLNAutoSwap<T>>,
|
|
318
324
|
intermediary: Intermediary
|
|
319
325
|
}[] {
|
|
326
|
+
if(!this.isInitialized) throw new Error("Not initialized, call init() first!");
|
|
327
|
+
|
|
320
328
|
const _options = {
|
|
329
|
+
paymentHash: options?.paymentHash,
|
|
321
330
|
unsafeSkipLnNodeCheck: options?.unsafeSkipLnNodeCheck ?? this._options.unsafeSkipLnNodeCheck,
|
|
322
331
|
gasAmount: options?.gasAmount ?? 0n,
|
|
323
332
|
feeSafetyFactor: options?.feeSafetyFactor ?? 1.25, //No need to add much of a margin, since the claim should happen rather soon
|
|
324
333
|
unsafeZeroWatchtowerFee: options?.unsafeZeroWatchtowerFee ?? false,
|
|
334
|
+
description: options?.description,
|
|
325
335
|
descriptionHash: options?.descriptionHash
|
|
326
336
|
};
|
|
327
337
|
|
|
328
|
-
if(
|
|
338
|
+
if(_options.paymentHash!=null && _options.paymentHash.length!==32)
|
|
339
|
+
throw new UserError("Invalid payment hash length, must be exactly 32 bytes!");
|
|
329
340
|
|
|
330
341
|
if(_options.descriptionHash!=null && _options.descriptionHash.length!==32)
|
|
331
342
|
throw new UserError("Invalid description hash length");
|
|
332
343
|
|
|
333
|
-
|
|
344
|
+
if(_options.description!=null && Buffer.byteLength(_options.description, "utf8") > 500)
|
|
345
|
+
throw new UserError("Invalid description length");
|
|
346
|
+
|
|
347
|
+
if(preFetches==null) preFetches = {};
|
|
348
|
+
|
|
349
|
+
let secret: Buffer | undefined;
|
|
350
|
+
let paymentHash: Buffer;
|
|
351
|
+
if(_options?.paymentHash!=null) {
|
|
352
|
+
paymentHash = _options.paymentHash;
|
|
353
|
+
} else {
|
|
354
|
+
({secret, paymentHash} = this.getSecretAndHash());
|
|
355
|
+
}
|
|
334
356
|
const claimHash = this._contract.getHashForHtlc(paymentHash);
|
|
335
357
|
|
|
336
358
|
const nativeTokenAddress = this._chain.getNativeCurrencyAddress();
|
|
@@ -363,6 +385,7 @@ export class FromBTCLNAutoWrapper<
|
|
|
363
385
|
amount: amountData.amount,
|
|
364
386
|
claimer: recipient,
|
|
365
387
|
token: amountData.token.toString(),
|
|
388
|
+
description: _options.description,
|
|
366
389
|
descriptionHash: _options.descriptionHash,
|
|
367
390
|
exactOut: !amountData.exactIn,
|
|
368
391
|
additionalParams,
|
|
@@ -427,7 +450,7 @@ export class FromBTCLNAutoWrapper<
|
|
|
427
450
|
_options.gasAmount + resp.claimerBounty, resp.claimerBounty, nativeTokenAddress
|
|
428
451
|
),
|
|
429
452
|
pr: resp.pr,
|
|
430
|
-
secret: secret
|
|
453
|
+
secret: secret?.toString("hex"),
|
|
431
454
|
exactIn: amountData.exactIn ?? true
|
|
432
455
|
};
|
|
433
456
|
const quote = new FromBTCLNAutoSwap<T>(this, swapInit);
|
|
@@ -471,14 +494,21 @@ export class FromBTCLNAutoWrapper<
|
|
|
471
494
|
quote: Promise<FromBTCLNAutoSwap<T>>,
|
|
472
495
|
intermediary: Intermediary
|
|
473
496
|
}[]> {
|
|
497
|
+
if(!this.isInitialized) throw new Error("Not initialized, call init() first!");
|
|
498
|
+
|
|
474
499
|
const _options = {
|
|
500
|
+
paymentHash: options?.paymentHash,
|
|
475
501
|
unsafeSkipLnNodeCheck: options?.unsafeSkipLnNodeCheck ?? this._options.unsafeSkipLnNodeCheck,
|
|
476
502
|
gasAmount: options?.gasAmount ?? 0n,
|
|
477
503
|
feeSafetyFactor: options?.feeSafetyFactor ?? 1.25, //No need to add much of a margin, since the claim should happen rather soon
|
|
478
504
|
unsafeZeroWatchtowerFee: options?.unsafeZeroWatchtowerFee ?? false,
|
|
505
|
+
description: options?.description,
|
|
479
506
|
descriptionHash: options?.descriptionHash
|
|
480
507
|
};
|
|
481
508
|
|
|
509
|
+
if(_options.paymentHash!=null && _options.paymentHash.length!==32)
|
|
510
|
+
throw new UserError("Invalid payment hash length, must be exactly 32 bytes!");
|
|
511
|
+
|
|
482
512
|
const abortController = extendAbortController(abortSignal);
|
|
483
513
|
const preFetches = {
|
|
484
514
|
pricePrefetchPromise: this.preFetchPrice(amountData, abortController.signal),
|
|
@@ -641,6 +671,7 @@ export class FromBTCLNAutoWrapper<
|
|
|
641
671
|
swap._commitTxId = await init.getInitTxId();
|
|
642
672
|
const blockData = await init.getTxBlock();
|
|
643
673
|
swap.createdAt = blockData.blockTime * 1000;
|
|
674
|
+
swap._commitedAt = blockData.blockTime * 1000;
|
|
644
675
|
swap._setInitiated();
|
|
645
676
|
swap._state = FromBTCLNAutoSwapState.CLAIM_COMMITED;
|
|
646
677
|
await swap._sync(false, false, state);
|
|
@@ -34,6 +34,7 @@ import {TokenAmount, toTokenAmount} from "../../../../types/TokenAmount";
|
|
|
34
34
|
import {BitcoinTokens, BtcToken, SCToken} from "../../../../types/Token";
|
|
35
35
|
import {getLogger, LoggerType} from "../../../../utils/Logger";
|
|
36
36
|
import {toBitcoinWallet} from "../../../../utils/BitcoinWalletUtils";
|
|
37
|
+
import {SwapExecutionAction} from "../../../../types/SwapExecutionAction";
|
|
37
38
|
|
|
38
39
|
/**
|
|
39
40
|
* State enum for legacy escrow based Bitcoin -> Smart chain swaps.
|
|
@@ -73,9 +74,9 @@ export enum FromBTCSwapState {
|
|
|
73
74
|
*/
|
|
74
75
|
CLAIM_COMMITED = 1,
|
|
75
76
|
/**
|
|
76
|
-
* Input bitcoin transaction was confirmed, wait for automatic settlement by the
|
|
77
|
-
*
|
|
78
|
-
* function.
|
|
77
|
+
* Input bitcoin transaction was confirmed, wait for automatic settlement by the watchtowers
|
|
78
|
+
* using the {@link FromBTCSwap.waitTillClaimed} function or settle manually using the {@link FromBTCSwap.claim}
|
|
79
|
+
* or {@link FromBTCSwap.txsClaim} function.
|
|
79
80
|
*/
|
|
80
81
|
BTC_TX_CONFIRMED = 2,
|
|
81
82
|
/**
|
|
@@ -84,6 +85,17 @@ export enum FromBTCSwapState {
|
|
|
84
85
|
CLAIM_CLAIMED = 3
|
|
85
86
|
}
|
|
86
87
|
|
|
88
|
+
const FromBTCSwapStateDescription = {
|
|
89
|
+
[FromBTCSwapState.FAILED]: "Bitcoin swap address has expired and the intermediary (LP) has already refunded its funds. No BTC should be sent anymore!",
|
|
90
|
+
[FromBTCSwapState.EXPIRED]: "Bitcoin swap address has expired, user should not send any BTC anymore! Though the intermediary (LP) hasn't refunded yet. So if there is a transaction already in-flight the swap might still succeed.",
|
|
91
|
+
[FromBTCSwapState.QUOTE_EXPIRED]: "Swap has expired for good and there is no way how it can be executed anymore",
|
|
92
|
+
[FromBTCSwapState.QUOTE_SOFT_EXPIRED]: "The swap is expired, though there is still a chance that it will be processed",
|
|
93
|
+
[FromBTCSwapState.PR_CREATED]: "Swap quote was created, initiate it by creating the swap escrow on the destination smart chain",
|
|
94
|
+
[FromBTCSwapState.CLAIM_COMMITED]: "Swap escrow was initiated (committed) on the destination chain, user can send the BTC to the Bitcoin swap address.",
|
|
95
|
+
[FromBTCSwapState.BTC_TX_CONFIRMED]: "Input bitcoin transaction was confirmed, wait for automatic settlement by the watchtower or settle manually.",
|
|
96
|
+
[FromBTCSwapState.CLAIM_CLAIMED]: "Swap successfully settled and funds received on the destination chain"
|
|
97
|
+
};
|
|
98
|
+
|
|
87
99
|
export type FromBTCSwapInit<T extends SwapData> = IEscrowSelfInitSwapInit<T> & {
|
|
88
100
|
data: T;
|
|
89
101
|
address?: string;
|
|
@@ -110,7 +122,14 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
110
122
|
implements IBTCWalletSwap, IClaimableSwap<T, FromBTCDefinition<T>, FromBTCSwapState>, IAddressSwap {
|
|
111
123
|
|
|
112
124
|
protected readonly TYPE: SwapType.FROM_BTC = SwapType.FROM_BTC;
|
|
113
|
-
|
|
125
|
+
/**
|
|
126
|
+
* @internal
|
|
127
|
+
*/
|
|
128
|
+
protected readonly swapStateName = (state: number) => FromBTCSwapState[state];
|
|
129
|
+
/**
|
|
130
|
+
* @internal
|
|
131
|
+
*/
|
|
132
|
+
protected readonly swapStateDescription = FromBTCSwapStateDescription;
|
|
114
133
|
/**
|
|
115
134
|
* @internal
|
|
116
135
|
*/
|
|
@@ -137,6 +156,8 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
137
156
|
private txId?: string;
|
|
138
157
|
private vout?: number;
|
|
139
158
|
|
|
159
|
+
private btcTxConfirmedAt?: number;
|
|
160
|
+
|
|
140
161
|
constructor(wrapper: FromBTCWrapper<T>, init: FromBTCSwapInit<T["Data"]>);
|
|
141
162
|
constructor(wrapper: FromBTCWrapper<T>, obj: any);
|
|
142
163
|
constructor(wrapper: FromBTCWrapper<T>, initOrObject: FromBTCSwapInit<T["Data"]> | any) {
|
|
@@ -156,6 +177,7 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
156
177
|
this.txId = initOrObject.txId;
|
|
157
178
|
this.vout = initOrObject.vout;
|
|
158
179
|
this.requiredConfirmations = initOrObject.requiredConfirmations ?? this._data.getConfirmationsHint();
|
|
180
|
+
this.btcTxConfirmedAt = initOrObject.btcTxConfirmedAt;
|
|
159
181
|
}
|
|
160
182
|
this.tryRecomputeSwapPrice();
|
|
161
183
|
this.logger = getLogger("FromBTC("+this.getIdentifierHashString()+"): ");
|
|
@@ -285,6 +307,14 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
285
307
|
return this._state===FromBTCSwapState.FAILED || this._state===FromBTCSwapState.EXPIRED;
|
|
286
308
|
}
|
|
287
309
|
|
|
310
|
+
/**
|
|
311
|
+
* @inheritDoc
|
|
312
|
+
*/
|
|
313
|
+
isInProgress(): boolean {
|
|
314
|
+
return this._state===FromBTCSwapState.CLAIM_COMMITED ||
|
|
315
|
+
this._state===FromBTCSwapState.BTC_TX_CONFIRMED;
|
|
316
|
+
}
|
|
317
|
+
|
|
288
318
|
/**
|
|
289
319
|
* @inheritDoc
|
|
290
320
|
*/
|
|
@@ -519,6 +549,7 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
519
549
|
(this._state as FromBTCSwapState)!==FromBTCSwapState.CLAIM_CLAIMED &&
|
|
520
550
|
(this._state as FromBTCSwapState)!==FromBTCSwapState.FAILED
|
|
521
551
|
) {
|
|
552
|
+
this.btcTxConfirmedAt ??= Date.now();
|
|
522
553
|
this._state = FromBTCSwapState.BTC_TX_CONFIRMED;
|
|
523
554
|
}
|
|
524
555
|
|
|
@@ -737,6 +768,7 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
737
768
|
/**
|
|
738
769
|
* @inheritDoc
|
|
739
770
|
*
|
|
771
|
+
* @param options.bitcoinFeeRate Optional fee rate to use for the created Bitcoin transaction
|
|
740
772
|
* @param options.bitcoinWallet Bitcoin wallet to use, when provided the function returns a funded
|
|
741
773
|
* psbt (`"FUNDED_PSBT"`), if not passed just a bitcoin receive address is returned (`"ADDRESS"`)
|
|
742
774
|
* @param options.skipChecks Skip checks like making sure init signature is still valid and swap
|
|
@@ -746,6 +778,7 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
746
778
|
* @throws {Error} if the swap or quote is expired, or if triggered in invalid state
|
|
747
779
|
*/
|
|
748
780
|
async txsExecute(options?: {
|
|
781
|
+
bitcoinFeeRate?: number,
|
|
749
782
|
bitcoinWallet?: MinimalBitcoinWalletInterface,
|
|
750
783
|
skipChecks?: boolean
|
|
751
784
|
}) {
|
|
@@ -803,6 +836,47 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
803
836
|
throw new Error("Invalid swap state to obtain execution txns, required PR_CREATED or CLAIM_COMMITED");
|
|
804
837
|
}
|
|
805
838
|
|
|
839
|
+
/**
|
|
840
|
+
* @inheritDoc
|
|
841
|
+
*
|
|
842
|
+
* @param options.bitcoinFeeRate Optional fee rate to use for the created Bitcoin transaction
|
|
843
|
+
* @param options.bitcoinWallet Bitcoin wallet to use, when provided the function returns a funded
|
|
844
|
+
* psbt (`"FUNDED_PSBT"`), if not passed just a bitcoin receive address is returned (`"ADDRESS"`)
|
|
845
|
+
* @param options.skipChecks Skip checks like making sure init signature is still valid and swap
|
|
846
|
+
* wasn't commited yet (this is handled on swap creation, if you commit right after quoting, you
|
|
847
|
+
* can use `skipChecks=true`)
|
|
848
|
+
* @param options.manualSettlementSmartChainSigner Optional smart chain signer to create a manual claim (settlement) transaction
|
|
849
|
+
* @param options.maxWaitTillAutomaticSettlementSeconds Maximum time to wait for an automatic settlement after
|
|
850
|
+
* the bitcoin transaction is confirmed (defaults to 60 seconds)
|
|
851
|
+
*/
|
|
852
|
+
async getCurrentActions(options?: {
|
|
853
|
+
bitcoinFeeRate?: number,
|
|
854
|
+
bitcoinWallet?: MinimalBitcoinWalletInterface,
|
|
855
|
+
skipChecks?: boolean,
|
|
856
|
+
manualSettlementSmartChainSigner?: string | T["Signer"] | T["NativeSigner"],
|
|
857
|
+
maxWaitTillAutomaticSettlementSeconds?: number
|
|
858
|
+
}): Promise<SwapExecutionAction<T>[]> {
|
|
859
|
+
if(this._state===FromBTCSwapState.PR_CREATED || this._state===FromBTCSwapState.CLAIM_COMMITED) {
|
|
860
|
+
try {
|
|
861
|
+
return await this.txsExecute(options);
|
|
862
|
+
} catch (e) {}
|
|
863
|
+
}
|
|
864
|
+
if(this.isClaimable()) {
|
|
865
|
+
if(
|
|
866
|
+
this.btcTxConfirmedAt==null ||
|
|
867
|
+
options?.maxWaitTillAutomaticSettlementSeconds===0 ||
|
|
868
|
+
(Date.now() - this.btcTxConfirmedAt) > (options?.maxWaitTillAutomaticSettlementSeconds ?? 60)*1000
|
|
869
|
+
) {
|
|
870
|
+
return [{
|
|
871
|
+
name: "Claim" as const,
|
|
872
|
+
description: "Manually settle (claim) the swap on the destination smart chain",
|
|
873
|
+
chain: this.chainIdentifier,
|
|
874
|
+
txs: await this.txsClaim(options?.manualSettlementSmartChainSigner)
|
|
875
|
+
}];
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
return[];
|
|
879
|
+
}
|
|
806
880
|
|
|
807
881
|
//////////////////////////////
|
|
808
882
|
//// Commit
|
|
@@ -1047,7 +1121,8 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
1047
1121
|
requiredConfirmations: this.requiredConfirmations,
|
|
1048
1122
|
senderAddress: this.senderAddress,
|
|
1049
1123
|
txId: this.txId,
|
|
1050
|
-
vout: this.vout
|
|
1124
|
+
vout: this.vout,
|
|
1125
|
+
btcTxConfirmedAt: this.btcTxConfirmedAt
|
|
1051
1126
|
};
|
|
1052
1127
|
}
|
|
1053
1128
|
|
|
@@ -1156,6 +1231,7 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
1156
1231
|
save = true;
|
|
1157
1232
|
}
|
|
1158
1233
|
if(this.requiredConfirmations!=null && res.confirmations>=this.requiredConfirmations) {
|
|
1234
|
+
this.btcTxConfirmedAt ??= Date.now();
|
|
1159
1235
|
this._state = FromBTCSwapState.BTC_TX_CONFIRMED;
|
|
1160
1236
|
save = true;
|
|
1161
1237
|
}
|
|
@@ -1198,6 +1274,7 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
1198
1274
|
shouldSave = true;
|
|
1199
1275
|
}
|
|
1200
1276
|
if(this.requiredConfirmations!=null && res.confirmations>=this.requiredConfirmations) {
|
|
1277
|
+
this.btcTxConfirmedAt ??= Date.now();
|
|
1201
1278
|
this._state = FromBTCSwapState.BTC_TX_CONFIRMED;
|
|
1202
1279
|
if(save) await this._saveAndEmit();
|
|
1203
1280
|
shouldSave = true;
|
|
@@ -1215,4 +1292,4 @@ export class FromBTCSwap<T extends ChainType = ChainType>
|
|
|
1215
1292
|
return false;
|
|
1216
1293
|
}
|
|
1217
1294
|
|
|
1218
|
-
}
|
|
1295
|
+
}
|