forked from Zapper-fi/studio
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(mean-finance): Use lodash to refactor positions and remove call …
…to pairs (Zapper-fi#937)
- Loading branch information
1 parent
0af15de
commit 016c187
Showing
5 changed files
with
110 additions
and
234 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
145 changes: 55 additions & 90 deletions
145
src/apps/mean-finance/optimism/mean-finance.dca-position.contract-position-fetcher.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,140 +1,105 @@ | ||
import { Inject } from '@nestjs/common'; | ||
import { BigNumber } from 'ethers'; | ||
import { sumBy, keyBy } from 'lodash'; | ||
import { compact, groupBy, sumBy, values } from 'lodash'; | ||
|
||
import { IAppToolkit, APP_TOOLKIT } from '~app-toolkit/app-toolkit.interface'; | ||
import { Register } from '~app-toolkit/decorators'; | ||
import { drillBalance } from '~app-toolkit/helpers/balance/token-balance.helper'; | ||
import { getImagesFromToken } from '~app-toolkit/helpers/presentation/image.present'; | ||
import { getImagesFromToken, getLabelFromToken } from '~app-toolkit/helpers/presentation/image.present'; | ||
import { ContractType } from '~position/contract.interface'; | ||
import { WithMetaType } from '~position/display.interface'; | ||
import { BaseTokenBalance } from '~position/position-balance.interface'; | ||
import { PositionFetcher } from '~position/position-fetcher.interface'; | ||
import { ContractPosition } from '~position/position.interface'; | ||
import { BaseToken } from '~position/token.interface'; | ||
import { claimable, supplied } from '~position/position.utils'; | ||
import { Network } from '~types/network.interface'; | ||
|
||
import { getPairs, getPositions } from '../helpers/graph'; | ||
import { sortTokens } from '../helpers/tokens'; | ||
import { getPositions } from '../helpers/graph'; | ||
import { MEAN_FINANCE_DEFINITION } from '../mean-finance.definition'; | ||
|
||
const appId = MEAN_FINANCE_DEFINITION.id; | ||
const groupId = MEAN_FINANCE_DEFINITION.groups.dcaPosition.id; | ||
const network = Network.OPTIMISM_MAINNET; | ||
|
||
interface ExtendedContractPosition extends ContractPosition { | ||
tokenA?: BaseToken; | ||
tokenB?: BaseToken; | ||
tokenALiquidity: BigNumber; | ||
tokenBLiquidity: BigNumber; | ||
positions: number; | ||
id: string; | ||
} | ||
type MeanFinanceDcaPositionContractPositionDataProps = { | ||
liquidity: number; | ||
from: string; | ||
to: string; | ||
}; | ||
|
||
@Register.ContractPositionFetcher({ appId, groupId, network }) | ||
export class OptimismMeanFinanceDcaPositionContractPositionFetcher implements PositionFetcher<ContractPosition> { | ||
constructor(@Inject(APP_TOOLKIT) private readonly appToolkit: IAppToolkit) { } | ||
constructor(@Inject(APP_TOOLKIT) private readonly appToolkit: IAppToolkit) {} | ||
|
||
async getPositions() { | ||
const dcaHubAddress = '0x059d306a25c4ce8d7437d25743a8b94520536bd5'; | ||
const graphHelper = this.appToolkit.helpers.theGraphHelper; | ||
const positionsData = await getPositions(network, graphHelper); | ||
const pairsData = await getPairs(network, graphHelper); | ||
const baseTokens = await this.appToolkit.getBaseTokenPrices(network); | ||
const pairs = pairsData.pairs; | ||
const positions = positionsData.positions; | ||
const dcaHubAddress = '0x059d306a25c4ce8d7437d25743a8b94520536bd5'; | ||
|
||
const contractPositionsByKey: Record<string, ExtendedContractPosition> = keyBy(pairs.map(pair => { | ||
const tokenA = baseTokens.find(v => v.address === pair.tokenA.address); | ||
const tokenB = baseTokens.find(v => v.address === pair.tokenB.address); | ||
|
||
let images: string[] = []; | ||
|
||
if (tokenA) { | ||
tokenA.network = network; | ||
images = [...images, ...getImagesFromToken(tokenA)]; | ||
} | ||
if (tokenB) { | ||
tokenB.network = network; | ||
images = [...images, ...getImagesFromToken(tokenB)]; | ||
} | ||
const position: ExtendedContractPosition = { | ||
const maybePositions = positions.map(dcaPosition => { | ||
const from = baseTokens.find(v => v.address === dcaPosition.from.address.toLowerCase()); | ||
const to = baseTokens.find(v => v.address === dcaPosition.to.address.toLowerCase()); | ||
if (!from || !to) return null; | ||
|
||
const tokens = [supplied(from), claimable(to)]; | ||
const liquidityToSwapRaw = dcaPosition.current.remainingLiquidity; | ||
const liquidityToWithdrawRaw = dcaPosition.current.idleSwapped; | ||
const liquidityToSwap = (Number(liquidityToSwapRaw) / 10 ** from.decimals) * from.price; | ||
const liquidityToWithdraw = (Number(liquidityToWithdrawRaw) / 10 ** to.decimals) * to.price; | ||
const liquidity = liquidityToSwap + liquidityToWithdraw; | ||
|
||
const label = `${getLabelFromToken(from)} to ${getLabelFromToken(to)}`; | ||
const images = [...getImagesFromToken(from), ...getImagesFromToken(to)]; | ||
|
||
const position: ContractPosition<MeanFinanceDcaPositionContractPositionDataProps> = { | ||
type: ContractType.POSITION, | ||
address: dcaHubAddress, | ||
appId, | ||
groupId, | ||
appId: MEAN_FINANCE_DEFINITION.id, | ||
groupId: MEAN_FINANCE_DEFINITION.groups.dcaPosition.id, | ||
network, | ||
tokens: [], | ||
id: pair.id, | ||
tokenA, | ||
tokenB, | ||
tokenALiquidity: BigNumber.from('0'), | ||
tokenBLiquidity: BigNumber.from('0'), | ||
positions: 0, | ||
tokens, | ||
dataProps: { | ||
id: pair.id, | ||
from: from.address, | ||
to: to.address, | ||
liquidity, | ||
}, | ||
displayProps: { | ||
label: `${pair.tokenA.symbol}:${pair.tokenB.symbol} pair`, | ||
label, | ||
images, | ||
}, | ||
}; | ||
|
||
position.key = this.appToolkit.getPositionKey(position, ['id']); | ||
return position; | ||
}), 'id'); | ||
|
||
positions.forEach(dcaPosition => { | ||
const [tokenAAddress, tokenBAddress] = sortTokens(dcaPosition.from.address, dcaPosition.to.address); | ||
|
||
const toWithdraw = dcaPosition.current.idleSwapped; | ||
const remainingLiquidity = dcaPosition.current.remainingLiquidity; | ||
|
||
contractPositionsByKey[`${tokenAAddress}-${tokenBAddress}`].positions += 1; | ||
|
||
if (dcaPosition.from.address === tokenAAddress) { | ||
contractPositionsByKey[`${tokenAAddress}-${tokenBAddress}`].tokenALiquidity = contractPositionsByKey[`${tokenAAddress}-${tokenBAddress}`].tokenALiquidity.add(BigNumber.from(remainingLiquidity)); | ||
} else { | ||
contractPositionsByKey[`${tokenAAddress}-${tokenBAddress}`].tokenBLiquidity = contractPositionsByKey[`${tokenAAddress}-${tokenBAddress}`].tokenBLiquidity.add(BigNumber.from(remainingLiquidity)); | ||
} | ||
if (dcaPosition.to.address === tokenAAddress) { | ||
contractPositionsByKey[`${tokenAAddress}-${tokenBAddress}`].tokenALiquidity = contractPositionsByKey[`${tokenAAddress}-${tokenBAddress}`].tokenALiquidity.add(BigNumber.from(toWithdraw)); | ||
} else { | ||
contractPositionsByKey[`${tokenAAddress}-${tokenBAddress}`].tokenBLiquidity = contractPositionsByKey[`${tokenAAddress}-${tokenBAddress}`].tokenBLiquidity.add(BigNumber.from(toWithdraw)); | ||
} | ||
}); | ||
|
||
const contractPositions: ContractPosition[] = Object.values(contractPositionsByKey).map(position => { | ||
const tokens: WithMetaType<BaseTokenBalance>[] = []; | ||
|
||
if (position.tokenA) { | ||
tokens.push(drillBalance(position.tokenA, position.tokenALiquidity.toString())); | ||
} | ||
if (position.tokenB) { | ||
tokens.push(drillBalance(position.tokenB, position.tokenBLiquidity.toString())); | ||
} | ||
const allPositions = compact(maybePositions); | ||
const groupedPositionsRecord = groupBy(allPositions, v => `${v.dataProps.from}:${v.dataProps.to}`); | ||
const groupedPositions = values(groupedPositionsRecord); | ||
|
||
const balanceUSD = sumBy(tokens, t => t.balanceUSD); | ||
const mergedPositions = groupedPositions.map(positionsForDirectionalPair => { | ||
const totalLiquidity = sumBy(positionsForDirectionalPair, v => v.dataProps.liquidity); | ||
|
||
return { | ||
const anyPosition = positionsForDirectionalPair[0]; | ||
const mergedPosition: ContractPosition<MeanFinanceDcaPositionContractPositionDataProps> = { | ||
type: ContractType.POSITION, | ||
address: dcaHubAddress, | ||
appId, | ||
groupId, | ||
appId: MEAN_FINANCE_DEFINITION.id, | ||
groupId: MEAN_FINANCE_DEFINITION.groups.dcaPosition.id, | ||
network, | ||
tokens, | ||
tokens: anyPosition.tokens, | ||
dataProps: { | ||
id: position.dataProps.id, | ||
liquidity: balanceUSD, | ||
tokenALiquidity: position.tokenALiquidity.toString(), | ||
tokenBLiquidity: position.tokenBLiquidity.toString(), | ||
from: anyPosition.dataProps.from, | ||
to: anyPosition.dataProps.to, | ||
liquidity: totalLiquidity, | ||
}, | ||
displayProps: { | ||
...position.displayProps, | ||
secondaryLabel: `${position.positions} active positions` | ||
label: anyPosition.displayProps.label, | ||
secondaryLabel: `${positionsForDirectionalPair.length} active positions`, | ||
images: anyPosition.displayProps.images, | ||
}, | ||
} | ||
}; | ||
|
||
return mergedPosition; | ||
}); | ||
|
||
return contractPositions; | ||
return mergedPositions; | ||
} | ||
} |
Oops, something went wrong.