diff --git a/package.json b/package.json index 33ca7b290..507d3aed1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@paraswap/dex-lib", - "version": "3.11.10-stader.0", + "version": "3.11.10", "main": "build/index.js", "types": "build/index.d.ts", "repository": "https://github.com/paraswap/paraswap-dex-lib", diff --git a/src/dex/pancakeswap-v3/pancakeswap-v3-pool.ts b/src/dex/pancakeswap-v3/pancakeswap-v3-pool.ts index fc2fdb9f1..a97d99297 100644 --- a/src/dex/pancakeswap-v3/pancakeswap-v3-pool.ts +++ b/src/dex/pancakeswap-v3/pancakeswap-v3-pool.ts @@ -250,6 +250,33 @@ export class PancakeSwapV3EventPool extends StatefulEventSubscriber { return TICK_BITMAP_TO_USE + TICK_BITMAP_BUFFER; } + async checkState( + blockNumber: number, + ): Promise | null> { + const state = this.getState(blockNumber); + if (state) { + return state; + } + + this.logger.error( + `PancakeV3: No state found for ${this.name} ${this.addressesSubscribed[0]} for bn: ${blockNumber}`, + ); + return null; + } + + _setState(state: any, blockNumber: number, reason?: string): void { + if (this.parentName === 'PancakeswapV3') { + this.logger.info( + `PancakeV3: Setting state: ${!!state ? 'non-empty' : 'empty'} for '${ + this.name + }' for bn: '${blockNumber}' due to reason: '${ + reason ?? 'outside_of_event_subscriber' + }'`, + ); + } + super._setState(state, blockNumber); + } + async generateState(blockNumber: number): Promise> { const callData = this._getStateRequestCallData(); diff --git a/src/dex/pancakeswap-v3/pancakeswap-v3.ts b/src/dex/pancakeswap-v3/pancakeswap-v3.ts index fc267ad0f..ccc3ddc26 100644 --- a/src/dex/pancakeswap-v3/pancakeswap-v3.ts +++ b/src/dex/pancakeswap-v3/pancakeswap-v3.ts @@ -613,6 +613,10 @@ export class PancakeswapV3 if (selectedPools.length === 0) return null; + await Promise.all( + selectedPools.map(pool => pool.checkState(blockNumber)), + ); + const poolsToUse = selectedPools.reduce( (acc, pool) => { let state = pool.getState(blockNumber); @@ -632,6 +636,12 @@ export class PancakeswapV3 }, ); + poolsToUse.poolWithoutState.forEach(pool => { + this.logger.warn( + `PancakeV3: Pool ${pool.name} on ${this.dexKey} has no state. Fallback to rpc`, + ); + }); + const rpcResultsPromise = this.getPricingFromRpc( _srcToken, _destToken, diff --git a/src/dex/uniswap-v3/uniswap-v3-pool.ts b/src/dex/uniswap-v3/uniswap-v3-pool.ts index 2110470b2..c050eb4d7 100644 --- a/src/dex/uniswap-v3/uniswap-v3-pool.ts +++ b/src/dex/uniswap-v3/uniswap-v3-pool.ts @@ -254,6 +254,33 @@ export class UniswapV3EventPool extends StatefulEventSubscriber { return TICK_BITMAP_TO_USE + TICK_BITMAP_BUFFER; } + async checkState( + blockNumber: number, + ): Promise | null> { + const state = this.getState(blockNumber); + if (state) { + return state; + } + + this.logger.error( + `UniV3: No state found for ${this.name} ${this.addressesSubscribed[0]} for bn: ${blockNumber}`, + ); + return null; + } + + _setState(state: any, blockNumber: number, reason?: string): void { + if (this.parentName === 'UniswapV3') { + this.logger.info( + `UniV3: Setting state: '${!!state ? 'non-empty' : 'empty'}' for '${ + this.name + }' for bn: '${blockNumber}' due to reason: '${ + reason ?? 'outside_of_event_subscriber' + }'`, + ); + } + super._setState(state, blockNumber); + } + async generateState(blockNumber: number): Promise> { const callData = this._getStateRequestCallData(); diff --git a/src/dex/uniswap-v3/uniswap-v3.ts b/src/dex/uniswap-v3/uniswap-v3.ts index 40defeeae..91eeb74c0 100644 --- a/src/dex/uniswap-v3/uniswap-v3.ts +++ b/src/dex/uniswap-v3/uniswap-v3.ts @@ -715,6 +715,10 @@ export class UniswapV3 if (selectedPools.length === 0) return null; + await Promise.all( + selectedPools.map(pool => pool.checkState(blockNumber)), + ); + const poolsToUse = selectedPools.reduce( (acc, pool) => { let state = pool.getState(blockNumber); @@ -722,6 +726,7 @@ export class UniswapV3 this.logger.trace( `${this.dexKey}: State === null. Fallback to rpc ${pool.name}`, ); + // as we generate state (if nullified) in previous Promise.all, here should only be pools with failed initialization acc.poolWithoutState.push(pool); } else { acc.poolWithState.push(pool); @@ -734,6 +739,12 @@ export class UniswapV3 }, ); + poolsToUse.poolWithoutState.forEach(pool => { + this.logger.warn( + `UniV3: Pool ${pool.name} on ${this.dexKey} has no state. Fallback to rpc`, + ); + }); + const states = poolsToUse.poolWithState.map( p => p.getState(blockNumber)!, ); diff --git a/src/stateful-event-subscriber.ts b/src/stateful-event-subscriber.ts index f89d6a11a..3705cc3f2 100644 --- a/src/stateful-event-subscriber.ts +++ b/src/stateful-event-subscriber.ts @@ -89,14 +89,14 @@ export abstract class StatefulEventSubscriber ) { let masterBn: undefined | number = undefined; if (options && options.state) { - this.setState(options.state, blockNumber); + this.setState(options.state, blockNumber, 'initialize_1'); } else if (options && options.forceRegenerate) { // ZkEVM forces to always regenerate state when it is old this.logger.debug( `${this.parentName}: ${this.name}: forced to regenerate state`, ); const state = await this.generateState(blockNumber); - this.setState(state, blockNumber); + this.setState(state, blockNumber, 'initialize_2'); } else { if (this.dexHelper.config.isSlave && this.masterPoolNeeded) { let stateAsString = await this.dexHelper.cache.hget( @@ -135,14 +135,14 @@ export abstract class StatefulEventSubscriber } // set state and the according blockNumber. state.bn can be smaller, greater or equal // to blockNumber - this.setState(state.state, blockNumber); + this.setState(state.state, blockNumber, 'initialize_3'); } else { // if no state found in cache generate new state using rpc this.logger.info( `${this.parentName}: ${this.name}: did not found state on cache generating new one`, ); const state = await this.generateState(blockNumber); - this.setState(state, blockNumber); + this.setState(state, blockNumber, 'initialize_4'); // we should publish only if generateState succeeded const data = this.getPoolIdentifierData(); @@ -161,7 +161,7 @@ export abstract class StatefulEventSubscriber `${this.parentName}: ${this.name}: cache generating state`, ); const state = await this.generateState(blockNumber); - this.setState(state, blockNumber); + this.setState(state, blockNumber, 'initialize_5'); } } @@ -235,7 +235,7 @@ export abstract class StatefulEventSubscriber this.logger.info( `StatefulEventSubscriber_1 restart, bn: ${blockNumber}, state_bn: ${this.stateBlockNumber}: ${this.parentName}: ${this.name}`, ); - this._setState(null, blockNumber); + this._setState(null, blockNumber, 'restart'); } } @@ -275,7 +275,7 @@ export abstract class StatefulEventSubscriber } if (!this.state) { const freshState = await this.generateState(blockNumber); - this.setState(freshState, blockNumber); + this.setState(freshState, blockNumber, 'update_1'); } //Find the last state before the blockNumber of the logs let stateBeforeLog: DeepReadonly | undefined; @@ -291,7 +291,7 @@ export abstract class StatefulEventSubscriber logs.slice(index, indexBlockEnd), blockHeader, ); - if (nextState) this.setState(nextState, blockNumber); + if (nextState) this.setState(nextState, blockNumber, 'update_2'); } lastBlockNumber = blockNumber; index = indexBlockEnd; @@ -315,7 +315,7 @@ export abstract class StatefulEventSubscriber ); try { const state = await this.generateState(latestBlockNumber); - this.setState(state, latestBlockNumber); + this.setState(state, latestBlockNumber, 'update_3'); return true; } catch (e) { this.logger.error( @@ -346,12 +346,12 @@ export abstract class StatefulEventSubscriber } if (lastBn) { - this._setState(this.stateHistory[lastBn], lastBn); + this._setState(this.stateHistory[lastBn], lastBn, 'rollback_1'); } else { this.logger.info( `StatefulEventSubscriber_1 rollback, bn: ${blockNumber}: ${this.parentName}: ${this.name}`, ); - this._setState(null, blockNumber); + this._setState(null, blockNumber, 'rollback_2'); } } else { //Keep the current state in this.state and in the history @@ -390,7 +390,11 @@ export abstract class StatefulEventSubscriber return this.state; } - _setState(state: DeepReadonly | null, blockNumber: number) { + _setState( + state: DeepReadonly | null, + blockNumber: number, + reason?: string, + ) { if ( this.dexHelper.config.isSlave && this.masterPoolNeeded && @@ -418,7 +422,7 @@ export abstract class StatefulEventSubscriber `${this.parentName}: received state from a scheduled job`, 'info', ); - this.setState(state.state, state.bn); + this.setState(state.state, state.bn, 'addBatchHGet'); return true; }, ); @@ -481,14 +485,18 @@ export abstract class StatefulEventSubscriber //no longer needed. If the blockNumber is greater than or equal to the //current state, then the current state will be updated and the invalid flag //can be reset. - setState(state: DeepReadonly, blockNumber: number): void { + setState( + state: DeepReadonly, + blockNumber: number, + reason?: string, + ): void { if (!blockNumber) { this.logger.error('setState() with blockNumber', blockNumber); return; } this.stateHistory[blockNumber] = state; if (!this.state || blockNumber >= this.stateBlockNumber) { - this._setState(state, blockNumber); + this._setState(state, blockNumber, reason); this.invalid = false; } const minBlockNumberToKeep = this.stateBlockNumber - MAX_BLOCKS_HISTORY;