Publish Chain 138 RPC capability metadata

This commit is contained in:
defiQUG
2026-03-28 15:56:42 -07:00
parent 96a78eda33
commit 141c8a278e
6 changed files with 265 additions and 3 deletions

View File

@@ -11,6 +11,9 @@ var dualChainNetworksJSON []byte
//go:embed config/metamask/DUAL_CHAIN_TOKEN_LIST.tokenlist.json
var dualChainTokenListJSON []byte
//go:embed config/metamask/CHAIN138_RPC_CAPABILITIES.json
var chain138RPCCapabilitiesJSON []byte
// handleConfigNetworks serves GET /api/config/networks (Chain 138 + Ethereum Mainnet params for wallet_addEthereumChain).
func (s *Server) handleConfigNetworks(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
@@ -34,3 +37,15 @@ func (s *Server) handleConfigTokenList(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Cache-Control", "public, max-age=3600")
w.Write(dualChainTokenListJSON)
}
// handleConfigCapabilities serves GET /api/config/capabilities (Chain 138 wallet/RPC capability matrix).
func (s *Server) handleConfigCapabilities(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
w.Header().Set("Allow", "GET")
writeMethodNotAllowed(w)
return
}
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Cache-Control", "public, max-age=900")
w.Write(chain138RPCCapabilitiesJSON)
}

View File

@@ -0,0 +1,62 @@
{
"name": "Chain 138 RPC Capabilities",
"version": {
"major": 1,
"minor": 0,
"patch": 0
},
"generatedBy": "SolaceScanScout",
"timestamp": "2026-03-28T00:00:00Z",
"chainId": 138,
"chainName": "DeFi Oracle Meta Mainnet",
"rpcUrl": "https://rpc-http-pub.d-bis.org",
"explorerUrl": "https://explorer.d-bis.org",
"explorerApiUrl": "https://explorer.d-bis.org/api/v2",
"walletSupport": {
"walletAddEthereumChain": true,
"walletWatchAsset": true,
"notes": [
"MetaMask primarily relies on JSON-RPC correctness for balances, gas estimation, calls, and transaction submission.",
"Explorer-served network metadata and token list metadata complement wallet UX but do not replace RPC method support."
]
},
"http": {
"supportedMethods": [
"web3_clientVersion",
"net_version",
"eth_chainId",
"eth_blockNumber",
"eth_syncing",
"eth_gasPrice",
"eth_feeHistory",
"eth_estimateGas",
"eth_getCode"
],
"unsupportedMethods": [
"eth_maxPriorityFeePerGas"
],
"notes": [
"eth_feeHistory is available for wallet fee estimation.",
"eth_maxPriorityFeePerGas is currently not exposed on the public RPC, so some wallets will fall back to simpler fee heuristics."
]
},
"tracing": {
"supportedMethods": [
"trace_block",
"trace_replayBlockTransactions"
],
"unsupportedMethods": [
"debug_traceBlockByNumber"
],
"notes": [
"TRACE support is enabled for explorer-grade indexing and internal transaction analysis.",
"Debug tracing is intentionally not enabled on the public RPC tier."
]
},
"ws": {
"notes": [
"Use the dedicated public WebSocket endpoint for subscriptions and live wallet/provider events.",
"HTTP and WebSocket method coverage should be treated as separate operational surfaces."
]
}
}

View File

@@ -46,6 +46,29 @@ type testTokenList struct {
} `json:"tokens"`
}
type testCapabilitiesCatalog struct {
Name string `json:"name"`
GeneratedBy string `json:"generatedBy"`
ChainID int `json:"chainId"`
ChainName string `json:"chainName"`
RPCURL string `json:"rpcUrl"`
HTTP struct {
SupportedMethods []string `json:"supportedMethods"`
UnsupportedMethods []string `json:"unsupportedMethods"`
Notes []string `json:"notes"`
} `json:"http"`
Tracing struct {
SupportedMethods []string `json:"supportedMethods"`
UnsupportedMethods []string `json:"unsupportedMethods"`
Notes []string `json:"notes"`
} `json:"tracing"`
WalletSupport struct {
WalletAddEthereumChain bool `json:"walletAddEthereumChain"`
WalletWatchAsset bool `json:"walletWatchAsset"`
Notes []string `json:"notes"`
} `json:"walletSupport"`
}
func setupConfigHandler() http.Handler {
server := NewServer(nil, 138)
mux := http.NewServeMux()
@@ -53,6 +76,15 @@ func setupConfigHandler() http.Handler {
return server.addMiddleware(mux)
}
func containsString(items []string, want string) bool {
for _, item := range items {
if item == want {
return true
}
}
return false
}
func TestConfigNetworksEndpointProvidesWalletMetadata(t *testing.T) {
handler := setupConfigHandler()
req := httptest.NewRequest(http.MethodGet, "/api/config/networks", nil)
@@ -148,6 +180,38 @@ func TestConfigTokenListEndpointProvidesOptionalMetadata(t *testing.T) {
}
}
func TestConfigCapabilitiesEndpointProvidesRPCCapabilityMatrix(t *testing.T) {
handler := setupConfigHandler()
req := httptest.NewRequest(http.MethodGet, "/api/config/capabilities", nil)
w := httptest.NewRecorder()
handler.ServeHTTP(w, req)
if w.Code != http.StatusOK {
t.Fatalf("expected 200, got %d", w.Code)
}
var payload testCapabilitiesCatalog
if err := json.Unmarshal(w.Body.Bytes(), &payload); err != nil {
t.Fatalf("failed to parse capabilities payload: %v", err)
}
if payload.ChainID != 138 || payload.ChainName == "" || payload.RPCURL == "" || payload.GeneratedBy == "" {
t.Fatal("expected populated chain-level capability metadata")
}
if !payload.WalletSupport.WalletAddEthereumChain || !payload.WalletSupport.WalletWatchAsset {
t.Fatal("expected wallet support flags to be true")
}
if !containsString(payload.HTTP.SupportedMethods, "eth_feeHistory") {
t.Fatal("expected eth_feeHistory support to be documented")
}
if !containsString(payload.HTTP.UnsupportedMethods, "eth_maxPriorityFeePerGas") {
t.Fatal("expected missing eth_maxPriorityFeePerGas support to be documented")
}
if !containsString(payload.Tracing.SupportedMethods, "trace_block") {
t.Fatal("expected trace_block support to be documented")
}
}
func TestConfigEndpointsSupportOptionsPreflight(t *testing.T) {
handler := setupConfigHandler()
req := httptest.NewRequest(http.MethodOptions, "/api/config/token-list", nil)

View File

@@ -35,6 +35,7 @@ func (s *Server) SetupRoutes(mux *http.ServeMux) {
// MetaMask / dual-chain config (Chain 138 + Ethereum Mainnet)
mux.HandleFunc("/api/config/networks", s.handleConfigNetworks)
mux.HandleFunc("/api/config/token-list", s.handleConfigTokenList)
mux.HandleFunc("/api/config/capabilities", s.handleConfigCapabilities)
// Feature flags endpoint
mux.HandleFunc("/api/v1/features", s.handleFeatures)