@xchainjs/xchain-thorchain-query 0.1.0-alpha → 0.1.0-beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,8 +1,6 @@
1
1
  # `@xchainjs/xchain-thorchain-query`
2
2
 
3
- Thorchain-query module to query thorchain for
4
-
5
- ## Modules
3
+ Thorchain-query module to query thorchain for estimation of swaps. Returns a TxDetail object with all the information needed to conduct a swap.
6
4
 
7
5
  ## Installation
8
6
 
@@ -10,10 +8,46 @@ Thorchain-query module to query thorchain for
10
8
  yarn add @xchainjs/xchain-thorchain-query
11
9
  ```
12
10
 
11
+ Following peer dependencies have to be installed into your project. These are not included in `@xchainjs/xchain-thorchain-query`.
12
+
13
+ ```
14
+ yarn add @xchainjs/xchain-client @xchainjs/xchain-util @xchainjs/xchain-midgard @xchainjs/xchain-thornode axios
15
+
16
+ ```
17
+
13
18
  ## Examples
14
19
 
20
+ Estimation example from a swap of 2 BTC to RUNE
21
+
22
+ ```ts
23
+ {
24
+ memo: '=:THOR.RUNE::2071168559999',
25
+ expiry: 2022-09-07T02:16:45.732Z,
26
+ toAddress: '',
27
+ txEstimate: {
28
+ input: '₿ 2',
29
+ totalFees: {
30
+ inboundFee: 'ᚱ 0.02',
31
+ swapFee: 'ᚱ 52.85380999',
32
+ outboundFee: 'ᚱ 0.06',
33
+ affiliateFee: 'ᚱ 0'
34
+ },
35
+ slipPercentage: '0.00246920801878638026',
36
+ netOutput: 'ᚱ 21,352.25318742',
37
+ waitTimeSeconds: '1248',
38
+ canSwap: true,
39
+ errors: []
40
+ }
41
+ }
15
42
  ```
16
43
 
17
44
  ## Documentation
18
45
 
46
+ For bash exmples, see example folder at the base of this repository xchainjs/xchainjs-lib.
47
+
48
+ ```
49
+ ### [`xchain-thorchain-query`](http://docs.xchainjs.org/xchain-thorchain-query/)
50
+
51
+ [`How xchain-thorchain-query works`](http://docs.xchainjs.org/xchain-thorchain-query/how-it-works.html)\
52
+ [`How to use xchain-thorchain-query`](http://docs.xchainjs.org/xchain-thorchain-query/how-to-use.html)
19
53
  ```
@@ -25,8 +25,8 @@ export declare class CryptoAmount {
25
25
  * This guard protects against trying to perform math with different assets
26
26
  *
27
27
  * Example.
28
- * const x = new CryptoAmount(baseAmount(1),AssetBTC)
29
- * const y = new CryptoAmount(baseAmount(1),AssetETH)
28
+ * const x = new CryptoAmount(assetAmount(1),AssetBTC)
29
+ * const y = new CryptoAmount(assetAmount(1),AssetETH)
30
30
  *
31
31
  * x.plus(y) <- will throw error "cannot perform math on 2 diff assets BTC.BTC ETH.ETH
32
32
  *
package/lib/index.esm.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ObservedTxStatusEnum, TransactionsApi, Configuration as Configuration$1, QueueApi, NetworkApi, PoolsApi } from '@xchainjs/xchain-thornode';
2
- import { formatAssetAmountCurrency, baseToAsset, eqAsset, assetToString, baseAmount, AssetRuneNative, Chain, AssetAtom, AssetLUNA, AssetAVAX, AssetETH, AssetBNB, AssetDOGE, AssetLTC, AssetBCH, AssetBTC, AvalancheChain, TerraChain, DOGEChain, LTCChain, BCHChain, CosmosChain, THORChain, ETHChain, BTCChain, BNBChain, isAssetRuneNative, assetFromString, assetAmount, assetToBase } from '@xchainjs/xchain-util';
2
+ import { assetToBase, formatAssetAmountCurrency, baseToAsset, eqAsset, assetToString, baseAmount, AssetRuneNative, Chain, AssetAtom, AssetLUNA, AssetAVAX, AssetETH, AssetBNB, AssetDOGE, AssetLTC, AssetBCH, AssetBTC, AvalancheChain, TerraChain, DOGEChain, LTCChain, BCHChain, CosmosChain, THORChain, ETHChain, BTCChain, BNBChain, isAssetRuneNative, assetFromString } from '@xchainjs/xchain-util';
3
3
  import BigNumber$1, { BigNumber } from 'bignumber.js';
4
4
  import { Network } from '@xchainjs/xchain-client';
5
5
  import { MidgardApi, Configuration } from '@xchainjs/xchain-midgard';
@@ -85,55 +85,55 @@ class CryptoAmount {
85
85
  }
86
86
  plus(v) {
87
87
  this.check(v);
88
- const baseAmountResult = this.baseAmount.plus(v.baseAmount);
89
- return new CryptoAmount(baseAmountResult, this.asset);
88
+ const assetAmountResult = assetToBase(this.assetAmount.plus(v.assetAmount));
89
+ return new CryptoAmount(assetAmountResult, this.asset);
90
90
  }
91
91
  minus(v) {
92
92
  this.check(v);
93
- const baseAmountResult = this.baseAmount.minus(v.baseAmount);
94
- return new CryptoAmount(baseAmountResult, this.asset);
93
+ const assetAmountResult = assetToBase(this.assetAmount.minus(v.assetAmount));
94
+ return new CryptoAmount(assetAmountResult, this.asset);
95
95
  }
96
96
  times(v) {
97
97
  this.check(v);
98
98
  if (v instanceof CryptoAmount) {
99
- const baseAmountResult = this.baseAmount.times(v.baseAmount);
100
- return new CryptoAmount(baseAmountResult, this.asset);
99
+ const assetAmountResult = assetToBase(this.assetAmount.times(v.assetAmount));
100
+ return new CryptoAmount(assetAmountResult, this.asset);
101
101
  }
102
102
  else {
103
- const baseAmountResult = this.baseAmount.times(v);
104
- return new CryptoAmount(baseAmountResult, this.asset);
103
+ const assetAmountResult = assetToBase(this.assetAmount.times(v));
104
+ return new CryptoAmount(assetAmountResult, this.asset);
105
105
  }
106
106
  }
107
107
  div(v) {
108
108
  this.check(v);
109
109
  if (v instanceof CryptoAmount) {
110
- const baseAmountResult = this.baseAmount.div(v.baseAmount);
111
- return new CryptoAmount(baseAmountResult, this.asset);
110
+ const assetAmountResult = assetToBase(this.assetAmount.div(v.assetAmount));
111
+ return new CryptoAmount(assetAmountResult, this.asset);
112
112
  }
113
113
  else {
114
- const baseAmountResult = this.baseAmount.div(v);
115
- return new CryptoAmount(baseAmountResult, this.asset);
114
+ const assetAmountResult = assetToBase(this.assetAmount.div(v));
115
+ return new CryptoAmount(assetAmountResult, this.asset);
116
116
  }
117
117
  }
118
118
  lt(v) {
119
119
  this.check(v);
120
- return this.baseAmount.lt(v.baseAmount);
120
+ return this.assetAmount.lt(v.assetAmount);
121
121
  }
122
122
  lte(v) {
123
123
  this.check(v);
124
- return this.baseAmount.lte(v.baseAmount);
124
+ return this.assetAmount.lte(v.assetAmount);
125
125
  }
126
126
  gt(v) {
127
127
  this.check(v);
128
- return this.baseAmount.gt(v.baseAmount);
128
+ return this.assetAmount.gt(v.assetAmount);
129
129
  }
130
130
  gte(v) {
131
131
  this.check(v);
132
- return this.baseAmount.gte(v.baseAmount);
132
+ return this.assetAmount.gte(v.assetAmount);
133
133
  }
134
134
  eq(v) {
135
135
  this.check(v);
136
- return this.baseAmount.eq(v.baseAmount);
136
+ return this.assetAmount.eq(v.assetAmount);
137
137
  }
138
138
  formatedAssetString() {
139
139
  return formatAssetAmountCurrency({
@@ -152,8 +152,8 @@ class CryptoAmount {
152
152
  * This guard protects against trying to perform math with different assets
153
153
  *
154
154
  * Example.
155
- * const x = new CryptoAmount(baseAmount(1),AssetBTC)
156
- * const y = new CryptoAmount(baseAmount(1),AssetETH)
155
+ * const x = new CryptoAmount(assetAmount(1),AssetBTC)
156
+ * const y = new CryptoAmount(assetAmount(1),AssetETH)
157
157
  *
158
158
  * x.plus(y) <- will throw error "cannot perform math on 2 diff assets BTC.BTC ETH.ETH
159
159
  *
@@ -178,6 +178,13 @@ var TxStage;
178
178
  TxStage[TxStage["OUTBOUND_CHAIN_CONFIRMED"] = 5] = "OUTBOUND_CHAIN_CONFIRMED";
179
179
  })(TxStage || (TxStage = {}));
180
180
 
181
+ const getBaseAmountWithDiffDecimals = (inputAmount, outDecimals) => {
182
+ const inDecimals = inputAmount.baseAmount.decimal;
183
+ let baseAmountOut = inputAmount.baseAmount.amount();
184
+ const adjustDecimals = outDecimals - inDecimals;
185
+ baseAmountOut = baseAmountOut.times(Math.pow(10, adjustDecimals));
186
+ return baseAmount(baseAmountOut, outDecimals).amount();
187
+ };
181
188
  /**
182
189
  *
183
190
  * @param inputAmount - amount to swap
@@ -188,16 +195,18 @@ var TxStage;
188
195
  const getSwapFee = (inputAmount, pool, toRune) => {
189
196
  // formula: (x * x * Y) / (x + X) ^ 2
190
197
  // const isInputRune = isAssetRuneNative(inputAmount.asset)
191
- const x = inputAmount.baseAmount.amount();
198
+ const x = getBaseAmountWithDiffDecimals(inputAmount, 8);
192
199
  const X = toRune ? pool.assetBalance.amount() : pool.runeBalance.amount(); // input is asset if toRune
193
200
  const Y = toRune ? pool.runeBalance.amount() : pool.assetBalance.amount(); // output is rune if toRune
194
201
  const units = toRune ? AssetRuneNative : pool.asset;
195
- const decimals = toRune || !pool.decimals ? 8 : pool.decimals;
196
202
  const numerator = x.times(x).multipliedBy(Y);
197
203
  const denominator = x.plus(X).pow(2);
198
204
  const result = numerator.div(denominator);
199
- const swapFee = new CryptoAmount(baseAmount(result, decimals), units);
200
- // console.log(` swapFee ${swapFee.assetAmountFixedString()} ${assetToString(units)}`)
205
+ const eightDecimalResult = new CryptoAmount(baseAmount(result), units);
206
+ const decimals = toRune ? 8 : inputAmount.baseAmount.decimal;
207
+ const baseOut = getBaseAmountWithDiffDecimals(eightDecimalResult, decimals);
208
+ const swapFee = new CryptoAmount(baseAmount(baseOut, decimals), units);
209
+ //console.log(` swapFee ${swapFee.assetAmountFixedString()} `)
201
210
  return swapFee;
202
211
  };
203
212
  /**
@@ -210,7 +219,7 @@ const getSwapFee = (inputAmount, pool, toRune) => {
210
219
  */
211
220
  const getSwapSlip = (inputAmount, pool, toRune) => {
212
221
  // formula: (x) / (x + X)
213
- const x = inputAmount.baseAmount.amount();
222
+ const x = getBaseAmountWithDiffDecimals(inputAmount, 8);
214
223
  const X = toRune ? pool.assetBalance.amount() : pool.runeBalance.amount(); // input is asset if toRune
215
224
  const result = x.div(x.plus(X));
216
225
  return new BigNumber(result);
@@ -224,15 +233,18 @@ const getSwapSlip = (inputAmount, pool, toRune) => {
224
233
  */
225
234
  const getSwapOutput = (inputAmount, pool, toRune) => {
226
235
  // formula: (x * X * Y) / (x + X) ^ 2
227
- const x = inputAmount.baseAmount.amount();
236
+ const x = getBaseAmountWithDiffDecimals(inputAmount, 8);
228
237
  const X = toRune ? pool.assetBalance.amount() : pool.runeBalance.amount(); // input is asset if toRune
229
238
  const Y = toRune ? pool.runeBalance.amount() : pool.assetBalance.amount(); // output is rune if toRune
230
239
  const units = toRune ? AssetRuneNative : pool.asset;
231
- const decimals = toRune || !pool.decimals ? 8 : pool.decimals;
240
+ // const decimals = toRune || !pool.decimals ? 8 : pool.decimals
232
241
  const numerator = x.times(X).times(Y);
233
242
  const denominator = x.plus(X).pow(2);
234
243
  const result = numerator.div(denominator);
235
- return new CryptoAmount(baseAmount(result, decimals), units);
244
+ const eightDecimalResult = new CryptoAmount(baseAmount(result), units);
245
+ const decimals = toRune ? 8 : inputAmount.baseAmount.decimal;
246
+ const baseOut = getBaseAmountWithDiffDecimals(eightDecimalResult, decimals);
247
+ return new CryptoAmount(baseAmount(baseOut, decimals), units);
236
248
  };
237
249
  const getDoubleSwapOutput = (inputAmount, pool1, pool2) => {
238
250
  // formula: getSwapOutput(pool1) => getSwapOutput(pool2)
@@ -329,10 +341,10 @@ const calcNetworkFee = (asset, gasRate) => {
329
341
  const gasRateinAVAXGwei = gasRate;
330
342
  const gasRateinAVAXWei = baseAmount(gasRateinAVAXGwei.multipliedBy(Math.pow(10, 9)), 18);
331
343
  if (eqAsset(asset, AssetAVAX)) {
332
- return new CryptoAmount(gasRateinAVAXWei.times(21000), AssetETH);
344
+ return new CryptoAmount(gasRateinAVAXWei.times(21000), AssetAVAX);
333
345
  }
334
346
  else {
335
- return new CryptoAmount(gasRateinAVAXWei.times(70000), AssetETH);
347
+ return new CryptoAmount(gasRateinAVAXWei.times(70000), AssetAVAX);
336
348
  }
337
349
  case Chain.Terra:
338
350
  return new CryptoAmount(baseAmount(gasRate), AssetLUNA);
@@ -431,23 +443,47 @@ class ThorchainQuery {
431
443
 
432
444
  * @returns The SwapEstimate
433
445
  */
434
- estimateSwap(params, destinationAddress = '', affiliateAddress = '', interfaceID = 999) {
446
+ estimateSwap({ input, destinationAsset, destinationAddress, affiliateAddress = '', interfaceID = 999, affiliateFeePercent = 0, slipLimit, }) {
435
447
  return __awaiter(this, void 0, void 0, function* () {
436
- this.isValidSwap(params);
448
+ this.isValidSwap({
449
+ input,
450
+ destinationAsset,
451
+ destinationAddress,
452
+ affiliateAddress,
453
+ interfaceID,
454
+ affiliateFeePercent,
455
+ slipLimit,
456
+ });
437
457
  const inboundDetails = yield this.thorchainCache.getInboundDetails();
438
- const sourceInboundDetails = inboundDetails[params.input.asset.chain];
458
+ const sourceInboundDetails = inboundDetails[input.asset.chain];
439
459
  // console.log(JSON.stringify(sourceInboundDetails, null, 2))
440
- const destinationInboundDetails = inboundDetails[params.destinationAsset.chain];
460
+ const destinationInboundDetails = inboundDetails[destinationAsset.chain];
441
461
  // console.log(JSON.stringify(destinationInboundDetails, null, 2))
442
- const swapEstimate = yield this.calcSwapEstimate(params, sourceInboundDetails, destinationInboundDetails);
462
+ const swapEstimate = yield this.calcSwapEstimate({
463
+ input,
464
+ destinationAsset,
465
+ destinationAddress,
466
+ affiliateAddress,
467
+ interfaceID,
468
+ affiliateFeePercent,
469
+ slipLimit,
470
+ }, sourceInboundDetails, destinationInboundDetails);
443
471
  // Remove any affiliateFee. netInput * affiliateFee (%age) of the destination asset type
444
- const affiliateFee = params.input.baseAmount.times(params.affiliateFeePercent || 0);
472
+ const affiliateFee = input.baseAmount.times(affiliateFeePercent || 0);
445
473
  // Calculate expiry time
446
474
  const currentDatetime = new Date();
447
475
  const minutesToAdd = 15;
448
476
  const expiryDatetime = new Date(currentDatetime.getTime() + minutesToAdd * 60000);
449
477
  // Check for errors
450
- const errors = yield this.getSwapEstimateErrors(params, swapEstimate, sourceInboundDetails, destinationInboundDetails);
478
+ const errors = yield this.getSwapEstimateErrors({
479
+ input,
480
+ destinationAsset,
481
+ destinationAddress,
482
+ affiliateAddress,
483
+ interfaceID,
484
+ affiliateFeePercent,
485
+ slipLimit,
486
+ }, swapEstimate, sourceInboundDetails, destinationInboundDetails);
451
487
  const txDetails = {
452
488
  memo: '',
453
489
  toAddress: '',
@@ -461,26 +497,26 @@ class ThorchainQuery {
461
497
  else {
462
498
  txDetails.txEstimate.canSwap = true;
463
499
  // Retrieve inbound Asgard address.
464
- const inboundAsgard = (yield this.thorchainCache.getInboundAddressesItems())[params.input.asset.chain];
500
+ const inboundAsgard = (yield this.thorchainCache.getInboundAddressesItems())[input.asset.chain];
465
501
  txDetails.toAddress = (inboundAsgard === null || inboundAsgard === void 0 ? void 0 : inboundAsgard.address) || '';
466
502
  // Work out LIM from the slip percentage
467
503
  let limPercentage = BN_1;
468
- if (params.slipLimit) {
469
- limPercentage = BN_1.minus(params.slipLimit || 1);
504
+ if (slipLimit) {
505
+ limPercentage = BN_1.minus(slipLimit || 1);
470
506
  } // else allowed slip is 100%
471
507
  const limAssetAmount = swapEstimate.netOutput.times(limPercentage);
472
- const inboundDelay = yield this.confCounting(params.input);
508
+ const inboundDelay = yield this.confCounting(input);
473
509
  const outboundDelay = yield this.outboundDelay(limAssetAmount);
474
510
  txDetails.txEstimate.waitTimeSeconds = outboundDelay + inboundDelay;
475
511
  // Construct memo
476
512
  txDetails.memo = this.constructSwapMemo({
477
- input: params.input,
478
- destinationAsset: params.destinationAsset,
513
+ input: input,
514
+ destinationAsset: destinationAsset,
479
515
  limit: limAssetAmount.baseAmount,
480
- destinationAddress,
481
- affiliateAddress,
516
+ destinationAddress: destinationAddress,
517
+ affiliateAddress: affiliateAddress,
482
518
  affiliateFee,
483
- interfaceID,
519
+ interfaceID: interfaceID,
484
520
  });
485
521
  }
486
522
  return txDetails;
@@ -512,18 +548,24 @@ class ThorchainQuery {
512
548
  */
513
549
  calcSwapEstimate(params, sourceInboundDetails, destinationInboundDetails) {
514
550
  return __awaiter(this, void 0, void 0, function* () {
515
- //NOTE need to convert the asset to 8 decimals places for all calcs
516
- const input = yield this.thorchainCache.convert(params.input, params.input.asset);
517
- const inputInRune = yield this.thorchainCache.convert(input, AssetRuneNative);
551
+ // NOTE need to convert the asset to 8 decimals places for all calcs
552
+ const DEFAULT_THORCHAIN_DECIMALS = 8;
553
+ // If input is already in 8 decimals skip the convert
554
+ const input = params.input.baseAmount.decimal === DEFAULT_THORCHAIN_DECIMALS
555
+ ? params.input
556
+ : yield this.thorchainCache.convert(params.input, params.input.asset);
557
+ // If asset is already rune native, skip the convert
558
+ const inputInRune = input.asset === AssetRuneNative ? input : yield this.thorchainCache.convert(input, AssetRuneNative);
518
559
  const inboundFeeInAsset = calcNetworkFee(input.asset, sourceInboundDetails.gas_rate);
519
560
  let outboundFeeInAsset = calcNetworkFee(params.destinationAsset, destinationInboundDetails.gas_rate);
520
561
  outboundFeeInAsset = outboundFeeInAsset.times(3);
562
+ // convert fees to rune
521
563
  const inboundFeeInRune = yield this.thorchainCache.convert(inboundFeeInAsset, AssetRuneNative);
522
564
  let outboundFeeInRune = yield this.thorchainCache.convert(outboundFeeInAsset, AssetRuneNative);
523
565
  // ---------- Remove Fees from inbound before doing the swap -----------
524
- // TODO confirm with chris about this change
525
- // const inputMinusInboundFeeInRune = inputInRune.minus(inboundFeeInRune)
526
- const inputMinusInboundFeeInRune = inputInRune;
566
+ // TODO confirm with chris about this change, was there a reason why this was commented out?
567
+ const inputMinusInboundFeeInRune = inputInRune.minus(inboundFeeInRune);
568
+ //>//const inputMinusInboundFeeInRune = inputInRune
527
569
  // remove any affiliateFee. netInput * affiliateFee (%age) of the destination asset type
528
570
  const affiliateFeeInRune = inputMinusInboundFeeInRune.times(params.affiliateFeePercent || 0);
529
571
  // remove the affiliate fee from the input.
@@ -543,7 +585,7 @@ class ThorchainQuery {
543
585
  outboundFeeInRune = yield this.convert(newFee, AssetRuneNative);
544
586
  }
545
587
  }
546
- // Now calculate swapfee based on inputNetAmount
588
+ // Now calculate swap output based on inputNetAmount
547
589
  const swapOutput = yield this.thorchainCache.getExpectedSwapOutput(inputNetInAsset, params.destinationAsset);
548
590
  const swapFeeInRune = yield this.thorchainCache.convert(swapOutput.swapFee, AssetRuneNative);
549
591
  const outputInRune = yield this.thorchainCache.convert(swapOutput.output, AssetRuneNative);
@@ -1226,23 +1268,35 @@ class ThorchainCache {
1226
1268
  * Ex. convert(input:100 BUSD, outAsset: BTC) -> 0.0001234 BTC
1227
1269
  *
1228
1270
  * @param input - amount/asset to convert to outAsset
1229
- * @param ouAsset - the Asset you want to convert to
1271
+ * @param outAsset - the Asset you want to convert to
1230
1272
  * @returns CryptoAmount of input
1231
1273
  */
1232
1274
  convert(input, outAsset) {
1233
- var _a;
1234
1275
  return __awaiter(this, void 0, void 0, function* () {
1235
1276
  const exchangeRate = yield this.getExchangeRate(input.asset, outAsset);
1236
- let decimals = DEFAULT_THORCHAIN_DECIMALS;
1237
- if (!isAssetRuneNative(outAsset)) {
1238
- const pool = yield this.getPoolForAsset(outAsset);
1239
- decimals = (_a = pool.decimals) !== null && _a !== void 0 ? _a : DEFAULT_THORCHAIN_DECIMALS;
1240
- }
1241
- const amt = assetAmount(input.assetAmount.times(exchangeRate).amount().toFixed(), decimals);
1242
- const result = new CryptoAmount(assetToBase(amt), outAsset);
1277
+ const outDecimals = yield this.getDecimalForAsset(outAsset);
1278
+ const inDecimals = input.baseAmount.decimal;
1279
+ let baseAmountOut = input.baseAmount.times(exchangeRate).amount();
1280
+ const adjustDecimals = outDecimals - inDecimals;
1281
+ baseAmountOut = baseAmountOut.times(Math.pow(10, adjustDecimals));
1282
+ const amt = baseAmount(baseAmountOut, outDecimals);
1283
+ const result = new CryptoAmount(amt, outAsset);
1284
+ // console.log(
1285
+ // `${input.formatedAssetString()} ${input.asset.ticker} = ${result.formatedAssetString()} ${outAsset.ticker}`,
1286
+ // )
1243
1287
  return result;
1244
1288
  });
1245
1289
  }
1290
+ getDecimalForAsset(asset) {
1291
+ var _a;
1292
+ return __awaiter(this, void 0, void 0, function* () {
1293
+ if (!isAssetRuneNative(asset)) {
1294
+ const pool = yield this.getPoolForAsset(asset);
1295
+ return (_a = pool.decimals) !== null && _a !== void 0 ? _a : DEFAULT_THORCHAIN_DECIMALS;
1296
+ }
1297
+ return DEFAULT_THORCHAIN_DECIMALS;
1298
+ });
1299
+ }
1246
1300
  getRouterAddressForChain(chain) {
1247
1301
  return __awaiter(this, void 0, void 0, function* () {
1248
1302
  const inboundAsgard = (yield this.getInboundAddressesItems())[chain];
@@ -1699,6 +1753,7 @@ class Thornode {
1699
1753
  return __awaiter(this, void 0, void 0, function* () {
1700
1754
  for (const api of this.poolsApi) {
1701
1755
  try {
1756
+ // console.log(console.log(JSON.stringify(api, null, 2)))
1702
1757
  const pools = yield api.pools();
1703
1758
  return pools.data;
1704
1759
  }
package/lib/index.js CHANGED
@@ -95,55 +95,55 @@ class CryptoAmount {
95
95
  }
96
96
  plus(v) {
97
97
  this.check(v);
98
- const baseAmountResult = this.baseAmount.plus(v.baseAmount);
99
- return new CryptoAmount(baseAmountResult, this.asset);
98
+ const assetAmountResult = xchainUtil.assetToBase(this.assetAmount.plus(v.assetAmount));
99
+ return new CryptoAmount(assetAmountResult, this.asset);
100
100
  }
101
101
  minus(v) {
102
102
  this.check(v);
103
- const baseAmountResult = this.baseAmount.minus(v.baseAmount);
104
- return new CryptoAmount(baseAmountResult, this.asset);
103
+ const assetAmountResult = xchainUtil.assetToBase(this.assetAmount.minus(v.assetAmount));
104
+ return new CryptoAmount(assetAmountResult, this.asset);
105
105
  }
106
106
  times(v) {
107
107
  this.check(v);
108
108
  if (v instanceof CryptoAmount) {
109
- const baseAmountResult = this.baseAmount.times(v.baseAmount);
110
- return new CryptoAmount(baseAmountResult, this.asset);
109
+ const assetAmountResult = xchainUtil.assetToBase(this.assetAmount.times(v.assetAmount));
110
+ return new CryptoAmount(assetAmountResult, this.asset);
111
111
  }
112
112
  else {
113
- const baseAmountResult = this.baseAmount.times(v);
114
- return new CryptoAmount(baseAmountResult, this.asset);
113
+ const assetAmountResult = xchainUtil.assetToBase(this.assetAmount.times(v));
114
+ return new CryptoAmount(assetAmountResult, this.asset);
115
115
  }
116
116
  }
117
117
  div(v) {
118
118
  this.check(v);
119
119
  if (v instanceof CryptoAmount) {
120
- const baseAmountResult = this.baseAmount.div(v.baseAmount);
121
- return new CryptoAmount(baseAmountResult, this.asset);
120
+ const assetAmountResult = xchainUtil.assetToBase(this.assetAmount.div(v.assetAmount));
121
+ return new CryptoAmount(assetAmountResult, this.asset);
122
122
  }
123
123
  else {
124
- const baseAmountResult = this.baseAmount.div(v);
125
- return new CryptoAmount(baseAmountResult, this.asset);
124
+ const assetAmountResult = xchainUtil.assetToBase(this.assetAmount.div(v));
125
+ return new CryptoAmount(assetAmountResult, this.asset);
126
126
  }
127
127
  }
128
128
  lt(v) {
129
129
  this.check(v);
130
- return this.baseAmount.lt(v.baseAmount);
130
+ return this.assetAmount.lt(v.assetAmount);
131
131
  }
132
132
  lte(v) {
133
133
  this.check(v);
134
- return this.baseAmount.lte(v.baseAmount);
134
+ return this.assetAmount.lte(v.assetAmount);
135
135
  }
136
136
  gt(v) {
137
137
  this.check(v);
138
- return this.baseAmount.gt(v.baseAmount);
138
+ return this.assetAmount.gt(v.assetAmount);
139
139
  }
140
140
  gte(v) {
141
141
  this.check(v);
142
- return this.baseAmount.gte(v.baseAmount);
142
+ return this.assetAmount.gte(v.assetAmount);
143
143
  }
144
144
  eq(v) {
145
145
  this.check(v);
146
- return this.baseAmount.eq(v.baseAmount);
146
+ return this.assetAmount.eq(v.assetAmount);
147
147
  }
148
148
  formatedAssetString() {
149
149
  return xchainUtil.formatAssetAmountCurrency({
@@ -162,8 +162,8 @@ class CryptoAmount {
162
162
  * This guard protects against trying to perform math with different assets
163
163
  *
164
164
  * Example.
165
- * const x = new CryptoAmount(baseAmount(1),AssetBTC)
166
- * const y = new CryptoAmount(baseAmount(1),AssetETH)
165
+ * const x = new CryptoAmount(assetAmount(1),AssetBTC)
166
+ * const y = new CryptoAmount(assetAmount(1),AssetETH)
167
167
  *
168
168
  * x.plus(y) <- will throw error "cannot perform math on 2 diff assets BTC.BTC ETH.ETH
169
169
  *
@@ -187,6 +187,13 @@ class CryptoAmount {
187
187
  TxStage[TxStage["OUTBOUND_CHAIN_CONFIRMED"] = 5] = "OUTBOUND_CHAIN_CONFIRMED";
188
188
  })(exports.TxStage || (exports.TxStage = {}));
189
189
 
190
+ const getBaseAmountWithDiffDecimals = (inputAmount, outDecimals) => {
191
+ const inDecimals = inputAmount.baseAmount.decimal;
192
+ let baseAmountOut = inputAmount.baseAmount.amount();
193
+ const adjustDecimals = outDecimals - inDecimals;
194
+ baseAmountOut = baseAmountOut.times(Math.pow(10, adjustDecimals));
195
+ return xchainUtil.baseAmount(baseAmountOut, outDecimals).amount();
196
+ };
190
197
  /**
191
198
  *
192
199
  * @param inputAmount - amount to swap
@@ -197,16 +204,18 @@ class CryptoAmount {
197
204
  const getSwapFee = (inputAmount, pool, toRune) => {
198
205
  // formula: (x * x * Y) / (x + X) ^ 2
199
206
  // const isInputRune = isAssetRuneNative(inputAmount.asset)
200
- const x = inputAmount.baseAmount.amount();
207
+ const x = getBaseAmountWithDiffDecimals(inputAmount, 8);
201
208
  const X = toRune ? pool.assetBalance.amount() : pool.runeBalance.amount(); // input is asset if toRune
202
209
  const Y = toRune ? pool.runeBalance.amount() : pool.assetBalance.amount(); // output is rune if toRune
203
210
  const units = toRune ? xchainUtil.AssetRuneNative : pool.asset;
204
- const decimals = toRune || !pool.decimals ? 8 : pool.decimals;
205
211
  const numerator = x.times(x).multipliedBy(Y);
206
212
  const denominator = x.plus(X).pow(2);
207
213
  const result = numerator.div(denominator);
208
- const swapFee = new CryptoAmount(xchainUtil.baseAmount(result, decimals), units);
209
- // console.log(` swapFee ${swapFee.assetAmountFixedString()} ${assetToString(units)}`)
214
+ const eightDecimalResult = new CryptoAmount(xchainUtil.baseAmount(result), units);
215
+ const decimals = toRune ? 8 : inputAmount.baseAmount.decimal;
216
+ const baseOut = getBaseAmountWithDiffDecimals(eightDecimalResult, decimals);
217
+ const swapFee = new CryptoAmount(xchainUtil.baseAmount(baseOut, decimals), units);
218
+ //console.log(` swapFee ${swapFee.assetAmountFixedString()} `)
210
219
  return swapFee;
211
220
  };
212
221
  /**
@@ -219,7 +228,7 @@ const getSwapFee = (inputAmount, pool, toRune) => {
219
228
  */
220
229
  const getSwapSlip = (inputAmount, pool, toRune) => {
221
230
  // formula: (x) / (x + X)
222
- const x = inputAmount.baseAmount.amount();
231
+ const x = getBaseAmountWithDiffDecimals(inputAmount, 8);
223
232
  const X = toRune ? pool.assetBalance.amount() : pool.runeBalance.amount(); // input is asset if toRune
224
233
  const result = x.div(x.plus(X));
225
234
  return new BigNumber.BigNumber(result);
@@ -233,15 +242,18 @@ const getSwapSlip = (inputAmount, pool, toRune) => {
233
242
  */
234
243
  const getSwapOutput = (inputAmount, pool, toRune) => {
235
244
  // formula: (x * X * Y) / (x + X) ^ 2
236
- const x = inputAmount.baseAmount.amount();
245
+ const x = getBaseAmountWithDiffDecimals(inputAmount, 8);
237
246
  const X = toRune ? pool.assetBalance.amount() : pool.runeBalance.amount(); // input is asset if toRune
238
247
  const Y = toRune ? pool.runeBalance.amount() : pool.assetBalance.amount(); // output is rune if toRune
239
248
  const units = toRune ? xchainUtil.AssetRuneNative : pool.asset;
240
- const decimals = toRune || !pool.decimals ? 8 : pool.decimals;
249
+ // const decimals = toRune || !pool.decimals ? 8 : pool.decimals
241
250
  const numerator = x.times(X).times(Y);
242
251
  const denominator = x.plus(X).pow(2);
243
252
  const result = numerator.div(denominator);
244
- return new CryptoAmount(xchainUtil.baseAmount(result, decimals), units);
253
+ const eightDecimalResult = new CryptoAmount(xchainUtil.baseAmount(result), units);
254
+ const decimals = toRune ? 8 : inputAmount.baseAmount.decimal;
255
+ const baseOut = getBaseAmountWithDiffDecimals(eightDecimalResult, decimals);
256
+ return new CryptoAmount(xchainUtil.baseAmount(baseOut, decimals), units);
245
257
  };
246
258
  const getDoubleSwapOutput = (inputAmount, pool1, pool2) => {
247
259
  // formula: getSwapOutput(pool1) => getSwapOutput(pool2)
@@ -338,10 +350,10 @@ const calcNetworkFee = (asset, gasRate) => {
338
350
  const gasRateinAVAXGwei = gasRate;
339
351
  const gasRateinAVAXWei = xchainUtil.baseAmount(gasRateinAVAXGwei.multipliedBy(Math.pow(10, 9)), 18);
340
352
  if (xchainUtil.eqAsset(asset, xchainUtil.AssetAVAX)) {
341
- return new CryptoAmount(gasRateinAVAXWei.times(21000), xchainUtil.AssetETH);
353
+ return new CryptoAmount(gasRateinAVAXWei.times(21000), xchainUtil.AssetAVAX);
342
354
  }
343
355
  else {
344
- return new CryptoAmount(gasRateinAVAXWei.times(70000), xchainUtil.AssetETH);
356
+ return new CryptoAmount(gasRateinAVAXWei.times(70000), xchainUtil.AssetAVAX);
345
357
  }
346
358
  case xchainUtil.Chain.Terra:
347
359
  return new CryptoAmount(xchainUtil.baseAmount(gasRate), xchainUtil.AssetLUNA);
@@ -440,23 +452,47 @@ class ThorchainQuery {
440
452
 
441
453
  * @returns The SwapEstimate
442
454
  */
443
- estimateSwap(params, destinationAddress = '', affiliateAddress = '', interfaceID = 999) {
455
+ estimateSwap({ input, destinationAsset, destinationAddress, affiliateAddress = '', interfaceID = 999, affiliateFeePercent = 0, slipLimit, }) {
444
456
  return __awaiter(this, void 0, void 0, function* () {
445
- this.isValidSwap(params);
457
+ this.isValidSwap({
458
+ input,
459
+ destinationAsset,
460
+ destinationAddress,
461
+ affiliateAddress,
462
+ interfaceID,
463
+ affiliateFeePercent,
464
+ slipLimit,
465
+ });
446
466
  const inboundDetails = yield this.thorchainCache.getInboundDetails();
447
- const sourceInboundDetails = inboundDetails[params.input.asset.chain];
467
+ const sourceInboundDetails = inboundDetails[input.asset.chain];
448
468
  // console.log(JSON.stringify(sourceInboundDetails, null, 2))
449
- const destinationInboundDetails = inboundDetails[params.destinationAsset.chain];
469
+ const destinationInboundDetails = inboundDetails[destinationAsset.chain];
450
470
  // console.log(JSON.stringify(destinationInboundDetails, null, 2))
451
- const swapEstimate = yield this.calcSwapEstimate(params, sourceInboundDetails, destinationInboundDetails);
471
+ const swapEstimate = yield this.calcSwapEstimate({
472
+ input,
473
+ destinationAsset,
474
+ destinationAddress,
475
+ affiliateAddress,
476
+ interfaceID,
477
+ affiliateFeePercent,
478
+ slipLimit,
479
+ }, sourceInboundDetails, destinationInboundDetails);
452
480
  // Remove any affiliateFee. netInput * affiliateFee (%age) of the destination asset type
453
- const affiliateFee = params.input.baseAmount.times(params.affiliateFeePercent || 0);
481
+ const affiliateFee = input.baseAmount.times(affiliateFeePercent || 0);
454
482
  // Calculate expiry time
455
483
  const currentDatetime = new Date();
456
484
  const minutesToAdd = 15;
457
485
  const expiryDatetime = new Date(currentDatetime.getTime() + minutesToAdd * 60000);
458
486
  // Check for errors
459
- const errors = yield this.getSwapEstimateErrors(params, swapEstimate, sourceInboundDetails, destinationInboundDetails);
487
+ const errors = yield this.getSwapEstimateErrors({
488
+ input,
489
+ destinationAsset,
490
+ destinationAddress,
491
+ affiliateAddress,
492
+ interfaceID,
493
+ affiliateFeePercent,
494
+ slipLimit,
495
+ }, swapEstimate, sourceInboundDetails, destinationInboundDetails);
460
496
  const txDetails = {
461
497
  memo: '',
462
498
  toAddress: '',
@@ -470,26 +506,26 @@ class ThorchainQuery {
470
506
  else {
471
507
  txDetails.txEstimate.canSwap = true;
472
508
  // Retrieve inbound Asgard address.
473
- const inboundAsgard = (yield this.thorchainCache.getInboundAddressesItems())[params.input.asset.chain];
509
+ const inboundAsgard = (yield this.thorchainCache.getInboundAddressesItems())[input.asset.chain];
474
510
  txDetails.toAddress = (inboundAsgard === null || inboundAsgard === void 0 ? void 0 : inboundAsgard.address) || '';
475
511
  // Work out LIM from the slip percentage
476
512
  let limPercentage = BN_1;
477
- if (params.slipLimit) {
478
- limPercentage = BN_1.minus(params.slipLimit || 1);
513
+ if (slipLimit) {
514
+ limPercentage = BN_1.minus(slipLimit || 1);
479
515
  } // else allowed slip is 100%
480
516
  const limAssetAmount = swapEstimate.netOutput.times(limPercentage);
481
- const inboundDelay = yield this.confCounting(params.input);
517
+ const inboundDelay = yield this.confCounting(input);
482
518
  const outboundDelay = yield this.outboundDelay(limAssetAmount);
483
519
  txDetails.txEstimate.waitTimeSeconds = outboundDelay + inboundDelay;
484
520
  // Construct memo
485
521
  txDetails.memo = this.constructSwapMemo({
486
- input: params.input,
487
- destinationAsset: params.destinationAsset,
522
+ input: input,
523
+ destinationAsset: destinationAsset,
488
524
  limit: limAssetAmount.baseAmount,
489
- destinationAddress,
490
- affiliateAddress,
525
+ destinationAddress: destinationAddress,
526
+ affiliateAddress: affiliateAddress,
491
527
  affiliateFee,
492
- interfaceID,
528
+ interfaceID: interfaceID,
493
529
  });
494
530
  }
495
531
  return txDetails;
@@ -521,18 +557,24 @@ class ThorchainQuery {
521
557
  */
522
558
  calcSwapEstimate(params, sourceInboundDetails, destinationInboundDetails) {
523
559
  return __awaiter(this, void 0, void 0, function* () {
524
- //NOTE need to convert the asset to 8 decimals places for all calcs
525
- const input = yield this.thorchainCache.convert(params.input, params.input.asset);
526
- const inputInRune = yield this.thorchainCache.convert(input, xchainUtil.AssetRuneNative);
560
+ // NOTE need to convert the asset to 8 decimals places for all calcs
561
+ const DEFAULT_THORCHAIN_DECIMALS = 8;
562
+ // If input is already in 8 decimals skip the convert
563
+ const input = params.input.baseAmount.decimal === DEFAULT_THORCHAIN_DECIMALS
564
+ ? params.input
565
+ : yield this.thorchainCache.convert(params.input, params.input.asset);
566
+ // If asset is already rune native, skip the convert
567
+ const inputInRune = input.asset === xchainUtil.AssetRuneNative ? input : yield this.thorchainCache.convert(input, xchainUtil.AssetRuneNative);
527
568
  const inboundFeeInAsset = calcNetworkFee(input.asset, sourceInboundDetails.gas_rate);
528
569
  let outboundFeeInAsset = calcNetworkFee(params.destinationAsset, destinationInboundDetails.gas_rate);
529
570
  outboundFeeInAsset = outboundFeeInAsset.times(3);
571
+ // convert fees to rune
530
572
  const inboundFeeInRune = yield this.thorchainCache.convert(inboundFeeInAsset, xchainUtil.AssetRuneNative);
531
573
  let outboundFeeInRune = yield this.thorchainCache.convert(outboundFeeInAsset, xchainUtil.AssetRuneNative);
532
574
  // ---------- Remove Fees from inbound before doing the swap -----------
533
- // TODO confirm with chris about this change
534
- // const inputMinusInboundFeeInRune = inputInRune.minus(inboundFeeInRune)
535
- const inputMinusInboundFeeInRune = inputInRune;
575
+ // TODO confirm with chris about this change, was there a reason why this was commented out?
576
+ const inputMinusInboundFeeInRune = inputInRune.minus(inboundFeeInRune);
577
+ //>//const inputMinusInboundFeeInRune = inputInRune
536
578
  // remove any affiliateFee. netInput * affiliateFee (%age) of the destination asset type
537
579
  const affiliateFeeInRune = inputMinusInboundFeeInRune.times(params.affiliateFeePercent || 0);
538
580
  // remove the affiliate fee from the input.
@@ -552,7 +594,7 @@ class ThorchainQuery {
552
594
  outboundFeeInRune = yield this.convert(newFee, xchainUtil.AssetRuneNative);
553
595
  }
554
596
  }
555
- // Now calculate swapfee based on inputNetAmount
597
+ // Now calculate swap output based on inputNetAmount
556
598
  const swapOutput = yield this.thorchainCache.getExpectedSwapOutput(inputNetInAsset, params.destinationAsset);
557
599
  const swapFeeInRune = yield this.thorchainCache.convert(swapOutput.swapFee, xchainUtil.AssetRuneNative);
558
600
  const outputInRune = yield this.thorchainCache.convert(swapOutput.output, xchainUtil.AssetRuneNative);
@@ -1235,23 +1277,35 @@ class ThorchainCache {
1235
1277
  * Ex. convert(input:100 BUSD, outAsset: BTC) -> 0.0001234 BTC
1236
1278
  *
1237
1279
  * @param input - amount/asset to convert to outAsset
1238
- * @param ouAsset - the Asset you want to convert to
1280
+ * @param outAsset - the Asset you want to convert to
1239
1281
  * @returns CryptoAmount of input
1240
1282
  */
1241
1283
  convert(input, outAsset) {
1242
- var _a;
1243
1284
  return __awaiter(this, void 0, void 0, function* () {
1244
1285
  const exchangeRate = yield this.getExchangeRate(input.asset, outAsset);
1245
- let decimals = DEFAULT_THORCHAIN_DECIMALS;
1246
- if (!xchainUtil.isAssetRuneNative(outAsset)) {
1247
- const pool = yield this.getPoolForAsset(outAsset);
1248
- decimals = (_a = pool.decimals) !== null && _a !== void 0 ? _a : DEFAULT_THORCHAIN_DECIMALS;
1249
- }
1250
- const amt = xchainUtil.assetAmount(input.assetAmount.times(exchangeRate).amount().toFixed(), decimals);
1251
- const result = new CryptoAmount(xchainUtil.assetToBase(amt), outAsset);
1286
+ const outDecimals = yield this.getDecimalForAsset(outAsset);
1287
+ const inDecimals = input.baseAmount.decimal;
1288
+ let baseAmountOut = input.baseAmount.times(exchangeRate).amount();
1289
+ const adjustDecimals = outDecimals - inDecimals;
1290
+ baseAmountOut = baseAmountOut.times(Math.pow(10, adjustDecimals));
1291
+ const amt = xchainUtil.baseAmount(baseAmountOut, outDecimals);
1292
+ const result = new CryptoAmount(amt, outAsset);
1293
+ // console.log(
1294
+ // `${input.formatedAssetString()} ${input.asset.ticker} = ${result.formatedAssetString()} ${outAsset.ticker}`,
1295
+ // )
1252
1296
  return result;
1253
1297
  });
1254
1298
  }
1299
+ getDecimalForAsset(asset) {
1300
+ var _a;
1301
+ return __awaiter(this, void 0, void 0, function* () {
1302
+ if (!xchainUtil.isAssetRuneNative(asset)) {
1303
+ const pool = yield this.getPoolForAsset(asset);
1304
+ return (_a = pool.decimals) !== null && _a !== void 0 ? _a : DEFAULT_THORCHAIN_DECIMALS;
1305
+ }
1306
+ return DEFAULT_THORCHAIN_DECIMALS;
1307
+ });
1308
+ }
1255
1309
  getRouterAddressForChain(chain) {
1256
1310
  return __awaiter(this, void 0, void 0, function* () {
1257
1311
  const inboundAsgard = (yield this.getInboundAddressesItems())[chain];
@@ -1708,6 +1762,7 @@ class Thornode {
1708
1762
  return __awaiter(this, void 0, void 0, function* () {
1709
1763
  for (const api of this.poolsApi) {
1710
1764
  try {
1765
+ // console.log(console.log(JSON.stringify(api, null, 2)))
1711
1766
  const pools = yield api.pools();
1712
1767
  return pools.data;
1713
1768
  }
@@ -99,10 +99,11 @@ export declare class ThorchainCache {
99
99
  * Ex. convert(input:100 BUSD, outAsset: BTC) -> 0.0001234 BTC
100
100
  *
101
101
  * @param input - amount/asset to convert to outAsset
102
- * @param ouAsset - the Asset you want to convert to
102
+ * @param outAsset - the Asset you want to convert to
103
103
  * @returns CryptoAmount of input
104
104
  */
105
105
  convert(input: CryptoAmount, outAsset: Asset): Promise<CryptoAmount>;
106
+ private getDecimalForAsset;
106
107
  getRouterAddressForChain(chain: Chain): Promise<Address>;
107
108
  getInboundAddressesItems(): Promise<Record<string, InboundAddressesItem>>;
108
109
  getInboundDetails(): Promise<Record<string, InboundDetail>>;
@@ -26,7 +26,7 @@ export declare class ThorchainQuery {
26
26
 
27
27
  * @returns The SwapEstimate
28
28
  */
29
- estimateSwap(params: EstimateSwapParams, destinationAddress?: string, affiliateAddress?: string, interfaceID?: number): Promise<TxDetails>;
29
+ estimateSwap({ input, destinationAsset, destinationAddress, affiliateAddress, interfaceID, affiliateFeePercent, slipLimit, }: EstimateSwapParams): Promise<TxDetails>;
30
30
  /**
31
31
  * Basic Checks for swap information
32
32
  * @param params
package/lib/types.d.ts CHANGED
@@ -41,6 +41,9 @@ export declare type MidgardConfig = {
41
41
  export declare type EstimateSwapParams = {
42
42
  input: CryptoAmount;
43
43
  destinationAsset: Asset;
44
+ destinationAddress: Address;
45
+ affiliateAddress?: Address;
46
+ interfaceID?: number;
44
47
  affiliateFeePercent?: number;
45
48
  slipLimit?: BigNumber;
46
49
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xchainjs/xchain-thorchain-query",
3
- "version": "0.1.0-alpha",
3
+ "version": "0.1.0-beta",
4
4
  "license": "MIT",
5
5
  "description": "Thorchain query module that is resposible for estimating swap calculations and add/remove liquidity for thorchain ",
6
6
  "keywords": [