96 lines
1.9 KiB
Go
96 lines
1.9 KiB
Go
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]
|
|
}
|
|
|