@atomiqlabs/lp-lib 12.1.0 → 13.0.0-beta.1
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/index.d.ts +18 -13
- package/dist/index.js +18 -13
- package/dist/plugins/IPlugin.d.ts +35 -12
- package/dist/plugins/PluginManager.d.ts +38 -15
- package/dist/plugins/PluginManager.js +33 -9
- package/dist/prices/BinanceSwapPrice.d.ts +1 -1
- package/dist/prices/BinanceSwapPrice.js +1 -1
- package/dist/prices/CoinGeckoSwapPrice.d.ts +1 -1
- package/dist/prices/CoinGeckoSwapPrice.js +1 -1
- package/dist/{swaps → prices}/ISwapPrice.js +4 -0
- package/dist/prices/OKXSwapPrice.d.ts +1 -1
- package/dist/prices/OKXSwapPrice.js +1 -1
- package/dist/swaps/SwapHandler.d.ts +20 -58
- package/dist/swaps/SwapHandler.js +17 -186
- package/dist/swaps/SwapHandlerSwap.d.ts +8 -23
- package/dist/swaps/SwapHandlerSwap.js +7 -39
- package/dist/swaps/assertions/AmountAssertions.d.ts +28 -0
- package/dist/swaps/assertions/AmountAssertions.js +72 -0
- package/dist/swaps/assertions/FromBtcAmountAssertions.d.ts +76 -0
- package/dist/swaps/assertions/FromBtcAmountAssertions.js +162 -0
- package/dist/swaps/assertions/LightningAssertions.d.ts +44 -0
- package/dist/swaps/assertions/LightningAssertions.js +86 -0
- package/dist/swaps/assertions/ToBtcAmountAssertions.d.ts +53 -0
- package/dist/swaps/{ToBtcBaseSwapHandler.js → assertions/ToBtcAmountAssertions.js} +20 -94
- package/dist/swaps/escrow/EscrowHandler.d.ts +51 -0
- package/dist/swaps/escrow/EscrowHandler.js +158 -0
- package/dist/swaps/escrow/EscrowHandlerSwap.d.ts +35 -0
- package/dist/swaps/escrow/EscrowHandlerSwap.js +69 -0
- package/dist/swaps/{FromBtcBaseSwap.d.ts → escrow/FromBtcBaseSwap.d.ts} +2 -3
- package/dist/swaps/{FromBtcBaseSwap.js → escrow/FromBtcBaseSwap.js} +4 -7
- package/dist/swaps/{FromBtcBaseSwapHandler.d.ts → escrow/FromBtcBaseSwapHandler.d.ts} +10 -49
- package/dist/swaps/{FromBtcBaseSwapHandler.js → escrow/FromBtcBaseSwapHandler.js} +16 -137
- package/dist/swaps/{ToBtcBaseSwap.d.ts → escrow/ToBtcBaseSwap.d.ts} +2 -2
- package/dist/swaps/{ToBtcBaseSwap.js → escrow/ToBtcBaseSwap.js} +4 -4
- package/dist/swaps/escrow/ToBtcBaseSwapHandler.d.ts +53 -0
- package/dist/swaps/escrow/ToBtcBaseSwapHandler.js +81 -0
- package/dist/swaps/{frombtc_abstract → escrow/frombtc_abstract}/FromBtcAbs.d.ts +4 -4
- package/dist/swaps/{frombtc_abstract → escrow/frombtc_abstract}/FromBtcAbs.js +15 -15
- package/dist/swaps/{frombtc_abstract → escrow/frombtc_abstract}/FromBtcSwapAbs.js +1 -1
- package/dist/swaps/{frombtcln_abstract → escrow/frombtcln_abstract}/FromBtcLnAbs.d.ts +9 -7
- package/dist/swaps/{frombtcln_abstract → escrow/frombtcln_abstract}/FromBtcLnAbs.js +22 -19
- package/dist/swaps/{frombtcln_abstract → escrow/frombtcln_abstract}/FromBtcLnSwapAbs.js +3 -3
- package/dist/swaps/{tobtc_abstract → escrow/tobtc_abstract}/ToBtcAbs.d.ts +4 -4
- package/dist/swaps/{tobtc_abstract → escrow/tobtc_abstract}/ToBtcAbs.js +14 -13
- package/dist/swaps/{tobtc_abstract → escrow/tobtc_abstract}/ToBtcSwapAbs.js +3 -3
- package/dist/swaps/{tobtcln_abstract → escrow/tobtcln_abstract}/ToBtcLnAbs.d.ts +6 -26
- package/dist/swaps/{tobtcln_abstract → escrow/tobtcln_abstract}/ToBtcLnAbs.js +20 -57
- package/dist/swaps/{tobtcln_abstract → escrow/tobtcln_abstract}/ToBtcLnSwapAbs.js +3 -3
- package/dist/swaps/spv_vault_swap/SpvVault.d.ts +41 -0
- package/dist/swaps/spv_vault_swap/SpvVault.js +111 -0
- package/dist/swaps/spv_vault_swap/SpvVaultSwap.d.ts +63 -0
- package/dist/swaps/spv_vault_swap/SpvVaultSwap.js +145 -0
- package/dist/swaps/spv_vault_swap/SpvVaultSwapHandler.d.ts +68 -0
- package/dist/swaps/spv_vault_swap/SpvVaultSwapHandler.js +469 -0
- package/dist/swaps/spv_vault_swap/SpvVaults.d.ts +57 -0
- package/dist/swaps/spv_vault_swap/SpvVaults.js +369 -0
- package/dist/swaps/{frombtc_trusted → trusted/frombtc_trusted}/FromBtcTrusted.d.ts +10 -13
- package/dist/swaps/{frombtc_trusted → trusted/frombtc_trusted}/FromBtcTrusted.js +25 -30
- package/dist/swaps/{frombtc_trusted → trusted/frombtc_trusted}/FromBtcTrustedSwap.d.ts +9 -4
- package/dist/swaps/{frombtc_trusted → trusted/frombtc_trusted}/FromBtcTrustedSwap.js +15 -7
- package/dist/swaps/{frombtcln_trusted → trusted/frombtcln_trusted}/FromBtcLnTrusted.d.ts +12 -14
- package/dist/swaps/{frombtcln_trusted → trusted/frombtcln_trusted}/FromBtcLnTrusted.js +33 -35
- package/dist/swaps/{frombtcln_trusted → trusted/frombtcln_trusted}/FromBtcLnTrustedSwap.d.ts +9 -4
- package/dist/swaps/{frombtcln_trusted → trusted/frombtcln_trusted}/FromBtcLnTrustedSwap.js +17 -7
- package/dist/utils/Utils.d.ts +13 -5
- package/dist/utils/Utils.js +23 -1
- package/dist/wallets/IBitcoinWallet.d.ts +6 -0
- package/dist/wallets/ISpvVaultSigner.d.ts +7 -0
- package/dist/wallets/ISpvVaultSigner.js +2 -0
- package/dist/wallets/ISpvVaultWallet.d.ts +42 -0
- package/dist/wallets/ISpvVaultWallet.js +2 -0
- package/package.json +2 -2
- package/src/index.ts +21 -15
- package/src/plugins/IPlugin.ts +27 -19
- package/src/plugins/PluginManager.ts +51 -26
- package/src/prices/BinanceSwapPrice.ts +1 -1
- package/src/prices/CoinGeckoSwapPrice.ts +1 -1
- package/src/{swaps → prices}/ISwapPrice.ts +4 -0
- package/src/prices/OKXSwapPrice.ts +1 -1
- package/src/swaps/SwapHandler.ts +22 -205
- package/src/swaps/SwapHandlerSwap.ts +10 -46
- package/src/swaps/assertions/AmountAssertions.ts +77 -0
- package/src/swaps/assertions/FromBtcAmountAssertions.ts +228 -0
- package/src/swaps/assertions/LightningAssertions.ts +103 -0
- package/src/swaps/{ToBtcBaseSwapHandler.ts → assertions/ToBtcAmountAssertions.ts} +27 -142
- package/src/swaps/escrow/EscrowHandler.ts +179 -0
- package/src/swaps/escrow/EscrowHandlerSwap.ts +87 -0
- package/src/swaps/{FromBtcBaseSwap.ts → escrow/FromBtcBaseSwap.ts} +4 -8
- package/src/swaps/{FromBtcBaseSwapHandler.ts → escrow/FromBtcBaseSwapHandler.ts} +30 -190
- package/src/swaps/{ToBtcBaseSwap.ts → escrow/ToBtcBaseSwap.ts} +4 -5
- package/src/swaps/escrow/ToBtcBaseSwapHandler.ts +130 -0
- package/src/swaps/{frombtc_abstract → escrow/frombtc_abstract}/FromBtcAbs.ts +20 -20
- package/src/swaps/{frombtc_abstract → escrow/frombtc_abstract}/FromBtcSwapAbs.ts +1 -1
- package/src/swaps/{frombtcln_abstract → escrow/frombtcln_abstract}/FromBtcLnAbs.ts +29 -25
- package/src/swaps/{frombtcln_abstract → escrow/frombtcln_abstract}/FromBtcLnSwapAbs.ts +2 -2
- package/src/swaps/{tobtc_abstract → escrow/tobtc_abstract}/ToBtcAbs.ts +19 -18
- package/src/swaps/{tobtc_abstract → escrow/tobtc_abstract}/ToBtcSwapAbs.ts +2 -2
- package/src/swaps/{tobtcln_abstract → escrow/tobtcln_abstract}/ToBtcLnAbs.ts +26 -66
- package/src/swaps/{tobtcln_abstract → escrow/tobtcln_abstract}/ToBtcLnSwapAbs.ts +2 -2
- package/src/swaps/spv_vault_swap/SpvVault.ts +143 -0
- package/src/swaps/spv_vault_swap/SpvVaultSwap.ts +207 -0
- package/src/swaps/spv_vault_swap/SpvVaultSwapHandler.ts +606 -0
- package/src/swaps/spv_vault_swap/SpvVaults.ts +441 -0
- package/src/swaps/{frombtc_trusted → trusted/frombtc_trusted}/FromBtcTrusted.ts +36 -51
- package/src/swaps/{frombtc_trusted → trusted/frombtc_trusted}/FromBtcTrustedSwap.ts +18 -8
- package/src/swaps/{frombtcln_trusted → trusted/frombtcln_trusted}/FromBtcLnTrusted.ts +43 -52
- package/src/swaps/{frombtcln_trusted → trusted/frombtcln_trusted}/FromBtcLnTrustedSwap.ts +20 -8
- package/src/utils/Utils.ts +27 -1
- package/src/wallets/IBitcoinWallet.ts +4 -0
- package/src/wallets/ISpvVaultSigner.ts +11 -0
- package/dist/swaps/FromBtcLnBaseSwapHandler.d.ts +0 -26
- package/dist/swaps/FromBtcLnBaseSwapHandler.js +0 -46
- package/dist/swaps/ToBtcBaseSwapHandler.d.ts +0 -95
- package/src/swaps/FromBtcLnBaseSwapHandler.ts +0 -63
- /package/dist/{swaps → prices}/ISwapPrice.d.ts +0 -0
- /package/dist/swaps/{frombtc_abstract → escrow/frombtc_abstract}/FromBtcSwapAbs.d.ts +0 -0
- /package/dist/swaps/{frombtcln_abstract → escrow/frombtcln_abstract}/FromBtcLnSwapAbs.d.ts +0 -0
- /package/dist/swaps/{tobtc_abstract → escrow/tobtc_abstract}/ToBtcSwapAbs.d.ts +0 -0
- /package/dist/swaps/{tobtcln_abstract → escrow/tobtcln_abstract}/ToBtcLnSwapAbs.d.ts +0 -0
|
@@ -11,31 +11,23 @@ function objectBigIntsToString(obj: Object) {
|
|
|
11
11
|
return obj;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
export abstract class SwapHandlerSwap<
|
|
14
|
+
export abstract class SwapHandlerSwap<S = any> extends Lockable implements StorageObject {
|
|
15
|
+
type: SwapHandlerType;
|
|
15
16
|
|
|
16
17
|
chainIdentifier: string;
|
|
17
18
|
state: S;
|
|
18
19
|
|
|
19
|
-
type: SwapHandlerType;
|
|
20
|
-
data: T;
|
|
21
20
|
metadata: {
|
|
22
21
|
request: any,
|
|
23
22
|
times: {[key: string]: number},
|
|
24
23
|
[key: string]: any
|
|
25
24
|
};
|
|
26
25
|
txIds: {
|
|
27
|
-
|
|
28
|
-
claim?: string,
|
|
29
|
-
refund?: string
|
|
26
|
+
[key: string]: string
|
|
30
27
|
} = {};
|
|
31
28
|
readonly swapFee: bigint;
|
|
32
29
|
readonly swapFeeInToken: bigint;
|
|
33
30
|
|
|
34
|
-
prefix: string;
|
|
35
|
-
timeout: string;
|
|
36
|
-
signature: string;
|
|
37
|
-
feeRate: string;
|
|
38
|
-
|
|
39
31
|
protected constructor(chainIdentifier: string, swapFee: bigint, swapFeeInToken: bigint);
|
|
40
32
|
protected constructor(obj: any);
|
|
41
33
|
|
|
@@ -47,33 +39,23 @@ export abstract class SwapHandlerSwap<T extends SwapData = SwapData, S = any> ex
|
|
|
47
39
|
this.swapFeeInToken = swapFeeInToken;
|
|
48
40
|
return;
|
|
49
41
|
} else {
|
|
50
|
-
this.data = obj.data==null ? null : SwapData.deserialize(obj.data);
|
|
51
42
|
this.metadata = obj.metadata;
|
|
52
43
|
this.chainIdentifier = obj.chainIdentifier;
|
|
53
44
|
this.txIds = obj.txIds || {};
|
|
54
45
|
this.state = obj.state;
|
|
55
46
|
this.swapFee = deserializeBN(obj.swapFee);
|
|
56
47
|
this.swapFeeInToken = deserializeBN(obj.swapFeeInToken);
|
|
57
|
-
this.prefix = obj.prefix;
|
|
58
|
-
this.timeout = obj.timeout;
|
|
59
|
-
this.signature = obj.signature;
|
|
60
|
-
this.feeRate = obj.feeRate;
|
|
61
48
|
}
|
|
62
49
|
}
|
|
63
50
|
|
|
64
51
|
serialize(): any {
|
|
65
52
|
return {
|
|
66
53
|
state: this.state,
|
|
67
|
-
data: this.data==null ? null : this.data.serialize(),
|
|
68
54
|
chainIdentifier: this.chainIdentifier,
|
|
69
55
|
metadata: objectBigIntsToString(this.metadata),
|
|
70
56
|
txIds: this.txIds,
|
|
71
57
|
swapFee: serializeBN(this.swapFee),
|
|
72
|
-
swapFeeInToken: serializeBN(this.swapFeeInToken)
|
|
73
|
-
prefix: this.prefix,
|
|
74
|
-
timeout: this.timeout,
|
|
75
|
-
signature: this.signature,
|
|
76
|
-
feeRate: this.feeRate
|
|
58
|
+
swapFeeInToken: serializeBN(this.swapFeeInToken)
|
|
77
59
|
}
|
|
78
60
|
}
|
|
79
61
|
|
|
@@ -88,31 +70,13 @@ export abstract class SwapHandlerSwap<T extends SwapData = SwapData, S = any> ex
|
|
|
88
70
|
return PluginManager.swapStateChange(this, oldState);
|
|
89
71
|
}
|
|
90
72
|
|
|
91
|
-
/**
|
|
92
|
-
* Returns the escrow hash - i.e. hash of the escrow data
|
|
93
|
-
*/
|
|
94
|
-
getEscrowHash(): string {
|
|
95
|
-
return this.data.getEscrowHash();
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Returns the claim data hash - i.e. hash passed to the claim handler
|
|
100
|
-
*/
|
|
101
|
-
getClaimHash(): string {
|
|
102
|
-
return this.data.getClaimHash();
|
|
103
|
-
}
|
|
104
|
-
|
|
105
73
|
/**
|
|
106
74
|
* Returns the identification hash of the swap, usually claim data hash, but can be overriden, e.g. for
|
|
107
75
|
* lightning swaps the identifier hash is used instead of claim data hash
|
|
108
76
|
*/
|
|
109
|
-
getIdentifierHash(): string
|
|
110
|
-
return this.getClaimHash();
|
|
111
|
-
}
|
|
77
|
+
abstract getIdentifierHash(): string;
|
|
112
78
|
|
|
113
|
-
getSequence(): bigint | null
|
|
114
|
-
return this.data?.getSequence==null ? null : this.data.getSequence();
|
|
115
|
-
}
|
|
79
|
+
abstract getSequence(): bigint | null;
|
|
116
80
|
|
|
117
81
|
/**
|
|
118
82
|
* Returns unique identifier of the swap in the form <hash>_<sequence> or just <hash> if the swap type doesn't
|
|
@@ -128,9 +92,7 @@ export abstract class SwapHandlerSwap<T extends SwapData = SwapData, S = any> ex
|
|
|
128
92
|
/**
|
|
129
93
|
* Returns the smart chain token used for the swap
|
|
130
94
|
*/
|
|
131
|
-
getToken(): string
|
|
132
|
-
return this.data?.getToken();
|
|
133
|
-
}
|
|
95
|
+
abstract getToken(): string
|
|
134
96
|
|
|
135
97
|
/**
|
|
136
98
|
* Checks whether the swap is finished, such that it is final and either successful or failed
|
|
@@ -157,7 +119,9 @@ export abstract class SwapHandlerSwap<T extends SwapData = SwapData, S = any> ex
|
|
|
157
119
|
/**
|
|
158
120
|
* Returns the input amount paid by the user (excluding fees)
|
|
159
121
|
*/
|
|
160
|
-
|
|
122
|
+
getInputAmount(): bigint {
|
|
123
|
+
return this.getTotalInputAmount() - this.getSwapFee().inInputToken;
|
|
124
|
+
}
|
|
161
125
|
|
|
162
126
|
/**
|
|
163
127
|
* Returns the total input amount paid by the user (including all fees)
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import {ISwapPrice} from "../../prices/ISwapPrice";
|
|
2
|
+
import {isQuoteAmountTooHigh, isQuoteAmountTooLow, isQuoteThrow} from "../../plugins/IPlugin";
|
|
3
|
+
|
|
4
|
+
export type AmountAssertionsConfig = {min: bigint, max: bigint, baseFee: bigint, feePPM: bigint};
|
|
5
|
+
|
|
6
|
+
export abstract class AmountAssertions {
|
|
7
|
+
|
|
8
|
+
readonly config: AmountAssertionsConfig;
|
|
9
|
+
readonly swapPricing: ISwapPrice;
|
|
10
|
+
|
|
11
|
+
constructor(config: AmountAssertionsConfig, swapPricing: ISwapPrice) {
|
|
12
|
+
this.config = config;
|
|
13
|
+
this.swapPricing = swapPricing;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Checks whether the bitcoin amount is within specified min/max bounds
|
|
18
|
+
*
|
|
19
|
+
* @param amount
|
|
20
|
+
* @protected
|
|
21
|
+
* @throws {DefinedRuntimeError} will throw an error if the amount is outside minimum/maximum bounds
|
|
22
|
+
*/
|
|
23
|
+
protected checkBtcAmountInBounds(amount: bigint): void {
|
|
24
|
+
if (amount < this.config.min) {
|
|
25
|
+
throw {
|
|
26
|
+
code: 20003,
|
|
27
|
+
msg: "Amount too low!",
|
|
28
|
+
data: {
|
|
29
|
+
min: this.config.min.toString(10),
|
|
30
|
+
max: this.config.max.toString(10)
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if(amount > this.config.max) {
|
|
36
|
+
throw {
|
|
37
|
+
code: 20004,
|
|
38
|
+
msg: "Amount too high!",
|
|
39
|
+
data: {
|
|
40
|
+
min: this.config.min.toString(10),
|
|
41
|
+
max: this.config.max.toString(10)
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Handles and throws plugin errors
|
|
49
|
+
*
|
|
50
|
+
* @param res Response as returned from the PluginManager.onHandlePost{To,From}BtcQuote
|
|
51
|
+
* @protected
|
|
52
|
+
* @throws {DefinedRuntimeError} will throw an error if the response is an error
|
|
53
|
+
*/
|
|
54
|
+
static handlePluginErrorResponses(res: any): void {
|
|
55
|
+
if(isQuoteThrow(res)) throw {
|
|
56
|
+
code: 29999,
|
|
57
|
+
msg: res.message
|
|
58
|
+
};
|
|
59
|
+
if(isQuoteAmountTooHigh(res)) throw {
|
|
60
|
+
code: 20004,
|
|
61
|
+
msg: "Amount too high!",
|
|
62
|
+
data: {
|
|
63
|
+
min: res.data.min.toString(10),
|
|
64
|
+
max: res.data.max.toString(10)
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
if(isQuoteAmountTooLow(res)) throw {
|
|
68
|
+
code: 20003,
|
|
69
|
+
msg: "Amount too low!",
|
|
70
|
+
data: {
|
|
71
|
+
min: res.data.min.toString(10),
|
|
72
|
+
max: res.data.max.toString(10)
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import {FromBtcLnRequestType} from "../escrow/frombtcln_abstract/FromBtcLnAbs";
|
|
2
|
+
import {FromBtcRequestType} from "../escrow/frombtc_abstract/FromBtcAbs";
|
|
3
|
+
import {FromBtcLnTrustedRequestType} from "../trusted/frombtcln_trusted/FromBtcLnTrusted";
|
|
4
|
+
import {PluginManager} from "../../plugins/PluginManager";
|
|
5
|
+
import {isPluginQuote, isQuoteSetFees} from "../../plugins/IPlugin";
|
|
6
|
+
import {RequestData, SwapHandlerType} from "../SwapHandler";
|
|
7
|
+
import {AmountAssertions, AmountAssertionsConfig} from "./AmountAssertions";
|
|
8
|
+
import {ISwapPrice} from "../../prices/ISwapPrice";
|
|
9
|
+
import {FromBtcTrustedRequestType} from "../trusted/frombtc_trusted/FromBtcTrusted";
|
|
10
|
+
import {SpvVaultSwapRequestType} from "../spv_vault_swap/SpvVaultSwapHandler";
|
|
11
|
+
|
|
12
|
+
export type FromBtcAmountAssertionsConfig = AmountAssertionsConfig & {
|
|
13
|
+
gasTokenMax?: {[chainId: string]: bigint}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export class FromBtcAmountAssertions extends AmountAssertions {
|
|
17
|
+
|
|
18
|
+
readonly config: FromBtcAmountAssertionsConfig;
|
|
19
|
+
|
|
20
|
+
constructor(config: FromBtcAmountAssertionsConfig, swapPricing: ISwapPrice) {
|
|
21
|
+
super(config, swapPricing)
|
|
22
|
+
this.config = config;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Checks minimums/maximums, calculates the fee & total amount
|
|
27
|
+
*
|
|
28
|
+
* @param swapType
|
|
29
|
+
* @param request
|
|
30
|
+
* @param requestedAmount
|
|
31
|
+
* @param gasAmount
|
|
32
|
+
* @throws {DefinedRuntimeError} will throw an error if the amount is outside minimum/maximum bounds
|
|
33
|
+
*/
|
|
34
|
+
async preCheckFromBtcAmounts(
|
|
35
|
+
swapType: SwapHandlerType.FROM_BTCLN | SwapHandlerType.FROM_BTC | SwapHandlerType.FROM_BTCLN_TRUSTED | SwapHandlerType.FROM_BTC_TRUSTED | SwapHandlerType.FROM_BTC_SPV,
|
|
36
|
+
request: RequestData<FromBtcLnRequestType | FromBtcRequestType | FromBtcLnTrustedRequestType | FromBtcTrustedRequestType | SpvVaultSwapRequestType>,
|
|
37
|
+
requestedAmount: {input: boolean, amount: bigint, token: string},
|
|
38
|
+
gasAmount?: {input: false, amount: bigint, token: string}
|
|
39
|
+
): Promise<{
|
|
40
|
+
baseFee: bigint,
|
|
41
|
+
feePPM: bigint,
|
|
42
|
+
securityDepositApyPPM?: bigint,
|
|
43
|
+
securityDepositBaseMultiplierPPM?: bigint,
|
|
44
|
+
}> {
|
|
45
|
+
const res = await PluginManager.onHandlePreFromBtcQuote(
|
|
46
|
+
swapType,
|
|
47
|
+
request,
|
|
48
|
+
requestedAmount,
|
|
49
|
+
request.chainIdentifier,
|
|
50
|
+
{minInBtc: this.config.min, maxInBtc: this.config.max},
|
|
51
|
+
{baseFeeInBtc: this.config.baseFee, feePPM: this.config.feePPM},
|
|
52
|
+
gasAmount
|
|
53
|
+
);
|
|
54
|
+
if(res!=null) {
|
|
55
|
+
AmountAssertions.handlePluginErrorResponses(res);
|
|
56
|
+
if(isQuoteSetFees(res)) {
|
|
57
|
+
return {
|
|
58
|
+
baseFee: res.baseFee || this.config.baseFee,
|
|
59
|
+
feePPM: res.feePPM || this.config.feePPM,
|
|
60
|
+
securityDepositApyPPM: res.securityDepositApyPPM,
|
|
61
|
+
securityDepositBaseMultiplierPPM: res.securityDepositBaseMultiplierPPM
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if(requestedAmount.input) this.checkBtcAmountInBounds(requestedAmount.amount);
|
|
66
|
+
|
|
67
|
+
if(gasAmount!=null && gasAmount.amount!==0n) {
|
|
68
|
+
if(gasAmount.amount > (this.config.gasTokenMax?.[request.chainIdentifier] ?? 0n)) {
|
|
69
|
+
throw {
|
|
70
|
+
code: 20504,
|
|
71
|
+
msg: "Gas token amount too high!",
|
|
72
|
+
data: {
|
|
73
|
+
max: (this.config.gasTokenMax?.[request.chainIdentifier] ?? 0n).toString(10)
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
baseFee: this.config.baseFee,
|
|
81
|
+
feePPM: this.config.feePPM
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Checks minimums/maximums, calculates the fee & total amount
|
|
87
|
+
*
|
|
88
|
+
* @param swapType
|
|
89
|
+
* @param request
|
|
90
|
+
* @param requestedAmount
|
|
91
|
+
* @param fees
|
|
92
|
+
* @param signal
|
|
93
|
+
* @param gasTokenAmount
|
|
94
|
+
* @throws {DefinedRuntimeError} will throw an error if the amount is outside minimum/maximum bounds
|
|
95
|
+
*/
|
|
96
|
+
async checkFromBtcAmount(
|
|
97
|
+
swapType: SwapHandlerType.FROM_BTCLN | SwapHandlerType.FROM_BTC | SwapHandlerType.FROM_BTCLN_TRUSTED | SwapHandlerType.FROM_BTC_TRUSTED | SwapHandlerType.FROM_BTC_SPV,
|
|
98
|
+
request: RequestData<FromBtcLnRequestType | FromBtcRequestType | FromBtcLnTrustedRequestType | FromBtcTrustedRequestType | SpvVaultSwapRequestType>,
|
|
99
|
+
requestedAmount: {input: boolean, amount: bigint, token: string, pricePrefetch?: Promise<bigint>},
|
|
100
|
+
fees: {baseFee: bigint, feePPM: bigint},
|
|
101
|
+
signal: AbortSignal,
|
|
102
|
+
gasTokenAmount?: {input: false, amount: bigint, token: string, pricePrefetch?: Promise<bigint>}
|
|
103
|
+
): Promise<{
|
|
104
|
+
amountBD: bigint,
|
|
105
|
+
swapFee: bigint, //Swap fee in BTC
|
|
106
|
+
swapFeeInToken: bigint, //Swap fee in token on top of what should be paid out to the user
|
|
107
|
+
totalInToken: bigint, //Total to be paid out to the user
|
|
108
|
+
amountBDgas?: bigint
|
|
109
|
+
gasSwapFee?: bigint
|
|
110
|
+
gasSwapFeeInToken?: bigint,
|
|
111
|
+
totalInGasToken?: bigint,
|
|
112
|
+
securityDepositApyPPM?: bigint,
|
|
113
|
+
securityDepositBaseMultiplierPPM?: bigint
|
|
114
|
+
}> {
|
|
115
|
+
const chainIdentifier = request.chainIdentifier;
|
|
116
|
+
|
|
117
|
+
let securityDepositApyPPM: bigint;
|
|
118
|
+
let securityDepositBaseMultiplierPPM: bigint;
|
|
119
|
+
|
|
120
|
+
const res = await PluginManager.onHandlePostFromBtcQuote(
|
|
121
|
+
swapType,
|
|
122
|
+
request,
|
|
123
|
+
requestedAmount,
|
|
124
|
+
chainIdentifier,
|
|
125
|
+
{minInBtc: this.config.min, maxInBtc: this.config.max},
|
|
126
|
+
{baseFeeInBtc: fees.baseFee, feePPM: fees.feePPM},
|
|
127
|
+
gasTokenAmount
|
|
128
|
+
);
|
|
129
|
+
signal.throwIfAborted();
|
|
130
|
+
if(res!=null) {
|
|
131
|
+
AmountAssertions.handlePluginErrorResponses(res);
|
|
132
|
+
if(isQuoteSetFees(res)) {
|
|
133
|
+
if(res.baseFee!=null) fees.baseFee = res.baseFee;
|
|
134
|
+
if(res.feePPM!=null) fees.feePPM = res.feePPM;
|
|
135
|
+
if(res.securityDepositApyPPM!=null) securityDepositApyPPM = res.securityDepositApyPPM;
|
|
136
|
+
if(res.securityDepositBaseMultiplierPPM!=null) securityDepositBaseMultiplierPPM = res.securityDepositBaseMultiplierPPM;
|
|
137
|
+
}
|
|
138
|
+
if(isPluginQuote(res)) {
|
|
139
|
+
if(!requestedAmount.input) {
|
|
140
|
+
return {
|
|
141
|
+
amountBD: res.amount.amount + res.swapFee.inInputTokens,
|
|
142
|
+
swapFee: res.swapFee.inInputTokens,
|
|
143
|
+
swapFeeInToken: res.swapFee.inOutputTokens,
|
|
144
|
+
totalInToken: requestedAmount.amount
|
|
145
|
+
}
|
|
146
|
+
} else {
|
|
147
|
+
return {
|
|
148
|
+
amountBD: requestedAmount.amount,
|
|
149
|
+
swapFee: res.swapFee.inInputTokens,
|
|
150
|
+
swapFeeInToken: res.swapFee.inOutputTokens,
|
|
151
|
+
totalInToken: res.amount.amount
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
let amountBDgas: bigint = 0n;
|
|
158
|
+
if(gasTokenAmount!=null) {
|
|
159
|
+
amountBDgas = await this.swapPricing.getToBtcSwapAmount(gasTokenAmount.amount, gasTokenAmount.token, chainIdentifier, true, gasTokenAmount.pricePrefetch);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
let amountBD: bigint;
|
|
163
|
+
if(!requestedAmount.input) {
|
|
164
|
+
amountBD = await this.swapPricing.getToBtcSwapAmount(requestedAmount.amount, requestedAmount.token, chainIdentifier, true, requestedAmount.pricePrefetch);
|
|
165
|
+
signal.throwIfAborted();
|
|
166
|
+
|
|
167
|
+
// amt = (amt+base_fee)/(1-fee)
|
|
168
|
+
amountBD = (amountBD + fees.baseFee) * 1000000n / (1000000n - fees.feePPM);
|
|
169
|
+
amountBDgas = amountBDgas * 1000000n / (1000000n - fees.feePPM);
|
|
170
|
+
|
|
171
|
+
const tooLow = amountBD < (this.config.min * 95n / 100n);
|
|
172
|
+
const tooHigh = amountBD > (this.config.max * 105n / 100n);
|
|
173
|
+
if(tooLow || tooHigh) {
|
|
174
|
+
const adjustedMin = this.config.min * (1000000n - fees.feePPM) / (1000000n - fees.baseFee);
|
|
175
|
+
const adjustedMax = this.config.max * (1000000n - fees.feePPM) / (1000000n - fees.baseFee);
|
|
176
|
+
const minIn = await this.swapPricing.getFromBtcSwapAmount(
|
|
177
|
+
adjustedMin, requestedAmount.token, chainIdentifier, null, requestedAmount.pricePrefetch
|
|
178
|
+
);
|
|
179
|
+
const maxIn = await this.swapPricing.getFromBtcSwapAmount(
|
|
180
|
+
adjustedMax, requestedAmount.token, chainIdentifier, null, requestedAmount.pricePrefetch
|
|
181
|
+
);
|
|
182
|
+
throw {
|
|
183
|
+
code: tooLow ? 20003 : 20004,
|
|
184
|
+
msg: tooLow ? "Amount too low!" : "Amount too high!",
|
|
185
|
+
data: {
|
|
186
|
+
min: minIn.toString(10),
|
|
187
|
+
max: maxIn.toString(10)
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
} else {
|
|
192
|
+
amountBD = requestedAmount.amount - amountBDgas;
|
|
193
|
+
this.checkBtcAmountInBounds(amountBD);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const swapFee = fees.baseFee + (amountBD * fees.feePPM / 1000000n);
|
|
197
|
+
const swapFeeInToken = await this.swapPricing.getFromBtcSwapAmount(swapFee, requestedAmount.token, chainIdentifier, true, requestedAmount.pricePrefetch);
|
|
198
|
+
signal.throwIfAborted();
|
|
199
|
+
|
|
200
|
+
const gasSwapFee = ((amountBDgas * fees.feePPM) + 999999n) / 1000000n;
|
|
201
|
+
const gasSwapFeeInToken = gasTokenAmount==null ?
|
|
202
|
+
0n :
|
|
203
|
+
await this.swapPricing.getFromBtcSwapAmount(gasSwapFee, gasTokenAmount.token, chainIdentifier, true, gasTokenAmount.pricePrefetch);
|
|
204
|
+
signal.throwIfAborted();
|
|
205
|
+
|
|
206
|
+
let totalInToken: bigint;
|
|
207
|
+
if(!requestedAmount.input) {
|
|
208
|
+
totalInToken = requestedAmount.amount;
|
|
209
|
+
} else {
|
|
210
|
+
totalInToken = await this.swapPricing.getFromBtcSwapAmount(amountBD - swapFee - gasSwapFee, requestedAmount.token, chainIdentifier, null, requestedAmount.pricePrefetch);
|
|
211
|
+
signal.throwIfAborted();
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return {
|
|
215
|
+
amountBD,
|
|
216
|
+
swapFee,
|
|
217
|
+
swapFeeInToken,
|
|
218
|
+
totalInToken,
|
|
219
|
+
amountBDgas,
|
|
220
|
+
gasSwapFee,
|
|
221
|
+
gasSwapFeeInToken,
|
|
222
|
+
totalInGasToken: gasTokenAmount?.amount,
|
|
223
|
+
securityDepositApyPPM,
|
|
224
|
+
securityDepositBaseMultiplierPPM
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import {ILightningWallet, LightningNetworkChannel} from "../../wallets/ILightningWallet";
|
|
2
|
+
import {LoggerType} from "../../utils/Utils";
|
|
3
|
+
import {ISwapPrice} from "../../prices/ISwapPrice";
|
|
4
|
+
|
|
5
|
+
export class LightningAssertions {
|
|
6
|
+
|
|
7
|
+
protected readonly LIGHTNING_LIQUIDITY_CACHE_TIMEOUT = 5*1000;
|
|
8
|
+
lightningLiquidityCache: {
|
|
9
|
+
liquidity: bigint,
|
|
10
|
+
timestamp: number
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
readonly lightning: ILightningWallet;
|
|
14
|
+
readonly logger: LoggerType;
|
|
15
|
+
|
|
16
|
+
constructor(
|
|
17
|
+
logger: LoggerType,
|
|
18
|
+
lightning: ILightningWallet
|
|
19
|
+
) {
|
|
20
|
+
this.logger = logger;
|
|
21
|
+
this.lightning = lightning;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Checks if the prior payment with the same paymentHash exists
|
|
26
|
+
*
|
|
27
|
+
* @param paymentHash
|
|
28
|
+
* @param abortSignal
|
|
29
|
+
* @throws {DefinedRuntimeError} will throw an error if payment already exists
|
|
30
|
+
*/
|
|
31
|
+
async checkPriorPayment(paymentHash: string, abortSignal: AbortSignal): Promise<void> {
|
|
32
|
+
const payment = await this.lightning.getPayment(paymentHash);
|
|
33
|
+
if(payment!=null) throw {
|
|
34
|
+
code: 20010,
|
|
35
|
+
msg: "Already processed"
|
|
36
|
+
};
|
|
37
|
+
abortSignal.throwIfAborted();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Checks if the underlying LND backend has enough liquidity in channels to honor the swap
|
|
42
|
+
*
|
|
43
|
+
* @param amount
|
|
44
|
+
* @param abortSignal
|
|
45
|
+
* @param useCached Whether to use cached liquidity values
|
|
46
|
+
* @throws {DefinedRuntimeError} will throw an error if there isn't enough liquidity
|
|
47
|
+
*/
|
|
48
|
+
async checkLiquidity(amount: bigint, abortSignal: AbortSignal, useCached: boolean = false): Promise<void> {
|
|
49
|
+
if(!useCached || this.lightningLiquidityCache==null || this.lightningLiquidityCache.timestamp<Date.now()-this.LIGHTNING_LIQUIDITY_CACHE_TIMEOUT) {
|
|
50
|
+
const channelBalances = await this.lightning.getLightningBalance();
|
|
51
|
+
this.lightningLiquidityCache = {
|
|
52
|
+
liquidity: channelBalances.localBalance,
|
|
53
|
+
timestamp: Date.now()
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if(amount > this.lightningLiquidityCache.liquidity) {
|
|
57
|
+
throw {
|
|
58
|
+
code: 20002,
|
|
59
|
+
msg: "Not enough liquidity"
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
abortSignal.throwIfAborted();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Checks if we have enough inbound liquidity to be able to receive an LN payment (without MPP)
|
|
67
|
+
*
|
|
68
|
+
* @param amountBD
|
|
69
|
+
* @param channelsPrefetch
|
|
70
|
+
* @param signal
|
|
71
|
+
* @throws {DefinedRuntimeError} will throw an error if there isn't enough inbound liquidity to receive the LN payment
|
|
72
|
+
*/
|
|
73
|
+
async checkInboundLiquidity(amountBD: bigint, channelsPrefetch: Promise<LightningNetworkChannel[]>, signal: AbortSignal) {
|
|
74
|
+
const channelsResponse = await channelsPrefetch;
|
|
75
|
+
|
|
76
|
+
signal.throwIfAborted();
|
|
77
|
+
|
|
78
|
+
let hasEnoughInboundLiquidity = false;
|
|
79
|
+
channelsResponse.forEach(channel => {
|
|
80
|
+
if(channel.remoteBalance >= amountBD) hasEnoughInboundLiquidity = true;
|
|
81
|
+
});
|
|
82
|
+
if(!hasEnoughInboundLiquidity) {
|
|
83
|
+
throw {
|
|
84
|
+
code: 20050,
|
|
85
|
+
msg: "Not enough LN inbound liquidity"
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Starts LN channels pre-fetch
|
|
92
|
+
*
|
|
93
|
+
* @param abortController
|
|
94
|
+
*/
|
|
95
|
+
getChannelsPrefetch(abortController: AbortController): Promise<LightningNetworkChannel[]> {
|
|
96
|
+
return this.lightning.getChannels(true).catch(e => {
|
|
97
|
+
this.logger.error("getChannelsPrefetch(): error", e);
|
|
98
|
+
abortController.abort(e);
|
|
99
|
+
return null;
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
}
|