@@ -6,7 +6,7 @@ import { fetchState, decodeFillStatusAccount } from "@across-protocol/contracts/
6
6
import { SvmCpiEventsClient } from "./eventsClient" ;
7
7
import { Deposit , FillStatus , FillWithBlock , RelayData } from "../../interfaces" ;
8
8
import { BigNumber , chainIsSvm , chunk , isUnsafeDepositId } from "../../utils" ;
9
- import { getFillStatusPda } from "./utils" ;
9
+ import { getFillStatusPda , unwrapEventData } from "./utils" ;
10
10
import { SVMEventNames } from "./types" ;
11
11
12
12
type Provider = Rpc < SolanaRpcApi > ;
@@ -224,30 +224,53 @@ export async function fillStatusArray(
224
224
}
225
225
226
226
/**
227
- * Find the block at which a fill was completed.
228
- * @todo After SpokePool upgrade, this function can be simplified to use the FillStatus enum.
229
- * @param spokePool SpokePool contract instance.
230
- * @param relayData Deposit information that is used to complete a fill.
231
- * @param lowBlockNumber The lower bound of the search. Must be bounded by SpokePool deployment.
232
- * @param highBlocknumber Optional upper bound for the search.
233
- * @returns The block number at which the relay was completed, or undefined.
227
+ * Finds the `FilledRelay` event for a given deposit within the provided slot range.
228
+ *
229
+ * @param relayData - Deposit information that is used to complete a fill.
230
+ * @param destinationChainId - Destination chain ID (must be an SVM chain).
231
+ * @param svmEventsClient - SVM events client instance for querying events.
232
+ * @param fromSlot - Starting slot to search.
233
+ * @param toSlot (Optional) Ending slot to search. If not provided, the current confirmed slot will be used.
234
+ * @returns The fill event with block info, or `undefined` if not found.
234
235
*/
235
- export function findFillBlock (
236
- _spokePool : unknown ,
237
- _relayData : RelayData ,
238
- _lowBlockNumber : number ,
239
- _highBlockNumber ?: number
240
- ) : Promise < number | undefined > {
241
- throw new Error ( "fillStatusArray: not implemented" ) ;
242
- }
243
-
244
- export function findFillEvent (
245
- _spokePool : unknown ,
246
- _relayData : RelayData ,
247
- _lowBlockNumber : number ,
248
- _highBlockNumber ?: number
236
+ export async function findFillEvent (
237
+ relayData : RelayData ,
238
+ destinationChainId : number ,
239
+ svmEventsClient : SvmCpiEventsClient ,
240
+ fromSlot : number ,
241
+ toSlot ?: number
249
242
) : Promise < FillWithBlock | undefined > {
250
- throw new Error ( "fillStatusArray: not implemented" ) ;
243
+ assert ( chainIsSvm ( destinationChainId ) , "Destination chain must be an SVM chain" ) ;
244
+ toSlot ??= Number ( await svmEventsClient . getRpc ( ) . getSlot ( { commitment : "confirmed" } ) . send ( ) ) ;
245
+
246
+ // Get fillStatus PDA using relayData
247
+ const programId = svmEventsClient . getProgramAddress ( ) ;
248
+ const fillStatusPda = await getFillStatusPda ( programId , relayData , destinationChainId ) ;
249
+
250
+ // Get fill events from fillStatus PDA
251
+ const fillEvents = await svmEventsClient . queryDerivedAddressEvents (
252
+ SVMEventNames . FilledRelay ,
253
+ fillStatusPda ,
254
+ BigInt ( fromSlot ) ,
255
+ BigInt ( toSlot ) ,
256
+ { limit : 10 }
257
+ ) ;
258
+ assert ( fillEvents . length <= 1 , `Expected at most one fill event for ${ fillStatusPda } , got ${ fillEvents . length } ` ) ;
259
+
260
+ if ( fillEvents . length > 0 ) {
261
+ const rawFillEvent = fillEvents [ 0 ] ;
262
+ const parsedFillEvent = {
263
+ transactionHash : rawFillEvent . signature ,
264
+ blockNumber : Number ( rawFillEvent . slot ) ,
265
+ transactionIndex : 0 ,
266
+ logIndex : 0 ,
267
+ destinationChainId,
268
+ ...( unwrapEventData ( rawFillEvent . data ) as Record < string , unknown > ) ,
269
+ } as unknown as FillWithBlock ;
270
+ return parsedFillEvent ;
271
+ }
272
+
273
+ return undefined ;
251
274
}
252
275
253
276
async function resolveFillStatusFromPdaEvents (
0 commit comments