Skip to content

Commit

Permalink
Spark Borrow Incremental (#448)
Browse files Browse the repository at this point in the history
* feat: WIP spark protocol data

* feat: implement spark protocol data layer

* feat: finish implementing spark view layer

* feat: fix op resolver and implement aave-like payback-withdraw

* fix: aave strategy exports

* feat: add payback-withdraw strategy into aave/spark

* chore: fix linting issues
  • Loading branch information
zerotucks authored Aug 29, 2023
1 parent f293a45 commit b7e5e1d
Show file tree
Hide file tree
Showing 31 changed files with 549 additions and 246 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { AaveBorrowOperations, AaveMultiplyOperations, operations } from '@dma-library/operations'
import { SparkBorrowOperations } from '@dma-library/operations/spark'
import { PositionType } from '@dma-library/types'
import { AaveLikeProtocol } from '@dma-library/types/protocol'

Expand Down Expand Up @@ -43,7 +44,7 @@ export function isAaveOperation(op: any): op is AaveBorrowOperations | AaveMulti
export function resolveAaveLikeOperations(
protocolType: AaveLikeProtocol,
positionType: PositionType,
) {
): SparkBorrowOperations | AaveBorrowOperations['v2'] | AaveBorrowOperations['v3'] {
const { protocol, type, version } = resolveProtocolKeyConfig(protocolType, positionType)

if (protocol === 'aave' && !version) {
Expand Down
2 changes: 1 addition & 1 deletion packages/dma-library/src/operations/spark/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const multiply = {
adjustRiskUp: {},
}

type SparkBorrowOperations = {
export type SparkBorrowOperations = {
borrow: SparkBorrowOperation
deposit: SparkDepositOperation
depositBorrow: SparkDepositBorrowOperation
Expand Down
4 changes: 4 additions & 0 deletions packages/dma-library/src/protocols/aave-like/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import BigNumber from 'bignumber.js'

export type PriceResult = BigNumber | undefined
export type ReserveDataResult = any
73 changes: 73 additions & 0 deletions packages/dma-library/src/protocols/aave-like/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { Address } from '@deploy-configurations/types/address'
import { AaveLikeProtocol as AaveLikeProtocolContracts } from '@deploy-configurations/types/deployment-config'
import { amountFromWei } from '@dma-common/utils/common'
import { AaveLikeStrategyAddresses } from '@dma-library/operations/aave-like'
import { PriceResult, ReserveDataResult } from '@dma-library/protocols/aave-like/types'
import { AaveLikeProtocol } from '@dma-library/types/protocol'
import { getAbiForContract } from '@dma-library/utils/abis/get-abi-for-contract'
import BigNumber from 'bignumber.js'
import { Contract, ethers, providers } from 'ethers'

export function determineReserveEModeCategory(
collateralEModeCategoryResult: number,
debtEModeCategoryResult: number,
): number {
const collateralEModeCategory = Number(collateralEModeCategoryResult.toString())
const debtEModeCategory = Number(debtEModeCategoryResult.toString())

if (collateralEModeCategory === debtEModeCategory) {
return collateralEModeCategory
}
return 0
}

export async function getContract(
address: Address,
contractName: AaveLikeProtocolContracts,
provider: providers.Provider,
protocol: AaveLikeProtocol,
): Promise<Contract> {
const abi = await getAbiForContract(contractName, provider, protocol)
return new ethers.Contract(address, abi, provider)
}

export async function fetchAssetPrice(
priceOracle: Contract,
tokenAddress?: string,
): Promise<PriceResult> {
if (!tokenAddress) return undefined
const amount: ethers.BigNumberish = await priceOracle.getAssetPrice(tokenAddress)
return amountFromWei(new BigNumber(amount.toString()))
}

export async function fetchReserveData(
dataProvider: Contract,
tokenAddress?: string,
): Promise<ReserveDataResult> {
if (!tokenAddress) return undefined
return dataProvider.getReserveConfigurationData(tokenAddress)
}

export async function fetchUserReserveData(
dataProvider: Contract,
tokenAddress: string,
proxy: string,
): Promise<ReserveDataResult> {
return dataProvider.getUserReserveData(tokenAddress, proxy)
}

export async function getAaveLikeSystemContracts(
addresses: AaveLikeStrategyAddresses,
provider: providers.Provider,
protocol: AaveLikeProtocol,
) {
const oracle = await getContract(addresses.oracle, 'Oracle', provider, protocol)
const poolDataProvider = await getContract(
addresses.poolDataProvider,
'PoolDataProvider',
provider,
protocol,
)
const pool = await getContract(addresses.lendingPool, 'LendingPool', provider, protocol)
return { oracle, poolDataProvider, pool }
}
127 changes: 40 additions & 87 deletions packages/dma-library/src/protocols/aave/get-aave-protocol-data.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
// V2 ABIs
import { Address } from '@deploy-configurations/types/address'
import { AaveLikeProtocol } from '@deploy-configurations/types/deployment-config'
// V3 ABIs
// V3 L2 ABIs
import { amountFromWei } from '@dma-common/utils/common'
import { AaveLikeStrategyAddresses } from '@dma-library/operations/aave-like'
import { PriceResult, ReserveDataResult } from '@dma-library/protocols/aave-like/types'
import {
determineReserveEModeCategory,
fetchAssetPrice,
fetchReserveData,
fetchUserReserveData,
getAaveLikeSystemContracts,
} from '@dma-library/protocols/aave-like/utils'
import * as AaveCommon from '@dma-library/strategies/aave/common'
import { Protocol } from '@dma-library/types'
import { AaveVersion } from '@dma-library/types/aave'
import { getAbiForContract } from '@dma-library/utils/abis/get-abi-for-contract'
import BigNumber from 'bignumber.js'
import { ethers, providers } from 'ethers'
import { providers } from 'ethers'

type InternalAaveProtocolData = {
type SharedAaveProtocolDataArgs = {
collateralTokenAddress: string
debtTokenAddress: string
addresses: AaveLikeStrategyAddresses
Expand All @@ -22,14 +21,28 @@ type InternalAaveProtocolData = {
}

export type AaveProtocolDataArgs =
| (InternalAaveProtocolData & { protocolVersion: AaveVersion.v2 })
| (InternalAaveProtocolData & { protocolVersion: AaveVersion.v3 })
| (SharedAaveProtocolDataArgs & { protocolVersion: AaveVersion.v2 })
| (SharedAaveProtocolDataArgs & { protocolVersion: AaveVersion.v3 })

export type AaveProtocolData = {
aaveFlashloanAssetPriceInEth: PriceResult
aaveDebtTokenPriceInEth: PriceResult
aaveCollateralTokenPriceInEth: PriceResult
reserveDataForFlashloan: ReserveDataResult
reserveDataForCollateral: ReserveDataResult
reserveEModeCategory: number | undefined
userReserveDataForDebtToken: any
userReserveDataForCollateral: any
eModeCategoryData: any | undefined
}

export type GetAaveProtocolData = (args: AaveProtocolDataArgs) => Promise<AaveProtocolData>

export const getAaveProtocolData = async (args: AaveProtocolDataArgs) => {
export const getAaveProtocolData: GetAaveProtocolData = async args => {
if (
AaveCommon.isV2<
AaveProtocolDataArgs,
InternalAaveProtocolData & { protocolVersion: AaveVersion.v2 }
SharedAaveProtocolDataArgs & { protocolVersion: AaveVersion.v2 }
>(args)
) {
return getAaveV2ProtocolData(args)
Expand All @@ -41,24 +54,15 @@ export const getAaveProtocolData = async (args: AaveProtocolDataArgs) => {
throw new Error('Invalid Aave version')
}

type PriceResult = BigNumber | undefined
type ReserveDataResult = any

async function getAaveV2ProtocolData({
addresses,
provider,
debtTokenAddress,
collateralTokenAddress,
flashloanTokenAddress,
proxy,
}: InternalAaveProtocolData & { protocolVersion: AaveVersion.v2 }) {
const oracle = await getContract(addresses.oracle, 'Oracle', provider, 'AAVE')
const poolDataProvider = await getContract(
addresses.poolDataProvider,
'PoolDataProvider',
provider,
'AAVE',
)
}: SharedAaveProtocolDataArgs & { protocolVersion: AaveVersion.v2 }) {
const { oracle, poolDataProvider } = await getAaveLikeSystemContracts(addresses, provider, 'AAVE')

const [
flashloanPrice,
Expand Down Expand Up @@ -98,17 +102,12 @@ async function getAaveV3ProtocolData({
collateralTokenAddress,
flashloanTokenAddress,
proxy,
}: InternalAaveProtocolData & { protocolVersion: AaveVersion.v3 }) {
const oracle = await getContract(addresses.oracle, 'Oracle', provider, 'AAVE_V3')
const poolDataProvider = await getContract(
addresses.poolDataProvider,
'PoolDataProvider',
}: SharedAaveProtocolDataArgs & { protocolVersion: AaveVersion.v3 }) {
const { oracle, poolDataProvider, pool } = await getAaveLikeSystemContracts(
addresses,
provider,
'AAVE_V3',
)
const pool = await getContract(addresses.lendingPool, 'LendingPool', provider, 'AAVE_V3')

const hasProxy = !!proxy

const [
flashloanPrice,
Expand All @@ -126,15 +125,15 @@ async function getAaveV3ProtocolData({
fetchAssetPrice(oracle, collateralTokenAddress),
fetchReserveData(poolDataProvider, flashloanTokenAddress),
fetchReserveData(poolDataProvider, collateralTokenAddress),
hasProxy ? fetchUserReserveData(poolDataProvider, debtTokenAddress, proxy) : undefined,
hasProxy ? fetchUserReserveData(poolDataProvider, collateralTokenAddress, proxy) : undefined,
poolDataProvider.getReserveEModeCategory(collateralTokenAddress),
poolDataProvider.getReserveEModeCategory(debtTokenAddress),
proxy ? fetchUserReserveData(poolDataProvider, debtTokenAddress, proxy) : undefined,
proxy ? fetchUserReserveData(poolDataProvider, collateralTokenAddress, proxy) : undefined,
Number(poolDataProvider.getReserveEModeCategory(collateralTokenAddress).toString()),
Number(poolDataProvider.getReserveEModeCategory(debtTokenAddress).toString()),
])

const reserveEModeCategory = await determineReserveEModeCategory(
[collateralEModeCategory, debtEModeCategory],
hasProxy,
const reserveEModeCategory = determineReserveEModeCategory(
collateralEModeCategory,
debtEModeCategory,
)

let eModeCategoryData
Expand All @@ -154,49 +153,3 @@ async function getAaveV3ProtocolData({
eModeCategoryData: eModeCategoryData,
}
}
async function determineReserveEModeCategory(
collateralEModeCategoryResult: any,
debtEModeCategoryResult: any,
): Promise<number | undefined> {
const collateralEModeCategory = Number(collateralEModeCategoryResult.toString())
const debtEModeCategory = Number(debtEModeCategoryResult.toString())

if (collateralEModeCategory === debtEModeCategory) {
return collateralEModeCategory
}
return 0
}

async function getContract(
address: Address,
contractName: AaveLikeProtocol,
provider: any,
protocol: Protocol,
) {
const abi = await getAbiForContract(contractName, provider, protocol)
return new ethers.Contract(address, abi, provider)
}

async function fetchAssetPrice(priceOracle: any, tokenAddress?: string): Promise<PriceResult> {
if (!tokenAddress) return undefined
const amount: ethers.BigNumberish = await priceOracle.getAssetPrice(tokenAddress)
return amountFromWei(new BigNumber(amount.toString()))
}

async function fetchReserveData(
dataProvider: any,
tokenAddress?: string,
): Promise<ReserveDataResult> {
if (!tokenAddress) return undefined
return dataProvider.getReserveConfigurationData(tokenAddress)
}

async function fetchUserReserveData(
dataProvider: any,
tokenAddress: string,
proxy: string,
): Promise<ReserveDataResult> {
return dataProvider.getUserReserveData(tokenAddress, proxy)
}

export type AaveProtocolData = ReturnType<typeof getAaveProtocolData>
1 change: 1 addition & 0 deletions packages/dma-library/src/protocols/aave/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export {
AaveProtocolData,
AaveProtocolDataArgs,
GetAaveProtocolData,
getAaveProtocolData,
} from './get-aave-protocol-data'
26 changes: 23 additions & 3 deletions packages/dma-library/src/protocols/index.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,36 @@
import { AaveProtocolData, AaveProtocolDataArgs, getAaveProtocolData } from './aave'
import {
AaveProtocolData,
AaveProtocolDataArgs,
GetAaveProtocolData,
getAaveProtocolData,
} from './aave'
import { calculateAjnaApyPerDays } from './ajna'
import {
GetSparkProtocolData,
getSparkProtocolData,
SparkProtocolData,
SparkProtocolDataArgs,
} from './spark'

const aave: {
getAaveProtocolData: typeof getAaveProtocolData
getAaveProtocolData: GetAaveProtocolData
} = {
getAaveProtocolData,
}

export { AaveProtocolData, AaveProtocolDataArgs }
const spark: {
getSparkProtocolData: GetSparkProtocolData
} = {
getSparkProtocolData,
}

export const protocols = {
aave,
spark,
}

export { AaveProtocolData, AaveProtocolDataArgs }
export { SparkProtocolData, SparkProtocolDataArgs }

export { calculateAjnaApyPerDays }
export { calculateAjnaMaxLiquidityWithdraw, getAjnaLiquidationPrice } from './ajna/index'
Loading

0 comments on commit b7e5e1d

Please sign in to comment.