Skip to content

Commit

Permalink
UI 678 lm table (#621)
Browse files Browse the repository at this point in the history
* update: allow baltable to render a totals column

* update: allow usePoolsQuery to take in a list of poolids to filter from and change the page size

* feature: liquidity mining table

* feature: liquidity mining page

* update: allow usePoolsQuery querykey to rely on poolids

* update: stable pool token pills fix

* fix: loading states

* update: baltable sort styling

* fix: warnings and add banner

* update: use new pricing composable func

* fix: linting errors
  • Loading branch information
arb000r authored Aug 5, 2021
1 parent 232d921 commit 55b8023
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 105 deletions.
7 changes: 1 addition & 6 deletions src/components/_global/BalTable/BalTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -202,12 +202,7 @@
'p-6 bg-white dark:bg-gray-850 border-t dark:border-gray-900'
]"
>
<slot
v-if="column.totalsCell"
v-bind="dataItem"
:name="column.totalsCell"
>
</slot>
<slot v-if="column.totalsCell" :name="column.totalsCell"> </slot>
</td>
</tr>
</tbody>
Expand Down
69 changes: 19 additions & 50 deletions src/components/tables/LMTable/LMTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
</div>
</template>
<template v-slot:poolNameCell="pool">
{{ console.log('steble', pool) }}
<div class="px-6 py-4">
<TokenPills
:tokens="orderedPoolTokens(pool)"
Expand Down Expand Up @@ -79,27 +78,25 @@

