Skip to content

Commit

Permalink
Merge pull request #7 from morpho-labs/feat/morpho-optimizers
Browse files Browse the repository at this point in the history
Feat/morpho optimizers
  • Loading branch information
tomrpl authored Jan 17, 2024
2 parents ca2f95c + 1a0bd68 commit 0ebb15a
Show file tree
Hide file tree
Showing 12 changed files with 136 additions and 801 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@
"dotenv": "^16.3.1",
"ethers": "^6.7.1",
"evm-maths": "^6.0.0",
"pino": "^8.15.0"
"pino": "^8.15.0",
"zod": "^3.22.4"
}
}
4 changes: 2 additions & 2 deletions src/adapters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ import { IZiswapAdapter } from './iziswap/products/iziswap/iZiswapAdapter'
import { LidoStEthAdapter } from './lido/products/st-eth/lidoStEthAdapter'
import { LidoWstEthAdapter } from './lido/products/wst-eth/lidoWstEthAdapter'
import { SDaiAdapter } from './maker/products/yield/sDaiAdapter'
import { MendiFinanceBorrowAdapter } from './mendi-finance/products/borrow/mendiFinanceBorrowAdapter'
import { MendiFinanceSupplyAdapter } from './mendi-finance/products/supply/mendiFinanceSupplyAdapter'
import { MorphoAaveV2OptimizerBorrowAdapter } from './morpho-aave-v2/products/optimizer-borrow/morphoAaveV2OptimizerBorrowAdapter'
import { MorphoAaveV2OptimizerSupplyAdapter } from './morpho-aave-v2/products/optimizer-supply/morphoAaveV2OptimizerSupplyAdapter'
import { MorphoAaveV3ETHOptimizerBorrowAdapter } from './morpho-aave-v3-eth/products/optimizer-borrow/morphoAaveV3ETHOptimizerBorrowAdapter'
import { MorphoAaveV3ETHOptimizerSupplyAdapter } from './morpho-aave-v3-eth/products/optimizer-supply/morphoAaveV3ETHOptimizerSupplyAdapter'
import { MorphoCompoundV2OptimizerBorrowAdapter } from './morpho-compound-v2/products/optimizer-borrow/morphoCompoundV2OptimizerBorrowAdapter'
import { MorphoCompoundV2OptimizerSupplyAdapter } from './morpho-compound-v2/products/optimizer-supply/morphoCompoundV2OptimizerSupplyAdapter'
import { MendiFinanceBorrowAdapter } from './mendi-finance/products/borrow/mendiFinanceBorrowAdapter'
import { MendiFinanceSupplyAdapter } from './mendi-finance/products/supply/mendiFinanceSupplyAdapter'
import { PricesUSDAdapter } from './prices/products/usd/pricesUSDAdapter'
import { Protocol } from './protocols'
import { StargatePoolAdapter } from './stargate/products/pool/stargatePoolAdapter'
Expand Down
2 changes: 1 addition & 1 deletion src/adapters/integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ import { testCases as gMXTestCases } from './gmx/tests/testCases'
import { testCases as iZiSwapTestCases } from './iziswap/tests/testCases'
import { testCases as lidoTestCases } from './lido/tests/testCases'
import { testCases as makerTestCases } from './maker/tests/testCases'
import { testCases as mendiFinanceTestCases } from './mendi-finance/tests/testCases'
import { testCases as morphoAaveV2TestCases } from './morpho-aave-v2/tests/testCases'
import { testCases as morphoAaveV3ETHOptimizerTestCases } from './morpho-aave-v3-eth/tests/testCases'
import { testCases as morphoCompoundV2OptimizerTestCases } from './morpho-compound-v2/tests/testCases'
import { testCases as mendiFinanceTestCases } from './mendi-finance/tests/testCases'
import { testCases as pricesTestCases } from './prices/tests/testCases'
import { Protocol } from './protocols'
import { testCases as stargateTestCases } from './stargate/tests/testCases'
Expand Down
145 changes: 10 additions & 135 deletions src/adapters/morpho-aave-v2/common/morphoBasePoolAdapter.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,20 @@
import { formatUnits } from 'ethers'
import { AdaptersController } from '../../../core/adaptersController'
import { Chain } from '../../../core/constants/chains'
import { RAY } from '../../../core/constants/RAY'
import { SECONDS_PER_YEAR } from '../../../core/constants/SECONDS_PER_YEAR'
import { ZERO_ADDRESS } from '../../../core/constants/ZERO_ADDRESS'
import { IMetadataBuilder } from '../../../core/decorators/cacheToFile'
import { NotImplementedError } from '../../../core/errors/errors'
import { aggregateTrades } from '../../../core/utils/aggregateTrades'
import { aprToApy } from '../../../core/utils/aprToApy'
import { CustomJsonRpcProvider } from '../../../core/utils/customJsonRpcProvider'
import { getTokenMetadata } from '../../../core/utils/getTokenMetadata'
import { logger } from '../../../core/utils/logger'
import { formatProtocolTokenArrayToMap } from '../../../core/utils/protocolTokenToMap'
import {
GetPositionsInput,
GetEventsInput,
GetApyInput,
GetAprInput,
GetTotalValueLockedInput,
GetProfitsInput,
GetConversionRateInput,
MovementsByBlock,
PositionType,
Expand All @@ -27,14 +23,12 @@ import {
ProtocolTokenApr,
ProtocolTokenApy,
ProtocolTokenUnderlyingRate,
ProfitsWithRange,
ProtocolTokenTvl,
ProtocolPosition,
TokenBalance,
TokenType,
Underlying,
UnderlyingTokenRate,
BaseTokenMovement,
} from '../../../types/adapter'
import { Erc20Metadata } from '../../../types/erc20Metadata'
import { Protocol } from '../../protocols'
Expand Down Expand Up @@ -334,124 +328,6 @@ export abstract class MorphoBasePoolAdapter implements IMetadataBuilder {
})
}

