Skip to content

Commit

Permalink
feat: lib Balancer & forks (#973)
Browse files Browse the repository at this point in the history
* [WIP] - balancer&aura lib

* add balancer lib + missing stake aura contract
  • Loading branch information
0xpeluche authored Oct 19, 2023
1 parent 4afbcc4 commit c2af21e
Show file tree
Hide file tree
Showing 10 changed files with 258 additions and 359 deletions.
168 changes: 22 additions & 146 deletions src/adapters/aura/common/balance.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { getExtraRewardsBalances } from '@adapters/aura/common/extraReward'
import type { Balance, BalancesContext, Contract } from '@lib/adapter'
import { mapSuccessFilter } from '@lib/array'
import { getUnderlyingsBalancesFromBalancer, type IBalancerBalance } from '@lib/balancer/underlying'
import { call } from '@lib/call'
import { abi as erc20Abi } from '@lib/erc20'
import { getBalancesOf } from '@lib/erc20'
import { multicall } from '@lib/multicall'
import { parseEther } from 'viem'

Expand All @@ -13,25 +15,6 @@ const abi = {
stateMutability: 'view',
type: 'function',
},
extraEarned: {
inputs: [
{
internalType: 'address',
name: 'account',
type: 'address',
},
],
name: 'earned',
outputs: [
{
internalType: 'uint256',
name: '',
type: 'uint256',
},
],
stateMutability: 'view',
type: 'function',
},
getPoolTokens: {
inputs: [{ internalType: 'bytes32', name: 'poolId', type: 'bytes32' }],
name: 'getPoolTokens',
Expand Down Expand Up @@ -103,147 +86,40 @@ const AURA: { [key: string]: `0x${string}`[] } = {
export async function getAuraBalStakerBalances(ctx: BalancesContext, staker: Contract): Promise<Balance> {
const balanceOfRes = await call({ ctx, target: staker.address, params: [ctx.address], abi: abi.balanceOfUnderlying })

return {
...staker,
amount: balanceOfRes,
underlyings: undefined,
rewards: undefined,
category: 'farm',
}
return { ...staker, amount: balanceOfRes, underlyings: undefined, rewards: undefined, category: 'farm' }
}

export async function getAuraFarmBalances(
ctx: BalancesContext,
pools: Contract[],
vault: Contract,
): Promise<Balance[]> {
const balanceWithStandardRewards: Balance[] = []
const balanceWithExtraRewards: Balance[] = []
const balances = await getAuraBalancesInternal(ctx, pools, vault, 'gauge')

const earnedsRes = await multicall({
ctx,
calls: balances.map((balance: Contract) => ({ target: balance.gauge, params: [ctx.address] }) as const),
abi: abi.earned,
})

mapSuccessFilter(earnedsRes, (res, idx) => {
const balance = balances[idx]
const rewards = balance.rewards

const poolBalance: Balance = {
const balances: Balance[] = (await getBalancesOf(ctx, pools, { getAddress: (contract) => contract.gauge })).map(
(balance) => ({
...balance,
rewards: [{ ...rewards![0], amount: res.output }, ...rewards!.slice(1)],
}

if (poolBalance.rewards && poolBalance.rewards.length > 1) {
balanceWithExtraRewards.push(poolBalance)
} else {
balanceWithStandardRewards.push(poolBalance)
}
})

const balanceWithExtraRewardsBalances = await getExtraRewardsBalances(ctx, balanceWithExtraRewards)

return getAuraMintAmount(ctx, [...balanceWithStandardRewards, ...balanceWithExtraRewardsBalances])
}

export async function getAuraBalancesInternal(
ctx: BalancesContext,
inputPools: Contract[],
vault: Contract,
targetProp: 'address' | 'gauge',
): Promise<Balance[]> {
const balances: Balance[] = []

const fmtPools: Contract[] = []
inputPools.forEach((pool) => {
if (targetProp === 'gauge' && Array.isArray(pool.gauge)) {
pool.gauge.forEach((gauge) => {
fmtPools.push({ ...pool, gauge: gauge })
})
} else {
fmtPools.push(pool)
}
})

const [poolBalancesRes, uBalancesRes, totalSuppliesRes] = await Promise.all([
multicall({
ctx,
calls: fmtPools.map((pool) => ({ target: pool[targetProp], params: [ctx.address] }) as const),
abi: erc20Abi.balanceOf,
}),
multicall({
ctx,
calls: fmtPools.map((pool) => ({ target: vault.address, params: [pool.poolId] }) as const),
abi: abi.getPoolTokens,
category: 'farm',
}),
multicall({
ctx,
calls: fmtPools.map((pool) => ({ target: pool.address }) as const),
abi: erc20Abi.totalSupply,
}),
])

for (const [index, pool] of fmtPools.entries()) {
const underlyings = pool.underlyings as Contract[]
const rewards = pool.rewards as Balance[]
const poolBalanceRes = poolBalancesRes[index]
const uBalanceRes = uBalancesRes[index]
const totalSupplyRes = totalSuppliesRes[index]

if (
!underlyings ||
!poolBalanceRes.success ||
!uBalanceRes.success ||
!totalSupplyRes.success ||
totalSupplyRes.output === 0n
) {
continue
}
)

const [_tokens, underlyingsBalances] = uBalanceRes.output

underlyings.forEach((underlying, idx) => {
const amount = underlyingsBalances[idx]
underlying.amount = amount
})

const lpTokenBalance = underlyings.find(
(underlying) => underlying.address.toLowerCase() === pool.address.toLowerCase(),
)

const fmtUnderlyings = underlyings
.map((underlying) => {
const realSupply = lpTokenBalance ? totalSupplyRes.output - lpTokenBalance.amount : totalSupplyRes.output
const amount = (underlying.amount * poolBalanceRes.output) / realSupply

return {
...underlying,
amount,
}
})
.filter((underlying) => underlying.address.toLowerCase() !== pool.address.toLowerCase())

balances.push({ ...pool, amount: poolBalanceRes.output, underlyings: fmtUnderlyings, rewards, category: 'farm' })
}

return balances
}
const poolBalances = await getUnderlyingsBalancesFromBalancer(ctx, balances as IBalancerBalance[], vault, {
getAddress: (balance: Balance) => balance.address,
getCategory: (balance: Balance) => balance.category,
})

const getExtraRewardsBalances = async (ctx: BalancesContext, poolBalance: Balance[]): Promise<Balance[]> => {
const extraRewardsBalancesRes = await multicall({
const earnedsRes = await multicall({
ctx,
calls: poolBalance.map((pool: Contract) => ({ target: pool.rewarder, params: [ctx.address] }) as const),
abi: abi.extraEarned,
calls: poolBalances.map((balance: Contract) => ({ target: balance.gauge, params: [ctx.address] }) as const),
abi: abi.earned,
})

poolBalance.forEach((pool, idx) => {
const extraRewardsBalances = extraRewardsBalancesRes[idx].success ? extraRewardsBalancesRes[idx].output : 0n
pool.rewards = [pool.rewards![0], { ...pool.rewards![1], amount: extraRewardsBalances! }]
})
const fmtBalances = mapSuccessFilter(earnedsRes, (res, idx) => {
const poolBalance = poolBalances[idx]
const rewards = poolBalance.rewards as Contract[]

return { ...poolBalance, rewards: [{ ...rewards![0], amount: res.output }, ...rewards!.slice(1)] }
}) as Balance[]

return poolBalance
return getAuraMintAmount(ctx, await getExtraRewardsBalances(ctx, fmtBalances))
}

const getAuraMintAmount = async (ctx: BalancesContext, balances: Balance[]): Promise<Balance[]> => {
Expand Down
35 changes: 35 additions & 0 deletions src/adapters/aura/common/extraReward.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type { Balance, BalancesContext, Contract } from '@lib/adapter'
import { multicall } from '@lib/multicall'

const abi = {
extraEarned: {
inputs: [{ internalType: 'address', name: 'account', type: 'address' }],
name: 'earned',
outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
stateMutability: 'view',
type: 'function',
},
} as const

export const getExtraRewardsBalances = async (ctx: BalancesContext, poolBalance: Balance[]): Promise<Balance[]> => {
const balanceWithStandardRewards: Balance[] = poolBalance.filter((poolBalance) => {
return !poolBalance.rewards || poolBalance.rewards.length === 0
})

const balanceWithExtraRewards: Balance[] = poolBalance.filter((poolBalance) => {
return poolBalance.rewards && poolBalance.rewards.length > 0
})

const extraRewardsBalancesRes = await multicall({
ctx,
calls: balanceWithExtraRewards.map((pool: Contract) => ({ target: pool.rewarder, params: [ctx.address] }) as const),
abi: abi.extraEarned,
})

balanceWithExtraRewards.forEach((pool, idx) => {
const extraRewardsBalances = extraRewardsBalancesRes[idx].success ? extraRewardsBalancesRes[idx].output : 0n
pool.rewards = [pool.rewards![0], { ...pool.rewards![1], amount: extraRewardsBalances! }]
})

return [...balanceWithExtraRewards, ...balanceWithStandardRewards]
}
22 changes: 6 additions & 16 deletions src/adapters/aura/common/pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export async function getAuraPools(ctx: BaseContext, booster: Contract, vault: C
address: lptoken,
pool: lptoken,
lpToken: lptoken,
gauge: [crvRewards],
gauge: crvRewards,
rewards: [BAL],
}
})
Expand Down Expand Up @@ -161,10 +161,7 @@ const getAuraPoolsUnderlyings = async (ctx: BaseContext, pools: Contract[], vaul
const poolsWithUnderlyings: Contract[] = mapSuccessFilter(underlyingsRes, (res, idx) => {
const [tokens]: any = res.output

return {
...pools[idx],
underlyings: tokens,
}
return { ...pools[idx], underlyings: tokens }
})

return unwrapPoolsAsUnderlyings(poolsWithUnderlyings)
Expand All @@ -177,16 +174,11 @@ const unwrapPoolsAsUnderlyings = (pools: Contract[]) => {

for (const pool of pools) {
const underlyings = pool.underlyings as Contract[]
if (!underlyings) {
continue
}
if (!underlyings) continue

const unwrappedUnderlyings = underlyings.map((address) => poolByAddress[address.toLowerCase()] || address)

unwrappedPools.push({
...pool,
underlyings: unwrappedUnderlyings,
})
unwrappedPools.push({ ...pool, underlyings: unwrappedUnderlyings })
}

return unwrappedPools
Expand All @@ -198,7 +190,7 @@ const getAuraExtraRewards = async (ctx: BaseContext, pools: Contract[]): Promise

const extraRewardsLengthRes = await multicall({
ctx,
calls: pools.map((pool) => ({ target: pool.gauge[0] }) as const),
calls: pools.map((pool) => ({ target: pool.gauge }) as const),
abi: abi.extraRewardsLength,
})

Expand Down Expand Up @@ -237,9 +229,7 @@ const getAuraExtraRewards = async (ctx: BaseContext, pools: Contract[]): Promise
extraRewardsPools.forEach((pool, idx) => {
const baseTokenRes: any = baseTokensRes[idx]

if (!baseTokenRes) {
return
}
if (!baseTokenRes) return

pool.rewards?.push(baseTokenRes.output)
})
Expand Down
Loading

0 comments on commit c2af21e

Please sign in to comment.