Skip to content

Commit

Permalink
Hotfix 1.17.5 (#780)
Browse files Browse the repository at this point in the history
* Add ability to add third party APRs & add Lido steth APR

* 1.17.5
  • Loading branch information
garethfuller authored Sep 2, 2021
1 parent f69dec2 commit 41a7c4b
Show file tree
Hide file tree
Showing 10 changed files with 129 additions and 21 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@balancer-labs/frontend-v2",
"version": "1.17.4",
"version": "1.17.5",
"engines": {
"node": "14.x",
"npm": ">=7"
Expand Down
26 changes: 25 additions & 1 deletion src/components/tooltips/LiquidityMiningTooltip.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@
{{ fNum(pool.dynamic.apr.pool, 'percent') }}
<span class="ml-1 text-gray-500 text-xs">{{ $t('swapFeeAPR') }}</span>
</div>
<div
v-if="hasThirdPartyAPR"
class="whitespace-nowrap flex items-center mb-1"
>
{{ fNum(pool.dynamic.apr.thirdParty, 'percent') }}
<span class="ml-1 text-gray-500 text-xs">
{{ thirdPartyAPRLabel }}
</span>
</div>
<div class="whitespace-nowrap flex items-center">
{{ fNum(pool.dynamic.apr.liquidityMining, 'percent') }}
<span class="ml-1 text-gray-500 text-xs flex items-center">
Expand Down Expand Up @@ -54,6 +63,9 @@ import { defineComponent, PropType, computed } from 'vue';
import useNumbers from '@/composables/useNumbers';
import useTokens from '@/composables/useTokens';
import { DecoratedPool } from '@/services/balancer/subgraph/types';
import { bnum } from '@/lib/utils';
import { isWstETH } from '@/composables/usePool';
import { useI18n } from 'vue-i18n';
export default defineComponent({
name: 'LiquidityMiningTooltip',
Expand All @@ -71,6 +83,7 @@ export default defineComponent({
*/
const { fNum } = useNumbers();
const { getTokens } = useTokens();
const { t } = useI18n();
/**
* COMPUTED
Expand All @@ -85,11 +98,22 @@ export default defineComponent({
() => Object.keys(lmTokens.value).length > 1
);
const hasThirdPartyAPR = computed(() =>
bnum(props.pool.dynamic.apr.thirdParty).gt(0)
);
const thirdPartyAPRLabel = computed(() => {
if (isWstETH(props.pool)) return t('thirdPartyAPR.steth');
return '';
});
return {
lmBreakdown,
fNum,
lmTokens,
multiRewardPool
multiRewardPool,
hasThirdPartyAPR,
thirdPartyAPRLabel
};
}
});
Expand Down
4 changes: 2 additions & 2 deletions src/composables/useTime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ export const oneMinInMs = 60 * oneSecondInMs;
export const oneHourInMs = 60 * oneMinInMs;

export const twentyFourHoursInMs = 24 * oneHourInMs;
export const twentyFourHourseInSecs = twentyFourHoursInMs / oneSecondInMs;
export const twentyFourHoursInSecs = twentyFourHoursInMs / oneSecondInMs;

export const timeNowInMs = Math.floor(Date.now() / oneSecondInMs);

Expand All @@ -13,6 +13,6 @@ export default function useTime() {
oneMinInMs,
oneHourInMs,
twentyFourHoursInMs,
twentyFourHourseInSecs
twentyFourHoursInSecs
};
}
5 changes: 4 additions & 1 deletion src/locales/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@
"tradeSuccess": "Successfully traded your tokens",
"tradeInterface": "Trade interface",
"tradeInterfaceTooltip": "Choose Balancer for the best liquidity across Balancer V1 and V2 pools. Choose Gnosis to buy and sell tokens using gas-less orders while providing MEV protection.",
"thirdPartyAPR": {
"steth": "stETH staking rewards APR"
},
"investmentPools": "Investment pools",
"investmentSettled": "Your investment has settled",
"investmentSuccess": "Your tokens have been added to this pool, and you have received a new LP token representing this investment.",
Expand Down Expand Up @@ -391,4 +394,4 @@
"yearAbbrev": "y",
"youDidIt": "You did it!",
"yourTransactions": "Your transactions in this pool"
}
}
44 changes: 36 additions & 8 deletions src/services/balancer/subgraph/entities/pools/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ import { NetworkId } from '@/constants/network';
import { configService as _configService } from '@/services/config/config.service';
import { TokenPrices } from '@/services/coingecko/api/price.service';
import { FiatCurrency } from '@/constants/currency';
import { isStable } from '@/composables/usePool';
import { isStable, isWstETH } from '@/composables/usePool';
import { twentyFourHoursInSecs } from '@/composables/useTime';
import { lidoService } from '@/services/lido/lido.service';

const IS_LIQUIDITY_MINING_ENABLED = true;

Expand Down Expand Up @@ -60,14 +62,14 @@ export default class Pools {
return this.serialize(pools, pastPools, period, prices, currency);
}

private serialize(
private async serialize(
pools: Pool[],
pastPools: Pool[],
period: TimeTravelPeriod,
prices: TokenPrices,
currency: FiatCurrency
): DecoratedPool[] {
return pools.map(pool => {
): Promise<DecoratedPool[]> {
const promises = pools.map(async pool => {
pool.address = this.addressFor(pool.id);
pool.tokenAddresses = pool.tokensList.map(t => getAddress(t));
pool.tokens = this.formatPoolTokens(pool);
Expand All @@ -82,7 +84,12 @@ export default class Pools {
liquidityMiningAPR,
liquidityMiningBreakdown
} = this.calcLiquidityMiningAPR(pool, prices, currency);
const totalAPR = this.calcTotalAPR(poolAPR, liquidityMiningAPR);
const thirdPartyAPR = await this.calcThirdPartyAPR(pool);
const totalAPR = this.calcTotalAPR(
poolAPR,
liquidityMiningAPR,
thirdPartyAPR
);

return {
...pool,
Expand All @@ -93,13 +100,16 @@ export default class Pools {
fees,
apr: {
pool: poolAPR,
thirdParty: thirdPartyAPR,
liquidityMining: liquidityMiningAPR,
liquidityMiningBreakdown,
total: totalAPR
}
}
};
});

return Promise.all(promises);
}

private formatPoolTokens(pool: Pool): PoolToken[] {
Expand Down Expand Up @@ -171,9 +181,26 @@ export default class Pools {
};
}

private calcTotalAPR(poolAPR: string, liquidityMiningAPR: string): string {
/**
* Fetch additional APRs not covered by pool swap fees and
* liquidity minning rewards. These APRs may require 3rd party
* API requests.
*/
private async calcThirdPartyAPR(pool: Pool): Promise<string> {
if (isWstETH(pool)) {
return await lidoService.calcStEthAPRFor(pool);
}
return '0';
}

private calcTotalAPR(
poolAPR: string,
liquidityMiningAPR: string,
thirdPartyAPR: string
): string {
return bnum(poolAPR)
.plus(liquidityMiningAPR)
.plus(thirdPartyAPR)
.toString();
}

Expand All @@ -187,8 +214,9 @@ export default class Pools {

private async timeTravelBlock(period: TimeTravelPeriod): Promise<number> {
const currentBlock = await this.service.rpcProviderService.getBlockNumber();
const dayInSecs = 24 * 60 * 60;
const blocksInDay = Math.round(dayInSecs / this.service.blockTime);
const blocksInDay = Math.round(
twentyFourHoursInSecs / this.service.blockTime
);

switch (period) {
case '24h':
Expand Down
1 change: 1 addition & 0 deletions src/services/balancer/subgraph/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export interface DecoratedPool extends Pool {
volume: string;
apr: {
pool: string;
thirdParty: string;
liquidityMining: string;
liquidityMiningBreakdown: { [address: string]: string };
total: string;
Expand Down
8 changes: 4 additions & 4 deletions src/services/coingecko/api/price.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { configService as _configService } from '@/services/config/config.servic
import { invert } from 'lodash';
import { returnChecksum } from '@/lib/decorators/return-checksum.decorator';
import { retryPromiseWithDelay } from '@/lib/utils/promise';
import { twentyFourHourseInSecs } from '@/composables/useTime';
import { twentyFourHoursInSecs } from '@/composables/useTime';

/**
* TYPES
Expand Down Expand Up @@ -117,8 +117,8 @@ export class PriceService {
throw new Error('To many requests for rate limit.');

const now = Math.floor(Date.now() / 1000);
const end = now - (now % twentyFourHourseInSecs);
const start = end - days * twentyFourHourseInSecs;
const end = now - (now % twentyFourHoursInSecs);
const start = end - days * twentyFourHoursInSecs;

// TODO - remove once wsteth is supported
addresses = addresses.filter(
Expand Down Expand Up @@ -184,7 +184,7 @@ export class PriceService {
address === this.appAddresses.stETH
? price * TOKENS.Prices.ExchangeRates.wstETH.stETH
: price;
dayTimestamp += twentyFourHourseInSecs;
dayTimestamp += twentyFourHoursInSecs;
}
}
return [address, prices];
Expand Down
53 changes: 53 additions & 0 deletions src/services/lido/lido.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { bnum } from '@/lib/utils';
import axios from 'axios';
import { Pool } from '../balancer/subgraph/types';
import ConfigService, { configService } from '../config/config.service';

type LidoAPRs = {
eth: string;
steth: string;
};

type ApiResponse = {
data: LidoAPRs;
};

export default class LidoService {
wethAddress: string;
wstEthAddress: string;

constructor(readonly config: ConfigService = configService) {
this.wethAddress = config.network.addresses.weth;
this.wstEthAddress = config.network.addresses.wstETH;
}

async getStEthAPR(): Promise<string> {
try {
const {
data: { data: aprs }
} = await axios.get<ApiResponse>('https://stake.lido.fi/api/apr');
return bnum(aprs.steth)
.div(100)
.toString();
} catch (error) {
console.error('Failed to fetch stETH APR:', error);
return '0';
}
}

async calcStEthAPRFor(pool: Pool): Promise<string> {
const stethAPR = await this.getStEthAPR();
const wethBalance =
pool.tokens.find(t => t.address === this.wethAddress)?.balance || '0';
const wstethBalance =
pool.tokens.find(t => t.address === this.wstEthAddress)?.balance || '0';
const totalBalance = bnum(wethBalance).plus(wstethBalance);
const wstethRatio = bnum(wstethBalance).div(totalBalance);

return bnum(stethAPR)
.times(wstethRatio)
.toString();
}
}

export const lidoService = new LidoService();
3 changes: 1 addition & 2 deletions src/services/web3/useWeb3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useQuery } from 'vue-query';
import { Web3Plugin, Web3ProviderSymbol } from './web3.plugin';
import { Web3Provider } from '@ethersproject/providers';
import QUERY_KEYS from '@/constants/queryKeys';
import ConfigService from '../config/config.service';
import { configService } from '../config/config.service';
import { isAddress } from '@ethersproject/address';
import { web3Service } from './web3.service';
import { rpcProviderService } from '../rpc-provider/rpc-provider.service';
Expand Down Expand Up @@ -32,7 +32,6 @@ export default function useWeb3() {
disconnectWallet,
connectWallet
} = inject(Web3ProviderSymbol) as Web3Plugin;
const configService = new ConfigService();
const appNetworkConfig = configService.network;
const isV1Supported = isAddress(
configService.network.addresses.exchangeProxy
Expand Down

4 comments on commit 41a7c4b

@vercel
Copy link

@vercel vercel bot commented on 41a7c4b Sep 2, 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 41a7c4b Sep 2, 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 41a7c4b Sep 2, 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:

app – ./

app-balancer.vercel.app
app.balancer.fi
pm2.vercel.app
app-git-master-balancer.vercel.app

@vercel
Copy link

@vercel vercel bot commented on 41a7c4b Sep 2, 2021

Choose a reason for hiding this comment

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

Please sign in to comment.