async getProfits({
userAddress,
fromBlock,
toBlock,
}: GetProfitsInput): Promise<ProfitsWithRange> {
// Fetch end and start position values
const positionType = this.getProtocolDetails().positionType

const [endPositionValues, startPositionValues] = await Promise.all([
this.getPositions({
userAddress,
blockNumber: toBlock,
}).then(formatProtocolTokenArrayToMap),
this.getPositions({
userAddress,
blockNumber: fromBlock,
}).then(formatProtocolTokenArrayToMap),
])

// Fetch and process each token's movements
const tokens = await Promise.all(
Object.values(endPositionValues).map(
async ({
protocolTokenMetadata,
underlyingTokenPositions: underlyingEndPositions,
}) => {
const getEventsInput: GetEventsInput = {
userAddress,
protocolTokenAddress: protocolTokenMetadata.address,
fromBlock,
toBlock,
}
let eventsOut: Record<string, bigint>
let eventsIn: Record<string, bigint>

if (positionType === PositionType.Supply) {
;[eventsOut, eventsIn] = await Promise.all([
this.getWithdrawals(getEventsInput).then(aggregateTrades),
this.getDeposits(getEventsInput).then(aggregateTrades),
])
} else {
;[eventsOut, eventsIn] = await Promise.all([
this.getBorrows(getEventsInput).then(aggregateTrades),
this.getRepays(getEventsInput).then(aggregateTrades),
])
}

return {
...protocolTokenMetadata,
type: TokenType.Protocol,
tokens: Object.values(underlyingEndPositions).map(
({
address,
name,
symbol,
decimals,
balanceRaw: endPositionValueRaw,
}) => {
const startPositionValueRaw =
startPositionValues[protocolTokenMetadata.address]
?.underlyingTokenPositions[address]?.balanceRaw ?? 0n

const calculationData = {
outRaw: eventsOut[address] ?? 0n,
inRaw: eventsIn[address] ?? 0n,
endPositionValueRaw: endPositionValueRaw ?? 0n,
startPositionValueRaw,
}

let profitRaw =
calculationData.endPositionValueRaw +
calculationData.outRaw -
calculationData.inRaw -
calculationData.startPositionValueRaw

if (
this.getProtocolDetails().positionType === PositionType.Borrow
) {
profitRaw *= -1n
}

return {
address,
name,
symbol,
decimals,
profitRaw,
type: TokenType.Underlying,
calculationData: {
withdrawalsRaw: eventsOut[address] ?? 0n,
withdrawals: formatUnits(
eventsOut[address] ?? 0n,
decimals,
),
depositsRaw: eventsIn[address] ?? 0n,
deposits: formatUnits(eventsIn[address] ?? 0n, decimals),
startPositionValueRaw: startPositionValueRaw ?? 0n,
startPositionValue: formatUnits(
startPositionValueRaw ?? 0n,
decimals,
),
endPositionValueRaw,
endPositionValue: formatUnits(
endPositionValueRaw ?? 0n,
decimals,
),
},
}
},
),
}
},
),
)

return { tokens, fromBlock, toBlock }
}

