package mempool import ( "context" "database/sql" "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" "github.com/jackc/pgx/v5/pgxpool" ) // Tracker tracks pending transactions in the mempool type Tracker struct { db *pgxpool.Pool client *ethclient.Client chainID int } // NewTracker creates a new mempool tracker func NewTracker(db *pgxpool.Pool, client *ethclient.Client, chainID int) *Tracker { return &Tracker{ db: db, client: client, chainID: chainID, } } // TrackPendingTransaction tracks a pending transaction func (t *Tracker) TrackPendingTransaction(ctx context.Context, tx *types.Transaction) error { from, _ := types.Sender(types.LatestSignerForChainID(tx.ChainId()), tx) var toAddress sql.NullString if tx.To() != nil { toAddress.String = tx.To().Hex() toAddress.Valid = true } var maxFeePerGas, maxPriorityFeePerGas sql.NullInt64 if tx.Type() == types.DynamicFeeTxType { if tx.GasFeeCap() != nil { maxFeePerGas.Int64 = tx.GasFeeCap().Int64() maxFeePerGas.Valid = true } if tx.GasTipCap() != nil { maxPriorityFeePerGas.Int64 = tx.GasTipCap().Int64() maxPriorityFeePerGas.Valid = true } } query := ` INSERT INTO mempool_transactions ( time, chain_id, hash, from_address, to_address, value, gas_price, max_fee_per_gas, max_priority_fee_per_gas, gas_limit, nonce, input_data_length, first_seen, status ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) ON CONFLICT (time, chain_id, hash) DO UPDATE SET status = $14, updated_at = NOW() ` _, err := t.db.Exec(ctx, query, time.Now(), t.chainID, tx.Hash().Hex(), from.Hex(), toAddress, tx.Value().String(), tx.GasPrice().Int64(), maxFeePerGas, maxPriorityFeePerGas, tx.Gas(), tx.Nonce(), len(tx.Data()), time.Now(), "pending", ) return err } // UpdateTransactionStatus updates transaction status when confirmed func (t *Tracker) UpdateTransactionStatus(ctx context.Context, txHash common.Hash, blockNumber int64, status string) error { query := ` UPDATE mempool_transactions SET status = $1, confirmed_block_number = $2, confirmed_at = NOW() WHERE chain_id = $3 AND hash = $4 ` _, err := t.db.Exec(ctx, query, status, blockNumber, t.chainID, txHash.Hex()) return err }