diff --git a/api/lightwallet_rest.md b/api/lightwallet_rest.md new file mode 100644 index 0000000..1592f19 --- /dev/null +++ b/api/lightwallet_rest.md @@ -0,0 +1,402 @@ +# Lightwallet API +This document describes a reference standard specification for the Monero +lightwallet server/client API. It’s implemented by OpenMonero, MyMonero, and +the official Monero project, and is maintained with the purpose of organizing +and recording the consensus of Monero lightwallet API projects, and to support +alternate implementations. + +Modifications to this specification should only be made with consensus of the +projects which participate by implementing the specification. + +## Encoding Schemes +### JSON +JSON is the original and required encoding scheme used for the API. Binary +values (public keys, hashes, etc) are sent as an ascii-hex string. Some +integers, that may exceed 2^53, are sent as strings. This is to due to the +limitation within Javascript where all integers are double floating point +values. + +## Transport Layers +### HTTP-REST +When calling an API method, the client must use HTTP POST to a path with the +method name. As an example, to invoke the `get_address_txs` method, the client +sends a POST message to `/get_address_txs` where the body contains the JSON +request object associated with that method name. If the requested method does +not exist, a HTTP 404 "Not Found" error must be returned. If the request type +is not POST, the server shall return a HTTP 405 "Method Not Allowed" error. If +the server is unable to complete a request temporarily due to load, then the +server shall return a HTTP 503 "Service Unavailable" error to indicate to the +client that the request may be serviceable later. + +Servers must support the JSON encoding scheme. The client must send the HTTP +field `Content-Type: application/json`; if the server is not provided that +content type from the client then the server shall respond with a HTTP 415 +"Unsupported Media Type" error. + +This transport layer does not use HTTP authentication, and instead uses the +`view_key` field for authorization. Documentation for a specific method will +indicate whether `view_key` is required. When it is not necessary, anyone can +invoke the method. + +## Schema +The ascii name of the field is used as a key in JSON encoding. If a field has +a `*` indicator, that means the field is optional. If `*` is used next to the +type, the value can be "null" or a value valid according to the type. + +### Types +**binary** + +A hex-ascii string in JSON. This is generally some irreducible cryptographic +concept - a public key or hash. + +**base58-address** + +A standard Monero public address encoded as a string in JSON. + +**output** object + +Information needed to spend an output. + +| Field | Type | Description | +|------------------|-------------------|-------------------------------| +| tx_id | uint64 | Index of tx in blockchain | +| amount | uint64-string | XMR value of output | +| index | uint16 | Index within vout vector | +| global_index | uint64-string | Index within amount | +| rct | binary | Bytes of ringct data | +| tx_hash | binary | Bytes of tx hash | +| tx_prefix_hash | binary | Bytes of tx prefix hash | +| public_key | binary | Bytes of output public key | +| tx_pub_key | binary | Bytes of the tx public key | +| spend_key_images | array of binary's | Bytes of key images | +| timestamp | timestamp | Timestamp of containing block | +| height | uint64 | Containing block height | + +> `tx_id` is determined by the monero daemon. It is the offset that a +> transaction appears in the blockchain from the genesis block. + +> `global_index` is determined by the monero daemon. It is the offset from the +> first time the amount appeared in the blockchain. After ringct, this is the +> order of outputs as they appear in the blockchain. + +> `tx_hash` and `tx_prefix_hash` are determined by how `monerod` computes the +> hash. + +> `rct` is, for ringct outputs, a 96-byte blob containing the concatenation +> of the public commitment, then the ringct mask value, and finally the +> ringct amount value. For ringct coinbase outputs, the mask is always the +> identity mask and the amount is zero; for non-coinbase ringct outputs, the +> mask and amount are the respective raw encrypted values, which must be +> decrypted by the client using the view secret key. For non-ringct outputs, +> this field is nil. + +**rates** object + +| Field | Type | Description | +|-------|---------|-----------------------| +| AUD * | float32 | AUD/XMR exchange rate | +| BRL * | float32 | BRL/XMR exchange rate | +| BTC * | float32 | BTC/XMR exchange rate | +| CAD * | float32 | CAD/XMR exchange rate | +| CHF * | float32 | CHF/XMR exchange rate | +| CNY * | float32 | CNY/XMR exchange rate | +| EUR * | float32 | EUR/XMR exchange rate | +| GBP * | float32 | GBP/XMR exchange rate | +| HKD * | float32 | HKD/XMR exchange rate | +| INR * | float32 | INR/XMR exchange rate | +| JPY * | float32 | JPY/XMR exchange rate | +| KRW * | float32 | KRW/XMR exhcnage rate | +| MXN * | float32 | MXN/XMR exchange rate | +| NOK * | float32 | NOK/XMR exchange rate | +| NZD * | float32 | NZD/XMR exchange rate | +| SEK * | float32 | SEK/XMR exchange rate | +| SGD * | float32 | SGD/XMR exchange rate | +| TRY * | float32 | TRY/XMR exchange rate | +| USD * | float32 | USD/XMR exchange rate | +| RUB * | float32 | RUB/XMR exchange rate | +| ZAR * | float32 | ZAR/XMR exchange rate | + +> If an exchange rate is unavailable, the server field shall omit the field +> from the JSON object. + +**spend** object + +| Field | Type | Description | +|------------|---------------|----------------------------| +| amount | uint64-string | XMR possibly being spent | +| key_image | binary | Bytes of the key image | +| tx_pub_key | binary | Bytes of the tx public key | +| out_index | uint16 | Index of source output | +| mixin | uint32 | Mixin of the spend | + +> `out_index` is a zero-based offset from the original received output. The +> variable within the monero codebase is the `vout` array, this is the index +> within that. It is needed for correct computation of the `key_image`. + +> `mixin` does not include the real spend - this is the number of dummy inputs. + +**timestamp** + +A string in JSON. The string format is "YYYY-HH-MM-SS.0-00:00". Monero +blockchain timestamps do not have sub-seconds. + +**transaction** object + +| Field | Type | Description | +|----------------|------------------|---------------------------| +| id | uint64 | Index of tx in blockchain | +| hash | binary | Bytes of tx hash | +| timestamp * | timestamp | Timestamp of block | +| total_received | uint64-string | Total XMR received | +| total_sent | uint64-string | XMR possibly being spent | +| unlock_time | uint64 | Tx unlock time field | +| height * | uint64 | Block height | +| spent_outputs | array of spend's | List of possible spends | +| payment_id * | binary | Bytes of tx payment id | +| coinbase | boolean | True if tx is coinbase | +| mempool | boolean | True if tx is in mempool | +| mixin | uint32 | Mixin of the receive | + +> `id` is determined by the monero daemon. It is the offset that a +> transaction appears in the blockchain from the genesis block. + +> `timestamp` and `height` are not sent when `mempool` is true. + +> `hash` is determined by how the monero core computes the hash. + +> `spent_outputs` is the list of possible spends in _this_ transaction only. + +> `payment_id` is omitted if the transaction had none. It is decrypted when the +> encrypted form is used. The decryption may be incorrect - if the transaction +> was TO another address, then this will be random bytes. This happens +> frequently with outgoing payment ids; the received XMR in the transaction is +> change and the payment id is for the real recipient. + +> `mixin` does not include the real spend - this is the number of dummy inputs. + +**uint16** / **uint32** / **uint64** + +Sent as a standard decimal encoded number in JSON. The JSON decoder must reject +number values that exceed the specified bit-width. + +**uint64-string** + +A uint64 encoded as a decimal string value in JSON. Used when a value may +exceed 2^53 - all numbers are 64-bit floats in JavaScript. + +**random_output** object + +| Field | Type | Description | +|--------------|---------------|------------------------------------| +| global_index | uint64-string | Index within amount | +| public_key | bytes | Bytes of output public key | +| rct | bytes | Bytes containing ringct commitment | + +> `global_index` is determined by the monero daemon. It is the offset from the +> first time the amount appeared in the blockchain. After ringct, this is the +> order of outputs as they appear in the blockchain. + +**random_outputs** object + +Randomly selected outputs for use in a ring signature. + +| Field | Type | Description | +|-----------|--------------------------|-------------------------| +| amount | uint64-string | XMR amount, 0 if ringct | +| outputs * | array of random_output's | Selected outputs | + +> `outputs` is omitted by the server if the `amount` does not have enough +> mixable outputs. + +### Methods +#### `get_address_info` +Returns the minimal set of information needed to calculate a wallet balance. +The server cannot calculate when a spend occurs without the spend key, so a +list of candidate spends is returned. + +**Request** object + +| Field | Type | Description | +|-----------|----------------|---------------------------------------| +| address | base58-address | Address to retrieve | +| view_key | binary | View key bytes for authorization | + +> If `address` is not authorized, the server must return a HTTP 403 +> "Forbidden" error. + +**Response** object + +| Field | Type | Description | +|----------------------|------------------|---------------------------| +| locked_funds | uint64-string | Sum of unspendable XMR | +| total_received | uint64-string | Sum of received XMR | +| total_sent | uint64-string | Sum of possibly spent XMR | +| scanned_height | uint64 | Current tx scan progress | +| scanned_block_height | uint64 | Current scan progress | +| start_height | uint64 | Start height of response | +| transaction_height | uint64 | Total txes sent in Monero | +| blockchain_height | uint64 | Current blockchain height | +| spent_outputs | array of spend's | Possible spend info | +| rates * | rates | Current exchange rates | + +> `rates` is omitted if unavailable. + +#### `get_address_txs` +Returns information needed to show transaction history. The server cannot +calculate when a spend occurs without the spend key, so a list of candidate +spends is returned. + +**Request** object + +| Field | Type | Description | +|----------|----------------|---------------------------------------| +| address | base58-address | Address to retrieve | +| view_key | binary | View key bytes for authorization | + +> If `address` is not authorized, the server must return a HTTP 403 +> "Forbidden" error. + +**Response** object + +| Field | Type | Description | +|----------------------|------------------------|---------------------------| +| total_received | uint64-string | Sum of received outputs | +| scanned_height | uint64 | Current tx scan progress | +| scanned_block_height | uint64 | Current scan progress | +| start_height | uint64 | Start height of response | +| blockchain_height | uint64 | Current blockchain height | +| transactions | array of transaction's | Possible spend info | + +#### `get_random_outs` +Selects random outputs to use in a ring signature of a new transaction. If the +`amount` is `0` then the `monerod` RPC `get_output_distribution` should be used +to locally select outputs using a gamma distribution as described in "An +Empirical Analysis of Traceability in the Monero Blockchain". If the `amount` +is not `0`, then the `monerod` RPC `get_output_histogram` should be used to +locally select outputs using a triangular distribution +(`uint64_t dummy_out = histogram.total * sqrt(float64(random_uint53) / float64(2^53))`). + +**Request** object + +| Field | Type | Description | +|------------|---------------------------|----------------------------------| +| count | uint32 | Mixin (name is historical) | +| amounts | array of uint64-strings's | XMR amounts that need mixing | + +> Clients must use amount `0` when computing a ringct output. + +> If clients are creating multiple rings with the same amount, they must set +> `count` to the mixin level and add the value to `amounts` multiple times. +> Server must respond to each value in `amounts`, even if the value appears +> multiple times. + +**Response** object + +| Field | Type | Description | +|-------------|--------------------------|----------------------------------| +| amount_outs | array of random_outputs' | Dummy outputs for each `amounts` | + +> If there are not enough outputs to mix for a specific amount, the server +> shall omit the `outputs` field in `amount_outs`. + +#### `get_unspent_outs` +Returns a list of received outputs. The client must determine when the output +was actually spent. + +**Request** object + +| Field | Type | Description | +|------------------|----------------|----------------------------------| +| address | base58-address | Address to create/probe | +| view_key | binary | View key bytes | +| amount | uint64-string | XMR send amount | +| mixin | uint32 | Minimum mixin for source output | +| use_dust | boolean | Return all available outputs | +| dust_threshold * | uint64-string | Ignore outputs below this amount | + +> If the total received outputs for the address is less than `amount`, the +> server shall return a HTTP 400 "Bad Request" error code. + +**Response** object + +| Field | Type | Description | +|--------------|-------------------|-----------------------------------------| +| per_byte_fee | uint64-string | Estimated network fee | +| fee_mask | uint64-string | Fee quantization mask | +| amount | uint64-string | The total value in outputs | +| outputs | array of output's | Outputs possibly available for spending | + +#### `import_request` +Request an account scan from the genesis block. + +**Request** object + +| Field | Type | Description | +|----------|----------------|-------------------------| +| address | base58-address | Address to create/probe | +| view_key | binary | View key bytes | + +**Response** object + +| Field | Type | Description | +|--------------------|----------------|----------------------------------| +| payment_address * | base58-address | Payment location | +| payment_id * | binary | Bytes for payment_id tx field | +| import_fee * | uint64-string | Fee required to complete request | +| new_request | boolean | New or existing request | +| request_fulfilled | boolean | Indicates success | +| status | string | Custom message | + +> `payment_id`, `import_fee`, and `payment_address` may be omitted if the +> client does not need to send XMR to complete the request. + +#### `login` +Check for the existence of an account or create a new one. + +**Request** object + +| Field | Type | Description | +|-------------------|----------------|----------------------------------| +| address | base58-address | Address to create/probe | +| view_key | binary | View key bytes | +| create_account | boolean | Try to create new account | +| generated_locally | boolean | Indicate that the address is new | + +> The view key bytes are required even if an account is not being created, to +> prevent metadata leakage. + +> If the server does not allow account creations, HTTP 501 "Not Implemented" +> error must be returned. + +> If approval process is manual, a successful HTTP 200 OK and response object +> must be returned. Subsequent requests shall be HTTP 403 "Forbidden" until +> account is approved. + +**Response** object + +| Field | Type | Description | +|---------------------|---------|------------------------------------| +| new_address | boolean | Whether account was just created | +| generated_locally * | boolean | Flag from initial account creation | +| start_height * | uint64 | Account scanning start block | + +#### `submit_raw_tx` +Submit raw transaction to be relayed to monero network. + +**Request** object + +| Field | Type | Description | +|------------|----------------|-----------------------------------------------------------| +| tx | binary | Raw transaction bytes, in format used by daemon p2p comms | + +> This format is tricky unfortunately, it is custom to the monero daemon. The +> internal code of `monerod` must be read to determine this format currently. + +**Response** object + +| Field | Type | Description | +|--------|--------|-----------------| +| status | string | Status of relay | + +> `status` is typically the response by the monero daemon attempting to relay +> the transaction.