From a92733d8d2cafebba31479d3c218de3458823c7e Mon Sep 17 00:00:00 2001 From: gs8nrv <55771972+GuillaumeNervoXS@users.noreply.github.com> Date: Thu, 25 Apr 2024 15:56:22 +0200 Subject: [PATCH] all tests passing --- .../angle-transmuter-e2e.test.ts | 2 +- .../angle-transmuter-integration.test.ts | 219 +++++++++--------- .../angle-transmuter/angle-transmuter-pool.ts | 136 +++++------ src/dex/angle-transmuter/morphoOracle.ts | 4 +- src/dex/angle-transmuter/transmuter.ts | 1 + 5 files changed, 179 insertions(+), 183 deletions(-) diff --git a/src/dex/angle-transmuter/angle-transmuter-e2e.test.ts b/src/dex/angle-transmuter/angle-transmuter-e2e.test.ts index f84a4c9e4..edc00591d 100644 --- a/src/dex/angle-transmuter/angle-transmuter-e2e.test.ts +++ b/src/dex/angle-transmuter/angle-transmuter-e2e.test.ts @@ -87,7 +87,7 @@ describe('AngleTransmuter E2E', () => { const stables = [tokens.EURA, tokens.USDA]; const collaterals: Collateral = { - USDA: [tokens.USDC, tokens.steakUSDC, tokens.bIB01], + USDA: [tokens.bIB01, tokens.USDC, tokens.steakUSDC], EURA: [tokens.EUROC, tokens.bC3M, tokens.bERNX], }; diff --git a/src/dex/angle-transmuter/angle-transmuter-integration.test.ts b/src/dex/angle-transmuter/angle-transmuter-integration.test.ts index 7617f6499..6fc6c9b32 100644 --- a/src/dex/angle-transmuter/angle-transmuter-integration.test.ts +++ b/src/dex/angle-transmuter/angle-transmuter-integration.test.ts @@ -188,17 +188,10 @@ describe('AngleTransmuter', () => { const tokens = Tokens[network]; - const stables = [ - // tokens.EURA, - tokens.USDA, - ]; + const stables = [tokens.EURA, tokens.USDA]; const collaterals: Collateral = { - USDA: [ - // tokens.bIB01, - // tokens.USDC, - tokens.steakUSDC, - ], + USDA: [tokens.bIB01, tokens.USDC, tokens.steakUSDC], EURA: [tokens.EUROC, tokens.bC3M, tokens.bERNX], }; @@ -210,15 +203,15 @@ describe('AngleTransmuter', () => { const amounts = [ 0n, 1n * BI_POWS[tokens.USDA.decimals], - // 2n * BI_POWS[tokens.USDA.decimals], - // 3n * BI_POWS[tokens.USDA.decimals], - // 4n * BI_POWS[tokens.USDA.decimals], - // 5n * BI_POWS[tokens.USDA.decimals], - // 6n * BI_POWS[tokens.USDA.decimals], - // 7n * BI_POWS[tokens.USDA.decimals], - // 8n * BI_POWS[tokens.USDA.decimals], - // 9n * BI_POWS[tokens.USDA.decimals], - // 10n * BI_POWS[tokens.USDA.decimals], + 2n * BI_POWS[tokens.USDA.decimals], + 3n * BI_POWS[tokens.USDA.decimals], + 4n * BI_POWS[tokens.USDA.decimals], + 5n * BI_POWS[tokens.USDA.decimals], + 6n * BI_POWS[tokens.USDA.decimals], + 7n * BI_POWS[tokens.USDA.decimals], + 8n * BI_POWS[tokens.USDA.decimals], + 9n * BI_POWS[tokens.USDA.decimals], + 10n * BI_POWS[tokens.USDA.decimals], ]; beforeAll(async () => { @@ -235,60 +228,60 @@ describe('AngleTransmuter', () => { const amountsCollateral = [ 0n, 1n * BI_POWS[collateral.decimals], - // 2n * BI_POWS[collateral.decimals], - // 3n * BI_POWS[collateral.decimals], - // 4n * BI_POWS[collateral.decimals], - // 5n * BI_POWS[collateral.decimals], - // 6n * BI_POWS[collateral.decimals], - // 7n * BI_POWS[collateral.decimals], - // 8n * BI_POWS[collateral.decimals], - // 9n * BI_POWS[collateral.decimals], - // 10n * BI_POWS[collateral.decimals], + 2n * BI_POWS[collateral.decimals], + 3n * BI_POWS[collateral.decimals], + 4n * BI_POWS[collateral.decimals], + 5n * BI_POWS[collateral.decimals], + 6n * BI_POWS[collateral.decimals], + 7n * BI_POWS[collateral.decimals], + 8n * BI_POWS[collateral.decimals], + 9n * BI_POWS[collateral.decimals], + 10n * BI_POWS[collateral.decimals], ]; - // it('getTopPoolsForToken - collateral', async () => { - // // We have to check without calling initializePricing, because - // // pool-tracker is not calling that function - // const newAngleTransmuter = new AngleTransmuter( - // network, - // dexKey, - // dexHelper, - // ); - // if (newAngleTransmuter.updatePoolState) { - // await newAngleTransmuter.updatePoolState(); - // } - // const poolLiquidity = await newAngleTransmuter.getTopPoolsForToken( - // collateral.address, - // 10, - // ); - // console.log(`${collateral.symbol} Top Pools:`, poolLiquidity); - - // if (!newAngleTransmuter.hasConstantPriceLargeAmounts) { - // checkPoolsLiquidity(poolLiquidity, collateral.address, dexKey); - // } - // }); - - // it('getTopPoolsForToken - stablecoin', async () => { - // // We have to check without calling initializePricing, because - // // pool-tracker is not calling that function - // const newAngleTransmuter = new AngleTransmuter( - // network, - // dexKey, - // dexHelper, - // ); - // if (newAngleTransmuter.updatePoolState) { - // await newAngleTransmuter.updatePoolState(); - // } - // const poolLiquidity = await newAngleTransmuter.getTopPoolsForToken( - // stable.address, - // 10, - // ); - // console.log(`${stable.symbol} Top Pools:`, poolLiquidity); - - // if (!newAngleTransmuter.hasConstantPriceLargeAmounts) { - // checkPoolsLiquidity(poolLiquidity, stable.address, dexKey); - // } - // }); + it('getTopPoolsForToken - collateral', async () => { + // We have to check without calling initializePricing, because + // pool-tracker is not calling that function + const newAngleTransmuter = new AngleTransmuter( + network, + dexKey, + dexHelper, + ); + if (newAngleTransmuter.updatePoolState) { + await newAngleTransmuter.updatePoolState(); + } + const poolLiquidity = await newAngleTransmuter.getTopPoolsForToken( + collateral.address, + 10, + ); + console.log(`${collateral.symbol} Top Pools:`, poolLiquidity); + + if (!newAngleTransmuter.hasConstantPriceLargeAmounts) { + checkPoolsLiquidity(poolLiquidity, collateral.address, dexKey); + } + }); + + it('getTopPoolsForToken - stablecoin', async () => { + // We have to check without calling initializePricing, because + // pool-tracker is not calling that function + const newAngleTransmuter = new AngleTransmuter( + network, + dexKey, + dexHelper, + ); + if (newAngleTransmuter.updatePoolState) { + await newAngleTransmuter.updatePoolState(); + } + const poolLiquidity = await newAngleTransmuter.getTopPoolsForToken( + stable.address, + 10, + ); + console.log(`${stable.symbol} Top Pools:`, poolLiquidity); + + if (!newAngleTransmuter.hasConstantPriceLargeAmounts) { + checkPoolsLiquidity(poolLiquidity, stable.address, dexKey); + } + }); it('getPoolIdentifiers and getPricesVolume SELL - collateral', async () => { await testPricingOnNetwork( @@ -304,49 +297,49 @@ describe('AngleTransmuter', () => { ); }); - // it('getPoolIdentifiers and getPricesVolume BUY - stablecoin', async () => { - // await testPricingOnNetwork( - // angleTransmuter, - // network, - // dexKey, - // blockNumber, - // stable.symbol!, - // collateral.symbol!, - // SwapSide.BUY, - // amountsCollateral, - // 'quoteOut', - // ); - // }); - - // if (!isKYC[collateral.symbol!]) { - // it('getPoolIdentifiers and getPricesVolume SELL - stablecoin', async () => { - // await testPricingOnNetwork( - // angleTransmuter, - // network, - // dexKey, - // blockNumber, - // stable.symbol!, - // collateral.symbol!, - // SwapSide.SELL, - // amounts, - // 'quoteIn', - // ); - // }); - - // it('getPoolIdentifiers and getPricesVolume BUY - collateral', async () => { - // await testPricingOnNetwork( - // angleTransmuter, - // network, - // dexKey, - // blockNumber, - // collateral.symbol!, - // stable.symbol!, - // SwapSide.BUY, - // amounts, - // 'quoteOut', - // ); - // }); - // } + it('getPoolIdentifiers and getPricesVolume BUY - stablecoin', async () => { + await testPricingOnNetwork( + angleTransmuter, + network, + dexKey, + blockNumber, + stable.symbol!, + collateral.symbol!, + SwapSide.BUY, + amountsCollateral, + 'quoteOut', + ); + }); + + if (!isKYC[collateral.symbol!]) { + it('getPoolIdentifiers and getPricesVolume SELL - stablecoin', async () => { + await testPricingOnNetwork( + angleTransmuter, + network, + dexKey, + blockNumber, + stable.symbol!, + collateral.symbol!, + SwapSide.SELL, + amounts, + 'quoteIn', + ); + }); + + it('getPoolIdentifiers and getPricesVolume BUY - collateral', async () => { + await testPricingOnNetwork( + angleTransmuter, + network, + dexKey, + blockNumber, + collateral.symbol!, + stable.symbol!, + SwapSide.BUY, + amounts, + 'quoteOut', + ); + }); + } }), ), ); diff --git a/src/dex/angle-transmuter/angle-transmuter-pool.ts b/src/dex/angle-transmuter/angle-transmuter-pool.ts index f7ae41865..4d28f95a4 100644 --- a/src/dex/angle-transmuter/angle-transmuter-pool.ts +++ b/src/dex/angle-transmuter/angle-transmuter-pool.ts @@ -32,7 +32,12 @@ import { filterDictionaryOnly, } from './utils'; import { RedstoneSubscriber } from './redstone'; -import { formatEther, formatUnits, parseEther } from 'ethers/lib/utils'; +import { + formatEther, + formatUnits, + parseEther, + parseUnits, +} from 'ethers/lib/utils'; import { BackedSubscriber } from './backedOracle'; import { SwapSide } from '../../constants'; import { ethers } from 'ethers'; @@ -105,20 +110,29 @@ export class AngleTransmuterEventPool extends ComposedEventSubscriber acc: { [address: string]: MorphoVaultSubscriber }, [key, value], ) => { - acc[value.baseVault] = new MorphoVaultSubscriber( - value.baseVault, - lens>().oracles.morphoVault[key], - dexHelper.getLogger( - `${key}:${value.baseVault} Morpho Vault for ${parentName}-${network}`, - ), - ); - acc[value.quoteVault] = new MorphoVaultSubscriber( - value.quoteVault, - lens>().oracles.morphoVault[key], - dexHelper.getLogger( - `${key}:${value.quoteVault} Morpho Vault for ${parentName}-${network}`, - ), - ); + if (value.baseVault && value.baseVault !== ethers.constants.AddressZero) + acc[value.baseVault] = new MorphoVaultSubscriber( + value.baseVault, + lens>().oracles.morphoVault[ + value.baseVault + ], + dexHelper.getLogger( + `${key}:${value.baseVault} Morpho Vault for ${parentName}-${network}`, + ), + ); + if ( + value.quoteVault && + value.quoteVault !== ethers.constants.AddressZero + ) + acc[value.quoteVault] = new MorphoVaultSubscriber( + value.quoteVault, + lens>().oracles.morphoVault[ + value.quoteVault + ], + dexHelper.getLogger( + `${key}:${value.quoteVault} Morpho Vault for ${parentName}-${network}`, + ), + ); return acc; }, {}, @@ -308,14 +322,14 @@ export class AngleTransmuterEventPool extends ComposedEventSubscriber ); } else if (oracleFeed.isPyth) { pythIds.ids = pythIds.ids.concat(oracleFeed.pyth!.feedIds); - } else if (oracleFeed.morpho) { + } else if (oracleFeed.isMorpho) { const morphoOracleResult = ( await multiContract.methods - .aggregate([ + .aggregate( MorphoOracleEventPool.getGenerateInfoMultiCallInput( - oracleFeed.morpho.oracle, + oracleFeed.morpho!.oracle, ), - ]) + ) .call({}, blockNumber) ).returnData; const morphoOracleInfo = @@ -360,7 +374,7 @@ export class AngleTransmuterEventPool extends ComposedEventSubscriber blockNumber, multiContract, )); - morphoMap[oracleFeed.morpho.oracle] = morphoOracleInfo; + morphoMap[oracleFeed.morpho!.oracle] = morphoOracleInfo; } else { throw new Error('Unknown oracle feed'); } @@ -476,7 +490,8 @@ export class AngleTransmuterEventPool extends ComposedEventSubscriber // add all the feed oracles used to their respective channels if ( oracleConfigDecoded.oracleType === OracleReadType.CHAINLINK_FEEDS || - oracleConfigDecoded.oracleType === OracleReadType.PYTH + oracleConfigDecoded.oracleType === OracleReadType.PYTH || + oracleConfigDecoded.oracleType === OracleReadType.MORPHO_ORACLE ) { const oracleFeed = TransmuterSubscriber._decodeOracleFeed( oracleConfigDecoded.oracleType, @@ -496,7 +511,8 @@ export class AngleTransmuterEventPool extends ComposedEventSubscriber } if ( oracleConfigDecoded.targetType === OracleReadType.CHAINLINK_FEEDS || - oracleConfigDecoded.targetType === OracleReadType.PYTH + oracleConfigDecoded.targetType === OracleReadType.PYTH || + oracleConfigDecoded.targetType === OracleReadType.MORPHO_ORACLE ) { const oracleFeed = TransmuterSubscriber._decodeOracleFeed( oracleConfigDecoded.targetType, @@ -715,13 +731,13 @@ export class AngleTransmuterEventPool extends ComposedEventSubscriber if (oracleType === OracleReadType.CHAINLINK_FEEDS) { price = this._quoteAmount(feed.chainlink!.quoteType, baseValue); for (let i = 0; i < feed.chainlink!.circuitChainlink.length; i++) { - price = this._readChainlink( + ({ price } = this._readChainlink( config, state, feed.chainlink!.circuitChainlink[i], feed.chainlink!.circuitChainIsMultiplied[i], price, - ); + )); } } else if (oracleType === OracleReadType.PYTH) { price = this._quoteAmount(feed.pyth!.quoteType, baseValue); @@ -755,62 +771,38 @@ export class AngleTransmuterEventPool extends ComposedEventSubscriber : 1n; const baseFeed1Price = morphoOracleConfig.baseFeed1 !== ethers.constants.AddressZero - ? bigIntify( - parseEther( - this._readChainlink( - config, - state, - morphoOracleConfig.baseFeed1, - 1, - 1, - ).toString(), - ), + ? this._readMorphoFeedChainlink( + config, + state, + morphoOracleConfig.baseFeed1, ) : 1n; const baseFeed2Price = morphoOracleConfig.baseFeed2 !== ethers.constants.AddressZero - ? bigIntify( - parseEther( - this._readChainlink( - config, - state, - morphoOracleConfig.baseFeed2, - 1, - 1, - ).toString(), - ), + ? this._readMorphoFeedChainlink( + config, + state, + morphoOracleConfig.baseFeed2, ) : 1n; const quoteFeed1Price = morphoOracleConfig.quoteFeed1 !== ethers.constants.AddressZero - ? bigIntify( - parseEther( - this._readChainlink( - config, - state, - morphoOracleConfig.quoteFeed1, - 1, - 1, - ).toString(), - ), + ? this._readMorphoFeedChainlink( + config, + state, + morphoOracleConfig.quoteFeed1, ) : 1n; const quoteFeed2Price = morphoOracleConfig.quoteFeed2 !== ethers.constants.AddressZero - ? bigIntify( - parseEther( - this._readChainlink( - config, - state, - morphoOracleConfig.quoteFeed2, - 1, - 1, - ).toString(), - ), + ? this._readMorphoFeedChainlink( + config, + state, + morphoOracleConfig.quoteFeed2, ) : 1n; price = Number.parseFloat( - formatEther( + formatUnits( (morphoOracleConfig.scaleFactor * baseVaultPrice * baseFeed1Price * @@ -818,6 +810,7 @@ export class AngleTransmuterEventPool extends ComposedEventSubscriber quoteVaultPrice / quoteFeed1Price / quoteFeed2Price, + 36, ), ); } @@ -830,7 +823,7 @@ export class AngleTransmuterEventPool extends ComposedEventSubscriber id: string, isMultiplied: number, price: number, - ): number { + ): { price: number; decimals: number } { let decimals: number; if (Object.keys(config.oracles.chainlink).includes(id)) decimals = config.oracles.chainlink[id].decimals; @@ -842,6 +835,15 @@ export class AngleTransmuterEventPool extends ComposedEventSubscriber ); if (isMultiplied === 1) price *= rate; else price /= rate; - return price; + return { price, decimals }; + } + + _readMorphoFeedChainlink( + config: PoolConfig, + state: PoolState, + id: string, + ): bigint { + const { price, decimals } = this._readChainlink(config, state, id, 1, 1); + return bigIntify(parseUnits(price.toString(), decimals)); } } diff --git a/src/dex/angle-transmuter/morphoOracle.ts b/src/dex/angle-transmuter/morphoOracle.ts index b2c50fb51..dfd2b155b 100644 --- a/src/dex/angle-transmuter/morphoOracle.ts +++ b/src/dex/angle-transmuter/morphoOracle.ts @@ -173,7 +173,7 @@ export class MorphoOracleEventPool extends StatefulEventSubscriber extends PartialEventSubscriber< 18, ), ); + return transmuterState; }