Skip to content

Commit

Permalink
fix(sequence): ZapAddLiquidity - workaround for explorer slowly updat…
Browse files Browse the repository at this point in the history
…ing pool data (wait for actually update); update coin balance order and fix BEE featuring; update deps
  • Loading branch information
shrpne committed May 15, 2023
1 parent fbc9b72 commit 9155b6b
Show file tree
Hide file tree
Showing 5 changed files with 490 additions and 452 deletions.
2 changes: 2 additions & 0 deletions .ncurc.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,7 @@ module.exports = {
// 'beeper',
// 'camelcase-keys',
// 'del',
// broken
'nuxt-i18n-default',
],
};
60 changes: 50 additions & 10 deletions api/explorer.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {cacheAdapterEnhancer, Cache} from 'axios-extensions';
import stripZeros from 'pretty-num/src/strip-zeros.js';
import {convertToPip} from 'minterjs-util';
import coinBlockList from 'minter-coin-block-list';
import {wait} from '@shrpne/utils/src/wait.js';
import {getVerifiedMinterCoinList} from '~/api/hub.js';
import {getCoinIconList as getChainikIconList} from '~/api/chainik.js';
import {BASE_COIN, EXPLORER_API_URL, TX_STATUS} from '~/assets/variables.js';
Expand Down Expand Up @@ -152,14 +153,20 @@ export function getTransaction(hash) {
export async function getBalance(address) {
const response = await explorer.get('addresses/' + address + '?with_sum=true');

// replace empty BIP with BEE
const bipBalance = response.data.data.balances.find((item) => item.coin.symbol === BASE_COIN);
const beeBalance = response.data.data.balances.find((item) => item.coin.symbol === 'BEE');
if (bipBalance && Number(bipBalance.amount) === 0) {
bipBalance.coin = {
symbol: 'BEE',
id: 2361,
type: 'token',
};
if (!beeBalance) {
// replace empty BIP with BEE
bipBalance.coin = {
symbol: 'BEE',
id: 2361,
type: 'token',
};
} else {
// remove empty BIP
response.data.data.balances = response.data.data.balances.filter((item) => item.coin.symbol !== BASE_COIN);
}
}

response.data.data.balances = await prepareBalance(response.data.data.balances);
Expand Down Expand Up @@ -189,6 +196,12 @@ export async function prepareBalance(balanceList) {
balanceList = await markVerified(Promise.resolve(balanceList));

return balanceList.sort((a, b) => {
// BEE goes first
if (a.coin.symbol === 'BEE') {
return -1;
} else if (b.coin.symbol === 'BEE') {
return 1;
}
// base coin goes first
if (a.coin.symbol === BASE_COIN) {
return -1;
Expand All @@ -203,8 +216,10 @@ export async function prepareBalance(balanceList) {
return 1;
}

return +b.bipAmount - +a.bipAmount;

// sort coins by name, instead of reserve
return a.coin.symbol.localeCompare(b.coin.symbol);
// return a.coin.symbol.localeCompare(b.coin.symbol);
})
.map((coinItem) => {
return {
Expand Down Expand Up @@ -417,11 +432,12 @@ const poolCache = new Cache({ttl: 10 * 1000, max: 100});
/**
* @param {string|number} coin0
* @param {string|number} coin1
* @param {boolean} [skipCache]
* @return {Promise<Pool>}
*/
export function getPool(coin0, coin1) {
export function getPool(coin0, coin1, skipCache) {
return explorer.get(`pools/coins/${coin0}/${coin1}`, {
cache: poolCache,
cache: skipCache ? undefined : poolCache,
})
.then((response) => response.data.data);
}
Expand All @@ -437,6 +453,29 @@ export function getPoolByToken(symbol) {
.then((response) => response.data.data);
}

/**
* @param {string|number} coin0
* @param {string|number} coin1
* @param {object} [options]
* @param {number} [options.updatedAtBlock]
* @param {number} [options.tryLimit]
* @return {Promise<Pool>}
*/
export function waitPool(coin0, coin1, {updatedAtBlock, tryLimit = 15} = {}) {
return getPool(coin0, coin1, !!updatedAtBlock)
.then((poolData) => {
if (!updatedAtBlock || poolData.updatedAtBlock >= updatedAtBlock) {
return poolData;
}
if (tryLimit <= 0) {
return poolData;
}
return wait(3000).then(() => {
return waitPool(coin0, coin1, {updatedAtBlock, tryLimit: tryLimit - 1});
});
});
}

/**
* @param {string|number} coin0
* @param {string|number} coin1
Expand Down Expand Up @@ -594,8 +633,9 @@ export function getSwapEstimate(coin0, coin1, {buyAmount, sellAmount}, axiosOpti
* @property {number|string} amount1
* @property {number|string} liquidity
* @property {number|string} liquidityBip
* @property {string} token
* @property {Coin} token
* @property {number|string} tradeVolumeBip1D
* @property {number} updatedAtBlock
*/

/**
Expand Down
41 changes: 34 additions & 7 deletions components/ActionZapPoolAddLiquidity.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import minLength from 'vuelidate/src/validators/minLength.js';
import minValue from 'vuelidate/src/validators/minValue.js';
import {TX_TYPE} from 'minterjs-util/src/tx-types.js';
import {wait} from '@shrpne/utils/src/wait.js';
import {getPool} from '~/api/explorer.js';
import {waitPool} from '~/api/explorer.js';
import {estimateTxCommissionGasCoinOnly} from '~/api/gate.js';
import checkEmpty from '~/assets/v-check-empty.js';
import {pretty, prettyExact} from "~/assets/utils.js";
Expand Down Expand Up @@ -83,6 +83,7 @@ export default {
v$estimation1: {},
estimationFetchState0: null,
estimationFetchState1: null,
/** @type {Pool|null} */
poolData: null,
isSequenceProcessing: false,
};
Expand Down Expand Up @@ -161,6 +162,7 @@ export default {
return this.fee?.resultList?.[2];
},
sequenceParams() {
let poolBlock = this.poolData?.updatedAtBlock;
const finalState = {
coin0Amount: this.coin0Amount,
coin1Amount: this.coin1Amount,
Expand Down Expand Up @@ -202,6 +204,11 @@ export default {
finalize: (tx) => {
const swapReturn = convertFromPip(tx.tags['tx.return']);
finalState[`coin${index}Amount`] = swapReturn;
if (isPoolAffected(tx, this.poolData.token.symbol)) {
poolBlock = Number(tx.height);
}
return tx;
},
};
Expand All @@ -215,14 +222,16 @@ export default {
prepare: [
// @TODO 3rd estimated fee will stay as dust
async () => {
await this.fetchPoolData();
await this.fetchPoolData(poolBlock);
console.log('finalState', {...finalState}, {...this.poolData});
let isCoin1Bigger = getIsCoin1Bigger(finalState, this.poolData);
// use bigger coin as new gasCoin
const gasCoin = isCoin1Bigger ? this.params.coin1 : this.params.coin0;
// @TODO can throw here, new gasCoin may be not eligible to pay fee, need to use old gasCoin
const {commission} = await estimateTxCommissionGasCoinOnly({
...this.sequenceParams[2].txParams,
// use bigger coin as new gasCoin
gasCoin: isCoin1Bigger ? this.params.coin1 : this.params.coin0,
gasCoin,
});
// reduce amount by fee
if (isCoin1Bigger) {
Expand All @@ -231,11 +240,18 @@ export default {
finalState.coin0Amount = new Big(finalState.coin0Amount).minus(commission).toString();
}
// @TODO some validation can be made to prevent such case
if (finalState.coin1Amount < 0 || finalState.coin0Amount < 0) {
throw new Error(`Not enough ${gasCoin} to pay fee`);
}
console.log('finalState', {...finalState}, {...this.poolData});
// update isCoin1Bigger after fee deduction
isCoin1Bigger = getIsCoin1Bigger(finalState, this.poolData);
return {
gasCoin,
// bigger volume go second
data: isCoin1Bigger ? {
coin0: this.params.coin0,
Expand Down Expand Up @@ -290,15 +306,15 @@ export default {
methods: {
pretty,
prettyExact,
fetchPoolData() {
fetchPoolData(updatedAtBlock) {
// no pair entered
if (!this.form.coin0 || !this.form.coin1 || this.form.coin0 === this.form.coin1) {
return;
}
return getPool(this.form.coin0, this.form.coin1)
return waitPool(this.form.coin0, this.form.coin1, {updatedAtBlock})
.then((poolData) => {
this.poolData = poolData;
this.poolData = Object.freeze(poolData);
});
},
clearForm() {
Expand All @@ -309,6 +325,17 @@ export default {
},
},
};
function isPoolAffected(tx, lpTokenSymbol) {
const tagsPoolId = Number(lpTokenSymbol.replace('LP-', ''));
const swapPools = tx.tags['tx.pools'] && JSON.parse(tx.tags['tx.pools']);
const feePool = tx.tags['tx.commission_details'] && JSON.parse(tx.tags['tx.commission_details']);
const pools = [].concat(swapPools, feePool);
const idList = pools.map((pool) => pool?.['pool_id']);
return idList.includes(tagsPoolId);
}
</script>
<template>
Expand Down
Loading

0 comments on commit 9155b6b

Please sign in to comment.