@xchainjs/xchain-thorchain-query 0.1.0-beta → 0.1.0-beta2
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.esm.js +471 -135
- package/lib/index.js +434 -98
- package/lib/thorchain-cache.d.ts +12 -0
- package/lib/thorchain-query.d.ts +31 -2
- package/lib/types.d.ts +67 -7
- package/lib/utils/liquidity.d.ts +24 -17
- package/lib/utils/midgard.d.ts +19 -3
- package/lib/utils/thornode.d.ts +24 -1
- package/package.json +5 -5
package/lib/index.js
CHANGED
|
@@ -5,6 +5,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
5
5
|
var xchainThornode = require('@xchainjs/xchain-thornode');
|
|
6
6
|
var xchainUtil = require('@xchainjs/xchain-util');
|
|
7
7
|
var BigNumber = require('bignumber.js');
|
|
8
|
+
var lib = require('@xchainjs/xchain-util/lib');
|
|
8
9
|
var xchainClient = require('@xchainjs/xchain-client');
|
|
9
10
|
var xchainMidgard = require('@xchainjs/xchain-midgard');
|
|
10
11
|
var axios = require('axios');
|
|
@@ -185,7 +186,107 @@ class CryptoAmount {
|
|
|
185
186
|
TxStage[TxStage["OUTBOUND_QUEUED"] = 3] = "OUTBOUND_QUEUED";
|
|
186
187
|
TxStage[TxStage["OUTBOUND_CHAIN_UNCONFIRMED"] = 4] = "OUTBOUND_CHAIN_UNCONFIRMED";
|
|
187
188
|
TxStage[TxStage["OUTBOUND_CHAIN_CONFIRMED"] = 5] = "OUTBOUND_CHAIN_CONFIRMED";
|
|
188
|
-
})(exports.TxStage || (exports.TxStage = {}));
|
|
189
|
+
})(exports.TxStage || (exports.TxStage = {}));
|
|
190
|
+
// export type LiquidityProvider = {
|
|
191
|
+
// asset: string
|
|
192
|
+
// rune_address: string
|
|
193
|
+
// asset_address: string
|
|
194
|
+
// last_add_height: number
|
|
195
|
+
// last_withdraw_height: number
|
|
196
|
+
// units: number
|
|
197
|
+
// pending_rune: number
|
|
198
|
+
// pending_asset: number
|
|
199
|
+
// pending_tx_Id: string
|
|
200
|
+
// rune_deposit_value: number
|
|
201
|
+
// asset_deposit_value: number
|
|
202
|
+
// }
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* https://dev.thorchain.org/thorchain-dev/interface-guide/math#lp-units-add
|
|
206
|
+
* @param liquidity - asset amount added
|
|
207
|
+
* @param pool - pool depths
|
|
208
|
+
* @returns liquidity units - ownership of pool
|
|
209
|
+
*/
|
|
210
|
+
const getLiquidityUnits = (liquidity, pool) => {
|
|
211
|
+
const P = new BigNumber.BigNumber(pool.pool.liquidityUnits);
|
|
212
|
+
const r = liquidity.rune.amount();
|
|
213
|
+
const a = liquidity.asset.amount();
|
|
214
|
+
const R = pool.runeBalance.amount();
|
|
215
|
+
const A = pool.assetBalance.amount();
|
|
216
|
+
const part1 = R.times(a);
|
|
217
|
+
const part2 = r.times(A);
|
|
218
|
+
const numerator = P.times(part1.plus(part2));
|
|
219
|
+
const denominator = R.times(A).times(2);
|
|
220
|
+
const result = numerator.div(denominator);
|
|
221
|
+
return result;
|
|
222
|
+
};
|
|
223
|
+
/**
|
|
224
|
+
*
|
|
225
|
+
* @param unitData - units for both asset and rune
|
|
226
|
+
* @param pool - pool that the asset is bound to
|
|
227
|
+
* @returns - pool share of both asset and rune in percentage
|
|
228
|
+
*/
|
|
229
|
+
const getPoolShare = (unitData, pool) => {
|
|
230
|
+
// formula: (rune * part) / total; (asset * part) / total
|
|
231
|
+
const units = unitData.liquidityUnits.amount();
|
|
232
|
+
const total = unitData.totalUnits.amount();
|
|
233
|
+
const R = pool.runeBalance.amount();
|
|
234
|
+
const T = pool.assetBalance.amount();
|
|
235
|
+
const asset = T.times(units).div(total);
|
|
236
|
+
const rune = R.times(units).div(total);
|
|
237
|
+
const poolShareDetail = {
|
|
238
|
+
assetShare: new CryptoAmount(lib.baseAmount(asset), pool.asset),
|
|
239
|
+
runeShare: new CryptoAmount(lib.baseAmount(rune), lib.AssetRuneNative),
|
|
240
|
+
};
|
|
241
|
+
return poolShareDetail;
|
|
242
|
+
};
|
|
243
|
+
/**
|
|
244
|
+
*
|
|
245
|
+
* @param poolShare - the share of asset and rune added to the pool
|
|
246
|
+
* @param pool - Pool that the asset is attached to
|
|
247
|
+
* @returns - returns bignumber representing a slip percentage
|
|
248
|
+
*/
|
|
249
|
+
const getSlipOnLiquidity = (stake, pool) => {
|
|
250
|
+
// formula: (t * R - T * r)/ (T*r + R*T)
|
|
251
|
+
const r = stake.rune.amount();
|
|
252
|
+
const t = stake.asset.amount();
|
|
253
|
+
const R = pool.runeBalance.amount();
|
|
254
|
+
const T = pool.assetBalance.amount();
|
|
255
|
+
const numerator = t.times(R).minus(T.times(r));
|
|
256
|
+
const denominator = T.times(r).plus(R.times(T));
|
|
257
|
+
const result = numerator.div(denominator).abs();
|
|
258
|
+
return result;
|
|
259
|
+
};
|
|
260
|
+
/**
|
|
261
|
+
* https://docs.thorchain.org/thorchain-finance/continuous-liquidity-pools#impermanent-loss-protection
|
|
262
|
+
* @param poolShare - the share of asset and rune added to the pool
|
|
263
|
+
* @param pool - Pool that the asset is attached to
|
|
264
|
+
* @param block - blockl object with current, last added and the constant blocksforlossProtection
|
|
265
|
+
* @returns
|
|
266
|
+
*/
|
|
267
|
+
// Blocks for full protection 1440000 // 100 days
|
|
268
|
+
const getLiquidityProtectionData = (depositValue, poolShare, block) => {
|
|
269
|
+
//Coverage formula coverage=((A0∗P1)+R0)−((A1∗P1)+R1)=>((A0∗R1/A1)+R0)−(R1+R1)
|
|
270
|
+
//formula: protectionProgress (currentHeight-heightLastAdded)/blocksforfullprotection
|
|
271
|
+
const R0 = depositValue.rune.amount(); // rune deposit value
|
|
272
|
+
const A0 = depositValue.asset.amount(); // asset deposit value
|
|
273
|
+
const R1 = poolShare.runeShare.baseAmount.amount(); // rune amount to redeem
|
|
274
|
+
const A1 = poolShare.assetShare.baseAmount.amount(); // asset amount to redeem
|
|
275
|
+
const P1 = R1.div(A1); // Pool ratio at withdrawal
|
|
276
|
+
const part1 = A0.times(P1).plus(R0).minus(A1.times(P1).plus(R1)); // start position minus end position
|
|
277
|
+
const part2 = A0.times(R1.div(A1)).plus(R0).minus(R1.plus(R1)); // different way to check position
|
|
278
|
+
const coverage = part1 >= part2 ? part1 : part2; // Coverage represents how much ILP a LP is entitled to
|
|
279
|
+
const currentHeight = block.current;
|
|
280
|
+
const heightLastAdded = block.lastAdded || 0; //default to zero if undefined
|
|
281
|
+
const blocksforfullprotection = block.fullProtection;
|
|
282
|
+
const protectionProgress = (currentHeight - heightLastAdded) / blocksforfullprotection; // percentage of entitlement
|
|
283
|
+
const result = coverage.times(protectionProgress); // impermanent loss protection result
|
|
284
|
+
const ILProtection = {
|
|
285
|
+
ILProtection: new CryptoAmount(lib.baseAmount(result), lib.AssetRuneNative),
|
|
286
|
+
totalDays: (protectionProgress * 100).toFixed(2),
|
|
287
|
+
};
|
|
288
|
+
return ILProtection;
|
|
289
|
+
};
|
|
189
290
|
|
|
190
291
|
const getBaseAmountWithDiffDecimals = (inputAmount, outDecimals) => {
|
|
191
292
|
const inDecimals = inputAmount.baseAmount.decimal;
|
|
@@ -788,7 +889,9 @@ class ThorchainQuery {
|
|
|
788
889
|
const networkValues = yield this.thorchainCache.getNetworkValues();
|
|
789
890
|
const minTxOutVolumeThreshold = new CryptoAmount(xchainUtil.baseAmount(networkValues['MINTXOUTVOLUMETHRESHOLD']), xchainUtil.AssetRuneNative);
|
|
790
891
|
const maxTxOutOffset = networkValues['MAXTXOUTOFFSET'];
|
|
791
|
-
let txOutDelayRate = new CryptoAmount(xchainUtil.baseAmount(networkValues['TXOUTDELAYRATE']), xchainUtil.AssetRuneNative)
|
|
892
|
+
let txOutDelayRate = new CryptoAmount(xchainUtil.baseAmount(networkValues['TXOUTDELAYRATE']), xchainUtil.AssetRuneNative).assetAmount
|
|
893
|
+
.amount()
|
|
894
|
+
.toNumber();
|
|
792
895
|
const getScheduledOutboundValue = yield this.thorchainCache.midgard.getScheduledOutboundValue();
|
|
793
896
|
const thorChainblocktime = this.chainAttributes[xchainUtil.Chain.THORChain].avgBlockTimeInSecs; // blocks required to confirm tx
|
|
794
897
|
// If asset is equal to Rune set runeValue as outbound amount else set it to the asset's value in rune
|
|
@@ -806,11 +909,9 @@ class ThorchainQuery {
|
|
|
806
909
|
// calculate the if outboundAmountTotal is over the volume threshold
|
|
807
910
|
const volumeThreshold = outboundAmountTotal.div(minTxOutVolumeThreshold);
|
|
808
911
|
// check delay rate
|
|
809
|
-
txOutDelayRate = txOutDelayRate
|
|
810
|
-
? new CryptoAmount(xchainUtil.baseAmount(1), xchainUtil.AssetRuneNative)
|
|
811
|
-
: txOutDelayRate;
|
|
912
|
+
txOutDelayRate = txOutDelayRate - volumeThreshold.assetAmount.amount().toNumber() <= 1 ? 1 : txOutDelayRate;
|
|
812
913
|
// calculate the minimum number of blocks in the future the txn has to be
|
|
813
|
-
let minBlocks = runeValue.
|
|
914
|
+
let minBlocks = runeValue.assetAmount.amount().toNumber() / txOutDelayRate;
|
|
814
915
|
minBlocks = minBlocks > maxTxOutOffset ? maxTxOutOffset : minBlocks;
|
|
815
916
|
return minBlocks * thorChainblocktime;
|
|
816
917
|
});
|
|
@@ -845,10 +946,12 @@ class ThorchainQuery {
|
|
|
845
946
|
if (!pool)
|
|
846
947
|
throw Error(`No pool found from memo`);
|
|
847
948
|
const getAsset = xchainUtil.assetFromString(pool[1].toUpperCase());
|
|
949
|
+
if (!getAsset)
|
|
950
|
+
throw Error(`Invalid pool asset`);
|
|
848
951
|
// Retrieve thorchain blockHeight for the tx
|
|
849
952
|
if (!((_b = txData.observed_tx.tx) === null || _b === void 0 ? void 0 : _b.id))
|
|
850
953
|
throw Error('No action observed');
|
|
851
|
-
const recordedAction = yield this.thorchainCache.midgard.getActions(txData.observed_tx.tx.id);
|
|
954
|
+
const recordedAction = yield this.thorchainCache.midgard.getActions('', txData.observed_tx.tx.id);
|
|
852
955
|
const recordedTCBlock = recordedAction.find((block) => {
|
|
853
956
|
return block;
|
|
854
957
|
});
|
|
@@ -1022,6 +1125,228 @@ class ThorchainQuery {
|
|
|
1022
1125
|
return txStatus;
|
|
1023
1126
|
});
|
|
1024
1127
|
}
|
|
1128
|
+
/**
|
|
1129
|
+
* Estimates a liquidity position for given crypto amount value, both asymmetrical and symetrical
|
|
1130
|
+
* @param params - parameters needed for a estimated liquidity position
|
|
1131
|
+
* @returns - type object EstimateLP
|
|
1132
|
+
*/
|
|
1133
|
+
estimateAddLP(params) {
|
|
1134
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1135
|
+
const errors = [];
|
|
1136
|
+
if (params.asset.asset.synth || params.rune.asset.synth)
|
|
1137
|
+
errors.push('you cannot add liquidity with a synth');
|
|
1138
|
+
if (!xchainUtil.isAssetRuneNative(params.rune.asset))
|
|
1139
|
+
errors.push('params.rune must be THOR.RUNE');
|
|
1140
|
+
const assetPool = yield this.thorchainCache.getPoolForAsset(params.asset.asset);
|
|
1141
|
+
const lpUnits = getLiquidityUnits({ asset: params.asset.baseAmount, rune: params.rune.baseAmount }, assetPool);
|
|
1142
|
+
const inboundDetails = yield this.thorchainCache.midgard.getInboundDetails();
|
|
1143
|
+
const unitData = {
|
|
1144
|
+
liquidityUnits: xchainUtil.baseAmount(lpUnits),
|
|
1145
|
+
totalUnits: xchainUtil.baseAmount(assetPool.pool.liquidityUnits),
|
|
1146
|
+
};
|
|
1147
|
+
const poolShare = getPoolShare(unitData, assetPool);
|
|
1148
|
+
const assetWaitTimeSeconds = yield this.confCounting(params.asset);
|
|
1149
|
+
const runeWaitTimeSeconds = yield this.confCounting(params.rune);
|
|
1150
|
+
const waitTimeSeconds = assetWaitTimeSeconds > runeWaitTimeSeconds ? assetWaitTimeSeconds : runeWaitTimeSeconds;
|
|
1151
|
+
let assetInboundFee = new CryptoAmount(xchainUtil.baseAmount(0), params.asset.asset);
|
|
1152
|
+
let runeInboundFee = new CryptoAmount(xchainUtil.baseAmount(0), xchainUtil.AssetRuneNative);
|
|
1153
|
+
if (!params.asset.assetAmount.eq(0)) {
|
|
1154
|
+
assetInboundFee = calcNetworkFee(params.asset.asset, inboundDetails[params.asset.asset.chain].gas_rate);
|
|
1155
|
+
if (assetInboundFee.assetAmount.amount().times(3).gt(params.asset.assetAmount.amount()))
|
|
1156
|
+
errors.push(`Asset amount is less than fees`);
|
|
1157
|
+
}
|
|
1158
|
+
if (!params.rune.assetAmount.eq(0)) {
|
|
1159
|
+
runeInboundFee = calcNetworkFee(params.rune.asset, inboundDetails[params.rune.asset.chain].gas_rate);
|
|
1160
|
+
if (runeInboundFee.assetAmount.amount().times(3).gt(params.rune.assetAmount.amount()))
|
|
1161
|
+
errors.push(`Rune amount is less than fees`);
|
|
1162
|
+
}
|
|
1163
|
+
const totalFees = (yield this.convert(assetInboundFee, xchainUtil.AssetRuneNative)).plus(runeInboundFee);
|
|
1164
|
+
const slip = getSlipOnLiquidity({ asset: params.asset.baseAmount, rune: params.rune.baseAmount }, assetPool);
|
|
1165
|
+
const estimateLP = {
|
|
1166
|
+
slipPercent: slip.times(100),
|
|
1167
|
+
poolShare: poolShare,
|
|
1168
|
+
lpUnits: xchainUtil.baseAmount(lpUnits),
|
|
1169
|
+
runeToAssetRatio: assetPool.runeToAssetRatio,
|
|
1170
|
+
transactionFee: {
|
|
1171
|
+
assetFee: assetInboundFee,
|
|
1172
|
+
runeFee: runeInboundFee,
|
|
1173
|
+
totalFees: totalFees,
|
|
1174
|
+
},
|
|
1175
|
+
estimatedWaitSeconds: waitTimeSeconds,
|
|
1176
|
+
errors,
|
|
1177
|
+
canAdd: errors.length > 0 ? false : true,
|
|
1178
|
+
};
|
|
1179
|
+
return estimateLP;
|
|
1180
|
+
});
|
|
1181
|
+
}
|
|
1182
|
+
/**
|
|
1183
|
+
* @param - Asset for lp
|
|
1184
|
+
* @param address - address used for Lp
|
|
1185
|
+
* @returns - Type Object liquidityPosition
|
|
1186
|
+
*/
|
|
1187
|
+
checkLiquidityPosition(asset, assetOrRuneAddress) {
|
|
1188
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1189
|
+
const poolAsset = yield this.thorchainCache.getPoolForAsset(asset);
|
|
1190
|
+
if (!poolAsset)
|
|
1191
|
+
throw Error(`Could not find pool for ${asset}`);
|
|
1192
|
+
const liquidityProvider = yield this.thorchainCache.thornode.getLiquidityProvider(poolAsset.assetString, assetOrRuneAddress);
|
|
1193
|
+
if (!liquidityProvider)
|
|
1194
|
+
throw Error(`Could not find LP for ${assetOrRuneAddress}`);
|
|
1195
|
+
// Current block number for that chain
|
|
1196
|
+
const blockData = (yield this.thorchainCache.thornode.getLastBlock()).find((item) => item.chain === asset.chain);
|
|
1197
|
+
if (!blockData)
|
|
1198
|
+
throw Error(`Could not get block data`);
|
|
1199
|
+
// Pools total units & Lp's total units
|
|
1200
|
+
const unitData = {
|
|
1201
|
+
totalUnits: xchainUtil.baseAmount(poolAsset.pool.liquidityUnits),
|
|
1202
|
+
liquidityUnits: xchainUtil.baseAmount(liquidityProvider.units),
|
|
1203
|
+
};
|
|
1204
|
+
//console.log(`unit data`, unitData.totalUnits.amount().toNumber(), unitData.liquidityUnits.amount().toNumber())
|
|
1205
|
+
const networkValues = yield this.thorchainCache.midgard.getNetworkValues();
|
|
1206
|
+
const block = {
|
|
1207
|
+
current: blockData.thorchain,
|
|
1208
|
+
lastAdded: liquidityProvider.last_add_height,
|
|
1209
|
+
fullProtection: networkValues['FULLIMPLOSSPROTECTIONBLOCKS'],
|
|
1210
|
+
};
|
|
1211
|
+
//
|
|
1212
|
+
const currentLP = {
|
|
1213
|
+
asset: xchainUtil.baseAmount(liquidityProvider.asset_deposit_value),
|
|
1214
|
+
rune: xchainUtil.baseAmount(liquidityProvider.rune_deposit_value),
|
|
1215
|
+
};
|
|
1216
|
+
const poolShare = getPoolShare(unitData, poolAsset);
|
|
1217
|
+
// console.log(poolShare.assetShare.toNumber(), poolShare.runeShare.toNumber())
|
|
1218
|
+
// console.log(poolAsset.pool.liquidityUnits)
|
|
1219
|
+
const impermanentLossProtection = getLiquidityProtectionData(currentLP, poolShare, block);
|
|
1220
|
+
const lpPosition = {
|
|
1221
|
+
poolShare,
|
|
1222
|
+
position: liquidityProvider,
|
|
1223
|
+
impermanentLossProtection: impermanentLossProtection,
|
|
1224
|
+
};
|
|
1225
|
+
return lpPosition;
|
|
1226
|
+
});
|
|
1227
|
+
}
|
|
1228
|
+
/**
|
|
1229
|
+
* Do not send assetNativeRune, There is no pool for it.
|
|
1230
|
+
* @param asset - asset required to find the pool
|
|
1231
|
+
* @returns - object type ratios
|
|
1232
|
+
*/
|
|
1233
|
+
getPoolRatios(asset) {
|
|
1234
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1235
|
+
const assetPool = yield this.thorchainCache.getPoolForAsset(asset);
|
|
1236
|
+
const poolRatio = {
|
|
1237
|
+
assetToRune: assetPool.assetToRuneRatio,
|
|
1238
|
+
runeToAsset: assetPool.runeToAssetRatio,
|
|
1239
|
+
};
|
|
1240
|
+
return poolRatio;
|
|
1241
|
+
});
|
|
1242
|
+
}
|
|
1243
|
+
/**
|
|
1244
|
+
*
|
|
1245
|
+
* @param params
|
|
1246
|
+
*/
|
|
1247
|
+
estimateWithdrawLP(params) {
|
|
1248
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1249
|
+
// Caution Dust Limits: BTC,BCH,LTC chains 10k sats; DOGE 1m Sats; ETH 0 wei; THOR 0 RUNE.
|
|
1250
|
+
if (!params.assetAddress)
|
|
1251
|
+
throw Error(`can't estimate lp without an asset address`);
|
|
1252
|
+
const memberDetail = yield this.checkLiquidityPosition(params.asset, params.assetAddress);
|
|
1253
|
+
const dustValues = yield this.getDustValues(params.asset); // returns asset and rune dust values
|
|
1254
|
+
const assetPool = yield this.thorchainCache.getPoolForAsset(params.asset);
|
|
1255
|
+
// get pool share from unit data
|
|
1256
|
+
const poolShare = getPoolShare({
|
|
1257
|
+
liquidityUnits: xchainUtil.baseAmount(memberDetail.position.units),
|
|
1258
|
+
totalUnits: xchainUtil.baseAmount(assetPool.pool.liquidityUnits),
|
|
1259
|
+
}, assetPool);
|
|
1260
|
+
// calculate total fees
|
|
1261
|
+
const totalFees = (yield this.convert(dustValues.asset, xchainUtil.AssetRuneNative)).plus(dustValues.rune);
|
|
1262
|
+
// get slip on liquidity removal
|
|
1263
|
+
const slip = getSlipOnLiquidity({
|
|
1264
|
+
asset: poolShare.assetShare.baseAmount,
|
|
1265
|
+
rune: poolShare.runeShare.baseAmount,
|
|
1266
|
+
}, assetPool);
|
|
1267
|
+
// TODO make sure we compare wait times for withdrawing both rune and asset OR just rune OR just asset
|
|
1268
|
+
const waitTimeSecondsForAsset = yield this.confCounting(poolShare.assetShare.div(params.percentage / 100));
|
|
1269
|
+
const waitTimeSecondsForRune = yield this.confCounting(poolShare.runeShare.div(params.percentage / 100));
|
|
1270
|
+
let waitTimeSeconds = 0;
|
|
1271
|
+
if (params.assetAddress && params.runeAddress) {
|
|
1272
|
+
waitTimeSeconds = waitTimeSecondsForAsset + waitTimeSecondsForRune;
|
|
1273
|
+
}
|
|
1274
|
+
else if (params.assetAddress) {
|
|
1275
|
+
waitTimeSeconds = waitTimeSecondsForAsset;
|
|
1276
|
+
}
|
|
1277
|
+
else {
|
|
1278
|
+
waitTimeSeconds = waitTimeSecondsForRune;
|
|
1279
|
+
}
|
|
1280
|
+
const estimateLP = {
|
|
1281
|
+
slipPercent: slip.times(100),
|
|
1282
|
+
transactionFee: {
|
|
1283
|
+
assetFee: dustValues.asset,
|
|
1284
|
+
runeFee: dustValues.rune,
|
|
1285
|
+
totalFees: totalFees,
|
|
1286
|
+
},
|
|
1287
|
+
assetAmount: poolShare.assetShare,
|
|
1288
|
+
runeAmount: poolShare.runeShare,
|
|
1289
|
+
estimatedWaitSeconds: waitTimeSeconds,
|
|
1290
|
+
impermanentLossProtection: memberDetail.impermanentLossProtection,
|
|
1291
|
+
};
|
|
1292
|
+
return estimateLP;
|
|
1293
|
+
});
|
|
1294
|
+
}
|
|
1295
|
+
/**
|
|
1296
|
+
* // can this become a quried constant? added to inbound_addresses or something
|
|
1297
|
+
* @param asset - asset needed to retrieve dust values
|
|
1298
|
+
* @returns - object type dust values
|
|
1299
|
+
*/
|
|
1300
|
+
getDustValues(asset) {
|
|
1301
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1302
|
+
let dustValues;
|
|
1303
|
+
switch (asset.chain) {
|
|
1304
|
+
case 'BNB':
|
|
1305
|
+
dustValues = {
|
|
1306
|
+
asset: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0.000001)), xchainUtil.AssetBNB),
|
|
1307
|
+
rune: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), xchainUtil.AssetRuneNative),
|
|
1308
|
+
};
|
|
1309
|
+
return dustValues;
|
|
1310
|
+
case 'BTC' :
|
|
1311
|
+
// 10k sats
|
|
1312
|
+
dustValues = {
|
|
1313
|
+
asset: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0.0001)), asset),
|
|
1314
|
+
rune: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), xchainUtil.AssetRuneNative),
|
|
1315
|
+
};
|
|
1316
|
+
return dustValues;
|
|
1317
|
+
case 'ETH':
|
|
1318
|
+
// 0 wei
|
|
1319
|
+
dustValues = {
|
|
1320
|
+
asset: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), asset),
|
|
1321
|
+
rune: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), xchainUtil.AssetRuneNative),
|
|
1322
|
+
};
|
|
1323
|
+
return dustValues;
|
|
1324
|
+
case 'THOR':
|
|
1325
|
+
// 0 Rune
|
|
1326
|
+
dustValues = {
|
|
1327
|
+
asset: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), asset),
|
|
1328
|
+
rune: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), xchainUtil.AssetRuneNative),
|
|
1329
|
+
};
|
|
1330
|
+
return dustValues;
|
|
1331
|
+
case 'GAIA':
|
|
1332
|
+
// 0 GAIA
|
|
1333
|
+
dustValues = {
|
|
1334
|
+
asset: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), asset),
|
|
1335
|
+
rune: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), xchainUtil.AssetRuneNative),
|
|
1336
|
+
};
|
|
1337
|
+
return dustValues;
|
|
1338
|
+
case 'DOGE':
|
|
1339
|
+
// 1 million sats
|
|
1340
|
+
dustValues = {
|
|
1341
|
+
asset: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0.01)), asset),
|
|
1342
|
+
rune: new CryptoAmount(xchainUtil.assetToBase(xchainUtil.assetAmount(0)), xchainUtil.AssetRuneNative),
|
|
1343
|
+
};
|
|
1344
|
+
return dustValues;
|
|
1345
|
+
default:
|
|
1346
|
+
throw Error('Unknown chain');
|
|
1347
|
+
}
|
|
1348
|
+
});
|
|
1349
|
+
}
|
|
1025
1350
|
}
|
|
1026
1351
|
|
|
1027
1352
|
/**
|
|
@@ -1051,12 +1376,15 @@ const TEN_MINUTES = 10 * 60 * 1000;
|
|
|
1051
1376
|
const DEFAULT_THORCHAIN_DECIMALS = 8;
|
|
1052
1377
|
const USD_ASSETS = {
|
|
1053
1378
|
mainnet: [
|
|
1054
|
-
xchainUtil.
|
|
1055
|
-
xchainUtil.
|
|
1056
|
-
xchainUtil.
|
|
1379
|
+
xchainUtil.assetFromStringEx('BNB.BUSD-BD1'),
|
|
1380
|
+
xchainUtil.assetFromStringEx('ETH.USDC-0XA0B86991C6218B36C1D19D4A2E9EB0CE3606EB48'),
|
|
1381
|
+
xchainUtil.assetFromStringEx('ETH.USDT-0XDAC17F958D2EE523A2206206994597C13D831EC7'),
|
|
1382
|
+
],
|
|
1383
|
+
stagenet: [xchainUtil.assetFromStringEx('ETH.USDT-0XDAC17F958D2EE523A2206206994597C13D831EC7')],
|
|
1384
|
+
testnet: [
|
|
1385
|
+
xchainUtil.assetFromStringEx('BNB.BUSD-74E'),
|
|
1386
|
+
xchainUtil.assetFromStringEx('ETH.USDT-0XA3910454BF2CB59B8B3A401589A3BACC5CA42306'),
|
|
1057
1387
|
],
|
|
1058
|
-
stagenet: [xchainUtil.assetFromString('ETH.USDT-0XDAC17F958D2EE523A2206206994597C13D831EC7')],
|
|
1059
|
-
testnet: [xchainUtil.assetFromString('BNB.BUSD-74E'), xchainUtil.assetFromString('ETH.USDT-0XA3910454BF2CB59B8B3A401589A3BACC5CA42306')],
|
|
1060
1388
|
};
|
|
1061
1389
|
/**
|
|
1062
1390
|
* This class manages retrieving information from up to date Thorchain
|
|
@@ -1315,6 +1643,10 @@ class ThorchainCache {
|
|
|
1315
1643
|
return inboundAsgard === null || inboundAsgard === void 0 ? void 0 : inboundAsgard.router;
|
|
1316
1644
|
});
|
|
1317
1645
|
}
|
|
1646
|
+
/**
|
|
1647
|
+
*
|
|
1648
|
+
* @returns - inbound adresses item
|
|
1649
|
+
*/
|
|
1318
1650
|
getInboundAddressesItems() {
|
|
1319
1651
|
var _a;
|
|
1320
1652
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -1335,6 +1667,10 @@ class ThorchainCache {
|
|
|
1335
1667
|
}
|
|
1336
1668
|
});
|
|
1337
1669
|
}
|
|
1670
|
+
/**
|
|
1671
|
+
*
|
|
1672
|
+
* @returns - inbound details
|
|
1673
|
+
*/
|
|
1338
1674
|
getInboundDetails() {
|
|
1339
1675
|
var _a;
|
|
1340
1676
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -1355,6 +1691,10 @@ class ThorchainCache {
|
|
|
1355
1691
|
}
|
|
1356
1692
|
});
|
|
1357
1693
|
}
|
|
1694
|
+
/**
|
|
1695
|
+
*
|
|
1696
|
+
* @returns - network values
|
|
1697
|
+
*/
|
|
1358
1698
|
getNetworkValues() {
|
|
1359
1699
|
var _a;
|
|
1360
1700
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -1394,95 +1734,13 @@ class ThorchainCache {
|
|
|
1394
1734
|
}
|
|
1395
1735
|
}
|
|
1396
1736
|
|
|
1397
|
-
/**
|
|
1398
|
-
*
|
|
1399
|
-
* @param liquidity - asset amount added
|
|
1400
|
-
* @param pool - pool depths
|
|
1401
|
-
* @returns liquidity units
|
|
1402
|
-
*/
|
|
1403
|
-
const getLiquidityUnits = (liquidity, pool) => {
|
|
1404
|
-
// formula: ((R + T) (r T + R t))/(4 R T)
|
|
1405
|
-
// part1 * (part2 + part3) / denominator
|
|
1406
|
-
const r = liquidity.rune;
|
|
1407
|
-
const t = liquidity.asset;
|
|
1408
|
-
const R = pool.runeBalance.amount().plus(r); // Must add r first
|
|
1409
|
-
const T = pool.assetBalance.amount().plus(t); // Must add t first
|
|
1410
|
-
const part1 = R.plus(T);
|
|
1411
|
-
const part2 = r.times(T);
|
|
1412
|
-
const part3 = R.times(t);
|
|
1413
|
-
const numerator = part1.times(part2.plus(part3));
|
|
1414
|
-
const denominator = R.times(T).times(4);
|
|
1415
|
-
const result = numerator.div(denominator);
|
|
1416
|
-
return result;
|
|
1417
|
-
};
|
|
1418
|
-
/**
|
|
1419
|
-
*
|
|
1420
|
-
* @param unitData
|
|
1421
|
-
* @param pool
|
|
1422
|
-
* @returns
|
|
1423
|
-
*/
|
|
1424
|
-
const getPoolShare = (unitData, pool) => {
|
|
1425
|
-
// formula: (rune * part) / total; (asset * part) / total
|
|
1426
|
-
const units = unitData.liquidityUnits;
|
|
1427
|
-
const total = unitData.totalUnits;
|
|
1428
|
-
const R = pool.runeBalance.amount();
|
|
1429
|
-
const T = pool.assetBalance.amount();
|
|
1430
|
-
const asset = T.times(units).div(total);
|
|
1431
|
-
const rune = R.times(units).div(total);
|
|
1432
|
-
const liquidityData = {
|
|
1433
|
-
asset: asset,
|
|
1434
|
-
rune: rune,
|
|
1435
|
-
};
|
|
1436
|
-
return liquidityData;
|
|
1437
|
-
};
|
|
1438
|
-
/**
|
|
1439
|
-
*
|
|
1440
|
-
* @param liquidity
|
|
1441
|
-
* @param pool
|
|
1442
|
-
* @returns
|
|
1443
|
-
*/
|
|
1444
|
-
const getSlipOnLiquidity = (liquidity, pool) => {
|
|
1445
|
-
// formula: (t * R - T * r)/ (T*r + R*T)
|
|
1446
|
-
const r = liquidity.rune;
|
|
1447
|
-
const t = liquidity.asset;
|
|
1448
|
-
const R = pool.runeBalance.amount();
|
|
1449
|
-
const T = pool.assetBalance.amount();
|
|
1450
|
-
const numerator = t.times(R).minus(T.times(r));
|
|
1451
|
-
const denominator = T.times(r).plus(R.times(T));
|
|
1452
|
-
const result = numerator.div(denominator).abs();
|
|
1453
|
-
return result;
|
|
1454
|
-
};
|
|
1455
|
-
/**
|
|
1456
|
-
*
|
|
1457
|
-
* @param liquidity
|
|
1458
|
-
* @param pool
|
|
1459
|
-
* @param block
|
|
1460
|
-
* @returns
|
|
1461
|
-
*/
|
|
1462
|
-
// Blocks for full protection 144000 // 100 days
|
|
1463
|
-
const getLiquidityProtectionData = (liquidity, pool, block) => {
|
|
1464
|
-
//formula: protectionProgress (currentHeight-heightLastAdded)/blocksforfullprotection
|
|
1465
|
-
const R0 = liquidity.rune; // symetrical value of rune deposit
|
|
1466
|
-
const A0 = liquidity.asset; // symetrical value of asset deposit
|
|
1467
|
-
const R1 = pool.runeBalance.amount(); // rune to redeem
|
|
1468
|
-
const A1 = pool.assetBalance.amount(); // asset to redeem
|
|
1469
|
-
const P1 = R1.div(A1); // Pool ratio at withdrawal
|
|
1470
|
-
const coverage = A0.times(P1).plus(R0).minus(A1.times(P1).plus(R1));
|
|
1471
|
-
const currentHeight = block.current;
|
|
1472
|
-
const heightLastAdded = block.lastAdded;
|
|
1473
|
-
const blocksforfullprotection = block.fullProtection;
|
|
1474
|
-
const protectionProgress = (currentHeight - heightLastAdded) / blocksforfullprotection;
|
|
1475
|
-
const result = protectionProgress * coverage.toNumber(); // impermanent loss protection result
|
|
1476
|
-
return result;
|
|
1477
|
-
};
|
|
1478
|
-
|
|
1479
1737
|
const defaultMidgardConfig = {
|
|
1480
1738
|
mainnet: {
|
|
1481
1739
|
apiRetries: 3,
|
|
1482
1740
|
midgardBaseUrls: [
|
|
1741
|
+
'https://midgard.ninerealms.com',
|
|
1483
1742
|
'https://midgard.thorchain.info',
|
|
1484
1743
|
'https://midgard.thorswap.net',
|
|
1485
|
-
'https://midgard.ninerealms.com',
|
|
1486
1744
|
],
|
|
1487
1745
|
},
|
|
1488
1746
|
stagenet: {
|
|
@@ -1579,6 +1837,10 @@ class Midgard {
|
|
|
1579
1837
|
return inboundDetails;
|
|
1580
1838
|
});
|
|
1581
1839
|
}
|
|
1840
|
+
/**
|
|
1841
|
+
*
|
|
1842
|
+
* @returns - constants
|
|
1843
|
+
*/
|
|
1582
1844
|
getConstantsDetails() {
|
|
1583
1845
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1584
1846
|
const path = '/v2/thorchain/constants';
|
|
@@ -1656,15 +1918,15 @@ class Midgard {
|
|
|
1656
1918
|
});
|
|
1657
1919
|
}
|
|
1658
1920
|
/**
|
|
1659
|
-
* Gets actions
|
|
1921
|
+
* Gets actions object for any of the parameters
|
|
1660
1922
|
* @param txHash transaction id
|
|
1661
1923
|
* @returns Type Action array of objects
|
|
1662
1924
|
*/
|
|
1663
|
-
getActions(
|
|
1925
|
+
getActions(address, txid, asset, type, affiliate, limit, offset) {
|
|
1664
1926
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1665
1927
|
for (const api of this.midgardApis) {
|
|
1666
1928
|
try {
|
|
1667
|
-
const actions = (yield api.getActions(
|
|
1929
|
+
const actions = (yield api.getActions(address, txid, asset, type, affiliate, limit, offset)).data.actions;
|
|
1668
1930
|
return actions;
|
|
1669
1931
|
}
|
|
1670
1932
|
catch (e) {
|
|
@@ -1674,6 +1936,44 @@ class Midgard {
|
|
|
1674
1936
|
throw Error(`Midgard not responding`);
|
|
1675
1937
|
});
|
|
1676
1938
|
}
|
|
1939
|
+
/**
|
|
1940
|
+
* Function to return member details based on valid liquidity position
|
|
1941
|
+
* @param address - needed to query for Lp details
|
|
1942
|
+
* @returns - object type of Member Detail
|
|
1943
|
+
*/
|
|
1944
|
+
getMember(address) {
|
|
1945
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1946
|
+
for (const api of this.midgardApis) {
|
|
1947
|
+
try {
|
|
1948
|
+
const memberDetail = (yield api.getMemberDetail(address)).data;
|
|
1949
|
+
return memberDetail;
|
|
1950
|
+
}
|
|
1951
|
+
catch (e) {
|
|
1952
|
+
console.error(e);
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
throw Error(`Midgard not responding`);
|
|
1956
|
+
});
|
|
1957
|
+
}
|
|
1958
|
+
/**
|
|
1959
|
+
* Function to return pool statistics for a particular asset
|
|
1960
|
+
* @param asset - asset string to query its pool stats
|
|
1961
|
+
* @returns - type object poolstatsDetail
|
|
1962
|
+
*/
|
|
1963
|
+
getPoolStats(asset) {
|
|
1964
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1965
|
+
for (const api of this.midgardApis) {
|
|
1966
|
+
try {
|
|
1967
|
+
const poolDetail = (yield api.getPoolStats(asset)).data;
|
|
1968
|
+
return poolDetail;
|
|
1969
|
+
}
|
|
1970
|
+
catch (e) {
|
|
1971
|
+
console.error(e);
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
throw Error(`Midgard not responding`);
|
|
1975
|
+
});
|
|
1976
|
+
}
|
|
1677
1977
|
}
|
|
1678
1978
|
|
|
1679
1979
|
const defaultThornodeConfig = {
|
|
@@ -1703,6 +2003,7 @@ class Thornode {
|
|
|
1703
2003
|
this.queueApi = this.config.thornodeBaseUrls.map((url) => new xchainThornode.QueueApi(new xchainThornode.Configuration({ basePath: url })));
|
|
1704
2004
|
this.networkApi = this.config.thornodeBaseUrls.map((url) => new xchainThornode.NetworkApi(new xchainThornode.Configuration({ basePath: url })));
|
|
1705
2005
|
this.poolsApi = this.config.thornodeBaseUrls.map((url) => new xchainThornode.PoolsApi(new xchainThornode.Configuration({ basePath: url })));
|
|
2006
|
+
this.liquidityProvidersApi = this.config.thornodeBaseUrls.map((url) => new xchainThornode.LiquidityProvidersApi(new xchainThornode.Configuration({ basePath: url })));
|
|
1706
2007
|
}
|
|
1707
2008
|
/**
|
|
1708
2009
|
* Returns the oubound transactions held by THORChain due to outbound delay
|
|
@@ -1726,6 +2027,11 @@ class Thornode {
|
|
|
1726
2027
|
throw Error(`THORNode not responding`);
|
|
1727
2028
|
});
|
|
1728
2029
|
}
|
|
2030
|
+
/**
|
|
2031
|
+
*
|
|
2032
|
+
* @param txHash - transaction hash
|
|
2033
|
+
* @returns - transaction object
|
|
2034
|
+
*/
|
|
1729
2035
|
getTxData(txHash) {
|
|
1730
2036
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1731
2037
|
for (const api of this.transactionsApi) {
|
|
@@ -1744,6 +2050,11 @@ class Thornode {
|
|
|
1744
2050
|
throw new Error(`THORNode not responding`);
|
|
1745
2051
|
});
|
|
1746
2052
|
}
|
|
2053
|
+
/**
|
|
2054
|
+
*
|
|
2055
|
+
* @param height - optional thorchain height only
|
|
2056
|
+
* @returns - last block data || or block data pertaining to that height number
|
|
2057
|
+
*/
|
|
1747
2058
|
getLastBlock(height) {
|
|
1748
2059
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1749
2060
|
for (const api of this.networkApi) {
|
|
@@ -1758,6 +2069,10 @@ class Thornode {
|
|
|
1758
2069
|
throw new Error(`THORNode not responding`);
|
|
1759
2070
|
});
|
|
1760
2071
|
}
|
|
2072
|
+
/**
|
|
2073
|
+
*
|
|
2074
|
+
* @returns - thorchain pool
|
|
2075
|
+
*/
|
|
1761
2076
|
getPools() {
|
|
1762
2077
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1763
2078
|
for (const api of this.poolsApi) {
|
|
@@ -1773,6 +2088,27 @@ class Thornode {
|
|
|
1773
2088
|
throw new Error(`THORNode not responding`);
|
|
1774
2089
|
});
|
|
1775
2090
|
}
|
|
2091
|
+
/**
|
|
2092
|
+
*
|
|
2093
|
+
* @param asset - asset string
|
|
2094
|
+
* @param address - address
|
|
2095
|
+
* @param height - optional block height, defaults to current tip
|
|
2096
|
+
* @returns
|
|
2097
|
+
*/
|
|
2098
|
+
getLiquidityProvider(asset, address, height) {
|
|
2099
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2100
|
+
for (const api of this.liquidityProvidersApi) {
|
|
2101
|
+
try {
|
|
2102
|
+
const lps = (yield api.liquidityProviders(asset, height)).data;
|
|
2103
|
+
return lps.find((lp) => lp.asset_address === address || lp.rune_address === address);
|
|
2104
|
+
}
|
|
2105
|
+
catch (e) {
|
|
2106
|
+
console.error(e);
|
|
2107
|
+
}
|
|
2108
|
+
}
|
|
2109
|
+
throw new Error(`THORNode not responding`);
|
|
2110
|
+
});
|
|
2111
|
+
}
|
|
1776
2112
|
}
|
|
1777
2113
|
|
|
1778
2114
|
exports.CryptoAmount = CryptoAmount;
|