@@ -66,27 +66,50 @@ const makeDataService = () => {
6666 RelayerRegistered : events . map ( ( e ) => relayerRegistered ( BigInt ( e . blockNumber ) ) ) ,
6767 } ) ) ;
6868
69+ const getContractDeploymentBlock = vi . fn ( async ( ) => 42n ) ;
70+
6971 return {
7072 getBlockNumber : vi . fn ( async ( ) => HEAD ) ,
7173 getPoolEvents,
7274 parsePoolEvents,
7375 getRelayerRegistryEvents,
7476 parseRelayerRegistryEvents,
77+ getContractDeploymentBlock,
7578 } as unknown as IDataService & {
7679 getPoolEvents : typeof getPoolEvents ;
7780 parsePoolEvents : typeof parsePoolEvents ;
7881 getRelayerRegistryEvents : typeof getRelayerRegistryEvents ;
7982 parseRelayerRegistryEvents : typeof parseRelayerRegistryEvents ;
83+ getContractDeploymentBlock : typeof getContractDeploymentBlock ;
8084 } ;
8185} ;
8286
83- const makeProvider = ( coverage : bigint | null , events : ExternalRawEvent [ ] = [ ] ) => {
87+ const makeProvider = (
88+ coverage : bigint | null ,
89+ events : ExternalRawEvent [ ] = [ ] ,
90+ firstBlock : bigint | null = null ,
91+ ) => {
8492 const getEvents = vi . fn ( async ( ) => events ) ;
8593
8694 return {
87- lastCoveredBlock : vi . fn ( async ( ) => ( coverage == null ? null : toHex ( coverage ) ) ) ,
95+ // Coverage methods throw (rather than return null) when the provider has no
96+ // data for the pool.
97+ lastCoveredBlock : vi . fn ( async ( ) => {
98+ if ( coverage == null ) throw new Error ( 'no coverage' ) ;
99+
100+ return toHex ( coverage ) ;
101+ } ) ,
102+ firstCoveredBlock : vi . fn ( async ( ) => {
103+ if ( firstBlock == null ) throw new Error ( 'no coverage' ) ;
104+
105+ return toHex ( firstBlock ) ;
106+ } ) ,
88107 getEvents,
89- } as unknown as ExternalSyncClient & { getEvents : typeof getEvents } ;
108+ } as unknown as ExternalSyncClient & {
109+ getEvents : typeof getEvents ;
110+ lastCoveredBlock : ReturnType < typeof vi . fn > ;
111+ firstCoveredBlock : ReturnType < typeof vi . fn > ;
112+ } ;
90113} ;
91114
92115const rawAt = ( block : bigint ) : ExternalRawEvent => ( {
@@ -235,3 +258,48 @@ describe('SyncService.getRelayerRegistryEvents', () => {
235258 expect ( result . RelayerRegistered . map ( ( r ) => r . blockNumber ) ) . toEqual ( [ 100n ] ) ;
236259 } ) ;
237260} ) ;
261+
262+ describe ( 'SyncService.getPoolDeploymentBlock' , ( ) => {
263+ it ( "uses the provider's first covered block, skipping the on-chain search" , async ( ) => {
264+ const dataService = makeDataService ( ) ;
265+ const provider = makeProvider ( 600n , [ ] , 12345n ) ;
266+ const service = new SyncService ( {
267+ dataService,
268+ externalSyncProvider : provider ,
269+ minExternalSyncBlocksAmount : 100 ,
270+ } ) ;
271+
272+ const block = await service . getPoolDeploymentBlock ( { chainId : CHAIN_ID , address : POOL } ) ;
273+
274+ expect ( block ) . toBe ( 12345n ) ;
275+ expect ( provider . firstCoveredBlock ) . toHaveBeenCalledWith (
276+ expect . objectContaining ( { chainId : toHex ( CHAIN_ID ) } ) ,
277+ ) ;
278+ expect ( dataService . getContractDeploymentBlock ) . not . toHaveBeenCalled ( ) ;
279+ } ) ;
280+
281+ it ( 'falls back to the on-chain deployment block when the provider has no coverage' , async ( ) => {
282+ const dataService = makeDataService ( ) ;
283+ const provider = makeProvider ( 600n , [ ] , null ) ; // firstCoveredBlock throws
284+ const service = new SyncService ( {
285+ dataService,
286+ externalSyncProvider : provider ,
287+ minExternalSyncBlocksAmount : 100 ,
288+ } ) ;
289+
290+ const block = await service . getPoolDeploymentBlock ( { chainId : CHAIN_ID , address : POOL } ) ;
291+
292+ expect ( block ) . toBe ( 42n ) ;
293+ expect ( dataService . getContractDeploymentBlock ) . toHaveBeenCalledWith ( POOL ) ;
294+ } ) ;
295+
296+ it ( 'falls back to the on-chain deployment block when no provider is configured' , async ( ) => {
297+ const dataService = makeDataService ( ) ;
298+ const service = new SyncService ( { dataService } ) ;
299+
300+ const block = await service . getPoolDeploymentBlock ( { chainId : CHAIN_ID , address : POOL } ) ;
301+
302+ expect ( block ) . toBe ( 42n ) ;
303+ expect ( dataService . getContractDeploymentBlock ) . toHaveBeenCalledWith ( POOL ) ;
304+ } ) ;
305+ } ) ;
0 commit comments