package fee import ( "context" "fmt" "math/big" "github.com/jackc/pgx/v5/pgxpool" ) // Oracle provides gas price estimates type Oracle struct { db *pgxpool.Pool chainID int } // NewOracle creates a new fee oracle func NewOracle(db *pgxpool.Pool, chainID int) *Oracle { return &Oracle{ db: db, chainID: chainID, } } // FeeEstimate represents gas price estimates type FeeEstimate struct { Slow string `json:"slow"` Standard string `json:"standard"` Fast string `json:"fast"` Urgent string `json:"urgent"` } // GetFeeEstimates gets current fee estimates func (o *Oracle) GetFeeEstimates(ctx context.Context) (*FeeEstimate, error) { // Get recent gas prices from last 100 blocks query := ` SELECT avg_gas_price FROM gas_price_history WHERE chain_id = $1 ORDER BY time DESC LIMIT 100 ` rows, err := o.db.Query(ctx, query, o.chainID) if err != nil { return nil, fmt.Errorf("failed to query gas prices: %w", err) } defer rows.Close() var prices []int64 for rows.Next() { var price int64 if err := rows.Scan(&price); err == nil { prices = append(prices, price) } } if len(prices) == 0 { // Return default estimates if no data return &FeeEstimate{ Slow: "20000000000", Standard: "30000000000", Fast: "50000000000", Urgent: "100000000000", }, nil } // Calculate percentiles p25 := percentile(prices, 0.25) p50 := percentile(prices, 0.50) p75 := percentile(prices, 0.75) p95 := percentile(prices, 0.95) return &FeeEstimate{ Slow: big.NewInt(p25).String(), Standard: big.NewInt(p50).String(), Fast: big.NewInt(p75).String(), Urgent: big.NewInt(p95).String(), }, nil } // percentile calculates percentile of sorted slice func percentile(data []int64, p float64) int64 { if len(data) == 0 { return 0 } index := int(float64(len(data)) * p) if index >= len(data) { index = len(data) - 1 } return data[index] }