@xchainjs/xchain-thorchain-query 0.2.3 → 0.2.5

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/lib/index.js CHANGED
@@ -2,21 +2,12 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var xchainBinance = require('@xchainjs/xchain-binance');
6
- var xchainBitcoin = require('@xchainjs/xchain-bitcoin');
7
- var xchainCosmos = require('@xchainjs/xchain-cosmos');
8
- var xchainThorchain = require('@xchainjs/xchain-thorchain');
9
5
  var xchainUtil = require('@xchainjs/xchain-util');
10
6
  var bignumber_js = require('bignumber.js');
11
7
  var xchainClient = require('@xchainjs/xchain-client');
12
8
  var xchainMidgard = require('@xchainjs/xchain-midgard');
13
9
  var axios = require('axios');
14
10
  var axiosRetry = require('axios-retry');
15
- var xchainAvax = require('@xchainjs/xchain-avax');
16
- var xchainBitcoincash = require('@xchainjs/xchain-bitcoincash');
17
- var xchainDoge = require('@xchainjs/xchain-doge');
18
- var xchainEthereum = require('@xchainjs/xchain-ethereum');
19
- var xchainLitecoin = require('@xchainjs/xchain-litecoin');
20
11
  var xchainThornode = require('@xchainjs/xchain-thornode');
21
12
 
22
13
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
@@ -86,6 +77,14 @@ const DefaultChainAttributes = {
86
77
  blockReward: 0,
87
78
  avgBlockTimeInSecs: 6,
88
79
  },
80
+ BSC: {
81
+ blockReward: 0,
82
+ avgBlockTimeInSecs: 3,
83
+ },
84
+ MAYA: {
85
+ blockReward: 0,
86
+ avgBlockTimeInSecs: 6,
87
+ },
89
88
  };
90
89
 
91
90
  /**
@@ -205,148 +204,29 @@ class LiquidityPool {
205
204
  }
206
205
  }
207
206
 
208
- const defaultMidgardConfig = {
209
- mainnet: {
210
- apiRetries: 3,
211
- midgardBaseUrls: ['https://midgard.ninerealms.com'],
212
- },
213
- stagenet: {
214
- apiRetries: 3,
215
- midgardBaseUrls: ['https://stagenet-midgard.ninerealms.com'],
216
- },
217
- testnet: {
218
- apiRetries: 3,
219
- midgardBaseUrls: ['https://testnet.midgard.thorchain.info'],
220
- },
221
- };
222
- class Midgard {
223
- constructor(network = xchainClient.Network.Mainnet, config) {
224
- this.network = network;
225
- this.config = config !== null && config !== void 0 ? config : defaultMidgardConfig[this.network];
226
- axiosRetry__default['default'](axios__default['default'], { retries: this.config.apiRetries, retryDelay: axiosRetry__default['default'].exponentialDelay });
227
- this.midgardApis = this.config.midgardBaseUrls.map((url) => new xchainMidgard.MidgardApi(new xchainMidgard.Configuration({ basePath: url })));
228
- }
229
- /**
230
- *
231
- * @returns an array of Pools
232
- */
233
- getPools() {
234
- return __awaiter(this, void 0, void 0, function* () {
235
- for (const api of this.midgardApis) {
236
- try {
237
- return (yield api.getPools()).data;
238
- }
239
- catch (e) {
240
- //console.error(e)
241
- }
242
- }
243
- throw new Error(`Midgard not responding`);
244
- });
245
- }
246
- /**
247
- * Gets the latest block using the Health endpoint within Midgard
248
- *
249
- * @returns
250
- */
251
- getLatestBlockHeight() {
252
- return __awaiter(this, void 0, void 0, function* () {
253
- for (const api of this.midgardApis) {
254
- try {
255
- const data = (yield api.getHealth()).data;
256
- return +data.scannerHeight;
257
- }
258
- catch (e) {
259
- //console.error(e)
260
- }
261
- }
262
- throw Error(`Midgard not responding`);
263
- });
264
- }
265
- /**
266
- * Gets actions object for any of the parameters
267
- * @param txHash transaction id
268
- * @returns Type Action array of objects
269
- */
270
- getActions(address, txid, asset, type, affiliate, limit, offset) {
271
- return __awaiter(this, void 0, void 0, function* () {
272
- for (const api of this.midgardApis) {
273
- try {
274
- const actions = (yield api.getActions(address, txid, asset, type, affiliate, limit, offset)).data.actions;
275
- return actions;
276
- }
277
- catch (e) {
278
- //console.error(e)
279
- }
280
- }
281
- throw Error(`Midgard not responding`);
282
- });
283
- }
284
- /**
285
- * Function to return member details based on valid liquidity position
286
- * @param address - needed to query for Lp details
287
- * @returns - object type of Member Detail
288
- */
289
- getMember(address) {
290
- return __awaiter(this, void 0, void 0, function* () {
291
- for (const api of this.midgardApis) {
292
- try {
293
- const memberDetail = (yield api.getMemberDetail(address)).data;
294
- return memberDetail;
295
- }
296
- catch (e) {
297
- //console.error(e)
298
- }
299
- }
300
- throw Error(`Midgard not responding`);
301
- });
302
- }
303
- /**
304
- * Function to return pool statistics for a particular asset
305
- * @param asset - asset string to query its pool stats
306
- * @returns - type object poolstatsDetail
307
- */
308
- getPoolStats(asset) {
309
- return __awaiter(this, void 0, void 0, function* () {
310
- for (const api of this.midgardApis) {
311
- try {
312
- const poolDetail = (yield api.getPoolStats(asset)).data;
313
- return poolDetail;
314
- }
315
- catch (e) {
316
- //console.error(e)
317
- }
318
- }
319
- throw Error(`Midgard not responding`);
320
- });
321
- }
322
- /**
323
- * Function to return THORNameDetails for a particular name
324
- * @param name - thorname string to query
325
- * @returns - type object THORNameDetails
326
- */
327
- getTHORNameDetails(name) {
328
- return __awaiter(this, void 0, void 0, function* () {
329
- for (const api of this.midgardApis) {
330
- try {
331
- const resp = yield api.getTHORNameDetail(name);
332
- if (resp.status == 404) {
333
- return undefined;
334
- }
335
- else if (resp.status == 200) {
336
- return resp.data;
337
- }
338
- }
339
- catch (e) {
340
- // if (resp.status == 404) {
341
- // return undefined
342
- // }
343
- //console.error(e)
344
- }
345
- }
346
- throw Error(`Midgard not responding`);
347
- });
348
- }
349
- }
207
+ const AssetBNB = xchainUtil.assetFromStringEx('BNB.BNB');
208
+ const AssetAVAX = xchainUtil.assetFromStringEx('AVAX.AVAX');
209
+ const AssetBTC = xchainUtil.assetFromStringEx('BTC.BTC');
210
+ const AssetBCH = xchainUtil.assetFromStringEx('BCH.BHC');
211
+ const AssetETH = xchainUtil.assetFromStringEx('ETH.ETH');
212
+ const AssetDOGE = xchainUtil.assetFromStringEx('DOGE.DOGE');
213
+ const AssetLTC = xchainUtil.assetFromStringEx('LTC.LTC');
214
+ const AssetATOM = xchainUtil.assetFromStringEx('GAIA.ATOM');
215
+ const AssetMAYA = xchainUtil.assetFromStringEx('MAYA.CACAO');
216
+ const AssetBSC = xchainUtil.assetFromStringEx('BSC.BNB');
217
+ const AssetRuneNative = xchainUtil.assetFromStringEx('THOR.RUNE');
218
+ const BNBChain = 'BNB';
219
+ const BTCChain = 'BTC';
220
+ const BCHChain = 'BCH';
221
+ const ETHChain = 'ETH';
222
+ const GAIAChain = 'GAIA';
223
+ const DOGEChain = 'DOGE';
224
+ const LTCChain = 'LTC';
225
+ const AVAXChain = 'AVAX';
226
+ const MAYAChain = 'MAYA';
227
+ const BSCChain = 'BSC';
228
+ const THORChain = 'THOR';
229
+ const isAssetRuneNative = (asset) => xchainUtil.assetToString(asset) === xchainUtil.assetToString(AssetRuneNative);
350
230
 
