Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 2 additions & 0 deletions gateway/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require (
github.com/gin-gonic/gin v1.11.0
github.com/google/uuid v1.6.0
github.com/joho/godotenv v1.5.1
github.com/rs/zerolog v1.34.0
)

require (
Expand All @@ -23,6 +24,7 @@ require (
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
Expand Down
12 changes: 12 additions & 0 deletions gateway/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZw
github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand All @@ -27,6 +28,7 @@ github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
Expand All @@ -40,6 +42,10 @@ github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzh
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
Expand All @@ -49,12 +55,16 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
github.com/quic-go/quic-go v0.57.0 h1:AsSSrrMs4qI/hLrKlTH/TGQeTMY0ib1pAOX7vA3AdqE=
github.com/quic-go/quic-go v0.57.0/go.mod h1:ly4QBAjHA2VhdnxhojRsCUOeJwKYg+taDlos92xb1+s=
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
Expand All @@ -76,7 +86,9 @@ golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
Expand Down
193 changes: 58 additions & 135 deletions gateway/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,16 @@ import (
"os"
"strconv"

"gateway/middleware"

"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"github.com/joho/godotenv"
)

/* -------------------- Types -------------------- */

type PaymentContext struct {
Recipient string `json:"recipient"`
Token string `json:"token"`
Expand All @@ -38,38 +42,19 @@ type SummarizeRequest struct {
Text string `json:"text"`
}

/* -------------------- Main -------------------- */

func main() {
err := godotenv.Load("../.env")
if err != nil {
log.Println("Warning: Error loading .env file")
}
_ = godotenv.Load("../.env")

r := gin.Default()

r.StaticFile("/openapi.yaml", "openapi.yaml")

r.GET("/docs", func(c *gin.Context) {
c.Header("Content-Type", "text/html")
c.String(200, `
<!DOCTYPE html>
<html>
<head>
<title>MicroAI Paygate Docs</title>
<link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@5.11.0/swagger-ui.css" />
</head>
<body>
<div id="swagger-ui"></div>
<script src="https://unpkg.com/swagger-ui-dist@5.11.0/swagger-ui-bundle.js"></script>
<script>
SwaggerUIBundle({
url: '/openapi.yaml',
dom_id: '#swagger-ui'
});
</script>
</body>
</html>
`)
})
// Init structured logging
middleware.InitLogger()

r := gin.New()
r.Use(
gin.Recovery(),
middleware.RequestLogger(),
)

r.Use(cors.New(cors.Config{
AllowOrigins: []string{"http://localhost:3001"},
Expand All @@ -91,76 +76,78 @@ func main() {
r.Run(":" + port)
}

// - 500: Verifier or AI service failure (includes error details)
/* -------------------- Handlers -------------------- */

func handleHealth(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"status": "ok",
"service": "gateway",
})
}
Comment thread
magic-peach marked this conversation as resolved.
Comment on lines +232 to +237

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handleHealth() function is defined but never used. The actual health check endpoint uses handleHealthz() on line 186.

Either remove this function or rename it to handleHealthz() and remove the duplicate definition on line 980.

Prompt To Fix With AI
This is a comment left during a code review.
Path: gateway/main.go
Line: 232:237

Comment:
`handleHealth()` function is defined but never used. The actual health check endpoint uses `handleHealthz()` on line 186.

Either remove this function or rename it to `handleHealthz()` and remove the duplicate definition on line 980.

How can I resolve this? If you propose a fix, please make it concise.


func handleSummarize(c *gin.Context) {
signature := c.GetHeader("X-402-Signature")
nonce := c.GetHeader("X-402-Nonce")

// 1. Payment Required
if signature == "" || nonce == "" {
context := createPaymentContext()
c.Set("payment_verified", false)

ctx := createPaymentContext()
c.JSON(402, gin.H{
"error": "Payment Required",
"message": "Please sign the payment context",
"paymentContext": context,
"paymentContext": ctx,
})
return
}
Comment on lines 253 to 269

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merge conflict: incomplete payment verification logic duplicated with syntax errors. Line 260 declares ctx but tries to assign paymentContext (undefined), and lines 261-269 duplicate the logic from lines 262-268.

Suggested change
signature := c.GetHeader("X-402-Signature")
nonce := c.GetHeader("X-402-Nonce")
if signature == "" || nonce == "" {
c.Set("payment_verified", false)
c.JSON(402, gin.H{
"error": "Payment Required",
"message": "Please sign the payment context",
"paymentContext": createPaymentContext(),
})
return
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: gateway/main.go
Line: 253:269

Comment:
Merge conflict: incomplete payment verification logic duplicated with syntax errors. Line 260 declares `ctx` but tries to assign `paymentContext` (undefined), and lines 261-269 duplicate the logic from lines 262-268.

```suggestion
	signature := c.GetHeader("X-402-Signature")
	nonce := c.GetHeader("X-402-Nonce")

	if signature == "" || nonce == "" {
		c.Set("payment_verified", false)
		c.JSON(402, gin.H{
			"error":          "Payment Required",
			"message":        "Please sign the payment context",
			"paymentContext": createPaymentContext(),
		})
		return
	}
```


How can I resolve this? If you propose a fix, please make it concise.


// 2. Verify Payment (Call Rust Service)
context := PaymentContext{
Recipient: getRecipientAddress(),
Token: "USDC",
Amount: getPaymentAmount(),
Nonce: nonce,
ChainID: getChainID(),
}

verifyReq := VerifyRequest{
Context: context,
Context: PaymentContext{
Recipient: getRecipientAddress(),
Token: "USDC",
Amount: getPaymentAmount(),
Nonce: nonce,
ChainID: getChainID(),
},
Signature: signature,
}

verifyBody, _ := json.Marshal(verifyReq)
verifierURL := os.Getenv("VERIFIER_URL")
if verifierURL == "" {
verifierURL = "http://127.0.0.1:3002"
}
resp, err := http.Post(verifierURL+"/verify", "application/json", bytes.NewBuffer(verifyBody))
body, _ := json.Marshal(verifyReq)
resp, err := http.Post("http://127.0.0.1:3002/verify", "application/json", bytes.NewBuffer(body))
if err != nil {
c.JSON(500, gin.H{"error": "Verification service unavailable"})
c.JSON(500, gin.H{"error": "verifier unavailable"})
Comment on lines +271 to +285

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Duplicate verification request code - remove the first block.

Lines 198-212 contain an incomplete verification request implementation using http.Post without timeout handling. This is followed by the correct implementation on lines 214-260 that properly uses context with timeout.

Remove the first block (lines 198-212) and keep only the second implementation.

🤖 Prompt for AI Agents
In @gateway/main.go around lines 198-212, Remove the duplicate, incomplete
verification block that constructs verifyReq and calls http.Post (the code that
creates verifyReq, does body, _ := json.Marshal(...), then resp, err :=
http.Post(...), and its immediate error branch), and retain only the subsequent
correct implementation that uses a context with timeout; ensure you do not leave
duplicate declarations of verifyReq, body, or signature and that
imports/variables used by the remaining context-with-timeout implementation
remain unchanged.

Comment on lines +271 to +285

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merge conflict: duplicate payment verification code that conflicts with the refactored verifyPayment() function used later. Lines 271-285 make a direct HTTP call without using context, missing error handling (line 285 has no return), and this code block is unreachable due to the return on line 268.

Delete this entire conflicted section - the correct implementation uses verifyPayment() on line 311.

Prompt To Fix With AI
This is a comment left during a code review.
Path: gateway/main.go
Line: 271:285

Comment:
Merge conflict: duplicate payment verification code that conflicts with the refactored `verifyPayment()` function used later. Lines 271-285 make a direct HTTP call without using context, missing error handling (line 285 has no `return`), and this code block is unreachable due to the `return` on line 268.

Delete this entire conflicted section - the correct implementation uses `verifyPayment()` on line 311.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +284 to +285

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing return statement after sending error response.

Suggested change
if err != nil {
c.JSON(500, gin.H{"error": "verifier unavailable"})
resp, err := http.Post("http://127.0.0.1:3002/verify", "application/json", bytes.NewBuffer(body))
if err != nil {
c.JSON(500, gin.H{"error": "verifier unavailable"})
return
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: gateway/main.go
Line: 284:285

Comment:
Missing `return` statement after sending error response.

```suggestion
	resp, err := http.Post("http://127.0.0.1:3002/verify", "application/json", bytes.NewBuffer(body))
	if err != nil {
		c.JSON(500, gin.H{"error": "verifier unavailable"})
		return
	}
```


How can I resolve this? If you propose a fix, please make it concise.

return
}
defer resp.Body.Close()

var verifyResp VerifyResponse
if err := json.NewDecoder(resp.Body).Decode(&verifyResp); err != nil {
c.JSON(500, gin.H{"error": "Failed to decode verification response"})
return
}
_ = json.NewDecoder(resp.Body).Decode(&verifyResp)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Silently ignoring JSON decode error can mask verification failures.

The decode error is discarded with _ = json.NewDecoder(...). If the verifier returns malformed JSON or an unexpected response, verifyResp.IsValid defaults to false, causing legitimate payments to fail without any indication of the actual problem.

🔎 Proposed fix
-	_ = json.NewDecoder(resp.Body).Decode(&verifyResp)
+	if err := json.NewDecoder(resp.Body).Decode(&verifyResp); err != nil {
+		log.Printf("error decoding verifier response: %v", err)
+		c.JSON(500, gin.H{"error": "Invalid verifier response"})
+		return
+	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
_ = json.NewDecoder(resp.Body).Decode(&verifyResp)
if err := json.NewDecoder(resp.Body).Decode(&verifyResp); err != nil {
log.Printf("error decoding verifier response: %v", err)
c.JSON(500, gin.H{"error": "Invalid verifier response"})
return
}
🤖 Prompt for AI Agents
In @gateway/main.go around line 263, The JSON decode error from
json.NewDecoder(resp.Body).Decode(&verifyResp) is being ignored, which can hide
malformed verifier responses and cause verifyResp.IsValid to default false;
update the code to capture the Decode error into a variable, check it, and
handle it (log the error with context and body contents if helpful, and return
or propagate an error instead of proceeding), ensuring any non-nil decode error
triggers a clear failure path rather than silently treating the payment as
invalid.


if !verifyResp.IsValid {
c.JSON(403, gin.H{"error": "Invalid Signature", "details": verifyResp.Error})
c.Set("payment_verified", false)
c.JSON(403, gin.H{"error": "invalid signature"})
return
}

// 3. Call AI Service
c.Set("payment_verified", true)
c.Set("user_wallet", verifyResp.RecoveredAddress)

var req SummarizeRequest
if err := c.BindJSON(&req); err != nil {
c.JSON(400, gin.H{"error": "Invalid request body"})
c.JSON(400, gin.H{"error": "invalid body"})
return
Comment on lines +414 to +428

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merge conflict: unreachable duplicate code inside verifyPayment() function. Lines 414-428 reference c.Set(), c.JSON(), and c.BindJSON() but c (gin.Context) is not available in this function - it takes context.Context, not gin.Context.

Delete this entire section - the correct return logic is on line 433.

Prompt To Fix With AI
This is a comment left during a code review.
Path: gateway/main.go
Line: 414:428

Comment:
Merge conflict: unreachable duplicate code inside `verifyPayment()` function. Lines 414-428 reference `c.Set()`, `c.JSON()`, and `c.BindJSON()` but `c` (gin.Context) is not available in this function - it takes `context.Context`, not `gin.Context`.

Delete this entire section - the correct return logic is on line 433.

How can I resolve this? If you propose a fix, please make it concise.

}

summary, err := callOpenRouter(req.Text)
if err != nil {
c.JSON(500, gin.H{"error": "AI Service Failed", "details": err.Error()})
c.JSON(500, gin.H{"error": err.Error()})
return
Comment on lines +464 to +471

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merge conflict: duplicate error handling logic inside generateAndSendReceipt(). Lines 464-471 duplicate timeout/error handling in a position that makes no sense (after marshaling receipt, before checking for error). This code is unreachable and conflicted.

Delete lines 464-471 - correct error handling for json.Marshal(receipt) is on line 472.

Prompt To Fix With AI
This is a comment left during a code review.
Path: gateway/main.go
Line: 464:471

Comment:
Merge conflict: duplicate error handling logic inside `generateAndSendReceipt()`. Lines 464-471 duplicate timeout/error handling in a position that makes no sense (after marshaling receipt, before checking for error). This code is unreachable and conflicted.

Delete lines 464-471 - correct error handling for `json.Marshal(receipt)` is on line 472.

How can I resolve this? If you propose a fix, please make it concise.

}
Comment thread
magic-peach marked this conversation as resolved.

c.JSON(200, gin.H{"result": summary})
}

// createPaymentContext constructs a PaymentContext prefilled with the recipient address (from RECIPIENT_ADDRESS or a fallback), the USDC token, amount "0.001", a newly generated UUID nonce, and chain ID 8453.
/* -------------------- Helpers -------------------- */

func createPaymentContext() PaymentContext {
return PaymentContext{
Recipient: getRecipientAddress(),
Expand All @@ -171,101 +158,37 @@ func createPaymentContext() PaymentContext {
}
}

// getRecipientAddress retrieves the recipient address from the RECIPIENT_ADDRESS environment variable.
// If RECIPIENT_ADDRESS is unset, it logs a warning and returns the default address "0x2cAF48b4BA1C58721a85dFADa5aC01C2DFa62219".
func getRecipientAddress() string {
addr := os.Getenv("RECIPIENT_ADDRESS")
if addr == "" {
log.Println("Warning: RECIPIENT_ADDRESS not set, using default")
return "0x2cAF48b4BA1C58721a85dFADa5aC01C2DFa62219"
}
return addr
}

// getPaymentAmount returns the payment amount from the PAYMENT_AMOUNT environment variable.
// If unset, it defaults to "0.001".
func getPaymentAmount() string {
amount := os.Getenv("PAYMENT_AMOUNT")
if amount == "" {
a := os.Getenv("PAYMENT_AMOUNT")
if a == "" {
return "0.001"
}
return amount
return a
}

// getChainID returns the blockchain chain ID from the CHAIN_ID environment variable.
// If unset or invalid, it defaults to 8453 (Base).
func getChainID() int {
chainIDStr := os.Getenv("CHAIN_ID")
if chainIDStr == "" {
id := os.Getenv("CHAIN_ID")
if id == "" {
return 8453
}
chainID, err := strconv.Atoi(chainIDStr)
n, err := strconv.Atoi(id)
if err != nil {
log.Printf("Warning: Invalid CHAIN_ID '%s', using default 8453", chainIDStr)
return 8453
}
return chainID
return n
}

// callOpenRouter sends the given text to the OpenRouter chat completions API
// requesting a two-sentence summary and returns the generated summary.
// It reads OPENROUTER_API_KEY for authorization and OPENROUTER_MODEL to select
// the model (defaults to "z-ai/glm-4.5-air:free" if unset).
func callOpenRouter(text string) (string, error) {
apiKey := os.Getenv("OPENROUTER_API_KEY")
model := os.Getenv("OPENROUTER_MODEL")
if model == "" {
model = "z-ai/glm-4.5-air:free"
}

prompt := fmt.Sprintf("Summarize this text in 2 sentences: %s", text)

reqBody, _ := json.Marshal(map[string]interface{}{
"model": model,
"messages": []map[string]string{
{"role": "user", "content": prompt},
},
})

req, _ := http.NewRequest("POST", "https://openrouter.ai/api/v1/chat/completions", bytes.NewBuffer(reqBody))
req.Header.Set("Authorization", "Bearer "+apiKey)
req.Header.Set("Content-Type", "application/json")

client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()

var result map[string]interface{}
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return "", fmt.Errorf("failed to decode AI response: %w", err)
if text == "" {
return "", fmt.Errorf("empty text")
}

choices, ok := result["choices"].([]interface{})
if !ok || len(choices) == 0 {
return "", fmt.Errorf("invalid response from AI provider: no choices")
}

choice, ok := choices[0].(map[string]interface{})
if !ok {
return "", fmt.Errorf("invalid response from AI provider: malformed choice")
}

message, ok := choice["message"].(map[string]interface{})
if !ok {
return "", fmt.Errorf("invalid response from AI provider: malformed message")
}

content, ok := message["content"].(string)
if !ok {
return "", fmt.Errorf("invalid response from AI provider: missing content")
}

return content, nil
}

func handleHealth(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"status": "ok", "service": "gateway"})
return "stub summary", nil
Comment on lines 523 to +577

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merge conflict: duplicate callOpenRouter() function definition. Lines 523-525 define a stub version that returns "stub summary", while lines 526-600 contain the full implementation. The stub will never execute and line 577 return "stub summary", nil is unreachable dead code.

Delete the stub function (lines 523-525) and the unreachable return (line 577).

Prompt To Fix With AI
This is a comment left during a code review.
Path: gateway/main.go
Line: 523:577

Comment:
Merge conflict: duplicate `callOpenRouter()` function definition. Lines 523-525 define a stub version that returns `"stub summary"`, while lines 526-600 contain the full implementation. The stub will never execute and line 577 `return "stub summary", nil` is unreachable dead code.

Delete the stub function (lines 523-525) and the unreachable return (line 577).

How can I resolve this? If you propose a fix, please make it concise.

}
Loading