Sequencer is working (minimal parsing)

This commit is contained in:
Krypto Kajun
2025-09-14 06:21:10 -05:00
parent 7dd5b5b692
commit 518758790a
59 changed files with 10539 additions and 471 deletions

343
pkg/arbitrum/l2_parser.go Normal file
View File

@@ -0,0 +1,343 @@
package arbitrum
import (
"context"
"encoding/hex"
"fmt"
"math/big"
"strings"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rpc"
"github.com/fraktal/mev-beta/internal/logger"
)
// RawL2Transaction represents a raw Arbitrum L2 transaction
type RawL2Transaction struct {
Hash string `json:"hash"`
From string `json:"from"`
To string `json:"to"`
Value string `json:"value"`
Gas string `json:"gas"`
GasPrice string `json:"gasPrice"`
Input string `json:"input"`
Nonce string `json:"nonce"`
TransactionIndex string `json:"transactionIndex"`
Type string `json:"type"`
ChainID string `json:"chainId,omitempty"`
V string `json:"v,omitempty"`
R string `json:"r,omitempty"`
S string `json:"s,omitempty"`
}
// RawL2Block represents a raw Arbitrum L2 block
type RawL2Block struct {
Hash string `json:"hash"`
Number string `json:"number"`
Timestamp string `json:"timestamp"`
Transactions []RawL2Transaction `json:"transactions"`
}
// DEXFunctionSignature represents a DEX function signature
type DEXFunctionSignature struct {
Signature string
Name string
Protocol string
Description string
}
// ArbitrumL2Parser handles parsing of Arbitrum L2 transactions
type ArbitrumL2Parser struct {
client *rpc.Client
logger *logger.Logger
// DEX contract addresses on Arbitrum
dexContracts map[common.Address]string
// DEX function signatures
dexFunctions map[string]DEXFunctionSignature
}
// NewArbitrumL2Parser creates a new Arbitrum L2 transaction parser
func NewArbitrumL2Parser(rpcEndpoint string, logger *logger.Logger) (*ArbitrumL2Parser, error) {
client, err := rpc.Dial(rpcEndpoint)
if err != nil {
return nil, fmt.Errorf("failed to connect to Arbitrum RPC: %v", err)
}
parser := &ArbitrumL2Parser{
client: client,
logger: logger,
dexContracts: make(map[common.Address]string),
dexFunctions: make(map[string]DEXFunctionSignature),
}
// Initialize DEX contracts and functions
parser.initializeDEXData()
return parser, nil
}
// initializeDEXData initializes known DEX contracts and function signatures
func (p *ArbitrumL2Parser) initializeDEXData() {
// Official Arbitrum DEX contracts
p.dexContracts[common.HexToAddress("0xf1D7CC64Fb4452F05c498126312eBE29f30Fbcf9")] = "UniswapV2Factory"
p.dexContracts[common.HexToAddress("0x1F98431c8aD98523631AE4a59f267346ea31F984")] = "UniswapV3Factory"
p.dexContracts[common.HexToAddress("0xc35DADB65012eC5796536bD9864eD8773aBc74C4")] = "SushiSwapFactory"
p.dexContracts[common.HexToAddress("0x4752ba5dbc23f44d87826276bf6fd6b1c372ad24")] = "UniswapV2Router02"
p.dexContracts[common.HexToAddress("0xE592427A0AEce92De3Edee1F18E0157C05861564")] = "UniswapV3Router"
p.dexContracts[common.HexToAddress("0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45")] = "UniswapV3Router02"
p.dexContracts[common.HexToAddress("0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506")] = "SushiSwapRouter"
p.dexContracts[common.HexToAddress("0xC36442b4a4522E871399CD717aBDD847Ab11FE88")] = "UniswapV3PositionManager"
// CORRECT DEX function signatures verified for Arbitrum (first 4 bytes of keccak256(function_signature))
// Uniswap V2 swap functions
p.dexFunctions["0x38ed1739"] = DEXFunctionSignature{
Signature: "0x38ed1739",
Name: "swapExactTokensForTokens",
Protocol: "UniswapV2",
Description: "Swap exact tokens for tokens",
}
p.dexFunctions["0x8803dbee"] = DEXFunctionSignature{
Signature: "0x8803dbee",
Name: "swapTokensForExactTokens",
Protocol: "UniswapV2",
Description: "Swap tokens for exact tokens",
}
p.dexFunctions["0x7ff36ab5"] = DEXFunctionSignature{
Signature: "0x7ff36ab5",
Name: "swapExactETHForTokens",
Protocol: "UniswapV2",
Description: "Swap exact ETH for tokens",
}
p.dexFunctions["0x4a25d94a"] = DEXFunctionSignature{
Signature: "0x4a25d94a",
Name: "swapTokensForExactETH",
Protocol: "UniswapV2",
Description: "Swap tokens for exact ETH",
}
p.dexFunctions["0x18cbafe5"] = DEXFunctionSignature{
Signature: "0x18cbafe5",
Name: "swapExactTokensForETH",
Protocol: "UniswapV2",
Description: "Swap exact tokens for ETH",
}
p.dexFunctions["0x791ac947"] = DEXFunctionSignature{
Signature: "0x791ac947",
Name: "swapExactTokensForETHSupportingFeeOnTransferTokens",
Protocol: "UniswapV2",
Description: "Swap exact tokens for ETH supporting fee-on-transfer tokens",
}
p.dexFunctions["0xb6f9de95"] = DEXFunctionSignature{
Signature: "0xb6f9de95",
Name: "swapExactETHForTokensSupportingFeeOnTransferTokens",
Protocol: "UniswapV2",
Description: "Swap exact ETH for tokens supporting fee-on-transfer tokens",
}
p.dexFunctions["0x5c11d795"] = DEXFunctionSignature{
Signature: "0x5c11d795",
Name: "swapExactTokensForTokensSupportingFeeOnTransferTokens",
Protocol: "UniswapV2",
Description: "Swap exact tokens for tokens supporting fee-on-transfer tokens",
}
// Uniswap V2 liquidity functions
p.dexFunctions["0xe8e33700"] = DEXFunctionSignature{
Signature: "0xe8e33700",
Name: "addLiquidity",
Protocol: "UniswapV2",
Description: "Add liquidity to pool",
}
p.dexFunctions["0xf305d719"] = DEXFunctionSignature{
Signature: "0xf305d719",
Name: "addLiquidityETH",
Protocol: "UniswapV2",
Description: "Add liquidity with ETH",
}
p.dexFunctions["0xbaa2abde"] = DEXFunctionSignature{
Signature: "0xbaa2abde",
Name: "removeLiquidity",
Protocol: "UniswapV2",
Description: "Remove liquidity from pool",
}
p.dexFunctions["0x02751cec"] = DEXFunctionSignature{
Signature: "0x02751cec",
Name: "removeLiquidityETH",
Protocol: "UniswapV2",
Description: "Remove liquidity with ETH",
}
// Uniswap V3 swap functions
p.dexFunctions["0x414bf389"] = DEXFunctionSignature{
Signature: "0x414bf389",
Name: "exactInputSingle",
Protocol: "UniswapV3",
Description: "Exact input single swap",
}
p.dexFunctions["0xc04b8d59"] = DEXFunctionSignature{
Signature: "0xc04b8d59",
Name: "exactInput",
Protocol: "UniswapV3",
Description: "Exact input multi-hop swap",
}
p.dexFunctions["0xdb3e2198"] = DEXFunctionSignature{
Signature: "0xdb3e2198",
Name: "exactOutputSingle",
Protocol: "UniswapV3",
Description: "Exact output single swap",
}
p.dexFunctions["0xf28c0498"] = DEXFunctionSignature{
Signature: "0xf28c0498",
Name: "exactOutput",
Protocol: "UniswapV3",
Description: "Exact output multi-hop swap",
}
p.dexFunctions["0xac9650d8"] = DEXFunctionSignature{
Signature: "0xac9650d8",
Name: "multicall",
Protocol: "UniswapV3",
Description: "Batch multiple function calls",
}
// Uniswap V3 position management functions
p.dexFunctions["0x88316456"] = DEXFunctionSignature{
Signature: "0x88316456",
Name: "mint",
Protocol: "UniswapV3",
Description: "Mint new liquidity position",
}
p.dexFunctions["0xfc6f7865"] = DEXFunctionSignature{
Signature: "0xfc6f7865",
Name: "collect",
Protocol: "UniswapV3",
Description: "Collect fees from position",
}
p.dexFunctions["0x219f5d17"] = DEXFunctionSignature{
Signature: "0x219f5d17",
Name: "increaseLiquidity",
Protocol: "UniswapV3",
Description: "Increase liquidity in position",
}
p.dexFunctions["0x0c49ccbe"] = DEXFunctionSignature{
Signature: "0x0c49ccbe",
Name: "decreaseLiquidity",
Protocol: "UniswapV3",
Description: "Decrease liquidity in position",
}
}
// GetBlockByNumber fetches a block with full transaction details using raw RPC
func (p *ArbitrumL2Parser) GetBlockByNumber(ctx context.Context, blockNumber uint64) (*RawL2Block, error) {
var block RawL2Block
blockNumHex := fmt.Sprintf("0x%x", blockNumber)
err := p.client.CallContext(ctx, &block, "eth_getBlockByNumber", blockNumHex, true)
if err != nil {
return nil, fmt.Errorf("failed to get block %d: %v", blockNumber, err)
}
p.logger.Debug(fmt.Sprintf("Retrieved L2 block %d with %d transactions", blockNumber, len(block.Transactions)))
return &block, nil
}
// ParseDEXTransactions analyzes transactions in a block for DEX interactions
func (p *ArbitrumL2Parser) ParseDEXTransactions(ctx context.Context, block *RawL2Block) []DEXTransaction {
var dexTransactions []DEXTransaction
for _, tx := range block.Transactions {
if dexTx := p.parseDEXTransaction(tx); dexTx != nil {
dexTransactions = append(dexTransactions, *dexTx)
}
}
if len(dexTransactions) > 0 {
p.logger.Info(fmt.Sprintf("Block %s: Found %d DEX transactions", block.Number, len(dexTransactions)))
}
return dexTransactions
}
// DEXTransaction represents a parsed DEX transaction
type DEXTransaction struct {
Hash string
From string
To string
Value *big.Int
FunctionSig string
FunctionName string
Protocol string
InputData []byte
ContractName string
BlockNumber string
}
// parseDEXTransaction checks if a transaction is a DEX interaction
func (p *ArbitrumL2Parser) parseDEXTransaction(tx RawL2Transaction) *DEXTransaction {
// Skip transactions without recipient (contract creation)
if tx.To == "" || tx.To == "0x" {
return nil
}
// Skip transactions without input data
if tx.Input == "" || tx.Input == "0x" || len(tx.Input) < 10 {
return nil
}
toAddr := common.HexToAddress(tx.To)
// Check if transaction is to a known DEX contract
contractName, isDEXContract := p.dexContracts[toAddr]
// Extract function signature (first 4 bytes of input data)
functionSig := tx.Input[:10] // "0x" + 8 hex chars = 10 chars
// Check if function signature matches known DEX functions
if funcInfo, isDEXFunction := p.dexFunctions[functionSig]; isDEXFunction {
// Parse value
value := big.NewInt(0)
if tx.Value != "" && tx.Value != "0x" && tx.Value != "0x0" {
value.SetString(strings.TrimPrefix(tx.Value, "0x"), 16)
}
// Parse input data
inputData, err := hex.DecodeString(strings.TrimPrefix(tx.Input, "0x"))
if err != nil {
p.logger.Debug(fmt.Sprintf("Failed to decode input data for transaction %s: %v", tx.Hash, err))
inputData = []byte{}
}
p.logger.Info(fmt.Sprintf("DEX Transaction detected: %s -> %s (%s) calling %s (%s), Value: %s ETH",
tx.From, tx.To, contractName, funcInfo.Name, funcInfo.Protocol,
new(big.Float).Quo(new(big.Float).SetInt(value), big.NewFloat(1e18)).String()))
return &DEXTransaction{
Hash: tx.Hash,
From: tx.From,
To: tx.To,
Value: value,
FunctionSig: functionSig,
FunctionName: funcInfo.Name,
Protocol: funcInfo.Protocol,
InputData: inputData,
ContractName: contractName,
BlockNumber: "", // Will be set by caller
}
}
// Check if it's to a known DEX contract but unknown function
if isDEXContract {
p.logger.Debug(fmt.Sprintf("Unknown DEX function call: %s -> %s (%s), Function: %s",
tx.From, tx.To, contractName, functionSig))
}
return nil
}
// Close closes the RPC connection
func (p *ArbitrumL2Parser) Close() {
if p.client != nil {
p.client.Close()
}
}