-
Notifications
You must be signed in to change notification settings - Fork 33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(rest-api): API gateway for rfq-indexer API and rfq API + swagger merge [SLT-339] #3323
Conversation
WalkthroughThe pull request introduces several changes across multiple files, primarily focusing on updates to configuration and dependencies. The Changes
Possibly related PRs
Suggested labels
Suggested reviewers
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
Documentation and Community
|
Deploying sanguine-fe with
|
Latest commit: |
81877a7
|
Status: | ✅ Deploy successful! |
Preview URL: | https://5ac89975.sanguine-fe.pages.dev |
Branch Preview URL: | https://api-gateway.sanguine-fe.pages.dev |
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #3323 +/- ##
===================================================
- Coverage 33.27199% 33.24228% -0.02972%
===================================================
Files 543 543
Lines 34777 34778 +1
Branches 82 82
===================================================
- Hits 11571 11561 -10
- Misses 22183 22195 +12
+ Partials 1023 1022 -1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 10
🧹 Outside diff range and nitpick comments (9)
packages/rest-api/package.json (1)
Line range hint
8-20
: Add npm scripts for swagger operationsSeveral swagger packages have been added but there are no corresponding npm scripts to utilize them. Consider adding scripts for swagger validation and merging.
Add these scripts to the "scripts" section:
"scripts": { ... + "swagger:validate": "swagger-cli validate ./src/openapi/openapi.yaml", + "swagger:merge": "swagger-merger -i ./src/openapi/openapi.yaml -o ./dist/openapi.yaml", "test": "jest",packages/rest-api/src/app.ts (1)
16-35
: Documentation: Add API gateway documentation and implement health checks.The API gateway implementation would benefit from:
- Documentation explaining the purpose and expected usage of each proxy route
- Health check endpoints for downstream services
- Metrics collection for monitoring proxy performance and reliability
Consider adding JSDoc comments above the
apiProxyRoutes
configuration:/** * API Gateway proxy route configuration * * RFQ Indexer API: * - Purpose: Handles RFQ indexing and search operations * - Rate limits: 100 requests per 15 minutes per IP * - Expected latency: < 1000ms * * RFQ API: * - Purpose: Manages RFQ creation and lifecycle * - Rate limits: 100 requests per 15 minutes per IP * - Expected latency: < 500ms */ const apiProxyRoutes = [...]Would you like me to help create:
- Health check endpoints for the proxied services?
- Metrics collection middleware?
- API documentation for the gateway endpoints?
package.json (1)
52-60
: Consider documenting the reason for these updates.These ESLint-related updates seem tangential to the API gateway feature. Consider documenting the motivation for these changes in the PR description.
services/rfq/api/docs/swagger.json (4)
Line range hint
1-521
: Critical: Add security definitions and authentication requirementsThe API specification lacks security definitions and authentication requirements. This is critical for an API handling financial data and trading operations.
Add the following security definitions to protect the API endpoints:
{ "swagger": "2.0", "info": { "contact": {} }, + "securityDefinitions": { + "Bearer": { + "type": "apiKey", + "name": "Authorization", + "in": "header", + "description": "JWT token, prefixed with 'Bearer: '" + } + }, + "security": [ + { + "Bearer": [] + } + ], "paths": {Each path operation should also specify security requirements:
"/rfq": { "put": { "description": "Handle user quote request and return the best quote available.", + "security": [ + { + "Bearer": [] + } + ], "consumes": [🧰 Tools
🪛 checkov
[HIGH] 1-521: Ensure that security requirement defined in securityDefinitions - version 2.0 files
(CKV_OPENAPI_6)
[HIGH] 1-521: Ensure that the global security field has rules defined
(CKV_OPENAPI_4)
[HIGH] 1-521: Ensure that security operations is not empty.
(CKV_OPENAPI_5)
[HIGH] 1-521: Ensure that securityDefinitions is defined and not empty - version 2.0 files
(CKV_OPENAPI_1)
Line range hint
1-521
: Enhance API versioning documentationThe API uses header-based versioning (
X-Api-Version
) but lacks crucial version-related information.Add version information to the info section:
"swagger": "2.0", "info": { + "version": "1.0.0", + "title": "RFQ API", + "description": "API for handling Request for Quote operations. Supports version negotiation via X-Api-Version header.", "contact": {} },🧰 Tools
🪛 checkov
[HIGH] 1-521: Ensure that security requirement defined in securityDefinitions - version 2.0 files
(CKV_OPENAPI_6)
[HIGH] 1-521: Ensure that the global security field has rules defined
(CKV_OPENAPI_4)
[HIGH] 1-521: Ensure that security operations is not empty.
(CKV_OPENAPI_5)
[HIGH] 1-521: Ensure that securityDefinitions is defined and not empty - version 2.0 files
(CKV_OPENAPI_1)
Line range hint
261-289
: Enhance WebSocket endpoint documentationThe WebSocket endpoint
/rfq_stream
lacks crucial operational details.Consider adding the following details to the endpoint documentation:
"/rfq_stream": { "get": { "description": "Establish a WebSocket connection to receive active quote requests.", + "x-websocket-metadata": { + "heartbeat": { + "interval": "30s", + "timeout": "90s" + }, + "rate-limit": { + "messages-per-minute": 100 + }, + "reconnection": { + "strategy": "exponential-backoff", + "max-attempts": 5 + } + }, "produces": [🧰 Tools
🪛 checkov
[HIGH] 1-521: Ensure that security requirement defined in securityDefinitions - version 2.0 files
(CKV_OPENAPI_6)
[HIGH] 1-521: Ensure that the global security field has rules defined
(CKV_OPENAPI_4)
[HIGH] 1-521: Ensure that security operations is not empty.
(CKV_OPENAPI_5)
[HIGH] 1-521: Ensure that securityDefinitions is defined and not empty - version 2.0 files
(CKV_OPENAPI_1)
Line range hint
1-521
: Add error response definitionsThe API specification lacks error response definitions for common HTTP status codes.
Add common error responses and schema:
"definitions": { + "Error": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "details": { + "type": "object" + } + } + },And for each endpoint, add error responses:
"responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/model.PutRFQResponse" } }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/Error" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/Error" + } + }, + "429": { + "description": "Too Many Requests", + "schema": { + "$ref": "#/definitions/Error" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/Error" + } + }🧰 Tools
🪛 checkov
[HIGH] 1-521: Ensure that security requirement defined in securityDefinitions - version 2.0 files
(CKV_OPENAPI_6)
[HIGH] 1-521: Ensure that the global security field has rules defined
(CKV_OPENAPI_4)
[HIGH] 1-521: Ensure that security operations is not empty.
(CKV_OPENAPI_5)
[HIGH] 1-521: Ensure that securityDefinitions is defined and not empty - version 2.0 files
(CKV_OPENAPI_1)
packages/rest-api/swagger.json (2)
2632-2660
: Enhance WebSocket documentationThe WebSocket endpoint documentation lacks important details about the message format and connection handling.
Add the following information:
- Message format for both client and server
- Heartbeat mechanism
- Reconnection strategy
- Example WebSocket messages
326-377
: Expand error response documentationWhile the basic error handling is in place, some common error scenarios are not documented.
Add these additional error responses:
- 429 Too Many Requests (rate limiting)
- 401 Unauthorized
- 403 Forbidden
Example addition:
"responses": { + "401": { + "description": "Unauthorized - Invalid or missing authentication", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Invalid API key" + } + } + } + } + } + }, + "429": { + "description": "Too Many Requests", + "headers": { + "Retry-After": { + "schema": { + "type": "integer", + "description": "Number of seconds to wait before retrying" + } + } + } + }
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
⛔ Files ignored due to path filters (1)
yarn.lock
is excluded by!**/yarn.lock
,!**/*.lock
📒 Files selected for processing (7)
- .vscode/settings.json (2 hunks)
- package.json (1 hunks)
- packages/rest-api/package.json (2 hunks)
- packages/rest-api/src/app.ts (2 hunks)
- packages/rest-api/src/swagger.ts (1 hunks)
- packages/rest-api/swagger.json (1 hunks)
- services/rfq/api/docs/swagger.json (1 hunks)
🧰 Additional context used
🪛 GitHub Check: lint
packages/rest-api/src/app.ts
[failure] 7-7:
There should be at least one empty line between import groups
[failure] 8-8:
fs
import should occur before import ofexpress
[failure] 9-9:
path
import should occur before import ofexpress
[warning] 101-101:
Delete⏎
🪛 Gitleaks
packages/rest-api/swagger.json
287-287: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
300-300: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
1245-1245: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
🪛 checkov
packages/rest-api/swagger.json
[HIGH] 1-2887: Ensure that the global security field has rules defined
(CKV_OPENAPI_4)
[HIGH] 1-2887: Ensure that security operations is not empty.
(CKV_OPENAPI_5)
services/rfq/api/docs/swagger.json
[HIGH] 1-521: Ensure that security requirement defined in securityDefinitions - version 2.0 files
(CKV_OPENAPI_6)
[HIGH] 1-521: Ensure that the global security field has rules defined
(CKV_OPENAPI_4)
[HIGH] 1-521: Ensure that security operations is not empty.
(CKV_OPENAPI_5)
[HIGH] 1-521: Ensure that securityDefinitions is defined and not empty - version 2.0 files
(CKV_OPENAPI_1)
🔇 Additional comments (4)
.vscode/settings.json (2)
29-29
: LGTM!Adding a newline at the end of file follows standard practice.
7-7
: Verify Prettier configuration for TypeScript formatting.Switching to Prettier as the default formatter is a good choice, but please ensure:
- A
.prettierrc
configuration exists- Prettier rules don't conflict with ESLint rules
✅ Verification successful
Let me gather more information about the Prettier configuration since we found
eslint-config-prettier
but no.prettierrc
file.
Let's try one more time with the correct flags to check hidden files:
Prettier configuration is properly set up through ESLint integration
The switch to Prettier as the default formatter is safe because:
- ESLint is configured with
plugin:prettier/recommended
in the extends arrayeslint-config-prettier
is installed (version ^8.3.0)- Prettier rules are properly configured in ESLint with
'prettier/prettier': 'warn'
- The configuration is consistent across multiple packages in the monorepo
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Check for Prettier configuration and potential conflicts # Test 1: Check if Prettier config exists echo "Checking for Prettier config files..." fd -t f "^\.prettierrc(\.(js|json|yaml|yml))?$|^prettier\.config\.(js|cjs)$" # Test 2: Check if eslint-config-prettier is installed to prevent conflicts echo "Checking for eslint-config-prettier in package.json..." fd "package.json" -t f -x jq -r '.dependencies["eslint-config-prettier"] // .devDependencies["eslint-config-prettier"] // "not found"'Length of output: 624
Script:
#!/bin/bash # Check for Prettier configuration in package.json and potential conflicts in ESLint config # Test 1: Check if Prettier config exists in package.json echo "Checking for Prettier config in package.json..." fd "package.json" -t f -x jq -r '.prettier // empty' # Test 2: Check ESLint config for Prettier integration echo "Checking ESLint config files..." fd "^\.eslintrc(\.(js|json|yaml|yml))?$" -t f -x cat {}Length of output: 498
Script:
#!/bin/bash # Check for Prettier configuration in package.json and ESLint config with hidden files # Test 1: Check if Prettier config exists in package.json echo "Checking for Prettier config in package.json..." fd "package.json" -t f -x jq -r '.prettier // empty' # Test 2: Check ESLint config files echo "Checking ESLint config files..." fd -H "^\.eslintrc(\.(js|json|yaml|yml))?$" -t f -x cat {} # Test 3: Check if prettier is listed in extends in any JS/JSON file echo "Checking for Prettier in ESLint extends..." rg -l "extends.*prettier" --type js --type jsonLength of output: 18971
packages/rest-api/package.json (1)
31-31
: LGTM: http-proxy-middleware additionThe added proxy middleware package is compatible with the project's Node.js version requirement (>=18.17.0).
package.json (1)
52-52
: Request: Update yarn.lock file.These dependency updates require corresponding changes in the lock file to ensure consistent installations across environments.
#!/bin/bash # Check if yarn.lock exists and contains the updated versions echo "Checking yarn.lock for updated versions..." if [ -f "yarn.lock" ]; then echo "Checking for updated eslint version..." rg "eslint@\^8\.53\.0" yarn.lock echo "Checking for updated eslint-config-standard version..." rg "eslint-config-standard@\^17\.0\.0" yarn.lock echo "Checking for updated eslint-plugin-promise version..." rg "eslint-plugin-promise@\^6\.0\.0" yarn.lock fiAlso applies to: 54-54, 60-60
// Define the path to your static swagger.json file | ||
const swaggerFilePath = path.join(__dirname, '../swagger.json') | ||
|
||
const isDevelopment = process.env.NODE_ENV === 'development' | ||
const serverUrl = isDevelopment | ||
? 'http://localhost:3000' | ||
: 'https://api.synapseprotocol.com' | ||
// Read the static swagger.json file | ||
const specs = JSON.parse(fs.readFileSync(swaggerFilePath, 'utf8')) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add error handling and consider asynchronous file reading.
The current implementation has several potential issues:
- Synchronous file reading can block the Node.js event loop
- No error handling for missing file or invalid JSON
- No validation of the parsed swagger specification
Consider implementing this more robust approach:
-// Define the path to your static swagger.json file
-const swaggerFilePath = path.join(__dirname, '../swagger.json')
-
-// Read the static swagger.json file
-const specs = JSON.parse(fs.readFileSync(swaggerFilePath, 'utf8'))
+import { OpenAPIV3 } from 'openapi-types'
+
+const swaggerFilePath = path.join(__dirname, '../swagger.json')
+
+function loadSwaggerSpec(): OpenAPIV3.Document {
+ try {
+ const fileContent = fs.readFileSync(swaggerFilePath, 'utf8')
+ const parsedSpec = JSON.parse(fileContent)
+
+ // Basic validation of the OpenAPI spec
+ if (!parsedSpec.openapi || !parsedSpec.info || !parsedSpec.paths) {
+ throw new Error('Invalid OpenAPI specification format')
+ }
+
+ return parsedSpec
+ } catch (error) {
+ if (error instanceof Error) {
+ throw new Error(`Failed to load Swagger specification: ${error.message}`)
+ }
+ throw error
+ }
+}
+
+const specs = loadSwaggerSpec()
Committable suggestion was skipped due to low confidence.
import fs from 'fs' | ||
import path from 'path' | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-var-requires | ||
const packageJson = require('../package.json') | ||
// Define the path to your static swagger.json file | ||
const swaggerFilePath = path.join(__dirname, '../swagger.json') | ||
|
||
const isDevelopment = process.env.NODE_ENV === 'development' | ||
const serverUrl = isDevelopment | ||
? 'http://localhost:3000' | ||
: 'https://api.synapseprotocol.com' | ||
// Read the static swagger.json file | ||
const specs = JSON.parse(fs.readFileSync(swaggerFilePath, 'utf8')) | ||
|
||
const options: swaggerJsdoc.Options = { | ||
definition: { | ||
openapi: '3.0.0', | ||
info: { | ||
title: 'Synapse Protocol REST API', | ||
version: packageJson.version, | ||
description: 'API documentation for the Synapse Protocol REST API', | ||
}, | ||
servers: [ | ||
{ | ||
url: serverUrl, | ||
}, | ||
], | ||
}, | ||
apis: ['./src/routes/*.ts', './src/*.ts'], | ||
} | ||
|
||
export const specs = swaggerJsdoc(options) | ||
// Export the specs for use in your application | ||
export { specs } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codebase verification
🛠️ Refactor suggestion
Add TypeScript types and validation for better API specification safety
The suggestion is valid as:
- The project uses TypeScript with strict mode disabled
- The swagger.json file exists and is valid OpenAPI spec
- The specs are used in the application with swagger-ui-express
- No type definitions or validation are currently implemented
Required changes:
- Install
openapi-types
as a dev dependency - Add type definitions for the OpenAPI specification
- Consider enabling TypeScript's strict mode for better type safety
Example implementation:
import { OpenAPIV3 } from 'openapi-types'
import fs from 'fs'
import path from 'path'
const swaggerFilePath = path.join(__dirname, '../swagger.json')
const rawSpecs = fs.readFileSync(swaggerFilePath, 'utf8')
// Parse and type the specs
export const specs: OpenAPIV3.Document = JSON.parse(rawSpecs)
🔗 Analysis chain
Consider adding TypeScript types and validation.
The current implementation lacks type safety and runtime validation of the OpenAPI specification.
- Add TypeScript types for better type safety
- Consider using a validation library like
openapi-validator
+import { OpenAPIV3 } from 'openapi-types'
import fs from 'fs'
import path from 'path'
-// Export the specs for use in your application
-export { specs }
+export const specs: OpenAPIV3.Document = loadSwaggerSpec()
Let's verify the OpenAPI specification file exists and is valid:
Let me gather more information about the current TypeScript setup and dependencies to provide a more informed response.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check if swagger.json exists and is valid JSON
if [ -f "packages/rest-api/swagger.json" ]; then
if jq empty "packages/rest-api/swagger.json" 2>/dev/null; then
echo "swagger.json exists and is valid JSON"
# Check for required OpenAPI fields
jq -e '.openapi and .info and .paths' "packages/rest-api/swagger.json"
else
echo "swagger.json is not valid JSON"
fi
else
echo "swagger.json does not exist"
fi
Length of output: 246
Script:
#!/bin/bash
# Check if openapi-types is already installed
grep -r "openapi-types" packages/rest-api/package.json || echo "openapi-types not found in package.json"
# Check TypeScript configuration
cat packages/rest-api/tsconfig.json 2>/dev/null || echo "tsconfig.json not found"
# Check for existing type definitions or validation
rg -g "*.ts" "OpenAPI|swagger" packages/rest-api/src/ -A 2
Length of output: 2133
packages/rest-api/package.json
Outdated
"swagger-cli": "^4.0.4", | ||
"swagger-combine": "^1.4.0", | ||
"swagger-merger": "^1.5.4", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider consolidating swagger packages
There appear to be multiple packages with overlapping functionality:
- swagger-merger and swagger-merge serve similar purposes
- swagger-combine provides similar functionality to swagger-merger
Consider choosing one package to reduce maintenance overhead and potential confusion.
Suggested approach: Use only swagger-cli and swagger-merger, removing swagger-combine and swagger-merge:
"swagger-cli": "^4.0.4",
- "swagger-combine": "^1.4.0",
"swagger-merger": "^1.5.4",
...
- "swagger-merge": "^0.4.0",
Also applies to: 56-56
packages/rest-api/src/app.ts
Outdated
@@ -1,15 +1,39 @@ | |||
import express from 'express' | |||
import swaggerUi from 'swagger-ui-express' | |||
import { createProxyMiddleware } from 'http-proxy-middleware' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove unused imports and fix import ordering.
The fs
and path
modules are imported but never used in the code. Additionally, the import order should be standardized.
Apply this diff to fix the issues:
+import fs from 'fs'
+import path from 'path'
import express from 'express'
import swaggerUi from 'swagger-ui-express'
import { createProxyMiddleware } from 'http-proxy-middleware'
-import fs from 'fs'
-import path from 'path'
Also applies to: 8-9
packages/rest-api/src/app.ts
Outdated
const apiProxyRoutes = [ | ||
{ | ||
route: '/rfq-indexer-api', | ||
target: 'https://triumphant-magic-production.up.railway.app', | ||
}, | ||
{ route: '/rfq-api', target: 'https://rfq-api.omnirpc.io/' }, | ||
] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Security: Move sensitive URLs to environment variables.
Hardcoding production URLs in the source code is a security risk and makes environment-specific configuration difficult. These URLs should be configurable via environment variables.
Apply this diff to implement environment-based configuration:
const apiProxyRoutes = [
{
route: '/rfq-indexer-api',
- target: 'https://triumphant-magic-production.up.railway.app',
+ target: process.env.RFQ_INDEXER_API_URL || 'http://localhost:3001',
},
- { route: '/rfq-api', target: 'https://rfq-api.omnirpc.io/' },
+ {
+ route: '/rfq-api',
+ target: process.env.RFQ_API_URL || 'http://localhost:3002',
+ },
]
Also, consider adding validation for these environment variables during application startup.
Committable suggestion was skipped due to low confidence.
packages/rest-api/src/app.ts
Outdated
apiProxyRoutes.forEach(({ route, target }) => { | ||
app.use( | ||
route, | ||
createProxyMiddleware({ | ||
target, | ||
changeOrigin: true, | ||
pathRewrite: { | ||
[`^${route}`]: '', | ||
}, | ||
}) | ||
) | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Security: Add essential security and reliability features to the proxy middleware.
The current proxy implementation lacks several important security and reliability features:
- Rate limiting to prevent abuse
- Request validation
- Timeouts
- Specific error handling for proxy failures
Consider implementing these improvements:
apiProxyRoutes.forEach(({ route, target }) => {
app.use(
route,
+ rateLimit({
+ windowMs: 15 * 60 * 1000, // 15 minutes
+ max: 100 // limit each IP to 100 requests per windowMs
+ }),
createProxyMiddleware({
target,
changeOrigin: true,
+ timeout: 30000, // 30 seconds timeout
+ proxyTimeout: 31000,
pathRewrite: {
[`^${route}`]: '',
},
+ onError: (err, req, res) => {
+ logger.error(`Proxy error: ${err.message}`, { route, target });
+ res.status(502).json({ error: 'Bad Gateway' });
+ },
})
)
})
Also consider:
- Adding request size limits
- Implementing circuit breakers for downstream service protection
- Adding request validation middleware specific to each route
Committable suggestion was skipped due to low confidence.
@@ -49,15 +49,15 @@ | |||
"copyfiles": "^2.3.0", | |||
"depcheck": "^1.4.3", | |||
"doctoc": "^2.2.0", | |||
"eslint": "^8.16.0", | |||
"eslint": "^8.53.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codebase verification
The version updates are mostly compatible, but there's one important issue:
- eslint-config-standard@17.0.0 requires
eslint-plugin-n
as a peer dependency, which is not present in your package.json - All other peer dependencies are satisfied with current versions:
- eslint@^8.53.0 satisfies the requirements
- eslint-plugin-import@^2.26.0 satisfies the requirement
- eslint-plugin-promise@^6.0.0 is exactly the version required
Please add the missing peer dependency:
"eslint-plugin-n": "^15.0.0"
🔗 Analysis chain
Verify compatibility with major version updates.
The updates include major version bumps that might introduce breaking changes:
- eslint-config-standard: 16 -> 17
- eslint-plugin-promise: 5 -> 6
Also applies to: 54-54, 60-60
Let me gather more information about the ESLint configuration and potential peer dependency issues.
Let me check one more thing to verify the peer dependencies of the updated packages.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check for peer dependency warnings in package.json files
echo "Checking for peer dependency requirements..."
rg -A 5 '"peerDependencies"'
# Check if there are any existing ESLint configuration files
echo "Checking for ESLint config files..."
fd -e .eslintrc.js -e .eslintrc.json -e .eslintrc.yml
Length of output: 685
Script:
#!/bin/bash
# Check for ESLint configuration
echo "Checking ESLint configuration..."
fd '.eslintrc' --type f --exec cat {}
# Check package.json for ESLint related dependencies
echo -e "\nChecking ESLint related dependencies..."
rg '"eslint.*":' package.json
# Check for any existing ESLint errors with current config
echo -e "\nChecking for potential ESLint configuration issues..."
fd '.js' --type f --exec grep -l "eslint-disable" {} \;
Length of output: 876
Script:
#!/bin/bash
# Check npm registry for peer dependencies of the updated packages
echo "Checking peer dependencies for eslint-config-standard@17.0.0..."
curl -s https://registry.npmjs.org/eslint-config-standard/17.0.0 | jq '.peerDependencies'
echo -e "\nChecking peer dependencies for eslint-plugin-promise@6.0.0..."
curl -s https://registry.npmjs.org/eslint-plugin-promise/6.0.0 | jq '.peerDependencies'
Length of output: 619
"servers": [ | ||
{ | ||
"url": "http://localhost:3000" | ||
} | ||
], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update server configuration for production use
The server URL is currently set to localhost, which is not suitable for production deployment.
Add production and staging server URLs:
"servers": [
{
- "url": "http://localhost:3000"
+ "url": "https://api.synapse.protocol",
+ "description": "Production server"
},
+ {
+ "url": "https://api.staging.synapse.protocol",
+ "description": "Staging server"
+ },
+ {
+ "url": "http://localhost:3000",
+ "description": "Development server"
+ }
]
📝 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.
"servers": [ | |
{ | |
"url": "http://localhost:3000" | |
} | |
], | |
"servers": [ | |
{ | |
"url": "https://api.synapse.protocol", | |
"description": "Production server" | |
}, | |
{ | |
"url": "https://api.staging.synapse.protocol", | |
"description": "Staging server" | |
}, | |
{ | |
"url": "http://localhost:3000", | |
"description": "Development server" | |
} | |
], |
packages/rest-api/swagger.json
Outdated
"items": { | ||
"type": "string" | ||
} | ||
}, | ||
"user_address": { | ||
"type": "string" | ||
} | ||
} | ||
}, | ||
"model.PutRFQResponse": { | ||
"type": "object", | ||
"properties": { | ||
"dest_amount": { | ||
"type": "string" | ||
}, | ||
"quote_id": { | ||
"type": "string" | ||
}, | ||
"quote_type": { | ||
"type": "string" | ||
}, | ||
"reason": { | ||
"type": "string" | ||
}, | ||
"relayer_address": { | ||
"type": "string" | ||
}, | ||
"success": { | ||
"type": "boolean" | ||
} | ||
} | ||
}, | ||
"model.PutRelayerQuoteRequest": { | ||
"type": "object", | ||
"properties": { | ||
"dest_amount": { | ||
"type": "string" | ||
}, | ||
"dest_chain_id": { | ||
"type": "integer" | ||
}, | ||
"dest_fast_bridge_address": { | ||
"type": "string" | ||
}, | ||
"dest_token_addr": { | ||
"type": "string" | ||
}, | ||
"fixed_fee": { | ||
"type": "string" | ||
}, | ||
"max_origin_amount": { | ||
"type": "string" | ||
}, | ||
"origin_chain_id": { | ||
"type": "integer" | ||
}, | ||
"origin_fast_bridge_address": { | ||
"type": "string" | ||
}, | ||
"origin_token_addr": { | ||
"type": "string" | ||
} | ||
} | ||
}, | ||
"model.QuoteData": { | ||
"type": "object", | ||
"properties": { | ||
"dest_amount": { | ||
"type": "string" | ||
}, | ||
"dest_chain_id": { | ||
"type": "integer" | ||
}, | ||
"dest_token_addr": { | ||
"type": "string" | ||
}, | ||
"expiration_window": { | ||
"type": "integer" | ||
}, | ||
"origin_amount": { | ||
"type": "string" | ||
}, | ||
"origin_chain_id": { | ||
"type": "integer" | ||
}, | ||
"origin_token_addr": { | ||
"type": "string" | ||
}, | ||
"quote_id": { | ||
"type": "string" | ||
}, | ||
"relayer_address": { | ||
"type": "string" | ||
} | ||
} | ||
} | ||
} | ||
}, | ||
"tags": [] | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add security schemes and authentication requirements
The API specification lacks global security definitions and authentication requirements. This is critical for an API handling financial transactions and sensitive operations.
- Add a global security scheme (e.g., OAuth2, API keys)
- Define security requirements for sensitive endpoints
- Implement rate limiting
Example addition:
{
"openapi": "3.0.0",
+ "security": [
+ {
+ "bearerAuth": []
+ }
+ ],
"components": {
"securitySchemes": {
+ "bearerAuth": {
+ "type": "http",
+ "scheme": "bearer",
+ "bearerFormat": "JWT"
+ }
}
}
}
📝 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.
{ | |
"openapi": "3.0.0", | |
"info": { | |
"title": "Synapse Protocol REST API", | |
"version": "1.7.0", | |
"description": "API documentation for the Synapse Protocol REST API" | |
}, | |
"servers": [ | |
{ | |
"url": "http://localhost:3000" | |
} | |
], | |
"paths": { | |
"/bridgeLimits": { | |
"get": { | |
"summary": "Get min/max origin values for bridge quote", | |
"description": "Retrieve min/max bridgeable amounts to bridge from source chain to destination chain. Returns null for min/max amounts if limits are unavailable.", | |
"parameters": [ | |
{ | |
"in": "query", | |
"name": "fromChain", | |
"required": true, | |
"schema": { | |
"type": "integer" | |
}, | |
"description": "The source chain ID." | |
}, | |
{ | |
"in": "query", | |
"name": "toChain", | |
"required": true, | |
"schema": { | |
"type": "integer" | |
}, | |
"description": "The destination chain ID." | |
}, | |
{ | |
"in": "query", | |
"name": "fromToken", | |
"required": true, | |
"schema": { | |
"type": "string" | |
}, | |
"description": "The address of the token on the source chain." | |
}, | |
{ | |
"in": "query", | |
"name": "toToken", | |
"required": true, | |
"schema": { | |
"type": "string" | |
}, | |
"description": "The address of the token on the destination chain." | |
} | |
], | |
"responses": { | |
"200": { | |
"description": "Successful response containing min and max origin amounts.", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"maxOriginAmount": { | |
"type": "string", | |
"description": "Maximum amount of tokens that can be bridged from the origin chain." | |
}, | |
"minOriginAmount": { | |
"type": "string", | |
"description": "Minimum amount of tokens that can be bridged from the origin chain." | |
} | |
} | |
}, | |
"example": { | |
"maxOriginAmount": "999600", | |
"minOriginAmount": "4" | |
} | |
} | |
} | |
}, | |
"400": { | |
"description": "Invalid input", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"error": { | |
"type": "object", | |
"properties": { | |
"value": { | |
"type": "string" | |
}, | |
"message": { | |
"type": "string" | |
}, | |
"field": { | |
"type": "string" | |
}, | |
"location": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
}, | |
"example": { | |
"error": { | |
"value": "999", | |
"message": "Unsupported fromChain", | |
"field": "fromChain", | |
"location": "query" | |
} | |
} | |
} | |
} | |
}, | |
"500": { | |
"description": "Server error", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"error": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
"/bridge": { | |
"get": { | |
"summary": "Get quotes for bridging tokens between chains", | |
"description": "Retrieve list of detailed bridge quotes based on origin and destination chains based on tokens and amount", | |
"parameters": [ | |
{ | |
"in": "query", | |
"name": "fromChain", | |
"required": true, | |
"schema": { | |
"type": "integer" | |
}, | |
"description": "The source chain ID" | |
}, | |
{ | |
"in": "query", | |
"name": "toChain", | |
"required": true, | |
"schema": { | |
"type": "integer" | |
}, | |
"description": "The destination chain ID" | |
}, | |
{ | |
"in": "query", | |
"name": "fromToken", | |
"required": true, | |
"schema": { | |
"type": "string" | |
}, | |
"description": "The address of the token on the source chain" | |
}, | |
{ | |
"in": "query", | |
"name": "toToken", | |
"required": true, | |
"schema": { | |
"type": "string" | |
}, | |
"description": "The address of the token on the destination chain" | |
}, | |
{ | |
"in": "query", | |
"name": "amount", | |
"required": true, | |
"schema": { | |
"type": "number" | |
}, | |
"description": "The amount of tokens to bridge" | |
}, | |
{ | |
"in": "query", | |
"name": "originUserAddress", | |
"required": false, | |
"schema": { | |
"type": "string" | |
}, | |
"description": "The address of the user on the origin chain" | |
} | |
], | |
"responses": { | |
"200": { | |
"description": "Successful response", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "array", | |
"items": { | |
"type": "object", | |
"properties": { | |
"id": { | |
"type": "string" | |
}, | |
"feeAmount": { | |
"$ref": "#/components/schemas/BigNumber" | |
}, | |
"feeConfig": { | |
"type": "object", | |
"properties": { | |
"bridgeFee": { | |
"type": "integer" | |
}, | |
"minFee": { | |
"$ref": "#/components/schemas/BigNumber" | |
}, | |
"maxFee": { | |
"$ref": "#/components/schemas/BigNumber" | |
} | |
} | |
}, | |
"routerAddress": { | |
"type": "string" | |
}, | |
"maxAmountOut": { | |
"$ref": "#/components/schemas/BigNumber" | |
}, | |
"originQuery": { | |
"type": "object" | |
}, | |
"destQuery": { | |
"type": "object" | |
}, | |
"estimatedTime": { | |
"type": "integer" | |
}, | |
"bridgeModuleName": { | |
"type": "string" | |
}, | |
"gasDropAmount": { | |
"$ref": "#/components/schemas/BigNumber" | |
}, | |
"originChainId": { | |
"type": "integer" | |
}, | |
"destChainId": { | |
"type": "integer" | |
}, | |
"maxAmountOutStr": { | |
"type": "string" | |
}, | |
"bridgeFeeFormatted": { | |
"type": "string" | |
} | |
} | |
} | |
}, | |
"example": [ | |
{ | |
"id": "01920c87-7f14-7cdf-90e1-e13b2d4af55f", | |
"feeAmount": { | |
"type": "BigNumber", | |
"hex": "0x17d78400" | |
}, | |
"feeConfig": { | |
"bridgeFee": 4000000, | |
"minFee": { | |
"type": "BigNumber", | |
"hex": "0x3d0900" | |
}, | |
"maxFee": { | |
"type": "BigNumber", | |
"hex": "0x17d78400" | |
} | |
}, | |
"routerAddress": "0xd5a597d6e7ddf373a92C8f477DAAA673b0902F48", | |
"maxAmountOut": { | |
"type": "BigNumber", | |
"hex": "0xe89bd2cb27" | |
}, | |
"originQuery": { | |
"routerAdapter": "0x0000000000000000000000000000000000000000", | |
"tokenOut": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", | |
"minAmountOut": { | |
"type": "BigNumber", | |
"hex": "0xe8d4a51000" | |
}, | |
"deadline": { | |
"type": "BigNumber", | |
"hex": "0x66ecb04b" | |
}, | |
"rawParams": "0x" | |
}, | |
"destQuery": { | |
"routerAdapter": "0xd5a597d6e7ddf373a92C8f477DAAA673b0902F48", | |
"tokenOut": "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9", | |
"minAmountOut": { | |
"type": "BigNumber", | |
"hex": "0xe89bd2cb27" | |
}, | |
"deadline": { | |
"type": "BigNumber", | |
"hex": "0x66f5e873" | |
}, | |
"rawParams": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009a2dea7b81cfe3e0011d44d41c5c5142b8d9abdf00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002" | |
}, | |
"estimatedTime": 1020, | |
"bridgeModuleName": "SynapseCCTP", | |
"gasDropAmount": { | |
"type": "BigNumber", | |
"hex": "0x0110d9316ec000" | |
}, | |
"originChainId": 1, | |
"destChainId": 42161, | |
"maxAmountOutStr": "999046.695719", | |
"bridgeFeeFormatted": "400" | |
} | |
] | |
} | |
} | |
}, | |
"400": { | |
"description": "Invalid input", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"error": { | |
"type": "object", | |
"properties": { | |
"value": { | |
"type": "string" | |
}, | |
"message": { | |
"type": "string" | |
}, | |
"field": { | |
"type": "string" | |
}, | |
"location": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
}, | |
"example": { | |
"error": { | |
"value": "999", | |
"message": "Unsupported fromChain", | |
"field": "fromChain", | |
"location": "query" | |
} | |
} | |
} | |
} | |
}, | |
"500": { | |
"description": "Server error", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"error": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
"/bridgeTxInfo": { | |
"get": { | |
"summary": "Get bridge transaction information", | |
"description": "Retrieve transaction information for bridging tokens between chains", | |
"parameters": [ | |
{ | |
"in": "query", | |
"name": "fromChain", | |
"required": true, | |
"schema": { | |
"type": "integer" | |
}, | |
"description": "The source chain ID" | |
}, | |
{ | |
"in": "query", | |
"name": "fromToken", | |
"required": true, | |
"schema": { | |
"type": "string" | |
}, | |
"description": "The address of the token on the source chain" | |
}, | |
{ | |
"in": "query", | |
"name": "toChain", | |
"required": true, | |
"schema": { | |
"type": "integer" | |
}, | |
"description": "The destination chain ID" | |
}, | |
{ | |
"in": "query", | |
"name": "toToken", | |
"required": true, | |
"schema": { | |
"type": "string" | |
}, | |
"description": "The address of the token on the destination chain" | |
}, | |
{ | |
"in": "query", | |
"name": "amount", | |
"required": true, | |
"schema": { | |
"type": "number" | |
}, | |
"description": "The amount of tokens to bridge" | |
}, | |
{ | |
"in": "query", | |
"name": "destAddress", | |
"required": true, | |
"schema": { | |
"type": "string" | |
}, | |
"description": "The destination address for the bridged tokens" | |
}, | |
{ | |
"in": "query", | |
"name": "originUserAddress", | |
"required": false, | |
"schema": { | |
"type": "string" | |
}, | |
"description": "The address of the user on the origin chain" | |
} | |
], | |
"responses": { | |
"200": { | |
"description": "Successful response", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "array", | |
"items": { | |
"type": "object", | |
"properties": { | |
"data": { | |
"type": "string", | |
"description": "Encoded transaction data" | |
}, | |
"to": { | |
"type": "string", | |
"description": "The address of the contract to interact with" | |
}, | |
"value": { | |
"type": "object", | |
"properties": { | |
"type": { | |
"type": "string", | |
"enum": ["BigNumber"] | |
}, | |
"hex": { | |
"type": "string" | |
} | |
}, | |
"description": "The amount of native currency to send with the transaction" | |
} | |
} | |
} | |
}, | |
"example": [ | |
{ | |
"data": "0xc2288147000000000000000000000000abb4f79430002534df3f62e964d62659a010ef3c000000000000000000000000000000000000000000000000000000000000a4b1000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000174876e80000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000174876e8000000000000000000000000000000000000000000000000000000000066ecbadf00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d5a597d6e7ddf373a92c8f477daaa673b0902f48000000000000000000000000fd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb90000000000000000000000000000000000000000000000000000001744e380400000000000000000000000000000000000000000000000000000000066f5f30700000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009a2dea7b81cfe3e0011d44d41c5c5142b8d9abdf00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004", | |
"to": "0xd5a597d6e7ddf373a92C8f477DAAA673b0902F48", | |
"value": { | |
"type": "BigNumber", | |
"hex": "0x00" | |
} | |
} | |
] | |
} | |
} | |
}, | |
"400": { | |
"description": "Invalid input", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"error": { | |
"type": "object", | |
"properties": { | |
"value": { | |
"type": "string" | |
}, | |
"message": { | |
"type": "string" | |
}, | |
"field": { | |
"type": "string" | |
}, | |
"location": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
}, | |
"example": { | |
"error": { | |
"value": "999", | |
"message": "Unsupported fromChain", | |
"field": "fromChain", | |
"location": "query" | |
} | |
} | |
} | |
} | |
}, | |
"500": { | |
"description": "Server error", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"error": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
"/bridgeTxStatus": { | |
"get": { | |
"summary": "Get Bridge Transaction Status", | |
"description": "Used to get the status of a bridge transaction, and the destination transaction information if the transaction is finalized", | |
"parameters": [ | |
{ | |
"in": "query", | |
"name": "destChainId", | |
"required": true, | |
"schema": { | |
"type": "integer" | |
}, | |
"description": "The ID of the destination chain" | |
}, | |
{ | |
"in": "query", | |
"name": "bridgeModule", | |
"required": true, | |
"schema": { | |
"type": "string", | |
"enum": ["SynapseRFQ", "SynapseBridge", "SynapseCCTP"] | |
}, | |
"description": "The bridge module used for the transaction" | |
}, | |
{ | |
"in": "query", | |
"name": "synapseTxId", | |
"required": true, | |
"schema": { | |
"type": "string" | |
}, | |
"description": "The Synapse transaction ID" | |
} | |
], | |
"responses": { | |
"200": { | |
"description": "Successful response", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"status": { | |
"type": "boolean", | |
"description": "The status of the transaction" | |
}, | |
"toInfo": { | |
"type": "object", | |
"properties": { | |
"chainID": { | |
"type": "integer", | |
"description": "The destination chain ID" | |
}, | |
"address": { | |
"type": "string", | |
"description": "The recipient address" | |
}, | |
"txnHash": { | |
"type": "string", | |
"description": "The transaction hash on the destination chain" | |
}, | |
"USDValue": { | |
"type": "number", | |
"description": "The USD value of the transaction" | |
}, | |
"tokenSymbol": { | |
"type": "string", | |
"description": "The symbol of the token transferred" | |
}, | |
"formattedTime": { | |
"type": "string", | |
"description": "The formatted time of the transaction" | |
}, | |
"formattedValue": { | |
"type": "string", | |
"description": "The formatted value of the transaction" | |
} | |
} | |
} | |
} | |
}, | |
"example": { | |
"status": true, | |
"toInfo": { | |
"chainID": 10, | |
"address": "0xRL3Bab0e4c09Ff447863f507E16090A9F22792d2", | |
"txnHash": "0x4eff784e85df5265dcc8e3c30b9df4b5c8a0c940300f6d8ad7ed737e9beb6fab", | |
"USDValue": 1.79848, | |
"tokenSymbol": "USDC", | |
"formattedTime": "2024-09-01 17:10:41 +0000 UTC", | |
"formattedValue": "1.797684" | |
} | |
} | |
} | |
} | |
}, | |
"400": { | |
"description": "Invalid input", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"error": { | |
"type": "object", | |
"properties": { | |
"value": { | |
"type": "string" | |
}, | |
"message": { | |
"type": "string" | |
}, | |
"field": { | |
"type": "string" | |
}, | |
"location": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
}, | |
"example": { | |
"error": { | |
"value": "999", | |
"message": "Unsupported destChainId", | |
"field": "destChainId", | |
"location": "query" | |
} | |
} | |
} | |
} | |
}, | |
"500": { | |
"description": "Server error", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"error": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
"/destinationTokens": { | |
"get": { | |
"summary": "Get possible destination tokens for a bridge", | |
"description": "Retrieve possible destination tokens for a given source chain ID and token address", | |
"parameters": [ | |
{ | |
"in": "query", | |
"name": "fromChain", | |
"required": true, | |
"schema": { | |
"type": "integer" | |
}, | |
"description": "The source chain ID" | |
}, | |
{ | |
"in": "query", | |
"name": "fromToken", | |
"required": true, | |
"schema": { | |
"type": "string" | |
}, | |
"description": "The address of the token on the source chain" | |
} | |
], | |
"responses": { | |
"200": { | |
"description": "Successful response", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "array", | |
"items": { | |
"type": "object", | |
"properties": { | |
"symbol": { | |
"type": "string", | |
"description": "The token symbol" | |
}, | |
"chainId": { | |
"type": "string", | |
"description": "The chain ID where the token is available" | |
}, | |
"address": { | |
"type": "string", | |
"description": "The token contract address" | |
} | |
} | |
} | |
}, | |
"example": [ | |
{ | |
"symbol": "USDC", | |
"chainId": "1", | |
"address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" | |
}, | |
{ | |
"symbol": "USDT", | |
"chainId": "42161", | |
"address": "0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9" | |
}, | |
{ | |
"symbol": "crvUSD", | |
"chainId": "8453", | |
"address": "0x417Ac0e078398C154EdFadD9Ef675d30Be60Af93" | |
} | |
] | |
} | |
} | |
}, | |
"400": { | |
"description": "Invalid input", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"error": { | |
"type": "object", | |
"properties": { | |
"value": { | |
"type": "string" | |
}, | |
"message": { | |
"type": "string" | |
}, | |
"field": { | |
"type": "string" | |
}, | |
"location": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
}, | |
"example": { | |
"error": { | |
"value": "100", | |
"message": "Unsupported fromChain", | |
"field": "fromChain", | |
"location": "query" | |
} | |
} | |
} | |
} | |
}, | |
"500": { | |
"description": "Server error", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"error": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
"/destinationTx": { | |
"get": { | |
"summary": "Get Destination Transaction Information", | |
"description": "Used to get the status of a bridge transaction, and the destination transaction information if the transaction is finalized", | |
"parameters": [ | |
{ | |
"in": "query", | |
"name": "originChainId", | |
"required": true, | |
"schema": { | |
"type": "integer" | |
}, | |
"description": "The ID of the origin chain where the transaction was initiated" | |
}, | |
{ | |
"in": "query", | |
"name": "txHash", | |
"required": true, | |
"schema": { | |
"type": "string" | |
}, | |
"description": "The transaction hash on the origin chain" | |
} | |
], | |
"responses": { | |
"200": { | |
"description": "Successful response", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"status": { | |
"type": "string", | |
"description": "The status of the transaction" | |
}, | |
"fromInfo": { | |
"type": "object", | |
"properties": { | |
"chainID": { | |
"type": "integer", | |
"description": "The origin chain ID" | |
}, | |
"address": { | |
"type": "string", | |
"description": "The recipient address" | |
}, | |
"txnHash": { | |
"type": "string", | |
"description": "The transaction hash on the destination chain" | |
}, | |
"USDValue": { | |
"type": "number", | |
"description": "The USD value of the transaction" | |
}, | |
"tokenSymbol": { | |
"type": "string", | |
"description": "The symbol of the token transferred" | |
}, | |
"blockNumber": { | |
"type": "integer", | |
"description": "The block number of the transaction" | |
}, | |
"formattedTime": { | |
"type": "string", | |
"description": "The formatted time of the transaction" | |
}, | |
"formattedValue": { | |
"type": "string", | |
"description": "The formatted value of the transaction" | |
} | |
} | |
}, | |
"toInfo": { | |
"type": "object", | |
"properties": { | |
"chainID": { | |
"type": "integer", | |
"description": "The destination chain ID" | |
}, | |
"address": { | |
"type": "string", | |
"description": "The recipient address" | |
}, | |
"txnHash": { | |
"type": "string", | |
"description": "The transaction hash on the destination chain" | |
}, | |
"USDValue": { | |
"type": "number", | |
"description": "The USD value of the transaction" | |
}, | |
"tokenSymbol": { | |
"type": "string", | |
"description": "The symbol of the token transferred" | |
}, | |
"blockNumber": { | |
"type": "integer", | |
"description": "The block number of the transaction" | |
}, | |
"formattedTime": { | |
"type": "string", | |
"description": "The formatted time of the transaction" | |
}, | |
"formattedValue": { | |
"type": "string", | |
"description": "The formatted value of the transaction" | |
} | |
} | |
} | |
} | |
}, | |
"example": { | |
"status": "completed", | |
"fromInfo": { | |
"chainID": 8453, | |
"address": "0x6eA4207627aAf2Ef86642eD8B331579b606471c3", | |
"txnHash": "0x13486d9eaefd68de6a20b704d70deb8436effbac1f77fddfc0c7ef14f08e96c3", | |
"USDValue": "11660.93019,", | |
"tokenSymbol": "USDC", | |
"blockNumber": "19857812,", | |
"formattedTime": "2024-09-16 16:42:51 +0000 UTC", | |
"formattedValue": "11637.654884" | |
}, | |
"toInfo": { | |
"chainID": 42161, | |
"address": "0xfC8f27Bcf34FfD52869ffa4A5A6B9b0A872281Ad", | |
"txnHash": "0xe26be8f4296c14dc8da6ef92d39c1d20577a43704bfb0b2cea5ee2f516be0f4e", | |
"USDValue": 11660.92558, | |
"tokenSymbol": "USDC", | |
"blockNumber": 254173724, | |
"formattedTime": "2024-09-16 16:42:55 +0000 UTC", | |
"formattedValue": "11637.650281" | |
} | |
} | |
} | |
} | |
}, | |
"400": { | |
"description": "Invalid input", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"error": { | |
"type": "object", | |
"properties": { | |
"value": { | |
"type": "string" | |
}, | |
"message": { | |
"type": "string" | |
}, | |
"field": { | |
"type": "string" | |
}, | |
"location": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
}, | |
"example": { | |
"error": { | |
"value": "999", | |
"message": "originChainId is required", | |
"field": "originChainId", | |
"location": "query" | |
} | |
} | |
} | |
} | |
}, | |
"404": { | |
"description": "Not found", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"status": { | |
"type": "string" | |
}, | |
"fromInfo": { | |
"type": "object", | |
"nullable": true | |
}, | |
"toInfo": { | |
"type": "object", | |
"nullable": true | |
} | |
} | |
} | |
} | |
} | |
}, | |
"500": { | |
"description": "Server error", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"error": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
"/": { | |
"get": { | |
"summary": "Get API information", | |
"description": "Retrieve general information about the Synapse REST API, including available chains and tokens", | |
"responses": { | |
"200": { | |
"description": "Successful response", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"message": { | |
"type": "string", | |
"description": "Welcome message for the API" | |
}, | |
"availableChains": { | |
"type": "array", | |
"description": "List of available blockchain networks", | |
"items": { | |
"type": "object", | |
"properties": { | |
"name": { | |
"type": "string", | |
"description": "Name of the blockchain network" | |
}, | |
"id": { | |
"type": "integer", | |
"description": "Chain ID of the blockchain network" | |
} | |
} | |
} | |
}, | |
"availableTokens": { | |
"type": "array", | |
"description": "List of available tokens across different chains", | |
"items": { | |
"type": "object", | |
"properties": { | |
"symbol": { | |
"type": "string", | |
"description": "Token symbol" | |
}, | |
"chains": { | |
"type": "array", | |
"description": "List of chains where the token is available", | |
"items": { | |
"type": "object", | |
"properties": { | |
"chainId": { | |
"type": "string", | |
"description": "Chain ID where the token is available" | |
}, | |
"address": { | |
"type": "string", | |
"description": "Token contract address on the specific chain" | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
"example": { | |
"message": "Welcome to the Synapse REST API for swap and bridge quotes", | |
"availableChains": [ | |
{ | |
"name": "Ethereum", | |
"id": 1 | |
}, | |
{ | |
"name": "Arbitrum", | |
"id": 42161 | |
} | |
], | |
"availableTokens": [ | |
{ | |
"symbol": "USDC", | |
"chains": [ | |
{ | |
"chainId": "1", | |
"address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" | |
}, | |
{ | |
"chainId": "42161", | |
"address": "0xaf88d065e77c8cc2239327c5edb3a432268e5831" | |
} | |
] | |
} | |
] | |
} | |
} | |
} | |
}, | |
"500": { | |
"description": "Server error", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"error": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
"/swap": { | |
"get": { | |
"summary": "Get swap quote for tokens on a specific chain", | |
"description": "Retrieve detailed swap quote for exchanging one token for another on a specified chain", | |
"parameters": [ | |
{ | |
"in": "query", | |
"name": "chain", | |
"required": true, | |
"schema": { | |
"type": "integer" | |
}, | |
"description": "The chain ID where the swap will occur" | |
}, | |
{ | |
"in": "query", | |
"name": "fromToken", | |
"required": true, | |
"schema": { | |
"type": "string" | |
}, | |
"description": "The address of the token to swap from" | |
}, | |
{ | |
"in": "query", | |
"name": "toToken", | |
"required": true, | |
"schema": { | |
"type": "string" | |
}, | |
"description": "The address of the token to swap to" | |
}, | |
{ | |
"in": "query", | |
"name": "amount", | |
"required": true, | |
"schema": { | |
"type": "number" | |
}, | |
"description": "The amount of tokens to swap" | |
} | |
], | |
"responses": { | |
"200": { | |
"description": "Successful response", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"routerAddress": { | |
"type": "string", | |
"description": "The address of the router contract" | |
}, | |
"maxAmountOut": { | |
"type": "string", | |
"description": "The maximum amount of tokens that will be received" | |
}, | |
"query": { | |
"type": "object", | |
"properties": { | |
"swapAdapter": { | |
"type": "string", | |
"description": "The address of the swap adapter" | |
}, | |
"tokenOut": { | |
"type": "string", | |
"description": "The address of the token being received" | |
}, | |
"minAmountOut": { | |
"$ref": "#/components/schemas/BigNumber" | |
}, | |
"deadline": { | |
"$ref": "#/components/schemas/BigNumber" | |
}, | |
"rawParams": { | |
"type": "string", | |
"description": "Raw parameters for the swap" | |
} | |
} | |
} | |
} | |
}, | |
"example": { | |
"routerAddress": "0x7E7A0e201FD38d3ADAA9523Da6C109a07118C96a", | |
"maxAmountOut": "999.746386", | |
"query": { | |
"swapAdapter": "0x7E7A0e201FD38d3ADAA9523Da6C109a07118C96a", | |
"tokenOut": "0xdAC17F958D2ee523a2206206994597C13D831ec7", | |
"minAmountOut": { | |
"type": "BigNumber", | |
"hex": "0x3b96eb52" | |
}, | |
"deadline": { | |
"type": "BigNumber", | |
"hex": "0x66ecb470" | |
}, | |
"rawParams": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001116898dda4015ed8ddefb84b6e8bc24528af2d800000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002" | |
} | |
} | |
} | |
} | |
}, | |
"400": { | |
"description": "Invalid input", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"error": { | |
"type": "object", | |
"properties": { | |
"value": { | |
"type": "string" | |
}, | |
"message": { | |
"type": "string" | |
}, | |
"field": { | |
"type": "string" | |
}, | |
"location": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
}, | |
"example": { | |
"error": { | |
"value": "999", | |
"message": "Unsupported chain", | |
"field": "chain", | |
"location": "query" | |
} | |
} | |
} | |
} | |
}, | |
"500": { | |
"description": "Server error", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"error": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
"/swapTxInfo": { | |
"get": { | |
"summary": "Get swap transaction information", | |
"description": "Retrieve transaction information for swapping tokens on a specific chain", | |
"parameters": [ | |
{ | |
"in": "query", | |
"name": "chain", | |
"required": true, | |
"schema": { | |
"type": "integer" | |
}, | |
"description": "The chain ID where the swap will occur" | |
}, | |
{ | |
"in": "query", | |
"name": "fromToken", | |
"required": true, | |
"schema": { | |
"type": "string" | |
}, | |
"description": "The address of the token to swap from" | |
}, | |
{ | |
"in": "query", | |
"name": "toToken", | |
"required": true, | |
"schema": { | |
"type": "string" | |
}, | |
"description": "The address of the token to swap to" | |
}, | |
{ | |
"in": "query", | |
"name": "amount", | |
"required": true, | |
"schema": { | |
"type": "number" | |
}, | |
"description": "The amount of tokens to swap" | |
}, | |
{ | |
"in": "query", | |
"name": "address", | |
"required": true, | |
"schema": { | |
"type": "string" | |
}, | |
"description": "The Ethereum address of the user performing the swap" | |
} | |
], | |
"responses": { | |
"200": { | |
"description": "Successful response", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"data": { | |
"type": "string", | |
"description": "Encoded transaction data" | |
}, | |
"to": { | |
"type": "string", | |
"description": "The address of the contract to interact with" | |
}, | |
"value": { | |
"type": "object", | |
"properties": { | |
"type": { | |
"type": "string", | |
"enum": ["BigNumber"] | |
}, | |
"hex": { | |
"type": "string" | |
} | |
}, | |
"description": "The amount of native currency to send with the transaction" | |
} | |
} | |
}, | |
"example": { | |
"data": "0xb5d1cdd4000000000000000000000000abb4f79430002534df3f62e964d62659a010ef3c000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000000000800000000000000000000000007e7a0e201fd38d3adaa9523da6c109a07118c96a000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000000000000000000000000000000000003b96eaed0000000000000000000000000000000000000000000000000000000066ecbb7c00000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001116898dda4015ed8ddefb84b6e8bc24528af2d800000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", | |
"to": "0x7E7A0e201FD38d3ADAA9523Da6C109a07118C96a", | |
"value": { | |
"type": "BigNumber", | |
"hex": "0x00" | |
} | |
} | |
} | |
} | |
}, | |
"400": { | |
"description": "Invalid input", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"error": { | |
"type": "object", | |
"properties": { | |
"value": { | |
"type": "string" | |
}, | |
"message": { | |
"type": "string" | |
}, | |
"field": { | |
"type": "string" | |
}, | |
"location": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
}, | |
"example": { | |
"error": { | |
"value": "999", | |
"message": "Unsupported chain", | |
"field": "chain", | |
"location": "query" | |
} | |
} | |
} | |
} | |
}, | |
"500": { | |
"description": "Server error", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"error": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
"/synapseTxId": { | |
"get": { | |
"summary": "Get Synapse Transaction ID", | |
"description": "Retrieve the Synapse transaction ID for a given origin chain transaction", | |
"parameters": [ | |
{ | |
"in": "query", | |
"name": "originChainId", | |
"required": true, | |
"schema": { | |
"type": "integer" | |
}, | |
"description": "The ID of the origin chain where the transaction was initiated" | |
}, | |
{ | |
"in": "query", | |
"name": "bridgeModule", | |
"required": true, | |
"schema": { | |
"type": "string", | |
"enum": ["SynapseRFQ", "SynapseBridge", "SynapseCCTP"] | |
}, | |
"description": "The bridge module used for the transaction" | |
}, | |
{ | |
"in": "query", | |
"name": "txHash", | |
"required": true, | |
"schema": { | |
"type": "string" | |
}, | |
"description": "The transaction hash on the origin chain" | |
} | |
], | |
"responses": { | |
"200": { | |
"description": "Successful response", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"synapseTxId": { | |
"type": "string", | |
"description": "The Synapse transaction ID" | |
} | |
} | |
}, | |
"example": { | |
"synapseTxId": "0x812516c5477aeeb4361ecbdd561abcd10f779a0fce22bad13635b8cae088760a" | |
} | |
} | |
} | |
}, | |
"400": { | |
"description": "Invalid input", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"error": { | |
"type": "object", | |
"properties": { | |
"value": { | |
"type": "string" | |
}, | |
"message": { | |
"type": "string" | |
}, | |
"field": { | |
"type": "string" | |
}, | |
"location": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
}, | |
"example": { | |
"error": { | |
"value": "999", | |
"message": "Invalid bridge module. Must be one of: SynapseRFQ, SynapseBridge, SynapseCCTP", | |
"field": "bridgeModule", | |
"location": "query" | |
} | |
} | |
} | |
} | |
}, | |
"500": { | |
"description": "Server error", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"error": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
"/tokenlist": { | |
"get": { | |
"summary": "Get the list of bridgeable tokens & associated chain metadata", | |
"description": "Retrieve the complete list of tokens that can be bridged across different chains", | |
"responses": { | |
"200": { | |
"description": "Successful response", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"additionalProperties": { | |
"type": "object", | |
"properties": { | |
"addresses": { | |
"type": "object", | |
"additionalProperties": { | |
"type": "string" | |
} | |
}, | |
"decimals": { | |
"type": "object", | |
"additionalProperties": { | |
"type": "integer" | |
} | |
}, | |
"symbol": { | |
"type": "string" | |
}, | |
"name": { | |
"type": "string" | |
}, | |
"swapableType": { | |
"type": "string" | |
}, | |
"color": { | |
"type": "string" | |
}, | |
"priorityRank": { | |
"type": "integer" | |
}, | |
"routeSymbol": { | |
"type": "string" | |
}, | |
"imgUrl": { | |
"type": "string" | |
} | |
} | |
} | |
}, | |
"example": { | |
"USDC": { | |
"addresses": { | |
"1": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", | |
"10": "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85" | |
}, | |
"decimals": { | |
"1": 6, | |
"10": 6 | |
}, | |
"symbol": "USDC", | |
"name": "USD Coin", | |
"swapableType": "USD", | |
"color": "blue", | |
"priorityRank": 100, | |
"routeSymbol": "USDC", | |
"imgUrl": "https://example.com/usdc.svg" | |
}, | |
"USDT": { | |
"addresses": { | |
"1": "0xdac17f958d2ee523a2206206994597c13d831ec7", | |
"10": "0x94b008aA00579c1307B0EF2c499aD98a8ce58e58" | |
}, | |
"decimals": { | |
"1": 6, | |
"10": 6 | |
}, | |
"symbol": "USDT", | |
"name": "USD Tether", | |
"swapableType": "USD", | |
"color": "lime", | |
"priorityRank": 100, | |
"routeSymbol": "USDT", | |
"imgUrl": "https://example.com/usdt.svg" | |
}, | |
"NUSD": { | |
"addresses": { | |
"1": "0x1B84765dE8B7566e4cEAF4D0fD3c5aF52D3DdE4F", | |
"10": "0x67C10C397dD0Ba417329543c1a40eb48AAa7cd00" | |
}, | |
"decimals": { | |
"1": 18, | |
"10": 18 | |
}, | |
"symbol": "nUSD", | |
"name": "Synapse nUSD", | |
"swapableType": "USD", | |
"color": "purple", | |
"priorityRank": 500, | |
"routeSymbol": "nUSD", | |
"imgUrl": "https://example.com/nusd.svg" | |
} | |
} | |
} | |
} | |
}, | |
"500": { | |
"description": "Server error", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"error": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
"/conflicting-proofs": { | |
"get": { | |
"summary": "Get conflicting proofs", | |
"description": "Retrieves a list of transactions where the relayer in the proof differs from the relayer in the relay event", | |
"responses": { | |
"200": { | |
"description": "Successful response", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "array", | |
"items": { | |
"type": "object", | |
"properties": { | |
"Bridge": { | |
"type": "object", | |
"description": "General transaction fields" | |
}, | |
"BridgeRequest": { | |
"type": "object", | |
"description": "Deposit information" | |
}, | |
"BridgeRelay": { | |
"type": "object", | |
"description": "Relay information" | |
}, | |
"BridgeRefund": { | |
"type": "object", | |
"description": "Refund information" | |
}, | |
"BridgeProof": { | |
"type": "object", | |
"description": "Proof information (if available)" | |
}, | |
"BridgeClaim": { | |
"type": "object", | |
"description": "Claim information (if available)" | |
}, | |
"BridgeDispute": { | |
"type": "object", | |
"description": "Dispute information (if available)" | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
"404": { | |
"description": "No conflicting proofs found", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"message": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
} | |
}, | |
"500": { | |
"description": "Server error", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"message": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
"/disputes": { | |
"get": { | |
"summary": "Get all active disputes", | |
"description": "Retrieves a list of all active disputes", | |
"responses": { | |
"200": { | |
"description": "Successful response", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "array", | |
"items": { | |
"type": "object", | |
"properties": { | |
"Bridge": { | |
"type": "object", | |
"description": "General transaction fields" | |
}, | |
"BridgeRequest": { | |
"type": "object", | |
"description": "Deposit information" | |
}, | |
"BridgeRelay": { | |
"type": "object", | |
"description": "Relay information" | |
}, | |
"BridgeRefund": { | |
"type": "object", | |
"description": "Refund information" | |
}, | |
"BridgeProof": { | |
"type": "object", | |
"description": "Proof information (if available)" | |
}, | |
"BridgeClaim": { | |
"type": "object", | |
"description": "Claim information (if available)" | |
}, | |
"BridgeDispute": { | |
"type": "object", | |
"description": "Dispute information (if available)" | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
"404": { | |
"description": "No disputes found", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"message": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
} | |
}, | |
"500": { | |
"description": "Server error", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"message": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
"/invalid-relays": { | |
"get": { | |
"summary": "Get recent invalid relays", | |
"description": "Retrieves a list of recent invalid relay events from the past 2 weeks", | |
"responses": { | |
"200": { | |
"description": "Successful response", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "array", | |
"items": { | |
"type": "object", | |
"properties": { | |
"Bridge": { | |
"type": "object", | |
"description": "General transaction fields" | |
}, | |
"BridgeRequest": { | |
"type": "object", | |
"description": "Deposit information" | |
}, | |
"BridgeRelay": { | |
"type": "object", | |
"description": "Relay information" | |
}, | |
"BridgeRefund": { | |
"type": "object", | |
"description": "Refund information" | |
}, | |
"BridgeProof": { | |
"type": "object", | |
"description": "Proof information (if available)" | |
}, | |
"BridgeClaim": { | |
"type": "object", | |
"description": "Claim information (if available)" | |
}, | |
"BridgeDispute": { | |
"type": "object", | |
"description": "Dispute information (if available)" | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
"404": { | |
"description": "No recent invalid relays found", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"message": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
} | |
}, | |
"500": { | |
"description": "Server error", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"message": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
"/pending-transactions/missing-claim": { | |
"get": { | |
"summary": "Get pending transactions missing claim", | |
"description": "Retrieves a list of transactions that have been deposited, relayed, and proven, but not yet claimed", | |
"responses": { | |
"200": { | |
"description": "Successful response", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "array", | |
"items": { | |
"type": "object", | |
"properties": { | |
"Bridge": { | |
"type": "object", | |
"description": "General transaction fields" | |
}, | |
"BridgeRequest": { | |
"type": "object", | |
"description": "Deposit information" | |
}, | |
"BridgeRelay": { | |
"type": "object", | |
"description": "Relay information" | |
}, | |
"BridgeRefund": { | |
"type": "object", | |
"description": "Refund information" | |
}, | |
"BridgeProof": { | |
"type": "object", | |
"description": "Proof information (if available)" | |
}, | |
"BridgeClaim": { | |
"type": "object", | |
"description": "Claim information (if available)" | |
}, | |
"BridgeDispute": { | |
"type": "object", | |
"description": "Dispute information (if available)" | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
"404": { | |
"description": "No pending transactions missing claim found", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"message": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
} | |
}, | |
"500": { | |
"description": "Server error", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"message": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
"/pending-transactions/missing-proof": { | |
"get": { | |
"summary": "Get pending transactions missing proof", | |
"description": "Retrieves a list of transactions that have been deposited and relayed, but not yet proven", | |
"responses": { | |
"200": { | |
"description": "Successful response", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "array", | |
"items": { | |
"type": "object", | |
"properties": { | |
"deposit": { | |
"type": "object" | |
}, | |
"relay": { | |
"type": "object" | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
"404": { | |
"description": "No pending transactions missing proof found", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"message": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
} | |
}, | |
"500": { | |
"description": "Server error", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"message": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
"/pending-transactions/missing-relay": { | |
"get": { | |
"summary": "Get pending transactions missing relay", | |
"description": "Retrieves a list of transactions that have been deposited, but not yet relayed or refunded", | |
"responses": { | |
"200": { | |
"description": "Successful response", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "array", | |
"items": { | |
"type": "object", | |
"properties": { | |
"deposit": { | |
"type": "object" | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
"404": { | |
"description": "No pending transactions missing relay found", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"message": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
} | |
}, | |
"500": { | |
"description": "Server error", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"message": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
"/pending-transactions/exceed-deadline": { | |
"get": { | |
"summary": "Get pending transactions exceed deadline", | |
"description": "Retrieves a list of transactions that have been deposited, but not yet relayed or refunded and have exceeded the deadline", | |
"responses": { | |
"200": { | |
"description": "Successful response", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "array", | |
"items": { | |
"type": "object", | |
"properties": { | |
"deposit": { | |
"type": "object" | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
"404": { | |
"description": "No pending transactionst that exceed the deadline found", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"message": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
} | |
}, | |
"500": { | |
"description": "Server error", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"message": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
"/refunded-and-relayed": { | |
"get": { | |
"summary": "Get refunded and relayed transactions", | |
"description": "Retrieves a list of transactions that have been both refunded and relayed", | |
"responses": { | |
"200": { | |
"description": "Successful response", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "array", | |
"items": { | |
"type": "object", | |
"properties": { | |
"Bridge": { | |
"type": "object", | |
"description": "General transaction fields" | |
}, | |
"BridgeRequest": { | |
"type": "object", | |
"description": "Deposit information" | |
}, | |
"BridgeRelay": { | |
"type": "object", | |
"description": "Relay information" | |
}, | |
"BridgeRefund": { | |
"type": "object", | |
"description": "Refund information" | |
}, | |
"BridgeProof": { | |
"type": "object", | |
"description": "Proof information (if available)" | |
}, | |
"BridgeClaim": { | |
"type": "object", | |
"description": "Claim information (if available)" | |
}, | |
"BridgeDispute": { | |
"type": "object", | |
"description": "Dispute information (if available)" | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
"404": { | |
"description": "No refunded and relayed transactions found", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"message": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
} | |
}, | |
"500": { | |
"description": "Server error", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"message": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
"/transaction-id/{transactionId}": { | |
"get": { | |
"summary": "Get transaction details by ID or the origin transaction hash", | |
"description": "Retrieves detailed information about a transaction, including deposit, relay, proof, claim, and refund data if available", | |
"parameters": [ | |
{ | |
"in": "path", | |
"name": "transactionId", | |
"required": true, | |
"schema": { | |
"type": "string" | |
}, | |
"description": "The unique identifier of the transaction or the origin transaction hash" | |
} | |
], | |
"responses": { | |
"200": { | |
"description": "Successful response", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"Bridge": { | |
"type": "object", | |
"description": "General transaction fields" | |
}, | |
"BridgeRequest": { | |
"type": "object", | |
"description": "Deposit information" | |
}, | |
"BridgeRelay": { | |
"type": "object", | |
"description": "Relay information" | |
}, | |
"BridgeRefund": { | |
"type": "object", | |
"description": "Refund information" | |
}, | |
"BridgeProof": { | |
"type": "object", | |
"description": "Proof information (if available)" | |
}, | |
"BridgeClaim": { | |
"type": "object", | |
"description": "Claim information (if available)" | |
}, | |
"BridgeDispute": { | |
"type": "object", | |
"description": "Dispute information (if available)" | |
} | |
} | |
} | |
} | |
} | |
}, | |
"404": { | |
"description": "Transaction not found", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"message": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
} | |
}, | |
"500": { | |
"description": "Server error", | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "object", | |
"properties": { | |
"message": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
"/ack": { | |
"put": { | |
"tags": ["ack"], | |
"summary": "Relay ack", | |
"description": "cache an ack request to synchronize relayer actions.", | |
"requestBody": { | |
"description": "query params", | |
"content": { | |
"application/json": { | |
"schema": { | |
"$ref": "#/components/schemas/model.PutRelayerQuoteRequest" | |
} | |
} | |
}, | |
"required": true | |
}, | |
"responses": { | |
"200": { | |
"description": "OK", | |
"headers": { | |
"X-Api-Version": { | |
"description": "API Version Number - See docs for more info", | |
"schema": { | |
"type": "string" | |
} | |
} | |
}, | |
"content": {} | |
} | |
}, | |
"x-codegen-request-body-name": "request" | |
} | |
}, | |
"/bulk_quotes": { | |
"put": { | |
"tags": ["quotes"], | |
"summary": "Upsert quotes", | |
"description": "upsert bulk quotes from relayer.", | |
"requestBody": { | |
"description": "query params", | |
"content": { | |
"application/json": { | |
"schema": { | |
"$ref": "#/components/schemas/model.PutBulkQuotesRequest" | |
} | |
} | |
}, | |
"required": true | |
}, | |
"responses": { | |
"200": { | |
"description": "OK", | |
"headers": { | |
"X-Api-Version": { | |
"description": "API Version Number - See docs for more info", | |
"schema": { | |
"type": "string" | |
} | |
} | |
}, | |
"content": {} | |
} | |
}, | |
"x-codegen-request-body-name": "request" | |
} | |
}, | |
"/contracts": { | |
"get": { | |
"tags": ["quotes"], | |
"summary": "Get contract addresses", | |
"description": "get quotes from all relayers.", | |
"responses": { | |
"200": { | |
"description": "OK", | |
"headers": { | |
"X-Api-Version": { | |
"description": "API Version Number - See docs for more info", | |
"schema": { | |
"type": "string" | |
} | |
} | |
}, | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "array", | |
"items": { | |
"$ref": "#/components/schemas/model.GetContractsResponse" | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
"/open_quote_requests": { | |
"get": { | |
"tags": ["quotes"], | |
"summary": "Get open quote requests", | |
"description": "Get all open quote requests that are currently in Received or Pending status.", | |
"responses": { | |
"200": { | |
"description": "OK", | |
"headers": { | |
"X-Api-Version": { | |
"description": "API Version Number - See docs for more info", | |
"schema": { | |
"type": "string" | |
} | |
} | |
}, | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "array", | |
"items": { | |
"$ref": "#/components/schemas/model.GetOpenQuoteRequestsResponse" | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
"/quotes": { | |
"get": { | |
"tags": ["quotes"], | |
"summary": "Get quotes", | |
"description": "get quotes from all relayers.", | |
"parameters": [ | |
{ | |
"name": "originChainID", | |
"in": "query", | |
"description": "origin chain id to filter quotes by", | |
"required": true, | |
"schema": { | |
"type": "integer" | |
} | |
}, | |
{ | |
"name": "originTokenAddr", | |
"in": "query", | |
"description": "origin chain id to filter quotes by", | |
"required": true, | |
"schema": { | |
"type": "string" | |
} | |
}, | |
{ | |
"name": "destChainID", | |
"in": "query", | |
"description": "destination chain id to filter quotes by", | |
"required": true, | |
"schema": { | |
"type": "integer" | |
} | |
}, | |
{ | |
"name": "destTokenAddr", | |
"in": "query", | |
"description": "destination token address to filter quotes by", | |
"required": true, | |
"schema": { | |
"type": "string" | |
} | |
}, | |
{ | |
"name": "relayerAddr", | |
"in": "query", | |
"description": "relayer address to filter quotes by", | |
"required": true, | |
"schema": { | |
"type": "string" | |
} | |
} | |
], | |
"responses": { | |
"200": { | |
"description": "OK", | |
"headers": { | |
"X-Api-Version": { | |
"description": "API Version Number - See docs for more info", | |
"schema": { | |
"type": "string" | |
} | |
} | |
}, | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "array", | |
"items": { | |
"$ref": "#/components/schemas/model.GetQuoteResponse" | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
"put": { | |
"tags": ["quotes"], | |
"summary": "Upsert quote", | |
"description": "upsert a quote from relayer.", | |
"requestBody": { | |
"description": "query params", | |
"content": { | |
"application/json": { | |
"schema": { | |
"$ref": "#/components/schemas/model.PutRelayerQuoteRequest" | |
} | |
} | |
}, | |
"required": true | |
}, | |
"responses": { | |
"200": { | |
"description": "OK", | |
"headers": { | |
"X-Api-Version": { | |
"description": "API Version Number - See docs for more info", | |
"schema": { | |
"type": "string" | |
} | |
} | |
}, | |
"content": {} | |
} | |
}, | |
"x-codegen-request-body-name": "request" | |
} | |
}, | |
"/rfq": { | |
"put": { | |
"tags": ["quotes"], | |
"summary": "Handle user quote request", | |
"description": "Handle user quote request and return the best quote available.", | |
"requestBody": { | |
"description": "User quote request", | |
"content": { | |
"application/json": { | |
"schema": { | |
"$ref": "#/components/schemas/model.PutRFQRequest" | |
} | |
} | |
}, | |
"required": true | |
}, | |
"responses": { | |
"200": { | |
"description": "OK", | |
"headers": { | |
"X-Api-Version": { | |
"description": "API Version Number - See docs for more info", | |
"schema": { | |
"type": "string" | |
} | |
} | |
}, | |
"content": { | |
"application/json": { | |
"schema": { | |
"$ref": "#/components/schemas/model.PutRFQResponse" | |
} | |
} | |
} | |
} | |
}, | |
"x-codegen-request-body-name": "request" | |
} | |
}, | |
"/rfq_stream": { | |
"get": { | |
"tags": ["quotes"], | |
"summary": "Handle WebSocket connection for active quote requests", | |
"description": "Establish a WebSocket connection to receive active quote requests.", | |
"responses": { | |
"101": { | |
"description": "Switching Protocols", | |
"headers": { | |
"X-Api-Version": { | |
"description": "API Version Number - See docs for more info", | |
"schema": { | |
"type": "string" | |
} | |
} | |
}, | |
"content": { | |
"application/json": { | |
"schema": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
"components": { | |
"schemas": { | |
"BigNumber": { | |
"type": "object", | |
"properties": { | |
"type": { | |
"type": "string", | |
"enum": ["BigNumber"] | |
}, | |
"hex": { | |
"type": "string" | |
} | |
} | |
}, | |
"model.GetContractsResponse": { | |
"type": "object", | |
"properties": { | |
"contracts": { | |
"type": "object", | |
"additionalProperties": { | |
"type": "string" | |
}, | |
"description": "Contracts is a map of chain id to contract address" | |
} | |
} | |
}, | |
"model.GetOpenQuoteRequestsResponse": { | |
"type": "object", | |
"properties": { | |
"created_at": { | |
"type": "string" | |
}, | |
"dest_chain_id": { | |
"type": "integer" | |
}, | |
"dest_token": { | |
"type": "string" | |
}, | |
"expiration_window": { | |
"type": "integer" | |
}, | |
"origin_amount": { | |
"type": "string" | |
}, | |
"origin_chain_id": { | |
"type": "integer" | |
}, | |
"origin_token": { | |
"type": "string" | |
}, | |
"user_address": { | |
"type": "string" | |
} | |
} | |
}, | |
"model.GetQuoteResponse": { | |
"type": "object", | |
"properties": { | |
"dest_amount": { | |
"type": "string", | |
"description": "DestAmount is the max amount of liquidity which exists for a given destination token, provided in the destination token decimals" | |
}, | |
"dest_chain_id": { | |
"type": "integer", | |
"description": "DestChainID is the chain which the relayer is willing to relay to" | |
}, | |
"dest_fast_bridge_address": { | |
"type": "string", | |
"description": "DestFastBridgeAddress is the address of the fast bridge contract on the destination chain" | |
}, | |
"dest_token_addr": { | |
"type": "string", | |
"description": "DestToken is the token address for which the relayer willing to relay to" | |
}, | |
"fixed_fee": { | |
"type": "string", | |
"description": "FixedFee is the fixed fee for the quote, provided in the destination token terms" | |
}, | |
"max_origin_amount": { | |
"type": "string", | |
"description": "MaxOriginAmount is the maximum amount of origin tokens bridgeable" | |
}, | |
"origin_chain_id": { | |
"type": "integer", | |
"description": "OriginChainID is the chain which the relayer is willing to relay from" | |
}, | |
"origin_fast_bridge_address": { | |
"type": "string", | |
"description": "OriginFastBridgeAddress is the address of the fast bridge contract on the origin chain" | |
}, | |
"origin_token_addr": { | |
"type": "string", | |
"description": "OriginTokenAddr is the token address for which the relayer willing to relay from" | |
}, | |
"relayer_addr": { | |
"type": "string", | |
"description": "Address of the relayer providing the quote" | |
}, | |
"updated_at": { | |
"type": "string", | |
"description": "UpdatedAt is the time that the quote was last upserted" | |
} | |
} | |
}, | |
"model.PutBulkQuotesRequest": { | |
"type": "object", | |
"properties": { | |
"quotes": { | |
"type": "array", | |
"items": { | |
"$ref": "#/components/schemas/model.PutRelayerQuoteRequest" | |
} | |
} | |
} | |
}, | |
"model.PutRFQRequest": { | |
"type": "object", | |
"properties": { | |
"data": { | |
"$ref": "#/components/schemas/model.QuoteData" | |
}, | |
"integrator_id": { | |
"type": "string" | |
}, | |
"quote_types": { | |
"type": "array", | |
"items": { | |
"type": "string" | |
} | |
}, | |
"user_address": { | |
"type": "string" | |
} | |
} | |
}, | |
"model.PutRFQResponse": { | |
"type": "object", | |
"properties": { | |
"dest_amount": { | |
"type": "string" | |
}, | |
"quote_id": { | |
"type": "string" | |
}, | |
"quote_type": { | |
"type": "string" | |
}, | |
"reason": { | |
"type": "string" | |
}, | |
"relayer_address": { | |
"type": "string" | |
}, | |
"success": { | |
"type": "boolean" | |
} | |
} | |
}, | |
"model.PutRelayerQuoteRequest": { | |
"type": "object", | |
"properties": { | |
"dest_amount": { | |
"type": "string" | |
}, | |
"dest_chain_id": { | |
"type": "integer" | |
}, | |
"dest_fast_bridge_address": { | |
"type": "string" | |
}, | |
"dest_token_addr": { | |
"type": "string" | |
}, | |
"fixed_fee": { | |
"type": "string" | |
}, | |
"max_origin_amount": { | |
"type": "string" | |
}, | |
"origin_chain_id": { | |
"type": "integer" | |
}, | |
"origin_fast_bridge_address": { | |
"type": "string" | |
}, | |
"origin_token_addr": { | |
"type": "string" | |
} | |
} | |
}, | |
"model.QuoteData": { | |
"type": "object", | |
"properties": { | |
"dest_amount": { | |
"type": "string" | |
}, | |
"dest_chain_id": { | |
"type": "integer" | |
}, | |
"dest_token_addr": { | |
"type": "string" | |
}, | |
"expiration_window": { | |
"type": "integer" | |
}, | |
"origin_amount": { | |
"type": "string" | |
}, | |
"origin_chain_id": { | |
"type": "integer" | |
}, | |
"origin_token_addr": { | |
"type": "string" | |
}, | |
"quote_id": { | |
"type": "string" | |
}, | |
"relayer_address": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
}, | |
"tags": [] | |
} | |
{ | |
"openapi": "3.0.0", | |
"security": [ | |
{ | |
"bearerAuth": [] | |
} | |
], | |
"info": { | |
"title": "Synapse Protocol REST API", | |
"version": "1.7.0", | |
"description": "API documentation for the Synapse Protocol REST API" | |
}, | |
"servers": [ | |
{ | |
"url": "http://localhost:3000" | |
} | |
], | |
"components": { | |
"securitySchemes": { | |
"bearerAuth": { | |
"type": "http", | |
"scheme": "bearer", | |
"bearerFormat": "JWT" | |
} | |
}, | |
"schemas": { | |
// ... existing schemas ... | |
} | |
}, | |
// ... rest of the specification ... | |
} |
🧰 Tools
🪛 Gitleaks
287-287: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
300-300: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
1245-1245: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
🪛 checkov
[HIGH] 1-2887: Ensure that the global security field has rules defined
(CKV_OPENAPI_4)
[HIGH] 1-2887: Ensure that security operations is not empty.
(CKV_OPENAPI_5)
"type": "string" | ||
}, | ||
"quote_types": { | ||
"type": "array", | ||
"items": { | ||
"type": "string" | ||
} | ||
}, | ||
"user_address": { | ||
"type": "string" | ||
} | ||
} | ||
}, | ||
"model.PutRFQResponse": { | ||
"type": "object", | ||
"properties": { | ||
"dest_amount": { | ||
"type": "string" | ||
}, | ||
"quote_id": { | ||
"type": "string" | ||
}, | ||
"quote_type": { | ||
"type": "string" | ||
}, | ||
"reason": { | ||
"type": "string" | ||
}, | ||
"relayer_address": { | ||
"type": "string" | ||
}, | ||
"success": { | ||
"type": "boolean" | ||
} | ||
} | ||
}, | ||
"model.PutRelayerQuoteRequest": { | ||
"type": "object", | ||
"properties": { | ||
"dest_amount": { | ||
"type": "string" | ||
}, | ||
"dest_chain_id": { | ||
"type": "integer" | ||
}, | ||
"dest_fast_bridge_address": { | ||
"type": "string" | ||
}, | ||
"dest_token_addr": { | ||
"type": "string" | ||
}, | ||
"fixed_fee": { | ||
"type": "string" | ||
}, | ||
"max_origin_amount": { | ||
"type": "string" | ||
}, | ||
"origin_chain_id": { | ||
"type": "integer" | ||
}, | ||
"origin_fast_bridge_address": { | ||
"type": "string" | ||
}, | ||
"origin_token_addr": { | ||
"type": "string" | ||
} | ||
} | ||
}, | ||
"model.QuoteData": { | ||
"type": "object", | ||
"properties": { | ||
"dest_amount": { | ||
"type": "string" | ||
}, | ||
"dest_chain_id": { | ||
"type": "integer" | ||
}, | ||
"dest_token_addr": { | ||
"type": "string" | ||
}, | ||
"expiration_window": { | ||
"type": "integer" | ||
}, | ||
"origin_amount": { | ||
"type": "string" | ||
}, | ||
"origin_chain_id": { | ||
"type": "integer" | ||
}, | ||
"origin_token_addr": { | ||
"type": "string" | ||
}, | ||
"quote_id": { | ||
"type": "string" | ||
}, | ||
"relayer_address": { | ||
"type": "string" | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Strengthen request parameter validation
The schema definitions lack proper validation constraints for critical fields.
Add validation constraints to the QuoteData schema:
"model.QuoteData": {
"type": "object",
"properties": {
"dest_amount": {
- "type": "string"
+ "type": "string",
+ "pattern": "^[0-9]+$",
+ "description": "Amount in smallest unit (e.g., Wei for ETH)"
},
"dest_chain_id": {
- "type": "integer"
+ "type": "integer",
+ "minimum": 1,
+ "description": "Must be a valid EVM chain ID"
},
"dest_token_addr": {
- "type": "string"
+ "type": "string",
+ "pattern": "^0x[a-fA-F0-9]{40}$",
+ "description": "ERC20 token contract address"
}
},
+ "required": [
+ "dest_chain_id",
+ "dest_token_addr",
+ "origin_chain_id",
+ "origin_token_addr"
+ ]
}
Committable suggestion was skipped due to low confidence.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
📒 Files selected for processing (2)
- packages/rest-api/src/app.ts (2 hunks)
- packages/rest-api/src/utils/isGatewayRoute.ts (1 hunks)
🔇 Additional comments (2)
packages/rest-api/src/app.ts (2)
7-7
: Imports added correctlyThe functions and proxies are correctly imported from
./utils/isGatewayRoute
.
39-47
: Ensure proxy middleware includes essential security measuresIt's important that the
rfqApiProxy
andrfqIndexerProxy
middleware functions implement security features such as rate limiting, input validation, timeouts, and proper error handling to protect the application from potential abuse and enhance reliability.Please review the implementations of these proxy functions to ensure they include these essential security measures.
export const isRFQAPIRequest = (route: string): boolean => { | ||
return ( | ||
route.includes('/ack') || | ||
route.includes('/bulk_quotes') || | ||
route.includes('/contracts') || | ||
route.includes('/open_quote_requests') || | ||
route.includes('/quotes') || | ||
route.includes('/rfq') || | ||
route.includes('/rfq_stream') | ||
) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apply the same security improvements to RFQ API route checking.
The function has the same security vulnerabilities as isRFQIndexerRequest
.
Apply similar improvements:
export const isRFQAPIRequest = (route: string): boolean => {
+ if (!route) return false;
+ const validPaths = [
+ '/ack',
+ '/bulk_quotes',
+ '/contracts',
+ '/open_quote_requests',
+ '/quotes',
+ '/rfq',
+ '/rfq_stream'
+ ];
+ return validPaths.some(path =>
+ route === path || route.startsWith(`${path}/`)
+ );
- return (
- route.includes('/ack') ||
- route.includes('/bulk_quotes') ||
- route.includes('/contracts') ||
- route.includes('/open_quote_requests') ||
- route.includes('/quotes') ||
- route.includes('/rfq') ||
- route.includes('/rfq_stream')
- )
}
📝 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.
export const isRFQAPIRequest = (route: string): boolean => { | |
return ( | |
route.includes('/ack') || | |
route.includes('/bulk_quotes') || | |
route.includes('/contracts') || | |
route.includes('/open_quote_requests') || | |
route.includes('/quotes') || | |
route.includes('/rfq') || | |
route.includes('/rfq_stream') | |
) | |
} | |
export const isRFQAPIRequest = (route: string): boolean => { | |
if (!route) return false; | |
const validPaths = [ | |
'/ack', | |
'/bulk_quotes', | |
'/contracts', | |
'/open_quote_requests', | |
'/quotes', | |
'/rfq', | |
'/rfq_stream' | |
]; | |
return validPaths.some(path => | |
route === path || route.startsWith(`${path}/`) | |
); | |
} |
export const isRFQIndexerRequest = (route: string): boolean => { | ||
return ( | ||
route.includes('/conflicting-proofs') || | ||
route.includes('/disputes') || | ||
route.includes('/invalid-relaus') || | ||
route.includes('/pending-transactions') || | ||
route.includes('/refunded-and-relayed') || | ||
route.includes('/transaction-id') | ||
) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Security and reliability improvements needed in route checking.
The current implementation has several issues:
- Using
includes()
is vulnerable to partial matches (e.g.,/my-disputes-api
would match/disputes
) - There's a typo in
/invalid-relaus
(should be/invalid-relays
) - Missing input validation for null/undefined routes
Consider this safer implementation:
export const isRFQIndexerRequest = (route: string): boolean => {
+ if (!route) return false;
+ const validPaths = [
+ '/conflicting-proofs',
+ '/disputes',
+ '/invalid-relays',
+ '/pending-transactions',
+ '/refunded-and-relayed',
+ '/transaction-id'
+ ];
+ return validPaths.some(path =>
+ route === path || route.startsWith(`${path}/`)
+ );
- return (
- route.includes('/conflicting-proofs') ||
- route.includes('/disputes') ||
- route.includes('/invalid-relaus') ||
- route.includes('/pending-transactions') ||
- route.includes('/refunded-and-relayed') ||
- route.includes('/transaction-id')
- )
}
📝 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.
export const isRFQIndexerRequest = (route: string): boolean => { | |
return ( | |
route.includes('/conflicting-proofs') || | |
route.includes('/disputes') || | |
route.includes('/invalid-relaus') || | |
route.includes('/pending-transactions') || | |
route.includes('/refunded-and-relayed') || | |
route.includes('/transaction-id') | |
) | |
} | |
export const isRFQIndexerRequest = (route: string): boolean => { | |
if (!route) return false; | |
const validPaths = [ | |
'/conflicting-proofs', | |
'/disputes', | |
'/invalid-relays', | |
'/pending-transactions', | |
'/refunded-and-relayed', | |
'/transaction-id' | |
]; | |
return validPaths.some(path => | |
route === path || route.startsWith(`${path}/`) | |
); | |
} |
export const rfqApiProxy = createProxyMiddleware({ | ||
target: 'https://rfq-api.omnirpc.io', | ||
changeOrigin: true, | ||
}) | ||
|
||
export const rfqIndexerProxy = createProxyMiddleware({ | ||
target: 'https://rfq-indexer.synapseprotocol.com/api', | ||
changeOrigin: true, | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codebase verification
Security enhancements needed for proxy middleware configuration
The codebase analysis reveals:
- Environment variables are already in use for other configurations (OMNIRPC_BASE_URL, NODE_ENV, PORT)
- No existing error handling in proxy routes
- Rate limiting exists in bridge-related components but not for proxy routes
Recommended changes:
- Move proxy URLs to environment variables following existing patterns
- Add error handling for proxy failures
- Extend existing rate limiting to proxy routes
- Add security headers
export const rfqApiProxy = createProxyMiddleware({
target: process.env.RFQ_API_URL || 'https://rfq-api.omnirpc.io',
changeOrigin: true,
headers: {
'X-Forwarded-Proto': 'https',
},
onError: (err, req, res) => {
logger.error('RFQ API Proxy Error:', err);
res.status(502).json({ error: 'Gateway Error' });
},
})
export const rfqIndexerProxy = createProxyMiddleware({
target: process.env.RFQ_INDEXER_URL || 'https://rfq-indexer.synapseprotocol.com/api',
changeOrigin: true,
headers: {
'X-Forwarded-Proto': 'https',
},
onError: (err, req, res) => {
logger.error('RFQ Indexer Proxy Error:', err);
res.status(502).json({ error: 'Gateway Error' });
},
})
🔗 Analysis chain
Enhance proxy middleware security and configuration.
The current proxy setup lacks several important security features and best practices:
- Hardcoded URLs should be environment variables
- Missing security headers and options
- No rate limiting or request validation
- No error handling
Consider this improved implementation:
+const RFQ_API_URL = process.env.RFQ_API_URL || 'https://rfq-api.omnirpc.io';
+const RFQ_INDEXER_URL = process.env.RFQ_INDEXER_URL || 'https://rfq-indexer.synapseprotocol.com/api';
export const rfqApiProxy = createProxyMiddleware({
- target: 'https://rfq-api.omnirpc.io',
+ target: RFQ_API_URL,
changeOrigin: true,
+ pathRewrite: {
+ '^/api': '', // remove /api prefix if needed
+ },
+ headers: {
+ 'X-Forwarded-Proto': 'https',
+ },
+ onError: (err, req, res) => {
+ console.error('Proxy Error:', err);
+ res.status(500).json({ error: 'Proxy Error' });
+ },
})
export const rfqIndexerProxy = createProxyMiddleware({
- target: 'https://rfq-indexer.synapseprotocol.com/api',
+ target: RFQ_INDEXER_URL,
changeOrigin: true,
+ pathRewrite: {
+ '^/api': '',
+ },
+ headers: {
+ 'X-Forwarded-Proto': 'https',
+ },
+ onError: (err, req, res) => {
+ console.error('Proxy Error:', err);
+ res.status(500).json({ error: 'Proxy Error' });
+ },
})
Additionally, consider implementing rate limiting middleware and request validation before proxying requests.
Let's verify the environment configuration in the project:
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check if environment variables are properly configured
rg -l "RFQ_API_URL|RFQ_INDEXER_URL" --type yaml --type env
Length of output: 88
Script:
#!/bin/bash
# Check for environment variable configurations in various config files
rg -l "RFQ_API_URL|RFQ_INDEXER_URL"
# Check for any existing environment configuration patterns
rg -l "process\.env\." packages/rest-api/src/
# Look for any configuration files
fd -e yaml -e yml -e env -e config.js -e config.ts packages/rest-api/
# Check the proxy middleware implementation details
ast-grep --pattern 'createProxyMiddleware({$$$})'
Length of output: 1349
Script:
#!/bin/bash
# Check how environment variables are used in the existing files
rg -A 5 "process\.env\." packages/rest-api/src/app.ts packages/rest-api/src/utils/getOmniRpcUrl.ts packages/rest-api/src/middleware/logger.ts
# Check if there's any existing error handling in proxy routes
rg -A 5 "onError|error" packages/rest-api/src/utils/isGatewayRoute.ts
# Look for any rate limiting implementations
rg -l "rate|limit" packages/rest-api/src/
Length of output: 1465
packages/rest-api/src/app.ts
Outdated
if (isRFQAPIRequest(originalPath)) { | ||
return rfqApiProxy(req, res, next); | ||
} | ||
|
||
if (isRFQIndexerRequest(originalPath)) { | ||
return rfqIndexerProxy(req, res, next); | ||
} | ||
|
||
return next(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Refactor middleware to separate concerns
The routing logic for proxying requests is placed within the logging middleware. For better separation of concerns and to improve maintainability and readability, consider moving the proxy logic into separate middleware functions.
Apply this diff to separate the proxy logic from the logging middleware:
app.use((req, res, next) => {
logger.info({
msg: `Incoming request ${req.path}`,
method: req.method,
path: req.path,
query: req.query,
body: req.method === 'POST' || req.method === 'PUT' ? req.body : undefined,
});
const originalPath = req.path;
const originalJson = res.json;
res.json = function (body) {
logger.info({
msg: `Outgoing response ${originalPath}`,
method: req.method,
path: originalPath,
statusCode: res.statusCode,
body:
originalPath === '/' || originalPath.toLowerCase() === '/tokenlist'
? '[truncated for size]'
: body,
});
return originalJson.call(this, body);
};
- if (isRFQAPIRequest(originalPath)) {
- return rfqApiProxy(req, res, next);
- }
-
- if (isRFQIndexerRequest(originalPath)) {
- return rfqIndexerProxy(req, res, next);
- }
-
- return next();
+ next();
});
+ // Handle RFQ API requests
+ app.use((req, res, next) => {
+ if (isRFQAPIRequest(req.path)) {
+ return rfqApiProxy(req, res, next);
+ }
+ next();
+ });
+
+ // Handle RFQ Indexer requests
+ app.use((req, res, next) => {
+ if (isRFQIndexerRequest(req.path)) {
+ return rfqIndexerProxy(req, res, next);
+ }
+ next();
+ });
📝 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.
if (isRFQAPIRequest(originalPath)) { | |
return rfqApiProxy(req, res, next); | |
} | |
if (isRFQIndexerRequest(originalPath)) { | |
return rfqIndexerProxy(req, res, next); | |
} | |
return next(); | |
if (isRFQAPIRequest(originalPath)) { | |
return rfqApiProxy(req, res, next); | |
} | |
if (isRFQIndexerRequest(originalPath)) { | |
return rfqIndexerProxy(req, res, next); | |
} | |
return next(); | |
``` | |
The suggested code would be: | |
```suggestion | |
next(); | |
``` | |
And after this middleware, add these new middleware functions: | |
```suggestion | |
// Handle RFQ API requests | |
app.use((req, res, next) => { | |
if (isRFQAPIRequest(req.path)) { | |
return rfqApiProxy(req, res, next); | |
} | |
next(); | |
}); | |
// Handle RFQ Indexer requests | |
app.use((req, res, next) => { | |
if (isRFQIndexerRequest(req.path)) { | |
return rfqIndexerProxy(req, res, next); | |
} | |
next(); | |
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Outside diff range and nitpick comments (2)
packages/rest-api/src/app.ts (2)
7-12
: Consider renaming the utility file to better reflect its contents.The file
isGatewayRoute.ts
contains both route checking utilities and proxy middleware implementations. A more descriptive name likegatewayRouteUtils.ts
orproxyMiddleware.ts
would better represent its contents.
44-52
: Separate proxy routing from logging middleware.The current implementation mixes logging and proxy routing concerns within the same middleware, which violates the Single Responsibility Principle. This makes the code harder to maintain and test.
Consider implementing a dedicated proxy routing middleware:
// Logging middleware app.use((req, res, next) => { logger.info({ msg: `Incoming request ${req.path}`, // ... logging setup ... }); // ... response logging setup ... next(); }); +// Proxy routing middleware +app.use((req, res, next) => { + if (isRFQAPIRequest(req.path)) { + return rfqApiProxy(req, res, next); + } + if (isRFQIndexerRequest(req.path)) { + return rfqIndexerProxy(req, res, next); + } + next(); +});This separation would:
- Make the code more maintainable
- Make it easier to test each middleware independently
- Allow for better error handling specific to proxy routing
- Make it easier to add new proxy routes in the future
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
⛔ Files ignored due to path filters (1)
yarn.lock
is excluded by!**/yarn.lock
,!**/*.lock
📒 Files selected for processing (2)
- packages/rest-api/package.json (2 hunks)
- packages/rest-api/src/app.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/rest-api/package.json
Im seeing build errors around the router initialization in the rest-api endpoints in this PR. I think we likely need to just declare the type and resolve the portability warning by changing: const router = express.Router() to something like: const router: express.Router = express.Router(). Once we make that change, yarn build is working properly and and we have updated readMe's I think this is ready to go in. Also you can make the edits to the relevant docs: This should sufficiently finalize the work done here. Everything else functions as expected. Nice work |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Outside diff range and nitpick comments (6)
packages/rfq-indexer/README.md (1)
39-39
: Enhance example with response formatConsider adding an example response payload to help users understand what to expect.
Replace {transaction-id} with the actual transaction ID. This request will return details such as transaction status, timestamps, and associated events in JSON format. + +Example response: +```json +{ + "transactionId": "0x123...", + "status": "completed", + "timestamp": "2024-10-15T14:30:00Z", + "events": [ + // ... event details + ] +} +```packages/rest-api/src/routes/indexRoute.ts (1)
Line range hint
8-71
: Consider adding RFQ-related endpoint documentation.The OpenAPI documentation is well-structured and includes comprehensive examples. However, since this PR introduces an API gateway for rfq-indexer and rfq APIs, consider adding documentation for these new endpoints.
Would you like me to help generate the OpenAPI documentation for the RFQ-related endpoints? This would align with the documentation links mentioned in the PR comments:
- RFQ-Indexer API Documentation
- RFQ API Documentation
packages/rest-api/src/routes/bridgeTxStatusRoute.ts (2)
Line range hint
11-108
: Consider adding rate limiting information to the OpenAPI documentation.While the API documentation is comprehensive, it would be beneficial to include information about rate limiting if applicable, as this is a public-facing API gateway endpoint.
Add the following to the OpenAPI documentation:
* summary: Get Bridge Transaction Status * description: Used to get the status of a bridge transaction, and the destination transaction information if the transaction is finalized +* x-rateLimit: +* limit: <rate_limit_value> +* period: <time_period> * parameters:
No rate limiting found - endpoint needs protection against DoS attacks
The code analysis shows no rate limiting implementation in the REST API. This is concerning for a public-facing API gateway endpoint that handles transaction status queries. To protect against potential DoS attacks, rate limiting should be implemented using a middleware like
express-rate-limit
.Suggested implementation:
- Add rate limiting middleware at the application level in
app.ts
- Configure reasonable limits based on expected legitimate usage patterns
- Apply rate limiting specifically to the
/bridgeTxStatus
endpoint🔗 Analysis chain
Line range hint
109-143
: Verify rate limiting implementation for this endpoint.Since this is a public-facing API gateway endpoint that handles transaction status queries, it should be protected against potential DoS attacks.
Let's verify if rate limiting is implemented at the application level:
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Check for rate limiting middleware implementation # Expected: Find rate limiting middleware configuration # Search for rate limiting imports and usage rg -l "rate-limit|rateLimit" --type ts # Search for express-rate-limit configuration ast-grep --pattern 'new RateLimit({ $$$ })'Length of output: 88
Script:
#!/bin/bash # Let's try different approaches to find rate limiting implementation # Search for any rate limiting related terms more broadly rg -i "rate.?limit" --type ts # Look for common rate limiting middleware patterns rg -i "limiter|throttle" --type ts # Check the main application setup file for middleware fd "app.ts|index.ts" --type f --exec cat {} # Look for any middleware registration patterns ast-grep --pattern 'app.use($$$)'Length of output: 278209
Script:
#!/bin/bash # Let's check for rate limiting middleware or configuration rg -A 5 -i "rate.?limit|throttle" --type ts # Search for any rate limiting related imports rg -l "express-rate-limit|rate-limit" --type ts # Look for rate limiting configuration files fd -e json -e yaml -e js -e ts "rate" -x cat {}Length of output: 46599
packages/rest-api/src/routes/bridgeLimitsRoute.ts (1)
Line range hint
15-85
: Consider enhancing OpenAPI documentation.While the documentation is comprehensive, consider adding:
- Examples for different validation error scenarios
- Description of token address normalization and checksum rules
- Details about route validation logic
Example enhancement for validation error responses:
description: Invalid input content: application/json: schema: type: object properties: error: type: object properties: value: type: string message: type: string field: type: string location: type: string examples: + invalidChain: + value: { error: { value: "999", message: "Unsupported fromChain", field: "fromChain", location: "query" } } + invalidToken: + value: { error: { value: "0xinvalid", message: "Invalid fromToken address", field: "fromToken", location: "query" } } + unsupportedToken: + value: { error: { value: "0x1234...", message: "Token not supported on specified chain", field: "fromToken", location: "query" } } + invalidRoute: + value: { error: { value: "", message: "No valid route exists for the chain/token combination", field: "", location: "query" } }packages/rest-api/src/routes/destinationTxRoute.ts (1)
Line range hint
134-146
: Consider enhancing input validation for security.While basic validation is in place, consider adding these security enhancements:
- Add length limits for
txHash
to prevent DoS attacks- Add a regex pattern for
txHash
to validate hex format- Add range validation for
originChainId
to ensure it's within supported chain IDsExample enhancement:
router.get( '/', [ check('originChainId') .exists() .withMessage('originChainId is required') - .isNumeric(), + .isNumeric() + .isInt({ min: 1 }) + .custom(value => { + const supportedChains = [1, 42161, 8453]; // add your supported chains + return supportedChains.includes(Number(value)); + }) + .withMessage('Unsupported chain ID'), check('txHash') .exists() .withMessage('txHash is required') - .isString(), + .isString() + .isLength({ min: 66, max: 66 }) + .matches(/^0x[a-fA-F0-9]{64}$/) + .withMessage('Invalid transaction hash format'), ], showFirstValidationError, destinationTxController )
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
📒 Files selected for processing (15)
- packages/rest-api/src/routes/bridgeLimitsRoute.ts (1 hunks)
- packages/rest-api/src/routes/bridgeRoute.ts (1 hunks)
- packages/rest-api/src/routes/bridgeTxInfoRoute.ts (1 hunks)
- packages/rest-api/src/routes/bridgeTxStatusRoute.ts (1 hunks)
- packages/rest-api/src/routes/destinationTokensRoute.ts (1 hunks)
- packages/rest-api/src/routes/destinationTxRoute.ts (1 hunks)
- packages/rest-api/src/routes/index.ts (1 hunks)
- packages/rest-api/src/routes/indexRoute.ts (1 hunks)
- packages/rest-api/src/routes/swapRoute.ts (1 hunks)
- packages/rest-api/src/routes/swapTxInfoRoute.ts (1 hunks)
- packages/rest-api/src/routes/synapseTxIdRoute.ts (1 hunks)
- packages/rest-api/src/routes/tokenListRoute.ts (1 hunks)
- packages/rfq-indexer/README.md (1 hunks)
- packages/rfq-indexer/api/README.md (1 hunks)
- services/rfq/api/README.md (1 hunks)
✅ Files skipped from review due to trivial changes (5)
- packages/rest-api/src/routes/bridgeRoute.ts
- packages/rest-api/src/routes/bridgeTxInfoRoute.ts
- packages/rest-api/src/routes/swapRoute.ts
- packages/rest-api/src/routes/swapTxInfoRoute.ts
- services/rfq/api/README.md
🧰 Additional context used
🪛 Markdownlint
packages/rfq-indexer/api/README.md
5-5: null
Bare URL used(MD034, no-bare-urls)
🔇 Additional comments (14)
packages/rest-api/src/routes/index.ts (2)
15-15
: LGTM: Type annotation improves type safetyThe explicit type annotation
express.Router
resolves the build errors and follows TypeScript best practices.
Line range hint
17-28
: Verify: Missing RFQ-related routesThe PR objectives mention implementing an API gateway for rfq-indexer and rfq APIs, but I don't see any RFQ-related routes registered here. Please verify if these routes need to be added.
packages/rfq-indexer/README.md (1)
41-41
: Ensure consistent domain usage in documentation linksThe API documentation link uses a different format (
api.synapseprotocol.com/api-docs
) compared to the example endpoint. Please verify if this is the correct documentation URL.✅ Verification successful
Based on the search results, I can generate the final response as there's enough evidence to verify the domain usage consistency.
Domain format is consistent across documentation
The search results show that
api.synapseprotocol.com
is consistently used across all documentation files, including READMEs and API docs. Both HTTP and HTTPS protocols are used, but the domain remains consistent. The API documentation URL atapi.synapseprotocol.com/api-docs
is correctly referenced.🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Check for other occurrences of the API domain to ensure consistency rg -i "api\.synapseprotocol\.com" --type mdLength of output: 5404
packages/rest-api/src/routes/indexRoute.ts (1)
5-5
: LGTM! Type annotation addresses the build error.The explicit type annotation
express.Router
matches the fix suggested by Defi-Moses and resolves the reported build issues.Let's verify if similar type annotations are consistently applied across other route files:
✅ Verification successful
Type annotations are consistently applied across all route files
The verification shows that all route files in the
packages/rest-api/src/routes
directory are using the explicitexpress.Router
type annotation consistently. No files were found with missing type annotations, confirming that the codebase follows a uniform pattern.🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Check router type annotations in route files # Expected: All route files should use explicit type annotations # Test: Search for router initialization patterns echo "Files potentially missing type annotations:" rg "const router = express\.Router\(\)" "packages/rest-api/src/routes" echo -e "\nFiles with correct type annotations:" rg "const router: express\.Router = express\.Router\(\)" "packages/rest-api/src/routes"Length of output: 1489
packages/rest-api/src/routes/synapseTxIdRoute.ts (2)
8-8
: LGTM! Type annotation improves type safety.The explicit type annotation for the router aligns with TypeScript best practices and resolves the build issues mentioned in the PR comments.
Line range hint
8-106
: Consider enhancing error handling for the controller.While the input validation is well implemented and the OpenAPI documentation covers error responses, it would be beneficial to verify that the
synapseTxIdController
properly handles and returns these documented error responses.Let's verify the controller implementation:
✅ Verification successful
Error handling in the controller is properly implemented
The controller already implements comprehensive error handling that matches the documented responses:
- Returns 400 status with validation errors when input validation fails
- Returns 500 status with error message for unexpected errors
- Includes proper error logging with query parameters and stack traces
- Response formats match the OpenAPI documentation
The implementation is robust and no changes are needed.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Check error handling implementation in the controller # Test: Look for error handling patterns in the controller ast-grep --pattern 'catch ($_) { $$$ }' # Test: Check if the controller returns the documented status codes rg -A 5 'res\.status\((400|500)\)' 'src/controllers/synapseTxIdController.ts'Length of output: 202
Script:
#!/bin/bash # Let's first locate the controller file fd synapseTxIdController # Then check its content fd synapseTxIdController --exec cat {}Length of output: 1131
packages/rest-api/src/routes/tokenListRoute.ts (2)
5-5
: LGTM! Type annotation fixes build issues.The explicit type annotation
express.Router
aligns with the build fix suggested in the PR comments and improves type safety.
Line range hint
1-108
: Well-structured API implementation with comprehensive OpenAPI documentation.The implementation provides:
- Clear API documentation with detailed schema
- Proper error handling
- Realistic examples that aid integration
packages/rest-api/src/routes/destinationTokensRoute.ts (2)
13-13
: LGTM! Type annotation addresses build issues.The explicit type annotation
router: express.Router
follows TypeScript best practices and resolves the build errors mentioned in the PR comments.
Line range hint
15-106
: Excellent OpenAPI documentation!The comprehensive OpenAPI specification includes:
- Clear endpoint description
- Detailed parameter documentation
- Well-structured response schemas with examples
- Proper error response documentation
This level of documentation significantly improves API usability and maintainability.
packages/rest-api/src/routes/bridgeTxStatusRoute.ts (1)
9-9
: LGTM! Type annotation fixes build issues.The explicit type annotation for the router follows TypeScript best practices and resolves the build errors mentioned in the PR comments.
packages/rest-api/src/routes/bridgeLimitsRoute.ts (2)
13-13
: LGTM! Type annotation addresses build errors.The explicit type annotation for the router variable aligns with TypeScript best practices and resolves the build errors mentioned in the PR comments.
Line range hint
86-143
: Verify route validation implementation.The validation chain looks robust with proper middleware ordering and comprehensive checks. Let's verify the implementation of the route validation utility.
✅ Verification successful
Route validation implementation is robust and well-tested
The validation chain implementation is solid with:
- Comprehensive route validation in
validateRouteExists
that checks both token existence and valid routes usingBRIDGE_ROUTE_MAPPING_SYMBOLS
- Well-structured route mapping generation in
bridgeRouteMapping.ts
that considers chain and token compatibility- Thorough test coverage including positive and negative test cases for:
- Valid routes (USDC and ETH bridging)
- Unsupported routes
- Invalid chain combinations
- Missing token parameters
The implementation correctly validates the existence of bridge routes between chains and tokens before allowing the request to reach the controller.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify the implementation of validateRouteExists utility # Test: Check the implementation of validateRouteExists rg -A 10 "function validateRouteExists" # Test: Check for any test files covering this validation fd -g "*test*" -x rg -l "validateRouteExists"Length of output: 87
Script:
#!/bin/bash # Let's try a broader search to locate the validateRouteExists implementation rg -l "validateRouteExists" # Also search for files containing route validation related terms rg -l "route.*validation|validate.*route" # Look for the file containing the bridgeLimitsRoute implementation fd -g "*bridgeLimits*.ts"Length of output: 558
Script:
#!/bin/bash # Let's examine the implementation of validateRouteExists cat packages/rest-api/src/validations/validateRouteExists.ts # Check the test coverage cat packages/rest-api/src/tests/bridgeLimitsRoute.test.ts # Look at the controller implementation to understand the full flow cat packages/rest-api/src/controllers/bridgeLimitsController.tsLength of output: 7416
Script:
#!/bin/bash # Let's check the dependencies needed for route validation cat packages/rest-api/src/utils/bridgeRouteMapping.ts cat packages/rest-api/src/utils/tokenAddressToToken.tsLength of output: 3447
packages/rest-api/src/routes/destinationTxRoute.ts (1)
7-7
: LGTM: Type annotation fixes build error.The explicit type annotation
express.Router
matches the fix suggested in PR comments and follows TypeScript best practices.
To query information for a specific transaction, use the following `curl` command: | ||
|
||
```bash | ||
curl -X 'GET' 'http://api.synapseprotocol.com/transaction-id/{transaction-id}' -H 'accept: application/json' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use HTTPS for API endpoint example
The example uses an insecure HTTP protocol. For security best practices, use HTTPS instead.
-curl -X 'GET' 'http://api.synapseprotocol.com/transaction-id/{transaction-id}' -H 'accept: application/json'
+curl -X 'GET' 'https://api.synapseprotocol.com/transaction-id/{transaction-id}' -H 'accept: application/json'
📝 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.
curl -X 'GET' 'http://api.synapseprotocol.com/transaction-id/{transaction-id}' -H 'accept: application/json' | |
curl -X 'GET' 'https://api.synapseprotocol.com/transaction-id/{transaction-id}' -H 'accept: application/json' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Outside diff range and nitpick comments (2)
docs/bridge/docs/04-Routers/RFQ/API/index.md (2)
53-53
: Fix list indentation.The unordered list item should be properly indented. Please adjust the indentation to match the Markdown style guidelines.
Apply this formatting fix:
-Mainnet: `api.synapseprotocol.com/quotes` + - Mainnet: `api.synapseprotocol.com/quotes`🧰 Tools
🪛 Markdownlint
53-53: Expected: 0; Actual: 1
Unordered list indentation(MD007, ul-indent)
Line range hint
1-54
: Add context about the API gateway introduction.While the URL change is documented, it would be helpful to add a brief section explaining the introduction of the API gateway and its benefits. This context would help users understand the architectural changes.
Consider adding a section like this at the beginning of the document:
## API Gateway The RFQ API is now served through a centralized API gateway at `api.synapseprotocol.com`. This gateway provides: - Unified access to both RFQ and RFQ-indexer APIs - Improved routing and request handling - Enhanced monitoring and security🧰 Tools
🪛 Markdownlint
53-53: Expected: 0; Actual: 1
Unordered list indentation(MD007, ul-indent)
54-54: Expected: 0; Actual: 1
Unordered list indentation(MD007, ul-indent)
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
📒 Files selected for processing (2)
- docs/bridge/docs/04-Routers/RFQ/API/index.md (1 hunks)
- docs/bridge/docs/06-Services/06-RFQ-Indexer-API.md (1 hunks)
✅ Files skipped from review due to trivial changes (1)
- docs/bridge/docs/06-Services/06-RFQ-Indexer-API.md
🧰 Additional context used
🪛 Markdownlint
docs/bridge/docs/04-Routers/RFQ/API/index.md
53-53: Expected: 0; Actual: 1
Unordered list indentation(MD007, ul-indent)
- Mainnet: `api.synapseprotocol.com/quotes` | ||
- Testnet: `rfq-api-testnet.omnirpc.io` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codebase verification
API endpoint inconsistency detected in configuration
There's an inconsistency in the API endpoints across the documentation. While the RFQ API documentation has been updated to use api.synapseprotocol.com/quotes
for mainnet, the docusaurus.config.ts
file still contains a reference to the old endpoint: baseUrl: 'https://rfq-api.omnirpc.io/'
.
docs/bridge/docusaurus.config.ts
: Update thebaseUrl
configuration to use the new API endpoint- Ensure the testnet endpoint
rfq-api-testnet.omnirpc.io
is still valid and intended to be used
🔗 Analysis chain
Verify API endpoint consistency across documentation.
The mainnet API URL has been updated to use the new base URL. Let's ensure this change is consistently reflected across all related documentation.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for any remaining references to the old API URL and verify consistency of the new URL
# across documentation files
echo "Checking for old API URL references..."
rg -i "rfq-api\.omnirpc\.io" docs/
echo "Verifying consistency of new API URL..."
rg -i "api\.synapseprotocol\.com/quotes" docs/
Length of output: 430
Script:
#!/bin/bash
# Let's check for any other variations of the API endpoints to ensure complete coverage
echo "Checking for variations of omnirpc domain..."
rg -i "omnirpc" docs/
echo "Checking for variations of synapseprotocol domain..."
rg -i "synapseprotocol" docs/
echo "Checking for any API endpoint configurations in code..."
fd -e ts -e js -e json --exec grep -l -i "api\." {} \;
Length of output: 12309
🧰 Tools
🪛 Markdownlint
53-53: Expected: 0; Actual: 1
Unordered list indentation(MD007, ul-indent)
54-54: Expected: 0; Actual: 1
Unordered list indentation(MD007, ul-indent)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Outside diff range and nitpick comments (1)
packages/rest-api/swagger.json (1)
281-282
: Use placeholder addresses in examplesThe example responses contain real contract addresses. While these are public contracts, it's better to use placeholder addresses in documentation to:
- Prevent confusion between environments
- Avoid unintentional dependencies on specific addresses
- Reduce maintenance when contracts are upgraded
Replace real addresses with clearly marked example addresses like
0x0000...Example
in all examples.Also applies to: 1248-1249
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
📒 Files selected for processing (1)
- packages/rest-api/swagger.json (1 hunks)
🧰 Additional context used
🪛 Gitleaks
packages/rest-api/swagger.json
288-288: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
301-301: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
1252-1252: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
🪛 checkov
packages/rest-api/swagger.json
[HIGH] 1-2907: Ensure that the global security field has rules defined
(CKV_OPENAPI_4)
[HIGH] 1-2907: Ensure that security operations is not empty.
(CKV_OPENAPI_5)
🔇 Additional comments (1)
packages/rest-api/swagger.json (1)
8-12
: Previous server configuration comment is still validThe server configuration still only includes localhost, which is not suitable for production use. Please refer to the previous review comment for the recommended changes.
"type": "object", | ||
"properties": { | ||
"dest_amount": { | ||
"type": "string" | ||
}, | ||
"dest_chain_id": { | ||
"type": "integer" | ||
}, | ||
"dest_token_addr": { | ||
"type": "string" | ||
}, | ||
"expiration_window": { | ||
"type": "integer" | ||
}, | ||
"origin_amount": { | ||
"type": "string" | ||
}, | ||
"origin_chain_id": { | ||
"type": "integer" | ||
}, | ||
"origin_token_addr": { | ||
"type": "string" | ||
}, | ||
"quote_id": { | ||
"type": "string" | ||
}, | ||
"relayer_address": { | ||
"type": "string" | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Strengthen request parameter validation
The QuoteData schema lacks proper validation constraints for critical fields. This could lead to invalid data being processed.
Add validation constraints:
"model.QuoteData": {
"type": "object",
"properties": {
"dest_amount": {
- "type": "string"
+ "type": "string",
+ "pattern": "^[0-9]+$",
+ "description": "Amount in smallest unit (e.g., Wei for ETH)"
},
"dest_chain_id": {
- "type": "integer"
+ "type": "integer",
+ "minimum": 1,
+ "description": "Must be a valid EVM chain ID"
},
"dest_token_addr": {
- "type": "string"
+ "type": "string",
+ "pattern": "^0x[a-fA-F0-9]{40}$",
+ "description": "ERC20 token contract address"
}
},
+ "required": [
+ "dest_chain_id",
+ "dest_token_addr",
+ "origin_chain_id",
+ "origin_token_addr"
+ ]
}
Committable suggestion was skipped due to low confidence.
{ | ||
"openapi": "3.0.0", | ||
"info": { | ||
"title": "Synapse Protocol REST API", | ||
"version": "1.7.0", | ||
"description": "API documentation for the Synapse Protocol REST API" | ||
}, | ||
"servers": [ | ||
{ | ||
"url": "http://localhost:3000" | ||
} | ||
], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add API security requirements
The API specification lacks critical security definitions. For a financial API handling sensitive transactions, you must:
- Define global security schemes
- Implement authentication requirements
- Add rate limiting
Add the following security configuration:
{
"openapi": "3.0.0",
+ "security": [
+ {
+ "bearerAuth": []
+ }
+ ],
"components": {
+ "securitySchemes": {
+ "bearerAuth": {
+ "type": "http",
+ "scheme": "bearer",
+ "bearerFormat": "JWT"
+ }
+ }
}
}
Committable suggestion was skipped due to low confidence.
🧰 Tools
🪛 checkov
[HIGH] 1-2907: Ensure that the global security field has rules defined
(CKV_OPENAPI_4)
[HIGH] 1-2907: Ensure that security operations is not empty.
(CKV_OPENAPI_5)
Description
A clear and concise description of the features you're adding in this pull request.
Additional context
Add any other context about the problem you're solving.
Metadata
Summary by CodeRabbit
Release Notes
New Features
Bug Fixes
Chores
@synapsecns/rest-api
project for enhanced functionality.