Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 65 additions & 9 deletions tools/preconf-rpc/fastswap/fastswap.go
Original file line number Diff line number Diff line change
Expand Up @@ -442,30 +442,86 @@ func (s *Service) Handler() http.HandlerFunc {
return
}

var req SwapRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
var rawReq struct {
User string `json:"user"`
InputToken string `json:"inputToken"`
OutputToken string `json:"outputToken"`
InputAmt string `json:"inputAmt"`
UserAmtOut string `json:"userAmtOut"`
Recipient string `json:"recipient"`
Deadline string `json:"deadline"`
Nonce string `json:"nonce"`
Signature string `json:"signature"`
}

if err := json.NewDecoder(r.Body).Decode(&rawReq); err != nil {
http.Error(w, fmt.Sprintf("invalid request: %v", err), http.StatusBadRequest)
return
}

// Validate required fields
if req.User == (common.Address{}) {
http.Error(w, "missing user address", http.StatusBadRequest)
if rawReq.User == "" || !common.IsHexAddress(rawReq.User) {
http.Error(w, "missing or invalid user address", http.StatusBadRequest)
return
}
if req.InputToken == (common.Address{}) {
http.Error(w, "missing inputToken", http.StatusBadRequest)
if rawReq.InputToken == "" || !common.IsHexAddress(rawReq.InputToken) {
http.Error(w, "missing or invalid inputToken", http.StatusBadRequest)
return
}
if req.OutputToken == (common.Address{}) {
http.Error(w, "missing outputToken", http.StatusBadRequest)
if rawReq.OutputToken == "" || !common.IsHexAddress(rawReq.OutputToken) {
http.Error(w, "missing or invalid outputToken", http.StatusBadRequest)
return
}
if len(req.Signature) == 0 {
if rawReq.Recipient == "" || !common.IsHexAddress(rawReq.Recipient) {
http.Error(w, "missing or invalid recipient", http.StatusBadRequest)
return
}
if rawReq.Signature == "" {
http.Error(w, "missing signature", http.StatusBadRequest)
return
}

// Parse big.Int fields
inputAmt, ok := new(big.Int).SetString(rawReq.InputAmt, 10)
if !ok || inputAmt.Sign() <= 0 {
http.Error(w, "invalid inputAmt", http.StatusBadRequest)
return
}
userAmtOut, ok := new(big.Int).SetString(rawReq.UserAmtOut, 10)
if !ok {
http.Error(w, "invalid userAmtOut", http.StatusBadRequest)
return
}
deadline, ok := new(big.Int).SetString(rawReq.Deadline, 10)
if !ok || deadline.Sign() <= 0 {
http.Error(w, "invalid deadline", http.StatusBadRequest)
return
}
nonce, ok := new(big.Int).SetString(rawReq.Nonce, 10)
if !ok {
http.Error(w, "invalid nonce", http.StatusBadRequest)
return
}

// Decode signature from hex
signature, err := hex.DecodeString(strings.TrimPrefix(rawReq.Signature, "0x"))
if err != nil {
http.Error(w, "invalid signature hex", http.StatusBadRequest)
return
}

req := SwapRequest{
User: common.HexToAddress(rawReq.User),
InputToken: common.HexToAddress(rawReq.InputToken),
OutputToken: common.HexToAddress(rawReq.OutputToken),
InputAmt: inputAmt,
UserAmtOut: userAmtOut,
Recipient: common.HexToAddress(rawReq.Recipient),
Deadline: deadline,
Nonce: nonce,
Signature: signature,
}

result, err := s.HandleSwap(r.Context(), req)
if err != nil {
http.Error(w, fmt.Sprintf("swap failed: %v", err), http.StatusInternalServerError)
Expand Down
33 changes: 23 additions & 10 deletions tools/preconf-rpc/fastswap/fastswap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -391,17 +391,17 @@ func TestHandler(t *testing.T) {

handler := svc.Handler()

// Use raw JSON with flattened request structure
// Use raw JSON with string values for numeric fields (new handler format)
reqJSON := `{
"user": "0x0000000000000000000000000000000000000001",
"inputToken": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"outputToken": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"inputAmt": 1000000000,
"userAmtOut": 500000000000000000,
"inputAmt": "1000000000",
"userAmtOut": "500000000000000000",
"recipient": "0x0000000000000000000000000000000000000002",
"deadline": 1700000000,
"nonce": 1,
"signature": "AQIDBA=="
"deadline": "1700000000",
"nonce": "1",
"signature": "0x01020304"
}`

req := httptest.NewRequest(http.MethodPost, "/fastswap", strings.NewReader(reqJSON))
Expand Down Expand Up @@ -444,30 +444,43 @@ func TestHandler_MissingFields(t *testing.T) {
{
name: "missing user",
reqBody: map[string]interface{}{},
expected: "missing user address",
expected: "missing or invalid user address",
},
{
name: "missing inputToken",
reqBody: map[string]interface{}{
"user": "0x1234567890123456789012345678901234567890",
},
expected: "missing inputToken",
expected: "missing or invalid inputToken",
},
{
name: "missing outputToken",
reqBody: map[string]interface{}{
"user": "0x1234567890123456789012345678901234567890",
"inputToken": "0x1234567890123456789012345678901234567890",
},
expected: "missing outputToken",
expected: "missing or invalid outputToken",
},
{
name: "missing recipient",
reqBody: map[string]interface{}{
"user": "0x1234567890123456789012345678901234567890",
"inputToken": "0x1234567890123456789012345678901234567890",
"outputToken": "0x1234567890123456789012345678901234567890",
},
expected: "missing or invalid recipient",
},
{
name: "missing signature",
reqBody: map[string]interface{}{
"user": "0x1234567890123456789012345678901234567890",
"inputToken": "0x1234567890123456789012345678901234567890",
"outputToken": "0x1234567890123456789012345678901234567890",
"inputAmt": 1000,
"recipient": "0x1234567890123456789012345678901234567890",
"inputAmt": "1000",
"userAmtOut": "900",
"deadline": "1700000000",
"nonce": "0",
},
expected: "missing signature",
},
Expand Down
Loading