revert: non-custodial — client supplies addresses+paths to POST /wallets/create

This commit is contained in:
ZOMBIIIIIII
2026-05-11 19:51:10 +03:00
parent 8d91dbeb14
commit c8bc40af97
20 changed files with 122 additions and 1475 deletions

View File

@@ -2,8 +2,8 @@
"openapi": "3.0.0",
"info": {
"title": "CryptoWallet API",
"version": "3.0.0",
"description": "Multi-chain crypto wallet API. Auth via JWT (cookie/Bearer), issued by external auth-service (BITOK). CUSTODIAL: server генерит мнемонику, хранит её AES-GCM-зашифрованной (master-key из Vault) и сам подписывает транзакции."
"version": "4.0.0",
"description": "Multi-chain crypto wallet API (non-custodial). Клиент сам деривит mnemonic и шлёт публичные адреса; сервер хранит только адреса и строит unsigned tx для отправки. Auth via JWT (cookie/Bearer), issued by external auth-service (BITOK)."
},
"servers": [
{ "url": "/api", "description": "API root" }
@@ -52,31 +52,25 @@
"properties": {
"chain": { "$ref": "#/components/schemas/Chain" },
"address": { "type": "string" },
"derivationPath": { "type": "string" }
"derivationPath": { "type": "string", "description": "BIP32 path, например m/44'/60'/0'/0/0" }
}
},
"MnemonicResponse": {
"WalletInput": {
"type": "object",
"required": ["chain", "address", "derivationPath"],
"properties": {
"success": { "type": "boolean", "example": true },
"data": {
"type": "object",
"properties": {
"mnemonic": { "type": "string", "description": "BIP39 mnemonic (12 words)" }
}
}
"chain": { "$ref": "#/components/schemas/Chain" },
"address": { "type": "string", "maxLength": 64, "description": "Публичный адрес (chain-specific checksum-валидируется)" },
"derivationPath": { "type": "string", "maxLength": 64, "description": "BIP32 m/.. (например m/44'/60'/0'/0/0)" }
}
},
"TxBroadcastResponse": {
"CreateWalletsRequest": {
"type": "object",
"required": ["wallets"],
"properties": {
"success": { "type": "boolean", "example": true },
"data": {
"type": "object",
"properties": {
"txid": { "type": "string", "description": "Идентификатор отправленной транзакции" },
"chain": { "$ref": "#/components/schemas/Chain" }
}
"wallets": {
"type": "array", "minItems": 1, "maxItems": 20,
"items": { "$ref": "#/components/schemas/WalletInput" }
}
}
},
@@ -140,7 +134,7 @@
"success": { "type": "boolean" },
"data": {
"type": "object",
"description": "Unsigned tx — формат зависит от chain (kind: btc | tron | evm | solana). Клиент подписывает приватом и broadcast'ит через соответствующий /api/{btc,tron}/broadcast endpoint"
"description": "Unsigned tx — формат зависит от chain (kind: btc | tron | evm | solana). Клиент подписывает приватом и broadcast'ит через соответствующий /api/{btc,tron}/broadcast endpoint или RPC своей цепи."
}
}
}
@@ -173,44 +167,17 @@
"/wallets/create": {
"post": {
"summary": "Создать custodial-кошелёк (mnemonic генерится на сервере)",
"description": "Сервер генерит BIP39 mnemonic (12 слов), деривит адреса для 5 chains, шифрует mnemonic AES-GCM (master-key из Vault) и сохраняет. **Возвращает ТОЛЬКО адреса** — mnemonic клиенту НЕ отдаётся. Чтобы потом увидеть seed — отдельный endpoint GET /wallets/mnemonic. Идемпотентность: 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 — защита от случайного XHR / image-tag CSRF / стороннего origin. Rate-limit 5/час. Каждый запрос пишется в audit-log.",
"summary": "Upsert wallets для авторизованного юзера",
"description": "Клиент сам генерит mnemonic и деривит публичные адреса (BIP44 для ETH/BSC/BTC/TRX/SOL). Тело — массив `{chain, address, derivationPath}`. На конфликт (user_id, chain) сервер обновляет address+derivationPath. Mnemonic клиенту не нужно слать — сервер её не хранит.",
"tags": ["Wallets"],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": ["confirm"],
"properties": {
"confirm": { "type": "string", "enum": ["I_UNDERSTAND_SEED_IS_SECRET"] }
}
}
}
}
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateWalletsRequest" } } }
},
"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" }
"201": { "description": "Created/updated (вернёт сохранённые адреса)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WalletsResponse" } } } },
"400": { "description": "Invalid input (chain/address/derivationPath)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
"401": { "description": "Not authenticated" }
}
}
},
@@ -245,8 +212,8 @@
"/wallets/{chain}/send": {
"post": {
"summary": "Custodial send: server signs + broadcasts",
"description": "Сервер расшифровывает мнемонику → деривит chain-privkey → подписывает → broadcast'ит через RPC. Возвращает txid.",
"summary": "Build unsigned send transaction (non-custodial)",
"description": "Возвращает unsigned tx. Клиент подписывает приватным ключом и broadcast'ит через /api/{btc,tron}/broadcast или RPC своей цепи.",
"tags": ["Wallet Ops"],
"parameters": [{ "name": "chain", "in": "path", "required": true, "schema": { "$ref": "#/components/schemas/Chain" } }],
"requestBody": {
@@ -254,16 +221,14 @@
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/SendRequest" } } }
},
"responses": {
"200": { "description": "Broadcast successful", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TxBroadcastResponse" } } } },
"200": { "description": "Unsigned tx", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UnsignedTxResponse" } } } },
"400": { "description": "Invalid input" },
"404": { "description": "Wallet/mnemonic not found" },
"502": { "description": "Broadcast failed (upstream RPC error / insufficient balance / unsupported token)" },
"503": { "description": "Crypto service not ready" }
"404": { "description": "Wallet not found" },
"502": { "description": "Upstream RPC error" }
}
}
},
"/btc/utxos/{address}": {
"get": {
"summary": "Confirmed UTXOs for Bitcoin address",