diff --git a/src/abi/api3-proxy.json b/src/abi/api3-proxy.json index 41ce3c43e..ec343f133 100644 --- a/src/abi/api3-proxy.json +++ b/src/abi/api3-proxy.json @@ -42,5 +42,12 @@ ], "stateMutability": "view", "type": "function" + }, + { + "inputs": [], + "name": "dapiNameHash", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" } ] diff --git a/src/dex/balancer-v2/balancer-v2-e2e.test.ts b/src/dex/balancer-v2/balancer-v2-e2e.test.ts index 5cc919399..0938b3c25 100644 --- a/src/dex/balancer-v2/balancer-v2-e2e.test.ts +++ b/src/dex/balancer-v2/balancer-v2-e2e.test.ts @@ -2,7 +2,11 @@ import dotenv from 'dotenv'; dotenv.config(); import { testE2E } from '../../../tests/utils-e2e'; -import { Holders, NativeTokenSymbols, Tokens } from '../../../tests/constants-e2e'; +import { + Holders, + NativeTokenSymbols, + Tokens, +} from '../../../tests/constants-e2e'; import { ContractMethod, Network, SwapSide } from '../../constants'; import { StaticJsonRpcProvider } from '@ethersproject/providers'; @@ -37,13 +41,7 @@ function testForNetwork( ContractMethod.megaSwap, ], ], - [ - SwapSide.BUY, - [ - ContractMethod.simpleBuy, - ContractMethod.buy, - ], - ], + [SwapSide.BUY, [ContractMethod.simpleBuy, ContractMethod.buy]], ]); describe(`${network}`, () => { diff --git a/src/dex/balancer-v2/config.ts b/src/dex/balancer-v2/config.ts index 86e7e2930..1f05ae1c1 100644 --- a/src/dex/balancer-v2/config.ts +++ b/src/dex/balancer-v2/config.ts @@ -80,5 +80,5 @@ export const Adapters: Record = { [Network.BASE]: { [SwapSide.SELL]: [{ name: 'BaseAdapter01', index: 4 }], [SwapSide.BUY]: [{ name: 'BaseBuyAdapter', index: 3 }], - } + }, }; diff --git a/src/dex/maverick-v1/maverick-v1-e2e.test.ts b/src/dex/maverick-v1/maverick-v1-e2e.test.ts index 8f4c76a8e..6840f7464 100644 --- a/src/dex/maverick-v1/maverick-v1-e2e.test.ts +++ b/src/dex/maverick-v1/maverick-v1-e2e.test.ts @@ -38,13 +38,7 @@ function testForNetwork( ContractMethod.megaSwap, ], ], - [ - SwapSide.BUY, - [ - ContractMethod.simpleBuy, - ContractMethod.buy, - ], - ], + [SwapSide.BUY, [ContractMethod.simpleBuy, ContractMethod.buy]], ]); describe(`${network}`, () => { diff --git a/src/dex/pancakeswap-v3/pancakeswap-v3-e2e.test.ts b/src/dex/pancakeswap-v3/pancakeswap-v3-e2e.test.ts index f3c61fdd3..af1065c76 100644 --- a/src/dex/pancakeswap-v3/pancakeswap-v3-e2e.test.ts +++ b/src/dex/pancakeswap-v3/pancakeswap-v3-e2e.test.ts @@ -38,13 +38,7 @@ function testForNetwork( ContractMethod.megaSwap, ], ], - [ - SwapSide.BUY, - [ - ContractMethod.simpleBuy, - ContractMethod.buy, - ], - ], + [SwapSide.BUY, [ContractMethod.simpleBuy, ContractMethod.buy]], ]); describe(`${network}`, () => { diff --git a/src/dex/quick-perps/pool.ts b/src/dex/quick-perps/pool.ts index 8b922b236..26fe455ba 100644 --- a/src/dex/quick-perps/pool.ts +++ b/src/dex/quick-perps/pool.ts @@ -104,6 +104,7 @@ export class QuickPerpsEventPool extends ComposedEventSubscriber { const evenState = this.getState(blockNumber); if (evenState) return evenState; const onChainState = await this.generateState(blockNumber); + this.logger.warn(`State is generated in RPC fallback call`); this.setState(onChainState, blockNumber); return onChainState; } @@ -283,7 +284,8 @@ export class QuickPerpsEventPool extends ComposedEventSubscriber { for (let priceFeed of priceFeeds) { const api3ServerAddressCallData = Api3FeedSubscriber.getApi3ServerV1MultiCallInput(priceFeed); - const dataFeedIdCallData = Api3FeedSubscriber.getDataFeedId(priceFeed); + const dataFeedIdCallData = + Api3FeedSubscriber.getDapiNameHashMultiCallInput(priceFeed); multiCallData.push(...[api3ServerAddressCallData, dataFeedIdCallData]); multicallSlices.push([i, i + 2]); i += 2; @@ -315,24 +317,31 @@ export class QuickPerpsEventPool extends ComposedEventSubscriber { await multiContract.methods.aggregate(multiCallData).call({}, blockNumber) ).returnData; - const api3ServerV1: { + const api3ServerV1Prep: { [address: string]: { proxy: Address; api3ServerV1: Address; - dataFeedId: string; }; } = {}; + const getFeedIdRequests: MultiCallInput[] = []; + for (let token of tokens) { - const [api3ServerAddressRes, dataFeedIdRes] = configResults.slice( + const [api3ServerAddressRes, dapiNameHashRes] = configResults.slice( ...multicallSlices.shift()!, ); const serverV1Address = Api3FeedSubscriber.decodeApi3ServerV1Result(api3ServerAddressRes); - const dataFeedId = Api3FeedSubscriber.decodeDataFeedId(dataFeedIdRes); - api3ServerV1[token] = { + const dapiNameHash = + Api3FeedSubscriber.decodeDapiNameHash(dapiNameHashRes); + getFeedIdRequests.push( + Api3FeedSubscriber.getFeedIdFromDapiNameHash( + serverV1Address, + dapiNameHash, + ), + ); + api3ServerV1Prep[token] = { proxy: priceFeeds.shift(), api3ServerV1: serverV1Address, - dataFeedId, }; } @@ -355,6 +364,32 @@ export class QuickPerpsEventPool extends ComposedEventSubscriber { const vaultConfigResults = configResults.slice(...multicallSlices.shift()!); const vaultConfig = Vault.getConfig(vaultConfigResults, tokens); + const feedIdResults = ( + await multiContract.methods + .aggregate(getFeedIdRequests) + .call({}, blockNumber) + ).returnData; + + const api3ServerV1: { + [address: string]: { + proxy: Address; + api3ServerV1: Address; + dataFeedId: string; + }; + } = {}; + for (let [i, token] of tokens.entries()) { + const { proxy, api3ServerV1: api3ServerAddress } = + api3ServerV1Prep[token]; + const dataFeedId = Api3FeedSubscriber.decodeFeedIdFromDapiNameHash( + feedIdResults[i], + ); + api3ServerV1[token] = { + proxy, + api3ServerV1: api3ServerAddress, + dataFeedId, + }; + } + return { vaultAddress: dexParams.vault, readerAddress: dexParams.reader, diff --git a/src/dex/quick-perps/quick-perps-events.test.ts b/src/dex/quick-perps/quick-perps-events.test.ts index f3d4999e2..16cf510aa 100644 --- a/src/dex/quick-perps/quick-perps-events.test.ts +++ b/src/dex/quick-perps/quick-perps-events.test.ts @@ -81,7 +81,6 @@ describe('QuickPerps Event', function () { dexKey, network, dexHelper, - logger, config, ); await testEventSubscriber( diff --git a/src/dex/quick-perps/quick-perps.ts b/src/dex/quick-perps/quick-perps.ts index ac0e4e0c3..0cbefeea7 100644 --- a/src/dex/quick-perps/quick-perps.ts +++ b/src/dex/quick-perps/quick-perps.ts @@ -117,45 +117,55 @@ export class QuickPerps extends SimpleExchange implements IDex { limitPools?: string[], ): Promise> { if (side === SwapSide.BUY || !this.pool) return null; - const srcAddress = this.dexHelper.config - .wrapETH(srcToken) - .address.toLowerCase(); - const destAddress = this.dexHelper.config - .wrapETH(destToken) - .address.toLowerCase(); - if ( - srcAddress === destAddress || - !( - this.supportedTokensMap[srcAddress] && - this.supportedTokensMap[destAddress] + try { + const srcAddress = this.dexHelper.config + .wrapETH(srcToken) + .address.toLowerCase(); + const destAddress = this.dexHelper.config + .wrapETH(destToken) + .address.toLowerCase(); + if ( + srcAddress === destAddress || + !( + this.supportedTokensMap[srcAddress] && + this.supportedTokensMap[destAddress] + ) ) - ) - return null; - const srcPoolIdentifier = `${this.dexKey}_${srcAddress}`; - const destPoolIdentifier = `${this.dexKey}_${destAddress}`; - const pools = [srcPoolIdentifier, destPoolIdentifier]; - if (limitPools && pools.some(p => !limitPools.includes(p))) return null; + return null; + const srcPoolIdentifier = `${this.dexKey}_${srcAddress}`; + const destPoolIdentifier = `${this.dexKey}_${destAddress}`; + const pools = [srcPoolIdentifier, destPoolIdentifier]; + if (limitPools && pools.some(p => !limitPools.includes(p))) return null; - const unitVolume = getBigIntPow(srcToken.decimals); - const prices = await this.pool.getAmountOut( - srcAddress, - destAddress, - [unitVolume, ...amounts], - blockNumber, - ); + const unitVolume = getBigIntPow(srcToken.decimals); + const prices = await this.pool.getAmountOut( + srcAddress, + destAddress, + [unitVolume, ...amounts], + blockNumber, + ); - if (!prices) return null; + if (!prices) return null; - return [ - { - prices: prices.slice(1), - unit: prices[0], - gasCost: QuickPerpsGasCost, - exchange: this.dexKey, - data: {}, - poolAddresses: [this.params.vault], - }, - ]; + return [ + { + prices: prices.slice(1), + unit: prices[0], + gasCost: QuickPerpsGasCost, + exchange: this.dexKey, + data: {}, + poolAddresses: [this.params.vault], + }, + ]; + } catch (e) { + this.logger.error( + `Error_getPrices ${srcToken.symbol || srcToken.address}, ${ + destToken.symbol || destToken.address + }, ${side}: `, + e, + ); + return null; + } } // Returns estimated gas cost of calldata for this DEX in multiSwap diff --git a/src/dex/solidly/config.ts b/src/dex/solidly/config.ts index c4dccd96b..baedb5183 100644 --- a/src/dex/solidly/config.ts +++ b/src/dex/solidly/config.ts @@ -204,5 +204,5 @@ export const Adapters: Record = { }, [Network.BASE]: { [SwapSide.SELL]: [{ name: 'BaseAdapter01', index: 3 }], // aerodrome, equalizer - } + }, }; diff --git a/src/dex/solidly/forks-override/aerodrome.ts b/src/dex/solidly/forks-override/aerodrome.ts index ae09c0930..505ed4c71 100644 --- a/src/dex/solidly/forks-override/aerodrome.ts +++ b/src/dex/solidly/forks-override/aerodrome.ts @@ -16,11 +16,7 @@ export class Aerodrome extends VelodromeV2 { dexKey: string, protected dexHelper: IDexHelper, ) { - super( - network, - dexKey, - dexHelper, - ); + super(network, dexKey, dexHelper); this.factory = new dexHelper.web3Provider.eth.Contract( AerodromeFactoryABI as any, diff --git a/src/dex/uniswap-v3/config.ts b/src/dex/uniswap-v3/config.ts index 4a419d9b8..d2bbd45f4 100644 --- a/src/dex/uniswap-v3/config.ts +++ b/src/dex/uniswap-v3/config.ts @@ -220,8 +220,7 @@ export const UniswapV3Config: DexConfigMap = { chunksCount: 10, initRetryFrequency: 10, initHash: `0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54`, - subgraphURL: - 'https://api.studio.thegraph.com/query/32073/v3-base/v0.0.1', + subgraphURL: 'https://api.studio.thegraph.com/query/32073/v3-base/v0.0.1', }, }, ChronosV3: { diff --git a/src/dex/uniswap-v3/uniswap-v3-e2e.test.ts b/src/dex/uniswap-v3/uniswap-v3-e2e.test.ts index 0bae0339a..900de38a0 100644 --- a/src/dex/uniswap-v3/uniswap-v3-e2e.test.ts +++ b/src/dex/uniswap-v3/uniswap-v3-e2e.test.ts @@ -429,13 +429,7 @@ describe('UniswapV3 E2E', () => { ContractMethod.megaSwap, ], ], - [ - SwapSide.BUY, - [ - ContractMethod.simpleBuy, - ContractMethod.buy - ], - ], + [SwapSide.BUY, [ContractMethod.simpleBuy, ContractMethod.buy]], ]); sideToContractMethods.forEach((contractMethods, side) => diff --git a/src/dex/uniswap-v3/uniswap-v3-integration.test.ts b/src/dex/uniswap-v3/uniswap-v3-integration.test.ts index 47367cda3..32a463c97 100644 --- a/src/dex/uniswap-v3/uniswap-v3-integration.test.ts +++ b/src/dex/uniswap-v3/uniswap-v3-integration.test.ts @@ -1099,6 +1099,4 @@ describe('SushiSwapV3', () => { checkPoolsLiquidity(poolLiquidity, TokenB.address, dexKey); }); }); - }); - diff --git a/src/lib/api3-feed.ts b/src/lib/api3-feed.ts index 588204372..c0a7b90e8 100644 --- a/src/lib/api3-feed.ts +++ b/src/lib/api3-feed.ts @@ -51,6 +51,14 @@ export class Api3FeedSubscriber extends PartialEventSubscriber< }; } + static getDapiNameHashMultiCallInput(proxy: Address): MultiCallInput { + return { + target: proxy, + callData: + Api3FeedSubscriber.proxyInterface.encodeFunctionData('dapiNameHash'), + }; + } + static getDataFeedId(proxy: Address): MultiCallInput { return { target: proxy, @@ -59,6 +67,33 @@ export class Api3FeedSubscriber extends PartialEventSubscriber< }; } + static getFeedIdFromDapiNameHash( + api3Server: Address, + dapiNameHash: string, + ): MultiCallInput { + return { + target: api3Server, + callData: Api3FeedSubscriber.api3ServerV1Iface.encodeFunctionData( + 'dapiNameHashToDataFeedId', + [dapiNameHash], + ), + }; + } + + static decodeFeedIdFromDapiNameHash(multicallOutput: MultiCallOutput) { + return Api3FeedSubscriber.api3ServerV1Iface.decodeFunctionResult( + 'dapiNameHashToDataFeedId', + multicallOutput, + )[0]; + } + + static decodeDapiNameHash(multicallOutput: MultiCallOutput) { + return Api3FeedSubscriber.proxyInterface.decodeFunctionResult( + 'dapiNameHash', + multicallOutput, + )[0]; + } + static decodeDataFeedId(multicallOutput: MultiCallOutput) { return Api3FeedSubscriber.proxyInterface.decodeFunctionResult( 'dataFeedId',