Ship bridge lanes, public API access doc, and WalletConnect client stack.
Some checks failed
Deploy Explorer Live / deploy (push) Failing after 15s
Validate Explorer / frontend (push) Failing after 20s
Validate Explorer / smoke-e2e (push) Has been skipped

Align CCIP catalog UX with 11-lane config-ready routes, document the no-key public API decision, and enable browser WalletConnect pairing with backend session registration and deploy-time project ID wiring.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
defiQUG
2026-05-23 02:21:37 -07:00
parent efd7c8bbcb
commit ab9c1f9f98
18 changed files with 4278 additions and 150 deletions

View File

@@ -1,6 +1,7 @@
package rest
import (
"encoding/json"
"net/http"
"strings"
@@ -49,6 +50,31 @@ func (s *Server) handleWalletConnectConnect(w http.ResponseWriter, r *http.Reque
writeJSON(w, http.StatusOK, response)
}
// handleWalletConnectSessionRegister handles POST /api/v1/walletconnect/session
func (s *Server) handleWalletConnectSessionRegister(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
writeError(w, http.StatusMethodNotAllowed, "method_not_allowed", "Method not allowed")
return
}
var req struct {
SessionID string `json:"sessionId"`
Address string `json:"address"`
ChainID int `json:"chainId"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
writeError(w, http.StatusBadRequest, "bad_request", "invalid JSON body")
return
}
session, err := s.walletConnectHandler().RegisterSession(r.Context(), req.SessionID, req.Address, req.ChainID)
if err != nil {
writeError(w, http.StatusBadRequest, "bad_request", err.Error())
return
}
writeJSON(w, http.StatusOK, session)
}
// handleWalletConnectSession handles GET /api/v1/walletconnect/session/{id}
func (s *Server) handleWalletConnectSession(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
@@ -65,7 +91,7 @@ func (s *Server) handleWalletConnectSession(w http.ResponseWriter, r *http.Reque
session, err := s.walletConnectHandler().GetSession(r.Context(), sessionID)
if err != nil {
writeJSON(w, http.StatusNotImplemented, session)
writeJSON(w, http.StatusNotFound, session)
return
}
writeJSON(w, http.StatusOK, session)
@@ -83,6 +109,8 @@ func (s *Server) handleWalletConnectRoot(w http.ResponseWriter, r *http.Request)
s.handleWalletConnectMetadata(w, r)
case "connect":
s.handleWalletConnectConnect(w, r)
case "session":
s.handleWalletConnectSessionRegister(w, r)
case "":
if r.Method != http.MethodGet {
writeError(w, http.StatusMethodNotAllowed, "method_not_allowed", "Method not allowed")
@@ -93,6 +121,7 @@ func (s *Server) handleWalletConnectRoot(w http.ResponseWriter, r *http.Request)
"/api/v1/walletconnect/config",
"/api/v1/walletconnect/metadata",
"/api/v1/walletconnect/connect",
"POST /api/v1/walletconnect/session",
"/api/v1/walletconnect/session/{sessionId}",
},
"fallbackAuth": "/api/v1/auth/wallet",

View File

@@ -33,7 +33,8 @@ func TestHandleWalletConnectConfig(t *testing.T) {
}
}
func TestHandleWalletConnectConnectStub(t *testing.T) {
func TestHandleWalletConnectConnectDisabled(t *testing.T) {
t.Setenv("WALLETCONNECT_PROJECT_ID", "")
server := NewServer(nil, 138)
req := httptest.NewRequest(http.MethodPost, "/api/v1/walletconnect/connect", strings.NewReader("{}"))
@@ -43,25 +44,58 @@ func TestHandleWalletConnectConnectStub(t *testing.T) {
if rec.Code != http.StatusNotImplemented {
t.Fatalf("expected 501, got %d", rec.Code)
}
}
func TestHandleWalletConnectConnectClientMode(t *testing.T) {
t.Setenv("WALLETCONNECT_PROJECT_ID", "test-project-id")
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.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["status"] != "stub" {
t.Fatalf("expected stub status, got %#v", payload["status"])
if payload["status"] != "client" {
t.Fatalf("expected client status, got %#v", payload["status"])
}
}
func TestHandleWalletConnectSessionStub(t *testing.T) {
func TestHandleWalletConnectSessionMissing(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)
if rec.Code != http.StatusNotFound {
t.Fatalf("expected 404, got %d", rec.Code)
}
}
func TestHandleWalletConnectSessionRegister(t *testing.T) {
server := NewServer(nil, 138)
body := strings.NewReader(`{"sessionId":"wc-demo","address":"0x4A666F96fC8764181194447A7dFdb7d471b301C8","chainId":138}`)
req := httptest.NewRequest(http.MethodPost, "/api/v1/walletconnect/session", body)
rec := httptest.NewRecorder()
server.handleWalletConnectSessionRegister(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("expected 200, got %d body=%s", rec.Code, rec.Body.String())
}
getReq := httptest.NewRequest(http.MethodGet, "/api/v1/walletconnect/session/wc-demo", nil)
getRec := httptest.NewRecorder()
server.handleWalletConnectSession(getRec, getReq)
if getRec.Code != http.StatusOK {
t.Fatalf("expected lookup 200, got %d", getRec.Code)
}
}