Files
cryptowallet/apps/api/swagger.json
ZOMBIIIIIII 53635806d6 swaggerready
2026-05-14 01:11:20 +03:00

746 lines
39 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"openapi": "3.0.0",
"info": {
"title": "CryptoWallet API",
"version": "5.0.0",
"description": "Multi-chain custodial wallet API (ETH/BSC/BTC/TRX/SOL). Сервер генерит mnemonic, шифрует AES-256-GCM (master-key из HashiCorp Vault), хранит её и сам подписывает транзакции. Auth via JWT (cookie/Bearer), issued by external auth-service (BITOK)."
},
"servers": [
{ "url": "/api", "description": "API root" }
],
"tags": [
{ "name": "System", "description": "Health & service info" },
{ "name": "Wallets", "description": "Custodial wallet lifecycle" },
{ "name": "Wallet Ops", "description": "Per-chain balance / transactions / send" },
{ "name": "BTC", "description": "Bitcoin RPC proxy (Blockstream)" },
{ "name": "TRON", "description": "TRON RPC proxy (TronGrid)" },
{ "name": "Solana", "description": "Solana swap proxy (Jupiter)" },
{ "name": "TRON Swap", "description": "TRON swap proxy (SunSwap + FeeSwapRouter)" },
{ "name": "BSC", "description": "BSC swap proxy (PancakeSwap V2)" },
{ "name": "Relay", "description": "Cross-chain bridges (Relay Protocol)" },
{ "name": "Prices", "description": "USD-цены (CoinGecko + KeyDB cache 5 мин)" }
],
"components": {
"securitySchemes": {
"bearerAuth": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" },
"cookieAuth": { "type": "apiKey", "in": "cookie", "name": "access_token" }
},
"schemas": {
"Error": {
"type": "object",
"properties": {
"success": { "type": "boolean", "example": false },
"error": { "type": "string" }
}
},
"HealthResponse": {
"type": "object",
"properties": {
"success": { "type": "boolean", "example": true },
"data": { "type": "object", "properties": { "status": { "type": "string", "example": "ok" } } }
}
},
"Chain": {
"type": "string",
"enum": ["ETH", "BTC", "SOL", "TRX", "BSC"]
},
"Wallet": {
"type": "object",
"properties": {
"chain": { "$ref": "#/components/schemas/Chain" },
"address": { "type": "string" },
"derivationPath": { "type": "string", "description": "BIP32 path" }
}
},
"WalletsResponse": {
"type": "object",
"properties": {
"success": { "type": "boolean", "example": true },
"data": { "type": "array", "items": { "$ref": "#/components/schemas/Wallet" } }
}
},
"MnemonicResponse": {
"type": "object",
"properties": {
"success": { "type": "boolean", "example": true },
"data": {
"type": "object",
"properties": {
"mnemonic": { "type": "string", "description": "BIP39 mnemonic (12 words)" }
}
}
}
},
"TxBroadcastResponse": {
"type": "object",
"properties": {
"success": { "type": "boolean", "example": true },
"data": {
"type": "object",
"properties": {
"txid": { "type": "string", "description": "Идентификатор отправленной транзакции" },
"chain": { "$ref": "#/components/schemas/Chain" }
}
}
}
},
"FormattedAmount": {
"type": "object",
"description": "Сумма с метаданными формата + USD-цена. Поля `usdPrice`/`usdValue` всегда присутствуют, но могут быть `null` если symbol не в registry или upstream price oracle (CoinGecko) недоступен.",
"required": ["raw", "formatted", "decimals", "usdPrice", "usdValue"],
"properties": {
"raw": { "type": "string", "description": "Smallest units (wei/sat/sun/lamports), string-encoded BigInt", "example": "1500000000000000000" },
"formatted": { "type": "string", "description": "Human-readable decimal", "example": "1.5" },
"decimals": { "type": "integer", "description": "Decimals of the chain/token", "example": 18 },
"usdPrice": {
"type": "number",
"nullable": true,
"description": "Цена 1 целой единицы в USD по данным CoinGecko (cache 5 мин, KeyDB). `null` если symbol не в registry или upstream недоступен.",
"example": 3210.45
},
"usdValue": {
"type": "number",
"nullable": true,
"description": "Совокупная стоимость holding'а в USD = `Number(formatted) × usdPrice`, округлено до 8 знаков. `null` если `usdPrice === null` или результат не finite.",
"example": 4815.675
}
}
},
"PricesResponse": {
"type": "object",
"properties": {
"success": { "type": "boolean", "example": true },
"data": {
"type": "object",
"description": "Map symbol → { usd: price | null }. `null` если symbol whitelist'ed но upstream не вернул котировку.",
"additionalProperties": {
"type": "object",
"properties": {
"usd": { "type": "number", "nullable": true, "example": 67432.12 }
}
},
"example": {
"BTC": { "usd": 67432.12 },
"ETH": { "usd": 3210.45 },
"USDT": { "usd": 1.0 }
}
}
}
},
"BalanceResponse": {
"type": "object",
"properties": {
"success": { "type": "boolean", "example": true },
"data": {
"type": "object",
"properties": {
"chain": { "$ref": "#/components/schemas/Chain" },
"address": { "type": "string" },
"native": { "$ref": "#/components/schemas/FormattedAmount" },
"tokens": {
"type": "object",
"description": "Map symbol → FormattedAmount. Содержит все известные токены chain'а (ETH: USDT/USDC/DAI/WBTC/LINK/UNI, BSC: USDT/USDC/DOGE/WBNB/BUSD, TRX: USDT/USDC, SOL: 14 токенов)",
"additionalProperties": { "$ref": "#/components/schemas/FormattedAmount" }
}
}
}
}
},
"Transaction": {
"type": "object",
"properties": {
"txid": { "type": "string" },
"timestamp": { "type": "integer", "nullable": true, "description": "Unix seconds" },
"direction": { "type": "string", "enum": ["in", "out", "self"] },
"amount": { "type": "string", "nullable": true },
"token": { "type": "string", "nullable": true },
"from": { "type": "string", "nullable": true },
"to": { "type": "string", "nullable": true }
}
},
"TransactionsResponse": {
"type": "object",
"properties": {
"success": { "type": "boolean" },
"data": { "type": "array", "items": { "$ref": "#/components/schemas/Transaction" } }
}
},
"SendRequest": {
"type": "object",
"required": ["to", "amount"],
"properties": {
"to": { "type": "string", "description": "Recipient address" },
"amount": { "type": "string", "description": "Amount в smallest units (wei для EVM, lamports для SOL, sat для BTC, sun для TRX)" },
"token": { "type": "string", "nullable": true, "description": "USDT для TRC20/ERC20/BEP20. Без token = native." },
"feeTier": {
"type": "string",
"enum": ["slow", "normal", "fast"],
"nullable": true,
"description": "Default 'normal'. ETH/BSC: eth_feeHistory p25/p50/p75 priority. BTC: blockstream targets 144/6/1 блок. TRX/SOL: игнорится."
}
}
},
"FeeQuote": {
"type": "object",
"properties": {
"maxFeePerGas": { "type": "string", "description": "wei (decimal string)" },
"maxPriorityFeePerGas": { "type": "string", "description": "wei (decimal string)" },
"gweiTotal": { "type": "number" },
"gweiPriority": { "type": "number" }
}
},
"FeeTiers": {
"type": "object",
"properties": {
"chain": { "type": "string", "enum": ["ETH", "BSC"] },
"baseFeeGwei": { "type": "number", "description": "Из feeHistory.baseFeePerGas (на BSC ~0)" },
"slow": { "$ref": "#/components/schemas/FeeQuote" },
"normal": { "$ref": "#/components/schemas/FeeQuote" },
"fast": { "$ref": "#/components/schemas/FeeQuote" }
}
},
"SignRawEvmTxRequest": {
"type": "object",
"required": ["to", "data", "value", "chainId", "gas", "maxFeePerGas", "maxPriorityFeePerGas"],
"properties": {
"to": { "type": "string", "description": "0x-prefixed 40-hex (контракт или EOA)" },
"data": { "type": "string", "description": "Calldata 0x-hex (может быть пустым 0x для native send)" },
"value": { "type": "string", "description": "wei (decimal string)" },
"chainId": { "type": "integer", "description": "1 (ETH) или 56 (BSC) — должен совпадать с path :chain" },
"gas": { "type": "string", "description": "gasLimit в decimal" },
"maxFeePerGas": { "type": "string", "description": "wei" },
"maxPriorityFeePerGas": { "type": "string", "description": "wei" },
"feeTier": {
"type": "string",
"enum": ["slow", "normal", "fast"],
"nullable": true,
"description": "Если задан → server переопределит maxFeePerGas/maxPriorityFeePerGas актуальным из eth_feeHistory (полезно если quote от Relay устарел)."
}
}
}
}
},
"security": [
{ "cookieAuth": [] },
{ "bearerAuth": [] }
],
"paths": {
"/health": {
"get": {
"summary": "Liveness check",
"tags": ["System"],
"security": [],
"responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HealthResponse" } } } } }
}
},
"/wallets": {
"get": {
"summary": "Get all wallets of authenticated user",
"tags": ["Wallets"],
"responses": {
"200": { "description": "List of wallets", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WalletsResponse" } } } },
"401": { "description": "Not authenticated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
}
}
},
"/wallets/create": {
"post": {
"summary": "Создать custodial-кошелёк (server-side mnemonic)",
"description": "**Тело запроса не требуется.** Сервер генерит BIP39 mnemonic (12 слов), деривит адреса для 5 chains (BIP44: ETH m/44'/60'/0'/0/0, BTC m/84'/0'/0'/0/0, TRX m/44'/195'/0'/0/0, SOL m/44'/501'/0'/0', BSC = ETH path), шифрует mnemonic AES-256-GCM (master-key из HashiCorp Vault) и атомарно сохраняет. **Возвращает ТОЛЬКО адреса** — mnemonic клиенту не отдаётся. Чтобы потом увидеть seed — отдельный endpoint POST /wallets/mnemonic/reveal. Идемпотентность: 409 если у юзера уже есть кошелёк.",
"tags": ["Wallets"],
"responses": {
"201": { "description": "Wallet created (returns addresses only)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WalletsResponse" } } } },
"401": { "description": "Not authenticated" },
"409": { "description": "Wallet already exists", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
"503": { "description": "Crypto service not ready" }
}
}
},
"/wallets/mnemonic/reveal": {
"post": {
"summary": "Раскрыть mnemonic (settings-screen)",
"description": "Расшифровывает и возвращает 12-словную BIP39 мнемонику юзера. POST + CSRF + body-confirmation. Rate-limit 5/час per-user. Каждый запрос пишется в audit-log.",
"tags": ["Wallets"],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": ["confirm"],
"properties": {
"confirm": { "type": "string", "enum": ["I_UNDERSTAND_SEED_IS_SECRET"] }
}
}
}
}
},
"responses": {
"200": { "description": "Mnemonic revealed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MnemonicResponse" } } } },
"400": { "description": "Missing/invalid confirm token" },
"401": { "description": "Not authenticated" },
"404": { "description": "Wallet not created yet" },
"429": { "description": "Rate limit (5/hour) exceeded" },
"503": { "description": "Crypto service not ready" }
}
}
},
"/wallets/{chain}/balance": {
"get": {
"summary": "Balance for user wallet in chain (с USD-ценами)",
"description": "Возвращает количество и USD-стоимость для native монеты + всех известных токенов сети. Каждый `FormattedAmount` содержит `raw` (smallest units), `formatted` (human-readable), `decimals`, `usdPrice` (цена 1 единицы), `usdValue` (стоимость holding'а). Цены — CoinGecko с 5-минутным KeyDB-кэшем. Если упал price oracle — `usdPrice`/`usdValue` = `null`, но количества всё равно возвращаются.\n\n**Пример curl:**\n```\ncurl -H \"Authorization: Bearer $JWT\" https://api.example.com/api/wallets/ETH/balance\n```",
"tags": ["Wallet Ops"],
"parameters": [{ "name": "chain", "in": "path", "required": true, "schema": { "$ref": "#/components/schemas/Chain" } }],
"responses": {
"200": {
"description": "Balance + USD prices",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/BalanceResponse" },
"example": {
"success": true,
"data": {
"chain": "ETH",
"address": "0x742d35Cc6634C0532925a3b844Bc9e7595f4F45A",
"native": {
"raw": "1500000000000000000",
"formatted": "1.5",
"decimals": 18,
"usdPrice": 3210.45,
"usdValue": 4815.675
},
"tokens": {
"USDT": { "raw": "1000000", "formatted": "1", "decimals": 6, "usdPrice": 1.0, "usdValue": 1.0 },
"USDC": { "raw": "0", "formatted": "0", "decimals": 6, "usdPrice": 0.9999, "usdValue": 0 },
"DAI": { "raw": "0", "formatted": "0", "decimals": 18, "usdPrice": 0.9998, "usdValue": 0 },
"WBTC": { "raw": "0", "formatted": "0", "decimals": 8, "usdPrice": 67432.12, "usdValue": 0 },
"LINK": { "raw": "0", "formatted": "0", "decimals": 18, "usdPrice": 14.32, "usdValue": 0 },
"UNI": { "raw": "0", "formatted": "0", "decimals": 18, "usdPrice": 8.41, "usdValue": 0 }
}
}
}
}
}
},
"401": { "description": "Not authenticated" },
"404": { "description": "Wallet for this chain not found" },
"502": { "description": "Upstream RPC error" }
}
}
},
"/wallets/{chain}/transactions": {
"get": {
"summary": "Transaction history for user wallet in chain",
"tags": ["Wallet Ops"],
"parameters": [
{ "name": "chain", "in": "path", "required": true, "schema": { "$ref": "#/components/schemas/Chain" } },
{ "name": "limit", "in": "query", "schema": { "type": "integer", "default": 20, "minimum": 1, "maximum": 100 } }
],
"responses": {
"200": { "description": "List of transactions", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TransactionsResponse" } } } },
"404": { "description": "Wallet for this chain not found" }
}
}
},
"/wallets/{chain}/send": {
"post": {
"summary": "Custodial send: server signs + broadcasts",
"description": "Юзер на клиенте жмёт 'подтвердить' → клиент шлёт {to, amount, token?, feeTier?}. Сервер расшифровывает мнемонику, деривит chain privkey, подписывает, broadcast'ит. Возвращает txid. Защита: TRX MITM check, EVM gas cap 500 gwei, SOL confirmTransaction, BTC timeout + safety multiplier. На ETH/BSC gas теперь берётся из eth_feeHistory (slow/normal/fast).",
"tags": ["Wallet Ops"],
"parameters": [{ "name": "chain", "in": "path", "required": true, "schema": { "$ref": "#/components/schemas/Chain" } }],
"requestBody": {
"required": true,
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/SendRequest" } } }
},
"responses": {
"200": { "description": "Broadcast successful", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TxBroadcastResponse" } } } },
"400": { "description": "Invalid input (incl. invalid feeTier)" },
"404": { "description": "Wallet/mnemonic not found" },
"502": { "description": "Broadcast failed (insufficient balance / RPC error / unsupported)" },
"503": { "description": "Crypto service not ready" }
}
}
},
"/wallets/{chain}/gas-suggestions": {
"get": {
"summary": "EVM gas oracle (slow/normal/fast)",
"description": "Парсит fees через `eth_feeHistory` (последние 5 блоков, percentile p25/p50/p75 priority tips). Возвращает 3 тира с maxFeePerGas/maxPriorityFeePerGas в wei + gwei для display. Floor: ETH=0.5 gwei, BSC=0.05 gwei (защита от dust). Cap: 500 gwei. Только ETH и BSC.",
"tags": ["Wallet Ops"],
"parameters": [{ "name": "chain", "in": "path", "required": true, "schema": { "type": "string", "enum": ["ETH", "BSC"] } }],
"responses": {
"200": {
"description": "Fee tiers",
"content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean" }, "data": { "$ref": "#/components/schemas/FeeTiers" } } } } }
},
"400": { "description": "Non-EVM chain" },
"502": { "description": "Upstream RPC error" }
}
}
},
"/wallets/{chain}/sign-raw-evm-tx": {
"post": {
"summary": "Custodial sign + broadcast arbitrary EVM tx (Relay bridge)",
"description": "Подписывает unsigned EVM tx из Relay /execute response. Policy: `to` ДОЛЖЕН быть в Relay router allowlist; selector blacklist (approve/permit/setApprovalForAll). Для DEX swap'ов используй `/wallets/{chain}/swap` — там chained custodial без этих ограничений.",
"tags": ["Wallet Ops"],
"parameters": [{ "name": "chain", "in": "path", "required": true, "schema": { "type": "string", "enum": ["ETH", "BSC"] } }],
"requestBody": {
"required": true,
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/SignRawEvmTxRequest" } } }
},
"responses": {
"200": { "description": "Broadcast successful", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TxBroadcastResponse" } } } },
"400": { "description": "Policy violation: to not in allowlist OR forbidden selector OR cap exceeded" },
"404": { "description": "Wallet/mnemonic not found" },
"502": { "description": "Broadcast failed" },
"503": { "description": "Crypto service not ready" }
}
}
},
"/wallets/{chain}/swap": {
"post": {
"summary": "Custodial chained swap (BSC PancakeSwap / TRX SunSwap+FeeSwapRouter / SOL Jupiter)",
"description": "Полностью custodial swap в один HTTP-вызов. Никакого client-side signing.\n\n**BSC** — PancakeSwap V2 approve+swap chained. Пары: BNB/USDT/USDC/DOGE/WBNB/BUSD.\n\n**TRX** — SunSwap V2 через FeeSwapRouter (0.7% fee). Только пары TRX↔USDT. Server делает approve(infinite, FeeSwapRouter) (если allowance < amount) + wait inclusion + swap. 4-layer MITM defense (txID/expiration/type/selector verify) — компрометированный TronGrid не сможет подсунуть `transfer` вместо `swap`.\n\n**SOL** — Jupiter aggregator. Любые mints из registry (USDT/USDC/PUMP/JUP/WIF/POPCAT/TRUMP/PYTH/JTO/W/BONK/ORCA/PENGU/RAY).\n\n**Slippage protection** — server computes `amountOutMin = quote × (10000-slippageBps)/10000` от actual quote (default 50 bps = 0.5%). Клиент НЕ задаёт amountOutMin напрямую (защита от MEV-sandwich). Optional `Idempotency-Key` header для anti double-spend.",
"tags": ["Wallet Ops"],
"parameters": [{ "name": "chain", "in": "path", "required": true, "schema": { "type": "string", "enum": ["BSC", "TRX", "SOL"] } }],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"oneOf": [
{
"type": "object",
"title": "BSC/TRX swap (symbols)",
"required": ["from", "to", "amount"],
"properties": {
"from": { "type": "string", "description": "BSC: BNB|USDT|USDC|DOGE|WBNB|BUSD; TRX: TRX|USDT (только эта пара поддерживается на TRON)" },
"to": { "type": "string" },
"amount": { "type": "string", "description": "Smallest units (wei для 18-dec EVM, sun для TRX 6-dec). Max для TRX = 9_007_199_254_740_991 (~9B TRX)." },
"slippageBps": { "type": "integer", "minimum": 1, "maximum": 1000, "description": "0.01%-10%. Default 50 (0.5%). Server вычислит amountOutMin сам — клиент НЕ задаёт его напрямую." },
"feeTier": { "type": "string", "enum": ["slow", "normal", "fast"], "description": "Только BSC (ETH/BSC). На TRX игнорится." }
}
},
{
"type": "object",
"title": "SOL swap (mints)",
"required": ["inputMint", "outputMint", "amount"],
"properties": {
"inputMint": { "type": "string", "description": "SPL mint address (base58)" },
"outputMint": { "type": "string" },
"amount": { "type": "string", "description": "Smallest units (lamports = 9-dec для SOL native)" },
"slippageBps": { "type": "integer", "minimum": 1, "maximum": 1000 }
}
}
]
}
}
}
},
"responses": {
"200": {
"description": "BSC: { approveTxid?, swapTxid }. TRX/SOL: { txid | signature }",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"success": { "type": "boolean" },
"data": {
"type": "object",
"properties": {
"chain": { "type": "string" },
"approveTxid": { "type": "string", "nullable": true, "description": "BSC only, если token-to-X swap требовал approve" },
"swapTxid": { "type": "string", "description": "BSC swap txid" },
"txid": { "type": "string", "description": "TRX txid" },
"signature": { "type": "string", "description": "SOL tx signature" }
}
}
}
}
}
}
},
"400": { "description": "Invalid pair / slippage / amount / unsupported chain" },
"404": { "description": "Wallet not found" },
"409": { "description": "Idempotency-Key reuse with different body, or operation in-flight" },
"502": { "description": "Swap failed (no liquidity / network error / contract revert)" },
"503": { "description": "Crypto service not ready" }
}
}
},
"/wallets/SOL/sign-and-broadcast-tx": {
"post": {
"summary": "Custodial sign + broadcast arbitrary Solana VersionedTransaction",
"description": "Подписывает unsigned serialized Solana tx (от Relay /execute SOL-side, или любого aggregator'а). Server verify feePayer === user's pubkey, partial-sign keypair'ом, broadcast, confirm.",
"tags": ["Wallet Ops"],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": ["transaction"],
"properties": {
"transaction": { "type": "string", "description": "Base64-encoded VersionedTransaction (max ~1500 bytes raw)" }
}
}
}
}
},
"responses": {
"200": {
"description": "Signed and broadcast",
"content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean" }, "data": { "type": "object", "properties": { "signature": { "type": "string" }, "chain": { "type": "string" } } } } } } }
},
"400": { "description": "Invalid base64 / tx size / feePayer mismatch" },
"404": { "description": "SOL wallet/mnemonic not found" },
"502": { "description": "Sign or broadcast failed" }
}
}
},
"/btc/utxos/{address}": {
"get": {
"summary": "Confirmed UTXOs for Bitcoin address",
"tags": ["BTC"],
"parameters": [{ "name": "address", "in": "path", "required": true, "schema": { "type": "string" } }],
"responses": { "200": { "description": "UTXOs" }, "401": { "description": "Not authenticated" } }
}
},
"/btc/fee-estimates": {
"get": {
"summary": "Bitcoin fee estimates (sat/vB)",
"tags": ["BTC"],
"responses": { "200": { "description": "fast/normal/slow" }, "401": { "description": "Not authenticated" } }
}
},
"/btc/broadcast": {
"post": {
"summary": "Broadcast raw signed Bitcoin tx",
"tags": ["BTC"],
"requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["hex"], "properties": { "hex": { "type": "string" } } } } } },
"responses": { "200": { "description": "txid" }, "400": { "description": "Invalid hex" } }
}
},
"/tron/account/{address}": {
"get": {
"summary": "TRON account info + USDT (TRC20) balance",
"tags": ["TRON"],
"parameters": [{ "name": "address", "in": "path", "required": true, "schema": { "type": "string" } }],
"responses": { "200": { "description": "Account data" } }
}
},
"/tron/createtransaction": {
"post": {
"summary": "Build unsigned TRX transfer",
"tags": ["TRON"],
"requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["owner_address", "to_address", "amount"], "properties": { "owner_address": { "type": "string" }, "to_address": { "type": "string" }, "amount": { "type": "integer" } } } } } },
"responses": { "200": { "description": "Unsigned tx" } }
}
},
"/tron/triggersmartcontract": {
"post": {
"summary": "Build unsigned TRC20 contract call",
"tags": ["TRON"],
"requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object" } } } },
"responses": { "200": { "description": "Unsigned tx" } }
}
},
"/tron/broadcasttransaction": {
"post": {
"summary": "Broadcast signed TRON tx",
"tags": ["TRON"],
"requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object" } } } },
"responses": { "200": { "description": "Result" } }
}
},
"/sol/swap/quote": {
"get": {
"summary": "Jupiter swap quote (Solana)",
"tags": ["Solana"],
"parameters": [
{ "name": "inputMint", "in": "query", "required": true, "schema": { "type": "string" } },
{ "name": "outputMint", "in": "query", "required": true, "schema": { "type": "string" } },
{ "name": "amount", "in": "query", "required": true, "schema": { "type": "string" } },
{ "name": "slippageBps", "in": "query", "required": true, "schema": { "type": "integer" } }
],
"responses": { "200": { "description": "Quote" } }
}
},
"/sol/swap/build": {
"post": {
"summary": "Jupiter swap build",
"tags": ["Solana"],
"requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["quoteResponse", "userPublicKey"], "properties": { "quoteResponse": { "type": "object" }, "userPublicKey": { "type": "string" } } } } } },
"responses": { "200": { "description": "Swap tx" } }
}
},
"/tron/swap/quote": {
"get": {
"summary": "TRON swap quote (TRX <-> USDT)",
"tags": ["TRON Swap"],
"parameters": [
{ "name": "from", "in": "query", "required": true, "schema": { "type": "string", "enum": ["TRX", "USDT"] } },
{ "name": "to", "in": "query", "required": true, "schema": { "type": "string", "enum": ["TRX", "USDT"] } },
{ "name": "amount", "in": "query", "required": true, "schema": { "type": "string" } }
],
"responses": { "200": { "description": "Quote" } }
}
},
"/tron/swap/build": {
"post": {
"summary": "Build TRON swap transactions",
"tags": ["TRON Swap"],
"requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["from", "to", "amount", "amountOutMin", "userAddress"], "properties": { "from": { "type": "string" }, "to": { "type": "string" }, "amount": { "type": "string" }, "amountOutMin": { "type": "string" }, "userAddress": { "type": "string" } } } } } },
"responses": { "200": { "description": "Unsigned txs" } }
}
},
"/tron/swap/broadcast": {
"post": {
"summary": "Broadcast signed TRON swap",
"tags": ["TRON Swap"],
"requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["signedTransaction"], "properties": { "signedTransaction": { "type": "object" } } } } } },
"responses": { "200": { "description": "Result" } }
}
},
"/bsc/swap/quote": {
"get": {
"summary": "BSC swap quote (PancakeSwap V2)",
"tags": ["BSC"],
"parameters": [
{ "name": "from", "in": "query", "required": true, "schema": { "type": "string", "enum": ["BNB", "USDT", "DOGE"] } },
{ "name": "to", "in": "query", "required": true, "schema": { "type": "string", "enum": ["BNB", "USDT", "DOGE"] } },
{ "name": "amount", "in": "query", "required": true, "schema": { "type": "string" } }
],
"responses": { "200": { "description": "Quote" } }
}
},
"/bsc/swap/build": {
"post": {
"summary": "Build BSC swap transactions",
"tags": ["BSC"],
"requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["from", "to", "amount", "amountOutMin", "userAddress"], "properties": { "from": { "type": "string" }, "to": { "type": "string" }, "amount": { "type": "string" }, "amountOutMin": { "type": "string" }, "userAddress": { "type": "string" } } } } } },
"responses": { "200": { "description": "Unsigned txs" } }
}
},
"/relay/quote": {
"post": {
"summary": "Relay bridge quote (POST с JSON body)",
"description": "Прокси к https://api.relay.link/quote. Параметры в body: user, recipient, originChainId, destinationChainId, originCurrency, destinationCurrency, amount (smallest units), tradeType (EXACT_INPUT|EXACT_OUTPUT).",
"tags": ["Relay"],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": ["user", "originChainId", "destinationChainId", "originCurrency", "destinationCurrency", "amount", "tradeType"],
"properties": {
"user": { "type": "string", "description": "Sender address (0x.. / T.. / SOL pubkey)" },
"recipient": { "type": "string", "description": "Обычно тот же что user" },
"originChainId": { "type": "integer", "description": "1=ETH, 56=BSC, 728126428=TRON, 792703809=SOL" },
"destinationChainId": { "type": "integer" },
"originCurrency": { "type": "string", "description": "Token address (EVM: 0x.., SOL: mint, TRX: contract или 'TRX')" },
"destinationCurrency": { "type": "string" },
"amount": { "type": "string", "description": "smallest units" },
"tradeType": { "type": "string", "enum": ["EXACT_INPUT", "EXACT_OUTPUT"] }
}
}
}
}
},
"responses": {
"200": { "description": "Quote с steps[], fees, details, breakdown" },
"502": { "description": "Relay upstream error (приложен upstream JSON для деталей)" }
}
}
},
"/relay/intents/status/v3": {
"get": {
"summary": "Relay intent status",
"tags": ["Relay"],
"parameters": [{ "name": "requestId", "in": "query", "required": true, "schema": { "type": "string", "description": "Из quote/execute response" } }],
"responses": { "200": { "description": "Status" }, "502": { "description": "Relay upstream error" } }
}
},
"/relay/execute/{action}": {
"post": {
"summary": "Relay execute (swap | bridge)",
"description": "Принимает ТОТ ЖЕ payload что и /quote и возвращает unsigned tx в steps[].items[].data. Эту tx надо потом подписать (для ETH/BSC — через /wallets/{chain}/sign-raw-evm-tx) и broadcast'нуть. Action whitelist: swap, bridge.",
"tags": ["Relay"],
"parameters": [{ "name": "action", "in": "path", "required": true, "schema": { "type": "string", "enum": ["swap", "bridge"] } }],
"requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "description": "Same as /relay/quote body" } } } },
"responses": {
"200": { "description": "steps[] with unsigned tx + fees + details" },
"502": { "description": "Relay upstream error" }
}
}
},
"/prices": {
"get": {
"summary": "USD-цены для списка символов",
"description": "Возвращает котировки USD для указанных символов (max 50). Символы должны быть из реестра поддерживаемых токенов (см. tag описание сетей в /wallets/{chain}/balance). Источник — CoinGecko free API, кэшируется в KeyDB 5 минут.\n\n**Resolution:**\n- Native символ совпадающий с chain code (BTC/ETH/BSC/TRX/SOL) → используется native CoinGecko id.\n- Иначе: ищется в реестре сети из `chain` query param.\n- Если `chain` не задан → fallback порядок ETH → BSC → SOL → TRX → BTC. Первый matched chain wins.\n\n**Безопасность:** symbols whitelisted, никакого user-input в URL CoinGecko (защита от SSRF). Max 50 символов на запрос. Auth обязательна (JWT Bearer или cookie).\n\n**Пример curl:**\n```\ncurl -H \"Authorization: Bearer $JWT\" \"https://api.example.com/api/prices?symbols=BTC,ETH,USDT,SOL,BONK\"\n```",
"tags": ["Prices"],
"parameters": [
{
"name": "symbols",
"in": "query",
"required": true,
"description": "Comma-separated список символов (макс 50). Каждый — `[A-Z0-9]{1,16}`. Только символы из registry: BTC, ETH, BSC, TRX, SOL (native) + USDT, USDC, DAI, WBTC, LINK, UNI, DOGE, WBNB, BUSD, PUMP, JUP, WIF, POPCAT, TRUMP, PYTH, JTO, W, BONK, ORCA, PENGU, RAY.",
"schema": { "type": "string", "example": "BTC,ETH,USDT" }
},
{
"name": "chain",
"in": "query",
"required": false,
"description": "Опционально: для disambiguation если symbol присутствует в нескольких сетях (USDT/USDC). Если не задан — fallback порядок: ETH → BSC → SOL → TRX → BTC.",
"schema": { "$ref": "#/components/schemas/Chain" }
}
],
"responses": {
"200": {
"description": "USD prices",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/PricesResponse" },
"example": {
"success": true,
"data": {
"BTC": { "usd": 67432.12 },
"ETH": { "usd": 3210.45 },
"USDT": { "usd": 1.0 },
"SOL": { "usd": 142.88 },
"BONK": { "usd": 0.00002145 }
}
}
}
}
},
"400": {
"description": "Validation error: пустой/слишком большой/невалидный список, неизвестный chain или unknown symbol",
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
},
"401": { "description": "Not authenticated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
"429": { "description": "Rate limit exceeded" },
"502": {
"description": "Upstream price oracle error (CoinGecko)",
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
}
}
}
}
}
}