Skip to content

Commit

Permalink
add flash mint nav quote provider
Browse files Browse the repository at this point in the history
  • Loading branch information
janndriessen committed Oct 23, 2024
1 parent b050b0c commit ef578a4
Show file tree
Hide file tree
Showing 3 changed files with 234 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/quote/flashmint/nav/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './provider'
116 changes: 116 additions & 0 deletions src/quote/flashmint/nav/provider.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { AddressZero } from 'constants/addresses'
import {
IndexZeroExSwapQuoteProvider,
LocalhostProviderUrl,
QuoteTokens,
} from 'tests/utils'
import { wei } from 'utils/numbers'
import { FlashMintNavQuoteRequest, FlashMintNavQuoteProvider } from './provider'
import { Exchange } from 'utils'

describe('FlashMintNavQuoteProvider()', () => {
const { icusd, usdc, weth } = QuoteTokens
const indexToken = icusd
const chainId = 1
const provider = LocalhostProviderUrl
const swapQuoteProvider = IndexZeroExSwapQuoteProvider

test('returns a quote for minting icUSD', async () => {
const inputToken = usdc
const request: FlashMintNavQuoteRequest = {
chainId,
isMinting: true,
inputToken,
outputToken: indexToken,
inputTokenAmount: wei(10, 6),
slippage: 0.5,
}
const quoteProvider = new FlashMintNavQuoteProvider(
provider,
swapQuoteProvider
)
const quote = await quoteProvider.getQuote(request)
if (!quote) fail()
expect(quote.inputTokenAmount).toEqual(request.inputTokenAmount)
expect(quote.outputTokenAmount.gt(0)).toEqual(true)
expect(quote.reserveAssetSwapData).toEqual({
exchange: Exchange.None,
fees: [],
path: [],
poolIds: [],
pool: AddressZero,
})
})

test('returns a quote for minting icUSD w/ WETH', async () => {
const inputToken = weth
const request: FlashMintNavQuoteRequest = {
chainId,
isMinting: true,
inputToken,
outputToken: indexToken,
inputTokenAmount: wei(1),
slippage: 0.5,
}
const quoteProvider = new FlashMintNavQuoteProvider(
provider,
swapQuoteProvider
)
const quote = await quoteProvider.getQuote(request)
if (!quote) fail()
expect(quote.inputTokenAmount).toEqual(request.inputTokenAmount)
expect(quote.outputTokenAmount.gt(0)).toEqual(true)
// TODO:
expect(quote.reserveAssetSwapData).toBeDefined()
})

test('returns a quote redeeming icUSD for USDC', async () => {
const outputToken = usdc
const request: FlashMintNavQuoteRequest = {
chainId,
isMinting: false,
inputToken: indexToken,
outputToken,
inputTokenAmount: wei(1),
slippage: 0.5,
}
const quoteProvider = new FlashMintNavQuoteProvider(
provider,
swapQuoteProvider
)
const quote = await quoteProvider.getQuote(request)
if (!quote) fail()
expect(quote.inputTokenAmount).toEqual(request.inputTokenAmount)
expect(quote.outputTokenAmount.gt(0)).toEqual(true)
expect(quote.reserveAssetSwapData).toEqual({
exchange: Exchange.None,
fees: [],
path: [],
poolIds: [],
pool: AddressZero,
})
})

// TODO:
test.skip('returns a quote for redeeming icUSD for WETH', async () => {
const outputToken = weth
const request: FlashMintNavQuoteRequest = {
chainId,
isMinting: false,
inputToken: indexToken,
outputToken,
inputTokenAmount: wei(1),
slippage: 0.5,
}
const quoteProvider = new FlashMintNavQuoteProvider(
provider,
swapQuoteProvider
)
const quote = await quoteProvider.getQuote(request)
if (!quote) fail()
expect(quote.inputTokenAmount).toEqual(request.inputTokenAmount)
expect(quote.outputTokenAmount.gt(0)).toEqual(true)
// TODO:
expect(quote.reserveAssetSwapData).toBeDefined()
})
})
117 changes: 117 additions & 0 deletions src/quote/flashmint/nav/provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { BigNumber } from '@ethersproject/bignumber'

import { AddressZero } from 'constants/addresses'
import { USDC } from 'constants/tokens'
import { SwapQuoteProvider } from 'quote/swap'
import {
Exchange,
getFlashMintNavContract,
isSameAddress,
slippageAdjustedTokenAmount,
SwapDataV3,
} from 'utils'
import { getRpcProvider } from 'utils/rpc-provider'

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

export interface FlashMintNavQuoteRequest {
chainId: number
isMinting: boolean
inputToken: QuoteToken
outputToken: QuoteToken
// In contrast to other quote providers, we always need the input amount (not the index amount)
inputTokenAmount: BigNumber
slippage: number
}

export interface FlashMintNavQuoteQuote {
inputTokenAmount: BigNumber
outputTokenAmount: BigNumber
reserveAssetSwapData: SwapDataV3
}

export class FlashMintNavQuoteProvider
implements QuoteProvider<FlashMintNavQuoteRequest, FlashMintNavQuoteQuote>
{
constructor(
private readonly rpcUrl: string,
private readonly swapQuoteProvider: SwapQuoteProvider
) {}

async getQuote(
request: FlashMintNavQuoteRequest
): Promise<FlashMintNavQuoteQuote | null> {
const {
chainId,
inputToken,
inputTokenAmount,
isMinting,
outputToken,
slippage,
} = request

const indexToken = isMinting ? outputToken : inputToken
const usdc = USDC.address!

Check warning on line 54 in src/quote/flashmint/nav/provider.ts

View workflow job for this annotation

GitHub Actions / build

Forbidden non-null assertion

const swapQuoteRequest = {
chainId,
inputToken: isMinting ? inputToken.address : usdc,
outputToken: isMinting ? usdc : outputToken.address,
// TODO:
inputAmount: inputTokenAmount.toString(),
// TODO:
// sources: [Exchange.UniV3],
slippage,
}
console.log(swapQuoteRequest)

let reserveAssetSwapData: SwapDataV3 = {
exchange: Exchange.None,
fees: [],
path: [],
poolIds: [],
pool: AddressZero,
}
if (
!isSameAddress(swapQuoteRequest.inputToken, swapQuoteRequest.outputToken)
) {
const res = await this.swapQuoteProvider.getSwapQuote(swapQuoteRequest)
console.log(res)
if (!res?.swapData) return null
reserveAssetSwapData = {
...res.swapData,
poolIds: [],
}
}

let estimatedInputOutputAmount: BigNumber = BigNumber.from(0)
const provider = getRpcProvider(this.rpcUrl)
const contract = getFlashMintNavContract(provider)
if (isMinting) {
estimatedInputOutputAmount = await contract.callStatic.getIssueAmount(
indexToken.address,
inputToken.address,
inputTokenAmount,
reserveAssetSwapData
)
} else {
estimatedInputOutputAmount = await contract.callStatic.getRedeemAmountOut(
indexToken.address,
inputTokenAmount,
outputToken.address,
reserveAssetSwapData
)
}
const outputTokenAmount = slippageAdjustedTokenAmount(
estimatedInputOutputAmount,
isMinting ? outputToken.decimals : inputToken.decimals,
slippage,
isMinting
)
return {
inputTokenAmount,
outputTokenAmount,
reserveAssetSwapData,
}
}
}

0 comments on commit ef578a4

Please sign in to comment.