Skip to content

Commit

Permalink
feat: add flash mint hyeth quote provider
Browse files Browse the repository at this point in the history
  • Loading branch information
janndriessen committed Jun 7, 2024
1 parent 99744f0 commit 32f1ff8
Show file tree
Hide file tree
Showing 6 changed files with 240 additions and 38 deletions.
9 changes: 7 additions & 2 deletions src/quote/flashmint/hyeth/component-quotes/across.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Contract } from '@ethersproject/contracts'

import { WETH } from 'constants/tokens'
import { SwapQuoteProvider } from 'quote/swap'
import { isSameAddress } from 'utils/addresses'
import { getRpcProvider } from 'utils/rpc-provider'

export class AcrossQuoteProvider {
Expand All @@ -29,17 +30,19 @@ export class AcrossQuoteProvider {
acrossLpAmount: bigint,
inputToken: string
): Promise<bigint | null> {
const outputToken = this.weth
const pool = this.getPoolContract()
const exchangeRate: BigNumber = await pool.callStatic.exchangeRateCurrent(
this.weth
)
const ethAmount =
(exchangeRate.toBigInt() * acrossLpAmount) / BigInt(1e18) +
this.roundingError
if (isSameAddress(inputToken, outputToken)) return ethAmount
const quote = await this.swapQuoteProvider.getSwapQuote({
chainId: 1,
inputToken,
outputToken: this.weth,
outputToken,
outputAmount: ethAmount.toString(),
})
if (!quote) return null
Expand All @@ -50,16 +53,18 @@ export class AcrossQuoteProvider {
acrossLpAmount: bigint,
outputToken: string
): Promise<bigint | null> {
const inputToken = this.weth
const pool = this.getPoolContract()
const exchangeRate: BigNumber = await pool.callStatic.exchangeRateCurrent(
this.weth
)
const ethAmount =
(exchangeRate.toBigInt() * acrossLpAmount) / BigInt(1e18) +
this.roundingError
if (isSameAddress(inputToken, outputToken)) return ethAmount
const quote = await this.swapQuoteProvider.getSwapQuote({
chainId: 1,
inputToken: this.weth,
inputToken,
outputToken,
inputAmount: ethAmount.toString(),
})
Expand Down
162 changes: 162 additions & 0 deletions src/quote/flashmint/hyeth/component-quotes/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import { BigNumber } from '@ethersproject/bignumber'
import { Address, isAddressEqual } from 'viem'

import { SwapQuoteProvider } from 'quote/swap'

import { QuoteToken } from '../../../interfaces'

import { AcrossQuoteProvider } from './across'
import { InstadappQuoteProvider } from './instadapp'
import { PendleQuoteProvider } from './pendle'

interface ComponentQuotesResult {
componentQuotes: string[]
inputOutputTokenAmount: bigint
}

export class ComponentQuotesProvider {
constructor(
readonly chainId: number,
readonly slippage: number,
readonly wethAddress: string,
readonly rpcUrl: string,
readonly swapQuoteProvider: SwapQuoteProvider
) {}

isAcross(token: string) {
return isAddressEqual(
token as Address,
'0x28F77208728B0A45cAb24c4868334581Fe86F95B'
)
}

isInstdapp(token: string) {
return isAddressEqual(
token as Address,
'0xA0D3707c569ff8C87FA923d3823eC5D81c98Be78'
)
}

isPendle(token: string) {
const pendleTokens: Address[] = [
'0x1c085195437738d73d75DC64bC5A3E098b7f93b1',
'0x6ee2b5E19ECBa773a352E5B21415Dc419A700d1d',
'0xf7906F274c174A52d444175729E3fa98f9bde285',
]
return pendleTokens.some((pendleToken) =>
isAddressEqual(pendleToken, token as Address)
)
}

async getComponentQuotes(
components: string[],
positions: BigNumber[],
isMinting: boolean,
inputToken: QuoteToken,
outputToken: QuoteToken
): Promise<ComponentQuotesResult | null> {
if (components.length === 0 || positions.length === 0) return null
if (components.length !== positions.length) return null

const { swapQuoteProvider } = this

const inputTokenAddress = this.getTokenAddressOrWeth(inputToken)
const outputTokenAddress = this.getTokenAddressOrWeth(outputToken)

const quotePromises: Promise<bigint | null>[] = []

for (let i = 0; i < components.length; i += 1) {
const index = i
const component = components[index]
const amount = positions[index].toBigInt()

if (this.isAcross(component)) {
const acrossQuoteProvider = new AcrossQuoteProvider(
this.rpcUrl,
swapQuoteProvider
)
if (isMinting) {
const quotePromise = acrossQuoteProvider.getDepositQuote(
amount,
inputTokenAddress
)
quotePromises.push(quotePromise)
} else {
const quotePromise = acrossQuoteProvider.getWithdrawQuote(
amount,
outputTokenAddress
)
quotePromises.push(quotePromise)
}
}

if (this.isInstdapp(component)) {
const instadappProvider = new InstadappQuoteProvider(
this.rpcUrl,
swapQuoteProvider
)
if (isMinting) {
const quotePromise = instadappProvider.getMintQuote(
component,
amount,
inputTokenAddress
)
quotePromises.push(quotePromise)
} else {
const quotePromise = instadappProvider.getRedeemQuote(
component,
amount,
outputTokenAddress
)
quotePromises.push(quotePromise)
}
}

if (this.isPendle(component)) {
const pendleQuoteProvider = new PendleQuoteProvider(
this.rpcUrl,
swapQuoteProvider
)
if (isMinting) {
const quotePromise = pendleQuoteProvider.getDepositQuote(
component,
amount,
inputTokenAddress
)
quotePromises.push(quotePromise)
} else {
const quotePromise = pendleQuoteProvider.getWithdrawQuote(
component,
amount,
outputTokenAddress
)
quotePromises.push(quotePromise)
}
}
}
const resultsWithNull = await Promise.all(quotePromises)
const results: bigint[] = resultsWithNull.filter(
(e): e is Exclude<typeof e, null> => e !== null
)
if (results.length !== resultsWithNull.length) return null
// const componentQuotes = results.map((result) => result.callData)
const inputOutputTokenAmount = results
.map((result) => result)
.reduce((prevValue, currValue) => {
return currValue + prevValue
})
return {
componentQuotes: [],
inputOutputTokenAmount,
}
}

/**
* Returns the WETH address if token is ETH. Otherwise the token's address.
* @param token A token of type QuoteToken.
* @returns a token address as string
*/
getTokenAddressOrWeth(token: QuoteToken): string {
return token.symbol === 'ETH' ? this.wethAddress : token.address
}
}
9 changes: 7 additions & 2 deletions src/quote/flashmint/hyeth/component-quotes/pendle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import FLASHMINT_HYETH_ABI from 'constants/abis/FlashMintHyEth.json'
import { FlashMintHyEthAddress } from 'constants/contracts'
import { WETH } from 'constants/tokens'
import { SwapQuoteProvider } from 'quote/swap'
import { isSameAddress } from 'utils/addresses'
import { getRpcProvider } from 'utils/rpc-provider'

export class PendleQuoteProvider {
Expand Down Expand Up @@ -49,6 +50,7 @@ export class PendleQuoteProvider {
position: bigint,
inputToken: string
): Promise<bigint | null> {
const outputToken = this.weth
const fmHyEth = this.getFlashMintHyEth()
const market = await fmHyEth.pendleMarkets(component)
// const ptContract = this.getPtContract(component)
Expand All @@ -57,10 +59,11 @@ export class PendleQuoteProvider {
const routerContract = this.getRouterStatic(this.routerStaticMainnet)
const assetRate: BigNumber = await routerContract.getPtToAssetRate(market)
const ethAmount = (position * assetRate.toBigInt()) / BigInt(1e18)
if (isSameAddress(inputToken, outputToken)) return ethAmount
const quote = await this.swapQuoteProvider.getSwapQuote({
chainId: 1,
inputToken,
outputToken: this.weth,
outputToken,
outputAmount: ethAmount.toString(),
})
if (!quote) return null
Expand All @@ -72,14 +75,16 @@ export class PendleQuoteProvider {
position: bigint,
outputToken: string
): Promise<bigint | null> {
const inputToken = this.weth
const fmHyEth = this.getFlashMintHyEth()
const market = await fmHyEth.pendleMarkets(component)
const routerContract = this.getRouterStatic(this.routerStaticMainnet)
const assetRate: BigNumber = await routerContract.getPtToAssetRate(market)
const ethAmount = (position * assetRate.toBigInt()) / BigInt(1e18)
if (isSameAddress(inputToken, outputToken)) return ethAmount
const quote = await this.swapQuoteProvider.getSwapQuote({
chainId: 1,
inputToken: this.weth,
inputToken,
outputToken,
inputAmount: ethAmount.toString(),
})
Expand Down
27 changes: 21 additions & 6 deletions src/quote/flashmint/hyeth/provider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
import { FlashMintHyEthQuoteProvider } from './provider'

const rpcUrl = LocalhostProviderUrl
// const swapQuoteProvider = IndexZeroExSwapQuoteProvider
const swapQuoteProvider = IndexZeroExSwapQuoteProvider

const { eth, hyeth, usdc, weth } = QuoteTokens
const indexToken = hyeth
Expand All @@ -32,7 +32,10 @@ describe('FlashMintHyEthQuoteProvider()', () => {
indexTokenAmount: wei(1).toBigInt(),
slippage: 0.5,
}
const quoteProvider = new FlashMintHyEthQuoteProvider(rpcUrl)
const quoteProvider = new FlashMintHyEthQuoteProvider(
rpcUrl,
swapQuoteProvider
)
const quote = await quoteProvider.getQuote(request)
if (!quote) fail()
expect(quote.indexTokenAmount).toEqual(request.indexTokenAmount)
Expand Down Expand Up @@ -67,7 +70,10 @@ describe('FlashMintHyEthQuoteProvider()', () => {
indexTokenAmount: wei(1).toBigInt(),
slippage: 0.5,
}
const quoteProvider = new FlashMintHyEthQuoteProvider(rpcUrl)
const quoteProvider = new FlashMintHyEthQuoteProvider(
rpcUrl,
swapQuoteProvider
)
const quote = await quoteProvider.getQuote(request)
if (!quote) fail()
expect(quote.indexTokenAmount).toEqual(request.indexTokenAmount)
Expand Down Expand Up @@ -116,7 +122,10 @@ describe('FlashMintHyEthQuoteProvider()', () => {
indexTokenAmount: wei(1).toBigInt(),
slippage: 0.5,
}
const quoteProvider = new FlashMintHyEthQuoteProvider(rpcUrl)
const quoteProvider = new FlashMintHyEthQuoteProvider(
rpcUrl,
swapQuoteProvider
)
const quote = await quoteProvider.getQuote(request)
if (!quote) fail()
expect(quote.indexTokenAmount).toEqual(request.indexTokenAmount)
Expand Down Expand Up @@ -165,7 +174,10 @@ describe('FlashMintHyEthQuoteProvider()', () => {
indexTokenAmount: wei(1).toBigInt(),
slippage: 0.5,
}
const quoteProvider = new FlashMintHyEthQuoteProvider(rpcUrl)
const quoteProvider = new FlashMintHyEthQuoteProvider(
rpcUrl,
swapQuoteProvider
)
const quote = await quoteProvider.getQuote(request)
if (!quote) fail()
expect(quote.indexTokenAmount).toEqual(request.indexTokenAmount)
Expand Down Expand Up @@ -200,7 +212,10 @@ describe('FlashMintHyEthQuoteProvider()', () => {
indexTokenAmount: wei(1).toBigInt(),
slippage: 0.5,
}
const quoteProvider = new FlashMintHyEthQuoteProvider(rpcUrl)
const quoteProvider = new FlashMintHyEthQuoteProvider(
rpcUrl,
swapQuoteProvider
)
const quote = await quoteProvider.getQuote(request)
if (!quote) fail()
expect(quote.indexTokenAmount).toEqual(request.indexTokenAmount)
Expand Down
Loading

0 comments on commit 32f1ff8

Please sign in to comment.