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:
146
backend/api/track1/bridge_status_data.go
Normal file
146
backend/api/track1/bridge_status_data.go
Normal file
@@ -0,0 +1,146 @@
|
||||
package track1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func relaySnapshotStatus(relay map[string]interface{}) string {
|
||||
if relay == nil {
|
||||
return ""
|
||||
}
|
||||
if probe, ok := relay["url_probe"].(map[string]interface{}); ok {
|
||||
if okValue, exists := probe["ok"].(bool); exists && !okValue {
|
||||
return "down"
|
||||
}
|
||||
if body, ok := probe["body"].(map[string]interface{}); ok {
|
||||
if status, ok := body["status"].(string); ok {
|
||||
return strings.ToLower(strings.TrimSpace(status))
|
||||
}
|
||||
}
|
||||
}
|
||||
if _, ok := relay["file_snapshot_error"].(string); ok {
|
||||
return "down"
|
||||
}
|
||||
if snapshot, ok := relay["file_snapshot"].(map[string]interface{}); ok {
|
||||
if status, ok := snapshot["status"].(string); ok {
|
||||
return strings.ToLower(strings.TrimSpace(status))
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func relayNeedsAttention(relay map[string]interface{}) bool {
|
||||
status := relaySnapshotStatus(relay)
|
||||
switch status {
|
||||
case "degraded", "stale", "stopped", "down":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// BuildBridgeStatusData builds the inner `data` object for bridge/status and SSE payloads.
|
||||
func (s *Server) BuildBridgeStatusData(ctx context.Context) map[string]interface{} {
|
||||
rpc138 := strings.TrimSpace(os.Getenv("RPC_URL"))
|
||||
if rpc138 == "" {
|
||||
rpc138 = "http://localhost:8545"
|
||||
}
|
||||
|
||||
var probes []RPCProbeResult
|
||||
p138 := ProbeEVMJSONRPC(ctx, "chain-138", "138", rpc138)
|
||||
probes = append(probes, p138)
|
||||
|
||||
if eth := strings.TrimSpace(os.Getenv("ETH_MAINNET_RPC_URL")); eth != "" {
|
||||
probes = append(probes, ProbeEVMJSONRPC(ctx, "ethereum-mainnet", "1", eth))
|
||||
}
|
||||
|
||||
for _, row := range ParseExtraRPCProbes() {
|
||||
name, u, ck := row[0], row[1], row[2]
|
||||
probes = append(probes, ProbeEVMJSONRPC(ctx, name, ck, u))
|
||||
}
|
||||
|
||||
overall := "operational"
|
||||
if !p138.OK {
|
||||
overall = "degraded"
|
||||
} else {
|
||||
for _, p := range probes {
|
||||
if !p.OK {
|
||||
overall = "degraded"
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
now := time.Now().UTC().Format(time.RFC3339)
|
||||
chains := map[string]interface{}{
|
||||
"138": map[string]interface{}{
|
||||
"name": "Defi Oracle Meta Mainnet",
|
||||
"status": chainStatusFromProbe(p138),
|
||||
"last_sync": now,
|
||||
"latency_ms": p138.LatencyMs,
|
||||
"head_age_sec": p138.HeadAgeSeconds,
|
||||
"block_number": p138.BlockNumberDec,
|
||||
"endpoint": p138.Endpoint,
|
||||
"probe_error": p138.Error,
|
||||
},
|
||||
}
|
||||
|
||||
for _, p := range probes {
|
||||
if p.ChainKey != "1" && p.Name != "ethereum-mainnet" {
|
||||
continue
|
||||
}
|
||||
chains["1"] = map[string]interface{}{
|
||||
"name": "Ethereum Mainnet",
|
||||
"status": chainStatusFromProbe(p),
|
||||
"last_sync": now,
|
||||
"latency_ms": p.LatencyMs,
|
||||
"head_age_sec": p.HeadAgeSeconds,
|
||||
"block_number": p.BlockNumberDec,
|
||||
"endpoint": p.Endpoint,
|
||||
"probe_error": p.Error,
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
probeJSON := make([]map[string]interface{}, 0, len(probes))
|
||||
for _, p := range probes {
|
||||
probeJSON = append(probeJSON, map[string]interface{}{
|
||||
"name": p.Name,
|
||||
"chainKey": p.ChainKey,
|
||||
"endpoint": p.Endpoint,
|
||||
"ok": p.OK,
|
||||
"latencyMs": p.LatencyMs,
|
||||
"blockNumber": p.BlockNumber,
|
||||
"blockNumberDec": p.BlockNumberDec,
|
||||
"headAgeSeconds": p.HeadAgeSeconds,
|
||||
"error": p.Error,
|
||||
})
|
||||
}
|
||||
|
||||
data := map[string]interface{}{
|
||||
"status": overall,
|
||||
"chains": chains,
|
||||
"rpc_probe": probeJSON,
|
||||
"checked_at": now,
|
||||
}
|
||||
if ov := readOptionalVerifyJSON(); ov != nil {
|
||||
data["operator_verify"] = ov
|
||||
}
|
||||
if relays := FetchCCIPRelayHealths(ctx); relays != nil {
|
||||
data["ccip_relays"] = relays
|
||||
if ccip := primaryRelayHealth(relays); ccip != nil {
|
||||
data["ccip_relay"] = ccip
|
||||
}
|
||||
for _, value := range relays {
|
||||
relay, ok := value.(map[string]interface{})
|
||||
if ok && relayNeedsAttention(relay) {
|
||||
data["status"] = "degraded"
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
Reference in New Issue
Block a user