Skip to content

Commit

Permalink
Merge pull request paraswap#444 from paraswap/fix/algebra-z-rpc
Browse files Browse the repository at this point in the history
Fix/algebra z rpc
  • Loading branch information
mwamedacen authored Jul 20, 2023
2 parents bbba7f5 + 8cdb722 commit ce0b2b1
Show file tree
Hide file tree
Showing 12 changed files with 255 additions and 164 deletions.
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.25.1",
"version": "2.26.0",
"main": "build/index.js",
"types": "build/index.d.ts",
"repository": "https://github.com/paraswap/paraswap-dex-lib",
Expand Down
3 changes: 3 additions & 0 deletions src/dex/algebra/algebra-pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ export class AlgebraEventPool extends StatefulEventSubscriber<PoolState> {

public readonly poolIface = new Interface(AlgebraABI);

public initFailed = false;
public initRetryAttemptCount = 0;

constructor(
readonly dexHelper: IDexHelper,
parentName: string,
Expand Down
130 changes: 77 additions & 53 deletions src/dex/algebra/algebra.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,13 +131,33 @@ export class Algebra extends SimpleExchange implements IDex<AlgebraData> {
destAddress: Address,
blockNumber: number,
): Promise<AlgebraEventPool | null> {
let pool = this.eventPools[this.getPoolIdentifier(srcAddress, destAddress)];
let pool = this.eventPools[
this.getPoolIdentifier(srcAddress, destAddress)
] as AlgebraEventPool | null | undefined;

if (pool === undefined) {
const [token0, token1] = this._sortTokens(srcAddress, destAddress);
if (pool === null) return null;

const key = `${token0}_${token1}`.toLowerCase();
if (pool) {
if (!pool.initFailed) {
return pool;
} else {
// if init failed then prefer to early return pool with empty state to fallback to rpc call
if (
++pool.initRetryAttemptCount % this.config.initRetryFrequency !==
0
) {
return pool;
}
// else pursue with re-try initialization
}
}

const [token0, token1] = this._sortTokens(srcAddress, destAddress);

const key = `${token0}_${token1}`.toLowerCase();

// no need to run this logic on retry initialisation scenario
if (!pool) {
const notExistingPoolScore = await this.dexHelper.cache.zscore(
this.notExistingPoolSetKey,
key,
Expand All @@ -158,9 +178,12 @@ export class Algebra extends SimpleExchange implements IDex<AlgebraData> {
token1,
}),
);
}

this.logger.trace(`starting to listen to new pool: ${key}`);
pool = new AlgebraEventPool(
this.logger.trace(`starting to listen to new pool: ${key}`);
pool =
pool ||
new AlgebraEventPool(
this.dexHelper,
this.dexKey,
this.stateMultiContract,
Expand All @@ -174,58 +197,56 @@ export class Algebra extends SimpleExchange implements IDex<AlgebraData> {
this.config.deployer,
);

try {
await pool.initialize(blockNumber, {
initCallback: (state: DeepReadonly<PoolState>) => {
//really hacky, we need to push poolAddress so that we subscribeToLogs in StatefulEventSubscriber
pool!.addressesSubscribed[0] = state.pool;
pool!.poolAddress = state.pool;
},
});
} catch (e) {
if (
// most zkEVM rpcs fails with "cannot execute unsigned transaction" issue. Prefer to flag pool as non existing instaed of trying to generateState on earch round
this.network === Network.ZKEVM ||
(e instanceof Error && e.message.endsWith('Pool does not exist'))
) {
// no need to await we want the set to have the pool key but it's not blocking
this.dexHelper.cache.zadd(
this.notExistingPoolSetKey,
[Date.now(), key],
'NX',
);

// Pool does not exist for this pair, so we can set it to null
// to prevent more requests for this pool
pool = null;
this.logger.trace(
`${this.dexHelper}: Pool: srcAddress=${srcAddress}, destAddress=${destAddress} not found`,
e,
);
} else {
// Unexpected Error. Break execution. Do not save the pool in this.eventPools
this.logger.error(
`${this.dexKey}: Can not generate pool state for srcAddress=${srcAddress}, destAddress=${destAddress}pool`,
e,
);
throw new Error('Cannot generate pool state');
}
}
try {
await pool.initialize(blockNumber, {
initCallback: (state: DeepReadonly<PoolState>) => {
//really hacky, we need to push poolAddress so that we subscribeToLogs in StatefulEventSubscriber
pool!.addressesSubscribed[0] = state.pool;
pool!.poolAddress = state.pool;
pool!.initFailed = false;
pool!.initRetryAttemptCount = 0;
},
});
} catch (e) {
if (e instanceof Error && e.message.endsWith('Pool does not exist')) {
// no need to await we want the set to have the pool key but it's not blocking
this.dexHelper.cache.zadd(
this.notExistingPoolSetKey,
[Date.now(), key],
'NX',
);

if (pool !== null) {
const allEventPools = Object.values(this.eventPools);
this.logger.info(
`starting to listen to new non-null pool: ${key}. Already following ${allEventPools
// Not that I like this reduce, but since it is done only on initialization, expect this to be ok
.reduce(
(acc, curr) => (curr !== null ? ++acc : acc),
0,
)} non-null pools or ${allEventPools.length} total pools`,
// Pool does not exist for this pair, so we can set it to null
// to prevent more requests for this pool
pool = null;
this.logger.trace(
`${this.dexHelper}: Pool: srcAddress=${srcAddress}, destAddress=${destAddress} not found`,
e,
);
} else {
// on unkown error mark as failed and increase retryCount for retry init strategy
// note: state would be null by default which allows to fallback
this.logger.warn(
`${this.dexKey}: Can not generate pool state for srcAddress=${srcAddress}, destAddress=${destAddress}pool fallback to rpc and retry every ${this.config.initRetryFrequency} times, initRetryAttemptCount=${pool.initRetryAttemptCount}`,
e,
);
pool.initFailed = true;
}
}

this.eventPools[this.getPoolIdentifier(srcAddress, destAddress)] = pool;
if (pool !== null) {
const allEventPools = Object.values(this.eventPools);
this.logger.info(
`starting to listen to new non-null pool: ${key}. Already following ${allEventPools
// Not that I like this reduce, but since it is done only on initialization, expect this to be ok
.reduce(
(acc, curr) => (curr !== null ? ++acc : acc),
0,
)} non-null pools or ${allEventPools.length} total pools`,
);
}

this.eventPools[this.getPoolIdentifier(srcAddress, destAddress)] = pool;
return pool;
}

Expand Down Expand Up @@ -400,6 +421,8 @@ export class Algebra extends SimpleExchange implements IDex<AlgebraData> {

const state = pool.getState(blockNumber);

if (state === null && this.network === Network.ZKEVM) return null; // never fallback as takes more time

if (state === null) {
const rpcPrice = await this.getPricingFromRpc(
_srcToken,
Expand Down Expand Up @@ -691,6 +714,7 @@ export class Algebra extends SimpleExchange implements IDex<AlgebraData> {
factory: this.config.factory.toLowerCase(),
algebraStateMulticall: this.config.algebraStateMulticall.toLowerCase(),
chunksCount: this.config.chunksCount,
initRetryFrequency: this.config.initRetryFrequency,
uniswapMulticall: this.config.uniswapMulticall,
deployer: this.config.deployer?.toLowerCase(),
initHash: this.config.initHash,
Expand Down
4 changes: 3 additions & 1 deletion src/dex/algebra/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const AlgebraConfig: DexConfigMap<DexParams> = {
initHash:
'0x6ec6c9c8091d160c0aa74b2b14ba9c1717e95093bd3ac085cee99a49aab294a4',
chunksCount: 10,
initRetryFrequency: 10,
algebraStateMulticall: '0xfb948e6e23eb58ec7320ddb60df9115de07141ec',
subgraphURL:
'https://api.thegraph.com/subgraphs/name/sameepsi/quickswap-v3',
Expand All @@ -23,7 +24,8 @@ export const AlgebraConfig: DexConfigMap<DexParams> = {
quoter: '0x55BeE1bD3Eb9986f6d2d963278de09eE92a3eF1D',
initHash:
'0x6ec6c9c8091d160c0aa74b2b14ba9c1717e95093bd3ac085cee99a49aab294a4',
chunksCount: 10,
chunksCount: 3,
initRetryFrequency: 30,
algebraStateMulticall: '0xa6bc273A238867dD74F2bBbD5fBbA3c941C939B9',
subgraphURL:
'https://api.studio.thegraph.com/query/44554/quickswap-v3-02/0.0.7',
Expand Down
1 change: 1 addition & 0 deletions src/dex/algebra/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export type DexParams = {
algebraStateMulticall: Address;
uniswapMulticall: Address;
chunksCount: number;
initRetryFrequency: number;
deployer: Address;
subgraphURL: string;
initHash: string;
Expand Down
2 changes: 2 additions & 0 deletions src/dex/pancakeswap-v3/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const PancakeswapV3Config: DexConfigMap<DexParams> = {
stateMulticall: '0x80898f80cFA3Fa3AbF410d90e69aDc432AE5D4c2',
uniswapMulticall: '0xac1cE734566f390A94b00eb9bf561c2625BF44ea',
chunksCount: 10,
initRetryFrequency: 10,
initHash:
'0x6ce8eb472fa82df5469c6ab6d485f17c3ad13c8cd7af59b3d4a8026c5ce0f7e2',
subgraphURL:
Expand All @@ -31,6 +32,7 @@ export const PancakeswapV3Config: DexConfigMap<DexParams> = {
stateMulticall: '0x9DAd2ED7ADc6eaacf81589Cd043579c9684E5C81',
uniswapMulticall: '0xac1cE734566f390A94b00eb9bf561c2625BF44ea',
chunksCount: 10,
initRetryFrequency: 30,
initHash:
'0x6ce8eb472fa82df5469c6ab6d485f17c3ad13c8cd7af59b3d4a8026c5ce0f7e2',
subgraphURL:
Expand Down
3 changes: 3 additions & 0 deletions src/dex/pancakeswap-v3/pancakeswap-v3-pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ export class PancakeSwapV3EventPool extends StatefulEventSubscriber<PoolState> {

public readonly poolIface = new Interface(PancakeswapV3PoolABI);

public initFailed = false;
public initRetryAttemptCount = 0;

public readonly feeCodeAsString;

constructor(
Expand Down
Loading

0 comments on commit ce0b2b1

Please sign in to comment.