{ "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), хранит её и сам подписывает транзакции. Все операции выполняются для фиксированного user_id на сервере; JWT/CSRF не используются." }, "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": [], "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": "**Без JWT/CSRF.** Кошелёк всегда создаётся для фиксированного user_id на сервере. **Тело запроса не требуется.** Сервер генерит 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"], "security": [], "responses": { "201": { "description": "Wallet created (returns addresses only)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WalletsResponse" } } } }, "429": { "description": "Rate limit exceeded" }, "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 мнемонику для фиксированного user_id на сервере. POST + body-confirmation. Rate-limit 5/час. Каждый запрос пишется в 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 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 символов на запрос.\n\n**Пример curl:**\n```\ncurl \"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" } } } } } } } } }