diff --git a/src/arch/svm/SpokeUtils.ts b/src/arch/svm/SpokeUtils.ts index 8eb4bee31..2b6923185 100644 --- a/src/arch/svm/SpokeUtils.ts +++ b/src/arch/svm/SpokeUtils.ts @@ -1,6 +1,8 @@ -import { Rpc, SolanaRpcApi } from "@solana/kit"; +import { Rpc, SolanaRpcApi, Address } from "@solana/kit"; + import { Deposit, FillStatus, FillWithBlock, RelayData } from "../../interfaces"; import { BigNumber, isUnsafeDepositId } from "../../utils"; +import { fetchState } from "@across-protocol/contracts/dist/src/svm/clients/SvmSpoke"; type Provider = Rpc; @@ -46,18 +48,14 @@ export async function getTimestampForBlock(provider: Provider, blockNumber: numb } /** - * Return maximum of fill deadline buffer at start and end of block range. - * @param spokePool SpokePool contract instance - * @param startBlock start block - * @param endBlock end block - * @returns maximum of fill deadline buffer at start and end block + * Returns the current fill deadline buffer. + * @param provider SVM Provider instance + * @param statePda Spoke Pool's State PDA + * @returns fill deadline buffer */ -export function getMaxFillDeadlineInRange( - _spokePool: unknown, - _startBlock: number, - _endBlock: number -): Promise { - throw new Error("getMaxFillDeadlineInRange: not implemented"); +export async function getFillDeadline(provider: Provider, statePda: Address): Promise { + const state = await fetchState(provider, statePda); + return state.data.fillDeadlineBuffer; } /** diff --git a/src/arch/svm/eventsClient.ts b/src/arch/svm/eventsClient.ts index 1be71c10f..42d51ece8 100644 --- a/src/arch/svm/eventsClient.ts +++ b/src/arch/svm/eventsClient.ts @@ -209,4 +209,8 @@ export class SvmSpokeEventsClient { return events; } + + public getSvmSpokeAddress(): Address { + return this.svmSpokeAddress; + } } diff --git a/src/arch/svm/utils.ts b/src/arch/svm/utils.ts index 5b1c18f7c..65fbbc44d 100644 --- a/src/arch/svm/utils.ts +++ b/src/arch/svm/utils.ts @@ -1,5 +1,6 @@ import { BN, BorshEventCoder, Idl } from "@coral-xyz/anchor"; -import web3, { address, RpcTransport } from "@solana/kit"; +import web3, { address, getProgramDerivedAddress, getU64Encoder, Address, RpcTransport } from "@solana/kit"; + import { EventName, EventData, SVMEventNames } from "./types"; /** @@ -64,3 +65,18 @@ export function getEventName(rawName: string): EventName { if (Object.values(SVMEventNames).some((name) => rawName.includes(name))) return rawName as EventName; throw new Error(`Unknown event name: ${rawName}`); } + +/** + * Returns the PDA for the State account. + * @param programId The SpokePool program ID. + * @returns The PDA for the State account. + */ +export async function getStatePda(programId: Address): Promise
{ + const intEncoder = getU64Encoder(); + const seed = intEncoder.encode(0); + const [statePda] = await getProgramDerivedAddress({ + programAddress: programId, + seeds: ["state", seed], + }); + return statePda; +} diff --git a/src/clients/SpokePoolClient/SVMSpokePoolClient.ts b/src/clients/SpokePoolClient/SVMSpokePoolClient.ts index 6e2dfd62b..b97a6ce4c 100644 --- a/src/clients/SpokePoolClient/SVMSpokePoolClient.ts +++ b/src/clients/SpokePoolClient/SVMSpokePoolClient.ts @@ -1,10 +1,18 @@ import winston from "winston"; -import { Rpc, SolanaRpcApiFromTransport, RpcTransport } from "@solana/kit"; +import { Address, Rpc, SolanaRpcApiFromTransport, RpcTransport } from "@solana/kit"; + import { BigNumber, DepositSearchResult, EventSearchConfig, MakeOptional } from "../../utils"; -import { SvmSpokeEventsClient, SVMEventNames } from "../../arch/svm"; +import { + SvmSpokeEventsClient, + SVMEventNames, + getFillDeadline, + getTimestampForBlock, + getStatePda, +} from "../../arch/svm"; import { HubPoolClient } from "../HubPoolClient"; import { knownEventNames, SpokePoolClient, SpokePoolUpdate } from "./SpokePoolClient"; import { RelayData, FillStatus } from "../../interfaces"; + /** * SvmSpokePoolClient is a client for the SVM SpokePool program. It extends the base SpokePoolClient * and implements the abstract methods required for interacting with an SVM Spoke Pool. @@ -19,6 +27,8 @@ export class SvmSpokePoolClient extends SpokePoolClient { chainId: number, deploymentSlot: bigint, // Using slot instead of block number for SVM eventSearchConfig: MakeOptional, + protected programId: Address, + protected statePda: Address, protected svmEventsClient: SvmSpokeEventsClient, protected rpc: Rpc> ) { @@ -38,12 +48,16 @@ export class SvmSpokePoolClient extends SpokePoolClient { rpc: Rpc> ): Promise { const svmEventsClient = await SvmSpokeEventsClient.create(rpc); + const programId = svmEventsClient.getSvmSpokeAddress(); + const statePda = await getStatePda(programId); return new SvmSpokePoolClient( logger, hubPoolClient, chainId, deploymentSlot, eventSearchConfig, + programId, + statePda, svmEventsClient, rpc ); @@ -150,18 +164,18 @@ export class SvmSpokePoolClient extends SpokePoolClient { } /** - * Retrieves the maximum fill deadline buffer. - * TODO: Implement SVM equivalent, perhaps reading from a config account. + * Retrieves the fill deadline buffer fetched from the State PDA. + * @note This function assumes that fill deadline buffer is a constant value in svm environments. */ - public getMaxFillDeadlineInRange(_startSlot: number, _endSlot: number): Promise { - throw new Error("getMaxFillDeadlineInRange not implemented for SVM"); + public override getMaxFillDeadlineInRange(_startSlot: number, _endSlot: number): Promise { + return getFillDeadline(this.rpc, this.statePda); } /** * Retrieves the timestamp for a given SVM slot number. */ - public getTimestampForBlock(_blockNumber: number): Promise { - throw new Error("getTimestampForBlock not implemented for SVM"); + public override getTimestampForBlock(blockNumber: number): Promise { + return getTimestampForBlock(this.rpc, blockNumber); } /**