diff --git a/cypress.config.js b/cypress.config.js index bfc84190..553377ac 100644 --- a/cypress.config.js +++ b/cypress.config.js @@ -13,4 +13,5 @@ export default defineConfig({ 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4.1 Mobile/15E148 Safari/604.1', viewportHeight: 800, viewportWidth: 400, + defaultCommandTimeout: 20000, }); diff --git a/src/components/ConfirmSwapModal.vue b/src/components/ConfirmSwapModal.vue index 41080d3b..02bb7d65 100644 --- a/src/components/ConfirmSwapModal.vue +++ b/src/components/ConfirmSwapModal.vue @@ -44,7 +44,7 @@ {{ slippage }}%
- {{ $t('confirmSwapModal.priceImpact') }} + {{ $t('confirmSwapModal.priceImpact', { token: from.symbol }) }} {{ priceImpact?.toFixed(8) }}%
diff --git a/src/components/explore/PairTable.vue b/src/components/explore/PairTable.vue index 102821d1..39760831 100644 --- a/src/components/explore/PairTable.vue +++ b/src/components/explore/PairTable.vue @@ -58,15 +58,15 @@ export default { value: pair.tvlUsd, }, volumeDay: { - text: formatUsdPretty(pair.volumeUsdDay, 0), + text: formatUsdPretty(pair.volumeUsdDay || 0, 0), value: pair.volumeUsdDay, }, volumeMonth: { - text: formatUsdPretty(pair.volumeUsdMonth, 0), + text: formatUsdPretty(pair.volumeUsdMonth || 0, 0), value: pair.volumeUsdMonth, }, volumeAll: { - text: formatUsdPretty(pair.volumeUsdAll, 0), + text: formatUsdPretty(pair.volumeUsdAll || 0, 0), value: pair.volumeUsdAll, }, })); diff --git a/src/components/explore/PriceHistoryGraph.vue b/src/components/explore/PriceHistoryGraph.vue index d90f8212..dacdfa37 100644 --- a/src/components/explore/PriceHistoryGraph.vue +++ b/src/components/explore/PriceHistoryGraph.vue @@ -4,10 +4,10 @@ v-for="label in labels" :key="label" class="p-16 hidden md:block" - :fill="label === selectedChart ? 'light' : 'transparent'" + :fill="label.type === selectedChart.type ? 'light' : 'transparent'" @click="changeChartContent(label)" > - {{ label }} + {{ label.text }}
@@ -18,7 +18,7 @@ @change="changeChartContent($event.target.value)" >
@@ -71,7 +71,6 @@ import { import { Line, Bar } from 'vue-chartjs'; import 'chartjs-adapter-date-fns'; import ButtonDefault from '@/components/ButtonDefault.vue'; -import BigNumber from 'bignumber.js'; const TIME_FRAMES = { '1H': 1, @@ -102,18 +101,27 @@ export default { Bar, }, props: { - datasets: { type: Array, required: true }, - x: { type: Array, required: true }, - initialChart: { type: String, default: 'Volume' }, + availableGraphTypes: { type: Array, required: true }, + initialChart: { type: Object, required: true }, initialTimeFrame: { type: String, default: 'MAX' }, - loading: { type: Boolean, default: false }, + pairId: { type: String, default: null }, + tokenId: { type: String, default: null }, }, data() { return { selectedTimeFrame: null, - selectedChart: null, + selectedChart: { + type: null, + text: null, + }, colors: ['red', 'green', 'blue', 'purple', 'orange'], timeFrames: TIME_FRAMES, + graph: { + labels: [], + data: [], + graphType: null, + }, + loading: false, }; }, computed: { @@ -137,7 +145,7 @@ export default { offset: true, min: Math.max( Date.now() - 1000 * 60 * 60 * this.timeFrames[this.selectedTimeFrame], - this.filteredData.filteredTime[0], + this.graph.labels[0], ), max: Date.now(), }, @@ -145,152 +153,22 @@ export default { ticks: { // Include a dollar sign in the ticks callback: (value) => - ['TVL', 'Fees', 'Volume'].includes(this.selectedChart) ? `$${value}` : value, + ['TVL', 'Fees', 'Volume'].includes(this.selectedChart.type) ? `$${value}` : value, }, }, }, }; }, labels() { - return this.datasets.map((d) => d.label); - }, - filteredData() { - const selectedDataSet = this.datasets.find((d) => d.label === this.selectedChart); - const minTime = - this.selectedTimeFrame === 'MAX' - ? Math.min(...this.x) - : Date.now() - 1000 * 60 * 60 * this.timeFrames[this.selectedTimeFrame]; - - const data = { - filteredData: selectedDataSet.data - .filter((_, i) => this.x[i] >= minTime) - .filter((d) => !new BigNumber(d).isNaN()), - excludedData: selectedDataSet.data - .filter((_, i) => this.x[i] < minTime) - .filter((d) => !new BigNumber(d).isNaN()), - filteredTime: this.x - .filter((_, i) => !new BigNumber(selectedDataSet.data[i]).isNaN()) - .filter((d) => d >= minTime) - .map((d) => Number(d)), - excludedTime: this.x - .filter((_, i) => !new BigNumber(selectedDataSet.data[i]).isNaN()) - .filter((d) => d < minTime) - .map((d) => Number(d)), - }; - - // interpolate data to show full frame - if ( - (['TVL', 'Locked'].includes(this.selectedChart) || this.selectedChart.includes('Price')) && - data.excludedData.length > 0 - ) { - // all of these are aggregated and summed, so we need to have baseline - data.filteredData.unshift(data.excludedData.pop()); - data.filteredTime.unshift(minTime); - data.excludedTime.pop(); - } - - if (['Volume', 'Fees'].includes(this.selectedChart) && data.filteredData.length > 0) { - // these just show the last value, so we need to have a baseline for the graph time but no value - // if there is no data, we do not need to add anything as we can show "no data" - data.filteredData.unshift(0); - data.filteredTime.unshift(minTime); - } - - if (this.selectedChart.includes('Price')) { - // as these always have current value, we need to add it to the end - // theoretically this is also required for TVL and locked, but we interpolate those in the graph based - // on the last value, so we don't need to add it here - data.filteredData.push(data.filteredData[data.filteredData.length - 1]); - data.filteredTime.push(Date.now()); - } - - return { - ...data, - selectedDataSet, - minTime, - }; + return this.availableGraphTypes; }, graphData() { - // filter data based on selected time - const { filteredTime, filteredData, selectedDataSet, minTime } = this.filteredData; - if ( - (filteredData.length === 0 || filteredTime.length === 0 || !selectedDataSet) && - (this.selectedChart === 'Fees' || this.selectedChart === 'Volume') - ) { - return { - labels: [], - datasets: [], - }; - } - - // aggregate data based on selected time - // retrieve min time from data or default to selected view - if (['TVL', 'Volume', 'Fees', 'Locked'].includes(this.selectedChart)) { - // these three charts are bar charts, so we need to calculate buckets - const bucketSize = (Date.now() - minTime) / 30; - - // seed empty buckets - const emptyBuckets = Object.fromEntries( - Array.from({ length: 31 }).map((_, i) => { - const key = minTime + i * bucketSize; - return [key, []]; - }), - ); - - const aggregatedData = filteredData.reduce((acc, d, i) => { - const time = filteredTime[i]; - const bucketIndex = Math.floor((time - minTime) / bucketSize); - const key = minTime + bucketIndex * bucketSize; - acc[key].push(d); - return acc; - }, emptyBuckets); - let bucketedData; - // interpolate TVL - if (['TVL', 'Locked'].includes(this.selectedChart)) { - // average TVL - let prevArr = []; - bucketedData = Object.fromEntries( - Object.entries(aggregatedData).map(([time, bucketArr], index) => { - let aggregatedValue = bucketArr - .reduce((acc, v) => acc.plus(v), new BigNumber(0)) - .div(bucketArr.length); - // interpolate TVL by filling in missing data with latest value from previous bucket - if (index > 0 && aggregatedValue.isNaN()) { - aggregatedValue = prevArr[prevArr.length - 1]; - } else { - prevArr = [...bucketArr]; - } - return [time, aggregatedValue]; - }), - ); - } else { - // sum fees and volume - bucketedData = Object.fromEntries( - Object.entries(aggregatedData).map(([time, bucketArr]) => [ - time, - bucketArr.reduce((acc, v) => acc.plus(v), new BigNumber(0)), - ]), - ); - } - return { - labels: Object.keys(bucketedData).map((x) => Number(x)), - datasets: [ - { - label: selectedDataSet.label, - data: Object.values(bucketedData).map((y) => Number(y)), - borderColor: 'rgb(0 255 157 / 80%)', - backgroundColor: 'rgb(0 255 157 / 80%)', - }, - ], - }; - } - return { - labels: filteredTime.map((x) => Number(x)), + labels: this.graph.labels.map((l) => Number(l)), datasets: [ { - label: selectedDataSet.label, - data: filteredData.map((y) => Number(y)), + label: this.graph.graphType, + data: this.graph.data?.map((n) => Number(n)), borderColor: 'rgb(0 255 157 / 80%)', backgroundColor: 'rgb(0 255 157 / 80%)', }, @@ -298,9 +176,12 @@ export default { }; }, showBar() { - return ['TVL', 'Volume', 'Fees', 'Locked'].includes(this.selectedChart); + return ['TVL', 'Volume', 'Fees', 'Locked'].includes(this.selectedChart.type); }, }, + async mounted() { + await this.fetchData(); + }, created() { this.selectedTimeFrame = this.initialTimeFrame; this.selectedChart = this.initialChart; @@ -308,9 +189,27 @@ export default { methods: { changeTimeFrame(newTimeFrame) { this.selectedTimeFrame = newTimeFrame; + this.fetchData(); }, changeChartContent(newChart) { this.selectedChart = newChart; + this.fetchData(); + }, + async fetchData() { + this.loading = true; + this.graph.data = []; + let options = { + graphType: this.selectedChart.type, + timeFrame: this.selectedTimeFrame, + }; + if (this.pairId) { + options = { ...options, pairAddress: this.pairId }; + } + if (this.tokenId) { + options = { ...options, tokenAddress: this.tokenId }; + } + this.graph = await this.$store.dispatch('backend/fetchGraph', options); + this.loading = false; }, }, }; diff --git a/src/components/explore/TokenTable.vue b/src/components/explore/TokenTable.vue index e04b193e..85a2319d 100644 --- a/src/components/explore/TokenTable.vue +++ b/src/components/explore/TokenTable.vue @@ -74,15 +74,15 @@ export default { value: token.priceChangeMonth, }, volumeDay: { - text: formatUsdPretty(token.volumeUsdDay, 0), + text: formatUsdPretty(token.volumeUsdDay || 0, 0), value: token.volumeUsdDay, }, volumeMonth: { - text: formatUsdPretty(token.volumeUsdMonth, 0), + text: formatUsdPretty(token.volumeUsdMonth || 0, 0), value: token.volumeUsdMonth, }, volumeAll: { - text: formatUsdPretty(token.volumeUsdAll, 0), + text: formatUsdPretty(token.volumeUsdAll || 0, 0), value: token.volumeUsdAll, }, })); diff --git a/src/lib/swapUtils.js b/src/lib/swapUtils.js index aeedbff8..723c4234 100644 --- a/src/lib/swapUtils.js +++ b/src/lib/swapUtils.js @@ -119,7 +119,7 @@ const getPriceImpactForPairReserves = (pairReserves, amountA) => { const marketPrice = BigNumber(1).div(ratioFromPairReserves(pairReserves)); const newPrice = BigNumber(amountA).div(receivedB); - return newPrice.minus(marketPrice).times(100).div(marketPrice).toNumber(); + return -newPrice.minus(marketPrice).times(100).div(newPrice).toNumber(); }; /** diff --git a/src/locales/en.json b/src/locales/en.json index fd8d73b9..382b50ff 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -50,7 +50,7 @@ "to": "To", "transactionDetails": "Transaction Details", "liquidityProviderFee": "Liquidity Provider Fee", - "priceImpact": "Price Impact", + "priceImpact": "Price Impact on {token}", "allowedSlippage": "Allowed Slippage", "minReceived": "Minimum received", "maxSpent": "Maximum spent", diff --git a/src/locales/fr.json b/src/locales/fr.json index 1f7b00dd..5c1092f1 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -42,7 +42,7 @@ "to": "Pour", "transactionDetails": "détails de la transaction", "liquidityProviderFee": "Frais de fournisseur de liquidité", - "priceImpact": "Incidence sur les prix", + "priceImpact": "Incidence sur les prix de {token}", "allowedSlippage": "Glissement autorisé", "minReceived": "Minimum reçu", "maxSpent": "Dépense maximale", diff --git a/src/locales/ru.json b/src/locales/ru.json index ca1d72ea..3d6cdecb 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -36,7 +36,7 @@ "to": "Получаете", "transactionDetails": "Детали транзакции", "liquidityProviderFee": "Комиссия поставщика ликвидности", - "priceImpact": "Влияние на цену", + "priceImpact": "Влияние на цену {token}", "allowedSlippage": "Допустимое проскальзывание", "minReceived": "Минимум к получению", "maxSpent": "Максимум к продаже", diff --git a/src/locales/zh-cn.json b/src/locales/zh-cn.json index 6ddf476c..c4f6e0fb 100644 --- a/src/locales/zh-cn.json +++ b/src/locales/zh-cn.json @@ -49,7 +49,7 @@ "to": "到", "transactionDetails": "交换详情", "liquidityProviderFee": "Liquidity Provider Fee", - "priceImpact": "价格影响", + "priceImpact": "价格影响针对 {token}", "allowedSlippage": "滑点", "minReceived": "最小收益", "maxSpent": "最多支付", diff --git a/src/store/modules/dexBackend.js b/src/store/modules/dexBackend.js index 0c590b96..cc4290e8 100644 --- a/src/store/modules/dexBackend.js +++ b/src/store/modules/dexBackend.js @@ -128,7 +128,7 @@ export default { if (!pair) return null; } const resp = await dispatch('safeFetch', { - url: `pairs/by-address/${pairAddress || pair.address}`, + url: `pairs/${pairAddress || pair.address}`, }); return ( resp && { @@ -144,7 +144,7 @@ export default { }, async fetchSwapRoutes({ dispatch }, { tokenA, tokenB }) { - return dispatch('safeFetch', { url: `pairs/swap-routes/${tokenA}/${tokenB}` }); + return dispatch('safeFetch', { url: `swap-routes/${tokenA}/${tokenB}` }); }, async getListedTokens({ dispatch }) { @@ -156,6 +156,10 @@ export default { })); }, + async getTokenWithUsd({ dispatch }, tokenId) { + return dispatch('safeFetch', { url: `tokens/${tokenId}` }); + }, + async getAllTokens({ dispatch }) { return dispatch('safeFetch', { url: 'tokens' }); }, @@ -194,11 +198,16 @@ export default { }, async fetchPairsByToken({ dispatch }, tokenId) { - return dispatch('safeFetch', { url: `tokens/by-address/${tokenId}/pairs` }); + return dispatch('safeFetch', { url: `tokens/${tokenId}/pairs` }); }, async fetchPairsByTokenUsd({ dispatch }, tokenId) { return dispatch('safeFetch', { url: `pairs?token=${tokenId}` }); }, + + async fetchGraph({ dispatch }, options) { + const queryString = new URLSearchParams(options).toString(); + return dispatch('safeFetch', { url: `graph?${queryString}` }); + }, }, }; diff --git a/src/views/AddLiquidity.vue b/src/views/AddLiquidity.vue index e87bb495..1e89fc29 100644 --- a/src/views/AddLiquidity.vue +++ b/src/views/AddLiquidity.vue @@ -153,7 +153,10 @@ export default { const amountTokenB = expandDecimals(this.amountTokenB, this.tokenB.decimals); const amount = amountTokenA * amountTokenB; const reserve = this.reserveTokenB * this.reserveTokenA; - return BigNumber(amount).times(100).div(reserve).toNumber(); + return BigNumber(amount) + .times(100) + .div(reserve + amount) + .toNumber(); }, ratio() { if (!this.reserveTokenA || !this.reserveTokenB || !this.tokenA || !this.tokenB) { diff --git a/src/views/ExploreView.vue b/src/views/ExploreView.vue index fa30d11d..8d7aec7e 100644 --- a/src/views/ExploreView.vue +++ b/src/views/ExploreView.vue @@ -4,21 +4,15 @@

TVL

Volume

@@ -74,7 +68,6 @@ import { defineComponent } from 'vue'; import ExploreWrapper from '@/components/explore/ExploreWrapper.vue'; import { mapGetters } from 'vuex'; -import BigNumber from 'bignumber.js'; import PriceHistoryGraph from '@/components/explore/PriceHistoryGraph.vue'; import PairTable from '@/components/explore/PairTable.vue'; import TransactionTable from '@/components/explore/TransactionTable.vue'; @@ -97,17 +90,10 @@ export default defineComponent({ history: [], tokenMap: new Map(), activeTab: 'Tokens', - loading: false, }; }, computed: { ...mapGetters(['activeNetwork']), - tvl() { - return [this.graphData.datasets[0]]; - }, - volume() { - return [this.graphData.datasets[1]]; - }, pairTable() { return this.pairs.map((pair) => ({ ...pair, @@ -125,57 +111,14 @@ export default defineComponent({ tokenTable() { return [...this.tokenMap.values()]; }, - graphData() { - let tvl = new BigNumber(0); - return this.history.reduce( - (acc, tx) => { - // TVL - // deltaUsdValue is already calculated but absolute, so we need to check the deltaReserve to get the sign - const delta0 = new BigNumber(tx.delta0UsdValue).times(Math.sign(tx.deltaReserve0)); - const delta1 = new BigNumber(tx.delta1UsdValue).times(Math.sign(tx.deltaReserve1)); - tvl = tvl.plus(delta0.isNaN() ? 0 : delta0).plus(delta1.isNaN() ? 0 : delta1); - acc.datasets[0].data = [...acc.datasets[0].data, tvl.toString()].map((d) => d || 0); - - // VOLUME - if (tx.type === 'SwapTokens') { - acc.datasets[1].data = [ - ...acc.datasets[1].data, - new BigNumber(tx.delta0UsdValue).plus(tx.delta1UsdValue).toString(), - ].map((d) => d || 0); - } else { - acc.datasets[1].data = [...acc.datasets[1].data, 0].map((d) => d || 0); - } - acc.x = [...acc.x, tx.microBlockTime]; - return acc; - }, - { - x: [], - datasets: [ - { - label: 'TVL', - data: [], - }, - { - label: 'Volume', - data: [], - }, - ], - }, - ); - }, }, async mounted() { - this.loading = true; // fetch all tokens const tokens = await this.$store.dispatch('backend/getAllTokens'); this.tokenMap = new Map(tokens.map((token) => [token.address, detectAndModifyWAE(token)])); // fetch all pairs const fetchResult = await this.$store.dispatch('backend/fetchPairs'); this.pairs = Object.values(fetchResult); - - // fetch all history - this.history = await this.$store.dispatch('backend/fetchHistory'); - this.loading = false; }, methods: { pairToToken(pairAddress) { diff --git a/src/views/PoolDetailView.vue b/src/views/PoolDetailView.vue index b254eb22..ac531221 100644 --- a/src/views/PoolDetailView.vue +++ b/src/views/PoolDetailView.vue @@ -3,18 +3,35 @@

- {{ - pair?.token0.symbol - }} + {{ pair?.token0.symbol }} + / - {{ - pair?.token1.symbol - }} + {{ pair?.token1.symbol }} +

- +
@@ -185,71 +202,6 @@ export default defineComponent({ const tx = this.history[this.history.length - 1]; return formatAmountPretty(tx?.reserve1, this.pair?.token1.decimals); }, - graphData() { - return this.history.reduce( - (acc, tx) => { - // Price 0/1 - acc.datasets[0].data = [ - ...acc.datasets[0].data, - new BigNumber(tx.reserve0) - .div(BigNumber(10).pow(this.pair.token0.decimals)) - .div(new BigNumber(tx.reserve1).div(BigNumber(10).pow(this.pair.token1.decimals))) - .toString(), - ].map((d) => d || 0); - // Price 1/0 - acc.datasets[1].data = [ - ...(acc.datasets[1].data || []), - new BigNumber(tx.reserve1) - .div(BigNumber(10).pow(this.pair.token1.decimals)) - .div(new BigNumber(tx.reserve0).div(BigNumber(10).pow(this.pair.token0.decimals))) - .toString(), - ].map((d) => d || 0); - // TVL - acc.datasets[2].data = [ - ...acc.datasets[2].data, - new BigNumber(tx.reserve0Usd).plus(tx.reserve1Usd).toString(), - ].map((d) => d || 0); - // Fee - acc.datasets[3].data = [...acc.datasets[3].data, tx.txUsdFee].map((d) => d || 0); - // Volume - if (tx.type === 'SwapTokens') { - acc.datasets[4].data = [ - ...acc.datasets[4].data, - new BigNumber(tx.delta0UsdValue).plus(tx.delta1UsdValue).toString(), - ].map((d) => d || 0); - } else { - acc.datasets[4].data = [...acc.datasets[4].data, 0].map((d) => d || 0); - } - acc.x = [...acc.x, tx.microBlockTime]; - return acc; - }, - { - x: [], - datasets: [ - { - label: `${this.pair?.token1.symbol} / ${this.pair?.token0.symbol} Price`, - data: [], - }, - { - label: `${this.pair?.token0.symbol} / ${this.pair?.token1.symbol} Price`, - data: [], - }, - { - label: 'TVL', - data: [], - }, - { - label: 'Fees', - data: [], - }, - { - label: 'Volume', - data: [], - }, - ], - }, - ); - }, }, async mounted() { this.loading = true; diff --git a/src/views/TokenDetailView.vue b/src/views/TokenDetailView.vue index 16258bd3..9c771697 100644 --- a/src/views/TokenDetailView.vue +++ b/src/views/TokenDetailView.vue @@ -2,11 +2,21 @@
-

{{ metaInfo?.symbol }} / {{ metaInfo?.name }}

+

{{ tokenWithUsd?.symbol }} / {{ tokenWithUsd?.name }}

- +
@@ -37,12 +47,12 @@
- +
- + - +
@@ -54,7 +64,7 @@

Transactions

@@ -68,8 +78,8 @@

Token Information

- - + + { - reserve = reserve.plus(this.getDeltaReserve(tx)); - acc.datasets[0].data = [...acc.datasets[0].data, this.getUsdPrice(tx)].map((d) => d || 0); - acc.datasets[1].data = [ - ...acc.datasets[1].data, - new BigNumber(reserve) - .multipliedBy(this.getUsdPrice(tx)) - .div(new BigNumber(10).pow(this.metaInfo.decimals)), - ].map((d) => d || 0); - acc.datasets[2].data = [ - ...acc.datasets[2].data, - new BigNumber(reserve).div(new BigNumber(10).pow(this.metaInfo.decimals)), - ].map((d) => d || 0); - if (tx.type === 'SwapTokens') { - acc.datasets[3].data = [ - ...acc.datasets[3].data, - new BigNumber(this.getDeltaReserve(tx)) - .abs() - .multipliedBy(this.getUsdPrice(tx)) - .div(new BigNumber(10).pow(this.metaInfo.decimals)), - ].map((d) => d || 0); - } else { - acc.datasets[3].data = [...acc.datasets[3].data, 0]; - } - acc.x = [...acc.x, tx.microBlockTime]; - return acc; - }, - { - x: [], - datasets: [ - { - label: 'Price', - data: [], - }, - { - label: 'TVL', - data: [], - }, - { - label: 'Locked', - data: [], - }, - { - label: 'Volume', - data: [], - }, - ], - }, - ); - }, reversedTransactions() { return this.history .slice() @@ -202,59 +172,25 @@ export default defineComponent({ })); }, supply() { - return formatAmountPretty(this.metaInfo.event_supply, this.metaInfo.decimals); - }, - priceRaw() { - // latest 20 history events - const latestHistoryEntries = this.history.slice(-5); - // average the price of the last events - const historicPriceEntries = latestHistoryEntries - .map((historyElement) => this.getUsdPrice(historyElement)) - .filter((price) => !price.isNaN()); - - return historicPriceEntries - .reduce((a, b) => a.plus(b), BigNumber(0)) - .div(historicPriceEntries.length); + return formatAmountPretty(this.totalSupply, this.tokenWithUsd.decimals); }, price() { - return formatUsdPretty(this.priceRaw, 0); - }, - lockedRaw() { - return this.pairs?.pairs0 - .map((pair) => pair.liquidityInfo.reserve0) - .filter((reserve) => !!reserve) - .reduce((a, b) => a.plus(b), BigNumber(0)) - .plus( - this.pairs.pairs1 - .map((pair) => pair.liquidityInfo.reserve1) - .filter((reserve) => !!reserve) - .reduce((a, b) => a.plus(b), BigNumber(0)), - ) - .div(new BigNumber(10).pow(this.metaInfo.decimals)); + return formatUsdPretty(this.tokenWithUsd.priceUsd, 0); }, locked() { - return formatAmountPretty(this.lockedRaw, 0); + return formatAmountPretty(this.tokenWithUsd.totalReserve, 0); }, tvl() { - return formatUsdPretty(new BigNumber(this.lockedRaw).multipliedBy(this.priceRaw), 0); + return formatUsdPretty(this.tokenWithUsd.tvlUsd, 0); }, fdv() { return formatUsdPretty( - new BigNumber(this.metaInfo.event_supply).multipliedBy(this.priceRaw).toString(), - this.metaInfo.decimals, - ); - }, - volume() { - return formatUsdPretty( - this.history - .filter((tx) => Date.now() - tx.microBlockTime < 24 * 60 * 60 * 1000) - .filter((tx) => tx.type === 'SwapTokens') - .reduce((acc, tx) => acc.plus(this.getUsdPrice(tx)), new BigNumber(0)), - 0, + new BigNumber(this.totalSupply).multipliedBy(this.tokenWithUsd.priceUsd).toString(), + this.tokenWithUsd.decimals, ); }, - fees() { - return 0; + volume24h() { + return formatUsdPretty(this.tokenWithUsd.volumeUsdDay || 0, 0); }, }, async mounted() { @@ -262,14 +198,19 @@ export default defineComponent({ // extract param from URL this.tokenId = this.$route.params.id; - const metaInfo = await this.$store.dispatch('tokens/fetchToken', this.tokenId); - this.metaInfo = detectAndModifyWAE({ - ...metaInfo, - address: this.tokenId, - }); + this.totalSupply = await this.$store + .dispatch('tokens/fetchToken', this.tokenId) + .then((r) => r.event_supply); this.pairs = await this.$store.dispatch('backend/fetchPairsByToken', this.tokenId); + this.tokenWithUsd = await this.$store.dispatch('backend/getTokenWithUsd', this.tokenId); + + this.tokenWithUsd = detectAndModifyWAE({ + ...this.tokenWithUsd, + address: this.tokenId, + }); + if (!this.pairs) { this.loading = false; // redirect to 404 @@ -282,7 +223,7 @@ export default defineComponent({ pair.address, { ...pair, - token0: this.metaInfo, + token0: this.tokenWithUsd, token1: detectAndModifyWAE(pair.oppositeToken), }, ]), @@ -291,7 +232,7 @@ export default defineComponent({ { ...pair, token0: detectAndModifyWAE(pair.oppositeToken), - token1: this.metaInfo, + token1: this.tokenWithUsd, }, ]), ]); @@ -302,10 +243,6 @@ export default defineComponent({ token0: this.pairMap.get(pair.address).token0, token1: this.pairMap.get(pair.address).token1, })); - this.tokenIdMap = new Map([ - ...this.pairs.pairs0.map((pair) => [pair.address, 0]), - ...this.pairs.pairs1.map((pair) => [pair.address, 1]), - ]); // Fetch token price history this.history = await this.$store.dispatch('backend/fetchHistory', { @@ -315,21 +252,6 @@ export default defineComponent({ }, methods: { shortenAddress, - getDeltaReserve(historyEntry) { - if (this.tokenIdMap.get(historyEntry.pairAddress) === 0) { - return historyEntry.deltaReserve0; - } - return historyEntry.deltaReserve1; - }, - getTokenPrice(historyEntry) { - if (this.tokenIdMap.get(historyEntry.pairAddress) === 0) { - return historyEntry.token0AePrice; - } - return historyEntry.token1AePrice; - }, - getUsdPrice(historyEntry) { - return new BigNumber(this.getTokenPrice(historyEntry)).multipliedBy(historyEntry.aeUsdPrice); - }, }, }); diff --git a/tests/unit/swap-utils.spec.js b/tests/unit/swap-utils.spec.js index 14406756..9177d011 100644 --- a/tests/unit/swap-utils.spec.js +++ b/tests/unit/swap-utils.spec.js @@ -70,7 +70,7 @@ describe('route price impact', () => { }); const toPairs = (xs) => xs.map(toPair); const priceImpact = (xs, tokenA, amountA) => getPriceImpactForRoute(toPairs(xs), tokenA, amountA); - it('price impact to be 0.5', () => { + it('price impact to be -0.4975124378109453', () => { expect( priceImpact( [ @@ -82,9 +82,9 @@ describe('route price impact', () => { 'a', 10000n, ), - ).toBe(0.5); + ).toBe(-0.4975124378109453); }); - it('price impact to be 5', () => { + it('price impact to be -4.761904761904762', () => { expect( priceImpact( [ @@ -96,7 +96,7 @@ describe('route price impact', () => { 'a', 100000n, ), - ).toBe(5); + ).toBe(-4.761904761904762); }); it('should receive 1', () => { expect(getReceivedTokensForPairReserves([[2, 2]], 2).toNumber()).toBe(1); @@ -113,7 +113,7 @@ describe('route price impact', () => { ).toBe(0.6666666666666666); }); - it('swapping reserveA will have priceImpact=100%', () => { + it('swapping reserveA will have priceImpact=-50%', () => { expect( priceImpact( [ @@ -125,10 +125,10 @@ describe('route price impact', () => { 'a', 2, ), - ).toBe(100); + ).toBe(-50); }); - it('swapping reserveA withing two pairs will have priceImpact=200%', () => { + it('swapping reserveA withing two pairs will have priceImpact=-66.66666666666667%', () => { expect( priceImpact( [ @@ -144,9 +144,9 @@ describe('route price impact', () => { 'a', 2, ), - ).toBe(200); + ).toBe(-66.66666666666667); }); - it('swapping reserveA withing 3 pairs will have priceImpact=300%', () => { + it('swapping reserveA withing 3 pairs will have priceImpact=-75%', () => { expect( priceImpact( [ @@ -166,9 +166,9 @@ describe('route price impact', () => { 'a', 2, ), - ).toBe(300); + ).toBe(-75); }); - it('swapping 25 for [[100,50],[25,25]] will have priceImpact=75%', () => { + it('swapping 25 for [[100,50],[25,25]] will have priceImpact=-42.857142857142854%', () => { expect( priceImpact( [ @@ -184,7 +184,7 @@ describe('route price impact', () => { 'a', 25, ), - ).toBe(75); + ).toBe(-42.857142857142854); }); }); describe('get route reserves', () => {