95 lines
2.3 KiB
Go
95 lines
2.3 KiB
Go
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
|
|
}
|
|
|