- Backend REST/gateway/track routes, analytics, Blockscout proxy paths. - Frontend wallet and liquidity surfaces; MetaMask token list alignment. - Deployment docs, verification scripts, address inventory updates. Check: go build ./... under backend/ (pass). Made-with: Cursor
531 lines
14 KiB
YAML
531 lines
14 KiB
YAML
openapi: 3.0.3
|
|
info:
|
|
title: SolaceScanScout API
|
|
description: |
|
|
Blockchain Explorer API for ChainID 138 with tiered access control.
|
|
|
|
## Authentication
|
|
|
|
Track 1 endpoints are public and require no authentication.
|
|
Track 2-4 endpoints require JWT authentication via wallet signature.
|
|
|
|
## Rate Limiting
|
|
|
|
- Track 1: 100 requests/minute per IP
|
|
- Track 2-4: Based on user tier and subscription
|
|
|
|
version: 1.0.0
|
|
contact:
|
|
name: API Support
|
|
email: support@d-bis.org
|
|
license:
|
|
name: MIT
|
|
url: https://opensource.org/licenses/MIT
|
|
|
|
servers:
|
|
- url: https://api.d-bis.org
|
|
description: Production server
|
|
- url: http://localhost:8080
|
|
description: Development server
|
|
|
|
tags:
|
|
- name: Health
|
|
description: Health check endpoints
|
|
- name: Blocks
|
|
description: Block-related endpoints
|
|
- name: Transactions
|
|
description: Transaction-related endpoints
|
|
- name: Addresses
|
|
description: Address-related endpoints
|
|
- name: Search
|
|
description: Unified search endpoints
|
|
- name: Track1
|
|
description: Public RPC gateway endpoints (no auth required)
|
|
- name: MissionControl
|
|
description: Public mission-control health, bridge trace, and cached liquidity helpers
|
|
- name: Track2
|
|
description: Indexed explorer endpoints (auth required)
|
|
- name: Track3
|
|
description: Analytics endpoints (Track 3+ required)
|
|
- name: Track4
|
|
description: Operator endpoints (Track 4 + IP whitelist)
|
|
|
|
paths:
|
|
/health:
|
|
get:
|
|
tags:
|
|
- Health
|
|
summary: Health check
|
|
description: Returns the health status of the API
|
|
operationId: getHealth
|
|
responses:
|
|
'200':
|
|
description: Service is healthy
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
status:
|
|
type: string
|
|
example: ok
|
|
timestamp:
|
|
type: string
|
|
format: date-time
|
|
database:
|
|
type: string
|
|
example: connected
|
|
|
|
/api/v1/blocks:
|
|
get:
|
|
tags:
|
|
- Blocks
|
|
summary: List blocks
|
|
description: Returns a paginated list of blocks
|
|
operationId: listBlocks
|
|
parameters:
|
|
- name: limit
|
|
in: query
|
|
description: Number of blocks to return
|
|
required: false
|
|
schema:
|
|
type: integer
|
|
minimum: 1
|
|
maximum: 100
|
|
default: 20
|
|
- name: page
|
|
in: query
|
|
description: Page number
|
|
required: false
|
|
schema:
|
|
type: integer
|
|
minimum: 1
|
|
default: 1
|
|
- name: chain_id
|
|
in: query
|
|
description: Chain ID filter
|
|
required: false
|
|
schema:
|
|
type: integer
|
|
default: 138
|
|
responses:
|
|
'200':
|
|
description: List of blocks
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/BlockListResponse'
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'500':
|
|
$ref: '#/components/responses/InternalServerError'
|
|
|
|
/api/v1/blocks/{chain_id}/{number}:
|
|
get:
|
|
tags:
|
|
- Blocks
|
|
summary: Get block by number
|
|
description: Returns block details by chain ID and block number
|
|
operationId: getBlockByNumber
|
|
parameters:
|
|
- name: chain_id
|
|
in: path
|
|
required: true
|
|
description: Chain ID
|
|
schema:
|
|
type: integer
|
|
example: 138
|
|
- name: number
|
|
in: path
|
|
required: true
|
|
description: Block number
|
|
schema:
|
|
type: integer
|
|
example: 1000
|
|
responses:
|
|
'200':
|
|
description: Block details
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Block'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'500':
|
|
$ref: '#/components/responses/InternalServerError'
|
|
|
|
/api/v1/transactions:
|
|
get:
|
|
tags:
|
|
- Transactions
|
|
summary: List transactions
|
|
description: Returns a paginated list of transactions
|
|
operationId: listTransactions
|
|
parameters:
|
|
- name: limit
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
default: 20
|
|
- name: page
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
default: 1
|
|
- name: chain_id
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
default: 138
|
|
responses:
|
|
'200':
|
|
description: List of transactions
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TransactionListResponse'
|
|
|
|
/api/v1/search:
|
|
get:
|
|
tags:
|
|
- Search
|
|
summary: Unified search
|
|
description: |
|
|
Searches for blocks, transactions, or addresses.
|
|
Automatically detects the type based on the query format.
|
|
operationId: search
|
|
parameters:
|
|
- name: q
|
|
in: query
|
|
required: true
|
|
description: Search query (block number, address, or transaction hash)
|
|
schema:
|
|
type: string
|
|
example: "0x1234567890abcdef"
|
|
responses:
|
|
'200':
|
|
description: Search results
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/SearchResponse'
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
|
|
/api/v1/track1/blocks/latest:
|
|
get:
|
|
tags:
|
|
- Track1
|
|
summary: Get latest blocks (Public)
|
|
description: Returns the latest blocks via RPC gateway. No authentication required.
|
|
operationId: getLatestBlocks
|
|
parameters:
|
|
- name: limit
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
default: 10
|
|
maximum: 50
|
|
responses:
|
|
'200':
|
|
description: Latest blocks
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/BlockListResponse'
|
|
|
|
/api/v1/mission-control/stream:
|
|
get:
|
|
tags:
|
|
- MissionControl
|
|
summary: Mission-control SSE stream
|
|
description: |
|
|
Server-Sent Events stream with the same inner `data` payload as `GET /api/v1/track1/bridge/status`.
|
|
Emits one event immediately, then refreshes every 20 seconds. Configure nginx with `proxy_buffering off`.
|
|
operationId: getMissionControlStream
|
|
responses:
|
|
'200':
|
|
description: SSE stream
|
|
content:
|
|
text/event-stream:
|
|
schema:
|
|
type: string
|
|
|
|
/api/v1/mission-control/liquidity/token/{address}/pools:
|
|
get:
|
|
tags:
|
|
- MissionControl
|
|
summary: Cached liquidity proxy
|
|
description: |
|
|
30-second in-memory cached proxy to the token-aggregation pools endpoint for the configured `CHAIN_ID`.
|
|
operationId: getMissionControlLiquidityPools
|
|
parameters:
|
|
- name: address
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
pattern: '^0x[a-fA-F0-9]{40}$'
|
|
responses:
|
|
'200':
|
|
description: Upstream JSON response
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'503':
|
|
description: `TOKEN_AGGREGATION_BASE_URL` not configured
|
|
|
|
/api/v1/mission-control/bridge/trace:
|
|
get:
|
|
tags:
|
|
- MissionControl
|
|
summary: Resolve a transaction through Blockscout and label 138-side contracts
|
|
description: |
|
|
Queries Blockscout using `BLOCKSCOUT_INTERNAL_URL` and labels the `from` and `to` addresses using Chain 138 entries from `SMART_CONTRACTS_MASTER_JSON`.
|
|
operationId: getMissionControlBridgeTrace
|
|
parameters:
|
|
- name: tx
|
|
in: query
|
|
required: true
|
|
schema:
|
|
type: string
|
|
pattern: '^0x[a-fA-F0-9]{64}$'
|
|
responses:
|
|
'200':
|
|
description: Labeled bridge trace
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'502':
|
|
description: Blockscout lookup failed
|
|
|
|
/api/v1/track4/operator/run-script:
|
|
post:
|
|
tags:
|
|
- Track4
|
|
summary: Run an allowlisted operator script
|
|
description: |
|
|
Track 4 endpoint. Requires authenticated wallet, IP allowlisting, `OPERATOR_SCRIPTS_ROOT`, and `OPERATOR_SCRIPT_ALLOWLIST`.
|
|
operationId: runOperatorScript
|
|
security:
|
|
- bearerAuth: []
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [script]
|
|
properties:
|
|
script:
|
|
type: string
|
|
description: Path relative to `OPERATOR_SCRIPTS_ROOT`
|
|
args:
|
|
type: array
|
|
items:
|
|
type: string
|
|
maxItems: 24
|
|
responses:
|
|
'200':
|
|
description: Script execution result
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'503':
|
|
description: Script root or allowlist not configured
|
|
|
|
/api/v1/track2/search:
|
|
get:
|
|
tags:
|
|
- Track2
|
|
summary: Advanced search (Auth Required)
|
|
description: Advanced search with indexed data. Requires Track 2+ authentication.
|
|
operationId: track2Search
|
|
security:
|
|
- bearerAuth: []
|
|
parameters:
|
|
- name: q
|
|
in: query
|
|
required: true
|
|
schema:
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: Search results
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
|
|
components:
|
|
securitySchemes:
|
|
bearerAuth:
|
|
type: http
|
|
scheme: bearer
|
|
bearerFormat: JWT
|
|
description: JWT token obtained from /api/v1/auth/wallet
|
|
|
|
schemas:
|
|
Block:
|
|
type: object
|
|
properties:
|
|
chain_id:
|
|
type: integer
|
|
example: 138
|
|
number:
|
|
type: integer
|
|
example: 1000
|
|
hash:
|
|
type: string
|
|
example: "0x1234567890abcdef"
|
|
parent_hash:
|
|
type: string
|
|
timestamp:
|
|
type: string
|
|
format: date-time
|
|
miner:
|
|
type: string
|
|
transaction_count:
|
|
type: integer
|
|
gas_used:
|
|
type: integer
|
|
gas_limit:
|
|
type: integer
|
|
|
|
Transaction:
|
|
type: object
|
|
properties:
|
|
chain_id:
|
|
type: integer
|
|
hash:
|
|
type: string
|
|
block_number:
|
|
type: integer
|
|
from_address:
|
|
type: string
|
|
to_address:
|
|
type: string
|
|
value:
|
|
type: string
|
|
gas:
|
|
type: integer
|
|
gas_price:
|
|
type: string
|
|
status:
|
|
type: string
|
|
enum: [success, failed]
|
|
|
|
BlockListResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Block'
|
|
pagination:
|
|
$ref: '#/components/schemas/Pagination'
|
|
|
|
TransactionListResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Transaction'
|
|
pagination:
|
|
$ref: '#/components/schemas/Pagination'
|
|
|
|
Pagination:
|
|
type: object
|
|
properties:
|
|
page:
|
|
type: integer
|
|
limit:
|
|
type: integer
|
|
total:
|
|
type: integer
|
|
total_pages:
|
|
type: integer
|
|
|
|
SearchResponse:
|
|
type: object
|
|
properties:
|
|
query:
|
|
type: string
|
|
results:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
type:
|
|
type: string
|
|
enum: [block, transaction, address]
|
|
data:
|
|
type: object
|
|
|
|
Error:
|
|
type: object
|
|
properties:
|
|
error:
|
|
type: object
|
|
properties:
|
|
code:
|
|
type: string
|
|
message:
|
|
type: string
|
|
|
|
responses:
|
|
BadRequest:
|
|
description: Bad request
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
example:
|
|
error:
|
|
code: "bad_request"
|
|
message: "Invalid request parameters"
|
|
|
|
Unauthorized:
|
|
description: Unauthorized - Authentication required
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
example:
|
|
error:
|
|
code: "unauthorized"
|
|
message: "Authentication required"
|
|
|
|
Forbidden:
|
|
description: Forbidden - Insufficient permissions
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
example:
|
|
error:
|
|
code: "forbidden"
|
|
message: "Insufficient permissions. Track 2+ required."
|
|
|
|
NotFound:
|
|
description: Resource not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
example:
|
|
error:
|
|
code: "not_found"
|
|
message: "Resource not found"
|
|
|
|
InternalServerError:
|
|
description: Internal server error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
example:
|
|
error:
|
|
code: "internal_error"
|
|
message: "An internal error occurred"
|