Skip to content

Commit

Permalink
add readable API markdown and alter docs
Browse files Browse the repository at this point in the history
  • Loading branch information
AdamISZ committed Sep 30, 2021
1 parent 46689a2 commit b527bbb
Show file tree
Hide file tree
Showing 3 changed files with 464 additions and 207 deletions.
220 changes: 20 additions & 200 deletions docs/JSON-RPC-API-using-jmwalletd.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,215 +20,35 @@ This HTTP server does *NOT* currently support multiple sessions; it is intended

Authentication is with the [JSON Web Token](https://jwt.io/) scheme, provided using the Python package [PyJWT](https://pypi.org/project/PyJWT/).

GET requests are used in case no content or parameters need to be provided with the request.
Note that for some methods, it's particularly important to deal with the HTTP response asynchronously, since it can take some time for wallet synchronization, service startup etc. to occur; in these cases a HTTP return code of 202 is sent.

POST requests are used in case content or parameters are to be provided with the request, and they are provided as utf-8 encoded serialized JSON, in the *body* of the POST request.
### API documentation

Note that for some methods, it's particularly important to deal with the HTTP response asynchronously, since it can take some time for wallet synchronization, service startup etc. to occur.
Current API version: v1.

### API v1
The [OpenAPI](https://github.com/OAI/OpenAPI-Specification) spec is given in [this yaml file](../jmclient/jmclient/wallet-rpc-api.yaml). Human readable documentation of the API is provided in [this document](../jmclient/jmclient/wallet-rpc-api.md), which is auto-generated with the node utility [swagger-markdown](https://www.npmjs.com/package/swagger-markdown).

### RPC Methods
Those wishing to write client code should adhere to that specification.

#### `listwallets`
#### What is and is not provided in the current version of the API.

Lists currently available wallet files.
As a brief summary, the functionality currently available is:

* HTTP Request type: GET
* Route: `/api/v1/wallet/all`
* Returns:
- on success, {"wallets": list[wallet: string]}
* create a wallet
* unlock (decrypt) a wallet
* lock a wallet
* display contents of a wallet
* list the utxos in the wallet
* get a new address for deposit in a given account
* send a payment without coinjoin
* send a paymen with coinjoin
* start the yield generator
* stop the yield generator
* a 'heartbeat' check that also reports whether a wallet is loaded, whether the maker is running, whether a coinjoin is in process.

##### Notes
Clearly there are several further functionalities currently available in the CLI and Qt versions of Joinmarket which are not yet supported. It is likely that several or all of these will be added in future (e.g.: payjoin, utxo freezing).

* `wallet` in the returned list value are each filenames in `datadir/wallets` (filename only, including `.jmdat`, not full path).

#### `createwallet`

Make a new wallet.

* HTTP Request type: POST
* Route: `/api/v1/wallet/create`
* POST body contents: {"walletname": string, "password": string, "wallettype": string}
* Returns:
- on success, {"walletname": string, "already_loaded": false, "token": string, "seedphrase": string}

##### Notes

* `walletname` is the filename for the wallet created on disk in `datadir/wallets`.
* `wallettype` must be one of `"sw"`, `"swl"` ; "sw" refers to `SegwitWallet` and "swl" to `SegwitLegacyWallet`. (TODO: make `SegwitWalletFidelityBonds` the default).
* `password` must be a string, and will be used as the encryption password for the wallet file created (see `unlockwallet` below).
* Return value of `already_loaded` will be `false` for successful creation.
* `token` will be the created JWT token.
* `seedphrase` will be the BIP39 12 word seedphrase of the newly created Joinmarket wallet.

#### `unlockwallet`

Open an existing wallet using a password.

* HTTP Request type: POST
* Route: `/api/v1/wallet/<string:walletname>/unlock`
* POST body contents: {"password": string}
* Returns:
- on success, {"walletname": string, "already_loaded": bool, "token": string}

##### Notes

* `walletname` in the request URL will be used as the filename for the wallet created on disk in `datadir/wallets`.
* `password` must be a string, used as the decryption password for the wallet file.
* `token` will be the created JWT token.
* `already_loaded` is false in case there is no currently unlocked wallet, and this wallet is unlocked successfully.
* `already_loaded` is true in case the same wallet is already unlocked, or another wallet is currently unlocked (note that this is not an error response).

#### `lockwallet`

Stops the wallet service for the current wallet; meaning it cannot then be accessed without re-authentication.

* HTTP Request type: GET
* Route: `/api/v1/wallet/<string:walletname>/lock`
* Returns:
- on success, {"walletname": string, "already_locked": bool}

##### Notes

* `walletname` in the request URL will be used as the filename for the wallet created on disk in `datadir/wallets`.
* `already_locked` is false if there was an unlocked wallet, and we locked it, otherwise true.

#### `displaywallet`

Get JSON representation of wallet contents for wallet named `walletname`:

* HTTP Request type: GET
* Route: `/wallet/<string:walletname>/display`
* Returns:
- on success, a JSON object which is the entire wallet contents, mixdepth by mixdepth.

##### Notes

* `walletname` in the request URL will be used as the filename for the wallet created on disk in `datadir/wallets`.
* Format of returned JSON: see [here](#displayexample).

#### `getaddress`

Get a new address for deposits.

* HTTP Request type: GET
* Route: `/api/v1/wallet/<string:walletname>/address/new/<string:mixdepth>`
* Returns:
- on success, {"address": string}

##### Notes

* `walletname` in the request URL will be used as the filename for the wallet created on disk in `datadir/wallets`.
* `mixdepth` in the request must be in the range of accounts in the default wallet structure, so "0".."4".
* The returned address is the first unused address in the *external* branch of the given account/mixdepth.

#### `listutxos`

Get a new address for deposits.

* HTTP Request type: GET
* Route: `/api/v1/wallet/<string:walletname>/utxos`
* Returns:
- on success, {"utxos": json-string}

##### Notes

* `walletname` in the request URL will be used as the filename for the wallet created on disk in `datadir/wallets`.
* The return value string is a json object with all utxos currently owned by the wallet.
* TODO: document the utxos return value format.

#### `directsend`

Make a bitcoin payment from the wallet, without coinjoin.

* HTTP Request type: POST
* Route: `/api/v1/wallet/<string:walletname>/taker/direct-send`
* POST body contents: {"mixdepth": string, "amount_sats": string, "destination": string}
* Returns:
- on success, {"walletname": string, "txinfo": json-string}

##### Notes

* `walletname` in the request URL will be used as the filename for the wallet created on disk in `datadir/wallets`.
* `mixdepth` in POST body is a string representing the mixdepth/account ("0".."4").
* `amount_sats` in POST body is a string containing the integer number of sats to pay.
* `destination` in POST body is the bitcoin address to receive the payment.

#### `docoinjoin`

Get a new address for deposits.

* HTTP Request type: POST
* Route: `/api/v1/wallet/<string:walletname>/taker/coinjoin`
* POST body contents: {"mixdepth": string, "amount": string, "counterparties": string, "destination": string}
* Returns:
- on success, {"coinjoin_started": bool}

##### Notes

* `walletname` in the request URL will be used as the filename for the wallet created on disk in `datadir/wallets`.
* This action only *starts* the coinjoin process, a successful return indicates start OK, not completion.
* TODO: link to notifications of progress and completion of coinjoin.

#### `session`

Check the status and liveness of the session.

* HTTP Request type: GET
* Route: `/api/v1/session`
* Returns:
- on success, {"session": bool, "maker_running": bool, "coinjoin_in_process": bool, "wallet_name": string}

##### Notes

* This method's primary goal is to give a client the assurance that the backend is actually running.
* TODO: the other return values will probably be removed as websocket notifications do the job better.
* `session` is true if and only if there is an active authentication and unlocked wallet.
* `walletname` in response is the Joinmarket internal wallet name, `joinmarket-<hex encoded 3 byte hash identifier>`.


#### `maker-start`

Starts the yield generator/maker service for the given wallet, using the IRC and tor network connections
in the backend (inside the process started with jmwalletd).
See Joinmarket yield generator config defaults in `jmclient.configure` module for info on the data that must
be specified in the POST body contents.

* HTTP Request type: POST
* Route: `/api/v1/wallet/<string:walletname>/maker/start`
* POST body contents: {"txfee": string, "cjfee_a": string, "cjfee_r": string, "ordertype": string, "minsize": string}
* Returns:
- on success, {"walletname": string}

##### Notes

* `walletname` in the request URL will be used as the filename for the wallet created on disk in `datadir/wallets`.
* `walletname` in response is the Joinmarket internal wallet name, `joinmarket-<hex encoded 3 byte hash identifier>`.
* See Joinmarket yield generator config defaults in `jmclient.configure` module for info on the data that must
be specified in the POST body contents.

#### `maker-stop`

Stops the yieldgenerator/maker service if currently running for the given wallet.

* HTTP Request type: GET
* Route: `/api/v1/wallet/<string:walletname>/maker/start`
* Returns: on success, {"walletname": string}

* `walletname` in the request URL will be used as the filename for the wallet created on disk in `datadir/wallets`.
* `walletname` in response is the Joinmarket internal wallet name, `joinmarket-<hex encoded 3 byte hash identifier>`.
* See Joinmarket yield generator config defaults in `jmclient.configure` module for info on the data that must
be specified in the POST body contents.


<a name="displayexample" />

##### Example wallet display JSON output from signet wallet

```
{'wallet_name': 'JM wallet', 'total_balance': '0.15842426', 'accounts': [{'account': '0', 'account_balance': '0.00861458', 'branches': [{'branch': "external addresses\tm/84'/1'/0'/0\ttpubDFGxEsV7NvVc4h2XL4QEppZt3CrDiCFksP97H6YbFPmCTKM6KMP2xUxW57gAu7bzDfB3YTqnMeKQaQRS5GJM3xMcrhbi5AGsQUd7p4PLMDV", 'balance': '0.00000000', 'entries': [{'hd_path': "m/84'/1'/0'/0/4", 'address': 'tb1qzugshsm85x6luegyjc6mk5zces2zqr0j8m4zkd', 'amount': '0.00000000', 'labels': 'new'}, {'hd_path': "m/84'/1'/0'/0/5", 'address': 'tb1qcwmdkg229ghmd8r3xgq4a9zxp459crws66n4ve', 'amount': '0.00000000', 'labels': 'new'}, {'hd_path': "m/84'/1'/0'/0/6", 'address': 'tb1q7lv6dwex3mhwp32vhku0fvpar9faar2lu595su', 'amount': '0.00000000', 'labels': 'new'}, {'hd_path': "m/84'/1'/0'/0/7", 'address': 'tb1qm42ltytvp22kj9efp995yu0r0r7x570d8j8crc', 'amount': '0.00000000', 'labels': 'new'}, {'hd_path': "m/84'/1'/0'/0/8", 'address': 'tb1qwvux8g0khuvvkla3zaqdslj6xpgwtq7jlvwmgu', 'amount': '0.00000000', 'labels': 'new'}, {'hd_path': "m/84'/1'/0'/0/9", 'address': 'tb1q3xr7l9nylsdlyqf9rkw0rg3f0yx6slguhtwpzp', 'amount': '0.00000000', 'labels': 'new'}]}, {'branch': "internal addresses\tm/84'/1'/0'/1\t", 'balance': '0.00861458', 'entries': [{'hd_path': "m/84'/1'/0'/1/7", 'address': 'tb1qjrzxkulgc5dnlyz0rjqj68zxgqjesqn839ue2w', 'amount': '0.00396839', 'labels': 'cj-out'}, {'hd_path': "m/84'/1'/0'/1/12", 'address': 'tb1qeqkk4te2t6gqt7jfgu8a9k4je2wwfw3d2m7gku', 'amount': '0.00464619', 'labels': 'non-cj-change'}]}]}, {'account': '1', 'account_balance': '0.09380968', 'branches': [{'branch': "external addresses\tm/84'/1'/1'/0\ttpubDE1TKa8tm3WWh4f9fV325BgYWX9i7WFMaQRd1C3tSFYU9RJEyE8w2Cw2KnhgXSKyjS4keeWAkc3iLEqp3pxUEG9T49RCtQiMpjuZM71FLpL", 'balance': '0.00000000', 'entries': [{'hd_path': "m/84'/1'/1'/0/0", 'address': 'tb1qd6qqg3uzk9sw88yhvpqpwt3tx5ls4hau3mwh3g', 'amount': '0.00000000', 'labels': 'new'}, {'hd_path': "m/84'/1'/1'/0/1", 'address': 'tb1qhkrmqn9e4ldzlwna8w5w9l5vaw978zlrl54hmh', 'amount': '0.00000000', 'labels': 'new'}, {'hd_path': "m/84'/1'/1'/0/2", 'address': 'tb1qp83afad8dl98w366vnvct0zc49qu33c2nfx386', 'amount': '0.00000000', 'labels': 'new'}, {'hd_path': "m/84'/1'/1'/0/3", 'address': 'tb1qjv0elh4kn5yaywajedgcrf93ujzz3m3q7ld7k3', 'amount': '0.00000000', 'labels': 'new'}, {'hd_path': "m/84'/1'/1'/0/4", 'address': 'tb1qk25u4ch7w0xylzh0krn4hefphe6xpyh0vc33sl', 'amount': '0.00000000', 'labels': 'new'}, {'hd_path': "m/84'/1'/1'/0/5", 'address': 'tb1qs3ep9nlypwn43swv75zwv6lgl3wgsmha20g87p', 'amount': '0.00000000', 'labels': 'new'}]}, {'branch': "internal addresses\tm/84'/1'/1'/1\t", 'balance': '0.09380968', 'entries': [{'hd_path': "m/84'/1'/1'/1/44", 'address': 'tb1qgmgpk22ueq9xk8f722aqjnuwd6s3jv58nwwan2', 'amount': '0.00009631', 'labels': 'non-cj-change'}, {'hd_path': "m/84'/1'/1'/1/49", 'address': 'tb1qjq86y8nzvafv5dsde93zf0emv7yrsphvupv69e', 'amount': '0.00013383', 'labels': 'non-cj-change'}, {'hd_path': "m/84'/1'/1'/1/54", 'address': 'tb1q7lvxk407xs38t24hfzy7vprp9t7tfsemv4rfym', 'amount': '0.00371951', 'labels': 'non-cj-change'}, {'hd_path': "m/84'/1'/1'/1/56", 'address': 'tb1qn2azshrkcg0d7py5apgfr0jh29nt9w2fmx9fyy', 'amount': '0.08986003', 'labels': 'non-cj-change'}]}, {'branch': 'Imported keys\tm/0\t', 'balance': '0.00000000', 'entries': [{'hd_path': 'imported/1/0', 'address': 'tb1q8znprh8c85za3mpwzn3qf9m0vwqzjkfu4qdncy', 'amount': '0.00000000', 'labels': 'empty'}, {'hd_path': 'imported/1/1', 'address': 'tb1qu4ajg3enea90xxtjuwcurj3d6lkqrud8p7w0yu', 'amount': '0.00000000', 'labels': 'empty'}, {'hd_path': 'imported/1/2', 'address': 'tb1qg7saqx69yalcqshfr8mjndy0gpx2umxrwqs823', 'amount': '0.00000000', 'labels': 'empty'}]}]}, {'account': '2', 'account_balance': '0.05600000', 'branches': [{'branch': "external addresses\tm/84'/1'/2'/0\ttpubDF8K7wXCrRXX1CQLVZGwMvEg9YEWF2VRpM1tjCwpMZDRRqKjpJ5YaeaDaLkqN1D7YM4pkX32FcCnosbhLQz2BgRiPNNdybWuvSBKp72mJsJ", 'balance': '0.00000000', 'entries': [{'hd_path': "m/84'/1'/2'/0/0", 'address': 'tb1qw95x9m84t6hqcun560vqfk3yc6ptl4g9arsty0', 'amount': '0.00000000', 'labels': 'new'}, {'hd_path': "m/84'/1'/2'/0/1", 'address': 'tb1qek4humez7rcwl53ly6uzr4mfwd0s2lu92e356q', 'amount': '0.00000000', 'labels': 'new'}, {'hd_path': "m/84'/1'/2'/0/2", 'address': 'tb1qxne4hyyeq2vrh0dfzs56th29qsymp9eq5pljdc', 'amount': '0.00000000', 'labels': 'new'}, {'hd_path': "m/84'/1'/2'/0/3", 'address': 'tb1qz3jk544j5vtwztznxfdwfgt8zcw77mjcut8vdz', 'amount': '0.00000000', 'labels': 'new'}, {'hd_path': "m/84'/1'/2'/0/4", 'address': 'tb1qg902humlsuc5s6aua6ew3d893hlgcxr05ntpyd', 'amount': '0.00000000', 'labels': 'new'}, {'hd_path': "m/84'/1'/2'/0/5", 'address': 'tb1qukz3l34ydy9snq8rkjaknk0ns04kfnlh34neqd', 'amount': '0.00000000', 'labels': 'new'}]}, {'branch': "internal addresses\tm/84'/1'/2'/1\t", 'balance': '0.05600000', 'entries': [{'hd_path': "m/84'/1'/2'/1/1", 'address': 'tb1qrtz5cwpneheg2v2v32wzc3h9yv0rzplxjtx9vc', 'amount': '0.00800000', 'labels': 'non-cj-change'}, {'hd_path': "m/84'/1'/2'/1/2", 'address': 'tb1qp4276g23y2w8g3367de25ustxkygjydmwk4fw2', 'amount': '0.00800000', 'labels': 'non-cj-change'}, {'hd_path': "m/84'/1'/2'/1/3", 'address': 'tb1qtqgvw445807tzcm8yhq6xgu3vmdfh66czx8jea', 'amount': '0.00800000', 'labels': 'non-cj-change'}, {'hd_path': "m/84'/1'/2'/1/4", 'address': 'tb1qxj7ulxdthe0dwxr5457p5d0w5u3jg7rwmc05pm', 'amount': '0.02400000', 'labels': 'non-cj-change'}, {'hd_path': "m/84'/1'/2'/1/5", 'address': 'tb1qv3kfe9ew42z0ldncgzmqcjznatsxz0vudvcjrv', 'amount': '0.00800000', 'labels': 'non-cj-change'}]}]}, {'account': '3', 'account_balance': '0.00000000', 'branches': [{'branch': "external addresses\tm/84'/1'/3'/0\ttpubDE9VN56aLW9BurCxHHGAWidSnVuU86ZsKPYQgxpTgkZxbogJYfj1vWJbtYip7WV5REcgmtjETb5eShXV8VUBzvCAMzuRm5Kv4ZGnnCiX6Jg", 'balance': '0.00000000', 'entries': [{'hd_path': "m/84'/1'/3'/0/0", 'address': 'tb1qp2w6ezmqn8nk9kc4gkpetgjj2mzqgp5x3hk86m', 'amount': '0.00000000', 'labels': 'new'}, {'hd_path': "m/84'/1'/3'/0/1", 'address': 'tb1qd0tt93aulqs508mtap5p8gls5z57fqa4ggnfx7', 'amount': '0.00000000', 'labels': 'new'}, {'hd_path': "m/84'/1'/3'/0/2", 'address': 'tb1qsp4hv46vgz4yjwt4p2wekh2gfmek7vgznrnd96', 'amount': '0.00000000', 'labels': 'new'}, {'hd_path': "m/84'/1'/3'/0/3", 'address': 'tb1qvs322uyrwh7a74dsxel0xcrgucm27c6dzdmj9j', 'amount': '0.00000000', 'labels': 'new'}, {'hd_path': "m/84'/1'/3'/0/4", 'address': 'tb1qnq9uk9azs9s7m5474ws7z7wxnwv3s3lxrtjter', 'amount': '0.00000000', 'labels': 'new'}, {'hd_path': "m/84'/1'/3'/0/5", 'address': 'tb1q5tlq36q6ps0m9zu6h08gd3azsgkgvm73sjcmxw', 'amount': '0.00000000', 'labels': 'new'}]}, {'branch': "internal addresses\tm/84'/1'/3'/1\t", 'balance': '0.00000000', 'entries': []}]}, {'account': '4', 'account_balance': '0.00000000', 'branches': [{'branch': "external addresses\tm/84'/1'/4'/0\ttpubDE6QfTimeNgCFSYuxPPaLc1Cp3VokAuJAusYoiGwWtVHVtQDsepf5dRAFNLWMwpBCgKDYkXdWGs2JspxXPokrtooPh7db5fniqYbdKGqD4F", 'balance': '0.00000000', 'entries': [{'hd_path': "m/84'/1'/4'/0/3", 'address': 'tb1qr2llfup6cnh27n77nm7egcyf9r7c0ykucrcu8k', 'amount': '0.00000000', 'labels': 'new'}, {'hd_path': "m/84'/1'/4'/0/4", 'address': 'tb1qahqjnd2y8j770l2m4kpf4fyfve9425c0zdumms', 'amount': '0.00000000', 'labels': 'new'}, {'hd_path': "m/84'/1'/4'/0/5", 'address': 'tb1q0jm0cxwcm2g60489fvtmeeaf7mzg658t8f8fk4', 'amount': '0.00000000', 'labels': 'new'}, {'hd_path': "m/84'/1'/4'/0/6", 'address': 'tb1qtpm5putpkzmrmecden0yytuuk4n9emhvxwqu8m', 'amount': '0.00000000', 'labels': 'new'}, {'hd_path': "m/84'/1'/4'/0/7", 'address': 'tb1qn60fc04pmprn9wpzkt0dnt80awu0rpy99w376g', 'amount': '0.00000000', 'labels': 'new'}, {'hd_path': "m/84'/1'/4'/0/8", 'address': 'tb1qakvrpp2hd3a3303zx7w2shmvfc7tqk28pwa9sj', 'amount': '0.00000000', 'labels': 'new'}]}, {'branch': "internal addresses\tm/84'/1'/4'/1\t", 'balance': '0.00000000', 'entries': []}]}]}
```
In addition to the above, a websocket service currently allowing subscription only to transaction events, is provided, see next.

<a name="websocket" />

Expand Down
Loading

0 comments on commit b527bbb

Please sign in to comment.