DChain single-node blockchain + React Native messenger client. Core: - PBFT consensus with multi-sig validator admission + equivocation slashing - BadgerDB + schema migration scaffold (CurrentSchemaVersion=0) - libp2p gossipsub (tx/v1, blocks/v1, relay/v1, version/v1) - Native Go contracts (username_registry) alongside WASM (wazero) - WebSocket gateway with topic-based fanout + Ed25519-nonce auth - Relay mailbox with NaCl envelope encryption (X25519 + Ed25519) - Prometheus /metrics, per-IP rate limit, body-size cap Deployment: - Single-node compose (deploy/single/) with Caddy TLS + optional Prometheus - 3-node dev compose (docker-compose.yml) with mocked internet topology - 3-validator prod compose (deploy/prod/) for federation - Auto-update from Gitea via /api/update-check + systemd timer - Build-time version injection (ldflags → node --version) - UI / Swagger toggle flags (DCHAIN_DISABLE_UI, DCHAIN_DISABLE_SWAGGER) Client (client-app/): - Expo / React Native / NativeWind - E2E NaCl encryption, typing indicator, contact requests - Auto-discovery of canonical contracts, chain_id aware, WS reconnect on node switch Documentation: - README.md, CHANGELOG.md, CONTEXT.md - deploy/single/README.md with 6 operator scenarios - deploy/UPDATE_STRATEGY.md with 4-layer forward-compat design - docs/contracts/*.md per contract
728 lines
29 KiB
JSON
728 lines
29 KiB
JSON
{
|
|
"openapi": "3.0.3",
|
|
"info": {
|
|
"title": "DChain Node API",
|
|
"version": "0.4.0",
|
|
"description": "API for reading blockchain state, submitting transactions, and using the relay mailbox. All token amounts are in micro-tokens (µT). 1 T = 1 000 000 µT."
|
|
},
|
|
"servers": [{ "url": "/" }],
|
|
"tags": [
|
|
{ "name": "chain", "description": "V2 chain-compatible endpoints" },
|
|
{ "name": "explorer", "description": "Block explorer read API" },
|
|
{ "name": "relay", "description": "Encrypted relay mailbox" }
|
|
],
|
|
"paths": {
|
|
"/api/netstats": {
|
|
"get": {
|
|
"tags": ["explorer"],
|
|
"summary": "Network statistics",
|
|
"responses": {
|
|
"200": {
|
|
"description": "Aggregate chain stats",
|
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/NetStats" } } }
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/blocks": {
|
|
"get": {
|
|
"tags": ["explorer"],
|
|
"summary": "Recent blocks",
|
|
"parameters": [
|
|
{ "name": "limit", "in": "query", "schema": { "type": "integer", "default": 20, "maximum": 100 } }
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Array of recent block summaries",
|
|
"content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/BlockSummary" } } } }
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/block/{index}": {
|
|
"get": {
|
|
"tags": ["explorer"],
|
|
"summary": "Block by index",
|
|
"parameters": [
|
|
{ "name": "index", "in": "path", "required": true, "schema": { "type": "integer", "format": "uint64" } }
|
|
],
|
|
"responses": {
|
|
"200": { "description": "Block detail", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BlockDetail" } } } },
|
|
"404": { "$ref": "#/components/responses/Error" }
|
|
}
|
|
}
|
|
},
|
|
"/api/txs/recent": {
|
|
"get": {
|
|
"tags": ["explorer"],
|
|
"summary": "Recent transactions",
|
|
"parameters": [
|
|
{ "name": "limit", "in": "query", "schema": { "type": "integer", "default": 20, "maximum": 100 } }
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Recent transactions",
|
|
"content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/TxListEntry" } } } }
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/tx/{txid}": {
|
|
"get": {
|
|
"tags": ["explorer"],
|
|
"summary": "Transaction by ID",
|
|
"parameters": [
|
|
{ "name": "txid", "in": "path", "required": true, "schema": { "type": "string" } }
|
|
],
|
|
"responses": {
|
|
"200": { "description": "Transaction detail", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TxDetail" } } } },
|
|
"404": { "$ref": "#/components/responses/Error" }
|
|
}
|
|
}
|
|
},
|
|
"/api/tx": {
|
|
"post": {
|
|
"tags": ["explorer"],
|
|
"summary": "Submit a signed transaction",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/Transaction" } } }
|
|
},
|
|
"responses": {
|
|
"200": { "description": "Accepted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SubmitTransactionResponse" } } } },
|
|
"400": { "$ref": "#/components/responses/Error" },
|
|
"500": { "$ref": "#/components/responses/Error" }
|
|
}
|
|
}
|
|
},
|
|
"/api/address/{addr}": {
|
|
"get": {
|
|
"tags": ["explorer"],
|
|
"summary": "Address balance and transactions",
|
|
"description": "Accepts a DC... wallet address or hex Ed25519 public key.",
|
|
"parameters": [
|
|
{ "name": "addr", "in": "path", "required": true, "schema": { "type": "string" }, "description": "DC... address or hex pub key" },
|
|
{ "name": "limit", "in": "query", "schema": { "type": "integer", "default": 50 } },
|
|
{ "name": "offset", "in": "query", "schema": { "type": "integer", "default": 0 } }
|
|
],
|
|
"responses": {
|
|
"200": { "description": "Address detail", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AddressDetail" } } } },
|
|
"404": { "$ref": "#/components/responses/Error" }
|
|
}
|
|
}
|
|
},
|
|
"/api/node/{pubkey}": {
|
|
"get": {
|
|
"tags": ["explorer"],
|
|
"summary": "Node reputation and stats",
|
|
"parameters": [
|
|
{ "name": "pubkey", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Hex Ed25519 pub key or DC... address" },
|
|
{ "name": "window", "in": "query", "schema": { "type": "integer", "default": 200 }, "description": "Number of recent blocks to scan for rewards" }
|
|
],
|
|
"responses": {
|
|
"200": { "description": "Node stats", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NodeStats" } } } },
|
|
"404": { "$ref": "#/components/responses/Error" }
|
|
}
|
|
}
|
|
},
|
|
"/api/relays": {
|
|
"get": {
|
|
"tags": ["explorer"],
|
|
"summary": "Registered relay nodes",
|
|
"description": "Returns all nodes that have submitted an REGISTER_RELAY transaction.",
|
|
"responses": {
|
|
"200": {
|
|
"description": "List of relay nodes",
|
|
"content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/RegisteredRelayInfo" } } } }
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/validators": {
|
|
"get": {
|
|
"tags": ["explorer"],
|
|
"summary": "Active validator set",
|
|
"description": "Returns the current on-chain validator set. The set changes via ADD_VALIDATOR / REMOVE_VALIDATOR transactions.",
|
|
"responses": {
|
|
"200": {
|
|
"description": "Active validators",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"count": { "type": "integer" },
|
|
"validators": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"properties": {
|
|
"pub_key": { "type": "string" },
|
|
"address": { "type": "string" }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/identity/{pubkey}": {
|
|
"get": {
|
|
"tags": ["explorer"],
|
|
"summary": "Identity info (Ed25519 + X25519 keys)",
|
|
"description": "Returns identity info for a pub key or DC address. x25519_pub is populated only if the identity has submitted a REGISTER_KEY transaction with an X25519 key.",
|
|
"parameters": [
|
|
{ "name": "pubkey", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Hex Ed25519 pub key or DC... address" }
|
|
],
|
|
"responses": {
|
|
"200": { "description": "Identity info", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IdentityInfo" } } } },
|
|
"404": { "$ref": "#/components/responses/Error" }
|
|
}
|
|
}
|
|
},
|
|
"/relay/send": {
|
|
"post": {
|
|
"tags": ["relay"],
|
|
"summary": "Send an encrypted message via the relay node",
|
|
"description": "The relay node seals the message using its own X25519 keypair (sender = relay node) and broadcasts it on gossipsub. No on-chain fee is attached.",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"required": ["recipient_pub", "msg_b64"],
|
|
"properties": {
|
|
"recipient_pub": { "type": "string", "description": "Hex X25519 public key of the recipient" },
|
|
"msg_b64": { "type": "string", "description": "Base64-encoded plaintext message" }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "Message sent",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"id": { "type": "string", "description": "Envelope ID" },
|
|
"recipient_pub": { "type": "string" },
|
|
"status": { "type": "string", "example": "sent" }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": { "$ref": "#/components/responses/Error" },
|
|
"503": { "$ref": "#/components/responses/Error" }
|
|
}
|
|
}
|
|
},
|
|
"/relay/broadcast": {
|
|
"post": {
|
|
"tags": ["relay"],
|
|
"summary": "Broadcast a pre-sealed envelope",
|
|
"description": "Light clients that seal their own NaCl-box envelopes use this to publish without a direct libp2p connection. The node stores it in the mailbox and gossips it.",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"required": ["envelope"],
|
|
"properties": {
|
|
"envelope": { "$ref": "#/components/schemas/Envelope" }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"responses": {
|
|
"200": {
|
|
"description": "Broadcast accepted",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"id": { "type": "string" },
|
|
"status": { "type": "string", "example": "broadcast" }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": { "$ref": "#/components/responses/Error" },
|
|
"503": { "$ref": "#/components/responses/Error" }
|
|
}
|
|
}
|
|
},
|
|
"/relay/inbox": {
|
|
"get": {
|
|
"tags": ["relay"],
|
|
"summary": "List inbox envelopes",
|
|
"description": "Returns envelopes stored for the given X25519 public key. Envelopes remain encrypted — the relay cannot read them.",
|
|
"parameters": [
|
|
{ "name": "pub", "in": "query", "required": true, "schema": { "type": "string" }, "description": "Hex X25519 public key of the recipient" },
|
|
{ "name": "since", "in": "query", "schema": { "type": "integer", "format": "int64" }, "description": "Unix timestamp — return only messages after this time" },
|
|
{ "name": "limit", "in": "query", "schema": { "type": "integer", "default": 50 } }
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Inbox contents",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"pub": { "type": "string" },
|
|
"count": { "type": "integer" },
|
|
"has_more": { "type": "boolean" },
|
|
"items": { "type": "array", "items": { "$ref": "#/components/schemas/InboxItem" } }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": { "$ref": "#/components/responses/Error" }
|
|
}
|
|
}
|
|
},
|
|
"/relay/inbox/count": {
|
|
"get": {
|
|
"tags": ["relay"],
|
|
"summary": "Count inbox envelopes",
|
|
"parameters": [
|
|
{ "name": "pub", "in": "query", "required": true, "schema": { "type": "string" } }
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Envelope count",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"pub": { "type": "string" },
|
|
"count": { "type": "integer" }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/relay/inbox/{envID}": {
|
|
"delete": {
|
|
"tags": ["relay"],
|
|
"summary": "Delete an envelope from the inbox",
|
|
"parameters": [
|
|
{ "name": "envID", "in": "path", "required": true, "schema": { "type": "string" } },
|
|
{ "name": "pub", "in": "query", "required": true, "schema": { "type": "string" }, "description": "X25519 pub key of the inbox owner" }
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Deleted",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"id": { "type": "string" },
|
|
"status": { "type": "string", "example": "deleted" }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": { "$ref": "#/components/responses/Error" }
|
|
}
|
|
}
|
|
},
|
|
"/relay/contacts": {
|
|
"get": {
|
|
"tags": ["relay"],
|
|
"summary": "Incoming contact requests",
|
|
"description": "Returns all CONTACT_REQUEST records for the given Ed25519 pub key, including pending, accepted, and blocked.",
|
|
"parameters": [
|
|
{ "name": "pub", "in": "query", "required": true, "schema": { "type": "string" }, "description": "Hex Ed25519 pub key" }
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Contact list",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"pub": { "type": "string" },
|
|
"count": { "type": "integer" },
|
|
"contacts": { "type": "array", "items": { "$ref": "#/components/schemas/ContactInfo" } }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": { "$ref": "#/components/responses/Error" }
|
|
}
|
|
}
|
|
},
|
|
"/v2/chain/accounts/{account_id}/transactions": {
|
|
"get": {
|
|
"tags": ["chain"],
|
|
"summary": "Account transactions",
|
|
"parameters": [
|
|
{ "name": "account_id", "in": "path", "required": true, "schema": { "type": "string" } },
|
|
{ "name": "limit", "in": "query", "schema": { "type": "integer", "default": 100, "minimum": 1, "maximum": 1000 } },
|
|
{ "name": "order", "in": "query", "schema": { "type": "string", "enum": ["desc", "asc"], "default": "desc" } },
|
|
{ "name": "after_block", "in": "query", "schema": { "type": "integer", "format": "uint64" } },
|
|
{ "name": "before_block", "in": "query", "schema": { "type": "integer", "format": "uint64" } }
|
|
],
|
|
"responses": {
|
|
"200": { "description": "Transactions", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChainTransactionsResponse" } } } },
|
|
"400": { "$ref": "#/components/responses/Error" },
|
|
"404": { "$ref": "#/components/responses/Error" }
|
|
}
|
|
}
|
|
},
|
|
"/v2/chain/transactions/{tx_id}": {
|
|
"get": {
|
|
"tags": ["chain"],
|
|
"summary": "Transaction by ID",
|
|
"parameters": [
|
|
{ "name": "tx_id", "in": "path", "required": true, "schema": { "type": "string" } }
|
|
],
|
|
"responses": {
|
|
"200": { "description": "Transaction detail", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChainTransactionDetailResponse" } } } },
|
|
"404": { "$ref": "#/components/responses/Error" }
|
|
}
|
|
}
|
|
},
|
|
"/v2/chain/transactions": {
|
|
"post": {
|
|
"tags": ["chain"],
|
|
"summary": "Submit transaction",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/SubmitTransactionRequest" } } }
|
|
},
|
|
"responses": {
|
|
"200": { "description": "Accepted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SubmitTransactionResponse" } } } },
|
|
"400": { "$ref": "#/components/responses/Error" },
|
|
"500": { "$ref": "#/components/responses/Error" }
|
|
}
|
|
}
|
|
},
|
|
"/v2/chain/transactions/draft": {
|
|
"post": {
|
|
"tags": ["chain"],
|
|
"summary": "Build unsigned TRANSFER draft",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/DraftTransactionRequest" } } }
|
|
},
|
|
"responses": {
|
|
"200": { "description": "Draft", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DraftTransactionResponse" } } } },
|
|
"400": { "$ref": "#/components/responses/Error" }
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"components": {
|
|
"responses": {
|
|
"Error": {
|
|
"description": "Error response",
|
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
}
|
|
},
|
|
"schemas": {
|
|
"ErrorResponse": {
|
|
"type": "object",
|
|
"properties": { "error": { "type": "string" } },
|
|
"required": ["error"]
|
|
},
|
|
"NetStats": {
|
|
"type": "object",
|
|
"properties": {
|
|
"height": { "type": "integer" },
|
|
"total_txs": { "type": "integer" },
|
|
"total_transfers": { "type": "integer" },
|
|
"total_relay_proofs": { "type": "integer" },
|
|
"avg_block_time_ms": { "type": "number" },
|
|
"tps": { "type": "number" },
|
|
"total_supply_ut": { "type": "integer", "format": "uint64" }
|
|
}
|
|
},
|
|
"BlockSummary": {
|
|
"type": "object",
|
|
"properties": {
|
|
"index": { "type": "integer", "format": "uint64" },
|
|
"hash": { "type": "string" },
|
|
"time": { "type": "string", "format": "date-time" },
|
|
"validator": { "type": "string", "description": "DC... address" },
|
|
"tx_count": { "type": "integer" },
|
|
"total_fees_ut": { "type": "integer", "format": "uint64" }
|
|
}
|
|
},
|
|
"BlockDetail": {
|
|
"allOf": [
|
|
{ "$ref": "#/components/schemas/BlockSummary" },
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"prev_hash": { "type": "string" },
|
|
"validator_addr": { "type": "string" },
|
|
"transactions": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"properties": {
|
|
"id": { "type": "string" },
|
|
"type": { "type": "string" },
|
|
"from": { "type": "string" },
|
|
"to": { "type": "string" },
|
|
"amount_ut": { "type": "integer", "format": "uint64" },
|
|
"fee_ut": { "type": "integer", "format": "uint64" }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
},
|
|
"TxListEntry": {
|
|
"type": "object",
|
|
"properties": {
|
|
"id": { "type": "string" },
|
|
"type": { "type": "string", "enum": ["TRANSFER","REGISTER_KEY","RELAY_PROOF","REGISTER_RELAY","CONTACT_REQUEST","ACCEPT_CONTACT","BLOCK_CONTACT","ADD_VALIDATOR","REMOVE_VALIDATOR","HEARTBEAT","BIND_WALLET","SLASH","OPEN_PAY_CHAN","CLOSE_PAY_CHAN","BLOCK_REWARD"] },
|
|
"from": { "type": "string" },
|
|
"from_addr": { "type": "string" },
|
|
"to": { "type": "string" },
|
|
"to_addr": { "type": "string" },
|
|
"amount_ut": { "type": "integer", "format": "uint64" },
|
|
"amount": { "type": "string", "description": "Human-readable token amount" },
|
|
"fee_ut": { "type": "integer", "format": "uint64" },
|
|
"fee": { "type": "string" },
|
|
"time": { "type": "string", "format": "date-time" },
|
|
"block_index": { "type": "integer", "format": "uint64" },
|
|
"block_hash": { "type": "string" }
|
|
}
|
|
},
|
|
"TxDetail": {
|
|
"allOf": [
|
|
{ "$ref": "#/components/schemas/TxListEntry" },
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"block_time": { "type": "string", "format": "date-time" },
|
|
"payload": { "description": "Decoded payload JSON (type-specific)" },
|
|
"payload_hex": { "type": "string" },
|
|
"signature_hex": { "type": "string" }
|
|
}
|
|
}
|
|
]
|
|
},
|
|
"AddressDetail": {
|
|
"type": "object",
|
|
"properties": {
|
|
"address": { "type": "string" },
|
|
"pub_key": { "type": "string" },
|
|
"balance_ut": { "type": "integer", "format": "uint64" },
|
|
"balance": { "type": "string" },
|
|
"tx_count": { "type": "integer" },
|
|
"offset": { "type": "integer" },
|
|
"limit": { "type": "integer" },
|
|
"has_more": { "type": "boolean" },
|
|
"next_offset": { "type": "integer" },
|
|
"transactions": { "type": "array", "items": { "$ref": "#/components/schemas/TxListEntry" } }
|
|
}
|
|
},
|
|
"NodeStats": {
|
|
"type": "object",
|
|
"properties": {
|
|
"pub_key": { "type": "string" },
|
|
"address": { "type": "string" },
|
|
"node_balance_ut": { "type": "integer", "format": "uint64" },
|
|
"node_balance": { "type": "string" },
|
|
"wallet_binding_address": { "type": "string" },
|
|
"wallet_binding_balance_ut": { "type": "integer", "format": "uint64" },
|
|
"reputation_score": { "type": "integer", "format": "int64" },
|
|
"reputation_rank": { "type": "string", "enum": ["Observer","Active","Trusted","Validator"] },
|
|
"blocks_produced": { "type": "integer", "format": "uint64" },
|
|
"relay_proofs": { "type": "integer", "format": "uint64" },
|
|
"slash_count": { "type": "integer", "format": "uint64" },
|
|
"heartbeats": { "type": "integer", "format": "uint64" },
|
|
"recent_window_blocks": { "type": "integer" },
|
|
"recent_blocks_produced": { "type": "integer" },
|
|
"recent_rewards_ut": { "type": "integer", "format": "uint64" },
|
|
"recent_rewards": { "type": "string" }
|
|
}
|
|
},
|
|
"IdentityInfo": {
|
|
"type": "object",
|
|
"properties": {
|
|
"pub_key": { "type": "string", "description": "Hex Ed25519 public key" },
|
|
"address": { "type": "string", "description": "DC... wallet address" },
|
|
"x25519_pub": { "type": "string", "description": "Hex Curve25519 public key for E2E encryption; empty if not published" },
|
|
"nickname": { "type": "string" },
|
|
"registered": { "type": "boolean", "description": "true if REGISTER_KEY tx was committed" }
|
|
}
|
|
},
|
|
"RegisteredRelayInfo": {
|
|
"type": "object",
|
|
"properties": {
|
|
"pub_key": { "type": "string" },
|
|
"address": { "type": "string" },
|
|
"relay": {
|
|
"type": "object",
|
|
"properties": {
|
|
"x25519_pub_key": { "type": "string" },
|
|
"fee_per_msg_ut": { "type": "integer", "format": "uint64" },
|
|
"multiaddr": { "type": "string" }
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"Envelope": {
|
|
"type": "object",
|
|
"description": "NaCl-box sealed message envelope. Only the holder of the recipient's X25519 private key can decrypt it.",
|
|
"required": ["id", "recipient_pub", "sender_pub", "nonce", "ciphertext"],
|
|
"properties": {
|
|
"id": { "type": "string", "description": "Hex SHA-256[:16] of nonce||ciphertext" },
|
|
"recipient_pub": { "type": "string", "description": "Hex X25519 public key of the recipient" },
|
|
"sender_pub": { "type": "string", "description": "Hex X25519 public key of the sender" },
|
|
"sender_ed25519_pub": { "type": "string", "description": "Sender's Ed25519 pub key for on-chain fee claims" },
|
|
"fee_ut": { "type": "integer", "format": "uint64", "description": "Delivery fee µT (0 = free)" },
|
|
"fee_sig": { "type": "string", "format": "byte", "description": "Ed25519 sig over FeeAuthBytes(id, fee_ut)" },
|
|
"nonce": { "type": "string", "format": "byte", "description": "24-byte NaCl nonce (base64)" },
|
|
"ciphertext": { "type": "string", "format": "byte", "description": "NaCl box ciphertext (base64)" },
|
|
"sent_at": { "type": "integer", "format": "int64", "description": "Unix timestamp" }
|
|
}
|
|
},
|
|
"InboxItem": {
|
|
"type": "object",
|
|
"properties": {
|
|
"id": { "type": "string" },
|
|
"sender_pub": { "type": "string" },
|
|
"recipient_pub": { "type": "string" },
|
|
"fee_ut": { "type": "integer", "format": "uint64" },
|
|
"sent_at": { "type": "integer", "format": "int64" },
|
|
"sent_at_human": { "type": "string", "format": "date-time" },
|
|
"nonce": { "type": "string", "format": "byte" },
|
|
"ciphertext": { "type": "string", "format": "byte" }
|
|
}
|
|
},
|
|
"ContactInfo": {
|
|
"type": "object",
|
|
"properties": {
|
|
"requester_pub": { "type": "string" },
|
|
"requester_addr": { "type": "string" },
|
|
"status": { "type": "string", "enum": ["pending", "accepted", "blocked"] },
|
|
"intro": { "type": "string", "description": "Optional plaintext intro (≤ 280 chars)" },
|
|
"fee_ut": { "type": "integer", "format": "uint64" },
|
|
"tx_id": { "type": "string" },
|
|
"created_at": { "type": "integer", "format": "int64" }
|
|
}
|
|
},
|
|
"Transaction": {
|
|
"type": "object",
|
|
"description": "Signed blockchain transaction. Sign the canonical JSON of the object with Signature set to null, using Ed25519.",
|
|
"required": ["type", "from"],
|
|
"properties": {
|
|
"id": { "type": "string" },
|
|
"type": { "type": "string", "enum": ["TRANSFER","REGISTER_KEY","RELAY_PROOF","REGISTER_RELAY","CONTACT_REQUEST","ACCEPT_CONTACT","BLOCK_CONTACT","ADD_VALIDATOR","REMOVE_VALIDATOR","HEARTBEAT","BIND_WALLET","SLASH","OPEN_PAY_CHAN","CLOSE_PAY_CHAN"] },
|
|
"from": { "type": "string", "description": "Hex Ed25519 pub key of the signer" },
|
|
"to": { "type": "string", "description": "Hex Ed25519 pub key of the recipient (if applicable)" },
|
|
"amount": { "type": "integer", "format": "uint64", "description": "µT to transfer (TRANSFER, CONTACT_REQUEST)" },
|
|
"fee": { "type": "integer", "format": "uint64", "description": "µT fee to block validator (min 1000)" },
|
|
"memo": { "type": "string" },
|
|
"payload": { "type": "string", "format": "byte", "description": "Base64 JSON payload (type-specific)" },
|
|
"signature": { "type": "string", "format": "byte", "description": "Ed25519 signature over canonical bytes" },
|
|
"timestamp": { "type": "string", "format": "date-time" }
|
|
}
|
|
},
|
|
"SubmitTransactionRequest": {
|
|
"type": "object",
|
|
"properties": {
|
|
"tx": { "$ref": "#/components/schemas/Transaction" },
|
|
"signed_tx": { "type": "string", "description": "Signed transaction as JSON/base64/hex string" }
|
|
}
|
|
},
|
|
"DraftTransactionRequest": {
|
|
"type": "object",
|
|
"required": ["from", "to", "amount_ut"],
|
|
"properties": {
|
|
"from": { "type": "string" },
|
|
"to": { "type": "string" },
|
|
"amount_ut": { "type": "integer", "format": "uint64" },
|
|
"memo": { "type": "string" },
|
|
"fee_ut": { "type": "integer", "format": "uint64", "description": "Optional; defaults to MinFee (1000 µT)" }
|
|
}
|
|
},
|
|
"DraftTransactionResponse": {
|
|
"type": "object",
|
|
"properties": {
|
|
"tx": { "$ref": "#/components/schemas/Transaction" },
|
|
"sign_bytes_hex": { "type": "string" },
|
|
"sign_bytes_base64": { "type": "string" },
|
|
"note": { "type": "string" }
|
|
},
|
|
"required": ["tx", "sign_bytes_hex", "sign_bytes_base64"]
|
|
},
|
|
"SubmitTransactionResponse": {
|
|
"type": "object",
|
|
"properties": {
|
|
"status": { "type": "string" },
|
|
"id": { "type": "string" }
|
|
},
|
|
"required": ["status", "id"]
|
|
},
|
|
"ChainTx": {
|
|
"type": "object",
|
|
"properties": {
|
|
"id": { "type": "string" },
|
|
"type": { "type": "string" },
|
|
"memo": { "type": "string" },
|
|
"from": { "type": "string" },
|
|
"from_addr": { "type": "string" },
|
|
"to": { "type": "string" },
|
|
"to_addr": { "type": "string" },
|
|
"amount_ut": { "type": "integer", "format": "uint64" },
|
|
"fee_ut": { "type": "integer", "format": "uint64" },
|
|
"block_index": { "type": "integer", "format": "uint64" },
|
|
"block_hash": { "type": "string" },
|
|
"time": { "type": "string", "format": "date-time" }
|
|
}
|
|
},
|
|
"ChainTransactionsResponse": {
|
|
"type": "object",
|
|
"properties": {
|
|
"account_id": { "type": "string" },
|
|
"account_addr": { "type": "string" },
|
|
"count": { "type": "integer" },
|
|
"order": { "type": "string" },
|
|
"limit_applied": { "type": "integer" },
|
|
"transactions": { "type": "array", "items": { "$ref": "#/components/schemas/ChainTx" } }
|
|
}
|
|
},
|
|
"ChainTransactionDetailResponse": {
|
|
"type": "object",
|
|
"properties": {
|
|
"tx": { "$ref": "#/components/schemas/ChainTx" },
|
|
"payload": {},
|
|
"payload_hex": { "type": "string" },
|
|
"signature_hex": { "type": "string" }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|