Add WalletConnect stub, track surfaces, legacy SPA retirement, and dual-domain checks.
Publish walletconnect config endpoints, Track 3/4 notes on analytics/operator pages, legacy SPA at /legacy/index.html with root redirect, and a parity verifier for explorer.d-bis.org vs blockscout.defi-oracle.io. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -54,6 +54,8 @@ func (s *Server) SetupRoutes(mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/v1/auth/wallet", s.handleAuthWallet)
|
||||
mux.HandleFunc("/api/v1/auth/refresh", s.handleAuthRefresh)
|
||||
mux.HandleFunc("/api/v1/auth/logout", s.handleAuthLogout)
|
||||
mux.HandleFunc("/api/v1/walletconnect/", s.handleWalletConnectRoot)
|
||||
mux.HandleFunc("/api/v1/walletconnect", s.handleWalletConnectRoot)
|
||||
mux.HandleFunc("/api/v1/auth/register", s.handleAuthRegister)
|
||||
mux.HandleFunc("/api/v1/auth/login", s.handleAuthLogin)
|
||||
mux.HandleFunc("/api/v1/access/me", s.handleAccessMe)
|
||||
|
||||
107
backend/api/rest/walletconnect.go
Normal file
107
backend/api/rest/walletconnect.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/explorer/backend/wallet"
|
||||
)
|
||||
|
||||
func (s *Server) walletConnectHandler() *wallet.WalletConnect {
|
||||
return wallet.NewWalletConnect(s.chainID)
|
||||
}
|
||||
|
||||
// handleWalletConnectConfig handles GET /api/v1/walletconnect/config
|
||||
func (s *Server) handleWalletConnectConfig(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
writeError(w, http.StatusMethodNotAllowed, "method_not_allowed", "Method not allowed")
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, s.walletConnectHandler().PublicConfig())
|
||||
}
|
||||
|
||||
// handleWalletConnectMetadata handles GET /api/v1/walletconnect/metadata
|
||||
func (s *Server) handleWalletConnectMetadata(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
writeError(w, http.StatusMethodNotAllowed, "method_not_allowed", "Method not allowed")
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, map[string]interface{}{
|
||||
"name": "DBIS Explorer",
|
||||
"description": "Chain 138 explorer by DBIS",
|
||||
"url": "https://explorer.d-bis.org",
|
||||
"icons": []string{"https://explorer.d-bis.org/favicon.ico"},
|
||||
})
|
||||
}
|
||||
|
||||
// handleWalletConnectConnect handles POST /api/v1/walletconnect/connect
|
||||
func (s *Server) handleWalletConnectConnect(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
writeError(w, http.StatusMethodNotAllowed, "method_not_allowed", "Method not allowed")
|
||||
return
|
||||
}
|
||||
|
||||
response, err := s.walletConnectHandler().Connect(r.Context())
|
||||
if err != nil {
|
||||
writeJSON(w, http.StatusNotImplemented, response)
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, response)
|
||||
}
|
||||
|
||||
// handleWalletConnectSession handles GET /api/v1/walletconnect/session/{id}
|
||||
func (s *Server) handleWalletConnectSession(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
writeError(w, http.StatusMethodNotAllowed, "method_not_allowed", "Method not allowed")
|
||||
return
|
||||
}
|
||||
|
||||
sessionID := strings.TrimPrefix(r.URL.Path, "/api/v1/walletconnect/session/")
|
||||
sessionID = strings.Trim(sessionID, "/")
|
||||
if sessionID == "" || strings.Contains(sessionID, "/") {
|
||||
writeError(w, http.StatusBadRequest, "bad_request", "session id is required")
|
||||
return
|
||||
}
|
||||
|
||||
session, err := s.walletConnectHandler().GetSession(r.Context(), sessionID)
|
||||
if err != nil {
|
||||
writeJSON(w, http.StatusNotImplemented, session)
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, session)
|
||||
}
|
||||
|
||||
// handleWalletConnectRoot dispatches walletconnect subroutes.
|
||||
func (s *Server) handleWalletConnectRoot(w http.ResponseWriter, r *http.Request) {
|
||||
path := strings.TrimPrefix(r.URL.Path, "/api/v1/walletconnect")
|
||||
path = strings.Trim(path, "/")
|
||||
|
||||
switch path {
|
||||
case "config":
|
||||
s.handleWalletConnectConfig(w, r)
|
||||
case "metadata":
|
||||
s.handleWalletConnectMetadata(w, r)
|
||||
case "connect":
|
||||
s.handleWalletConnectConnect(w, r)
|
||||
case "":
|
||||
if r.Method != http.MethodGet {
|
||||
writeError(w, http.StatusMethodNotAllowed, "method_not_allowed", "Method not allowed")
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, map[string]interface{}{
|
||||
"endpoints": []string{
|
||||
"/api/v1/walletconnect/config",
|
||||
"/api/v1/walletconnect/metadata",
|
||||
"/api/v1/walletconnect/connect",
|
||||
"/api/v1/walletconnect/session/{sessionId}",
|
||||
},
|
||||
"fallbackAuth": "/api/v1/auth/wallet",
|
||||
})
|
||||
default:
|
||||
if strings.HasPrefix(path, "session/") {
|
||||
s.handleWalletConnectSession(w, r)
|
||||
return
|
||||
}
|
||||
writeError(w, http.StatusNotFound, "not_found", "walletconnect route not found")
|
||||
}
|
||||
}
|
||||
79
backend/api/rest/walletconnect_internal_test.go
Normal file
79
backend/api/rest/walletconnect_internal_test.go
Normal file
@@ -0,0 +1,79 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHandleWalletConnectConfig(t *testing.T) {
|
||||
t.Setenv("WALLETCONNECT_PROJECT_ID", "test-project-id")
|
||||
server := NewServer(nil, 138)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/v1/walletconnect/config", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
server.handleWalletConnectConfig(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d", rec.Code)
|
||||
}
|
||||
|
||||
var payload map[string]interface{}
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &payload); err != nil {
|
||||
t.Fatalf("decode response: %v", err)
|
||||
}
|
||||
if payload["projectId"] != "test-project-id" {
|
||||
t.Fatalf("expected project id, got %#v", payload["projectId"])
|
||||
}
|
||||
if payload["fallbackAuth"] != "/api/v1/auth/wallet" {
|
||||
t.Fatalf("expected fallback auth path, got %#v", payload["fallbackAuth"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleWalletConnectConnectStub(t *testing.T) {
|
||||
server := NewServer(nil, 138)
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, "/api/v1/walletconnect/connect", strings.NewReader("{}"))
|
||||
rec := httptest.NewRecorder()
|
||||
server.handleWalletConnectConnect(rec, req)
|
||||
|
||||
if rec.Code != http.StatusNotImplemented {
|
||||
t.Fatalf("expected 501, got %d", rec.Code)
|
||||
}
|
||||
|
||||
var payload map[string]interface{}
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &payload); err != nil {
|
||||
t.Fatalf("decode response: %v", err)
|
||||
}
|
||||
if payload["status"] != "stub" {
|
||||
t.Fatalf("expected stub status, got %#v", payload["status"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleWalletConnectSessionStub(t *testing.T) {
|
||||
server := NewServer(nil, 138)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/v1/walletconnect/session/demo-session", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
server.handleWalletConnectSession(rec, req)
|
||||
|
||||
if rec.Code != http.StatusNotImplemented {
|
||||
t.Fatalf("expected 501, got %d", rec.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleWalletConnectRootIndex(t *testing.T) {
|
||||
_ = os.Setenv("WALLETCONNECT_PROJECT_ID", "")
|
||||
server := NewServer(nil, 138)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/v1/walletconnect", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
server.handleWalletConnectRoot(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d", rec.Code)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user