diff --git a/tee-apps/sealed-bid-auction/script/server.ts b/tee-apps/sealed-bid-auction/script/server.ts index 33c63d66..be51cb85 100644 --- a/tee-apps/sealed-bid-auction/script/server.ts +++ b/tee-apps/sealed-bid-auction/script/server.ts @@ -1,80 +1,97 @@ -import * as dotenv from "dotenv"; -import {AuctionApiServer} from "../src/api/AuctionApiServer.ts"; -import {ViemIntentObserver} from "../src/blockchain/ViemIntentObserver.ts"; -import {SolverPriceBook} from "../src/core/SolverPriceBook.ts"; -import {AuctionService} from "../src/core/AuctionService.ts"; -import {arbitrum, arbitrumSepolia, base, baseSepolia} from "viem/chains"; -import {BlockchainClient} from "../src/blockchain/BlockchainClient.ts"; +import * as dotenv from "dotenv" +import { AuctionApiServer } from "../src/api/AuctionApiServer.ts" +import { ViemIntentObserver } from "../src/blockchain/ViemIntentObserver.ts" +import { SolverPriceBook } from "../src/core/SolverPriceBook.ts" +import { AuctionService } from "../src/core/AuctionService.ts" +import { arbitrum, arbitrumSepolia, base, baseSepolia } from "viem/chains" +import { BlockchainClient } from "../src/blockchain/BlockchainClient.ts" -dotenv.config(); +dotenv.config() -const USE_TLS = process.env.USE_TLS as string === "true"; -const IS_MAINNET = process.env.IS_MAINNET as string === "true"; +const USE_TLS = (process.env.USE_TLS as string) === "true" +const IS_MAINNET = (process.env.IS_MAINNET as string) === "true" const SOLVER_PRICE_TTL_SECONDS = process.env.SOLVER_PRICE_TTL_SECONDS -const TEN_MINUTES_IN_SECONDS = 600; +const TEN_MINUTES_IN_SECONDS = 600 -const BASE_T1_ERC_7683_CONTRACT_ADDRESS = process.env.BASE_T1_ERC7683_CONTRACT_ADDRESS as `0x${string}`; -const ARBITRUM_T1_ERC_7683_CONTRACT_ADDRESS = process.env.ARBITRUM_T1_ERC7683_CONTRACT_ADDRESS as `0x${string}`; +const BASE_T1_ERC_7683_CONTRACT_ADDRESS = process.env + .BASE_T1_ERC7683_CONTRACT_ADDRESS as `0x${string}` +const ARBITRUM_T1_ERC_7683_CONTRACT_ADDRESS = process.env + .ARBITRUM_T1_ERC7683_CONTRACT_ADDRESS as `0x${string}` -const ARBITRUM_WS = (process.env.ARBITRUM_WS) as string; -const BASE_WS = (process.env.BASE_WS) as string; +const ARBITRUM_WS = process.env.ARBITRUM_WS as string +const BASE_WS = process.env.BASE_WS as string -const solverPriceBook = new SolverPriceBook(SOLVER_PRICE_TTL_SECONDS ? Number(SOLVER_PRICE_TTL_SECONDS as string) : TEN_MINUTES_IN_SECONDS); -const auctionService = new AuctionService(solverPriceBook); +const solverPriceBook = new SolverPriceBook( + SOLVER_PRICE_TTL_SECONDS + ? Number(SOLVER_PRICE_TTL_SECONDS as string) + : TEN_MINUTES_IN_SECONDS +) +const auctionService = new AuctionService(solverPriceBook) -const httpServer = new AuctionApiServer(solverPriceBook, auctionService); +const httpServer = new AuctionApiServer(solverPriceBook, auctionService) const arbitrumClient = new BlockchainClient( - ARBITRUM_WS, - IS_MAINNET ? arbitrum : arbitrumSepolia, - process.env.ARBITRUM_SIGNER_PRIVATE_KEY as `0x${string}` -); + ARBITRUM_WS, + IS_MAINNET ? arbitrum : arbitrumSepolia, + process.env.ARBITRUM_SIGNER_PRIVATE_KEY as `0x${string}` +) const baseClient = new BlockchainClient( - BASE_WS, - IS_MAINNET ? base : baseSepolia, - process.env.BASE_SIGNER_PRIVATE_KEY as `0x${string}` -); + BASE_WS, + IS_MAINNET ? base : baseSepolia, + process.env.BASE_SIGNER_PRIVATE_KEY as `0x${string}` +) + +const fromBlockEnv = process.env.INTENT_OBSERVER_FROM_BLOCK +const fromBlock = fromBlockEnv ? BigInt(fromBlockEnv) : null +const auctionPollingInterval = 500; + const arbitrumSepoliaIntentObserver = new ViemIntentObserver( - arbitrumClient, - ARBITRUM_T1_ERC_7683_CONTRACT_ADDRESS, - auctionService, - httpServer, - baseClient.publicClient.chain.id, - BASE_T1_ERC_7683_CONTRACT_ADDRESS -); + arbitrumClient, + ARBITRUM_T1_ERC_7683_CONTRACT_ADDRESS, + auctionService, + httpServer, + baseClient.publicClient.chain.id, + BASE_T1_ERC_7683_CONTRACT_ADDRESS, + auctionPollingInterval, + fromBlock +) const baseSepoliaIntentObserver = new ViemIntentObserver( - baseClient, - BASE_T1_ERC_7683_CONTRACT_ADDRESS, - auctionService, - httpServer, - arbitrumClient.publicClient.chain.id, - ARBITRUM_T1_ERC_7683_CONTRACT_ADDRESS -); + baseClient, + BASE_T1_ERC_7683_CONTRACT_ADDRESS, + auctionService, + httpServer, + arbitrumClient.publicClient.chain.id, + ARBITRUM_T1_ERC_7683_CONTRACT_ADDRESS, + auctionPollingInterval, + null +) async function main() { - console.log(`Starting ${IS_MAINNET ? 'mainnet' : 'testnet'} Sealed Bid API server...`); - await httpServer.start(Number(process.env.SERVER_PORT as string), USE_TLS); - arbitrumSepoliaIntentObserver.start(); - baseSepoliaIntentObserver.start(); + console.log( + `Starting ${IS_MAINNET ? "mainnet" : "testnet"} Sealed Bid API server...` + ) + await httpServer.start(Number(process.env.SERVER_PORT as string), USE_TLS) + arbitrumSepoliaIntentObserver.start() + baseSepoliaIntentObserver.start() } async function stopAll() { - await httpServer.stop(); + await httpServer.stop() } main() - .then() - .catch(async (error) => { - await stopAll(); - console.error("", error); - process.exit(1); - }); + .then() + .catch(async (error) => { + await stopAll() + console.error("", error) + process.exit(1) + }) process.on("SIGINT", async () => { - await stopAll(); - process.exit(0); -}); + await stopAll() + process.exit(0) +}) process.on("SIGTERM", async () => { - await stopAll(); - process.exit(0); -}); + await stopAll() + process.exit(0) +}) diff --git a/tee-apps/sealed-bid-auction/src/blockchain/ViemIntentObserver.ts b/tee-apps/sealed-bid-auction/src/blockchain/ViemIntentObserver.ts index 658208b2..b28ffd14 100644 --- a/tee-apps/sealed-bid-auction/src/blockchain/ViemIntentObserver.ts +++ b/tee-apps/sealed-bid-auction/src/blockchain/ViemIntentObserver.ts @@ -2,6 +2,7 @@ import { decodeAbiParameters, parseEventLogs, trim, + type Log, type WatchEventOnLogsParameter, } from "viem"; @@ -16,9 +17,11 @@ import { serialize, WinstonLogger } from "../utils/WinstonLogger.ts"; import type { BlockchainClient } from "./BlockchainClient.ts"; import type { AuctionResult } from "../api/types.ts"; +const HISTORICAL_BLOCK_CHUNK_SIZE = 100n; + export class ViemIntentObserver { private logger: WinstonLogger; - + constructor( private readonly sourceChainClient: BlockchainClient, private readonly sourceChainT1Erc7683ContractAddress: `0x${string}`, @@ -26,14 +29,23 @@ export class ViemIntentObserver { private readonly apiServer: AuctionApiServer, private readonly destinationChainId: number, private readonly destinationChainT1Erc7683ContractAddress: `0x${string}`, - private readonly auctionPollingInterval: number = 500 + private readonly auctionPollingInterval: number = 500, + private readonly fromBlock: bigint | null ) { this.logger = new WinstonLogger( `${ViemIntentObserver.name}[${this.sourceChainClient.publicClient.chain.name}]` ); } - public start() { + public async start() { + if (this.fromBlock !== null) { + await this.fetchHistoricalLogs(); + } + + this.startWatching(); + } + + private startWatching() { this.sourceChainClient.publicClient.watchEvent({ address: this.sourceChainT1Erc7683ContractAddress, event: OPEN_INTENT_ABI_EVENT, @@ -46,6 +58,41 @@ export class ViemIntentObserver { ); } + private async fetchHistoricalLogs() { + if (this.fromBlock === null) return; + + const currentBlock = await this.sourceChainClient.publicClient.getBlockNumber(); + this.logger.info( + `Fetching historical logs from block ${this.fromBlock} to ${currentBlock}` + ); + + let fromBlock = this.fromBlock; + + while (fromBlock <= currentBlock) { + const toBlock = fromBlock + HISTORICAL_BLOCK_CHUNK_SIZE - 1n > currentBlock + ? currentBlock + : fromBlock + HISTORICAL_BLOCK_CHUNK_SIZE - 1n; + + this.logger.info(`Fetching logs from block ${fromBlock} to ${toBlock}`); + + const logs = await this.sourceChainClient.publicClient.getLogs({ + address: this.sourceChainT1Erc7683ContractAddress, + event: OPEN_INTENT_ABI_EVENT, + fromBlock, + toBlock, + }); + + if (logs.length > 0) { + this.logger.info(`Found ${logs.length} historical logs in blocks ${fromBlock}-${toBlock}`); + await this.processIntentLogs(logs as unknown as WatchEventOnLogsParameter); + } + + fromBlock = toBlock + 1n; + } + + this.logger.info(`Finished fetching historical logs, caught up to block ${currentBlock}`); + } + private async processIntentLogs(logs: WatchEventOnLogsParameter) { this.logger.info("Intent was Open-ed!");