@atomiqlabs/lp-lib 14.0.0-dev.15 → 14.0.0-dev.17

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.
@@ -108,11 +108,15 @@ class FromBtcAmountAssertions extends AmountAssertions_1.AmountAssertions {
108
108
  amountBDgas = _amountBDgas;
109
109
  }
110
110
  let amountBD;
111
+ let swapFee;
111
112
  if (!requestedAmount.input) {
112
113
  amountBD = await this.swapPricing.getToBtcSwapAmount(requestedAmount.amount, requestedAmount.token, chainIdentifier, true, requestedAmount.pricePrefetch);
113
114
  signal.throwIfAborted();
114
115
  // amt = (amt+base_fee)/(1-fee)
115
- amountBD = (amountBD + fees.baseFee) * 1000000n / (1000000n - fees.feePPM);
116
+ const denominator = (1000000n - fees.feePPM);
117
+ const _amountBD = ((amountBD + fees.baseFee) * 1000000n + denominator - 1n) / denominator;
118
+ swapFee = _amountBD - amountBD;
119
+ amountBD = _amountBD;
116
120
  const tooLow = amountBD < (this.config.min * 95n / 100n);
117
121
  const tooHigh = amountBD > (this.config.max * 105n / 100n);
118
122
  if (tooLow || tooHigh) {
@@ -133,6 +137,7 @@ class FromBtcAmountAssertions extends AmountAssertions_1.AmountAssertions {
133
137
  else {
134
138
  this.checkBtcAmountInBounds(requestedAmount.amount);
135
139
  amountBD = requestedAmount.amount - amountBDgas;
140
+ swapFee = fees.baseFee + ((amountBD * fees.feePPM + 999999n) / 1000000n);
136
141
  if (amountBD < 0n) {
137
142
  throw {
138
143
  code: 20003,
@@ -144,7 +149,6 @@ class FromBtcAmountAssertions extends AmountAssertions_1.AmountAssertions {
144
149
  };
145
150
  }
146
151
  }
147
- const swapFee = fees.baseFee + (amountBD * fees.feePPM / 1000000n);
148
152
  const swapFeeInToken = await this.swapPricing.getFromBtcSwapAmount(swapFee, requestedAmount.token, chainIdentifier, true, requestedAmount.pricePrefetch);
149
153
  signal.throwIfAborted();
150
154
  const gasSwapFeeInToken = gasTokenAmount == null ?
@@ -232,6 +232,8 @@ class ToBtcLnAbs extends ToBtcBaseSwapHandler_1.ToBtcBaseSwapHandler {
232
232
  " maxFee: " + maxFee.toString(10) +
233
233
  " invoice: " + swap.pr);
234
234
  const blockHeight = await this.lightning.getBlockheight();
235
+ swap.payInitiated = true;
236
+ await this.saveSwapData(swap);
235
237
  try {
236
238
  await this.lightning.pay({
237
239
  request: swap.pr,
@@ -12,6 +12,7 @@ export declare enum ToBtcLnSwapState {
12
12
  export declare class ToBtcLnSwapAbs<T extends SwapData = SwapData> extends ToBtcBaseSwap<T, ToBtcLnSwapState> {
13
13
  lnPaymentHash: string;
14
14
  readonly pr: string;
15
+ payInitiated: boolean;
15
16
  secret: string;
16
17
  constructor(chainIdentifier: string, lnPaymentHash: string, pr: string, amountMtokens: bigint, swapFee: bigint, swapFeeInToken: bigint, quotedNetworkFee: bigint, quotedNetworkFeeInToken: bigint);
17
18
  constructor(obj: any);
@@ -27,6 +27,7 @@ class ToBtcLnSwapAbs extends ToBtcBaseSwap_1.ToBtcBaseSwap {
27
27
  this.pr = chainIdOrObj.pr;
28
28
  this.secret = chainIdOrObj.secret;
29
29
  this.lnPaymentHash = chainIdOrObj.lnPaymentHash;
30
+ this.payInitiated = chainIdOrObj.payInitiated;
30
31
  //Compatibility with older versions
31
32
  this.quotedNetworkFee ?? (this.quotedNetworkFee = (0, Utils_1.deserializeBN)(chainIdOrObj.maxFee));
32
33
  this.realNetworkFee ?? (this.realNetworkFee = (0, Utils_1.deserializeBN)(chainIdOrObj.realRoutingFee));
@@ -41,6 +42,7 @@ class ToBtcLnSwapAbs extends ToBtcBaseSwap_1.ToBtcBaseSwap {
41
42
  partialSerialized.pr = this.pr;
42
43
  partialSerialized.lnPaymentHash = this.lnPaymentHash;
43
44
  partialSerialized.secret = this.secret;
45
+ partialSerialized.payInitiated = this.payInitiated;
44
46
  return partialSerialized;
45
47
  }
46
48
  isInitiated() {
@@ -12,6 +12,7 @@ const FromBtcAmountAssertions_1 = require("../assertions/FromBtcAmountAssertions
12
12
  const crypto_1 = require("crypto");
13
13
  const btc_signer_1 = require("@scure/btc-signer");
14
14
  const SpvVaults_1 = require("./SpvVaults");
15
+ const BitcoinUtils_1 = require("../../utils/BitcoinUtils");
15
16
  const TX_MAX_VSIZE = 16 * 1024;
16
17
  class SpvVaultSwapHandler extends SwapHandler_1.SwapHandler {
17
18
  constructor(storageDirectory, vaultStorage, path, chainsData, swapPricing, bitcoin, bitcoinRpc, spvVaultSigner, config) {
@@ -342,7 +343,7 @@ class SpvVaultSwapHandler extends SwapHandler_1.SwapHandler {
342
343
  //Check correct psbt
343
344
  for (let i = 1; i < transaction.inputsLength; i++) { //Skip first vault input
344
345
  const txIn = transaction.getInput(i);
345
- if ((0, btc_signer_1.getInputType)(txIn).txType === "legacy")
346
+ if ((0, BitcoinUtils_1.isLegacyInput)(txIn))
346
347
  throw {
347
348
  code: 20514,
348
349
  msg: "Legacy (pre-segwit) inputs in tx are not allowed!"
@@ -0,0 +1,2 @@
1
+ import { TransactionInput } from "@scure/btc-signer/psbt";
2
+ export declare function isLegacyInput(input: TransactionInput): boolean;
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isLegacyInput = void 0;
4
+ const utxo_1 = require("@scure/btc-signer/utxo");
5
+ const btc_signer_1 = require("@scure/btc-signer");
6
+ function parsePushOpcode(script) {
7
+ if (script[0] === 0x00) {
8
+ return Uint8Array.from([]);
9
+ }
10
+ if (script[0] <= 0x4b) {
11
+ return script.slice(1, 1 + script[0]);
12
+ }
13
+ if (script[0] === 0x4c) {
14
+ return script.slice(2, 2 + script[1]);
15
+ }
16
+ if (script[0] === 0x4d) {
17
+ const length = Buffer.from(script.slice(1, 3)).readUInt16LE();
18
+ return script.slice(3, 3 + length);
19
+ }
20
+ if (script[0] === 0x4e) {
21
+ const length = Buffer.from(script.slice(1, 5)).readUInt32LE();
22
+ return script.slice(5, 5 + length);
23
+ }
24
+ if (script[0] === 0x4f) {
25
+ return Uint8Array.from([0x81]);
26
+ }
27
+ if (script[0] >= 0x51 && script[0] <= 0x60) {
28
+ return Uint8Array.from([script[0] - 0x50]);
29
+ }
30
+ throw new Error("No push opcode detected");
31
+ }
32
+ function isLegacyInput(input) {
33
+ const prevOut = (0, utxo_1.getPrevOut)(input);
34
+ const first = btc_signer_1.OutScript.decode(prevOut.script);
35
+ if (first.type === "tr" || first.type === "wsh" || first.type === "wpkh")
36
+ return false;
37
+ if (first.type === "sh") {
38
+ const redeemScript = input.redeemScript ?? parsePushOpcode(input.finalScriptSig);
39
+ const second = btc_signer_1.OutScript.decode(redeemScript);
40
+ if (second.type === "wsh" || second.type === "wpkh")
41
+ return false;
42
+ }
43
+ return true;
44
+ }
45
+ exports.isLegacyInput = isLegacyInput;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atomiqlabs/lp-lib",
3
- "version": "14.0.0-dev.15",
3
+ "version": "14.0.0-dev.17",
4
4
  "description": "Main functionality implementation for atomiq LP node",
5
5
  "main": "./dist/index.js",
6
6
  "types:": "./dist/index.d.ts",
@@ -166,12 +166,16 @@ export class FromBtcAmountAssertions extends AmountAssertions {
166
166
  }
167
167
 
168
168
  let amountBD: bigint;
169
+ let swapFee: bigint;
169
170
  if(!requestedAmount.input) {
170
171
  amountBD = await this.swapPricing.getToBtcSwapAmount(requestedAmount.amount, requestedAmount.token, chainIdentifier, true, requestedAmount.pricePrefetch);
171
172
  signal.throwIfAborted();
172
173
 
173
174
  // amt = (amt+base_fee)/(1-fee)
174
- amountBD = (amountBD + fees.baseFee) * 1000000n / (1000000n - fees.feePPM);
175
+ const denominator = (1000000n - fees.feePPM);
176
+ const _amountBD = ((amountBD + fees.baseFee) * 1000000n + denominator - 1n) / denominator;
177
+ swapFee = _amountBD - amountBD;
178
+ amountBD = _amountBD;
175
179
 
176
180
  const tooLow = amountBD < (this.config.min * 95n / 100n);
177
181
  const tooHigh = amountBD > (this.config.max * 105n / 100n);
@@ -196,6 +200,7 @@ export class FromBtcAmountAssertions extends AmountAssertions {
196
200
  } else {
197
201
  this.checkBtcAmountInBounds(requestedAmount.amount);
198
202
  amountBD = requestedAmount.amount - amountBDgas;
203
+ swapFee = fees.baseFee + ((amountBD * fees.feePPM + 999_999n) / 1000000n);
199
204
  if(amountBD < 0n) {
200
205
  throw {
201
206
  code: 20003,
@@ -208,7 +213,6 @@ export class FromBtcAmountAssertions extends AmountAssertions {
208
213
  }
209
214
  }
210
215
 
211
- const swapFee = fees.baseFee + (amountBD * fees.feePPM / 1000000n);
212
216
  const swapFeeInToken = await this.swapPricing.getFromBtcSwapAmount(swapFee, requestedAmount.token, chainIdentifier, true, requestedAmount.pricePrefetch);
213
217
  signal.throwIfAborted();
214
218
 
@@ -338,6 +338,8 @@ export class ToBtcLnAbs extends ToBtcBaseSwapHandler<ToBtcLnSwapAbs, ToBtcLnSwap
338
338
 
339
339
  const blockHeight = await this.lightning.getBlockheight();
340
340
 
341
+ swap.payInitiated = true;
342
+ await this.saveSwapData(swap);
341
343
  try {
342
344
  await this.lightning.pay({
343
345
  request: swap.pr,
@@ -17,6 +17,7 @@ export class ToBtcLnSwapAbs<T extends SwapData = SwapData> extends ToBtcBaseSwap
17
17
 
18
18
  lnPaymentHash: string;
19
19
  readonly pr: string;
20
+ payInitiated: boolean;
20
21
 
21
22
  secret: string;
22
23
 
@@ -43,6 +44,7 @@ export class ToBtcLnSwapAbs<T extends SwapData = SwapData> extends ToBtcBaseSwap
43
44
  this.pr = chainIdOrObj.pr;
44
45
  this.secret = chainIdOrObj.secret;
45
46
  this.lnPaymentHash = chainIdOrObj.lnPaymentHash;
47
+ this.payInitiated = chainIdOrObj.payInitiated;
46
48
 
47
49
  //Compatibility with older versions
48
50
  this.quotedNetworkFee ??= deserializeBN(chainIdOrObj.maxFee);
@@ -60,6 +62,7 @@ export class ToBtcLnSwapAbs<T extends SwapData = SwapData> extends ToBtcBaseSwap
60
62
  partialSerialized.pr = this.pr;
61
63
  partialSerialized.lnPaymentHash = this.lnPaymentHash;
62
64
  partialSerialized.secret = this.secret;
65
+ partialSerialized.payInitiated = this.payInitiated;
63
66
  return partialSerialized;
64
67
  }
65
68
 
@@ -29,6 +29,7 @@ import {FromBtcAmountAssertions} from "../assertions/FromBtcAmountAssertions";
29
29
  import {randomBytes} from "crypto";
30
30
  import {getInputType, OutScript, Transaction} from "@scure/btc-signer";
31
31
  import {SpvVaults, VAULT_DUST_AMOUNT} from "./SpvVaults";
32
+ import {isLegacyInput} from "../../utils/BitcoinUtils";
32
33
 
33
34
  export type SpvVaultSwapHandlerConfig = SwapBaseConfig & {
34
35
  vaultsCheckInterval: number,
@@ -471,7 +472,7 @@ export class SpvVaultSwapHandler extends SwapHandler<SpvVaultSwap, SpvVaultSwapS
471
472
  //Check correct psbt
472
473
  for(let i=1;i<transaction.inputsLength;i++) { //Skip first vault input
473
474
  const txIn = transaction.getInput(i);
474
- if(getInputType(txIn).txType==="legacy") throw {
475
+ if(isLegacyInput(txIn)) throw {
475
476
  code: 20514,
476
477
  msg: "Legacy (pre-segwit) inputs in tx are not allowed!"
477
478
  };
@@ -0,0 +1,42 @@
1
+ import {TransactionInput} from "@scure/btc-signer/psbt";
2
+ import {getPrevOut} from "@scure/btc-signer/utxo";
3
+ import {OutScript} from "@scure/btc-signer";
4
+
5
+ function parsePushOpcode(script: Uint8Array): Uint8Array {
6
+ if(script[0]===0x00) {
7
+ return Uint8Array.from([]);
8
+ }
9
+ if(script[0]<=0x4b) {
10
+ return script.slice(1, 1+script[0]);
11
+ }
12
+ if(script[0]===0x4c) {
13
+ return script.slice(2, 2+script[1]);
14
+ }
15
+ if(script[0]===0x4d) {
16
+ const length = Buffer.from(script.slice(1, 3)).readUInt16LE();
17
+ return script.slice(3, 3+length);
18
+ }
19
+ if(script[0]===0x4e) {
20
+ const length = Buffer.from(script.slice(1, 5)).readUInt32LE();
21
+ return script.slice(5, 5+length);
22
+ }
23
+ if(script[0]===0x4f) {
24
+ return Uint8Array.from([0x81]);
25
+ }
26
+ if(script[0]>=0x51 && script[0]<=0x60) {
27
+ return Uint8Array.from([script[0] - 0x50]);
28
+ }
29
+ throw new Error("No push opcode detected");
30
+ }
31
+
32
+ export function isLegacyInput(input: TransactionInput): boolean {
33
+ const prevOut = getPrevOut(input);
34
+ const first = OutScript.decode(prevOut.script);
35
+ if(first.type==="tr" || first.type==="wsh" || first.type==="wpkh") return false;
36
+ if(first.type==="sh") {
37
+ const redeemScript = input.redeemScript ?? parsePushOpcode(input.finalScriptSig);
38
+ const second = OutScript.decode(redeemScript);
39
+ if(second.type==="wsh" || second.type==="wpkh") return false;
40
+ }
41
+ return true;
42
+ }