async getTotalValueLocked({
blockNumber,
}: GetTotalValueLockedInput): Promise<ProtocolTokenTvl[]> {
Expand Down Expand Up @@ -605,24 +481,23 @@ export abstract class MorphoBasePoolAdapter implements IMetadataBuilder {
eventData._poolToken,
)

const underlyingTokensMovement: Record<string, BaseTokenMovement> = {}
underlyingTokens.forEach((underlyingToken) => {
underlyingTokensMovement[underlyingToken.address] = {
const tokens: Underlying[] = underlyingTokens.map(
(underlyingToken) => ({
...underlyingToken,
transactionHash: event.transactionHash,
movementValueRaw: eventData._amount,
}
})
balanceRaw: eventData._amount,
type: TokenType.Underlying,
}),
)

return {
protocolToken: {
...protocolToken,
},
underlyingTokensMovement,
protocolToken,
tokens,
blockNumber: event.blockNumber,
transactionHash: event.transactionHash,
}
}),
)

return movements.filter(
(movement): movement is MovementsByBlock => movement !== null,
) as MovementsByBlock[]
Expand Down
107 changes: 12 additions & 95 deletions src/adapters/morpho-aave-v2/tests/snapshots/ethereum.profits.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,40 +10,13 @@
"positionType": "borrow",
"chainId": 1,
"productId": "optimizer-borrow",
"success": true,
"tokens": [
{
"address": "0x030ba81f1c18d280636f32af80b9aad02cf0854e",
"name": "Aave interest bearing WETH",
"symbol": "aWETH",
"decimals": 18,
"type": "protocol",
"tokens": [
{
"address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
"name": "Wrapped Ether",
"symbol": "WETH",
"decimals": 18,
"profitRaw": "-95602153837365848n",
"type": "underlying",
"calculationData": {
"withdrawalsRaw": "0n",
"withdrawals": "0.0",
"depositsRaw": "0n",
"deposits": "0.0",
"startPositionValueRaw": "1500251298264201313462n",
"startPositionValue": "1500.251298264201313462",
"endPositionValueRaw": "1500346900418038679310n",
"endPositionValue": "1500.34690041803867931"
},
"profit": "-0.095602153837365848",
"iconUrl": "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/logo.png"
}
]
"success": false,
"error": {
"message": "Unable to calculate profits, missing USD price for token position 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
"details": {
"name": "Error"
}
],
"fromBlock": 18725934,
"toBlock": 18733080
}
},
{
"protocolId": "morpho-aave-v2",
Expand All @@ -54,69 +27,13 @@
"positionType": "supply",
"chainId": 1,
"productId": "optimizer-supply",
"success": true,
"tokens": [
{
"address": "0x3ed3b47dd13ec9a98b44e6204a523e766b225811",
"name": "Aave interest bearing USDT",
"symbol": "aUSDT",
"decimals": 6,
"type": "protocol",
"tokens": [
{
"address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
"name": "Tether USD",
"symbol": "USDT",
"decimals": 6,
"profitRaw": "313n",
"type": "underlying",
"calculationData": {
"withdrawalsRaw": "0n",
"withdrawals": "0.0",
"depositsRaw": "0n",
"deposits": "0.0",
"startPositionValueRaw": "1198908n",
"startPositionValue": "1.198908",
"endPositionValueRaw": "1199221n",
"endPositionValue": "1.199221"
},
"profit": "0.000313",
"iconUrl": "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xdAC17F958D2ee523a2206206994597C13D831ec7/logo.png"
}
]
},
{
"address": "0xbcca60bb61934080951369a648fb03df4f96263c",
"name": "Aave interest bearing USDC",
"symbol": "aUSDC",
"decimals": 6,
"type": "protocol",
"tokens": [
{
"address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
"name": "USD Coin",
"symbol": "USDC",
"decimals": 6,
"profitRaw": "901109849n",
"type": "underlying",
"calculationData": {
"withdrawalsRaw": "0n",
"withdrawals": "0.0",
"depositsRaw": "0n",
"deposits": "0.0",
"startPositionValueRaw": "4849837112609n",
"startPositionValue": "4849837.112609",
"endPositionValueRaw": "4850738222458n",
"endPositionValue": "4850738.222458"
},
"profit": "901.109849",
"iconUrl": "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png"
}
]
"success": false,
"error": {
"message": "Unable to calculate profits, missing USD price for token position 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
"details": {
"name": "Error"
}
],
"fromBlock": 18725934,
"toBlock": 18733080
}
}
]
}
Loading

0 comments on commit 0ebb15a

Please sign in to comment.