Add full monorepo: virtual-banker, backend, frontend, docs, scripts, deployment

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
defiQUG
2026-02-10 11:32:49 -08:00
parent aafcd913c2
commit 88bc76da91
815 changed files with 125522 additions and 264 deletions

View File

@@ -0,0 +1,95 @@
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]
}

View File

@@ -0,0 +1,94 @@
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
}