import { HandleEvmLogs, PollEvm, PollEvmLogsConfig, PollEvmLogsConfigProps, PollSolanaTransactions, PollSolanaTransactionsConfig, RunPollingJob, } from "../../domain/actions"; import { JobDefinition, Handler, LogFoundEvent } from "../../domain/entities"; import { EvmBlockRepository, JobRepository, MetadataRepository, SolanaSlotRepository, StatRepository, SuiRepository, } from "../../domain/repositories"; import { FileMetadataRepository, SnsEventRepository } from "./index"; import { HandleSolanaTransactions } from "../../domain/actions/solana/HandleSolanaTransactions"; import { solanaLogMessagePublishedMapper, solanaTransferRedeemedMapper, evmLogMessagePublishedMapper, evmRedeemedTransactionFoundMapper, } from "../mappers"; import log from "../log"; import { HandleEvmTransactions } from "../../domain/actions/evm/HandleEvmTransactions"; import { suiRedeemedTransactionFoundMapper } from "../mappers/sui/suiRedeemedTransactionFoundMapper"; import { HandleSuiTransactions } from "../../domain/actions/sui/HandleSuiTransactions"; import { PollSuiTransactions, PollSuiTransactionsConfig, } from "../../domain/actions/sui/PollSuiTransactions"; export class StaticJobRepository implements JobRepository { private fileRepo: FileMetadataRepository; private environment: string; private dryRun: boolean = false; private sources: Map RunPollingJob> = new Map(); private handlers: Map Promise> = new Map(); private mappers: Map = new Map(); private targets: Map Promise<(items: any[], chain: string) => Promise>> = new Map(); private blockRepoProvider: (chain: string) => EvmBlockRepository; private metadataRepo: MetadataRepository; private statsRepo: StatRepository; private snsRepo: SnsEventRepository; private solanaSlotRepo: SolanaSlotRepository; private suiRepo: SuiRepository; constructor( environment: string, path: string, dryRun: boolean, blockRepoProvider: (chain: string) => EvmBlockRepository, repos: { metadataRepo: MetadataRepository; statsRepo: StatRepository; snsRepo: SnsEventRepository; solanaSlotRepo: SolanaSlotRepository; suiRepo: SuiRepository; } ) { this.fileRepo = new FileMetadataRepository(path); this.blockRepoProvider = blockRepoProvider; this.metadataRepo = repos.metadataRepo; this.statsRepo = repos.statsRepo; this.snsRepo = repos.snsRepo; this.solanaSlotRepo = repos.solanaSlotRepo; this.suiRepo = repos.suiRepo; this.environment = environment; this.dryRun = dryRun; this.fill(); } async getJobDefinitions(): Promise { const persisted = await this.fileRepo.get("jobs"); if (!persisted) { return Promise.resolve([]); } return persisted; } getSource(jobDef: JobDefinition): RunPollingJob { const src = this.sources.get(jobDef.source.action); if (!src) { throw new Error(`Source ${jobDef.source.action} not found`); } return src(jobDef); } async getHandlers(jobDef: JobDefinition): Promise { const result: Handler[] = []; for (const handler of jobDef.handlers) { const maybeHandler = this.handlers.get(handler.action); if (!maybeHandler) { throw new Error(`Handler ${handler.action} not found`); } const mapper = this.mappers.get(handler.mapper); if (!mapper) { throw new Error(`Handler ${handler.mapper} not found`); } const config = { ...(handler.config as any), commitment: jobDef.source.config.commitment, chainId: jobDef.chainId, chain: jobDef.chain, id: jobDef.id, }; result.push((await maybeHandler(config, handler.target, mapper)).bind(maybeHandler)); } return result; } private fill() { // Actions const pollEvm = (jobDef: JobDefinition) => new PollEvm( this.blockRepoProvider(jobDef.source.config.chain), this.metadataRepo, this.statsRepo, new PollEvmLogsConfig({ ...(jobDef.source.config as PollEvmLogsConfigProps), id: jobDef.id, environment: this.environment, }), jobDef.source.records ); const pollSolanaTransactions = (jobDef: JobDefinition) => new PollSolanaTransactions(this.metadataRepo, this.solanaSlotRepo, this.statsRepo, { ...(jobDef.source.config as PollSolanaTransactionsConfig), id: jobDef.id, }); const pollSuiTransactions = (jobDef: JobDefinition) => new PollSuiTransactions( new PollSuiTransactionsConfig({ ...jobDef.source.config, id: jobDef.id }), this.statsRepo, this.metadataRepo, this.suiRepo ); this.sources.set("PollEvm", pollEvm); this.sources.set("PollSolanaTransactions", pollSolanaTransactions); this.sources.set("PollSuiTransactions", pollSuiTransactions); // Mappers this.mappers.set("evmLogMessagePublishedMapper", evmLogMessagePublishedMapper); this.mappers.set("evmRedeemedTransactionFoundMapper", evmRedeemedTransactionFoundMapper); this.mappers.set("solanaLogMessagePublishedMapper", solanaLogMessagePublishedMapper); this.mappers.set("solanaTransferRedeemedMapper", solanaTransferRedeemedMapper); this.mappers.set("suiRedeemedTransactionFoundMapper", suiRedeemedTransactionFoundMapper); // Targets const snsTarget = () => this.snsRepo.asTarget(); const dummyTarget = async () => async (events: any[]) => { log.info(`Got ${events.length} events`); }; this.targets.set("sns", snsTarget); this.targets.set("dummy", dummyTarget); // Handles const handleEvmLogs = async (config: any, target: string, mapper: any) => { const instance = new HandleEvmLogs>( config, mapper, await this.targets.get(this.dryRun ? "dummy" : target)!(), this.statsRepo ); return instance.handle.bind(instance); }; const handleEvmTransactions = async (config: any, target: string, mapper: any) => { const instance = new HandleEvmTransactions>( config, mapper, await this.targets.get(this.dryRun ? "dummy" : target)!(), this.statsRepo ); return instance.handle.bind(instance); }; const handleSolanaTx = async (config: any, target: string, mapper: any) => { const instance = new HandleSolanaTransactions( config, mapper, await this.getTarget(target), this.statsRepo ); return instance.handle.bind(instance); }; const handleSuiTx = async (config: any, target: string, mapper: any) => { const instance = new HandleSuiTransactions( config, mapper, await this.getTarget(target), this.statsRepo ); return instance.handle.bind(instance); }; this.handlers.set("HandleEvmLogs", handleEvmLogs); this.handlers.set("HandleEvmTransactions", handleEvmTransactions); this.handlers.set("HandleSolanaTransactions", handleSolanaTx); this.handlers.set("HandleSuiTransactions", handleSuiTx); } private async getTarget(target: string): Promise<(items: any[], chain: string) => Promise> { const maybeTarget = this.targets.get(this.dryRun ? "dummy" : target); if (!maybeTarget) { throw new Error(`Target ${target} not found`); } return maybeTarget(); } }