From 5f613afe94cee178af4979ccbc55aff1199c21f1 Mon Sep 17 00:00:00 2001 From: 0xPeluche <0xpeluche@proton.me> Date: Wed, 28 Feb 2024 11:57:44 +0100 Subject: [PATCH] fix, Uwu-lend --- src/adapters/uwu-lend/ethereum/index.ts | 8 +- src/adapters/uwu-lend/ethereum/lending.ts | 138 +++++++++++++++++++++ src/adapters/uwu-lend/ethereum/multifee.ts | 10 +- 3 files changed, 150 insertions(+), 6 deletions(-) create mode 100644 src/adapters/uwu-lend/ethereum/lending.ts diff --git a/src/adapters/uwu-lend/ethereum/index.ts b/src/adapters/uwu-lend/ethereum/index.ts index 2194521a7..7a25040eb 100644 --- a/src/adapters/uwu-lend/ethereum/index.ts +++ b/src/adapters/uwu-lend/ethereum/index.ts @@ -1,7 +1,7 @@ +import { getUWULendingPoolBalances, getUWULendingPoolContracts } from '@adapters/uwu-lend/ethereum/lending' import { getLendingPoolHealthFactor } from '@lib/aave/v2/lending' import type { AdapterConfig, BaseContext, Contract, GetBalancesHandler } from '@lib/adapter' import { resolveBalances } from '@lib/balance' -import { getLendingPoolBalances, getLendingPoolContracts } from '@lib/geist/lending' import { getMultiFeeDistributionContracts } from '@lib/geist/stake' import type { Token } from '@lib/token' @@ -25,7 +25,7 @@ const chefIncentivesControllerContract: Contract = { name: 'ChefIncentivesController', displayName: 'UwU incentives controller', chain: 'ethereum', - address: '0x21953192664867e19F85E96E1D1Dd79dc31cCcdB', + address: '0xDB5C23ae97f76dacC907f5F13bDa54131C8e9e5a', } const UwU: Token = { @@ -46,7 +46,7 @@ const UWU_WETH: Contract = { export const getContracts = async (ctx: BaseContext) => { const [pools, fmtMultiFeeDistributionContracts] = await Promise.all([ - getLendingPoolContracts(ctx, lendingPoolContract, chefIncentivesControllerContract, UwU), + getUWULendingPoolContracts(ctx, lendingPoolContract, chefIncentivesControllerContract, UwU), getMultiFeeDistributionContracts(ctx, multiFeeDistributionContract, UWU_WETH), ]) @@ -59,7 +59,7 @@ export const getContracts = async (ctx: BaseContext) => { export const getBalances: GetBalancesHandler = async (ctx, contracts) => { const [balances, healthFactor] = await Promise.all([ resolveBalances(ctx, contracts, { - pools: (...args) => getLendingPoolBalances(...args, chefIncentivesControllerContract), + pools: (...args) => getUWULendingPoolBalances(...args, chefIncentivesControllerContract), fmtMultiFeeDistributionContracts: (...args) => getUWUMultiFeeDistributionBalances(...args, { multiFeeDistribution: multiFeeDistributionContract, diff --git a/src/adapters/uwu-lend/ethereum/lending.ts b/src/adapters/uwu-lend/ethereum/lending.ts new file mode 100644 index 000000000..c21649d93 --- /dev/null +++ b/src/adapters/uwu-lend/ethereum/lending.ts @@ -0,0 +1,138 @@ +import { + getLendingPoolBalances as getAaveLendingPoolBalances, + getLendingPoolContracts as getAaveLendingPoolContracts, +} from '@lib/aave/v2/lending' +import type { Balance, BalancesContext, BaseContext, Contract } from '@lib/adapter' +import { keyBy, rangeBI } from '@lib/array' +import { call } from '@lib/call' +import { multicall } from '@lib/multicall' +import type { Token } from '@lib/token' + +const abi = { + registeredTokens: { + inputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + name: 'registeredTokens', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'view', + type: 'function', + }, + poolLength: { + inputs: [], + name: 'poolLength', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + claimableReward: { + inputs: [ + { internalType: 'address', name: '_user', type: 'address' }, + { internalType: 'address[]', name: '_tokens', type: 'address[]' }, + ], + name: 'claimableReward', + outputs: [{ internalType: 'uint256[]', name: '', type: 'uint256[]' }], + stateMutability: 'view', + type: 'function', + }, + userBaseClaimable: { + inputs: [{ internalType: 'address', name: '', type: 'address' }], + name: 'userBaseClaimable', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + mintedTokens: { + inputs: [], + name: 'mintedTokens', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, +} as const + +export interface GetLendingPoolContractsParams { + ctx: BaseContext + lendingPool: Contract + chefIncentivesController: Contract + rewardToken: Token +} + +/** + * Get AAVE LendingPool lending and borrowing contracts with rewards from ChefIncentives + */ + +export async function getUWULendingPoolContracts( + ctx: BaseContext, + lendingPool: Contract, + chefIncentivesController: Contract, + rewardToken: Token, +) { + const contracts: Contract[] = [] + const aaveLendingPoolContracts = await getAaveLendingPoolContracts(ctx, lendingPool) + const aaveLendingPoolContractsByAddress = keyBy(aaveLendingPoolContracts, 'address', { lowercase: false }) + const lmRewardsCount = await call({ ctx, target: chefIncentivesController.address, abi: abi.poolLength }) + + const registeredTokensRes = await multicall({ + ctx, + calls: rangeBI(0n, lmRewardsCount).map( + (idx) => ({ target: chefIncentivesController.address, params: [idx] }) as const, + ), + abi: abi.registeredTokens, + }) + + for (const registeredTokenRes of registeredTokensRes) { + if (!registeredTokenRes.success) { + continue + } + const contract = aaveLendingPoolContractsByAddress[registeredTokenRes.output] + if (contract) { + contracts.push({ ...contract, rewards: [rewardToken] }) + } + } + + return contracts +} + +export interface GetLendingPoolBalancesParams { + chefIncentivesController: Contract +} + +export async function getUWULendingPoolBalances( + ctx: BalancesContext, + contracts: Contract[], + chefIncentivesController: Contract, +) { + const balances: Balance[] = [] + const lendBalances = await getAaveLendingPoolBalances(ctx, contracts) + const balanceByAddress = keyBy(lendBalances, 'address', { lowercase: false }) + + const claimableRewards = await multicall({ + ctx, + // @ts-ignore + calls: contracts.map((contract) => ({ + target: chefIncentivesController.address, + params: [ctx.address, [contract.address]], + })), + abi: abi.claimableReward, + }) + + // Attach ChefIncentives rewards + for (let rewardIdx = 0; rewardIdx < claimableRewards.length; rewardIdx++) { + const claimableReward = claimableRewards[rewardIdx] + + if (!claimableReward.success) { + continue + } + + const balance = balanceByAddress[contracts[rewardIdx].address] + const reward = balance.rewards?.[0] as Contract + + if (balance && reward) { + balances.push({ + ...(balance as Balance), + rewards: [{ ...(reward as Contract), amount: claimableReward.output[0] }], + }) + } + } + + return balances +} diff --git a/src/adapters/uwu-lend/ethereum/multifee.ts b/src/adapters/uwu-lend/ethereum/multifee.ts index f90e4add5..9643d6e46 100644 --- a/src/adapters/uwu-lend/ethereum/multifee.ts +++ b/src/adapters/uwu-lend/ethereum/multifee.ts @@ -1,7 +1,6 @@ import type { Balance, BalancesContext, Contract, RewardBalance } from '@lib/adapter' import { keyBy } from '@lib/array' import { call } from '@lib/call' -import { abi as erc20Abi } from '@lib/erc20' import { multicall } from '@lib/multicall' import type { Token } from '@lib/token' import { getUnderlyingBalances } from '@lib/uniswap/v2/pair' @@ -90,6 +89,13 @@ const abi = { stateMutability: 'view', type: 'function', }, + totalLockedSupply: { + inputs: [], + name: 'totalLockedSupply', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, } as const export interface GetMultiFeeDistributionBalancesParams { @@ -137,7 +143,7 @@ export async function getUWUMultiFeeDistributionBalances( call({ ctx, target: params.multiFeeDistribution.address, params: [ctx.address], abi: abi.claimableRewards }), call({ ctx, target: params.multiFeeDistribution.address, params: [ctx.address], abi: abi.lockedBalances }), call({ ctx, target: params.multiFeeDistribution.address, params: [ctx.address], abi: abi.earnedBalances }), - call({ ctx, target: params.multiFeeDistribution.address, abi: erc20Abi.totalSupply }), + call({ ctx, target: params.multiFeeDistribution.address, abi: abi.totalLockedSupply }), multicall({ ctx, calls: rewards.map((token) => ({ target: contract.address, params: [token.address] }) as const),