Diff
Not logged in

Differences From Artifact [a4b120450a]:

To Artifact [3d251bcce4]:


66
67
68
69
70
71
72







73
74
75
76
77
78
79
80
81
82
83
84
...
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223


224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
...
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
...
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
...
433
434
435
436
437
438
439








440
441
442
443
444
445
446
...
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555






556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
...
602
603
604
605
606
607
608
609

Each ILSP needs to have one or more connectors to route the ILP packets from its customers to the Interledger and vice versa.

Some ILSPs are simply customers of a larger ILSP. Others are so-called tier-1 ILSPs. Tier-1 ILSPs have a special responsibility, they provide routing services for the network.

This implementation of the connector contains a routing protocol implementation for tier-1 connectors. Please note that in order to become a tier-1 connector you need to have a relationship with one or more existing tier-1 connectors and they need to trust you not to overwhelm them with traffic or harbor malicious customers on your network.








## Quickstart

```sh
npm install -g ilp-connector ilp-plugin-btp
CONNECTOR_STORE_PATH=~/.connector-data CONNECTOR_ACCOUNTS='{}' CONNECTOR_ILP_ADDRESS=test.quickstart ilp-connector
```

You are now running a connector!

##### What's next?

* [Connect your connector to the Interledger](#connect-your-connector-to-the-interledger)
................................................................................

#### `accounts`

* Environment: `CONNECTOR_ACCOUNTS`
* Type: `object`
* Default: `{}`

| Name                          | Type    | Description                                                                                                                                                                                                                                                                                                                                                                             |
| ----------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `*`                           | object  | Description of individual account.                                                                                                                                                                                                                                                                                                                                                      |
| `*.relation`                  | string  | Relationship between the connector and the counterparty that the account is with.                                                                                                                                                                                                                                                                                                       |
| `*.plugin`                    | string  | Name of the ILP plugin that should be used for this account.                                                                                                                                                                                                                                                                                                                            |
| `*.assetCode`                 | string  | Currency code or other asset identifier that will be passed to the backend to select the correct rate for this account.                                                                                                                                                                                                                                                                 |
| `*.assetScale`                | integer | Interledger amounts are integers, but most currencies are typically represented as fractional units, e.g. cents. This property defines how many Interledger units make up one regular units. For dollars, this would usually be set to 9, so that Interledger amounts are expressed in nanodollars.                                                                                     |
| `*.balance`                   | object  | _Optional_ Defines whether the connector should maintain and enforce a balance for this account. The balance is always from the connector's perspective. Therefore, a negative balance implies the connector owes money to the counterparty and a positive balance implies the counterparty owes money to the connector. This setting is enforced by the built-in `balance` middleware. |
| `*.balance.maximum`           | string  | Maximum balance (in this account's indivisible base units) the connector will allow. The connector will reject incoming packets if they would put it above this balance. The format is a string containing an integer (which may be prefixed with `-` to indicate a negative value), `"-Infinity"` or `"Infinity"`.                                                                     |
| `*.balance.minimum`           | string  | _Optional_ Minimum balance (in this account's indivisible base units) the connector must maintain. The connector will reject outgoing packets if they would put it below this balance. The format is a string containing an integer (which may be prefixed with `-` to indicate a negative value), `"-Infinity"` or `"Infinity"`.                                                       |
| `*.balance.settleThreshold`   | string  | _Optional_ Balance (in this account's indivisible base units) numerically below which the connector will automatically initiate a settlement. The format is a string containing an integer (which may be prefixed with `-` to indicate a negative value) or `"-Infinity"`.                                                                                                              |
| `*.balance.settleTo`          | string  | _Optional_ Balance (in this account's indivisible base units) the connector will attempt to reach when settling. The format is an integer (which may be prefixed with `-` to indicate a negative value) as a string.                                                                                                                                                                    |


| `*.ilpAddressSegment`         | string  | _Optional_ What segment will be appended to the connector's ILP address to form this account's ILP address. Only applicable to accounts with `relation=child`. Defaults to the id of the account, i.e. the key used in the `accounts` config object.                                                                                                                                    |
| `*.maxPacketAmount`           | string  | _Optional_ Maximum amount per packet for incoming prepare packets. Connector will reject any incoming prepare packets from this account with a higher amount. Amount should be provided as an integer in a string (in atomic units). This setting is enforced by the built-in `maxPacketAmount` middleware.                                                                             |
| `*.options.*`                 | object  | _Optional_                                                                                                                                                                                                                                                                                                                                                                              |
| `*.rateLimit`                 | object  | _Optional_ Maximum rate of incoming packets. Limit is implemented as a token bucket with a constant refill rate. When the token bucket is empty, all requests are immediately rejected. This setting is enforced by the built-in `rateLimit` middleware.                                                                                                                                |
| `*.rateLimit.capacity`        | integer | _Optional_ Maximum number of tokens in the bucket.                                                                                                                                                                                                                                                                                                                                      |
| `*.rateLimit.refillCount`     | integer | _Optional_ How many tokens are refilled per period. The default refill period is one second, so this would be the average number of requests per second.                                                                                                                                                                                                                                |
| `*.rateLimit.refillPeriod`    | integer | _Optional_ Length of time (in milliseconds) during which the token balance increases by `refillCount` tokens. Defaults to one second.                                                                                                                                                                                                                                                   |
| `*.receiveRoutes`             | boolean | _Optional_ Whether we should receive and process route broadcasts from this peer. Defaults to `false` for `relation=child` and `true` otherwise.                                                                                                                                                                                                                                        |
| `*.sendRoutes`                | boolean | _Optional_ Whether we should broadcast routes to this peer. Defaults to `false` for `relation=child` and `true` otherwise.                                                                                                                                                                                                                                                              |
| `*.throughput`                | object  | _Optional_ Configuration to limit the total amount sent via Interledger per unit of time. This setting is enforced by the built-in `throughput` middleware.                                                                                                                                                                                                                             |
| `*.throughput.incomingAmount` | string  | _Optional_ Maximum incoming throughput amount (in atomic units; per second) for incoming packets. If this setting is not set, the incoming throughput limit is disabled.                                                                                                                                                                                                                |
| `*.throughput.outgoingAmount` | string  | _Optional_ Maximum throughput amount (in atomic units; per second) for outgoing packets. If this setting is not set, the outgoing throughput limit is disabled.                                                                                                                                                                                                                         |
| `*.throughput.refillPeriod`   | integer | _Optional_ Length of time (in milliseconds) during which the token balance increases by `incomingAmount`/`outgoingAmount` tokens. Defaults to one second.                                                                                                                                                                                                                               |

#### `defaultRoute`

* Environment: `CONNECTOR_DEFAULT_ROUTE`
* Type: `string`
* Default: `"auto"`

................................................................................

* Environment: `CONNECTOR_ROUTE_EXPIRY`
* Type: `integer`
* Default: `45000`

The maximum age of a route provided by this connector. (in milliseconds)

#### `quoteExpiry`

* Environment: `CONNECTOR_QUOTE_EXPIRY`
* Type: `integer`
* Default: `45000`

The maximum age of a quote provided by this connector. (in milliseconds)

#### `routingSecret`

* Environment: `CONNECTOR_ROUTING_SECRET`
* Type: `string`
* Default: `""`

Seed used for generating routing table auth values.

#### `backend`

* Environment: `CONNECTOR_BACKEND`
* Type: `string`
* Default: `"fixerio"`

Name of the backend (can be built-in or a require-able module name). Built-in modules are: fixerio, fixerio-plus-xrp, fixerio-plus-coinmarketcap, one-to-one

#### `backendConfig`

* Environment: `CONNECTOR_BACKEND_CONFIG`
* Type: `object`
* Default: `{}`

................................................................................
* Type: `array`
* Default: `[]`

| Name | Type   | Description                           |
| ---- | ------ | ------------------------------------- |
| `[]` | string | Name of the middleware to be removed. |

#### `broadcastCurves`

* Environment: `CONNECTOR_BROADCAST_CURVES`
* Type: `boolean`
* Default: `true`

Whether to include liquidity curves when broadcasting routes.

#### `reflectPayments`

* Environment: `CONNECTOR_REFLECT_PAYMENTS`
* Type: `boolean`
* Default: `true`

Whether to allow routing payments back to the account that sent them.
................................................................................

* Environment: `CONNECTOR_ADMIN_API_HOST`
* Type: `string`
* Default: `"127.0.0.1"`

Host to bind to. Warning: The admin API interface should never be made public! Default: '127.0.0.1'









### API Reference

### Extensibility: Plugins

Plugins represent different ways to link senders, receivers and connectors together. Most plugins use [Bilateral Transfer Protocol (BTP)](https://github.com/interledger/rfcs/blob/master/0023-bilateral-transfer-protocol/0023-bilateral-transfer-protocol.md) in order to communicate. The main differences between plugins are whether they are **multi-user** and which **settlement ledger** they use.

Multi-user plugins are plugins which connect to multiple counterparties, rather than just one. They are usually used as server-side plugins to serve a large number of clients. An example is [**ilp-plugin-mini-accounts**](https://github.com/interledgerjs/ilp-plugin-mini-accounts). Multi-user plugins actually contain a little mini connector internally which knows how to route packets to the correct client.
................................................................................

Pure in-memory store. Resets every time the connector is run. Useful for development and testing.

### Extensibility: Middlewares

#### Built-in: errorHandler

* Pipelines: incomingData, incomingMoney

First middleware in the pipeline. Handles any errors that occur anywhere else and converts them into ILP rejections.

The `errorHandler` middleware will check the thrown error for a field called `ilpErrorCode` which should contain a three-character ILP error code. Otherwise it uses `'F00'` by default. For the `message` it uses the error message and for `triggeredBy` the connector's address. If the error object has a field `ilpErrorData` which is a `Buffer`, it will also attach the provided data to the error. Otherwise, it will attach an empty `data` buffer.

#### Built-in: deduplicate

* Pipelines: outgoingData

Prevents sending duplicate packets which helps reduce the impact of routing loops.

This middleware keeps track of all prepared transfers. If there is a transfer with the same `destination`, `executionCondition`, `data` and an equal or greater `amount` and `expiresAt` already prepared, then we simply link the new packet to the existing packet's outcome. If a packet is being routed in a loop, it will fulfill these requirements, the loop will be terminated, and the packet will time out.

See also: <https://github.com/interledger/rfcs/issues/330#issuecomment-348750488>

#### Built-in: rateLimit

* Pipelines: incomingData, incomingMoney, outgoingData, outgoingMoney

Reduces the maximum number of total requests incoming from or outgoing to any account.

Used for basic rate limiting and to help with DoS.

#### Built-in: maxPacketAmount

* Pipelines: incomingData, outgoingData

Rejects packets with an amount greater than the specified value.

#### Built-in: throughput

* Pipelines: incomingData, outgoingData

Limits the throughput for a given account. Throughput is the amount of money transferred per time.

#### Built-in: balance

* Pipelines: incomingData, incomingMoney, outgoingData, outgoingMoney

Tracks the balance of a given account from the perspective of the connector. This is also the subsystem that triggers settlements.

#### Built-in: validateFulfillment

* Pipelines: outgoingData

Validates fulfillments in incoming ILP fulfill responses. If the fulfillment is invalid, it converts the fulfillment into a rejection.

#### Built-in: expire

* Pipelines: outgoingData

Expires outgoing ILP packets at their designated `expiresAt` time. Returns a rejection when this occurs.







### Extensibility: Backends

Backends provide fee policies and exchange rates. For a professionally run connector, just should create your own backend, using exchange rates that come directly from the exchange or broker where you plan to trade to re-balance your accounts.

#### Built-in: one-to-one

* Supported currencies: _any_

The `one-to-one` backend applies the `CONNECTOR_SPREAD` setting, the `assetScale` settings, and otherwise uses a 1:1 exchange rate for all assets. This is the simplest backend, recommended for connectors that deal in only one currency.

#### Built-in: fixerio

* Supported currencies: see [fixer.io](http://fixer.io/)

The `fixerio` backend loads fiat exchange rates from [fixer.io](http://fixer.io/). **Suitable for development and experimental use only.**

#### Built-in: fixerio-plus-xrp

* Supported currencies: see [fixer.io](http://fixer.io/), XRP

The `fixerio-plus-xrp` backend loads fiat exchange rates from [fixer.io](http://fixer.io/) and XRP exchange rates from the [Ripple Data API](https://ripple.com/build/data-api-v2/). **Suitable for development and experimental use only.**

#### Built-in: fixerio-plus-coinmarketcap

* Supported currencies: see [fixer.io](http://fixer.io/), see [CoinMarketCap](https://coinmarketcap.com/)

The `fixerio-plus-coinmarketcap` backend loads fiat exchange rates from [fixer.io](http://fixer.io/) and crypto-currency exchange rates from [CoinMarketCap](https://coinmarketcap.com/). **Suitable for development and experimental use only.**

## Development

If you would like to contribute back to this project, please follow these steps:

#### Step 1: Clone repo

................................................................................

```sh
CONNECTOR_STORE_PATH=~/.connector-data CONNECTOR_ACCOUNTS='{}' CONNECTOR_ILP_ADDRESS=test.quickstart npm start
```

#### Step 4: Read the contributor guidelines

See [CONTRIBUTE.md](/CONTRIBUTE.md).







>
>
>
>
>
>
>




|







 







|
|
|
|
|
|
|
|
|
|
|
|
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|







 







<
<
<
<
<
<
<
<












|

|







 







<
<
<
<
<
<
<
<







 







>
>
>
>
>
>
>
>







 







|







|









|







|





|





|





|





|



>
>
>
>
>
>










|

|

|

|

|

|

|

|

|







 







|
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
...
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
...
316
317
318
319
320
321
322








323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
...
386
387
388
389
390
391
392








393
394
395
396
397
398
399
...
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
...
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
...
609
610
611
612
613
614
615
616

Each ILSP needs to have one or more connectors to route the ILP packets from its customers to the Interledger and vice versa.

Some ILSPs are simply customers of a larger ILSP. Others are so-called tier-1 ILSPs. Tier-1 ILSPs have a special responsibility, they provide routing services for the network.

This implementation of the connector contains a routing protocol implementation for tier-1 connectors. Please note that in order to become a tier-1 connector you need to have a relationship with one or more existing tier-1 connectors and they need to trust you not to overwhelm them with traffic or harbor malicious customers on your network.

## Timekeeping

Timekeeping is an important part of processing transactions. Your node must have the right time set to make sure it can handle packets from peers correctly. If you drift too far from the current time, your node will have a different time to your peers and might start to experience strange issues and/or accept/reject packets incorrectly. 

It is highly recommended you run some kind of time synchronisation service on your server. If you need help to install tools for keeping your clock in sync, this article describes how to do it:
https://www.techrepublic.com/blog/data-center/syncing-time-in-linux-and-windows-with-ntp/

## Quickstart

```sh
npm install -g ilp-connector ilp-plugin-btp
CONNECTOR_STORE_PATH=~/.connector-data CONNECTOR_ACCOUNTS='{}' CONNECTOR_ADMIN_API=true CONNECTOR_ILP_ADDRESS=test.quickstart ilp-connector
```

You are now running a connector!

##### What's next?

* [Connect your connector to the Interledger](#connect-your-connector-to-the-interledger)
................................................................................

#### `accounts`

* Environment: `CONNECTOR_ACCOUNTS`
* Type: `object`
* Default: `{}`

| Name                            | Type    | Description                                                                                                                                                                                                                                                                                                                                                                             |
| ------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `*`                             | object  | Description of individual account.                                                                                                                                                                                                                                                                                                                                                      |
| `*.relation`                    | string  | Relationship between the connector and the counterparty that the account is with.                                                                                                                                                                                                                                                                                                       |
| `*.plugin`                      | string  | Name or instance of the ILP plugin that should be used for this account. A plugin instance can only be passed when instantiating the connector from JavaScript.                                                                                                                                                                                                                         |
| `*.assetCode`                   | string  | Currency code or other asset identifier that will be passed to the backend to select the correct rate for this account.                                                                                                                                                                                                                                                                 |
| `*.assetScale`                  | integer | Interledger amounts are integers, but most currencies are typically represented as fractional units, e.g. cents. This property defines how many Interledger units make up one regular units. For dollars, this would usually be set to 9, so that Interledger amounts are expressed in nanodollars.                                                                                     |
| `*.balance`                     | object  | _Optional_ Defines whether the connector should maintain and enforce a balance for this account. The balance is always from the connector's perspective. Therefore, a negative balance implies the connector owes money to the counterparty and a positive balance implies the counterparty owes money to the connector. This setting is enforced by the built-in `balance` middleware. |
| `*.balance.maximum`             | string  | Maximum balance (in this account's indivisible base units) the connector will allow. The connector will reject incoming packets if they would put it above this balance. The format is a string containing an integer (which may be prefixed with `-` to indicate a negative value), `"-Infinity"` or `"Infinity"`.                                                                     |
| `*.balance.minimum`             | string  | _Optional_ Minimum balance (in this account's indivisible base units) the connector must maintain. The connector will reject outgoing packets if they would put it below this balance. The format is a string containing an integer (which may be prefixed with `-` to indicate a negative value), `"-Infinity"` or `"Infinity"`.                                                       |
| `*.balance.settleThreshold`     | string  | _Optional_ Balance (in this account's indivisible base units) numerically below which the connector will automatically initiate a settlement. The format is a string containing an integer (which may be prefixed with `-` to indicate a negative value) or `"-Infinity"`.                                                                                                              |
| `*.balance.settleTo`            | string  | _Optional_ Balance (in this account's indivisible base units) the connector will attempt to reach when settling. The format is an integer (which may be prefixed with `-` to indicate a negative value) as a string.                                                                                                                                                                    |
| `*.deduplicate.cleanupInterval` | integer | _Optional_ Frequency at which the connector removes old deduplicate records. (in milliseconds; defaults to 30 seconds)                                                                                                                                                                                                                                                                  |
| `*.deduplicate.packetLifetime`  | integer | _Optional_ Lifetime of a cache record. (in milliseconds; defaults to 30 seconds)                                                                                                                                                                                                                                                                                                        |
| `*.ilpAddressSegment`           | string  | _Optional_ What segment will be appended to the connector's ILP address to form this account's ILP address. Only applicable to accounts with `relation=child`. Defaults to the id of the account, i.e. the key used in the `accounts` config object.                                                                                                                                    |
| `*.maxPacketAmount`             | string  | _Optional_ Maximum amount per packet for incoming prepare packets. Connector will reject any incoming prepare packets from this account with a higher amount. Amount should be provided as an integer in a string (in atomic units). This setting is enforced by the built-in `maxPacketAmount` middleware.                                                                             |
| `*.options.*`                   | object  | _Optional_                                                                                                                                                                                                                                                                                                                                                                              |
| `*.rateLimit`                   | object  | _Optional_ Maximum rate of incoming packets. Limit is implemented as a token bucket with a constant refill rate. When the token bucket is empty, all requests are immediately rejected. This setting is enforced by the built-in `rateLimit` middleware.                                                                                                                                |
| `*.rateLimit.capacity`          | integer | _Optional_ Maximum number of tokens in the bucket.                                                                                                                                                                                                                                                                                                                                      |
| `*.rateLimit.refillCount`       | integer | _Optional_ How many tokens are refilled per period. The default refill period is one second, so this would be the average number of requests per second.                                                                                                                                                                                                                                |
| `*.rateLimit.refillPeriod`      | integer | _Optional_ Length of time (in milliseconds) during which the token balance increases by `refillCount` tokens. Defaults to one second.                                                                                                                                                                                                                                                   |
| `*.receiveRoutes`               | boolean | _Optional_ Whether we should receive and process route broadcasts from this peer. Defaults to `false` for `relation=child` and `true` otherwise.                                                                                                                                                                                                                                        |
| `*.sendRoutes`                  | boolean | _Optional_ Whether we should broadcast routes to this peer. Defaults to `false` for `relation=child` and `true` otherwise.                                                                                                                                                                                                                                                              |
| `*.throughput`                  | object  | _Optional_ Configuration to limit the total amount sent via Interledger per unit of time. This setting is enforced by the built-in `throughput` middleware.                                                                                                                                                                                                                             |
| `*.throughput.incomingAmount`   | string  | _Optional_ Maximum incoming throughput amount (in atomic units; per second) for incoming packets. If this setting is not set, the incoming throughput limit is disabled.                                                                                                                                                                                                                |
| `*.throughput.outgoingAmount`   | string  | _Optional_ Maximum throughput amount (in atomic units; per second) for outgoing packets. If this setting is not set, the outgoing throughput limit is disabled.                                                                                                                                                                                                                         |
| `*.throughput.refillPeriod`     | integer | _Optional_ Length of time (in milliseconds) during which the token balance increases by `incomingAmount`/`outgoingAmount` tokens. Defaults to one second.                                                                                                                                                                                                                               |

#### `defaultRoute`

* Environment: `CONNECTOR_DEFAULT_ROUTE`
* Type: `string`
* Default: `"auto"`

................................................................................

* Environment: `CONNECTOR_ROUTE_EXPIRY`
* Type: `integer`
* Default: `45000`

The maximum age of a route provided by this connector. (in milliseconds)









#### `routingSecret`

* Environment: `CONNECTOR_ROUTING_SECRET`
* Type: `string`
* Default: `""`

Seed used for generating routing table auth values.

#### `backend`

* Environment: `CONNECTOR_BACKEND`
* Type: `string`
* Default: `"ecb"`

Name of the backend (can be built-in or a require-able module name). Built-in modules are: ecb, ecb-plus-xrp, ecb-plus-coinmarketcap, one-to-one

#### `backendConfig`

* Environment: `CONNECTOR_BACKEND_CONFIG`
* Type: `object`
* Default: `{}`

................................................................................
* Type: `array`
* Default: `[]`

| Name | Type   | Description                           |
| ---- | ------ | ------------------------------------- |
| `[]` | string | Name of the middleware to be removed. |









#### `reflectPayments`

* Environment: `CONNECTOR_REFLECT_PAYMENTS`
* Type: `boolean`
* Default: `true`

Whether to allow routing payments back to the account that sent them.
................................................................................

* Environment: `CONNECTOR_ADMIN_API_HOST`
* Type: `string`
* Default: `"127.0.0.1"`

Host to bind to. Warning: The admin API interface should never be made public! Default: '127.0.0.1'

#### `collectDefaultMetrics`

* Environment: `CONNECTOR_COLLECT_DEFAULT_METRICS`
* Type: `boolean`
* Default: `false`

Whether the Prometheus exporter should include system metrics or not. Default: false (no)

### API Reference

### Extensibility: Plugins

Plugins represent different ways to link senders, receivers and connectors together. Most plugins use [Bilateral Transfer Protocol (BTP)](https://github.com/interledger/rfcs/blob/master/0023-bilateral-transfer-protocol/0023-bilateral-transfer-protocol.md) in order to communicate. The main differences between plugins are whether they are **multi-user** and which **settlement ledger** they use.

Multi-user plugins are plugins which connect to multiple counterparties, rather than just one. They are usually used as server-side plugins to serve a large number of clients. An example is [**ilp-plugin-mini-accounts**](https://github.com/interledgerjs/ilp-plugin-mini-accounts). Multi-user plugins actually contain a little mini connector internally which knows how to route packets to the correct client.
................................................................................

Pure in-memory store. Resets every time the connector is run. Useful for development and testing.

### Extensibility: Middlewares

#### Built-in: errorHandler

* Pipelines: `incomingData`, `incomingMoney`

First middleware in the pipeline. Handles any errors that occur anywhere else and converts them into ILP rejections.

The `errorHandler` middleware will check the thrown error for a field called `ilpErrorCode` which should contain a three-character ILP error code. Otherwise it uses `'F00'` by default. For the `message` it uses the error message and for `triggeredBy` the connector's address. If the error object has a field `ilpErrorData` which is a `Buffer`, it will also attach the provided data to the error. Otherwise, it will attach an empty `data` buffer.

#### Built-in: deduplicate

* Pipelines: `startup`, `teardown`, `outgoingData`

Prevents sending duplicate packets which helps reduce the impact of routing loops.

This middleware keeps track of all prepared transfers. If there is a transfer with the same `destination`, `executionCondition`, `data` and an equal or greater `amount` and `expiresAt` already prepared, then we simply link the new packet to the existing packet's outcome. If a packet is being routed in a loop, it will fulfill these requirements, the loop will be terminated, and the packet will time out.

See also: <https://github.com/interledger/rfcs/issues/330#issuecomment-348750488>

#### Built-in: rateLimit

* Pipelines: `incomingData`, `incomingMoney`, `outgoingData`, `outgoingMoney`

Reduces the maximum number of total requests incoming from or outgoing to any account.

Used for basic rate limiting and to help with DoS.

#### Built-in: maxPacketAmount

* Pipelines: `incomingData`, `outgoingData`

Rejects packets with an amount greater than the specified value.

#### Built-in: throughput

* Pipelines: `incomingData`, `outgoingData`

Limits the throughput for a given account. Throughput is the amount of money transferred per time.

#### Built-in: balance

* Pipelines: `startup`, `incomingData`, `incomingMoney`, `outgoingData`, `outgoingMoney`

Tracks the balance of a given account from the perspective of the connector. This is also the subsystem that triggers settlements.

#### Built-in: validateFulfillment

* Pipelines: `outgoingData`

Validates fulfillments in incoming ILP fulfill responses. If the fulfillment is invalid, it converts the fulfillment into a rejection.

#### Built-in: expire

* Pipelines: `outgoingData`

Expires outgoing ILP packets at their designated `expiresAt` time. Returns a rejection when this occurs.

#### Built-in: stats

* Pipelines: `incomingData`, `incomingMoney`, `outgoingData`, `outgoingMoney`

Tracks throughput by account. Results are accessible through the admin API.

### Extensibility: Backends

Backends provide fee policies and exchange rates. For a professionally run connector, just should create your own backend, using exchange rates that come directly from the exchange or broker where you plan to trade to re-balance your accounts.

#### Built-in: one-to-one

* Supported currencies: _any_

The `one-to-one` backend applies the `CONNECTOR_SPREAD` setting, the `assetScale` settings, and otherwise uses a 1:1 exchange rate for all assets. This is the simplest backend, recommended for connectors that deal in only one currency.

#### Built-in: ecb

* Supported currencies: see [Euro foreign exchange reference rates](http://www.ecb.europa.eu/stats/policy_and_exchange_rates/euro_reference_exchange_rates/html/index.en.html)

The `ecb` backend loads fiat exchange rates from [Euro foreign exchange reference rates](http://www.ecb.europa.eu/stats/policy_and_exchange_rates/euro_reference_exchange_rates/html/index.en.html). **Suitable for development and experimental use only.**

#### Built-in: ecb-plus-xrp

* Supported currencies: see [Euro foreign exchange reference rates](http://www.ecb.europa.eu/stats/policy_and_exchange_rates/euro_reference_exchange_rates/html/index.en.html), XRP

The `ecb-plus-xrp` backend loads fiat exchange rates from [Euro foreign exchange reference rates](http://www.ecb.europa.eu/stats/policy_and_exchange_rates/euro_reference_exchange_rates/html/index.en.html) and XRP exchange rates from the [Ripple Data API](https://ripple.com/build/data-api-v2/). **Suitable for development and experimental use only.**

#### Built-in: ecb-plus-coinmarketcap

* Supported currencies: see [Euro foreign exchange reference rates](http://www.ecb.europa.eu/stats/policy_and_exchange_rates/euro_reference_exchange_rates/html/index.en.html), see [CoinMarketCap](https://coinmarketcap.com/)

The `ecb-plus-coinmarketcap` backend loads fiat exchange rates from [Euro foreign exchange reference rates](http://www.ecb.europa.eu/stats/policy_and_exchange_rates/euro_reference_exchange_rates/html/index.en.html) and crypto-currency exchange rates from [CoinMarketCap](https://coinmarketcap.com/). **Suitable for development and experimental use only.**

## Development

If you would like to contribute back to this project, please follow these steps:

#### Step 1: Clone repo

................................................................................

```sh
CONNECTOR_STORE_PATH=~/.connector-data CONNECTOR_ACCOUNTS='{}' CONNECTOR_ILP_ADDRESS=test.quickstart npm start
```

#### Step 4: Read the contributor guidelines

See [CONTRIBUTING.md](/CONTRIBUTING.md).