mirror of
https://github.com/luxfi/dex.git
synced 2026-09-24 00:26:31 +00:00
163 lines
4.6 KiB
Go
163 lines
4.6 KiB
Go
package gateway
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
)
|
|
|
|
// registerApprovalRoutes registers ERC20 approval and Permit2 HTTP routes.
|
|
func (s *Server) registerApprovalRoutes() {
|
|
s.mux.HandleFunc("/v1/approval/check", s.handleApprovalCheck)
|
|
s.mux.HandleFunc("/v1/approval/build", s.handleApprovalBuild)
|
|
s.mux.HandleFunc("/v1/permit2/check", s.handlePermit2Check)
|
|
s.mux.HandleFunc("/v1/permit2/build", s.handlePermit2Build)
|
|
}
|
|
|
|
// handleApprovalCheck handles POST /v1/approval/check.
|
|
// Returns whether the given spender has sufficient ERC20 allowance.
|
|
// In the gateway layer (no RPC), this returns a conservative response
|
|
// indicating approval is always needed (the client should use the
|
|
// allowance calldata to query on-chain if it wants to check).
|
|
func (s *Server) handleApprovalCheck(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPost {
|
|
s.writeError(w, http.StatusMethodNotAllowed, fmt.Errorf("method not allowed"))
|
|
return
|
|
}
|
|
|
|
var req ApprovalRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
s.writeError(w, http.StatusBadRequest, fmt.Errorf("invalid request body: %w", err))
|
|
return
|
|
}
|
|
|
|
if err := req.Validate(); err != nil {
|
|
s.writeError(w, http.StatusBadRequest, err)
|
|
return
|
|
}
|
|
|
|
// Build the approve tx so the client can submit if needed
|
|
approveTx, err := BuildApproveTx(req)
|
|
if err != nil {
|
|
s.writeError(w, http.StatusBadRequest, err)
|
|
return
|
|
}
|
|
|
|
// Gateway has no RPC connection to read on-chain state;
|
|
// return needsApproval=true with the unsigned tx and the
|
|
// allowance check calldata so the client can query itself.
|
|
resp := ApprovalResponse{
|
|
Approved: false,
|
|
Allowance: "0",
|
|
NeedsApproval: true,
|
|
ApproveTx: approveTx,
|
|
}
|
|
|
|
s.writeJSON(w, http.StatusOK, resp)
|
|
}
|
|
|
|
// handleApprovalBuild handles POST /v1/approval/build.
|
|
// Returns an unsigned ERC20 approve() transaction.
|
|
func (s *Server) handleApprovalBuild(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPost {
|
|
s.writeError(w, http.StatusMethodNotAllowed, fmt.Errorf("method not allowed"))
|
|
return
|
|
}
|
|
|
|
var req ApprovalRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
s.writeError(w, http.StatusBadRequest, fmt.Errorf("invalid request body: %w", err))
|
|
return
|
|
}
|
|
|
|
tx, err := BuildApproveTx(req)
|
|
if err != nil {
|
|
s.writeError(w, http.StatusBadRequest, err)
|
|
return
|
|
}
|
|
|
|
s.writeJSON(w, http.StatusOK, tx)
|
|
}
|
|
|
|
// handlePermit2Check handles POST /v1/permit2/check.
|
|
// Returns whether the owner has granted sufficient Permit2 allowance for the spender.
|
|
// Like approval/check, this is a conservative response without RPC access.
|
|
func (s *Server) handlePermit2Check(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPost {
|
|
s.writeError(w, http.StatusMethodNotAllowed, fmt.Errorf("method not allowed"))
|
|
return
|
|
}
|
|
|
|
var req Permit2Request
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
s.writeError(w, http.StatusBadRequest, fmt.Errorf("invalid request body: %w", err))
|
|
return
|
|
}
|
|
|
|
if err := req.Validate(); err != nil {
|
|
s.writeError(w, http.StatusBadRequest, err)
|
|
return
|
|
}
|
|
|
|
sigReq, err := BuildPermit2SignatureRequest(req)
|
|
if err != nil {
|
|
s.writeError(w, http.StatusBadRequest, err)
|
|
return
|
|
}
|
|
|
|
resp := Permit2Response{
|
|
Permit2Approved: false,
|
|
Permit2Allowance: "0",
|
|
SignatureRequest: sigReq,
|
|
}
|
|
|
|
s.writeJSON(w, http.StatusOK, resp)
|
|
}
|
|
|
|
// handlePermit2Build handles POST /v1/permit2/build.
|
|
// Returns either:
|
|
// - An unsigned Permit2 approve() tx (on-chain allowance grant), or
|
|
// - An EIP-712 PermitSingle signature request (off-chain permit)
|
|
//
|
|
// Behavior is controlled by the "mode" query parameter:
|
|
// - ?mode=tx (default) returns an unsigned approve transaction
|
|
// - ?mode=sig returns an EIP-712 signature request
|
|
func (s *Server) handlePermit2Build(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPost {
|
|
s.writeError(w, http.StatusMethodNotAllowed, fmt.Errorf("method not allowed"))
|
|
return
|
|
}
|
|
|
|
var req Permit2Request
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
s.writeError(w, http.StatusBadRequest, fmt.Errorf("invalid request body: %w", err))
|
|
return
|
|
}
|
|
|
|
mode := r.URL.Query().Get("mode")
|
|
if mode == "" {
|
|
mode = "tx"
|
|
}
|
|
|
|
switch mode {
|
|
case "tx":
|
|
tx, err := BuildPermit2ApproveTx(req)
|
|
if err != nil {
|
|
s.writeError(w, http.StatusBadRequest, err)
|
|
return
|
|
}
|
|
s.writeJSON(w, http.StatusOK, tx)
|
|
|
|
case "sig":
|
|
sigReq, err := BuildPermit2SignatureRequest(req)
|
|
if err != nil {
|
|
s.writeError(w, http.StatusBadRequest, err)
|
|
return
|
|
}
|
|
s.writeJSON(w, http.StatusOK, sigReq)
|
|
|
|
default:
|
|
s.writeError(w, http.StatusBadRequest, fmt.Errorf("invalid mode %q: must be \"tx\" or \"sig\"", mode))
|
|
}
|
|
}
|