import { ethers, PopulatedTransaction } from 'ethers'; import { TransactionManagerEventEmitter, TransactionQueuedEvent, } from './events'; import { TransactionGasOptimizer } from './optimizer'; import { TransactionExecManager } from './transaction-exec-manager'; import { TransactionManagerResponse } from './transaction-inputs/transaction-manager-response'; import { AlchemyApiConfig, TenderlyApiConfig, TransactionManagerQueueItem } from './types'; // TransactionQueueHandler class to handle live and pending transactions queue export class TransactionQueueHandler { private liveTransactionQueue: Array; private pendingTransactionQueue: Array; private transactionExecManager: TransactionExecManager; private txTimeoutInSeconds: number; constructor( provider: ethers.providers.Provider, wallet: ethers.Wallet, txTimeoutInSeconds: number, gasMultiplier: number, tenderlyApiConfig: TenderlyApiConfig, alchemyConfig: AlchemyApiConfig, ) { this.liveTransactionQueue = []; this.pendingTransactionQueue = []; this.txTimeoutInSeconds = txTimeoutInSeconds; this.transactionExecManager = new TransactionExecManager( this, provider, wallet, this.txTimeoutInSeconds, gasMultiplier, tenderlyApiConfig, alchemyConfig ); } public getGasOptimizer(): TransactionGasOptimizer { return this.transactionExecManager.getGasOptimizer(); } public async initialize(chainId: number): Promise { await this.transactionExecManager.initialize(chainId); } private triggerTransactionQueuedEvent( emitter: TransactionManagerEventEmitter, transaction: PopulatedTransaction, isLiveQueue: boolean, transactionId: string, ) { const event: TransactionQueuedEvent = { transactionRequest: transaction, isLiveQueue, transactionId, }; emitter.transactionQueued(event); } // Add transaction to live queue public addToLiveQueue( transactionQueueItem: TransactionManagerQueueItem, ): void { process.env.DEBUG == 'true' && console.log('Added transaction to live queue ', transactionQueueItem.id); this.liveTransactionQueue.push(transactionQueueItem); this.triggerTransactionQueuedEvent( transactionQueueItem.transactionManagerResponse.events, transactionQueueItem.transaction, true, transactionQueueItem.id, ); } // Add transaction to pending queue public addToPendingQueue( transactionQueueItem: TransactionManagerQueueItem, ): void { process.env.DEBUG == 'true' && console.log( 'Adding transaction to pending queue ', transactionQueueItem.id, ); this.pendingTransactionQueue.push(transactionQueueItem); this.triggerTransactionQueuedEvent( transactionQueueItem.transactionManagerResponse.events, transactionQueueItem.transaction, false, transactionQueueItem.id, ); } // Remove transaction from live queue public removeFromLiveQueue( transactionQueueItem: TransactionManagerQueueItem, ): void { this.liveTransactionQueue = this.liveTransactionQueue.filter( (item) => item.transaction.nonce !== transactionQueueItem.transaction.nonce, ); } // Remove transaction from pending queue public removeFromPendingQueue( transactionQueueItem: TransactionManagerQueueItem, ): void { this.pendingTransactionQueue = this.pendingTransactionQueue.filter( (item) => item.transaction.nonce !== transactionQueueItem.transaction.nonce, ); } // Get live queue public getLiveQueue(): Array { return this.liveTransactionQueue; } // Get pending queue public getPendingQueue(): Array { return this.pendingTransactionQueue; } // Get live queue length public getLiveQueueLength(): number { return this.liveTransactionQueue.length; } // Get pending queue length public getPendingQueueLength(): number { return this.pendingTransactionQueue.length; } // shift on pending queue public shiftPendingQueue(): TransactionManagerQueueItem | void { return this.pendingTransactionQueue.shift(); } // shift on live queue public shiftLiveQueue(): TransactionManagerQueueItem | void { return this.liveTransactionQueue.shift(); } // Sort pending queue by priority public sortPendingQueueByPriority(): void { this.pendingTransactionQueue.sort((a, b) => b.priority - a.priority); } // Sort pending queue by priority public sortLiveQueueByPriority(): void { this.pendingTransactionQueue.sort((a, b) => b.priority - a.priority); } // process live queue item public async processLiveQueueItem( transactionQueueItem: TransactionManagerQueueItem, ): Promise { return await this.transactionExecManager.processTransactionQueueItem( transactionQueueItem, true, ); } // check any transaction is getting processed public isTransactionRunning(): boolean { const runningTransaction = this.pendingTransactionQueue.find( (transaction: TransactionManagerQueueItem) => transaction.transactionManagerResponse.status == 'started', ); return runningTransaction ? true : false; } // process pending queue item public async processPendingQueueItem( transactionQueueItem: TransactionManagerQueueItem, ): Promise { return await this.transactionExecManager.processTransactionQueueItem( transactionQueueItem, false, ); } }