351
231
  const getBaseAmountWithDiffDecimals = (inputAmount, outDecimals) => {
352
232
  const inDecimals = inputAmount.baseAmount.decimal;
@@ -369,7 +249,7 @@ const getSwapFee = (inputAmount, pool, toRune) => {
369
249
  const x = getBaseAmountWithDiffDecimals(inputAmount, 8);
370
250
  const X = toRune ? pool.assetBalance.amount() : pool.runeBalance.amount(); // input is asset if toRune
371
251
  const Y = toRune ? pool.runeBalance.amount() : pool.assetBalance.amount(); // output is rune if toRune
372
- const units = toRune ? xchainThorchain.AssetRuneNative : pool.asset;
252
+ const units = toRune ? AssetRuneNative : pool.asset;
373
253
  const numerator = x.times(x).multipliedBy(Y);
374
254
  const denominator = x.plus(X).pow(2);
375
255
  const result = numerator.div(denominator);
@@ -408,7 +288,7 @@ const getSwapOutput = (inputAmount, pool, toRune) => {
408
288
  const x = getBaseAmountWithDiffDecimals(inputAmount, 8);
409
289
  const X = toRune ? pool.assetBalance.amount() : pool.runeBalance.amount(); // input is asset if toRune
410
290
  const Y = toRune ? pool.runeBalance.amount() : pool.assetBalance.amount(); // output is rune if toRune
411
- const units = toRune ? xchainThorchain.AssetRuneNative : pool.asset;
291
+ const units = toRune ? AssetRuneNative : pool.asset;
412
292
  // const decimals = toRune || !pool.decimals ? 8 : pool.decimals
413
293
  const numerator = x.times(X).times(Y);
414
294
  const denominator = x.plus(X).pow(2);
@@ -453,7 +333,7 @@ const getDoubleSwapFee = (inputAmount, pool1, pool2, thorchainCache) => __awaite
453
333
  const fee1InRune = getSwapFee(inputAmount, pool1, true);
454
334
  const swapOutput = getSwapOutput(inputAmount, pool1, true);
455
335
  const fee2InAsset = getSwapFee(swapOutput, pool2, false);
456
- const fee2InRune = yield thorchainCache.convert(fee2InAsset, xchainThorchain.AssetRuneNative);
336
+ const fee2InRune = yield thorchainCache.convert(fee2InAsset, AssetRuneNative);
457
337
  const result = fee1InRune.plus(fee2InRune);
458
338
  return result;
459
339
  });
@@ -482,24 +362,28 @@ const getDoubleSwap = (inputAmount, pool1, pool2, thorchainCache) => __awaiter(v
482
362
  */
483
363
  const getChainAsset = (chain) => {
484
364
  switch (chain) {
485
- case xchainBinance.BNBChain:
486
- return xchainBinance.AssetBNB;
487
- case xchainBitcoin.BTCChain:
488
- return xchainBitcoin.AssetBTC;
489
- case xchainEthereum.ETHChain:
490
- return xchainEthereum.AssetETH;
491
- case xchainThorchain.THORChain:
492
- return xchainThorchain.AssetRuneNative;
493
- case xchainCosmos.GAIAChain:
494
- return xchainCosmos.AssetATOM;
495
- case xchainBitcoincash.BCHChain:
496
- return xchainBitcoincash.AssetBCH;
497
- case xchainLitecoin.LTCChain:
498
- return xchainLitecoin.AssetLTC;
499
- case xchainDoge.DOGEChain:
500
- return xchainDoge.AssetDOGE;
501
- case xchainAvax.AVAXChain:
502
- return xchainAvax.AssetAVAX;
365
+ case BNBChain:
366
+ return AssetBNB;
367
+ case BTCChain:
368
+ return AssetBTC;
369
+ case ETHChain:
370
+ return AssetETH;
371
+ case THORChain:
372
+ return AssetRuneNative;
373
+ case GAIAChain:
374
+ return AssetATOM;
375
+ case BCHChain:
376
+ return AssetBCH;
377
+ case LTCChain:
378
+ return AssetLTC;
379
+ case DOGEChain:
380
+ return AssetDOGE;
381
+ case AVAXChain:
382
+ return AssetAVAX;
383
+ case BSCChain:
384
+ return AssetBSC;
385
+ case MAYAChain:
386
+ return AssetMAYA;
503
387
  default:
504
388
  throw Error('Unknown chain');
505
389
  }
@@ -524,83 +408,325 @@ const isNativeChainAsset = (asset) => {
524
408
  const calcNetworkFee = (asset, inbound) => {
525
409
  // synths are always 0.02R fee
526
410
  if (asset.synth)
527
- return new CryptoAmount(xchainUtil.baseAmount(2000000), xchainThorchain.AssetRuneNative);
411
+ return new CryptoAmount(xchainUtil.baseAmount(2000000), AssetRuneNative);
528
412
  // if you are swapping a non-gas asset on a multiAsset chain (ex. ERC-20 on ETH), the
529
413
  // gas fees will be paid in a diff asset than the one you are swapping
530
414
  switch (asset.chain) {
531
- case xchainBitcoin.BTCChain:
532
- return new CryptoAmount(xchainUtil.baseAmount(inbound.gasRate.multipliedBy(inbound.outboundTxSize)), xchainBitcoin.AssetBTC);
533
- case xchainBitcoincash.BCHChain:
534
- return new CryptoAmount(xchainUtil.baseAmount(inbound.gasRate.multipliedBy(inbound.outboundTxSize)), xchainBitcoincash.AssetBCH);
535
- case xchainLitecoin.LTCChain:
536
- return new CryptoAmount(xchainUtil.baseAmount(inbound.gasRate.multipliedBy(inbound.outboundTxSize)), xchainLitecoin.AssetLTC);
537
- case xchainDoge.DOGEChain:
415
+ case BTCChain:
416
+ return new CryptoAmount(xchainUtil.baseAmount(inbound.gasRate.multipliedBy(inbound.outboundTxSize)), AssetBTC);
417
+ case BCHChain:
418
+ return new CryptoAmount(xchainUtil.baseAmount(inbound.gasRate.multipliedBy(inbound.outboundTxSize)), AssetBCH);
419
+ case LTCChain:
420
+ return new CryptoAmount(xchainUtil.baseAmount(inbound.gasRate.multipliedBy(inbound.outboundTxSize)), AssetLTC);
421
+ case DOGEChain:
538
422
  // NOTE: UTXO chains estimate fees with a 250 byte size
539
- return new CryptoAmount(xchainUtil.baseAmount(inbound.gasRate.multipliedBy(inbound.outboundTxSize)), xchainDoge.AssetDOGE);
540
- case xchainBinance.BNBChain:
423
+ return new CryptoAmount(xchainUtil.baseAmount(inbound.gasRate.multipliedBy(inbound.outboundTxSize)), AssetDOGE);
424
+ case BNBChain:
541
425
  //flat fee
542
- return new CryptoAmount(xchainUtil.baseAmount(inbound.gasRate), xchainBinance.AssetBNB);
543
- case xchainEthereum.ETHChain:
426
+ return new CryptoAmount(xchainUtil.baseAmount(inbound.gasRate), AssetBNB);
427
+ case ETHChain:
544
428
  const gasRateinETHGwei = inbound.gasRate;
545
429
  const gasRateinETHWei = xchainUtil.baseAmount(gasRateinETHGwei.multipliedBy(Math.pow(10, 9)), 18);
546
- if (xchainUtil.eqAsset(asset, xchainEthereum.AssetETH)) {
547
- return new CryptoAmount(gasRateinETHWei.times(21000), xchainEthereum.AssetETH);
430
+ if (xchainUtil.eqAsset(asset, AssetETH)) {
431
+ return new CryptoAmount(gasRateinETHWei.times(21000), AssetETH);
432
+ }
433
+ else {
434
+ return new CryptoAmount(gasRateinETHWei.times(70000), AssetETH);
435
+ }
436
+ case AVAXChain:
437
+ const gasRateinAVAXGwei = inbound.gasRate;
438
+ const gasRateinAVAXWei = xchainUtil.baseAmount(gasRateinAVAXGwei.multipliedBy(Math.pow(10, 9)), 18);
439
+ if (xchainUtil.eqAsset(asset, AssetAVAX)) {
440
+ return new CryptoAmount(gasRateinAVAXWei.times(21000), AssetAVAX);
441
+ }
442
+ else {
443
+ return new CryptoAmount(gasRateinAVAXWei.times(70000), AssetAVAX);
444
+ }
445
+ case GAIAChain:
446
+ return new CryptoAmount(xchainUtil.baseAmount(inbound.gasRate), AssetATOM);
447
+ case THORChain:
448
+ return new CryptoAmount(xchainUtil.baseAmount(2000000), AssetRuneNative);
449
+ case BSCChain:
450
+ return new CryptoAmount(xchainUtil.baseAmount(inbound.gasRate), AssetBSC);
451
+ case MAYAChain:
452
+ return new CryptoAmount(xchainUtil.baseAmount(inbound.gasRate), AssetMAYA);
453
+ }
454
+ throw new Error(`could not calculate inbound fee for ${asset.chain}`);
455
+ };
456
+ /**
457
+ * Works out the required outbound fee based on the chain.
458
+ * Call getInboundDetails to get the current outbound fee
459
+ *
460
+ * @param sourceAsset
461
+ * @param inbound detail
462
+ * @see https://dev.thorchain.org/thorchain-dev/thorchain-and-fees#fee-calcuation-by-chain
463
+ * @returns
464
+ */
465
+ const calcOutboundFee = (asset, inbound) => {
466
+ if (asset.synth)
467
+ return new CryptoAmount(xchainUtil.baseAmount(2000000), AssetRuneNative);
468
+ switch (asset.chain) {
469
+ case BTCChain:
470
+ return new CryptoAmount(xchainUtil.baseAmount(inbound.outboundFee), AssetBTC);
471
+ case BCHChain:
472
+ return new CryptoAmount(xchainUtil.baseAmount(inbound.outboundFee), AssetBCH);
473
+ case LTCChain:
474
+ return new CryptoAmount(xchainUtil.baseAmount(inbound.outboundFee), AssetLTC);
475
+ case DOGEChain:
476
+ // NOTE: UTXO chains estimate fees with a 250 byte size
477
+ return new CryptoAmount(xchainUtil.baseAmount(inbound.outboundFee), AssetDOGE);
478
+ case BNBChain:
479
+ //flat fee
480
+ return new CryptoAmount(xchainUtil.baseAmount(inbound.outboundFee), AssetBNB);
481
+ case ETHChain:
482
+ return new CryptoAmount(xchainUtil.baseAmount(inbound.outboundFee.multipliedBy(Math.pow(10, 9)), 18), AssetETH);
483
+ case AVAXChain:
484
+ return new CryptoAmount(xchainUtil.baseAmount(inbound.outboundFee.multipliedBy(Math.pow(10, 9)), 18), AssetAVAX);
485
+ case GAIAChain:
486
+ return new CryptoAmount(xchainUtil.baseAmount(inbound.outboundFee), AssetATOM);
487
+ case BSCChain:
488
+ return new CryptoAmount(xchainUtil.baseAmount(inbound.outboundFee), AssetBSC);
489
+ case THORChain:
490
+ return new CryptoAmount(xchainUtil.baseAmount(2000000), AssetRuneNative);
491
+ case MAYAChain:
492
+ return new CryptoAmount(xchainUtil.baseAmount(2000000), AssetMAYA);
493
+ }
494
+ throw new Error(`could not calculate outbound fee for ${asset.chain}`);
495
+ };
496
+
497
+ /**
498
+ * https://dev.thorchain.org/thorchain-dev/interface-guide/math#lp-units-add
499
+ * @param liquidity - asset amount added
500
+ * @param pool - pool depths
501
+ * @returns liquidity units - ownership of pool
502
+ */
503
+ const getLiquidityUnits = (liquidity, pool) => {
504
+ const baseAmount8decimals = getBaseAmountWithDiffDecimals(liquidity.asset, 8);
505
+ const P = new bignumber_js.BigNumber(pool.pool.liquidityUnits);
506
+ const r = liquidity.rune.baseAmount.amount();
507
+ const a = baseAmount8decimals;
508
+ const R = pool.runeBalance.amount();
509
+ const A = pool.assetBalance.amount();
510
+ const part1 = R.times(a);
511
+ const part2 = r.times(A);
512
+ const numerator = P.times(part1.plus(part2));
513
+ const denominator = R.times(A).times(2);
514
+ const result = numerator.div(denominator);
515
+ return result;
516
+ };
517
+ /**
518
+ *
519
+ * @param unitData - units for both asset and rune
520
+ * @param pool - pool that the asset is bound to
521
+ * @returns - pool share of both asset and rune in percentage
522
+ */
523
+ const getPoolShare = (unitData, pool) => {
524
+ // formula: (rune * part) / total; (asset * part) / total
525
+ const units = unitData.liquidityUnits;
526
+ const total = unitData.totalUnits;
527
+ const R = pool.runeBalance.amount();
528
+ const T = pool.assetBalance.amount();
529
+ const asset = T.times(units).div(total);
530
+ const rune = R.times(units).div(total);
531
+ const poolShareDetail = {
532
+ assetShare: new CryptoAmount(xchainUtil.baseAmount(asset), pool.asset),
533
+ runeShare: new CryptoAmount(xchainUtil.baseAmount(rune), AssetRuneNative),
534
+ };
535
+ return poolShareDetail;
536
+ };
537
+ /**
538
+ *
539
+ * @param poolShare - the share of asset and rune added to the pool
540
+ * @param pool - Pool that the asset is attached to
541
+ * @returns - returns bignumber representing a slip percentage
542
+ */
543
+ const getSlipOnLiquidity = (stake, pool) => {
544
+ const baseAmount8decimals = getBaseAmountWithDiffDecimals(stake.asset, 8);
545
+ // formula: (t * R - T * r)/ (T*r + R*T)
546
+ const r = stake.rune.baseAmount.amount();
547
+ const t = baseAmount8decimals;
548
+ const R = pool.runeBalance.amount();
549
+ const T = pool.assetBalance.amount();
550
+ const numerator = t.times(R).minus(T.times(r));
551
+ const denominator = T.times(r).plus(R.times(T));
552
+ const result = numerator.div(denominator).abs();
553
+ return result;
554
+ };
555
+ /**
556
+ * https://docs.thorchain.org/thorchain-finance/continuous-liquidity-pools#impermanent-loss-protection
557
+ * @param poolShare - the share of asset and rune added to the pool
558
+ * @param pool - Pool that the asset is attached to
559
+ * @param block - blockl object with current, last added and the constant blocksforlossProtection
560
+ * @returns
561
+ */
562
+ // Blocks for full protection 1440000 // 100 days
563
+ const getLiquidityProtectionData = (depositValue, poolShare, block) => {
564
+ //Coverage formula coverage=((A0∗P1)+R0)−((A1∗P1)+R1)=>((A0∗R1/A1)+R0)−(R1+R1)
565
+ //formula: protectionProgress (currentHeight-heightLastAdded)/blocksforfullprotection
566
+ const R0 = depositValue.rune.amount(); // rune deposit value
567
+ const A0 = depositValue.asset.amount(); // asset deposit value
568
+ const R1 = poolShare.runeShare.baseAmount.amount(); // rune amount to redeem
569
+ const A1 = poolShare.assetShare.baseAmount.amount(); // asset amount to redeem
570
+ const P1 = R1.div(A1); // Pool ratio at withdrawal
571
+ const part1 = A0.times(P1).plus(R0).minus(A1.times(P1).plus(R1)); // start position minus end position
572
+ const part2 = A0.times(R1.div(A1)).plus(R0).minus(R1.plus(R1)); // different way to check position
573
+ const coverage = part1 >= part2 ? part1 : part2; // Coverage represents how much ILP a LP is entitled to
574
+ const currentHeight = block.current;
575
+ const heightLastAdded = block.lastAdded || 0; //default to zero if undefined
576
+ const blocksforfullprotection = block.fullProtection;
577
+ const fractionOfFullILPProtection = (currentHeight - heightLastAdded) / blocksforfullprotection;
578
+ const protectionProgress = Math.min(fractionOfFullILPProtection, 1); // percentage of entitlement, max 100%
579
+ const result = coverage.times(protectionProgress); // impermanent loss protection result
580
+ const maxILP = result.lt(0) ? new bignumber_js.BigNumber(0) : result; // max negative ILP to 0
581
+ const ILProtection = {
582
+ ILProtection: new CryptoAmount(xchainUtil.baseAmount(maxILP), AssetRuneNative),
583
+ totalDays: (fractionOfFullILPProtection * 100).toFixed(2),
584
+ };
585
+ return ILProtection;
586
+ };
587
+
588
+ const defaultMidgardConfig = {
589
+ mainnet: {
590
+ apiRetries: 3,
591
+ midgardBaseUrls: ['https://midgard.ninerealms.com'],
592
+ },
593
+ stagenet: {
594
+ apiRetries: 3,
595
+ midgardBaseUrls: ['https://stagenet-midgard.ninerealms.com'],
596
+ },
597
+ testnet: {
598
+ apiRetries: 3,
599
+ midgardBaseUrls: ['https://testnet.midgard.thorchain.info'],
600
+ },
601
+ };
602
+ class Midgard {
603
+ constructor(network = xchainClient.Network.Mainnet, config) {
604
+ this.network = network;
605
+ this.config = config !== null && config !== void 0 ? config : defaultMidgardConfig[this.network];
606
+ axiosRetry__default['default'](axios__default['default'], { retries: this.config.apiRetries, retryDelay: axiosRetry__default['default'].exponentialDelay });
607
+ this.midgardApis = this.config.midgardBaseUrls.map((url) => new xchainMidgard.MidgardApi(new xchainMidgard.Configuration({ basePath: url })));
608
+ }
609
+ /**
610
+ *
611
+ * @returns an array of Pools
612
+ */
613
+ getPools() {
614
+ return __awaiter(this, void 0, void 0, function* () {
615
+ for (const api of this.midgardApis) {
616
+ try {
617
+ return (yield api.getPools()).data;
618
+ }
619
+ catch (e) {
620
+ //console.error(e)
621
+ }
622
+ }
623
+ throw new Error(`Midgard not responding`);
624
+ });
625
+ }
626
+ /**
627
+ * Gets the latest block using the Health endpoint within Midgard
628
+ *
629
+ * @returns
630
+ */
631
+ getLatestBlockHeight() {
632
+ return __awaiter(this, void 0, void 0, function* () {
633
+ for (const api of this.midgardApis) {
634
+ try {
635
+ const data = (yield api.getHealth()).data;
636
+ return +data.scannerHeight;
637
+ }
638
+ catch (e) {
639
+ //console.error(e)
640
+ }
548
641
  }
549
- else {
550
- return new CryptoAmount(gasRateinETHWei.times(70000), xchainEthereum.AssetETH);
642
+ throw Error(`Midgard not responding`);
643
+ });
644
+ }
645
+ /**
646
+ * Gets actions object for any of the parameters
647
+ * @param txHash transaction id
648
+ * @returns Type Action array of objects
649
+ */
650
+ getActions(address, txid, asset, type, affiliate, limit, offset) {
651
+ return __awaiter(this, void 0, void 0, function* () {
652
+ for (const api of this.midgardApis) {
653
+ try {
654
+ const actions = (yield api.getActions(address, txid, asset, type, affiliate, limit, offset)).data.actions;
655
+ return actions;
656
+ }
657
+ catch (e) {
658
+ //console.error(e)
659
+ }
551
660
  }
552
- case xchainAvax.AVAXChain:
553
- const gasRateinAVAXGwei = inbound.gasRate;
554
- const gasRateinAVAXWei = xchainUtil.baseAmount(gasRateinAVAXGwei.multipliedBy(Math.pow(10, 9)), 18);
555
- if (xchainUtil.eqAsset(asset, xchainAvax.AssetAVAX)) {
556
- return new CryptoAmount(gasRateinAVAXWei.times(21000), xchainAvax.AssetAVAX);
661
+ throw Error(`Midgard not responding`);
662
+ });
663
+ }
664
+ /**
665
+ * Function to return member details based on valid liquidity position
666
+ * @param address - needed to query for Lp details
667
+ * @returns - object type of Member Detail
668
+ */
669
+ getMember(address) {
670
+ return __awaiter(this, void 0, void 0, function* () {
671
+ for (const api of this.midgardApis) {
672
+ try {
673
+ const memberDetail = (yield api.getMemberDetail(address)).data;
674
+ return memberDetail;
675
+ }
676
+ catch (e) {
677
+ //console.error(e)
678
+ }
557
679
  }
558
- else {
559
- return new CryptoAmount(gasRateinAVAXWei.times(70000), xchainAvax.AssetAVAX);
680
+ throw Error(`Midgard not responding`);
681
+ });
682
+ }
683
+ /**
684
+ * Function to return pool statistics for a particular asset
685
+ * @param asset - asset string to query its pool stats
686
+ * @returns - type object poolstatsDetail
687
+ */
688
+ getPoolStats(asset) {
689
+ return __awaiter(this, void 0, void 0, function* () {
690
+ for (const api of this.midgardApis) {
691
+ try {
692
+ const poolDetail = (yield api.getPoolStats(asset)).data;
693
+ return poolDetail;
694
+ }
695
+ catch (e) {
696
+ //console.error(e)
697
+ }
560
698
  }
561
- case xchainCosmos.GAIAChain:
562
- return new CryptoAmount(xchainUtil.baseAmount(inbound.gasRate), xchainCosmos.AssetATOM);
563
- case xchainThorchain.THORChain:
564
- return new CryptoAmount(xchainUtil.baseAmount(2000000), xchainThorchain.AssetRuneNative);
699
+ throw Error(`Midgard not responding`);
700
+ });
565
701
  }
566
- throw new Error(`could not calculate inbound fee for ${asset.chain}`);
567
- };
568
- /**
569
- * Works out the required outbound fee based on the chain.
570
- * Call getInboundDetails to get the current outbound fee
571
- *
572
- * @param sourceAsset
573
- * @param inbound detail
574
- * @see https://dev.thorchain.org/thorchain-dev/thorchain-and-fees#fee-calcuation-by-chain
575
- * @returns
576
- */
577
- const calcOutboundFee = (asset, inbound) => {
578
- if (asset.synth)
579
- return new CryptoAmount(xchainUtil.baseAmount(2000000), xchainThorchain.AssetRuneNative);
580
- switch (asset.chain) {
581
- case xchainBitcoin.BTCChain:
582
- return new CryptoAmount(xchainUtil.baseAmount(inbound.outboundFee), xchainBitcoin.AssetBTC);
583
- case xchainBitcoincash.BCHChain:
584
- return new CryptoAmount(xchainUtil.baseAmount(inbound.outboundFee), xchainBitcoincash.AssetBCH);
585
- case xchainLitecoin.LTCChain:
586
- return new CryptoAmount(xchainUtil.baseAmount(inbound.outboundFee), xchainLitecoin.AssetLTC);
587
- case xchainDoge.DOGEChain:
588
- // NOTE: UTXO chains estimate fees with a 250 byte size
589
- return new CryptoAmount(xchainUtil.baseAmount(inbound.outboundFee), xchainDoge.AssetDOGE);
590
- case xchainBinance.BNBChain:
591
- //flat fee
592
- return new CryptoAmount(xchainUtil.baseAmount(inbound.outboundFee), xchainBinance.AssetBNB);
593
- case xchainEthereum.ETHChain:
594
- return new CryptoAmount(xchainUtil.baseAmount(inbound.outboundFee.multipliedBy(Math.pow(10, 9)), 18), xchainEthereum.AssetETH);
595
- case xchainAvax.AVAXChain:
596
- return new CryptoAmount(xchainUtil.baseAmount(inbound.outboundFee.multipliedBy(Math.pow(10, 9)), 18), xchainAvax.AssetAVAX);
597
- case xchainCosmos.GAIAChain:
598
- return new CryptoAmount(xchainUtil.baseAmount(inbound.outboundFee), xchainCosmos.AssetATOM);
599
- case xchainThorchain.THORChain:
600
- return new CryptoAmount(xchainUtil.baseAmount(2000000), xchainThorchain.AssetRuneNative);
702
+ /**
703
+ * Function to return THORNameDetails for a particular name
704
+ * @param name - thorname string to query
705
+ * @returns - type object THORNameDetails
706
+ */
707
+ getTHORNameDetails(name) {
708
+ return __awaiter(this, void 0, void 0, function* () {
709
+ for (const api of this.midgardApis) {
710
+ try {
711
+ const resp = yield api.getTHORNameDetail(name);
712
+ if (resp.status == 404) {
713
+ return undefined;
714
+ }
715
+ else if (resp.status == 200) {
716
+ return resp.data;
717
+ }
718
+ }
719
+ catch (e) {
720
+ // if (resp.status == 404) {
721
+ // return undefined
722
+ // }
723
+ //console.error(e)
724
+ }
725
+ }
726
+ throw Error(`Midgard not responding`);
727
+ });
601
728
  }
602
- throw new Error(`could not calculate outbound fee for ${asset.chain}`);
603
- };
729
+ }
604
730
 
605
731
  const defaultThornodeConfig = {
606
732
  mainnet: {
@@ -1041,12 +1167,12 @@ class ThorchainCache {
1041
1167
  if (xchainUtil.eqAsset(from, to)) {
1042
1168
  exchangeRate = SAME_ASSET_EXCHANGE_RATE;
1043
1169
  }
1044
- else if (xchainThorchain.isAssetRuneNative(from)) {
1170
+ else if (isAssetRuneNative(from)) {
1045
1171
  // Runes per Asset
1046
1172
  const lpTo = yield this.getPoolForAsset(to);
1047
1173
  exchangeRate = lpTo.assetToRuneRatio;
1048
1174
  }
1049
- else if (xchainThorchain.isAssetRuneNative(to)) {
1175
+ else if (isAssetRuneNative(to)) {
1050
1176
  // Asset per rune
1051
1177
  const lpFrom = yield this.getPoolForAsset(from);
1052
1178
  exchangeRate = lpFrom.runeToAssetRatio;
@@ -1070,7 +1196,7 @@ class ThorchainCache {
1070
1196
  */
1071
1197
  getPoolForAsset(asset) {
1072
1198
  return __awaiter(this, void 0, void 0, function* () {
1073
- if (xchainThorchain.isAssetRuneNative(asset))
1199
+ if (isAssetRuneNative(asset))
1074
1200
  throw Error(`AssetRuneNative doesn't have a pool`);
1075
1201
  const pools = yield this.getPools();
1076
1202
  // Note: we use ticker, not asset string to get the same pool for both assets and synths
@@ -1182,7 +1308,7 @@ class ThorchainCache {
1182
1308
  }
1183
1309
  // add mock THORCHAIN inbound details
1184
1310
  const details = {
1185
- chain: xchainThorchain.THORChain,
1311
+ chain: THORChain,
1186
1312
  address: '',
1187
1313
  router: '',
1188
1314
  gasRate: new bignumber_js.BigNumber(0),
@@ -1193,7 +1319,7 @@ class ThorchainCache {
1193
1319
  haltedTrading: !!mimirDetails['HALTTRADING'],
1194
1320
  haltedLP: false, //
1195
1321
  };
1196
- inboundDetails[xchainThorchain.THORChain] = details;
1322
+ inboundDetails[THORChain] = details;
1197
1323
  this.inboundDetailCache = {
1198
1324
  lastRefreshed: Date.now(),
1199
1325
  inboundDetails,
@@ -1230,12 +1356,12 @@ class ThorchainCache {
1230
1356
  getExpectedSwapOutput(inputAmount, destinationAsset) {
1231
1357
  return __awaiter(this, void 0, void 0, function* () {
1232
1358
  let swapOutput;
1233
- if (xchainThorchain.isAssetRuneNative(inputAmount.asset)) {
1359
+ if (isAssetRuneNative(inputAmount.asset)) {
1234
1360
  //singleswap from rune -> asset
1235
1361
  const pool = yield this.getPoolForAsset(destinationAsset);
1236
1362
  swapOutput = getSingleSwap(inputAmount, pool, false);
1237
1363
  }
1238
- else if (xchainThorchain.isAssetRuneNative(destinationAsset)) {
1364
+ else if (isAssetRuneNative(destinationAsset)) {
1239
1365
  //singleswap from asset -> rune
1240
1366
  const pool = yield this.getPoolForAsset(inputAmount.asset);
1241
1367
  swapOutput = getSingleSwap(inputAmount, pool, true);
@@ -1278,7 +1404,7 @@ class ThorchainCache {
1278
1404
  }
1279
1405
  getDecimalForAsset(asset) {
1280
1406
  return __awaiter(this, void 0, void 0, function* () {
1281
- if (!xchainThorchain.isAssetRuneNative(asset)) {
1407
+ if (!isAssetRuneNative(asset)) {
1282
1408
  const pool = yield this.getPoolForAsset(asset);
1283
1409
  const decimals = Number(pool.pool.nativeDecimal);
1284
1410
  if (decimals > 0)
@@ -1365,97 +1491,6 @@ class ThorchainCache {
1365
1491
  }
1366
1492
  }
1367
1493
 
1368
- /**
1369
- * https://dev.thorchain.org/thorchain-dev/interface-guide/math#lp-units-add
1370
- * @param liquidity - asset amount added
1371
- * @param pool - pool depths
1372
- * @returns liquidity units - ownership of pool
1373
- */
1374
- const getLiquidityUnits = (liquidity, pool) => {
1375
- const baseAmount8decimals = getBaseAmountWithDiffDecimals(liquidity.asset, 8);
1376
- const P = new bignumber_js.BigNumber(pool.pool.liquidityUnits);
1377
- const r = liquidity.rune.baseAmount.amount();
1378
- const a = baseAmount8decimals;
1379
- const R = pool.runeBalance.amount();
1380
- const A = pool.assetBalance.amount();
1381
- const part1 = R.times(a);
1382
- const part2 = r.times(A);
1383
- const numerator = P.times(part1.plus(part2));
1384
- const denominator = R.times(A).times(2);
1385
- const result = numerator.div(denominator);
1386
- return result;
1387
- };
1388
- /**
1389
- *
1390
- * @param unitData - units for both asset and rune
1391
- * @param pool - pool that the asset is bound to
1392
- * @returns - pool share of both asset and rune in percentage
1393
- */
1394
- const getPoolShare = (unitData, pool) => {
1395
- // formula: (rune * part) / total; (asset * part) / total
1396
- const units = unitData.liquidityUnits;
1397
- const total = unitData.totalUnits;
1398
- const R = pool.runeBalance.amount();
1399
- const T = pool.assetBalance.amount();
1400
- const asset = T.times(units).div(total);
1401
- const rune = R.times(units).div(total);
1402
- const poolShareDetail = {
1403
- assetShare: new CryptoAmount(xchainUtil.baseAmount(asset), pool.asset),
1404
- runeShare: new CryptoAmount(xchainUtil.baseAmount(rune), xchainThorchain.AssetRuneNative),
1405
- };
1406
- return poolShareDetail;
1407
- };
1408
- /**
1409
- *
1410
- * @param poolShare - the share of asset and rune added to the pool
1411
- * @param pool - Pool that the asset is attached to
1412
- * @returns - returns bignumber representing a slip percentage
1413
- */
1414
- const getSlipOnLiquidity = (stake, pool) => {
1415
- const baseAmount8decimals = getBaseAmountWithDiffDecimals(stake.asset, 8);
1416
- // formula: (t * R - T * r)/ (T*r + R*T)
1417
- const r = stake.rune.baseAmount.amount();
1418
- const t = baseAmount8decimals;
1419
- const R = pool.runeBalance.amount();
1420
- const T = pool.assetBalance.amount();
1421
- const numerator = t.times(R).minus(T.times(r));
1422
- const denominator = T.times(r).plus(R.times(T));
1423
- const result = numerator.div(denominator).abs();
1424
- return result;
1425
- };
1426
- /**
1427
- * https://docs.thorchain.org/thorchain-finance/continuous-liquidity-pools#impermanent-loss-protection
1428
- * @param poolShare - the share of asset and rune added to the pool
1429
- * @param pool - Pool that the asset is attached to
1430
- * @param block - blockl object with current, last added and the constant blocksforlossProtection
1431
- * @returns
1432
- */
1433
- // Blocks for full protection 1440000 // 100 days
1434
- const getLiquidityProtectionData = (depositValue, poolShare, block) => {
1435
- //Coverage formula coverage=((A0∗P1)+R0)−((A1∗P1)+R1)=>((A0∗R1/A1)+R0)−(R1+R1)
1436
- //formula: protectionProgress (currentHeight-heightLastAdded)/blocksforfullprotection
1437
- const R0 = depositValue.rune.amount(); // rune deposit value
1438
- const A0 = depositValue.asset.amount(); // asset deposit value
1439
- const R1 = poolShare.runeShare.baseAmount.amount(); // rune amount to redeem
1440
- const A1 = poolShare.assetShare.baseAmount.amount(); // asset amount to redeem
1441
- const P1 = R1.div(A1); // Pool ratio at withdrawal
1442
- const part1 = A0.times(P1).plus(R0).minus(A1.times(P1).plus(R1)); // start position minus end position
1443
- const part2 = A0.times(R1.div(A1)).plus(R0).minus(R1.plus(R1)); // different way to check position
1444
- const coverage = part1 >= part2 ? part1 : part2; // Coverage represents how much ILP a LP is entitled to
1445
- const currentHeight = block.current;
1446
- const heightLastAdded = block.lastAdded || 0; //default to zero if undefined
1447
- const blocksforfullprotection = block.fullProtection;
1448
- const fractionOfFullILPProtection = (currentHeight - heightLastAdded) / blocksforfullprotection;
1449
- const protectionProgress = Math.min(fractionOfFullILPProtection, 1); // percentage of entitlement, max 100%
1450
- const result = coverage.times(protectionProgress); // impermanent loss protection result
1451
- const maxILP = result.lt(0) ? new bignumber_js.BigNumber(0) : result; // max negative ILP to 0
1452
- const ILProtection = {
1453
- ILProtection: new CryptoAmount(xchainUtil.baseAmount(maxILP), xchainThorchain.AssetRuneNative),
1454
- totalDays: (fractionOfFullILPProtection * 100).toFixed(2),
1455
- };
1456
- return ILProtection;
1457
- };
1458
-
1459
1494
  const BN_1 = new bignumber_js.BigNumber(1);
1460
1495
  const defaultCache = new ThorchainCache();
1461
1496
  /**
@@ -1568,7 +1603,7 @@ class ThorchainQuery {
1568
1603
  isValidSwap(params) {
1569
1604
  var _a, _b;
1570
1605
  return __awaiter(this, void 0, void 0, function* () {
1571
- if (xchainThorchain.isAssetRuneNative(params.input.asset) || params.input.asset.synth) {
1606
+ if (isAssetRuneNative(params.input.asset) || params.input.asset.synth) {
1572
1607
  if (params.input.baseAmount.decimal !== 8)
1573
1608
  throw Error(`input asset ${xchainUtil.assetToString(params.input.asset)} must have decimals of 8`);
1574
1609
  }
@@ -1615,14 +1650,14 @@ class ThorchainQuery {
1615
1650
  const inboundFeeInInboundGasAsset = calcNetworkFee(input.asset, sourceInboundDetails);
1616
1651
  let outboundFeeInOutboundGasAsset = calcOutboundFee(params.destinationAsset, destinationInboundDetails);
1617
1652
  // Check outbound fee is equal too or greater than 1 USD * need to find a more permanent solution to this. referencing just 1 stable coin pool has problems
1618
- if (params.destinationAsset.chain !== xchainThorchain.THORChain && !params.destinationAsset.synth) {
1653
+ if (params.destinationAsset.chain !== THORChain && !params.destinationAsset.synth) {
1619
1654
  const deepestUSDPOOL = yield this.thorchainCache.getDeepestUSDPool();
1620
1655
  const usdAsset = deepestUSDPOOL.asset;
1621
1656
  const usdMinFee = new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount('1', Number(deepestUSDPOOL.pool.nativeDecimal))), usdAsset);
1622
1657
  const checkOutboundFee = (yield this.convert(outboundFeeInOutboundGasAsset, usdAsset)).gte(usdMinFee);
1623
1658
  if (!checkOutboundFee) {
1624
1659
  const newFee = usdMinFee;
1625
- outboundFeeInOutboundGasAsset = yield this.convert(newFee, xchainThorchain.AssetRuneNative);
1660
+ outboundFeeInOutboundGasAsset = yield this.convert(newFee, AssetRuneNative);
1626
1661
  }
1627
1662
  }
1628
1663
  // ----------- Remove Fees from inbound before doing the swap -----------
@@ -1633,15 +1668,15 @@ class ThorchainQuery {
1633
1668
  const affiliateFeePercent = params.affiliateFeeBasisPoints ? params.affiliateFeeBasisPoints / 10000 : 0;
1634
1669
  const affiliateFeeInAsset = inputMinusInboundFeeInAsset.times(affiliateFeePercent);
1635
1670
  let affiliateFeeSwapOutputInRune;
1636
- if (xchainThorchain.isAssetRuneNative(affiliateFeeInAsset.asset)) {
1671
+ if (isAssetRuneNative(affiliateFeeInAsset.asset)) {
1637
1672
  affiliateFeeSwapOutputInRune = {
1638
1673
  output: affiliateFeeInAsset,
1639
- swapFee: new CryptoAmount(xchainUtil.baseAmount(0), xchainThorchain.AssetRuneNative),
1674
+ swapFee: new CryptoAmount(xchainUtil.baseAmount(0), AssetRuneNative),
1640
1675
  slip: new bignumber_js.BigNumber(0),
1641
1676
  };
1642
1677
  }
1643
1678
  else {
1644
- affiliateFeeSwapOutputInRune = yield this.thorchainCache.getExpectedSwapOutput(affiliateFeeInAsset, xchainThorchain.AssetRuneNative);
1679
+ affiliateFeeSwapOutputInRune = yield this.thorchainCache.getExpectedSwapOutput(affiliateFeeInAsset, AssetRuneNative);
1645
1680
  }
1646
1681
  // remove the affiliate fee from the input.
1647
1682
  const inputNetInAsset = inputMinusInboundFeeInAsset.minus(affiliateFeeInAsset);
@@ -1672,7 +1707,7 @@ class ThorchainQuery {
1672
1707
  const contractAddress = xchainUtil.getContractAddressFromAsset(asset);
1673
1708
  if (contractAddress && contractAddress.length > 5) {
1674
1709
  const abrev = contractAddress.substring(contractAddress.length - 5);
1675
- const sep = asset.chain !== xchainThorchain.THORChain && asset.synth ? '/' : '.';
1710
+ const sep = asset.chain !== THORChain && asset.synth ? '/' : '.';
1676
1711
  return `${asset.chain}${sep}${asset.ticker}-${abrev}`;
1677
1712
  }
1678
1713
  return xchainUtil.assetToString(asset);
@@ -1693,7 +1728,7 @@ class ThorchainQuery {
1693
1728
  memo = memo.concat(`:${params.affiliateAddress}:${params.affiliateFeeBasisPoints}`);
1694
1729
  }
1695
1730
  // If memo length is too long for BTC, trim it
1696
- if (xchainUtil.eqAsset(params.input.asset, xchainBitcoin.AssetBTC) && memo.length > 80) {
1731
+ if (xchainUtil.eqAsset(params.input.asset, AssetBTC) && memo.length > 80) {
1697
1732
  memo = `=:${this.abbreviateAssetString(params.destinationAsset)}:${params.destinationAddress}:${lim}`;
1698
1733
  }
1699
1734
  return memo;
@@ -1731,12 +1766,12 @@ class ThorchainQuery {
1731
1766
  const errors = [];
1732
1767
  const sourceAsset = params.input.asset;
1733
1768
  const destAsset = params.destinationAsset;
1734
- if (!xchainThorchain.isAssetRuneNative(sourceAsset)) {
1769
+ if (!isAssetRuneNative(sourceAsset)) {
1735
1770
  const sourcePool = yield this.thorchainCache.getPoolForAsset(sourceAsset);
1736
1771
  if (!sourcePool.isAvailable())
1737
1772
  errors.push(`sourceAsset ${sourceAsset.ticker} does not have a valid liquidity pool`);
1738
1773
  }
1739
- if (!xchainThorchain.isAssetRuneNative(destAsset)) {
1774
+ if (!isAssetRuneNative(destAsset)) {
1740
1775
  const destPool = yield this.thorchainCache.getPoolForAsset(destAsset);
1741
1776
  if (!destPool.isAvailable())
1742
1777
  errors.push(`destinationAsset ${destAsset.ticker} does not have a valid liquidity pool`);
@@ -1782,8 +1817,8 @@ class ThorchainQuery {
1782
1817
  checkCoverFees(params, estimate) {
1783
1818
  return __awaiter(this, void 0, void 0, function* () {
1784
1819
  let result = undefined;
1785
- const inputInRune = yield this.thorchainCache.convert(params.input, xchainThorchain.AssetRuneNative);
1786
- const feesInRune = yield this.getFeesIn(estimate.totalFees, xchainThorchain.AssetRuneNative);
1820
+ const inputInRune = yield this.thorchainCache.convert(params.input, AssetRuneNative);
1821
+ const feesInRune = yield this.getFeesIn(estimate.totalFees, AssetRuneNative);
1787
1822
  const totalSwapFeesInRune = !params.input.asset.synth && isNativeChainAsset(params.input.asset)
1788
1823
  ? feesInRune.inboundFee.plus(feesInRune.outboundFee).plus(feesInRune.swapFee).plus(feesInRune.affiliateFee)
1789
1824
  : feesInRune.outboundFee.plus(feesInRune.swapFee).plus(feesInRune.affiliateFee);
@@ -1840,11 +1875,11 @@ class ThorchainQuery {
1840
1875
  confCounting(inbound) {
1841
1876
  return __awaiter(this, void 0, void 0, function* () {
1842
1877
  // RUNE, BNB and Synths have near instant finality, so no conf counting required. - need to make a BFT only case.
1843
- if (xchainThorchain.isAssetRuneNative(inbound.asset) ||
1844
- inbound.asset.chain == xchainBinance.BNBChain ||
1845
- inbound.asset.chain == xchainCosmos.GAIAChain ||
1878
+ if (isAssetRuneNative(inbound.asset) ||
1879
+ inbound.asset.chain == BNBChain ||
1880
+ inbound.asset.chain == GAIAChain ||
1846
1881
  inbound.asset.synth) {
1847
- return this.chainAttributes[xchainThorchain.THORChain].avgBlockTimeInSecs;
1882
+ return this.chainAttributes[THORChain].avgBlockTimeInSecs;
1848
1883
  }
1849
1884
  // Get the gas asset for the inbound.asset.chain
1850
1885
  const chainGasAsset = getChainAsset(inbound.asset.chain);
@@ -1869,16 +1904,16 @@ class ThorchainQuery {
1869
1904
  outboundDelay(outboundAmount) {
1870
1905
  return __awaiter(this, void 0, void 0, function* () {
1871
1906
  const networkValues = yield this.thorchainCache.getNetworkValues();
1872
- const minTxOutVolumeThreshold = new CryptoAmount(xchainUtil.baseAmount(networkValues['MINTXOUTVOLUMETHRESHOLD']), xchainThorchain.AssetRuneNative);
1907
+ const minTxOutVolumeThreshold = new CryptoAmount(xchainUtil.baseAmount(networkValues['MINTXOUTVOLUMETHRESHOLD']), AssetRuneNative);
1873
1908
  const maxTxOutOffset = networkValues['MAXTXOUTOFFSET'];
1874
- let txOutDelayRate = new CryptoAmount(xchainUtil.baseAmount(networkValues['TXOUTDELAYRATE']), xchainThorchain.AssetRuneNative).assetAmount
1909
+ let txOutDelayRate = new CryptoAmount(xchainUtil.baseAmount(networkValues['TXOUTDELAYRATE']), AssetRuneNative).assetAmount
1875
1910
  .amount()
1876
1911
  .toNumber();
1877
1912
  const getQueue = yield this.thorchainCache.thornode.getQueue();
1878
- const outboundValue = new CryptoAmount(xchainUtil.baseAmount(getQueue.scheduled_outbound_value), xchainThorchain.AssetRuneNative);
1879
- const thorChainblocktime = this.chainAttributes[xchainThorchain.THORChain].avgBlockTimeInSecs; // blocks required to confirm tx
1913
+ const outboundValue = new CryptoAmount(xchainUtil.baseAmount(getQueue.scheduled_outbound_value), AssetRuneNative);
1914
+ const thorChainblocktime = this.chainAttributes[THORChain].avgBlockTimeInSecs; // blocks required to confirm tx
1880
1915
  // If asset is equal to Rune set runeValue as outbound amount else set it to the asset's value in rune
1881
- const runeValue = yield this.thorchainCache.convert(outboundAmount, xchainThorchain.AssetRuneNative);
1916
+ const runeValue = yield this.thorchainCache.convert(outboundAmount, AssetRuneNative);
1882
1917
  // Check rune value amount
1883
1918
  if (runeValue.lt(minTxOutVolumeThreshold)) {
1884
1919
  return thorChainblocktime;
@@ -1909,7 +1944,7 @@ class ThorchainQuery {
1909
1944
  const errors = [];
1910
1945
  if (params.asset.asset.synth || params.rune.asset.synth)
1911
1946
  errors.push('you cannot add liquidity with a synth');
1912
- if (!xchainThorchain.isAssetRuneNative(params.rune.asset))
1947
+ if (!isAssetRuneNative(params.rune.asset))
1913
1948
  errors.push('params.rune must be THOR.RUNE');
1914
1949
  const assetPool = yield this.thorchainCache.getPoolForAsset(params.asset.asset);
1915
1950
  const lpUnits = getLiquidityUnits({ asset: params.asset, rune: params.rune }, assetPool);
@@ -1923,7 +1958,7 @@ class ThorchainQuery {
1923
1958
  const runeWaitTimeSeconds = yield this.confCounting(params.rune);
1924
1959
  const waitTimeSeconds = assetWaitTimeSeconds > runeWaitTimeSeconds ? assetWaitTimeSeconds : runeWaitTimeSeconds;
1925
1960
  let assetInboundFee = new CryptoAmount(xchainUtil.baseAmount(0), params.asset.asset);
1926
- let runeInboundFee = new CryptoAmount(xchainUtil.baseAmount(0), xchainThorchain.AssetRuneNative);
1961
+ let runeInboundFee = new CryptoAmount(xchainUtil.baseAmount(0), AssetRuneNative);
1927
1962
  if (!params.asset.assetAmount.eq(0)) {
1928
1963
  assetInboundFee = calcNetworkFee(params.asset.asset, inboundDetails[params.asset.asset.chain]);
1929
1964
  if (assetInboundFee.assetAmount.amount().times(3).gt(params.asset.assetAmount.amount()))
@@ -1934,7 +1969,7 @@ class ThorchainQuery {
1934
1969
  if (runeInboundFee.assetAmount.amount().times(3).gt(params.rune.assetAmount.amount()))
1935
1970
  errors.push(`Rune amount is less than fees`);
1936
1971
  }
1937
- const totalFees = (yield this.convert(assetInboundFee, xchainThorchain.AssetRuneNative)).plus(runeInboundFee);
1972
+ const totalFees = (yield this.convert(assetInboundFee, AssetRuneNative)).plus(runeInboundFee);
1938
1973
  const slip = getSlipOnLiquidity({ asset: params.asset, rune: params.rune }, assetPool);
1939
1974
  const estimateLP = {
1940
1975
  assetPool: assetPool.pool.asset,
@@ -2064,9 +2099,9 @@ class ThorchainQuery {
2064
2099
  }
2065
2100
  const allInboundDetails = yield this.thorchainCache.getInboundDetails();
2066
2101
  const inboundDetails = allInboundDetails[params.asset.chain];
2067
- const runeInbound = calcNetworkFee(xchainThorchain.AssetRuneNative, inboundDetails);
2102
+ const runeInbound = calcNetworkFee(AssetRuneNative, inboundDetails);
2068
2103
  const assetInbound = calcNetworkFee(params.asset, inboundDetails);
2069
- const runeOutbound = calcOutboundFee(xchainThorchain.AssetRuneNative, inboundDetails);
2104
+ const runeOutbound = calcOutboundFee(AssetRuneNative, inboundDetails);
2070
2105
  const assetOutbound = calcOutboundFee(params.asset, inboundDetails);
2071
2106
  const estimateLP = {
2072
2107
  assetAddress: memberDetail.position.asset_address,
@@ -2076,18 +2111,18 @@ class ThorchainQuery {
2076
2111
  minToSend: {
2077
2112
  rune: dustValues.rune,
2078
2113
  asset: dustValues.asset,
2079
- total: (yield this.convert(dustValues.asset, xchainThorchain.AssetRuneNative)).plus(dustValues.rune),
2114
+ total: (yield this.convert(dustValues.asset, AssetRuneNative)).plus(dustValues.rune),
2080
2115
  },
2081
2116
  fees: {
2082
2117
  rune: runeInbound,
2083
2118
  asset: assetInbound,
2084
- total: (yield this.convert(assetInbound, xchainThorchain.AssetRuneNative)).plus(runeInbound),
2119
+ total: (yield this.convert(assetInbound, AssetRuneNative)).plus(runeInbound),
2085
2120
  },
2086
2121
  },
2087
2122
  outboundFee: {
2088
2123
  asset: assetOutbound,
2089
2124
  rune: runeOutbound,
2090
- total: (yield this.convert(assetOutbound, xchainThorchain.AssetRuneNative)).plus(runeOutbound),
2125
+ total: (yield this.convert(assetOutbound, AssetRuneNative)).plus(runeOutbound),
2091
2126
  },
2092
2127
  assetAmount: poolShare.assetShare,
2093
2128
  runeAmount: poolShare.runeShare,
@@ -2110,8 +2145,8 @@ class ThorchainQuery {
2110
2145
  switch (asset.chain) {
2111
2146
  case 'BNB':
2112
2147
  dustValues = {
2113
- asset: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0.000001)), xchainBinance.AssetBNB),
2114
- rune: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), xchainThorchain.AssetRuneNative),
2148
+ asset: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0.000001)), AssetBNB),
2149
+ rune: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), AssetRuneNative),
2115
2150
  };
2116
2151
  return dustValues;
2117
2152
  case 'BTC':
@@ -2120,42 +2155,56 @@ class ThorchainQuery {
2120
2155
  // 10k sats
2121
2156
  dustValues = {
2122
2157
  asset: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0.0001)), asset),
2123
- rune: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), xchainThorchain.AssetRuneNative),
2158
+ rune: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), AssetRuneNative),
2124
2159
  };
2125
2160
  return dustValues;
2126
2161
  case 'ETH':
2127
2162
  // 0 wei
2128
2163
  dustValues = {
2129
2164
  asset: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), asset),
2130
- rune: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), xchainThorchain.AssetRuneNative),
2165
+ rune: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), AssetRuneNative),
2131
2166
  };
2132
2167
  return dustValues;
2133
2168
  case 'THOR':
2134
2169
  // 0 Rune
2135
2170
  dustValues = {
2136
2171
  asset: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), asset),
2137
- rune: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), xchainThorchain.AssetRuneNative),
2172
+ rune: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), AssetRuneNative),
2138
2173
  };
2139
2174
  return dustValues;
2140
2175
  case 'GAIA':
2141
2176
  // 0 GAIA
2142
2177
  dustValues = {
2143
2178
  asset: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), asset),
2144
- rune: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), xchainThorchain.AssetRuneNative),
2179
+ rune: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), AssetRuneNative),
2145
2180
  };
2146
2181
  return dustValues;
2147
2182
  case 'DOGE':
2148
2183
  // 1 million sats
2149
2184
  dustValues = {
2150
2185
  asset: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0.01)), asset),
2151
- rune: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), xchainThorchain.AssetRuneNative),
2186
+ rune: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), AssetRuneNative),
2152
2187
  };
2153
2188
  return dustValues;
2154
2189
  case 'AVAX':
2155
2190
  // 0 AVAX
2156
2191
  dustValues = {
2157
2192
  asset: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), asset),
2158
- rune: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), xchainThorchain.AssetRuneNative),
2193
+ rune: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), AssetRuneNative),
2194
+ };
2195
+ return dustValues;
2196
+ case 'BSC':
2197
+ // 0 BSC
2198
+ dustValues = {
2199
+ asset: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), asset),
2200
+ rune: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), AssetRuneNative),
2201
+ };
2202
+ return dustValues;
2203
+ case 'MAYA':
2204
+ // 0 MAYA
2205
+ dustValues = {
2206
+ asset: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), asset),
2207
+ rune: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), AssetRuneNative),
2159
2208
  };
2160
2209
  return dustValues;
2161
2210
  default:
@@ -2168,7 +2217,17 @@ class ThorchainQuery {
2168
2217
  estimateAddSaver(addAmount) {
2169
2218
  return __awaiter(this, void 0, void 0, function* () {
2170
2219
  let errors = [];
2220
+ // check for errors before sending quote
2171
2221
  errors = yield this.getAddSaversEstimateErrors(addAmount);
2222
+ // request param amount should always be in 1e8 which is why we pass in adjusted decimals if chain decimals != 8
2223
+ const newAddAmount = addAmount.baseAmount.decimal != 8 ? getBaseAmountWithDiffDecimals(addAmount, 8) : addAmount.baseAmount.amount();
2224
+ // Fetch quote
2225
+ const depositQuote = yield this.thorchainCache.thornode.getSaversDepositQuote(xchainUtil.assetToString(addAmount.asset), newAddAmount.toNumber());
2226
+ // error handling
2227
+ const response = JSON.parse(JSON.stringify(depositQuote));
2228
+ if (response.error)
2229
+ errors.push(`Thornode request quote failed: ${response.error}`);
2230
+ // Return errors if there is any
2172
2231
  if (errors.length > 0) {
2173
2232
  return {
2174
2233
  assetAmount: addAmount,
@@ -2188,29 +2247,27 @@ class ThorchainQuery {
2188
2247
  errors,
2189
2248
  };
2190
2249
  }
2191
- // request param amount should always be in 1e8 which is why we pass in adjusted decimals if chain decimals != 8
2192
- const newAddAmount = addAmount.baseAmount.decimal != 8 ? getBaseAmountWithDiffDecimals(addAmount, 8) : addAmount.baseAmount.amount();
2193
- const depositQuote = yield this.thorchainCache.thornode.getSaversDepositQuote(xchainUtil.assetToString(addAmount.asset), newAddAmount.toNumber());
2194
2250
  // Calculate transaction expiry time of the vault address
2195
2251
  const currentDatetime = new Date();
2196
2252
  const minutesToAdd = 15;
2197
2253
  const expiryDatetime = new Date(currentDatetime.getTime() + minutesToAdd * 60000);
2254
+ // Calculate seconds
2198
2255
  const estimatedWait = depositQuote.inbound_confirmation_seconds
2199
2256
  ? depositQuote.inbound_confirmation_seconds
2200
2257
  : yield this.confCounting(addAmount);
2201
2258
  const pool = (yield this.thorchainCache.getPoolForAsset(addAmount.asset)).pool;
2202
- if (addAmount.baseAmount.lte(depositQuote.expected_amount_out))
2203
- errors.push(`Amount being added to savers can't pay for fees`);
2259
+ // Organise fees
2204
2260
  const saverFees = {
2205
2261
  affiliate: new CryptoAmount(xchainUtil.baseAmount(depositQuote.fees.affiliate), addAmount.asset),
2206
2262
  asset: xchainUtil.assetFromStringEx(depositQuote.fees.asset),
2207
2263
  outbound: new CryptoAmount(xchainUtil.baseAmount(depositQuote.fees.outbound), addAmount.asset),
2208
2264
  };
2265
+ // define savers cap
2209
2266
  const saverCap = 0.3 * +pool.assetDepth;
2210
2267
  const saverCapFilledPercent = (+pool.saversDepth / saverCap) * 100;
2211
2268
  const estimateAddSaver = {
2212
2269
  assetAmount: new CryptoAmount(xchainUtil.baseAmount(depositQuote.expected_amount_out), addAmount.asset),
2213
- estimatedDepositValue: new CryptoAmount(xchainUtil.baseAmount(depositQuote.expected_amount_out), saverFees.asset),
2270
+ estimatedDepositValue: new CryptoAmount(xchainUtil.baseAmount(depositQuote.expected_amount_deposit), addAmount.asset),
2214
2271
  fee: saverFees,
2215
2272
  expiry: expiryDatetime,
2216
2273
  toAddress: depositQuote.inbound_address,
@@ -2231,12 +2288,56 @@ class ThorchainQuery {
2231
2288
  */
2232
2289
  estimateWithdrawSaver(withdrawParams) {
2233
2290
  return __awaiter(this, void 0, void 0, function* () {
2234
- if (xchainThorchain.isAssetRuneNative(withdrawParams.asset) || withdrawParams.asset.synth)
2235
- throw Error(`Native Rune and synth assets are not supported only L1's`);
2291
+ const errors = [];
2292
+ // return error if Asset in is incorrect
2293
+ if (isAssetRuneNative(withdrawParams.asset) || withdrawParams.asset.synth)
2294
+ errors.push(`Native Rune and synth assets are not supported only L1's`);
2295
+ const inboundDetails = yield this.thorchainCache.getInboundDetails();
2296
+ // Check to see if there is a position before calling withdraw quote
2297
+ const checkPositon = yield this.getSaverPosition(withdrawParams);
2298
+ if (checkPositon.errors.length > 0) {
2299
+ for (let i = 0; i < checkPositon.errors.length; i++) {
2300
+ errors.push(checkPositon.errors[i]);
2301
+ }
2302
+ return {
2303
+ expectedAssetAmount: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(checkPositon.redeemableValue.assetAmount.amount())), withdrawParams.asset),
2304
+ fee: {
2305
+ affiliate: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), withdrawParams.asset),
2306
+ asset: withdrawParams.asset,
2307
+ outbound: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(calcOutboundFee(withdrawParams.asset, inboundDetails[withdrawParams.asset.chain]).assetAmount.amount())), withdrawParams.asset),
2308
+ },
2309
+ expiry: new Date(0),
2310
+ toAddress: '',
2311
+ memo: '',
2312
+ estimatedWaitTime: -1,
2313
+ slipBasisPoints: -1,
2314
+ dustAmount: new CryptoAmount(xchainUtil.baseAmount(0), withdrawParams.asset),
2315
+ errors,
2316
+ };
2317
+ }
2318
+ // Request withdraw quote
2236
2319
  const withdrawQuote = yield this.thorchainCache.thornode.getSaversWithdrawQuote(withdrawParams);
2237
- if (!withdrawQuote.expected_amount_out)
2238
- throw Error(`Could not quote withdrawal ${JSON.stringify(withdrawQuote)}`);
2239
- // const pool = (await this.thorchainCache.getPoolForAsset(withdrawParams.asset)).pool
2320
+ // error handling
2321
+ const response = JSON.parse(JSON.stringify(withdrawQuote));
2322
+ if (response.error)
2323
+ errors.push(`Thornode request quote failed: ${response.error}`);
2324
+ if (errors.length > 0) {
2325
+ return {
2326
+ expectedAssetAmount: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), withdrawParams.asset),
2327
+ fee: {
2328
+ affiliate: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), withdrawParams.asset),
2329
+ asset: withdrawParams.asset,
2330
+ outbound: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), withdrawParams.asset),
2331
+ },
2332
+ expiry: new Date(0),
2333
+ toAddress: '',
2334
+ memo: '',
2335
+ estimatedWaitTime: -1,
2336
+ slipBasisPoints: -1,
2337
+ dustAmount: new CryptoAmount(xchainUtil.baseAmount(0), withdrawParams.asset),
2338
+ errors,
2339
+ };
2340
+ }
2240
2341
  // Calculate transaction expiry time of the vault address
2241
2342
  const currentDatetime = new Date();
2242
2343
  const minutesToAdd = 15;
@@ -2256,6 +2357,7 @@ class ThorchainQuery {
2256
2357
  estimatedWaitTime: estimatedWait,
2257
2358
  slipBasisPoints: withdrawQuote.slippage_bps,
2258
2359
  dustAmount: new CryptoAmount(xchainUtil.baseAmount(withdrawQuote.dust_amount), withdrawParams.asset),
2360
+ errors,
2259
2361
  };
2260
2362
  return estimateWithdrawSaver;
2261
2363
  });
@@ -2267,31 +2369,37 @@ class ThorchainQuery {
2267
2369
  */
2268
2370
  getSaverPosition(params) {
2269
2371
  return __awaiter(this, void 0, void 0, function* () {
2372
+ const errors = [];
2373
+ const inboundDetails = yield this.thorchainCache.getInboundDetails();
2270
2374
  const blockData = (yield this.thorchainCache.thornode.getLastBlock()).find((item) => item.chain === params.asset.chain);
2271
2375
  const savers = (yield this.thorchainCache.thornode.getSavers(`${params.asset.chain}.${params.asset.ticker}`)).find((item) => item.asset_address === params.address);
2272
2376
  const pool = (yield this.thorchainCache.getPoolForAsset(params.asset)).pool;
2273
2377
  if (!savers)
2274
- throw Error(`Could not find position for ${params.address}`);
2275
- if (!savers.last_add_height)
2276
- throw Error(`Could not find position for ${params.address}`);
2378
+ errors.push(`Could not find position for ${params.address}`);
2379
+ if (!(savers === null || savers === void 0 ? void 0 : savers.last_add_height))
2380
+ errors.push(`Could not find position for ${params.address}`);
2277
2381
  if (!(blockData === null || blockData === void 0 ? void 0 : blockData.thorchain))
2278
- throw Error(`Could not get thorchain block height`);
2279
- const ownerUnits = Number(savers.units);
2280
- const lastAdded = Number(savers.last_add_height);
2382
+ errors.push(`Could not get thorchain block height`);
2383
+ const outboundFee = yield calcOutboundFee(params.asset, inboundDetails[params.asset.chain]);
2384
+ if (Number(savers === null || savers === void 0 ? void 0 : savers.asset_redeem_value) < outboundFee.baseAmount.amount().toNumber())
2385
+ errors.push(`Unlikely to withdraw balance as outbound fee is greater than redeemable amount`);
2386
+ const ownerUnits = Number(savers === null || savers === void 0 ? void 0 : savers.units);
2387
+ const lastAdded = Number(savers === null || savers === void 0 ? void 0 : savers.last_add_height);
2281
2388
  const saverUnits = Number(pool.saversUnits);
2282
2389
  const assetDepth = Number(pool.saversDepth);
2283
2390
  const redeemableValue = (ownerUnits / saverUnits) * assetDepth;
2284
- const depositAmount = new CryptoAmount(xchainUtil.baseAmount(savers.asset_deposit_value), params.asset);
2391
+ const depositAmount = new CryptoAmount(xchainUtil.baseAmount(savers === null || savers === void 0 ? void 0 : savers.asset_deposit_value), params.asset);
2285
2392
  const redeemableAssetAmount = new CryptoAmount(xchainUtil.baseAmount(redeemableValue), params.asset);
2286
- const saversAge = ((blockData === null || blockData === void 0 ? void 0 : blockData.thorchain) - lastAdded) / ((365 * 86400) / 6);
2393
+ const saversAge = (Number(blockData === null || blockData === void 0 ? void 0 : blockData.thorchain) - lastAdded) / ((365 * 86400) / 6);
2287
2394
  const saverGrowth = redeemableAssetAmount.minus(depositAmount).div(depositAmount).times(100);
2288
2395
  const saversPos = {
2289
2396
  depositValue: depositAmount,
2290
2397
  redeemableValue: redeemableAssetAmount,
2291
- lastAddHeight: savers.last_add_height,
2398
+ lastAddHeight: Number(savers === null || savers === void 0 ? void 0 : savers.last_add_height),
2292
2399
  percentageGrowth: saverGrowth.assetAmount.amount().toNumber(),
2293
2400
  ageInYears: saversAge,
2294
2401
  ageInDays: saversAge * 365,
2402
+ errors,
2295
2403
  };
2296
2404
  return saversPos;
2297
2405
  });
@@ -2310,6 +2418,9 @@ class ThorchainQuery {
2310
2418
  const pool = (yield this.thorchainCache.getPoolForAsset(addAmount.asset)).pool;
2311
2419
  if (pool.status.toLowerCase() !== 'available')
2312
2420
  errors.push(`Pool is not available for this asset ${xchainUtil.assetToString(addAmount.asset)}`);
2421
+ const inboundFee = calcNetworkFee(addAmount.asset, inboundDetails[addAmount.asset.chain]);
2422
+ if (addAmount.lte(inboundFee))
2423
+ errors.push(`Add amount does not cover fees`);
2313
2424
  return errors;
2314
2425
  });
2315
2426
  }
@@ -2414,11 +2525,11 @@ class TransactionStage {
2414
2525
  //const assetIn = assetFromStringEx(txData.tx.tx.coins?.[0].asset)
2415
2526
  const swapStatus = ((_b = txData.out_txs[0].memo) === null || _b === void 0 ? void 0 : _b.match('OUT')) ? exports.SwapStatus.Complete : exports.SwapStatus.Complete_Refunded;
2416
2527
  // current height of thorchain, neeed for confirmations
2417
- const chainHeight = yield this.blockHeight(xchainThorchain.AssetRuneNative);
2528
+ const chainHeight = yield this.blockHeight(AssetRuneNative);
2418
2529
  // expected outbound height
2419
2530
  const outboundHeight = Number((_c = txData.outbound_height) !== null && _c !== void 0 ? _c : txData.finalised_height);
2420
2531
  const expectedOutBlock = Number((_d = txData.outbound_height) !== null && _d !== void 0 ? _d : txData.finalised_height);
2421
- const expectedOutDate = yield this.blockToDate(xchainThorchain.THORChain, txData, outboundHeight); // height held in the scheduled queue
2532
+ const expectedOutDate = yield this.blockToDate(THORChain, txData, outboundHeight); // height held in the scheduled queue
2422
2533
  const confirmations = chainHeight > outboundHeight ? chainHeight - outboundHeight : 0;
2423
2534
  const minimumAmountOut = memoFields.limit
2424
2535
  ? yield this.getCryptoAmount(memoFields.limit, assetOut)
@@ -2454,7 +2565,7 @@ class TransactionStage {
2454
2565
  }
2455
2566
  getCryptoAmount(baseAmt, asset) {
2456
2567
  return __awaiter(this, void 0, void 0, function* () {
2457
- const decimals = xchainThorchain.THORChain === asset.chain ? 8 : Number((yield this.thorchainCache.getPoolForAsset(asset)).pool.nativeDecimal);
2568
+ const decimals = THORChain === asset.chain ? 8 : Number((yield this.thorchainCache.getPoolForAsset(asset)).pool.nativeDecimal);
2458
2569
  return new CryptoAmount(xchainUtil.baseAmount(baseAmt, decimals), asset);
2459
2570
  });
2460
2571
  }
@@ -2471,8 +2582,8 @@ class TransactionStage {
2471
2582
  const assetIn = xchainUtil.assetFromStringEx((_b = txData.tx.tx.coins) === null || _b === void 0 ? void 0 : _b[0].asset);
2472
2583
  const inboundAmount = (_c = txData.tx.tx.coins) === null || _c === void 0 ? void 0 : _c[0].amount;
2473
2584
  const fromAddress = (_d = txData.tx.tx.from_address) !== null && _d !== void 0 ? _d : 'unknkown';
2474
- const block = txData.tx.tx.chain == xchainThorchain.THORChain ? Number(txData.finalised_height) : Number(txData.tx.block_height);
2475
- const finalizeBlock = txData.tx.tx.chain == xchainThorchain.THORChain ? Number(txData.finalised_height) : Number(txData.tx.finalise_height);
2585
+ const block = txData.tx.tx.chain == THORChain ? Number(txData.finalised_height) : Number(txData.tx.block_height);
2586
+ const finalizeBlock = txData.tx.tx.chain == THORChain ? Number(txData.finalised_height) : Number(txData.tx.finalise_height);
2476
2587
  const status = txData.tx.status === 'done' ? exports.InboundStatus.Observed_Consensus : exports.InboundStatus.Observed_Incomplete;
2477
2588
  if (operation.match(/swap|s|=/gi))
2478
2589
  progress.txType = exports.TxType.Swap;
@@ -2490,9 +2601,9 @@ class TransactionStage {
2490
2601
  progress.txType = exports.TxType.Other;
2491
2602
  const amount = yield this.getCryptoAmount(inboundAmount, assetIn);
2492
2603
  // find a date for when it should be competed
2493
- const dateObserved = yield this.blockToDate(xchainThorchain.THORChain, txData);
2494
- const expectedConfirmationDate = txData.tx.tx.chain === xchainThorchain.THORChain
2495
- ? yield this.blockToDate(xchainThorchain.THORChain, txData)
2604
+ const dateObserved = yield this.blockToDate(THORChain, txData);
2605
+ const expectedConfirmationDate = txData.tx.tx.chain === THORChain
2606
+ ? yield this.blockToDate(THORChain, txData)
2496
2607
  : yield this.blockToDate(assetIn.chain, txData);
2497
2608
  progress.inboundObserved = {
2498
2609
  status,
@@ -2516,8 +2627,8 @@ class TransactionStage {
2516
2627
  const memoFields = this.parseAddLpMemo(memo);
2517
2628
  const asset = xchainUtil.assetFromStringEx(memoFields.asset);
2518
2629
  const isSymmetric = memoFields.pairedAddress ? true : false;
2519
- const assetTx = !xchainThorchain.isAssetRuneNative(progress.inboundObserved.amount.asset) ? progress.inboundObserved : undefined;
2520
- const runeTx = xchainThorchain.isAssetRuneNative(progress.inboundObserved.amount.asset) ? progress.inboundObserved : undefined;
2630
+ const assetTx = !isAssetRuneNative(progress.inboundObserved.amount.asset) ? progress.inboundObserved : undefined;
2631
+ const runeTx = isAssetRuneNative(progress.inboundObserved.amount.asset) ? progress.inboundObserved : undefined;
2521
2632
  const pairedAssetExpectedConfirmationDate = assetTx ? yield this.blockToDate(asset.chain, txData) : undefined;
2522
2633
  const checkLpPosition = yield this.thorchainCache.thornode.getLiquidityProvider(memoFields.asset, progress.inboundObserved.fromAddress);
2523
2634
  const status = checkLpPosition ? exports.AddLpStatus.Complete : exports.AddLpStatus.Incomplete;
@@ -2544,14 +2655,14 @@ class TransactionStage {
2544
2655
  const currentHeight = lastBlockObj.find((obj) => obj);
2545
2656
  // find the date in which the asset should be seen in the wallet
2546
2657
  const outboundHeight = txData.tx.status === 'done' ? txData.finalised_height : Number(`${txData.outbound_height}`);
2547
- const expectedConfirmationDate = yield this.blockToDate(xchainThorchain.THORChain, txData, outboundHeight); // always pass in thorchain
2658
+ const expectedConfirmationDate = yield this.blockToDate(THORChain, txData, outboundHeight); // always pass in thorchain
2548
2659
  // if the TC has process the block that the outbound tx was assigned to then its completed.
2549
2660
  const status = txData.tx.status === 'done' ? exports.WithdrawStatus.Complete : exports.WithdrawStatus.Incomplete;
2550
2661
  const outAmount = status === exports.WithdrawStatus.Complete ? JSON.stringify(txData.out_txs).split(`"amount":"`)[1].split(`"`) : '';
2551
2662
  const outboundBlock = Number((_b = txData.outbound_height) !== null && _b !== void 0 ? _b : txData.finalised_height);
2552
2663
  const currentTCHeight = Number(`${currentHeight === null || currentHeight === void 0 ? void 0 : currentHeight.thorchain}`);
2553
2664
  const estimatedWaitTime = outboundBlock > currentTCHeight
2554
- ? (outboundBlock - currentTCHeight) * this.chainAttributes[xchainThorchain.THORChain].avgBlockTimeInSecs
2665
+ ? (outboundBlock - currentTCHeight) * this.chainAttributes[THORChain].avgBlockTimeInSecs
2555
2666
  : 0;
2556
2667
  const withdrawalAmount = yield this.getCryptoAmount(outAmount[0], asset);
2557
2668
  const withdrawLpInfo = {
@@ -2569,7 +2680,7 @@ class TransactionStage {
2569
2680
  checkAddSaverProgress(txData, progress) {
2570
2681
  return __awaiter(this, void 0, void 0, function* () {
2571
2682
  if (progress.inboundObserved) {
2572
- const assetTx = !xchainThorchain.isAssetRuneNative(progress.inboundObserved.amount.asset) ? progress.inboundObserved : undefined;
2683
+ const assetTx = !isAssetRuneNative(progress.inboundObserved.amount.asset) ? progress.inboundObserved : undefined;
2573
2684
  const checkSaverVaults = yield this.thorchainCache.thornode.getSaver(txData.tx.tx.coins[0].asset, `${assetTx === null || assetTx === void 0 ? void 0 : assetTx.fromAddress}`);
2574
2685
  const status = checkSaverVaults ? exports.AddSaverStatus.Complete : exports.AddSaverStatus.Incomplete;
2575
2686
  const addSaverInfo = {
@@ -2592,13 +2703,13 @@ class TransactionStage {
2592
2703
  const currentHeight = lastBlockObj.find((obj) => obj);
2593
2704
  // find the date in which the asset should be seen in the wallet
2594
2705
  const outboundHeight = txData.tx.status === 'done' ? txData.finalised_height : Number(`${txData.outbound_height}`);
2595
- const expectedConfirmationDate = yield this.blockToDate(xchainThorchain.THORChain, txData, outboundHeight); // always pass in thorchain
2706
+ const expectedConfirmationDate = yield this.blockToDate(THORChain, txData, outboundHeight); // always pass in thorchain
2596
2707
  const outAmount = txData.out_txs ? JSON.stringify(txData.out_txs).split(`"amount":"`)[1].split(`"`) : '';
2597
2708
  const outboundBlock = Number(txData.outbound_height);
2598
2709
  const finalisedHeight = Number(txData.finalised_height);
2599
2710
  const currentTCHeight = Number(`${currentHeight === null || currentHeight === void 0 ? void 0 : currentHeight.thorchain}`);
2600
2711
  const estimatedWaitTime = outboundBlock > currentTCHeight
2601
- ? (outboundBlock - currentTCHeight) * this.chainAttributes[xchainThorchain.THORChain].avgBlockTimeInSecs +
2712
+ ? (outboundBlock - currentTCHeight) * this.chainAttributes[THORChain].avgBlockTimeInSecs +
2602
2713
  this.chainAttributes[asset.chain].avgBlockTimeInSecs
2603
2714
  : 0;
2604
2715
  // if the TC has process the block that the outbound tx was assigned to then its completed.
@@ -2623,7 +2734,7 @@ class TransactionStage {
2623
2734
  const lastBlockObj = yield this.thorchainCache.thornode.getLastBlock();
2624
2735
  // find the date in which the asset should be seen in the wallet
2625
2736
  const outboundHeight = txData.tx.status === 'done' ? txData.finalised_height : Number(`${txData.outbound_height}`);
2626
- const expectedConfirmationDate = yield this.blockToDate(xchainThorchain.THORChain, txData, outboundHeight); // always pass in thorchain
2737
+ const expectedConfirmationDate = yield this.blockToDate(THORChain, txData, outboundHeight); // always pass in thorchain
2627
2738
  const amount = txData.tx.tx.coins[0].amount;
2628
2739
  const asset = xchainUtil.assetFromStringEx(txData.tx.tx.coins[0].asset);
2629
2740
  const toAddress = `${txData.tx.tx.to_address}`;
@@ -2633,7 +2744,7 @@ class TransactionStage {
2633
2744
  const finalisedHeight = Number(txData.finalised_height);
2634
2745
  const currentTCHeight = Number(`${currentHeight === null || currentHeight === void 0 ? void 0 : currentHeight.thorchain}`);
2635
2746
  const estimatedWaitTime = outboundBlock > currentTCHeight
2636
- ? (outboundBlock - currentTCHeight) * this.chainAttributes[xchainThorchain.THORChain].avgBlockTimeInSecs +
2747
+ ? (outboundBlock - currentTCHeight) * this.chainAttributes[THORChain].avgBlockTimeInSecs +
2637
2748
  this.chainAttributes[asset.chain].avgBlockTimeInSecs
2638
2749
  : 0;
2639
2750
  // if the TC has process the block that the outbound tx was assigned to then its completed.
@@ -2705,7 +2816,7 @@ class TransactionStage {
2705
2816
  }
2706
2817
  }
2707
2818
  // find out how long ago it was processed for all chains
2708
- if (chain == xchainThorchain.THORChain) {
2819
+ if (chain == THORChain) {
2709
2820
  const currentHeight = lastBlockObj.find((obj) => obj);
2710
2821
  const thorchainHeight = Number(`${currentHeight === null || currentHeight === void 0 ? void 0 : currentHeight.thorchain}`); // current height of the TC
2711
2822
  const finalisedHeight = Number(`${txData.finalised_height}`); // height tx was completed in
@@ -2730,7 +2841,7 @@ class TransactionStage {
2730
2841
  const lastBlockObj = yield this.thorchainCache.thornode.getLastBlock();
2731
2842
  const currentHeight = lastBlockObj.find((obj) => obj.chain == asset.chain);
2732
2843
  let blockHeight;
2733
- if (asset.chain === xchainThorchain.THORChain || asset.synth) {
2844
+ if (asset.chain === THORChain || asset.synth) {
2734
2845
  const currentHeight = lastBlockObj.find((obj) => obj);
2735
2846
  blockHeight = Number(`${currentHeight === null || currentHeight === void 0 ? void 0 : currentHeight.thorchain}`);
2736
2847
  }
@@ -2742,9 +2853,31 @@ class TransactionStage {
2742
2853
  }
2743
2854
  }
2744
2855
 
2856
+ exports.AVAXChain = AVAXChain;
2857
+ exports.AssetATOM = AssetATOM;
2858
+ exports.AssetAVAX = AssetAVAX;
2859
+ exports.AssetBCH = AssetBCH;
2860
+ exports.AssetBNB = AssetBNB;
2861
+ exports.AssetBSC = AssetBSC;
2862
+ exports.AssetBTC = AssetBTC;
2863
+ exports.AssetDOGE = AssetDOGE;
2864
+ exports.AssetETH = AssetETH;
2865
+ exports.AssetLTC = AssetLTC;
2866
+ exports.AssetMAYA = AssetMAYA;
2867
+ exports.AssetRuneNative = AssetRuneNative;
2868
+ exports.BCHChain = BCHChain;
2869
+ exports.BNBChain = BNBChain;
2870
+ exports.BSCChain = BSCChain;
2871
+ exports.BTCChain = BTCChain;
2745
2872
  exports.CryptoAmount = CryptoAmount;
2873
+ exports.DOGEChain = DOGEChain;
2874
+ exports.ETHChain = ETHChain;
2875
+ exports.GAIAChain = GAIAChain;
2876
+ exports.LTCChain = LTCChain;
2746
2877
  exports.LiquidityPool = LiquidityPool;
2878
+ exports.MAYAChain = MAYAChain;
2747
2879
  exports.Midgard = Midgard;
2880
+ exports.THORChain = THORChain;
2748
2881
  exports.ThorchainCache = ThorchainCache;
2749
2882
  exports.ThorchainQuery = ThorchainQuery;
2750
2883
  exports.Thornode = Thornode;
@@ -2756,3 +2889,4 @@ exports.getLiquidityUnits = getLiquidityUnits;
2756
2889
  exports.getPoolShare = getPoolShare;
2757
2890
  exports.getSingleSwap = getSingleSwap;
2758
2891
  exports.getSlipOnLiquidity = getSlipOnLiquidity;
2892
+ exports.isAssetRuneNative = isAssetRuneNative;