@atomiqlabs/sdk 8.7.1 → 8.7.3
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/SmartChainAssets.d.ts +20 -0
- package/dist/SmartChainAssets.js +20 -0
- package/dist/bitcoin/wallet/SingleAddressBitcoinWallet.js +15 -1
- package/dist/intermediaries/apis/IntermediaryAPI.d.ts +1 -0
- package/dist/intermediaries/apis/IntermediaryAPI.js +2 -1
- package/dist/prices/abstract/ISwapPrice.d.ts +4 -2
- package/dist/prices/abstract/ISwapPrice.js +18 -6
- package/dist/swaps/ISwap.js +10 -5
- package/dist/swaps/ISwapWrapper.d.ts +1 -0
- package/dist/swaps/ISwapWrapper.js +2 -2
- package/dist/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.js +3 -2
- package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.js +1 -1
- package/dist/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.js +2 -2
- package/dist/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.js +3 -2
- package/dist/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.js +4 -4
- package/dist/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.js +4 -4
- package/dist/swaps/spv_swaps/SpvFromBTCSwap.js +1 -1
- package/dist/swaps/spv_swaps/SpvFromBTCWrapper.d.ts +7 -0
- package/dist/swaps/spv_swaps/SpvFromBTCWrapper.js +3 -2
- package/dist/swaps/trusted/ln/LnForGasWrapper.js +1 -1
- package/dist/swaps/trusted/onchain/OnchainForGasWrapper.js +1 -1
- package/package.json +1 -1
- package/src/SmartChainAssets.ts +20 -0
- package/src/bitcoin/wallet/SingleAddressBitcoinWallet.ts +14 -2
- package/src/intermediaries/apis/IntermediaryAPI.ts +4 -2
- package/src/prices/abstract/ISwapPrice.ts +19 -6
- package/src/swaps/ISwap.ts +17 -6
- package/src/swaps/ISwapWrapper.ts +4 -3
- package/src/swaps/escrow_swaps/frombtc/ln/FromBTCLNWrapper.ts +4 -2
- package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoSwap.ts +4 -1
- package/src/swaps/escrow_swaps/frombtc/ln_auto/FromBTCLNAutoWrapper.ts +2 -2
- package/src/swaps/escrow_swaps/frombtc/onchain/FromBTCWrapper.ts +4 -2
- package/src/swaps/escrow_swaps/tobtc/ln/ToBTCLNWrapper.ts +6 -6
- package/src/swaps/escrow_swaps/tobtc/onchain/ToBTCWrapper.ts +5 -5
- package/src/swaps/spv_swaps/SpvFromBTCSwap.ts +4 -1
- package/src/swaps/spv_swaps/SpvFromBTCWrapper.ts +10 -2
- package/src/swaps/trusted/ln/LnForGasWrapper.ts +1 -1
- package/src/swaps/trusted/onchain/OnchainForGasWrapper.ts +1 -1
|
@@ -3,6 +3,16 @@
|
|
|
3
3
|
* @category Tokens
|
|
4
4
|
*/
|
|
5
5
|
export declare const SmartChainAssets: {
|
|
6
|
+
readonly _TESTNET_strkBTC: {
|
|
7
|
+
readonly pricing: {
|
|
8
|
+
readonly binancePair: "$fixed-100000000";
|
|
9
|
+
readonly okxPair: "$fixed-100000000";
|
|
10
|
+
readonly coinGeckoCoinId: "$fixed-100000000";
|
|
11
|
+
readonly coinPaprikaCoinId: "$fixed-100000000";
|
|
12
|
+
readonly krakenPair: "$fixed-100000000";
|
|
13
|
+
};
|
|
14
|
+
readonly name: "strkBTC (dev)";
|
|
15
|
+
};
|
|
6
16
|
readonly _TESTNET_WBTC_VESU: {
|
|
7
17
|
readonly pricing: {
|
|
8
18
|
readonly binancePair: "WBTCBTC";
|
|
@@ -23,6 +33,16 @@ export declare const SmartChainAssets: {
|
|
|
23
33
|
};
|
|
24
34
|
readonly name: "pegBTC (dev)";
|
|
25
35
|
};
|
|
36
|
+
readonly strkBTC: {
|
|
37
|
+
readonly pricing: {
|
|
38
|
+
readonly binancePair: "$fixed-100000000";
|
|
39
|
+
readonly okxPair: "$fixed-100000000";
|
|
40
|
+
readonly coinGeckoCoinId: "$fixed-100000000";
|
|
41
|
+
readonly coinPaprikaCoinId: "$fixed-100000000";
|
|
42
|
+
readonly krakenPair: "$fixed-100000000";
|
|
43
|
+
};
|
|
44
|
+
readonly name: "strkBTC";
|
|
45
|
+
};
|
|
26
46
|
readonly WBTC: {
|
|
27
47
|
readonly pricing: {
|
|
28
48
|
readonly binancePair: "WBTCBTC";
|
package/dist/SmartChainAssets.js
CHANGED
|
@@ -6,6 +6,16 @@ exports.SmartChainAssets = void 0;
|
|
|
6
6
|
* @category Tokens
|
|
7
7
|
*/
|
|
8
8
|
exports.SmartChainAssets = {
|
|
9
|
+
_TESTNET_strkBTC: {
|
|
10
|
+
pricing: {
|
|
11
|
+
binancePair: "$fixed-100000000",
|
|
12
|
+
okxPair: "$fixed-100000000",
|
|
13
|
+
coinGeckoCoinId: "$fixed-100000000",
|
|
14
|
+
coinPaprikaCoinId: "$fixed-100000000",
|
|
15
|
+
krakenPair: "$fixed-100000000"
|
|
16
|
+
},
|
|
17
|
+
name: "strkBTC (dev)"
|
|
18
|
+
},
|
|
9
19
|
_TESTNET_WBTC_VESU: {
|
|
10
20
|
pricing: {
|
|
11
21
|
binancePair: "WBTCBTC",
|
|
@@ -26,6 +36,16 @@ exports.SmartChainAssets = {
|
|
|
26
36
|
},
|
|
27
37
|
name: "pegBTC (dev)"
|
|
28
38
|
},
|
|
39
|
+
strkBTC: {
|
|
40
|
+
pricing: {
|
|
41
|
+
binancePair: "$fixed-100000000",
|
|
42
|
+
okxPair: "$fixed-100000000",
|
|
43
|
+
coinGeckoCoinId: "$fixed-100000000",
|
|
44
|
+
coinPaprikaCoinId: "$fixed-100000000",
|
|
45
|
+
krakenPair: "$fixed-100000000"
|
|
46
|
+
},
|
|
47
|
+
name: "strkBTC"
|
|
48
|
+
},
|
|
29
49
|
WBTC: {
|
|
30
50
|
pricing: {
|
|
31
51
|
binancePair: "WBTCBTC",
|
|
@@ -5,10 +5,12 @@ const utils_1 = require("@scure/btc-signer/utils");
|
|
|
5
5
|
const btc_signer_1 = require("@scure/btc-signer");
|
|
6
6
|
const buffer_1 = require("buffer");
|
|
7
7
|
const BitcoinWallet_1 = require("./BitcoinWallet");
|
|
8
|
+
const base_1 = require("@atomiqlabs/base");
|
|
8
9
|
const bip32_1 = require("@scure/bip32");
|
|
9
10
|
const bip39_1 = require("@scure/bip39");
|
|
10
11
|
const english_js_1 = require("@scure/bip39/wordlists/english.js");
|
|
11
12
|
const sha2_1 = require("@noble/hashes/sha2");
|
|
13
|
+
const logger = (0, base_1.getLogger)("SingleAddressBitcoinWallet: ");
|
|
12
14
|
/**
|
|
13
15
|
* Bitcoin wallet implementation deriving a single address from a WIF encoded private key
|
|
14
16
|
*
|
|
@@ -32,12 +34,24 @@ class SingleAddressBitcoinWallet extends BitcoinWallet_1.BitcoinWallet {
|
|
|
32
34
|
if (address == null)
|
|
33
35
|
throw new Error("Failed to generate p2wpkh address from the provided private key!");
|
|
34
36
|
this.address = address;
|
|
37
|
+
this.addressType = (0, BitcoinWallet_1.identifyAddressType)(this.address, network);
|
|
35
38
|
}
|
|
36
39
|
else {
|
|
37
40
|
this.address = addressDataOrWIF.address;
|
|
41
|
+
this.addressType = (0, BitcoinWallet_1.identifyAddressType)(this.address, network);
|
|
38
42
|
this.pubkey = buffer_1.Buffer.from(addressDataOrWIF.publicKey, "hex");
|
|
43
|
+
// Some wallets seem to be returning a full 33-byte compressed pubkey instead of a taproot
|
|
44
|
+
// 32-byte long X-only key. Handle these cases here
|
|
45
|
+
if (this.addressType === "p2tr") {
|
|
46
|
+
if (this.pubkey.length !== 33)
|
|
47
|
+
return;
|
|
48
|
+
const leadingByte = this.pubkey[0];
|
|
49
|
+
if (leadingByte !== 0x03 && leadingByte !== 0x02)
|
|
50
|
+
throw new Error("Invalid public key passed for taproot bitcoin wallet, expected an X-only 32-byte public key, or a compressed 33-byte public key");
|
|
51
|
+
logger.debug(`constructor(): Converting compressed public key ${addressDataOrWIF.publicKey} to taproot X-only 32-byte public key`);
|
|
52
|
+
this.pubkey = this.pubkey.slice(1);
|
|
53
|
+
}
|
|
39
54
|
}
|
|
40
|
-
this.addressType = (0, BitcoinWallet_1.identifyAddressType)(this.address, network);
|
|
41
55
|
}
|
|
42
56
|
/**
|
|
43
57
|
* Returns all the wallet addresses controlled by the wallet
|
|
@@ -244,6 +244,7 @@ export type SpvFromBTCPrepare = SwapInit & {
|
|
|
244
244
|
exactOut: boolean;
|
|
245
245
|
callerFeeRate: Promise<bigint>;
|
|
246
246
|
frontingFeeRate: bigint;
|
|
247
|
+
stickyAddress?: boolean;
|
|
247
248
|
};
|
|
248
249
|
declare const SpvFromBTCInitResponseSchema: {
|
|
249
250
|
readonly txId: FieldTypeEnum.String;
|
|
@@ -543,7 +543,8 @@ class IntermediaryAPI {
|
|
|
543
543
|
gasAmount: init.gasAmount.toString(10),
|
|
544
544
|
gasToken: init.gasToken,
|
|
545
545
|
frontingFeeRate: init.frontingFeeRate.toString(10),
|
|
546
|
-
callerFeeRate: init.callerFeeRate.then(val => val.toString(10))
|
|
546
|
+
callerFeeRate: init.callerFeeRate.then(val => val.toString(10)),
|
|
547
|
+
stickyAddress: init.stickyAddress
|
|
547
548
|
}, {
|
|
548
549
|
code: SchemaVerifier_1.FieldTypeEnum.Number,
|
|
549
550
|
msg: SchemaVerifier_1.FieldTypeEnum.String,
|
|
@@ -64,8 +64,9 @@ export declare abstract class ISwapPrice<T extends MultiChain = MultiChain> {
|
|
|
64
64
|
* @param tokenAddress Token address to be paid
|
|
65
65
|
* @param abortSignal
|
|
66
66
|
* @param preFetchedPrice An optional price pre-fetched with {@link preFetchPrice}
|
|
67
|
+
* @param realSwapFeeSats
|
|
67
68
|
*/
|
|
68
|
-
isValidAmountSend<C extends ChainIds<T>>(chainIdentifier: C, amountSats: bigint, satsBaseFee: bigint, feePPM: bigint, paidToken: bigint, tokenAddress: string, abortSignal?: AbortSignal, preFetchedPrice?: bigint | null): Promise<PriceInfoType>;
|
|
69
|
+
isValidAmountSend<C extends ChainIds<T>>(chainIdentifier: C, amountSats: bigint, satsBaseFee: bigint, feePPM: bigint, paidToken: bigint, tokenAddress: string, abortSignal?: AbortSignal, preFetchedPrice?: bigint | null, realSwapFeeSats?: bigint): Promise<PriceInfoType>;
|
|
69
70
|
/**
|
|
70
71
|
* Recomputes pricing info without fetching the current price
|
|
71
72
|
*
|
|
@@ -88,8 +89,9 @@ export declare abstract class ISwapPrice<T extends MultiChain = MultiChain> {
|
|
|
88
89
|
* @param tokenAddress Token address to be received
|
|
89
90
|
* @param abortSignal
|
|
90
91
|
* @param preFetchedPrice An optional price pre-fetched with {@link preFetchPrice}
|
|
92
|
+
* @param realSwapFeeSats
|
|
91
93
|
*/
|
|
92
|
-
isValidAmountReceive<C extends ChainIds<T>>(chainIdentifier: C, amountSats: bigint, satsBaseFee: bigint, feePPM: bigint, receiveToken: bigint, tokenAddress: string, abortSignal?: AbortSignal, preFetchedPrice?: bigint | null): Promise<PriceInfoType>;
|
|
94
|
+
isValidAmountReceive<C extends ChainIds<T>>(chainIdentifier: C, amountSats: bigint, satsBaseFee: bigint, feePPM: bigint, receiveToken: bigint, tokenAddress: string, abortSignal?: AbortSignal, preFetchedPrice?: bigint | null, realSwapFeeSats?: bigint): Promise<PriceInfoType>;
|
|
93
95
|
/**
|
|
94
96
|
* Pre-fetches the pricing data for a given token, such that further calls to {@link isValidAmountReceive} or
|
|
95
97
|
* {@link isValidAmountSend} are quicker and don't need to wait for the price fetch
|
|
@@ -59,10 +59,14 @@ class ISwapPrice {
|
|
|
59
59
|
* @param tokenAddress Token address to be paid
|
|
60
60
|
* @param abortSignal
|
|
61
61
|
* @param preFetchedPrice An optional price pre-fetched with {@link preFetchPrice}
|
|
62
|
+
* @param realSwapFeeSats
|
|
62
63
|
*/
|
|
63
|
-
async isValidAmountSend(chainIdentifier, amountSats, satsBaseFee, feePPM, paidToken, tokenAddress, abortSignal, preFetchedPrice) {
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
async isValidAmountSend(chainIdentifier, amountSats, satsBaseFee, feePPM, paidToken, tokenAddress, abortSignal, preFetchedPrice, realSwapFeeSats) {
|
|
65
|
+
if (realSwapFeeSats != undefined && realSwapFeeSats < 0)
|
|
66
|
+
throw new Error("Invalid swap fee! Swap fee cannot be negative!");
|
|
67
|
+
const totalSats = realSwapFeeSats != undefined
|
|
68
|
+
? amountSats + realSwapFeeSats
|
|
69
|
+
: (amountSats * (1000000n + feePPM) / 1000000n) + satsBaseFee;
|
|
66
70
|
const totalUSats = totalSats * 1000000n;
|
|
67
71
|
const swapPriceUSatPerToken = totalUSats * (10n ** BigInt(this.getDecimalsThrowing(chainIdentifier, tokenAddress))) / paidToken;
|
|
68
72
|
if (this.shouldIgnore(chainIdentifier, tokenAddress))
|
|
@@ -122,10 +126,18 @@ class ISwapPrice {
|
|
|
122
126
|
* @param tokenAddress Token address to be received
|
|
123
127
|
* @param abortSignal
|
|
124
128
|
* @param preFetchedPrice An optional price pre-fetched with {@link preFetchPrice}
|
|
129
|
+
* @param realSwapFeeSats
|
|
125
130
|
*/
|
|
126
|
-
async isValidAmountReceive(chainIdentifier, amountSats, satsBaseFee, feePPM, receiveToken, tokenAddress, abortSignal, preFetchedPrice) {
|
|
127
|
-
|
|
128
|
-
|
|
131
|
+
async isValidAmountReceive(chainIdentifier, amountSats, satsBaseFee, feePPM, receiveToken, tokenAddress, abortSignal, preFetchedPrice, realSwapFeeSats) {
|
|
132
|
+
if (realSwapFeeSats != undefined) {
|
|
133
|
+
if (realSwapFeeSats >= amountSats)
|
|
134
|
+
throw new Error("Invalid swap fee! Larger than or equal to total output amount!");
|
|
135
|
+
if (realSwapFeeSats < 0)
|
|
136
|
+
throw new Error("Invalid swap fee! Must be non-negative!");
|
|
137
|
+
}
|
|
138
|
+
const totalSats = realSwapFeeSats != undefined
|
|
139
|
+
? amountSats - realSwapFeeSats
|
|
140
|
+
: (amountSats * (1000000n - feePPM) / 1000000n) - satsBaseFee;
|
|
129
141
|
const totalUSats = totalSats * 1000000n;
|
|
130
142
|
const swapPriceUSatPerToken = totalUSats * (10n ** BigInt(this.getDecimalsThrowing(chainIdentifier, tokenAddress))) / receiveToken;
|
|
131
143
|
if (this.shouldIgnore(chainIdentifier, tokenAddress))
|
package/dist/swaps/ISwap.js
CHANGED
|
@@ -166,16 +166,21 @@ class ISwap {
|
|
|
166
166
|
if (this.pricingInfo == null)
|
|
167
167
|
return;
|
|
168
168
|
const priceUsdPerBtc = this.pricingInfo.realPriceUsdPerBitcoin;
|
|
169
|
-
const input = this.getInput();
|
|
170
169
|
const output = this.getOutput();
|
|
171
|
-
if (
|
|
170
|
+
if (output.isUnknown)
|
|
172
171
|
return;
|
|
173
|
-
if ((0, Token_1.isSCToken)(
|
|
174
|
-
|
|
172
|
+
if ((0, Token_1.isSCToken)(this.getInputToken()) && this.getDirection() === SwapDirection_1.SwapDirection.TO_BTC) {
|
|
173
|
+
const input = this.getInputWithoutFee();
|
|
174
|
+
if (input.isUnknown)
|
|
175
|
+
return;
|
|
176
|
+
this.pricingInfo = await this.wrapper._prices.isValidAmountSend(this.chainIdentifier, output.rawAmount, this.pricingInfo.satsBaseFee, this.pricingInfo.feePPM, input.rawAmount + this.swapFee, input.token.address, undefined, undefined, this.swapFeeBtc);
|
|
175
177
|
this.pricingInfo.realPriceUsdPerBitcoin = priceUsdPerBtc;
|
|
176
178
|
}
|
|
177
179
|
else if ((0, Token_1.isSCToken)(output.token) && this.getDirection() === SwapDirection_1.SwapDirection.FROM_BTC) {
|
|
178
|
-
|
|
180
|
+
const input = this.getInput();
|
|
181
|
+
if (input.isUnknown)
|
|
182
|
+
return;
|
|
183
|
+
this.pricingInfo = await this.wrapper._prices.isValidAmountReceive(this.chainIdentifier, input.rawAmount, this.pricingInfo.satsBaseFee, this.pricingInfo.feePPM, output.rawAmount, output.token.address, undefined, undefined, this.swapFeeBtc);
|
|
179
184
|
this.pricingInfo.realPriceUsdPerBitcoin = priceUsdPerBtc;
|
|
180
185
|
}
|
|
181
186
|
}
|
|
@@ -194,6 +194,7 @@ export declare abstract class ISwapWrapper<T extends ChainType, D extends SwapTy
|
|
|
194
194
|
swapFeePPM: number;
|
|
195
195
|
}, send: boolean, amountSats: bigint, amountToken: bigint, token: string, feeData: {
|
|
196
196
|
networkFee?: bigint;
|
|
197
|
+
swapFeeBtc?: bigint;
|
|
197
198
|
}, pricePrefetchPromise?: Promise<bigint | undefined>, usdPricePrefetchPromise?: Promise<number | undefined>, abortSignal?: AbortSignal): Promise<PriceInfoType>;
|
|
198
199
|
/**
|
|
199
200
|
* Processes a single smart chain on-chain event
|
|
@@ -114,8 +114,8 @@ class ISwapWrapper {
|
|
|
114
114
|
amountToken = amountToken - feeData.networkFee;
|
|
115
115
|
const [isValidAmount, usdPrice] = await Promise.all([
|
|
116
116
|
send ?
|
|
117
|
-
this._prices.isValidAmountSend(this.chainIdentifier, amountSats, swapBaseFee, swapFeePPM, amountToken, token, abortSignal, await pricePrefetchPromise) :
|
|
118
|
-
this._prices.isValidAmountReceive(this.chainIdentifier, amountSats, swapBaseFee, swapFeePPM, amountToken, token, abortSignal, await pricePrefetchPromise),
|
|
117
|
+
this._prices.isValidAmountSend(this.chainIdentifier, amountSats, swapBaseFee, swapFeePPM, amountToken, token, abortSignal, await pricePrefetchPromise, feeData.swapFeeBtc) :
|
|
118
|
+
this._prices.isValidAmountReceive(this.chainIdentifier, amountSats, swapBaseFee, swapFeePPM, amountToken, token, abortSignal, await pricePrefetchPromise, feeData.swapFeeBtc),
|
|
119
119
|
usdPricePrefetchPromise.then(value => {
|
|
120
120
|
if (value != null)
|
|
121
121
|
return value;
|
|
@@ -221,10 +221,11 @@ class FromBTCLNWrapper extends IFromBTCLNWrapper_1.IFromBTCLNWrapper {
|
|
|
221
221
|
if (decodedPr.timeExpireDate == null)
|
|
222
222
|
throw new IntermediaryError_1.IntermediaryError("Invalid returned swap invoice, no expiry date field");
|
|
223
223
|
const amountIn = (BigInt(decodedPr.millisatoshis) + 999n) / 1000n;
|
|
224
|
+
const swapFeeBtc = resp.swapFee * amountIn / (resp.total - resp.swapFee);
|
|
224
225
|
try {
|
|
225
226
|
this.verifyReturnedData(resp, amountData, lp, _options, decodedPr, paymentHash);
|
|
226
227
|
const [pricingInfo] = await Promise.all([
|
|
227
|
-
this.verifyReturnedPrice(lp.services[SwapType_1.SwapType.FROM_BTCLN], false, amountIn, resp.total, amountData.token, {}, _preFetches.pricePrefetchPromise, _preFetches.usdPricePrefetchPromise, abortController.signal),
|
|
228
|
+
this.verifyReturnedPrice(lp.services[SwapType_1.SwapType.FROM_BTCLN], false, amountIn, resp.total, amountData.token, { swapFeeBtc }, _preFetches.pricePrefetchPromise, _preFetches.usdPricePrefetchPromise, abortController.signal),
|
|
228
229
|
this.verifyIntermediaryLiquidity(resp.total, (0, Utils_1.throwIfUndefined)(liquidityPromise)),
|
|
229
230
|
lnCapacityPromise != null ? this.verifyLnNodeCapacity(lp, decodedPr, lnCapacityPromise, abortController.signal) : Promise.resolve()
|
|
230
231
|
]);
|
|
@@ -233,7 +234,7 @@ class FromBTCLNWrapper extends IFromBTCLNWrapper_1.IFromBTCLNWrapper {
|
|
|
233
234
|
url: lp.url,
|
|
234
235
|
expiry: decodedPr.timeExpireDate * 1000,
|
|
235
236
|
swapFee: resp.swapFee,
|
|
236
|
-
swapFeeBtc
|
|
237
|
+
swapFeeBtc,
|
|
237
238
|
feeRate: (await _preFetches.feeRatePromise[version]),
|
|
238
239
|
initialSwapData: await this._contract(version).createSwapData(base_1.ChainSwapType.HTLC, lp.getAddress(this.chainIdentifier), recipient, amountData.token, resp.total, _hash[version], this.getRandomSequence(), BigInt(Math.floor(Date.now() / 1000)), false, true, resp.securityDeposit, 0n, nativeTokenAddress),
|
|
239
240
|
pr: resp.pr,
|
|
@@ -206,7 +206,7 @@ class FromBTCLNAutoSwap extends IEscrowSwap_1.IEscrowSwap {
|
|
|
206
206
|
if (this.pricingInfo == null || this.btcAmountSwap == null)
|
|
207
207
|
return;
|
|
208
208
|
const usdPricePerBtc = this.pricingInfo.realPriceUsdPerBitcoin;
|
|
209
|
-
this.pricingInfo = await this.wrapper._prices.isValidAmountReceive(this.chainIdentifier, this.btcAmountSwap, this.pricingInfo.satsBaseFee, this.pricingInfo.feePPM, this.getOutputAmountWithoutFee(), this.getSwapData().getToken());
|
|
209
|
+
this.pricingInfo = await this.wrapper._prices.isValidAmountReceive(this.chainIdentifier, this.btcAmountSwap, this.pricingInfo.satsBaseFee, this.pricingInfo.feePPM, this.getOutputAmountWithoutFee(), this.getSwapData().getToken(), undefined, undefined, this.swapFeeBtc);
|
|
210
210
|
this.pricingInfo.realPriceUsdPerBitcoin = usdPricePerBtc;
|
|
211
211
|
}
|
|
212
212
|
//////////////////////////////
|
|
@@ -301,9 +301,9 @@ class FromBTCLNAutoWrapper extends IFromBTCLNWrapper_1.IFromBTCLNWrapper {
|
|
|
301
301
|
try {
|
|
302
302
|
this.verifyReturnedData(resp, amountData, lp, _options, decodedPr, paymentHash, claimerBounty);
|
|
303
303
|
const [pricingInfo, gasPricingInfo] = await Promise.all([
|
|
304
|
-
this.verifyReturnedPrice(lp.services[SwapType_1.SwapType.FROM_BTCLN_AUTO], false, resp.btcAmountSwap, resp.total, amountData.token, {}, _preFetches.pricePrefetchPromise, _preFetches.usdPricePrefetchPromise, abortController.signal),
|
|
304
|
+
this.verifyReturnedPrice(lp.services[SwapType_1.SwapType.FROM_BTCLN_AUTO], false, resp.btcAmountSwap, resp.total, amountData.token, { swapFeeBtc: resp.swapFeeBtc }, _preFetches.pricePrefetchPromise, _preFetches.usdPricePrefetchPromise, abortController.signal),
|
|
305
305
|
_options.gasAmount === 0n ? Promise.resolve(undefined) : this.verifyReturnedPrice({ ...lp.services[SwapType_1.SwapType.FROM_BTCLN_AUTO], swapBaseFee: 0 }, //Base fee should be charged only on the amount, not on gas
|
|
306
|
-
false, resp.btcAmountGas, resp.totalGas + resp.claimerBounty, nativeTokenAddress, {}, _preFetches.gasTokenPricePrefetchPromise, _preFetches.usdPricePrefetchPromise, abortController.signal),
|
|
306
|
+
false, resp.btcAmountGas, resp.totalGas + resp.claimerBounty, nativeTokenAddress, { swapFeeBtc: resp.gasSwapFeeBtc }, _preFetches.gasTokenPricePrefetchPromise, _preFetches.usdPricePrefetchPromise, abortController.signal),
|
|
307
307
|
this.verifyIntermediaryLiquidity(resp.total, (0, Utils_1.throwIfUndefined)(liquidityPromise)),
|
|
308
308
|
_options.unsafeSkipLnNodeCheck ? Promise.resolve() : this.verifyLnNodeCapacity(lp, decodedPr, lnCapacityPromise, abortController.signal)
|
|
309
309
|
]);
|
|
@@ -335,10 +335,11 @@ class FromBTCWrapper extends IFromBTCWrapper_1.IFromBTCWrapper {
|
|
|
335
335
|
}, undefined, e => e instanceof RequestError_1.RequestError, abortController.signal);
|
|
336
336
|
const data = new (this._swapDataDeserializer(version))(resp.data);
|
|
337
337
|
data.setClaimer(recipient);
|
|
338
|
+
const swapFeeBtc = resp.swapFee * resp.amount / (data.getAmount() - resp.swapFee);
|
|
338
339
|
this.verifyReturnedData(recipient, resp, amountData, lp, _options, data, sequence, (await claimerBountyPrefetchPromise[version]), nativeTokenAddress);
|
|
339
340
|
const [pricingInfo, signatureExpiry] = await Promise.all([
|
|
340
341
|
//Get intermediary's liquidity
|
|
341
|
-
this.verifyReturnedPrice(lp.services[SwapType_1.SwapType.FROM_BTC], false, resp.amount, resp.total, amountData.token, {}, pricePrefetchPromise, usdPricePrefetchPromise, abortController.signal),
|
|
342
|
+
this.verifyReturnedPrice(lp.services[SwapType_1.SwapType.FROM_BTC], false, resp.amount, resp.total, amountData.token, { swapFeeBtc }, pricePrefetchPromise, usdPricePrefetchPromise, abortController.signal),
|
|
342
343
|
this.verifyReturnedSignature(recipient, data, resp, feeRatePromise[version], signDataPromise, version, abortController.signal),
|
|
343
344
|
this.verifyIntermediaryLiquidity(data.getAmount(), (0, Utils_1.throwIfUndefined)(liquidityPromise)),
|
|
344
345
|
]);
|
|
@@ -347,7 +348,7 @@ class FromBTCWrapper extends IFromBTCWrapper_1.IFromBTCWrapper {
|
|
|
347
348
|
url: lp.url,
|
|
348
349
|
expiry: signatureExpiry,
|
|
349
350
|
swapFee: resp.swapFee,
|
|
350
|
-
swapFeeBtc
|
|
351
|
+
swapFeeBtc,
|
|
351
352
|
feeRate: (await feeRatePromise[version]),
|
|
352
353
|
signatureData: resp,
|
|
353
354
|
data,
|
|
@@ -181,15 +181,15 @@ class ToBTCLNWrapper extends IToBTCWrapper_1.IToBTCWrapper {
|
|
|
181
181
|
const data = new (this._swapDataDeserializer(version))(resp.data);
|
|
182
182
|
data.setOfferer(signer);
|
|
183
183
|
await this.verifyReturnedData(signer, resp, parsedPr, amountData.token, lp, calculatedOptions, data);
|
|
184
|
+
const swapFeeBtc = resp.swapFee * amountOut / (data.getAmount() - totalFee);
|
|
184
185
|
const [pricingInfo, signatureExpiry, reputation] = await Promise.all([
|
|
185
|
-
this.verifyReturnedPrice(lp.services[SwapType_1.SwapType.TO_BTCLN], true, amountOut, data.getAmount(), amountData.token, { networkFee: resp.maxFee }, preFetches.pricePreFetchPromise, preFetches.usdPricePrefetchPromise, abortController.signal),
|
|
186
|
+
this.verifyReturnedPrice(lp.services[SwapType_1.SwapType.TO_BTCLN], true, amountOut, data.getAmount(), amountData.token, { networkFee: resp.maxFee, swapFeeBtc }, preFetches.pricePreFetchPromise, preFetches.usdPricePrefetchPromise, abortController.signal),
|
|
186
187
|
this.verifyReturnedSignature(signer, data, resp, preFetches.feeRatePromise[version], signDataPromise, version, abortController.signal),
|
|
187
188
|
reputationPromise
|
|
188
189
|
]);
|
|
189
190
|
abortController.signal.throwIfAborted();
|
|
190
191
|
if (reputation != null)
|
|
191
192
|
lp.reputation[amountData.token.toString()] = reputation;
|
|
192
|
-
const swapFeeBtc = resp.swapFee * amountOut / (data.getAmount() - totalFee);
|
|
193
193
|
const quote = new ToBTCLNSwap_1.ToBTCLNSwap(this, {
|
|
194
194
|
pricingInfo,
|
|
195
195
|
url: lp.url,
|
|
@@ -339,15 +339,15 @@ class ToBTCLNWrapper extends IToBTCWrapper_1.IToBTCWrapper {
|
|
|
339
339
|
const data = new (this._swapDataDeserializer(version))(resp.data);
|
|
340
340
|
data.setOfferer(signer);
|
|
341
341
|
await this.verifyReturnedData(signer, resp, parsedInvoice, amountData.token, lp, calculatedOptions, data, amountData.amount);
|
|
342
|
+
const swapFeeBtc = resp.swapFee * amountOut / (data.getAmount() - totalFee);
|
|
342
343
|
const [pricingInfo, signatureExpiry, reputation] = await Promise.all([
|
|
343
|
-
this.verifyReturnedPrice(lp.services[SwapType_1.SwapType.TO_BTCLN], true, prepareResp.amount, data.getAmount(), amountData.token, { networkFee: resp.maxFee }, preFetches.pricePreFetchPromise, preFetches.usdPricePrefetchPromise, abortSignal),
|
|
344
|
+
this.verifyReturnedPrice(lp.services[SwapType_1.SwapType.TO_BTCLN], true, prepareResp.amount, data.getAmount(), amountData.token, { networkFee: resp.maxFee, swapFeeBtc }, preFetches.pricePreFetchPromise, preFetches.usdPricePrefetchPromise, abortSignal),
|
|
344
345
|
this.verifyReturnedSignature(signer, data, resp, preFetches.feeRatePromise[version], signDataPromise, version, abortController.signal),
|
|
345
346
|
reputationPromise
|
|
346
347
|
]);
|
|
347
348
|
abortController.signal.throwIfAborted();
|
|
348
349
|
if (reputation != null)
|
|
349
350
|
lp.reputation[amountData.token.toString()] = reputation;
|
|
350
|
-
const swapFeeBtc = resp.swapFee * amountOut / (data.getAmount() - totalFee);
|
|
351
351
|
const quote = new ToBTCLNSwap_1.ToBTCLNSwap(this, {
|
|
352
352
|
pricingInfo,
|
|
353
353
|
url: lp.url,
|
|
@@ -200,18 +200,18 @@ class ToBTCWrapper extends IToBTCWrapper_1.IToBTCWrapper {
|
|
|
200
200
|
let hash = _hash?.[version] ?? this._contract(version).getHashForOnchain(outputScript, resp.amount, _options.confirmations, nonce).toString("hex");
|
|
201
201
|
const data = new (this._swapDataDeserializer(version))(resp.data);
|
|
202
202
|
data.setOfferer(signer);
|
|
203
|
+
const inputWithoutFees = data.getAmount() - resp.swapFee - resp.networkFee;
|
|
204
|
+
const swapFeeBtc = resp.swapFee * resp.amount / inputWithoutFees;
|
|
205
|
+
const networkFeeBtc = resp.networkFee * resp.amount / inputWithoutFees;
|
|
203
206
|
this.verifyReturnedData(signer, resp, amountData, lp, _options, data, hash);
|
|
204
207
|
const [pricingInfo, signatureExpiry, reputation] = await Promise.all([
|
|
205
|
-
this.verifyReturnedPrice(lp.services[SwapType_1.SwapType.TO_BTC], true, resp.amount, data.getAmount(), amountData.token, resp, pricePreFetchPromise, usdPricePrefetchPromise, abortController.signal),
|
|
208
|
+
this.verifyReturnedPrice(lp.services[SwapType_1.SwapType.TO_BTC], true, resp.amount, data.getAmount(), amountData.token, { networkFee: resp.networkFee, swapFeeBtc }, pricePreFetchPromise, usdPricePrefetchPromise, abortController.signal),
|
|
206
209
|
this.verifyReturnedSignature(signer, data, resp, feeRatePromise[version], signDataPromise, version, abortController.signal),
|
|
207
210
|
reputationPromise
|
|
208
211
|
]);
|
|
209
212
|
abortController.signal.throwIfAborted();
|
|
210
213
|
if (reputation != null)
|
|
211
214
|
lp.reputation[amountData.token.toString()] = reputation;
|
|
212
|
-
const inputWithoutFees = data.getAmount() - resp.swapFee - resp.networkFee;
|
|
213
|
-
const swapFeeBtc = resp.swapFee * resp.amount / inputWithoutFees;
|
|
214
|
-
const networkFeeBtc = resp.networkFee * resp.amount / inputWithoutFees;
|
|
215
215
|
const quote = new ToBTCSwap_1.ToBTCSwap(this, {
|
|
216
216
|
pricingInfo,
|
|
217
217
|
url: lp.url,
|
|
@@ -255,7 +255,7 @@ class SpvFromBTCSwap extends ISwap_1.ISwap {
|
|
|
255
255
|
if (this.pricingInfo == null)
|
|
256
256
|
return;
|
|
257
257
|
const usdPricePerBtc = this.pricingInfo.realPriceUsdPerBitcoin;
|
|
258
|
-
this.pricingInfo = await this.wrapper._prices.isValidAmountReceive(this.chainIdentifier, this.btcAmountSwap, this.pricingInfo.satsBaseFee, this.pricingInfo.feePPM, this.getOutputWithoutFee().rawAmount, this.outputSwapToken);
|
|
258
|
+
this.pricingInfo = await this.wrapper._prices.isValidAmountReceive(this.chainIdentifier, this.btcAmountSwap, this.pricingInfo.satsBaseFee, this.pricingInfo.feePPM, this.getOutputWithoutFee().rawAmount, this.outputSwapToken, undefined, undefined, this.swapFeeBtc);
|
|
259
259
|
this.pricingInfo.realPriceUsdPerBitcoin = usdPricePerBtc;
|
|
260
260
|
}
|
|
261
261
|
//////////////////////////////
|
|
@@ -46,6 +46,13 @@ export type SpvFromBTCOptions = {
|
|
|
46
46
|
* the settlement gas fee cost)
|
|
47
47
|
*/
|
|
48
48
|
feeSafetyFactor?: number;
|
|
49
|
+
/**
|
|
50
|
+
* Instruct the LP to create a "sticky address" for your destination wallet address. After the first successful
|
|
51
|
+
* swap with that LP, the used bitcoin address will be permanently linked to your destination wallet address. So
|
|
52
|
+
* all subsequent swaps to the same address will yield the same LP deposit bitcoin address. Useful for corporate
|
|
53
|
+
* whitelist-only wallets
|
|
54
|
+
*/
|
|
55
|
+
stickyAddress?: boolean;
|
|
49
56
|
/**
|
|
50
57
|
* @deprecated Use `maxAllowedBitcoinFeeRate` instead!
|
|
51
58
|
*/
|
|
@@ -505,15 +505,16 @@ class SpvFromBTCWrapper extends ISwapWrapper_1.ISwapWrapper {
|
|
|
505
505
|
gasAmount: _options.gasAmount,
|
|
506
506
|
callerFeeRate: (0, Utils_1.throwIfUndefined)(callerFeePrefetchPromise[version], "Caller fee prefetch failed!"),
|
|
507
507
|
frontingFeeRate: 0n,
|
|
508
|
+
stickyAddress: options?.stickyAddress,
|
|
508
509
|
additionalParams
|
|
509
510
|
}, this._options.postRequestTimeout, abortController.signal, retryCount > 0 ? false : undefined);
|
|
510
511
|
}, undefined, e => e instanceof RequestError_1.RequestError, abortController.signal);
|
|
511
512
|
this.logger.debug("create(" + lp.url + "): LP response: ", resp);
|
|
512
513
|
const callerFeeShare = (await callerFeePrefetchPromise[version]);
|
|
513
514
|
const [pricingInfo, gasPricingInfo, { vault, vaultUtxoValue }] = await Promise.all([
|
|
514
|
-
this.verifyReturnedPrice(lp.services[SwapType_1.SwapType.SPV_VAULT_FROM_BTC], false, resp.btcAmountSwap, resp.total * (100000n + callerFeeShare) / 100000n, amountData.token, {}, pricePrefetchPromise, usdPricePrefetchPromise, abortController.signal),
|
|
515
|
+
this.verifyReturnedPrice(lp.services[SwapType_1.SwapType.SPV_VAULT_FROM_BTC], false, resp.btcAmountSwap, resp.total * (100000n + callerFeeShare) / 100000n, amountData.token, { swapFeeBtc: resp.swapFeeBtc }, pricePrefetchPromise, usdPricePrefetchPromise, abortController.signal),
|
|
515
516
|
_options.gasAmount === 0n ? Promise.resolve(undefined) : this.verifyReturnedPrice({ ...lp.services[SwapType_1.SwapType.SPV_VAULT_FROM_BTC], swapBaseFee: 0 }, //Base fee should be charged only on the amount, not on gas
|
|
516
|
-
false, resp.btcAmountGas, resp.totalGas * (100000n + callerFeeShare) / 100000n, nativeTokenAddress, {}, gasTokenPricePrefetchPromise, usdPricePrefetchPromise, abortController.signal),
|
|
517
|
+
false, resp.btcAmountGas, resp.totalGas * (100000n + callerFeeShare) / 100000n, nativeTokenAddress, { swapFeeBtc: resp.gasSwapFeeBtc }, gasTokenPricePrefetchPromise, usdPricePrefetchPromise, abortController.signal),
|
|
517
518
|
this.verifyReturnedData(resp, amountData, lp, _options, callerFeeShare, bitcoinFeeRatePromise, abortController.signal)
|
|
518
519
|
]);
|
|
519
520
|
const swapInit = {
|
|
@@ -62,7 +62,7 @@ class LnForGasWrapper extends ISwapWrapper_1.ISwapWrapper {
|
|
|
62
62
|
throw new IntermediaryError_1.IntermediaryError("Invalid total returned");
|
|
63
63
|
const pricingInfo = await this.verifyReturnedPrice(typeof (lpOrUrl) === "string" || lpOrUrl.services[SwapType_1.SwapType.TRUSTED_FROM_BTCLN] == null ?
|
|
64
64
|
{ swapFeePPM: 10000, swapBaseFee: 10 } :
|
|
65
|
-
lpOrUrl.services[SwapType_1.SwapType.TRUSTED_FROM_BTCLN], false, amountIn, amount, token, {});
|
|
65
|
+
lpOrUrl.services[SwapType_1.SwapType.TRUSTED_FROM_BTCLN], false, amountIn, amount, token, { swapFeeBtc: resp.swapFeeSats });
|
|
66
66
|
const quoteInit = {
|
|
67
67
|
pr: resp.pr,
|
|
68
68
|
outputAmount: resp.total,
|
|
@@ -69,7 +69,7 @@ class OnchainForGasWrapper extends ISwapWrapper_1.ISwapWrapper {
|
|
|
69
69
|
throw new IntermediaryError_1.IntermediaryError("Invalid total returned");
|
|
70
70
|
const pricingInfo = await this.verifyReturnedPrice(typeof (lpOrUrl) === "string" || lpOrUrl.services[SwapType_1.SwapType.TRUSTED_FROM_BTC] == null ?
|
|
71
71
|
{ swapFeePPM: 10000, swapBaseFee: 10 } :
|
|
72
|
-
lpOrUrl.services[SwapType_1.SwapType.TRUSTED_FROM_BTC], false, resp.amountSats, amount, this._chain.getNativeCurrencyAddress(), {});
|
|
72
|
+
lpOrUrl.services[SwapType_1.SwapType.TRUSTED_FROM_BTC], false, resp.amountSats, amount, this._chain.getNativeCurrencyAddress(), { swapFeeBtc: resp.swapFeeSats });
|
|
73
73
|
const quote = new OnchainForGasSwap_1.OnchainForGasSwap(this, {
|
|
74
74
|
paymentHash: resp.paymentHash,
|
|
75
75
|
sequence: resp.sequence,
|
package/package.json
CHANGED
package/src/SmartChainAssets.ts
CHANGED
|
@@ -4,6 +4,16 @@
|
|
|
4
4
|
* @category Tokens
|
|
5
5
|
*/
|
|
6
6
|
export const SmartChainAssets = {
|
|
7
|
+
_TESTNET_strkBTC: {
|
|
8
|
+
pricing: {
|
|
9
|
+
binancePair: "$fixed-100000000",
|
|
10
|
+
okxPair: "$fixed-100000000",
|
|
11
|
+
coinGeckoCoinId: "$fixed-100000000",
|
|
12
|
+
coinPaprikaCoinId: "$fixed-100000000",
|
|
13
|
+
krakenPair: "$fixed-100000000"
|
|
14
|
+
},
|
|
15
|
+
name: "strkBTC (dev)"
|
|
16
|
+
},
|
|
7
17
|
_TESTNET_WBTC_VESU: {
|
|
8
18
|
pricing: {
|
|
9
19
|
binancePair: "WBTCBTC",
|
|
@@ -24,6 +34,16 @@ export const SmartChainAssets = {
|
|
|
24
34
|
},
|
|
25
35
|
name: "pegBTC (dev)"
|
|
26
36
|
},
|
|
37
|
+
strkBTC: {
|
|
38
|
+
pricing: {
|
|
39
|
+
binancePair: "$fixed-100000000",
|
|
40
|
+
okxPair: "$fixed-100000000",
|
|
41
|
+
coinGeckoCoinId: "$fixed-100000000",
|
|
42
|
+
coinPaprikaCoinId: "$fixed-100000000",
|
|
43
|
+
krakenPair: "$fixed-100000000"
|
|
44
|
+
},
|
|
45
|
+
name: "strkBTC"
|
|
46
|
+
},
|
|
27
47
|
WBTC: {
|
|
28
48
|
pricing: {
|
|
29
49
|
binancePair: "WBTCBTC",
|
|
@@ -3,12 +3,14 @@ import {BTC_NETWORK, NETWORK, pubECDSA, randomPrivateKeyBytes, TEST_NETWORK} fro
|
|
|
3
3
|
import {getAddress, Transaction, WIF} from "@scure/btc-signer";
|
|
4
4
|
import {Buffer} from "buffer";
|
|
5
5
|
import {identifyAddressType, BitcoinWallet} from "./BitcoinWallet";
|
|
6
|
-
import {BitcoinNetwork, BitcoinRpcWithAddressIndex} from "@atomiqlabs/base";
|
|
6
|
+
import {BitcoinNetwork, BitcoinRpcWithAddressIndex, getLogger} from "@atomiqlabs/base";
|
|
7
7
|
import {HDKey} from "@scure/bip32";
|
|
8
8
|
import {entropyToMnemonic, generateMnemonic, mnemonicToSeed} from "@scure/bip39";
|
|
9
9
|
import {wordlist} from "@scure/bip39/wordlists/english.js";
|
|
10
10
|
import {sha256} from "@noble/hashes/sha2";
|
|
11
11
|
|
|
12
|
+
const logger = getLogger("SingleAddressBitcoinWallet: ");
|
|
13
|
+
|
|
12
14
|
/**
|
|
13
15
|
* Bitcoin wallet implementation deriving a single address from a WIF encoded private key
|
|
14
16
|
*
|
|
@@ -42,11 +44,21 @@ export class SingleAddressBitcoinWallet extends BitcoinWallet {
|
|
|
42
44
|
const address = getAddress("wpkh", this.privKey, network);
|
|
43
45
|
if(address==null) throw new Error("Failed to generate p2wpkh address from the provided private key!");
|
|
44
46
|
this.address = address;
|
|
47
|
+
this.addressType = identifyAddressType(this.address, network);
|
|
45
48
|
} else {
|
|
46
49
|
this.address = addressDataOrWIF.address;
|
|
50
|
+
this.addressType = identifyAddressType(this.address, network);
|
|
47
51
|
this.pubkey = Buffer.from(addressDataOrWIF.publicKey, "hex");
|
|
52
|
+
// Some wallets seem to be returning a full 33-byte compressed pubkey instead of a taproot
|
|
53
|
+
// 32-byte long X-only key. Handle these cases here
|
|
54
|
+
if(this.addressType==="p2tr") {
|
|
55
|
+
if(this.pubkey.length!==33) return;
|
|
56
|
+
const leadingByte = this.pubkey[0];
|
|
57
|
+
if(leadingByte!==0x03 && leadingByte!==0x02) throw new Error("Invalid public key passed for taproot bitcoin wallet, expected an X-only 32-byte public key, or a compressed 33-byte public key");
|
|
58
|
+
logger.debug(`constructor(): Converting compressed public key ${addressDataOrWIF.publicKey} to taproot X-only 32-byte public key`);
|
|
59
|
+
this.pubkey = this.pubkey.slice(1);
|
|
60
|
+
}
|
|
48
61
|
}
|
|
49
|
-
this.addressType = identifyAddressType(this.address, network);
|
|
50
62
|
}
|
|
51
63
|
|
|
52
64
|
/**
|
|
@@ -310,7 +310,8 @@ export type SpvFromBTCPrepare = SwapInit & {
|
|
|
310
310
|
gasToken: string,
|
|
311
311
|
exactOut: boolean,
|
|
312
312
|
callerFeeRate: Promise<bigint>,
|
|
313
|
-
frontingFeeRate: bigint
|
|
313
|
+
frontingFeeRate: bigint,
|
|
314
|
+
stickyAddress?: boolean
|
|
314
315
|
}
|
|
315
316
|
|
|
316
317
|
const SpvFromBTCInitResponseSchema = {
|
|
@@ -878,7 +879,8 @@ export class IntermediaryAPI {
|
|
|
878
879
|
gasAmount: init.gasAmount.toString(10),
|
|
879
880
|
gasToken: init.gasToken,
|
|
880
881
|
frontingFeeRate: init.frontingFeeRate.toString(10),
|
|
881
|
-
callerFeeRate: init.callerFeeRate.then(val => val.toString(10))
|
|
882
|
+
callerFeeRate: init.callerFeeRate.then(val => val.toString(10)),
|
|
883
|
+
stickyAddress: init.stickyAddress
|
|
882
884
|
}, {
|
|
883
885
|
code: FieldTypeEnum.Number,
|
|
884
886
|
msg: FieldTypeEnum.String,
|
|
@@ -100,6 +100,7 @@ export abstract class ISwapPrice<T extends MultiChain = MultiChain> {
|
|
|
100
100
|
* @param tokenAddress Token address to be paid
|
|
101
101
|
* @param abortSignal
|
|
102
102
|
* @param preFetchedPrice An optional price pre-fetched with {@link preFetchPrice}
|
|
103
|
+
* @param realSwapFeeSats
|
|
103
104
|
*/
|
|
104
105
|
public async isValidAmountSend<C extends ChainIds<T>>(
|
|
105
106
|
chainIdentifier: C,
|
|
@@ -109,11 +110,15 @@ export abstract class ISwapPrice<T extends MultiChain = MultiChain> {
|
|
|
109
110
|
paidToken: bigint,
|
|
110
111
|
tokenAddress: string,
|
|
111
112
|
abortSignal?: AbortSignal,
|
|
112
|
-
preFetchedPrice?: bigint | null
|
|
113
|
+
preFetchedPrice?: bigint | null,
|
|
114
|
+
realSwapFeeSats?: bigint
|
|
113
115
|
): Promise<PriceInfoType> {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
+
if(realSwapFeeSats!=undefined && realSwapFeeSats<0) throw new Error("Invalid swap fee! Swap fee cannot be negative!");
|
|
117
|
+
const totalSats = realSwapFeeSats!=undefined
|
|
118
|
+
? amountSats + realSwapFeeSats
|
|
119
|
+
: (amountSats * (1000000n + feePPM) / 1000000n) + satsBaseFee;
|
|
116
120
|
const totalUSats = totalSats * 1000000n;
|
|
121
|
+
|
|
117
122
|
const swapPriceUSatPerToken = totalUSats * (10n ** BigInt(this.getDecimalsThrowing(chainIdentifier, tokenAddress))) / paidToken;
|
|
118
123
|
|
|
119
124
|
if(this.shouldIgnore(chainIdentifier, tokenAddress)) return {
|
|
@@ -185,6 +190,7 @@ export abstract class ISwapPrice<T extends MultiChain = MultiChain> {
|
|
|
185
190
|
* @param tokenAddress Token address to be received
|
|
186
191
|
* @param abortSignal
|
|
187
192
|
* @param preFetchedPrice An optional price pre-fetched with {@link preFetchPrice}
|
|
193
|
+
* @param realSwapFeeSats
|
|
188
194
|
*/
|
|
189
195
|
public async isValidAmountReceive<C extends ChainIds<T>>(
|
|
190
196
|
chainIdentifier: C,
|
|
@@ -194,11 +200,18 @@ export abstract class ISwapPrice<T extends MultiChain = MultiChain> {
|
|
|
194
200
|
receiveToken: bigint,
|
|
195
201
|
tokenAddress: string,
|
|
196
202
|
abortSignal?: AbortSignal,
|
|
197
|
-
preFetchedPrice?: bigint | null
|
|
203
|
+
preFetchedPrice?: bigint | null,
|
|
204
|
+
realSwapFeeSats?: bigint
|
|
198
205
|
): Promise<PriceInfoType> {
|
|
199
|
-
|
|
200
|
-
|
|
206
|
+
if(realSwapFeeSats!=undefined) {
|
|
207
|
+
if(realSwapFeeSats>=amountSats) throw new Error("Invalid swap fee! Larger than or equal to total output amount!");
|
|
208
|
+
if(realSwapFeeSats<0) throw new Error("Invalid swap fee! Must be non-negative!");
|
|
209
|
+
}
|
|
210
|
+
const totalSats = realSwapFeeSats!=undefined
|
|
211
|
+
? amountSats - realSwapFeeSats
|
|
212
|
+
: (amountSats * (1000000n - feePPM) / 1000000n) - satsBaseFee;
|
|
201
213
|
const totalUSats = totalSats * 1000000n;
|
|
214
|
+
|
|
202
215
|
const swapPriceUSatPerToken = totalUSats * (10n ** BigInt(this.getDecimalsThrowing(chainIdentifier, tokenAddress))) / receiveToken;
|
|
203
216
|
|
|
204
217
|
if(this.shouldIgnore(chainIdentifier, tokenAddress)) return {
|
package/src/swaps/ISwap.ts
CHANGED
|
@@ -322,28 +322,39 @@ export abstract class ISwap<
|
|
|
322
322
|
public async refreshPriceData(): Promise<void> {
|
|
323
323
|
if(this.pricingInfo==null) return;
|
|
324
324
|
const priceUsdPerBtc = this.pricingInfo.realPriceUsdPerBitcoin;
|
|
325
|
-
const input = this.getInput();
|
|
326
325
|
const output = this.getOutput();
|
|
327
|
-
if(
|
|
326
|
+
if(output.isUnknown) return;
|
|
327
|
+
|
|
328
|
+
if(isSCToken(this.getInputToken()) && this.getDirection()===SwapDirection.TO_BTC) {
|
|
329
|
+
const input = this.getInputWithoutFee();
|
|
330
|
+
if(input.isUnknown) return;
|
|
328
331
|
|
|
329
|
-
if(isSCToken(input.token) && this.getDirection()===SwapDirection.TO_BTC) {
|
|
330
332
|
this.pricingInfo = await this.wrapper._prices.isValidAmountSend(
|
|
331
333
|
this.chainIdentifier,
|
|
332
334
|
output.rawAmount!,
|
|
333
335
|
this.pricingInfo.satsBaseFee,
|
|
334
336
|
this.pricingInfo.feePPM,
|
|
335
|
-
input.rawAmount
|
|
336
|
-
input.token.address
|
|
337
|
+
input.rawAmount! + this.swapFee,
|
|
338
|
+
input.token.address,
|
|
339
|
+
undefined,
|
|
340
|
+
undefined,
|
|
341
|
+
this.swapFeeBtc
|
|
337
342
|
);
|
|
338
343
|
this.pricingInfo.realPriceUsdPerBitcoin = priceUsdPerBtc;
|
|
339
344
|
} else if(isSCToken(output.token) && this.getDirection()===SwapDirection.FROM_BTC) {
|
|
345
|
+
const input = this.getInput();
|
|
346
|
+
if(input.isUnknown) return;
|
|
347
|
+
|
|
340
348
|
this.pricingInfo = await this.wrapper._prices.isValidAmountReceive(
|
|
341
349
|
this.chainIdentifier,
|
|
342
350
|
input.rawAmount!,
|
|
343
351
|
this.pricingInfo.satsBaseFee,
|
|
344
352
|
this.pricingInfo.feePPM,
|
|
345
353
|
output.rawAmount!,
|
|
346
|
-
output.token.address
|
|
354
|
+
output.token.address,
|
|
355
|
+
undefined,
|
|
356
|
+
undefined,
|
|
357
|
+
this.swapFeeBtc
|
|
347
358
|
);
|
|
348
359
|
this.pricingInfo.realPriceUsdPerBitcoin = priceUsdPerBtc;
|
|
349
360
|
}
|
|
@@ -259,7 +259,8 @@ export abstract class ISwapWrapper<
|
|
|
259
259
|
amountToken: bigint,
|
|
260
260
|
token: string,
|
|
261
261
|
feeData: {
|
|
262
|
-
networkFee?: bigint
|
|
262
|
+
networkFee?: bigint,
|
|
263
|
+
swapFeeBtc?: bigint
|
|
263
264
|
},
|
|
264
265
|
pricePrefetchPromise: Promise<bigint | undefined> = Promise.resolve(undefined),
|
|
265
266
|
usdPricePrefetchPromise: Promise<number | undefined> = Promise.resolve(undefined),
|
|
@@ -271,8 +272,8 @@ export abstract class ISwapWrapper<
|
|
|
271
272
|
|
|
272
273
|
const [isValidAmount, usdPrice] = await Promise.all([
|
|
273
274
|
send ?
|
|
274
|
-
this._prices.isValidAmountSend(this.chainIdentifier, amountSats, swapBaseFee, swapFeePPM, amountToken, token, abortSignal, await pricePrefetchPromise) :
|
|
275
|
-
this._prices.isValidAmountReceive(this.chainIdentifier, amountSats, swapBaseFee, swapFeePPM, amountToken, token, abortSignal, await pricePrefetchPromise),
|
|
275
|
+
this._prices.isValidAmountSend(this.chainIdentifier, amountSats, swapBaseFee, swapFeePPM, amountToken, token, abortSignal, await pricePrefetchPromise, feeData.swapFeeBtc) :
|
|
276
|
+
this._prices.isValidAmountReceive(this.chainIdentifier, amountSats, swapBaseFee, swapFeePPM, amountToken, token, abortSignal, await pricePrefetchPromise, feeData.swapFeeBtc),
|
|
276
277
|
usdPricePrefetchPromise.then(value => {
|
|
277
278
|
if(value!=null) return value;
|
|
278
279
|
return this._prices.preFetchUsdPrice(abortSignal);
|
|
@@ -342,12 +342,14 @@ export class FromBTCLNWrapper<
|
|
|
342
342
|
if(decodedPr.timeExpireDate==null) throw new IntermediaryError("Invalid returned swap invoice, no expiry date field");
|
|
343
343
|
const amountIn = (BigInt(decodedPr.millisatoshis) + 999n) / 1000n;
|
|
344
344
|
|
|
345
|
+
const swapFeeBtc = resp.swapFee * amountIn / (resp.total - resp.swapFee);
|
|
346
|
+
|
|
345
347
|
try {
|
|
346
348
|
this.verifyReturnedData(resp, amountData, lp, _options, decodedPr, paymentHash);
|
|
347
349
|
const [pricingInfo] = await Promise.all([
|
|
348
350
|
this.verifyReturnedPrice(
|
|
349
351
|
lp.services[SwapType.FROM_BTCLN], false, amountIn, resp.total,
|
|
350
|
-
amountData.token, {}, _preFetches.pricePrefetchPromise, _preFetches.usdPricePrefetchPromise, abortController.signal
|
|
352
|
+
amountData.token, {swapFeeBtc}, _preFetches.pricePrefetchPromise, _preFetches.usdPricePrefetchPromise, abortController.signal
|
|
351
353
|
),
|
|
352
354
|
this.verifyIntermediaryLiquidity(resp.total, throwIfUndefined(liquidityPromise)),
|
|
353
355
|
lnCapacityPromise!=null ? this.verifyLnNodeCapacity(lp, decodedPr, lnCapacityPromise, abortController.signal) : Promise.resolve()
|
|
@@ -358,7 +360,7 @@ export class FromBTCLNWrapper<
|
|
|
358
360
|
url: lp.url,
|
|
359
361
|
expiry: decodedPr.timeExpireDate*1000,
|
|
360
362
|
swapFee: resp.swapFee,
|
|
361
|
-
swapFeeBtc
|
|
363
|
+
swapFeeBtc,
|
|
362
364
|
feeRate: (await _preFetches.feeRatePromise[version])!,
|
|
363
365
|
initialSwapData: await this._contract(version).createSwapData(
|
|
364
366
|
ChainSwapType.HTLC, lp.getAddress(this.chainIdentifier), recipient, amountData.token,
|
|
@@ -309,7 +309,10 @@ export class FromBTCLNAutoSwap<T extends ChainType = ChainType>
|
|
|
309
309
|
this.pricingInfo.satsBaseFee,
|
|
310
310
|
this.pricingInfo.feePPM,
|
|
311
311
|
this.getOutputAmountWithoutFee(),
|
|
312
|
-
this.getSwapData().getToken()
|
|
312
|
+
this.getSwapData().getToken(),
|
|
313
|
+
undefined,
|
|
314
|
+
undefined,
|
|
315
|
+
this.swapFeeBtc
|
|
313
316
|
);
|
|
314
317
|
this.pricingInfo.realPriceUsdPerBitcoin = usdPricePerBtc;
|
|
315
318
|
}
|
|
@@ -468,13 +468,13 @@ export class FromBTCLNAutoWrapper<
|
|
|
468
468
|
lp.services[SwapType.FROM_BTCLN_AUTO],
|
|
469
469
|
false, resp.btcAmountSwap,
|
|
470
470
|
resp.total,
|
|
471
|
-
amountData.token, {}, _preFetches.pricePrefetchPromise, _preFetches.usdPricePrefetchPromise, abortController.signal
|
|
471
|
+
amountData.token, {swapFeeBtc: resp.swapFeeBtc}, _preFetches.pricePrefetchPromise, _preFetches.usdPricePrefetchPromise, abortController.signal
|
|
472
472
|
),
|
|
473
473
|
_options.gasAmount===0n ? Promise.resolve(undefined) : this.verifyReturnedPrice(
|
|
474
474
|
{...lp.services[SwapType.FROM_BTCLN_AUTO], swapBaseFee: 0}, //Base fee should be charged only on the amount, not on gas
|
|
475
475
|
false, resp.btcAmountGas,
|
|
476
476
|
resp.totalGas + resp.claimerBounty,
|
|
477
|
-
nativeTokenAddress, {}, _preFetches.gasTokenPricePrefetchPromise, _preFetches.usdPricePrefetchPromise, abortController.signal
|
|
477
|
+
nativeTokenAddress, {swapFeeBtc: resp.gasSwapFeeBtc}, _preFetches.gasTokenPricePrefetchPromise, _preFetches.usdPricePrefetchPromise, abortController.signal
|
|
478
478
|
),
|
|
479
479
|
this.verifyIntermediaryLiquidity(resp.total, throwIfUndefined(liquidityPromise)),
|
|
480
480
|
_options.unsafeSkipLnNodeCheck ? Promise.resolve() : this.verifyLnNodeCapacity(lp, decodedPr, lnCapacityPromise, abortController.signal)
|
|
@@ -528,12 +528,14 @@ export class FromBTCWrapper<
|
|
|
528
528
|
const data: T["Data"] = new (this._swapDataDeserializer(version))(resp.data);
|
|
529
529
|
data.setClaimer(recipient);
|
|
530
530
|
|
|
531
|
+
const swapFeeBtc = resp.swapFee * resp.amount / (data.getAmount() - resp.swapFee);
|
|
532
|
+
|
|
531
533
|
this.verifyReturnedData(recipient, resp, amountData, lp, _options, data, sequence, (await claimerBountyPrefetchPromise[version])!, nativeTokenAddress);
|
|
532
534
|
const [pricingInfo, signatureExpiry] = await Promise.all([
|
|
533
535
|
//Get intermediary's liquidity
|
|
534
536
|
this.verifyReturnedPrice(
|
|
535
537
|
lp.services[SwapType.FROM_BTC], false, resp.amount, resp.total,
|
|
536
|
-
amountData.token, {}, pricePrefetchPromise, usdPricePrefetchPromise, abortController.signal
|
|
538
|
+
amountData.token, {swapFeeBtc}, pricePrefetchPromise, usdPricePrefetchPromise, abortController.signal
|
|
537
539
|
),
|
|
538
540
|
this.verifyReturnedSignature(recipient, data, resp, feeRatePromise[version], signDataPromise, version, abortController.signal),
|
|
539
541
|
this.verifyIntermediaryLiquidity(data.getAmount(), throwIfUndefined(liquidityPromise)),
|
|
@@ -544,7 +546,7 @@ export class FromBTCWrapper<
|
|
|
544
546
|
url: lp.url,
|
|
545
547
|
expiry: signatureExpiry,
|
|
546
548
|
swapFee: resp.swapFee,
|
|
547
|
-
swapFeeBtc
|
|
549
|
+
swapFeeBtc,
|
|
548
550
|
feeRate: (await feeRatePromise[version])!,
|
|
549
551
|
signatureData: resp,
|
|
550
552
|
data,
|
|
@@ -315,10 +315,12 @@ export class ToBTCLNWrapper<T extends ChainType> extends IToBTCWrapper<T, ToBTCL
|
|
|
315
315
|
|
|
316
316
|
await this.verifyReturnedData(signer, resp, parsedPr, amountData.token, lp, calculatedOptions, data);
|
|
317
317
|
|
|
318
|
+
const swapFeeBtc = resp.swapFee * amountOut / (data.getAmount() - totalFee);
|
|
319
|
+
|
|
318
320
|
const [pricingInfo, signatureExpiry, reputation] = await Promise.all([
|
|
319
321
|
this.verifyReturnedPrice(
|
|
320
322
|
lp.services[SwapType.TO_BTCLN], true, amountOut, data.getAmount(),
|
|
321
|
-
amountData.token, {networkFee: resp.maxFee},
|
|
323
|
+
amountData.token, {networkFee: resp.maxFee, swapFeeBtc},
|
|
322
324
|
preFetches.pricePreFetchPromise, preFetches.usdPricePrefetchPromise, abortController.signal
|
|
323
325
|
),
|
|
324
326
|
this.verifyReturnedSignature(
|
|
@@ -330,8 +332,6 @@ export class ToBTCLNWrapper<T extends ChainType> extends IToBTCWrapper<T, ToBTCL
|
|
|
330
332
|
|
|
331
333
|
if(reputation!=null) lp.reputation[amountData.token.toString()] = reputation;
|
|
332
334
|
|
|
333
|
-
const swapFeeBtc = resp.swapFee * amountOut / (data.getAmount() - totalFee);
|
|
334
|
-
|
|
335
335
|
const quote = new ToBTCLNSwap<T>(this, {
|
|
336
336
|
pricingInfo,
|
|
337
337
|
url: lp.url,
|
|
@@ -528,10 +528,12 @@ export class ToBTCLNWrapper<T extends ChainType> extends IToBTCWrapper<T, ToBTCL
|
|
|
528
528
|
|
|
529
529
|
await this.verifyReturnedData(signer, resp, parsedInvoice, amountData.token, lp, calculatedOptions, data, amountData.amount);
|
|
530
530
|
|
|
531
|
+
const swapFeeBtc = resp.swapFee * amountOut / (data.getAmount() - totalFee);
|
|
532
|
+
|
|
531
533
|
const [pricingInfo, signatureExpiry, reputation] = await Promise.all([
|
|
532
534
|
this.verifyReturnedPrice(
|
|
533
535
|
lp.services[SwapType.TO_BTCLN], true, prepareResp.amount, data.getAmount(),
|
|
534
|
-
amountData.token, {networkFee: resp.maxFee},
|
|
536
|
+
amountData.token, {networkFee: resp.maxFee, swapFeeBtc},
|
|
535
537
|
preFetches.pricePreFetchPromise, preFetches.usdPricePrefetchPromise, abortSignal
|
|
536
538
|
),
|
|
537
539
|
this.verifyReturnedSignature(
|
|
@@ -543,8 +545,6 @@ export class ToBTCLNWrapper<T extends ChainType> extends IToBTCWrapper<T, ToBTCL
|
|
|
543
545
|
|
|
544
546
|
if(reputation!=null) lp.reputation[amountData.token.toString()] = reputation;
|
|
545
547
|
|
|
546
|
-
const swapFeeBtc = resp.swapFee * amountOut / (data.getAmount() - totalFee);
|
|
547
|
-
|
|
548
548
|
const quote = new ToBTCLNSwap<T>(this, {
|
|
549
549
|
pricingInfo,
|
|
550
550
|
url: lp.url,
|
|
@@ -304,11 +304,15 @@ export class ToBTCWrapper<T extends ChainType> extends IToBTCWrapper<T, ToBTCDef
|
|
|
304
304
|
const data: T["Data"] = new (this._swapDataDeserializer(version))(resp.data);
|
|
305
305
|
data.setOfferer(signer);
|
|
306
306
|
|
|
307
|
+
const inputWithoutFees = data.getAmount() - resp.swapFee - resp.networkFee;
|
|
308
|
+
const swapFeeBtc = resp.swapFee * resp.amount / inputWithoutFees;
|
|
309
|
+
const networkFeeBtc = resp.networkFee * resp.amount / inputWithoutFees;
|
|
310
|
+
|
|
307
311
|
this.verifyReturnedData(signer, resp, amountData, lp, _options, data, hash);
|
|
308
312
|
const [pricingInfo, signatureExpiry, reputation] = await Promise.all([
|
|
309
313
|
this.verifyReturnedPrice(
|
|
310
314
|
lp.services[SwapType.TO_BTC], true, resp.amount, data.getAmount(),
|
|
311
|
-
amountData.token, resp, pricePreFetchPromise, usdPricePrefetchPromise, abortController.signal
|
|
315
|
+
amountData.token, {networkFee: resp.networkFee, swapFeeBtc}, pricePreFetchPromise, usdPricePrefetchPromise, abortController.signal
|
|
312
316
|
),
|
|
313
317
|
this.verifyReturnedSignature(signer, data, resp, feeRatePromise[version], signDataPromise, version, abortController.signal),
|
|
314
318
|
reputationPromise
|
|
@@ -317,10 +321,6 @@ export class ToBTCWrapper<T extends ChainType> extends IToBTCWrapper<T, ToBTCDef
|
|
|
317
321
|
|
|
318
322
|
if(reputation!=null) lp.reputation[amountData.token.toString()] = reputation;
|
|
319
323
|
|
|
320
|
-
const inputWithoutFees = data.getAmount() - resp.swapFee - resp.networkFee;
|
|
321
|
-
const swapFeeBtc = resp.swapFee * resp.amount / inputWithoutFees;
|
|
322
|
-
const networkFeeBtc = resp.networkFee * resp.amount / inputWithoutFees
|
|
323
|
-
|
|
324
324
|
const quote = new ToBTCSwap<T>(this, {
|
|
325
325
|
pricingInfo,
|
|
326
326
|
url: lp.url,
|
|
@@ -402,7 +402,10 @@ export class SpvFromBTCSwap<T extends ChainType>
|
|
|
402
402
|
this.pricingInfo.satsBaseFee,
|
|
403
403
|
this.pricingInfo.feePPM,
|
|
404
404
|
this.getOutputWithoutFee().rawAmount,
|
|
405
|
-
this.outputSwapToken
|
|
405
|
+
this.outputSwapToken,
|
|
406
|
+
undefined,
|
|
407
|
+
undefined,
|
|
408
|
+
this.swapFeeBtc
|
|
406
409
|
);
|
|
407
410
|
this.pricingInfo.realPriceUsdPerBitcoin = usdPricePerBtc;
|
|
408
411
|
}
|
|
@@ -68,6 +68,13 @@ export type SpvFromBTCOptions = {
|
|
|
68
68
|
* the settlement gas fee cost)
|
|
69
69
|
*/
|
|
70
70
|
feeSafetyFactor?: number,
|
|
71
|
+
/**
|
|
72
|
+
* Instruct the LP to create a "sticky address" for your destination wallet address. After the first successful
|
|
73
|
+
* swap with that LP, the used bitcoin address will be permanently linked to your destination wallet address. So
|
|
74
|
+
* all subsequent swaps to the same address will yield the same LP deposit bitcoin address. Useful for corporate
|
|
75
|
+
* whitelist-only wallets
|
|
76
|
+
*/
|
|
77
|
+
stickyAddress?: boolean,
|
|
71
78
|
|
|
72
79
|
/**
|
|
73
80
|
* @deprecated Use `maxAllowedBitcoinFeeRate` instead!
|
|
@@ -681,6 +688,7 @@ export class SpvFromBTCWrapper<
|
|
|
681
688
|
gasAmount: _options.gasAmount,
|
|
682
689
|
callerFeeRate: throwIfUndefined(callerFeePrefetchPromise[version], "Caller fee prefetch failed!"),
|
|
683
690
|
frontingFeeRate: 0n,
|
|
691
|
+
stickyAddress: options?.stickyAddress,
|
|
684
692
|
additionalParams
|
|
685
693
|
},
|
|
686
694
|
this._options.postRequestTimeout, abortController.signal, retryCount>0 ? false : undefined
|
|
@@ -700,13 +708,13 @@ export class SpvFromBTCWrapper<
|
|
|
700
708
|
lp.services[SwapType.SPV_VAULT_FROM_BTC],
|
|
701
709
|
false, resp.btcAmountSwap,
|
|
702
710
|
resp.total * (100_000n + callerFeeShare) / 100_000n,
|
|
703
|
-
amountData.token, {}, pricePrefetchPromise, usdPricePrefetchPromise, abortController.signal
|
|
711
|
+
amountData.token, {swapFeeBtc: resp.swapFeeBtc}, pricePrefetchPromise, usdPricePrefetchPromise, abortController.signal
|
|
704
712
|
),
|
|
705
713
|
_options.gasAmount===0n ? Promise.resolve(undefined) : this.verifyReturnedPrice(
|
|
706
714
|
{...lp.services[SwapType.SPV_VAULT_FROM_BTC], swapBaseFee: 0}, //Base fee should be charged only on the amount, not on gas
|
|
707
715
|
false, resp.btcAmountGas,
|
|
708
716
|
resp.totalGas * (100_000n + callerFeeShare) / 100_000n,
|
|
709
|
-
nativeTokenAddress, {}, gasTokenPricePrefetchPromise, usdPricePrefetchPromise, abortController.signal
|
|
717
|
+
nativeTokenAddress, {swapFeeBtc: resp.gasSwapFeeBtc}, gasTokenPricePrefetchPromise, usdPricePrefetchPromise, abortController.signal
|
|
710
718
|
),
|
|
711
719
|
this.verifyReturnedData(resp, amountData, lp, _options, callerFeeShare, bitcoinFeeRatePromise, abortController.signal)
|
|
712
720
|
]);
|
|
@@ -68,7 +68,7 @@ export class LnForGasWrapper<T extends ChainType> extends ISwapWrapper<T, LnForG
|
|
|
68
68
|
{swapFeePPM: 10000, swapBaseFee: 10} :
|
|
69
69
|
lpOrUrl.services[SwapType.TRUSTED_FROM_BTCLN],
|
|
70
70
|
false, amountIn,
|
|
71
|
-
amount, token, {}
|
|
71
|
+
amount, token, {swapFeeBtc: resp.swapFeeSats}
|
|
72
72
|
);
|
|
73
73
|
|
|
74
74
|
const quoteInit: LnForGasSwapInit = {
|
|
@@ -105,7 +105,7 @@ export class OnchainForGasWrapper<T extends ChainType> extends ISwapWrapper<T, O
|
|
|
105
105
|
{swapFeePPM: 10000, swapBaseFee: 10} :
|
|
106
106
|
lpOrUrl.services[SwapType.TRUSTED_FROM_BTC],
|
|
107
107
|
false, resp.amountSats,
|
|
108
|
-
amount, this._chain.getNativeCurrencyAddress(), {}
|
|
108
|
+
amount, this._chain.getNativeCurrencyAddress(), {swapFeeBtc: resp.swapFeeSats}
|
|
109
109
|
);
|
|
110
110
|
|
|
111
111
|
const quote = new OnchainForGasSwap(this, {
|