feat: explorer API, wallet, CCIP scripts, and config refresh

- Backend REST/gateway/track routes, analytics, Blockscout proxy paths.
- Frontend wallet and liquidity surfaces; MetaMask token list alignment.
- Deployment docs, verification scripts, address inventory updates.

Check: go build ./... under backend/ (pass).
Made-with: Cursor
This commit is contained in:
defiQUG
2026-04-07 23:22:12 -07:00
parent d931be8e19
commit 6eef6b07f6
224 changed files with 19671 additions and 3291 deletions

View File

@@ -2,10 +2,13 @@ package rest
import (
"context"
"database/sql"
"encoding/json"
"fmt"
"math/big"
"net/http"
"strconv"
"strings"
"time"
)
@@ -122,7 +125,7 @@ func (s *Server) handleEtherscanAPI(w http.ResponseWriter, r *http.Request) {
var timestamp time.Time
var transactionCount int
var gasUsed, gasLimit int64
var transactions []string
var transactions interface{}
query := `
SELECT hash, parent_hash, timestamp, miner, transaction_count, gas_used, gas_limit
@@ -142,40 +145,28 @@ func (s *Server) handleEtherscanAPI(w http.ResponseWriter, r *http.Request) {
break
}
// If boolean is true, get full transaction objects
if boolean {
txQuery := `
SELECT hash FROM transactions
WHERE chain_id = $1 AND block_number = $2
ORDER BY transaction_index
`
rows, err := s.db.Query(ctx, txQuery, s.chainID, blockNumber)
if err == nil {
defer rows.Close()
for rows.Next() {
var txHash string
if err := rows.Scan(&txHash); err == nil {
transactions = append(transactions, txHash)
}
txObjects, err := s.loadEtherscanBlockTransactions(ctx, blockNumber)
if err != nil {
response = EtherscanResponse{
Status: "0",
Message: "Error",
Result: nil,
}
break
}
transactions = txObjects
} else {
// Just get transaction hashes
txQuery := `
SELECT hash FROM transactions
WHERE chain_id = $1 AND block_number = $2
ORDER BY transaction_index
`
rows, err := s.db.Query(ctx, txQuery, s.chainID, blockNumber)
if err == nil {
defer rows.Close()
for rows.Next() {
var txHash string
if err := rows.Scan(&txHash); err == nil {
transactions = append(transactions, txHash)
}
txHashes, err := s.loadEtherscanBlockTransactionHashes(ctx, blockNumber)
if err != nil {
response = EtherscanResponse{
Status: "0",
Message: "Error",
Result: nil,
}
break
}
transactions = txHashes
}
blockResult := map[string]interface{}{
@@ -216,3 +207,92 @@ func (s *Server) handleEtherscanAPI(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(response)
}
func (s *Server) loadEtherscanBlockTransactionHashes(ctx context.Context, blockNumber int64) ([]string, error) {
rows, err := s.db.Query(ctx, `
SELECT hash
FROM transactions
WHERE chain_id = $1 AND block_number = $2
ORDER BY transaction_index
`, s.chainID, blockNumber)
if err != nil {
return nil, err
}
defer rows.Close()
hashes := make([]string, 0)
for rows.Next() {
var txHash string
if err := rows.Scan(&txHash); err != nil {
return nil, err
}
hashes = append(hashes, txHash)
}
return hashes, rows.Err()
}
func (s *Server) loadEtherscanBlockTransactions(ctx context.Context, blockNumber int64) ([]map[string]interface{}, error) {
rows, err := s.db.Query(ctx, `
SELECT hash, block_hash, transaction_index, from_address, to_address, value::text,
COALESCE(gas_price, 0), gas_limit, nonce, COALESCE(input_data, '')
FROM transactions
WHERE chain_id = $1 AND block_number = $2
ORDER BY transaction_index
`, s.chainID, blockNumber)
if err != nil {
return nil, err
}
defer rows.Close()
transactions := make([]map[string]interface{}, 0)
for rows.Next() {
var hash, blockHash, fromAddress, value, inputData string
var toAddress sql.NullString
var transactionIndex int
var gasPrice, gasLimit, nonce int64
if err := rows.Scan(&hash, &blockHash, &transactionIndex, &fromAddress, &toAddress, &value, &gasPrice, &gasLimit, &nonce, &inputData); err != nil {
return nil, err
}
tx := map[string]interface{}{
"hash": hash,
"blockHash": blockHash,
"blockNumber": fmt.Sprintf("0x%x", blockNumber),
"transactionIndex": fmt.Sprintf("0x%x", transactionIndex),
"from": fromAddress,
"value": decimalStringToHex(value),
"gasPrice": fmt.Sprintf("0x%x", gasPrice),
"gas": fmt.Sprintf("0x%x", gasLimit),
"nonce": fmt.Sprintf("0x%x", nonce),
"input": normalizeHexInput(inputData),
}
if toAddress.Valid && toAddress.String != "" {
tx["to"] = toAddress.String
} else {
tx["to"] = nil
}
transactions = append(transactions, tx)
}
return transactions, rows.Err()
}
func decimalStringToHex(value string) string {
parsed, ok := new(big.Int).SetString(value, 10)
if !ok {
return "0x0"
}
return "0x" + parsed.Text(16)
}
func normalizeHexInput(input string) string {
trimmed := strings.TrimSpace(input)
if trimmed == "" {
return "0x"
}
if strings.HasPrefix(trimmed, "0x") {
return trimmed
}
return "0x" + trimmed
}