<script lang="ts">
import { ColumnDefinition } from '@/components/_global/BalTable/BalTable.vue';
import { WeeklyDistributions } from '@/pages/LiquidityMining.vue';
import { TokenTotal, WeeklyDistributions } from '@/pages/LiquidityMining.vue';
import TokenPills from '../PoolsTable/TokenPills/TokenPills.vue';
import {
DecoratedPoolWithShares,
PoolToken
} from '@/services/balancer/subgraph/types';
import { getAddress } from '@ethersproject/address';
import { computed, defineComponent, PropType, toRefs } from 'vue';
import { computed, defineComponent, PropType, Ref, toRefs } from 'vue';
import { useI18n } from 'vue-i18n';
import useTokens from '@/composables/useTokens';
import useNumbers from '@/composables/useNumbers';
import { sum } from 'lodash';
import { useStore } from 'vuex';
import useDarkMode from '@/composables/useDarkMode';
function getWeekName(week: string) {
const parts = week.split('_');
return `Week ${parts[1]}`;
}
type TokenTotal = { token: string; total: number };
export default defineComponent({
components: {
TokenPills
Expand All @@ -110,21 +107,23 @@ export default defineComponent({
required: true
},
poolMetadata: {
type: Object,
required: true
type: Object
},
isLoading: {
type: Boolean
},
totals: {
type: Object as PropType<Ref<Record<string, TokenTotal[]>>>,
required: true
}
},
setup(props) {
const { t } = useI18n();
const { weeks, poolMetadata } = toRefs(props);
const { tokens } = useTokens();
const { tokens, priceFor } = useTokens();
const { fNum } = useNumbers();
const store = useStore();
const { darkMode } = useDarkMode();
const prices = computed(() => store.state.market.prices);
const data = computed(() => {
if (!poolMetadata.value) return [];
return poolMetadata.value[0].pools.map(pool => ({
Expand Down Expand Up @@ -173,34 +172,6 @@ export default defineComponent({
];
});
const totals = computed(() => {
// map tracking a list of token totals for each week
const weeklyTotals: Record<string, TokenTotal[]> = {};
for (const week of weeks.value) {
// map tracking totals for each token
const tokenTotals: Record<string, TokenTotal> = {};
// this will be an array of pools with their token distributions,
// we just want the values, not the pool id
const distributions = Object.values(week.distributions);
for (const distribution of distributions) {
for (const allocation of distribution) {
if (!tokenTotals[allocation.tokenAddress]) {
tokenTotals[allocation.tokenAddress] = {
token: allocation.tokenAddress,
total: allocation.amount
};
continue;
} else {
tokenTotals[allocation.tokenAddress].total =
tokenTotals[allocation.tokenAddress].total + allocation.amount;
}
}
}
weeklyTotals[week.week] = Object.values(tokenTotals);
}
return weeklyTotals;
});
function orderedPoolTokens(pool: DecoratedPoolWithShares): PoolToken[] {
if (pool.poolType === 'Stable') return pool.tokens;
Expand All @@ -215,27 +186,25 @@ export default defineComponent({
}
function calculatePricesFor(totals: TokenTotal[]) {
let totalUsd = 0;
let totalFiat = 0;
for (const total of totals) {
const usdValue =
prices.value[total.token.toLowerCase()].price * total.total;
totalUsd = totalUsd + usdValue;
const usdValue = priceFor(getAddress(total.token)) * total.total;
totalFiat = totalFiat + usdValue;
}
return totalUsd;
return totalFiat;
}
return {
columns,
data,
orderedTokenAddressesFor,
orderedPoolTokens,
fNum,
getAddress,
totals,
tokens,
prices,
calculatePricesFor,
console
columns,
data,
tokens,
priceFor,
darkMode
};
}
});
Expand Down
3 changes: 3 additions & 0 deletions src/composables/queries/usePoolsQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ export default function usePoolsQuery(
tokensList_contains: tokenList.value
}
};
if (filterOptions?.poolIds?.value.length) {
queryArgs.where.id_in = filterOptions.poolIds.value;
}

const pools = await balancerSubgraphService.pools.get(queryArgs);

Expand Down
169 changes: 120 additions & 49 deletions src/pages/LiquidityMining.vue
Original file line number Diff line number Diff line change
@@ -1,45 +1,56 @@
<template>
<div class="lg:container lg:mx-auto pt-10 md:pt-12">
<div class="px-4">
<h3>{{ title }}</h3>
<span class="text-black-600">{{ description }}</span>
<LMTable
:is-loading="isLoadingPools || isLoadingPoolsIdle"
:poolMetadata="pools"
:weeks="distributions"
/>
<div class="mt-20">
<h4 class="font-bold">About liquidity mining</h4>
<p class="mt-2">
Liquidity mining is a form of ‘yield farming’ used to align incentives
between a protocol and its community. Typically, DeFi protocols
distribute tokens to users who perform certain activities which help
the network grow.<br /><br />
The Balancer protocol via the community Ballers, has allocated BAL
tokens to go to liquidity providers in certain eligible pools (as
listed in the tables above). Tokens are distributed proportional to
the amount of liquidity each address contributed, relative to the
total liquidity in eligible Balancer pools. BAL tokens represent an
ownership stake in the platform and voting rights in community
governance. In addition, other protocols like Polygon are further
incentivizing liquidity by also distributing MATIC tokens to Balancer
liquidity providers in certain pools on Polygon.
</p>
<div class="mt-6">
<h5>Liquidity mining details</h5>
<ul class="mt-2 pl-8 list-disc">
<li class="mt-2">
You’re eligible to receive token distributions if you add
liquidity to any of the eligible pools.
</li>
<li class="mt-2">
Liquidity mining weeks start and end at 00:00 UTC on Mondays.
</li>
<li class="mt-2">
BAL allocations and pool eligibility are determined weekly by the
community ‘Ballers’.
</li>
</ul>
<div>
<div class="lm-banner h-48 flex items-center justify-center flex-col">
<span class="text-white font-semibold"
>Week {{ currentWeek }} Liquidity mining incentives</span
>
<h1 class="font-body mt-2 text-white font-semi bold">
~{{ fNum(currentWeekTotalFiat, 'usd') }}
</h1>
</div>
<div class="lg:container lg:mx-auto pt-10 md:pt-12">
<div class="px-4">
<h3>{{ title }}</h3>
<span class="text-black-600">{{ description }}</span>
<LMTable
:is-loading="isLoadingPools || isLoadingPoolsIdle"
:poolMetadata="pools"
:weeks="weeks"
:totals="totals"
/>
<div class="mt-20">
<h4 class="font-bold">About liquidity mining</h4>
<p class="mt-2">
Liquidity mining is a form of ‘yield farming’ used to align
incentives between a protocol and its community. Typically, DeFi
protocols distribute tokens to users who perform certain activities
which help the network grow.<br /><br />
The Balancer protocol via the community Ballers, has allocated BAL
tokens to go to liquidity providers in certain eligible pools (as
listed in the tables above). Tokens are distributed proportional to
the amount of liquidity each address contributed, relative to the
total liquidity in eligible Balancer pools. BAL tokens represent an
ownership stake in the platform and voting rights in community
governance. In addition, other protocols like Polygon are further
incentivizing liquidity by also distributing MATIC tokens to
Balancer liquidity providers in certain pools on Polygon.
</p>
<div class="mt-6">
<h5>Liquidity mining details</h5>
<ul class="mt-2 pl-8 list-disc">
<li class="mt-2">
You’re eligible to receive token distributions if you add
liquidity to any of the eligible pools.
</li>
<li class="mt-2">
Liquidity mining weeks start and end at 00:00 UTC on Mondays.
</li>
<li class="mt-2">
BAL allocations and pool eligibility are determined weekly by
the community ‘Ballers’.
</li>
</ul>
</div>
</div>
</div>
</div>
Expand All @@ -51,19 +62,24 @@ import { computed, defineComponent } from 'vue';
import LMTable from '@/components/tables/LMTable/LMTable.vue';
import LiquidityMiningDistributions from '@/lib/utils/liquidityMining/MultiTokenLiquidityMining.json';
import usePoolsQuery from '@/composables/queries/usePoolsQuery';
import { flatten, takeRight, uniq } from 'lodash';
import { flatten, last, takeRight, uniq } from 'lodash';
import { Network } from '@/constants/network';
import useNumbers from '@/composables/useNumbers';
import useTokens from '@/composables/useTokens';
import { getAddress } from '@ethersproject/address';
type TokenDistribution = {
tokenAddress: string;
amount: number;
}[];
};
type PoolDistribution = {
chainId: number;
pools: Record<string, TokenDistribution[]>;
};
export type TokenTotal = { token: string; total: number };
type LiquidityMiningDistribution = Record<string, PoolDistribution[]>;
const NETWORK = process.env.VUE_APP_NETWORK || '1';
Expand All @@ -78,19 +94,62 @@ export default defineComponent({
LMTable
},
setup() {
const { fNum } = useNumbers();
const { priceFor } = useTokens();
// seperate variable to type the JSON
const weeks = (LiquidityMiningDistributions as unknown) as LiquidityMiningDistribution;
const weeksJSON = (LiquidityMiningDistributions as unknown) as LiquidityMiningDistribution;
const totals = computed(() => {
// map tracking a list of token totals for each week
const weeklyTotals: Record<string, TokenTotal[]> = {};
for (const week of weeks) {
// map tracking totals for each token
const tokenTotals: Record<string, TokenTotal> = {};
// this will be an array of pools with their token distributions,
// we just want the values, not the pool id
const distributions = Object.values(week.distributions);
for (const distribution of distributions) {
for (const allocation of distribution) {
if (!tokenTotals[allocation.tokenAddress]) {
tokenTotals[allocation.tokenAddress] = {
token: allocation.tokenAddress,
total: allocation.amount
};
continue;
} else {
tokenTotals[allocation.tokenAddress].total =
tokenTotals[allocation.tokenAddress].total + allocation.amount;
}
}
}
weeklyTotals[week.week] = Object.values(tokenTotals);
}
return weeklyTotals;
});
const currentWeekTotalFiat = computed(() => {
let totalFiat = 0;
const currentWeek = last(Object.values(totals.value));
if (currentWeek) {
for (const total of currentWeek) {
const fiatValue = priceFor(getAddress(total.token)) * total.total;
totalFiat = totalFiat + fiatValue;
}
}
return totalFiat;
});
// only concerned with past 3 weeks
const distributions = takeRight(Object.keys(weeks), 3).map(week => ({
const weeks = takeRight(Object.keys(weeksJSON), 3).map(week => ({
week: week,
distributions: weeks[week]
distributions: weeksJSON[week]
.filter(d => d.chainId === Number(NETWORK))
.map(d => d.pools)[0]
}));
const poolIds = computed(() =>
uniq(flatten(distributions.map(d => Object.keys(d.distributions))))
uniq(flatten(weeks.map(d => Object.keys(d.distributions))))
);
// there shouldn't be too many pools for the LM distribution for each chain
Expand Down Expand Up @@ -125,14 +184,26 @@ export default defineComponent({
return '';
});
const currentWeek = computed(() => last(last(weeks)?.week.split('_')));
return {
distributions,
weeks,
pools,
title,
totals,
description,
isLoadingPools,
isLoadingPoolsIdle
isLoadingPoolsIdle,
currentWeek,
currentWeekTotalFiat,
fNum
};
}
});
</script>

<style>
.lm-banner {
background-image: url('/images/backgrounds/bg-header.svg');
}
</style>

4 comments on commit 55b8023

@vercel
Copy link

@vercel vercel bot commented on 55b8023 Aug 5, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on 55b8023 Aug 5, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on 55b8023 Aug 5, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on 55b8023 Aug 5, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

beta-polygon – ./

beta-polygon-balancer.vercel.app
beta-polygon.vercel.app
beta-polygon-git-develop-balancer.vercel.app

Please sign in to comment.