Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

initial draft of ledger API #90

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
212 changes: 212 additions & 0 deletions 0012-ledger-web-api/0012-ledger-web-api.md
@@ -0,0 +1,212 @@
# Ledger Web API

This spec defines some guidelines for **RESTful ledger APIs** to easily integrate with the Interledger Protocol suite.

The advantages of following this spec when designing a ledger are:
- A standardized interface for inter-ledger communication
- Easy adoption by connectors that implement the standard Web client (Example: `ilp-plugin-web`)

<p align="center">
<img width="70%" height="70%" src ="./static/ilp_interface.png" />
</p>

## Requirements

In order for ledgers to integrate seamlessly with connectors the ledger needs to provide:
- a RESTful HTTP API with endpoints to initiate `transfers` and submit `fulfillments`
- PUSH notifications to notify connectors of changes in the ledger objects and incoming transfers or fulfillments.
This could be through websockets, long-polling (EPOLL), or server-sent events.

TODO: define types (uuid, base58, base64, URI, ...)

## RESTful API Methods

### Authorization

TODO: explain how it works

### Ledger Metadata

#### Retrieve Metadata

Retrieve some metadata about the ledger.

##### Request
```http
GET / HTTP/1.1
Host: ledger.example
Authorization: <token>/<cert>/<password>/...
Content-Type: application/json
```

##### Response
```http
HTTP/1.1 200 OK
{
"precision": <int>,
"scale": <int>,
"currencyCode": <string: optional>,
"currencySymbol": <string: optional>
}
```

For a detailed description of these properties, please see [`LedgerInfo`](https://github.com/interledger/rfcs/blob/master/0004-ledger-plugin-interface/0004-ledger-plugin-interface.md#class-ledgerinfo).

### Accounts

`TODO:` Account should be inline with the [ILP address specification](https://github.com/interledger/rfcs/blob/master/0004-ledger-plugin-interface/0004-ledger-plugin-interface.md#getaccount)

#### Retrieve account

##### Request
```http
GET /accounts/<uuid: ID> HTTP/1.1
Host: ledger.example
Authorization: <token>/<cert>/<password>/...
Content-Type: application/json
```

##### Response
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be useful to explain what the fields are in the responses. Maybe just a placeholder for now?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean the object structure and field types?
Or something more general?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean the object structure and field types?

Yeah

```http
HTTP/1.1 200 OK
{
"ledger": <uri>,
"name": <string: optional>,
"connector": <uri: optional>
}
```

`TODO:` define the fields
`TODO:` is the connector field required? Should the ledger be connector-agnostic?

#### Update account

##### Request
```http
PUT /accounts/<uuid: ID> HTTP/1.1
Host: ledger.example
Authorization: <token>/<cert>/<password>/...
Content-Type: application/json
Body:
{
"connector": <uri>,
"name": <string: optional>
}
```

`TODO:` define the fields
`TODO:` is the connector field required? Should the ledger be connector-agnostic?

##### Response
```http
HTTP/1.1 200 OK
{
"ledger": <uri>,
"name": <string>,
"connector": <uri>
}
```

#### Retrieve account balance

Return a decimal string representing the current balance.

##### Request
```http
GET /accounts/<uuid: ID>/balance HTTP/1.1
Host: ledger.example
Authorization: <token>/<cert>/<password>/...
Content-Type: application/json
```

##### Response
```http
HTTP/1.1 200 OK
{
"balance": <float>
}
```

### Transfers

Transfer payloads and responses need to conform to the [`Transfer` class](https://github.com/interledger/rfcs/blob/master/0004-ledger-plugin-interface/0004-ledger-plugin-interface.md#class-transfer).

#### Retrieve transfer item

##### Request
```http
GET /transfers/<uuid|base58: ID> HTTP/1.1
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the motivation for the base58 (think we should standardize on UUID for this API. If the underlying ledger uses something else then it would probably need to maintain a mapping of one to the other.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this is a bit of a PITA. Many blockchains use base58 encodings of a hash (ie bitcoin, ethereum, multichain, bigchaindb, others). I don't think it will be possible to enforce this at the server side for most...

one idea was to have the clients/connectors or the plugins keep track of the mappings.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a ledger is exposing this interface then it was either built with this interface in mind or this interface is being hosted by an adaptor on top of the underlying ledger so in the case of ledgers like Bitcoin I'd say only the latter is possible. In this case I'd expect the adaptor to maintain the mappings.

The adaptor could probably do some clever stuff like write the UUID into the transfer memo so that it can find it from the underlying ledger later and not need to persist the mappings for long.

Host: ledger.example
Authorization: <token>/<cert>/<password>/...
Content-Type: application/json
```

##### Response
```http
HTTP/1.1 200 OK
{
"id": "<string: uuid|base58>",
"amount": "<string: decimal value>",
"debitAccount": "<string: ILP address>",
"creditAccount": "<string: ILP address>",
"data": "<JSON object>",
"noteToSelf": "<JSON object>",
"executionCondition": "<string: ILP condition URI>",
"expiresAt": "<string: ISO 8601 timestamp>
}
```

#### Create transfer item

##### Request
```http
POST /transfers/<uuid|base58: ID> HTTP/1.1
Host: ledger.example
Authorization: <token>/<cert>/<password>/...
Content-Type: application/json
Body:
{
"id": "<string: uuid|base58>",
"amount": "<string: decimal value>",
"debitAccount": "<string: ILP address>",
"creditAccount": "<string: ILP address>",
"data": "<JSON object>",
"noteToSelf": "<JSON object>",
"executionCondition": "<string: ILP condition URI>",
"expiresAt": "<string: ISO 8601 timestamp>
}
```

##### Response
```http
HTTP/1.1 200 OK
```

#### Create/update fulfillment for transfer

##### Request
```http
PUT /transfers/<uuid|base58: ID>/fulfillment HTTP/1.1
Host: ledger.example
Authorization: <token>/<cert>/<password>/...
Content-Type: application/json
Body:
{
"fulfillment" : "<string: ILP fulfillment URI>"
}
```

##### Response
```http
HTTP/1.1 200 OK
```

## PUSH notifications (websockets)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will need to define what these messages would look like? Just JSON objects?


The emitted events of the ledger should include the [LedgerPlugin events](https://github.com/interledger/rfcs/blob/master/0004-ledger-plugin-interface/0004-ledger-plugin-interface.md#events)

#### Open

```
uri: ws://ledger.example/<uuid: accountID>/transfers
```
Binary file added 0012-ledger-web-api/static/ilp_interface.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.