Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BACK-1275: Implement fix for QuickPerps #501

Merged
merged 12 commits into from
Sep 27, 2023
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@paraswap/dex-lib",
"version": "2.36.0",
"version": "2.36.1",
"main": "build/index.js",
"types": "build/index.d.ts",
"repository": "https://github.com/paraswap/paraswap-dex-lib",
Expand Down
7 changes: 7 additions & 0 deletions src/abi/api3-proxy.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,12 @@
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "dapiNameHash",
"outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
"stateMutability": "view",
"type": "function"
}
]
14 changes: 6 additions & 8 deletions src/dex/balancer-v2/balancer-v2-e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -37,13 +41,7 @@ function testForNetwork(
ContractMethod.megaSwap,
],
],
[
SwapSide.BUY,
[
ContractMethod.simpleBuy,
ContractMethod.buy,
],
],
[SwapSide.BUY, [ContractMethod.simpleBuy, ContractMethod.buy]],
]);

describe(`${network}`, () => {
Expand Down
2 changes: 1 addition & 1 deletion src/dex/balancer-v2/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,5 +80,5 @@ export const Adapters: Record<number, AdapterMappings> = {
[Network.BASE]: {
[SwapSide.SELL]: [{ name: 'BaseAdapter01', index: 4 }],
[SwapSide.BUY]: [{ name: 'BaseBuyAdapter', index: 3 }],
}
},
};
8 changes: 1 addition & 7 deletions src/dex/maverick-v1/maverick-v1-e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,7 @@ function testForNetwork(
ContractMethod.megaSwap,
],
],
[
SwapSide.BUY,
[
ContractMethod.simpleBuy,
ContractMethod.buy,
],
],
[SwapSide.BUY, [ContractMethod.simpleBuy, ContractMethod.buy]],
]);

describe(`${network}`, () => {
Expand Down
8 changes: 1 addition & 7 deletions src/dex/pancakeswap-v3/pancakeswap-v3-e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,7 @@ function testForNetwork(
ContractMethod.megaSwap,
],
],
[
SwapSide.BUY,
[
ContractMethod.simpleBuy,
ContractMethod.buy,
],
],
[SwapSide.BUY, [ContractMethod.simpleBuy, ContractMethod.buy]],
]);

describe(`${network}`, () => {
Expand Down
49 changes: 42 additions & 7 deletions src/dex/quick-perps/pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ export class QuickPerpsEventPool extends ComposedEventSubscriber<PoolState> {
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;
}
Expand Down Expand Up @@ -283,7 +284,8 @@ export class QuickPerpsEventPool extends ComposedEventSubscriber<PoolState> {
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;
Expand Down Expand Up @@ -315,24 +317,31 @@ export class QuickPerpsEventPool extends ComposedEventSubscriber<PoolState> {
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,
};
}

Expand All @@ -355,6 +364,32 @@ export class QuickPerpsEventPool extends ComposedEventSubscriber<PoolState> {
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,
Expand Down
1 change: 0 additions & 1 deletion src/dex/quick-perps/quick-perps-events.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ describe('QuickPerps Event', function () {
dexKey,
network,
dexHelper,
logger,
config,
);
await testEventSubscriber(
Expand Down
80 changes: 45 additions & 35 deletions src/dex/quick-perps/quick-perps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,45 +117,55 @@ export class QuickPerps extends SimpleExchange implements IDex<QuickPerpsData> {
limitPools?: string[],
): Promise<null | ExchangePrices<QuickPerpsData>> {
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
Expand Down
2 changes: 1 addition & 1 deletion src/dex/solidly/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,5 +204,5 @@ export const Adapters: Record<number, AdapterMappings> = {
},
[Network.BASE]: {
[SwapSide.SELL]: [{ name: 'BaseAdapter01', index: 3 }], // aerodrome, equalizer
}
},
};
6 changes: 1 addition & 5 deletions src/dex/solidly/forks-override/aerodrome.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
3 changes: 1 addition & 2 deletions src/dex/uniswap-v3/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,7 @@ export const UniswapV3Config: DexConfigMap<DexParams> = {
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: {
Expand Down
8 changes: 1 addition & 7 deletions src/dex/uniswap-v3/uniswap-v3-e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) =>
Expand Down
2 changes: 0 additions & 2 deletions src/dex/uniswap-v3/uniswap-v3-integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1099,6 +1099,4 @@ describe('SushiSwapV3', () => {
checkPoolsLiquidity(poolLiquidity, TokenB.address, dexKey);
});
});

});

35 changes: 35 additions & 0 deletions src/lib/api3-feed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ export class Api3FeedSubscriber<State> extends PartialEventSubscriber<
};
}

static getDapiNameHashMultiCallInput(proxy: Address): MultiCallInput {
return {
target: proxy,
callData:
Api3FeedSubscriber.proxyInterface.encodeFunctionData('dapiNameHash'),
};
}

static getDataFeedId(proxy: Address): MultiCallInput {
return {
target: proxy,
Expand All @@ -59,6 +67,33 @@ export class Api3FeedSubscriber<State> 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',
Expand Down
Loading