# Java Connector

A Java implementation of an Interledger Connector supporting ILPv4.

This site contains documentation for the Java implementation of an Interledger Connector.

**Github project source code**: <https://github.com/interledger4j/ilpv4-connector>\
**Docs source code**: <https://github.com/interledger4j/java-ilpv4-connector-docs>\
**Documentation Website**: <https://connector.interledger4j.dev/>

## Feature request?

Have an idea or a feature request for the ILP Connector? We'd love to hear about it! Submit your ideas/requests/etc on [feedback.interledger4j.dev](https://feedback.interledger4j.dev).

## Overview

This implementation is a high-performance Interledger Connector that supports *many* incoming and outgoing connections that are tied together by an ILPv4 packet-switching fabric.&#x20;

This implementation supports the following features:

* **ILPv4:** Interledger Protocol version for as defined in [IL-RFC-27](https://github.com/interledger/rfcs/blob/master/0027-interledger-protocol-4/0027-interledger-protocol-4.md).
* **ILDCP**: Interledger Dynamic Configuration Protocol as specified in [IL-RFC-31](https://github.com/interledger/rfcs/blob/master/0031-dynamic-configuration-protocol/0031-dynamic-configuration-protocol.md).
* **ILP-over-HTTP**: Allows for sending and receiving ILPv4 packets over HTTP as defined in [IL-RFC-30](https://github.com/interledger/rfcs/pull/504).
* **Route Broadcast Protocol**: Defines how Connectors can exchange routing table updates as defined in [Route Broadcast Protocol](https://github.com/interledger/rfcs/pull/455).
* **Balance Tracking**: Durably tracks account balance updates in a high-performance manner using [Redis](https://redis.io).
* **Persistent Data Storage**: Account and other data can be stored using Postgres, MySQL, Oracle, MSSQL, and more.

To learn more about how this implementation is designed, see [Connector Design](/concepts/architecture-design).

To contribute to this project read more in [Connector Development](/contributing/development).

## Disclaimer

**WARNING:&#x20;*****This implementation is currently an "alpha" prototype and SHOULD NOT be used in a production deployment!***


# Feature Summary

A Java ILP Connector forwards packets from source links to destination links; applies exchange-rates; and tracks value-balances between itself and each peer.

## Account Tracking

In order to efficiently forward ILPv4 packets between its Peers, a Connector must track these relationships. Read more about how this implementation tracks account relationships in [Account Model](/concepts/peering-account-model).

## Packet Switching

The primary sub-system in this connector is called a Packet Switch. This component filters incoming packets, ensures that each packet satisfies a variety of preconditions, and then forwards this packed to the appropriate outgoing link. Read more about this component in [Packet Switching Fabric](/concepts/packet-switching-fabric).

## Exchange Rates

Each link in this ILPv4 Connector tracks an account in a unique asset. In order to switch packets from one link to another, it is sometimes necessary to apply an exchange-rate. Read more about how this is accomplished in [Exchange Rates](/concepts/exchange-rates).

## Balance Tracking

Each link this this Connector also tracks real-time debt positions between the Connector itself and any peer. Read more about this in [Balance Tracking](/concepts/balance-tracking).


# Terminology

Words, words, words...let's all get on the same page.

**Account**\
Interledger supports transactions on any type of fungible asset, and uses *accounts* to track debt positions  in a particular asset between two parties. Accounts are always denominated in a single, mutually agreed upon asset type and only ever include two parties.

**Account Assets**\
Asset types tracked in an account include any type of fungible asset. This includes fiat and crypto currencies like U.S. Dollars, Euros, Bitcoin, or XRP. Accounts are not limited to tracking currency, however, and can represent other fungible things like equities or commodities.

**Accounts Asset Identifiers**\
Interledger tracks assets using an identifier that can represent an asset. For example, `USD`, `EUR`, `BTC`, `XRP`or even stock symbols like `SBUX` or `AAPL`can be used. Interledger even supports contrived asset identifiers for specific use-cases, such as `WIDGET`.&#x20;

**Account Amounts**\
Each account includes a unit of account for the asset being tracked called an *amount*, which may be represented using any denomination. For example, one U.S. dollar may be represented as 1 USD or 100 cents, each of which is an equivalent unit of value. Likewise, one Bitcoin may be represented as 1 BTC or 100,000,000 satoshis.

**Account Standard Units**\
The **standard unit** represents the typical unit of account for a particular asset. For example $1 in the case of U.S. dollars, or 1 BTC in the case of Bitcoin.&#x20;

Note that peers are free to define this value in any way, but participants in an Interledger accounting relationship *must* be sure to use the same value. Thus, it is suggested to use *typical* values when possible.

**Account Fractional Units**\
A **fractional unit** represents some unit smaller than its corresponding standard unit, but with greater precision. Examples of fractional monetary units include one cent ($0.01 USD), or 1 satoshi (0.00000001 BTC).

**Account Scale**\
An **asset scale** is the difference, in orders of magnitude, between a **standard unit** and a corresponding **fractional unit**. More formally, the asset scale is a non-negative integer (0, 1, 2, …) such that one **standard unit** equals `10^(-scale)` of a corresponding **fractional unit**. If the fractional unit equals the standard unit, then the asset scale is 0.

For example, one "cent" represents an asset scale of 2 in the case of USD; 1 satoshi represents an asset scale of 8 in the case of Bitcoin; and 1 drop represents an asset scale of 6 in XRP.

**Account Balance**\
The total debt position between two peers represented in a particular fungible unit of account. Account balances can be tracked in arbitrary ways, although the two most common forms are bilateral (both parties track an independent view of the balance) or unilateral (one party tracks the balance for both sides of the Account).

**Account Balance Tracking (Bilateral)**\
A mechanism for tacking balances where both parties to an account track the balance independently, with the sum of both sides' balances always equaling zero.&#x20;

For example, this type of balance will always start off with each party having a balance of 0. If Alice Pays Bob 10 units, then Alice's balance tracker will show -10, whereas Bob's balance tracker will show +10.  If Bob then sends Alice 20 units, then Alice's balance tracker will show +10 and Bob's balance tracker will show -10.

**Account Balance Tracking (Unilateral)**\
A mechanism for tacking balances where only one party to an account tracks the balance for both parties. Generally speaking, the entity holding actual assets should be the party that tracks a unilateral account balance. As such, the unit of account on such a balance is an IOU payable from the balance tracking entity to the counterparty.

For example, if Alice tracks a balance for an account between herself and Bob, then a positive balance (e.g., 10 USD) indicates that Alice owes Bob $10. Conversely, a negative balance (e.g., -10 USD) indicates that Bob owes alice $10.

**Link**\
A connection between two peers, involving a single account, where ILPv4 packets can be exchanged over some network transport (such as a Websocket or a regular HTTP connection).

**Peer**\
Any entity that has agreed to exchange Interledger packets with another entity. This sometimes refers to two individuals who share an account. However, this can also refer to software programs that are connected to each other in a peering relationship. See **Peer Node** for more details.

**Peer Node**\
An Interledger sender, connector, or receiver that has an accounting relationship with another server.


# Account Model

Interledger Connectors track peer relationships using a concept called an Account.

Connector Accounts have two primary functions.&#x20;

The first is to track a debt position, denominated in a single fungible asset, between two Interledger parties (read more about this in [Balance Tracking](/concepts/balance-tracking)).&#x20;

The second purpose is to provide a conduit for exchanging ILP packets. When chained together to form a payment path, these relationships can enable value transfer across the Interledger.

When two Interledger nodes (two ILP Connectors, for example) enter into an account arrangement (sometimes called a Peering Relationship), each Connector will construct a unique identifier to track the relationship for itself. This implementation calls this identifier an `accoundId`.

Using account Ids, a Connector can correlate each details about the relationship using three different primitives (described below).&#x20;

This design is preferred over a single `Account` object because Connectors must be able to support ultra-high packet throughput, and using a single domain-model object would likely not scale well for all use-cases that a Connector must fulfill.

## Account Settings

The [`AccountsSettings`](https://github.com/interledger4j/ilpv4-connector/blob/master/connector-accounts/src/main/java/org/interledger/connector/accounts/AccountSettings.java) object tracks all information necessary for the Connector to *describe* an account. This includes minimum and balance thresholds, link information, and information about about the underlying asset for the account (i.e., the asset `code` and `scale`).

This data is typically stored in a durable data-store, and loaded at various times in a performant yet as-needed basis by the Connector. In general, account information is highly cacheable using local-caches with relatively short timeouts (which works well-enough across a cluster) so this type of information can easily live in a typical RDBMS. See [Connector Persistence](/ilpv4-connector-persistence) for more details around supported datastores.

## Balance Tracking

This implementation currently supports [Bilateral Balance Tracking](/concepts/terminology) to track balances for each account.&#x20;

In this configuration, each account holder should be thought of as holding discrete types of IOUs. For example, if Alice and Bob are tracking a bilateral balance in US Dollars, then from Alice's perspective the unit of account is called an "Alice Owes Bob Dollars" or `AOB`. From Bob's perspective, the unit of account is called a "Bob Owes Alice Dollars" or `BOA`.&#x20;

Balances on either side of the account can become positive or negative, but the sum total of both balances *must* always equal zero. Additionally, each balance-pair will always be the inverse of the other side's balance.&#x20;

Thus, if Alice has a balance of `-10` , then Bob *must* have a balance of `+10`, which means that Bob has 10 BOAs and Alice has -10 AOBs. In other words, Bob has a debt position with Alice in which he is holding 10 of her units, payable to Alice. Conversely, Alice has a lending position with Bob in which she has lent him 10 units (which he might not pay back). From Alice's perspective, she holds -10 AOBs, which is to say Alice holds -10 obligations to pay Bob $1 USD. Put into different language, this equates to Alice holding 10 obligations for Bob to pay her $1 USD.

Grokking the meaning of a bidirectional accounting relationship like this can be difficult. The simplest way to think about this is that generally two account holders are creating debt obligations between each other.

## Links

This implementation uses the concept of a [`Link`](https://github.com/sappenin/java-ilpv4-connector/blob/master/ilpv4-connector-link/src/main/java/org/interledger/connector/link/Link.java) to describe the connection between two peers. Links have their own identifier called a `LinkId` which uniquely identifies each Link.&#x20;

Because a Link is an abstraction over the connection between two peers, a Link can operate over any underlying transport. Examples of this include HTTP, WebSockets, UDP, or any other communications mechanism.

This implementation enforces a single Link per account at any given time, and also prohibits a Link from operating over more than a single underlying transport. Because of these restrictions, the `LinkId` in this implementation is always equal to the `AccountId`, which effectively means an packets are only ever being transacted over a given account using a single Link.


# Packet Switching Fabric

ILPv4 packets are forwarded to an outgoing link using a high-performance packet-switching fabric.

## Overall Design

This implementation relies upon a packet-switching fabric that applies business logic to each packet in order to ensure that packets meet various preconditions and can be properly routed. At a high level, this fabric looks like this:

![Packets enter the switching fabric on an inbound link, are processed, and then forwarded out on an outbound link. Responses traverse the fabric in the opposite direction.](/files/-Llbm2gG_Cf-SCZA44lC)

### Packet Filters

A packet filter applies business logic to a particular ILPv4 Prepare packet. The contract allows the filter to modify an in-flight packet, forward it onward to the next filter, or reject the packet outright. Read more about the contract [here](https://github.com/sappenin/java-ilpv4-connector/blob/aa84b650426817d9db322f9d0889ab80505f3c90/ilpv4-connector-service-api/src/main/java/com/sappenin/interledger/ilpv4/connector/packetswitch/filters/PacketSwitchFilter.java).&#x20;

### Packet Filter Chain

Packet filters are assembled together into a filter chain that is applied to every incoming packet. This implementation has a filter chain that looks like this:

![Each incoming ILPv4 packet is "filtered" according to the business logic of each Packet Filter.](/files/-LlbnPzjU7MCKAoTFNc9)

### Link Filters

A Link Filter is similar to a Packet Filter in that it applies business logic to a particular ILPv4 Prepare packet. However, these filters are only engaged before sending packets into an Outbound Link.

Like Packet Filters, the contract allows the filter to modify an in-flight packet, forward it onward, or reject the packet outright without sending it into the Outbound link. Read more about the contract [here](https://github.com/sappenin/java-ilpv4-connector/blob/aa84b650426817d9db322f9d0889ab80505f3c90/ilpv4-connector-service-api/src/main/java/com/sappenin/interledger/ilpv4/connector/links/filters/LinkFilter.java).&#x20;

### Link Filter Chain

Link filters are assembled together into a filter chain that is applied to every outgoing packet. This implementation has a filter chain that looks like this:

![Each outgoing ILPv4 packet is "filtered" according to the business logic of each Link Filter.](/files/-LlboM4uzV8_dXsIs-kh)


# Exchange Rates


# Routing Table Design


# Destination Address Handling

This page details how ILP destination address prefixes are handled by the Connector when it encounters a Prepare packet.

## Packet Destination Address Handling

Every ILPv4 `Prepare` packet has a destination address that indicates where a packet should ultimately be delivered. These addresses MUST always conform to [IL-RFC-15](https://github.com/interledger/rfcs/blob/master/0015-ilp-addresses) and may begin with one of several valid address-prefixes.&#x20;

Each of these prefixes has special meaning, and is handled by the Connector in slightly different ways, as described in the following chart.

|            Address Prefix            |       System Applicability      |                                                                                                        Purpose                                                                                                        |                                                                                                 Connector Handling                                                                                                | Accepts External Packets |    Forwards Out of Connector   |
| :----------------------------------: | :-----------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------: | :----------------------------: |
|                 `g.`                 |     Global Allocation Scheme    |                                                         ILP addresses that are intended to send and receive money from any other address in the global scheme.                                                        |                                                                               Forwarded to a plugin by the Packet-switching fabric.                                                                               |            Yes           |               Yes              |
|              `private.`              |        Private allocation       |                                                For ILP addresses that only have meaning in a private subnet or intranet. Analogous to the 192.168.0.0/16 range in IPv4.                                               |                                                                               Forwarded to a plugin by the Packet-switching fabric.                                                                               |            No            |               Yes              |
|              `example.`              |             Examples            |                                                  For "non-real" addresses that are used as examples or in documentation. Analogous to "555 phone numbers" in the USA.                                                 |                                                                                         Always rejected by the Connector.                                                                                         |            No            |               No               |
| `test.`, `test1.`, `test2.`,`test3.` | Interledger testnet and testing |                                           For addresses used on the public Interledger testnet and in local tests, such as unit or integration tests of compatible software.                                          |                                     Handled identically to a `g.` address if the Connector's Operating Address begins with `test`; Otherwise always rejected by the Connector.                                    |            Yes           |               Yes              |
|               `local.`               |         Connector-local         |                                          For addresses that are valid only in the a local-connector network, such among a cluster of connectors operated by the same entity.                                          |                                                                          Forwarded to a connected plugin by the Packet-switching fabric.                                                                          |            No            | Yes (only to another `local.`) |
|                `peer.`               |             Peering             | Addresses for exchange of packets only with a direct peer. Connectors MUST NOT forward packets with peer. addresses. Packets exchanged between peers to pass routing and config information will use peer. addresses. |                                                                                 Handled by the Connector as a message from a Peer.                                                                                |            Yes           |               No               |
|                `self.`               |          Local loopback         |               For addresses that are only valid on the local machine. For example, `self.ping`, `self.echo`, and other internal addresses that the Connector forwards traffic to for internal handling.               | External packets *can* make their way to `self.` handlers, but only indirectly. For example, Ping packets are addressed to this Connector's operator address, and are then forwarded to `self.ping` for handling. |            No            |               No               |


# Balance Tracking


# Settlement

Peers accrue debt with each other by processing Interledger packets. Settlement allows peers to pay down that debt to enable more interledger packet processing.

## Overview

Payment systems like Interledger can generally be separated into two layers: A higher-performance ***clearing*** layer, where value is transferred in a *provisional* manner; and a lower-performance ***settlement*** layer, which resolves any liabilities between counterparties accrued in the clearing layer.&#x20;

Most payments systems are organized in this way, and because many payment systems are often stacked on top of each other, it is common to see that one system's "settlement layer" is comprised of another system with its own clearing and settlement system. For example, from a consumer perspective, credit-card processors like Visa and Mastercard can be viewed as a "clearing systems" (swiping the card at a merchant) with an underlying settlement system to allow you to settle your debt to the credit card company each month (e.g., by making a payment from your bank account). What's interesting to see is that the system that appears to be a "settlement" system (i.e., the banking system) is actually comprised of its own clearing and settlement layers. For example, the bank's databases (i.e., the clearing system) and the Federal Reserve system (i.e., the settlement system).

As in the real world, settlement layers in Interledger can be based upon any medium of exchange that both parties in an Interledger peering relationship consider to be final, or "settled."&#x20;

Example settlement layer systems include:

* Offline fiat systems (e.g., cash or paper check)
* Direct asset transfers (e.g., a shipment of gold)
* Electronic ledgers (e.g., bank ledger, PayPal, Venmo)
* Electronic payment networks (e.g., SWIFT, ACH, SEPA, Visa, Mastercard)
* Cryptocurrency ledgers (e.g., Bitcoin or XRPL)
* Signing and exchanging payment channel claims (e.g., XRP Paychan)

### Settlement In Action

The Java ILP Connector [build system](https://circleci.com/gh/sappenin/java-ilpv4-connector) currently runs a nightly integration test to exercise and validate the its ability to interact with settlement engines that are compatible with IL-RFC-40 \[TODO Link]. These tests simulate a payment made from a hypothetical user `paul` who pings a connector identified as `bob` by traversing the `alice` connector. The inverse flow is also tested (`peter` pings `alice`) allowing settlement payments to&#x20;

![This topology allows Paul to ping the "Bob" Connector, and Peter to ping the Alice Connector.](/files/-LmPthUWpS8Koj5N6_wz)

In this setup, the `alice` and `bob` connectors are able to clear payments using Interledger, accruing bilateral debt between themselves. When this debt reaches some threshold agreed between Alice and Bob, their Connectors "settle" this debt by making a payment on the XRP Ledger.&#x20;

{% hint style="info" %}
**Interledger doesn't require the usage of XRP, or any particular underlying settlement system.** To wit, in this example, Alice and Bob could settle their outstanding debts using *any* underlying settlement system: fiat, crypto system, paper checks, or something else.
{% endhint %}

You can view the actual settlement transaction history of our integration test system by inspecting the XRP Ledger accounts in the [XRPL Testnet Faucet](https://xrpl.org/xrp-ledger-rpc-tool.html).


# Connector Configuration Properties

Knobs and switches to adjust before your Connector starts up.

Runtime configuration of this Connector can be obtained from a variety of potential sources when the connector starts up. This includes property files, environment variables, system properties and more, per the precedence defined by [Spring Boot](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html).

For example, any of the following configuration settings can be overridden at runtime by setting a system or environment variable, or by supplying a runtime switch to the JVM. For example: **`-Dredis.host=localhost`**.

{% hint style="info" %}
For advanced configurations with many overrides, it is recommend to place a file called **`application.yml`** onto the classpath.  Any values defined in this file will override the default values packaged with the application binary.
{% endhint %}

## Global Configuration Properties

This section details discrete Connector properties that can be configured, with examples.

### Root Properties

{% hint style="info" %}
The configuration property prefix for root properties i&#x73;**`interledger.connector`**
{% endhint %}

* **Required Properties**
  * **`nodeIlpAddress`**: ILP address of the connector. This property can be omitted if an account with relation `parent` is configured using the [Admin API](/api-references/admin-api).
  * **`adminPassword`**: A plain-text password used to authenticate to the admin API.
* **Optional Properties**
  * **`globalPrefix`**: The global prefix for the Connector. For production environments, this should be `g`. For test environments, consider `test`.(**Default**: `g`).
  * **`defaultJwtTokenIssuer`**: The issuer identifier for any tokens generated in accordance with [HTTP Auth Profiles RFC Proposal](https://github.com/interledger/rfcs/blob/master/proposals/0000-http-auth-profiles.md) (i.e., `JWT_HS_256` and `JWT_RS_256`).
  * **`minMessageWindowMillis`**: Default (`1000`) The minimum time the connector wants to budget for getting a message to the accounts its trading on. Budget is mainly to cover the latency to send the fulfillment packet to the downstream node (**Default**: `1000`).
  * **`maxHoldTimeMillis`**:  The amount of time that the Connector will wait for a fulfillment/rejection. This value is used to set any outgoing link's timeout duration (**Default**: `30000`).

{% code title="application.yml" %}

```yaml
interledger:
  connector:
    nodeIlpAddress: test.example
    adminPassword: shh # For prod usage, encrypt this value instead.
    globalPrefix: test
    defaultJwtTokenIssuer: https://connector.example.com
    minMessageWindowMillis: 1000
    maxHoldTimeMillis: 30000
```

{% endcode %}

### Properties: Global Routing Settings

{% hint style="info" %}
The configuration property prefix for Global Routing Settings i&#x73;**`interledger.connector.globalRoutingSettings`**
{% endhint %}

* **`routingSecret`**: A 32-byte secret seed value used to authenticate routing-table updates. If unspecified, an ephemeral random set of bytes will be generated and used.
* **`localAccountAddressSegment`**: An ILP address segment that will be used to route packets to any local accounts defined in the Connector. For example, if an account exists in the Connector with id of `alice`, then nodes wanting to send packets to that account would use the ILP address `{connector-operator-address}.accounts.alice`. Typically this will be used by the Connector to support IL-DCP, but will also be used to make routing decisions for any local accounts that might connect to the Connector. For example, `g.connector.accounts.alice.bob` would route to `alice`, allowing that node to figure out how to route to "bob" (**Default**: `accounts`).
* **`defaultRoute`**: An optionally-defined accountId that should be used as the default route for all un-routed traffic. If empty, the default route is disabled.
* **`routeBroadcastEnabled`**: Whether to broadcast known routes (**Default**: `true`).
* **`useParentForDefaultRoute`**: Determines if the parent-account should be used as the default route (**Default**: `false`).
* **`routeBroadcastInterval`**: Frequency, in milliseconds, at which the connector broadcasts its routes to adjacent connectors (**Default**: `30000`).
* **`routeCleanupInterval`**: The frequency, in milliseconds, at which the connector checks for expired routes (**Default**: `30000`).
* **`routeExpiry`**: The maximum age, in milliseconds, of a route provided by this connector (**Default**: `30000`).
* **`maxEpochsPerRoutingTable`**: The maximum number of epochs per routing table update (**Default**: `50`).

```yaml
interledger:
  connector:
    globalRoutingSettings:
      routingSecret: shh # For prod usage, encrypt this value instead.
      routeBroadcastEnabled: true
      useParentForDefaultRoute: true
      defaultRoute: parent-account
      routeBroadcastInterval: 30000
      routeCleanupInterval: 1000
      routeExpiry: 30000
      maxEpochsPerRoutingTable: 50
```

### Properties: Enabled Features

{% hint style="info" %}
The configuration property prefix for Enabled Features i&#x73;**`interledger.connector.enabledFeatures`**
{% endhint %}

* **`require32ByteSharedSecrets`**: Ensure that any shared secret values are at least 32 bytes, for security purposes. In non-production modes, this setting may be set to `false`, but in general it should always be `true` . (**Default** `true`).
* **`rateLimitingEnabled`**: Determines if rate-limiting is applied to any Connector accounts. If enabled, each account's `maxPacketsPerSecond` setting will be enforced (**Default**: `true`).
* **`localSpspFulfillmentsEnabled`** : Determines if this Connector will attempt to fulfill SPSP payments locally as opposed to forwarding them out to an upstream peer (**Default**: `false`). See "[Properties: Local SPSP Fulfillment](/configuration#properties-local-spsp-payment-fulfillment)" for more details.

{% code title="application.yml" %}

```yaml
interledger:
  connector:
    enabledFeatures:
      require32ByteSharedSecrets: true
      rateLimitingEnabled: true
      localSpspFulfillmentsEnabled: true
```

{% endcode %}

### Properties: Enabled Protocols

* **`ilpOverHttpEnabled`**: Determines if [Ilp-over-Http](https://github.com/interledger/rfcs/blob/master/0035-ilp-over-http/0035-ilp-over-http.md) is enabled for Connector account peering (Default: **`true`**).
* **`peerRoutingEnabled`**: Determines if Connector-to-Connector ([CCP](https://github.com/interledger/rfcs/pull/455)) protocol is enabled to allow this Connector to exchange routing table information with a peer (Default: **`true`**).
* **`pingProtocolEnabled`**: Determines if [ILP Ping](https://github.com/interledger/rfcs/pull/516) is enabled (Default: **`true`**).
* **`ildcpEnabled`**: Determines if [IL-DCP](https://github.com/interledger/rfcs/blob/master/0031-dynamic-configuration-protocol/0031-dynamic-configuration-protocol.md) is enabled (Default: **`true`**).

{% code title="application.yml" %}

```yaml
interledger:
  connector:
    enabledProtocols:
      ilpOverHttpEnabled: true
      peerRoutingEnabled: true
      pingProtocolEnabled: true
      ildcpEnabled: true
```

{% endcode %}

### Properties: Key Management

{% hint style="info" %}
The configuration property prefix for JKS properties i&#x73;**`interledger.connector.keystore`**
{% endhint %}

* **`primary`**: Indicates the primary keystore type. Acceptable values are `gcpkms` and `jks` (**Default**: `jks`).

{% code title="application.yml" %}

```yaml
interledger:
  connector:
    keystore:
      primary: jks
```

{% endcode %}

#### Properties: JKS Key Management

{% hint style="info" %}
The configuration property prefix for JKS properties i&#x73;**`interledger.connector.keystore.jks`**
{% endhint %}

The Connector supports storing keys and secrets in a [Java Keystore](https://en.wikipedia.org/wiki/Java_KeyStore) (JKS) file. To enable this mode, the following properties are supported:

* **`enabled`**: Enables or disables this keystore.
* **`filename`**: A filename for the JKS file (this file needs to be on the classpath).
* **`password`**: The password required to open the JKS file.
* **`secret0_alias`**: The alias name of they secret that is used by the Connector to encrypt, decrypt, and HMAC all other secret values.
* **`secret0_password`**: The password required to unlock the `secret0` alias in the Keystore.

{% code title="application.yml" %}

```yaml
interledger:
  connector:
    keystore:
      jks:
        enabled: true
        filename: crypto/crypto.p12
        password: password # For prod usage, encrypt this value instead.
        secret0_alias: secret0
        secret0_password: password # For prod usage, encrypt this value instead.
```

{% endcode %}

#### Properties: GCP KMS Key Management

{% hint style="info" %}
The configuration property prefix for Google KMS properties i&#x73;**`interledger.connector.keystore.gcpkms`**
{% endhint %}

The Connector supports storing keys and secrets in various Key Management Services (KMS). Currently, [Google Cloud KMS](https://cloud.google.com/kms/) is supported. To enable this mode, the following properties are supported:

* **`enabled`**: Enables or disables this keystore.
* **`locationId`**: The GCP [locationId](https://cloud.google.com/kms/docs/locations) for your configured KMS instance.

{% code title="application.yml" %}

```yaml
interledger:
  connector:
    keystore:
      gcpkms:
        enabled: false
        locationId: global
```

{% endcode %}

### Properties: Persistence Configuration&#x20;

#### Redis

Redis is used to track balances for every account operated by this Connector. The following properties may be used to configure Reds:

* **`spring.redis.host`**: (Default: `localhost`) The host that Redis is operating on.
* **`spring.redis.port`**: (Default: `6379`) The port that Redis is operating on.&#x20;
* **`spring.redis.password`**: (Default: none) An encrypted password String containing the password that can be used access Redis.

In the `application.yml` file, a sample configuration might look like this:

```yaml
spring:
  redis:
    host: localhost
    port: 6379
    password: enc:JKS:crypto.p12:redis_pw:1:aes_gcm:AAAADKZPmASojt1iayb2bPy4D-Toq7TGLTN95HzCQAeJtz0=
```

{% hint style="danger" %}
The Redis password should be encrypted, especially if it will reside in a property file per the above example. To generate this encrypted value, you can use the Connector Crypto CLI.&#x20;

For more details, read more in [Connector Crypto](/security-guide/crypto).
{% endhint %}

#### Postgres Configuration

Postgres can be used to store all non-balance tracking information, including account settings, routing tables, FX rates, and more.

* **`spring.datasource.url`**: The datasource URL used to connect to a Postgres instance.

In addition, the following two properties can be used to supply the Connector with Authentication credentials to connect to the database:

* **`spring.datasource.username`** (Default: **`postgres`**) The username to connect to the database as.
* **`spring.datasource.password`** The password to connect to the database as.

In the `application.yml` file, a sample configuration might look like this:

{% code title="application.yml" %}

```yaml
spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/connector_db
    username: postgres
    password: 
```

{% endcode %}

{% hint style="danger" %}
If security credentials are not required by your database, then the `username` and `password` properties may be omitted. **However, such a configuration is not recommended**.
{% endhint %}

### Properties: HTTP Clients

#### Settlement Engine Client

Configures how all underlying HTTP clients will interact with any Settlement Engine service. Currently, the Settlement Engine client creates a default connection pool holding up to 5 idle connections which will be evicted after 5 minutes of inactivity.

{% hint style="info" %}
The configuration property prefix for Settlement Engine clients is: **`interledger.connector.settlementEngines.connectionDefaults`**
{% endhint %}

* **`maxIdleConnections`**: The maximum number of idle connections that the underlying OkHttp client will hold open with no traffic flowing through them (Default: `5`*).*
* **`keepAliveMinutes`**: The number of minutes to hold an inactive HTTP connection open before evicting the connection from the connection pool (Default: `5 mins`).
* **`connectTimeoutMillis`**: Applied when connecting a TCP socket to the target host. A value of 0 means no timeout, otherwise values must be between 1 and `Integer#MAX_VALUE` (Default: `10000`).
* **`readTimeoutMillis`**: Applied to both the TCP socket and for individual read IO operations. A value of 0 means no timeout, otherwise values must be between 1 `Integer#MAX_VALUE` (Default: `30000`).
* **`writeTimeoutMillis`**: Applied to individual write IO operations. A value of 0 means no timeout, otherwise values must be between 1 and `Integer#MAX_VALUE` (Default: `30000`).

In the `application.yml` file, a sample configuration might look like this:

{% code title="application.yml" %}

```yaml
interledger:
  connector:
    settlementEngines:
      connectionDefaults:
        maxIdleConnections: 5
        keepAliveMinutes: 5
        connectTimeoutMillis: 10000
        readTimeoutMillis: 10000
        writeTimeoutMillis: 30000
```

{% endcode %}

#### ILP-over-HTTP Clients

Configures how all underlying HTTP clients will interact with any peer using [Ilp-over-Http](https://github.com/interledger/rfcs/blob/master/0035-ilp-over-http/0035-ilp-over-http.md). Currently, the Ilp-over-Http client creates a default connection pool holding up to 5 idle connections which will be evicted after 5 minutes of inactivity.

{% hint style="info" %}
The configuration property prefix for ILP-over-HTTP clients is: **`interledger.connector.settlementEngines.ilpOverHttp`**
{% endhint %}

* **`maxIdleConnections`**: The maximum number of idle connections that the underlying OkHttp client will hold open with no traffic flowing through them (Default: `5`*).*
* **`keepAliveMinutes`**: The number of minutes to hold an inactive HTTP connection open before evicting the connection from the connection pool (Default: `5 mins`).
* **`connectTimeoutMillis`**: Applied when connecting a TCP socket to the target host. A value of 0 means no timeout, otherwise values must be between 1 and `Integer#MAX_VALUE` (Default: `10000`).
* **`readTimeoutMillis`**: Applied to both the TCP socket and for individual read IO operations. A value of 0 means no timeout, otherwise values must be between 1 `Integer#MAX_VALUE` (Default: `60000`).
* **`writeTimeoutMillis`**: Applied to individual write IO operations. A value of 0 means no timeout, otherwise values must be between 1 and `Integer#MAX_VALUE` (Default: `60000`).
* **`maxRequests`** : The maximum number of HTTP requests to execute concurrently. Above this, requests queue in memory, waiting for the running calls to complete (Default: `100`).
* **`maxRequestsPerHost`**: The maximum number of requests for each host to execute concurrently. This limits requests by the URL's host name. Note that concurrent requests to a single IP address may still exceed this limit: multiple hostnames may share an IP address or be routed through the same HTTP proxy. (Default: `50`).

In the `application.yml` file, a sample configuration might look like this:

{% code title="application.yml" %}

```yaml
interledger:
  connector:
    ilpOverHttp:
      connectionDefaults:
        maxIdleConnections: 5
        keepAliveMinutes: 5
        connectTimeoutMillis: 10000
        readTimeoutMillis: 10000
        writeTimeoutMillis: 30000
        maxRequests: 100
        maxRequestsPerHost: 50
```

{% endcode %}

#### FX HTTP Clients

Configures how all underlying HTTP clients for Foreign Exchange (FX) will interact with any peer. Currently, the FX client creates a default connection pool holding up to 5 idle connections which will be evicted after 5 minutes of inactivity.

{% hint style="info" %}
The configuration property prefix for Http FX clients is:**`interledger.connector.fx`**
{% endhint %}

* **`maxIdleConnections`**: The maximum number of idle connections that the underlying OkHttp client will hold open with no traffic flowing through them (Default: **`5`***).*
* **`keepAliveMinutes`**: The number of minutes to hold an inactive HTTP connection open before evicting the connection from the connection pool (Default: **`5 mins`**).
* **`connectTimeoutMillis`**: Applied when connecting a TCP socket to the target host. A value of 0 means no timeout, otherwise values must be between 1 and `Integer#MAX_VALUE` (Default: **`10000`**).
* **`readTimeoutMillis`**: Applied to both the TCP socket and for individual read IO operations. A value of 0 means no timeout, otherwise values must be between 1 `Integer#MAX_VALUE` (Default: **`60000`**).
* **`writeTimeoutMillis`**: Applied to individual write IO operations. A value of 0 means no timeout, otherwise values must be between 1 and `Integer#MAX_VALUE` (Default: **`60000`**).

In the `application.yml` file, a sample configuration might look like this:

{% code title="application.yml" %}

```yaml
interledger:
  connector:
    fx:
      connectionDefaults:
        maxIdleConnections: 5
        keepAliveMinutes: 5
        connectTimeoutMillis: 10000
        readTimeoutMillis: 10000
        writeTimeoutMillis: 30000
```

{% endcode %}

### Properties: Keys and shared secrets

{% hint style="info" %}
The configuration property prefix for keys/secrets is:**`interledger.connector.keys`**
{% endhint %}

The connector uses key aliases and versions to determine what to use when handling encrypted shared secrets such as those for incoming and outgoing account settings links.

Following keys are configurable:

* **`secret0`**: Master encryption key for the connector.
* **`accountSettings`**: Encryption key for account settings shared secrets.

By default, the connector requires the shared secrets to be at least 32 bytes. To remove this requirement in non-production environments so that any secret length is allowed, set the following property to false:

* **`require32ByteSharedSecrets`**: Set to **`false`** to allow smaller shared-secrets. (Default: **`true`**).

In the `application.yml` file, a sample configuration might look like this.

```yaml
application.yml

interledger:
  connector:
    require32ByteSharedSecrets: false
    keys:
      secret0:
        alias: secret0
        version: 1
      accountSettings:
        alias: accounts
        version: 1
```

The connector makes use of keys to encrypt and decrypt shared secrets. By default, the plain text value of a shared secret must be 32 bytes but this can be&#x20;

### Properties: GCP Pub/Sub

{% hint style="info" %}
The configuration property prefix for GCP Pub/Sub configuration is: **`interledger.connector.pubsub`**
{% endhint %}

Publishing fulfillment and/or rejection packets to GCP Pub/Sub can be enabled by setting the following properties:

* **`spring.cloud.gcp.credentials.location`**: Path to GCP service account JSON. This service account should have permissions to publish to pubsub.
* **`spring.cloud.gcp.credentials.encoded_key`**: An alternative way to provide the service account JSON as a base-64 encoded string instead of as a file location. For example, on linux, using the output of the command `cat /path/to/credentials.json | base64`
* **`spring.cloud.gcp.project_id`**: Your GCP project id.
* **`spring.cloud.gcp.pubsub.enabled`** : `true` or `false` depending on whether pubsub is enabled (Default: `false`).
* **`interledger.connector.pubsub.topics.fulfillment_event`**: The GCP pub/sub topic name where fulfillment events should be published. If not set, fulfillments will not be published (Default: `ilp-events`).
* **`interledger.connector.pubsub.topics.rejection_event`**: The GCP pub/sub topic name where rejection events should be published. If not set, rejections will not be published. Note: you can publish both fulfillments and rejections to the same topic by using the same name (Default: `ilp-events`).

```yaml
interledger:
  connector:
    pubsub:
      topics:
        fulfillment-event: ilp-events
        rejection-event: ilp-events
        
spring:
  cloud:
    gcp:
      ## must set project-id and credentials
      project-id: {your-project-id}
      credentials:
        encoded-key: {your-base64-encoded-service-account-key-json}
      pubsub:
        enabled: true
```

### Properties: Local SPSP Payment Fulfillment

{% hint style="info" %}
The configuration property prefix for Local SPSP Payment Fulfillment configuration is: **`interledger.connector.spsp`**
{% endhint %}

The Connector can be configured to fulfill SPSP payments that are destined for accounts in the Connector itself. This functionality can be enabled via the following properties:

* **`serverSecret`** A base64-encoded String of bytes used to derive any values used in encryption/decryption for SPSP.
* **`addressPrefixSegment`**: A string that will be appended to the Connector's operating address in order to form an address prefix that the Connector will key off for fulfilling SPSP payments locally (Default: `spsp`).

```yaml
interledger:
  connector:
    enabledFeatures:
      localSpspFulfillmentEnabled: true
    spsp:
      # For prod usage, encrypt this value instead.
      serverSecret: aQLR5IWAGV2vKnBhnFFsl2cXOCh9u0IWz3PiA64KlJ8= 
      addressPrefixSegment: spsp
```

### Aggregate Profiles

Several Spring profiles are available to make it easier to enable certain features. Some commonly used profiles are:

* [**dev**](https://github.com/interledger4j/ilpv4-connector/tree/master/connector-server/src/main/resources/application-dev.yml)**:** single profile that includes other profiles for easily starting up a connector for dev purposes
* [**migrate**](https://github.com/interledger4j/ilpv4-connector/tree/master/connector-server/src/main/resources/application-migrate.yml): runs database migrations (via liquibase) before connector is started
* [**migrate-only**](https://github.com/interledger4j/ilpv4-connector/tree/master/connector-server/src/main/resources/application-migrate-only.yml): only runs database migrations (via liquibase) but does not start the connector (application will terminate after migrations complete)
* [**management**](https://github.com/interledger4j/ilpv4-connector/tree/master/connector-server/src/main/resources/application-management.yml): enables the Spring management endpoints
* [**h2**](https://github.com/interledger4j/ilpv4-connector/tree/master/connector-server/src/main/resources/application-h2.yml): enables hypersonic in-memory SQL database
* [**postgres**](https://github.com/interledger4j/ilpv4-connector/tree/master/connector-server/src/main/resources/application-postgres.yml)**:** enables postgres driver with defaults (must override url, username, pw)
* [**wallet-mode**](https://github.com/interledger4j/ilpv4-connector/blob/master/connector-server/src/main/resources/application-wallet-mode.yml): enables an SPSP server with local packet fulfillment.&#x20;

A complete list of profiles can be found [here](https://github.com/interledger4j/ilpv4-connector/tree/master/connector-server/src/main/resources/).

These profiles can be enabled by from the command-line using `-Dspring.profiles.active=h2,management,...`, via an environment variable `SPRING_PROFILES_ACTIVE=h2,management,...` or by adding the following to your application.yaml:

{% code title="application.yaml" %}

```yaml
spring:
  profiles:
    active: h2,management,...
```

{% endcode %}


# Persistence Initialization

This page describes available persistence stores and how to configure the Connector to operate using them.

## Overview

This implementation classifies persistence data into two broad categories: data collected during performance-sensitive operations, and all other data.

Data collected during performance-sensitive operations is limited to the data required to facilitate the ILPv4 packet flow. In general, this type of data is limited to balance tracking information, and this implementation supports both Redis and Postgres for this use-case.&#x20;

All other data, such as non-balance account configuration, runtime configuration, and more is stored into one of several supported RDBMS datastores. This implementation currently supports [Posgresql](https://www.postgresql.org/), [MS-SQL](https://www.microsoft.com/en-us/sql-server/default.aspx), [MySQL](https://www.mysql.com/), and [Oracle](https://www.oracle.com/database/12c-database/).

{% hint style="info" %}
This page details how to initialize a given persistence store for usage by the Connector. To set connection details and other runtime configuration properties, see [here](/configuration) instead.
{% endhint %}

## Postgresql

This section details how to use Postgresql as the underlying Connector datastore.

{% hint style="success" %}
This section assumes that you have created a database named `connector`inside of your Postgres installation. Note that this naming is used as an example only -- you can choose *any* database name.
{% endhint %}

### Generate DDL

To generate the DDL for the Connector database, execute the following commands:

```bash
mvn -DskipTests clean package -P liquibase-pg-sql liquibase:updateSQL
```

This will emit a file `/target/liquibase/migrate.sql` that can be used to populate your database.&#x20;

### Direct Initialization via Maven

As an alternative during development, you can utilize the liquibase-maven-plugin to directly connect to  Postgres and initialize the database for you.&#x20;

However, for this to work, you first need to update the `pom.xml` file in the `ilpv4-connector-persistence` module to conform to your connection parameters by setting the `configuration.url` to a value for your environment, like this:

{% code title="ilpv4-connector-persistence/pom.xml" %}

```markup
...
<profiles>
    <profile>
      <id>liquibase-pg-sql</id>
      ...
        <configuration>
          <url>jdbc:postgresql://localhost:5432/connector</url>
        </configuration>        
      ...
</profiles>
```

{% endcode %}

Once the liquibase-maven-plugin is configured properly, the following commands will update the database directly:

```bash
cd ./java-ilpv4-connector/ilpv4-connector-persistence
mvn -DskipTests clean package -P liquibase-pg-sql liquibase:update
```

If you want to reinitialize the database, for example during development, the following commands can be used:

```bash
mvn -DskipTests clean package -P liquibase-pg-sql liquibase:dropAll
mvn -DskipTests clean package -P liquibase-pg-sql liquibase:update
```

## Oracle

*Coming soon.*

## MySQL

*Coming soon.*

## MS-SQL

*Coming soon.*

## Redis

Redis is only used for balance tracking, so outside of configuring [runtime configuration properties](/configuration), no further initialization is required.


# Local STREAM Packet Termination

Describes how to locally terminate SPSP payments

## Background

Normally, a Connector only forwards packets from one ILP node to another. Separate, non-Connector nodes typically handle the responsibilities of sending and receiving, often using the Simple Payment Setup Protocol ([SPSP](https://github.com/interledger/rfcs/blob/master/0009-simple-payment-setup-protocol/0009-simple-payment-setup-protocol.md)). Combined with STREAM payments, receivers normally fulfill any received packets in order to satisfy the Interledger protocol. The following is a simple topology diagram to illustrate this:

![A simple ILPv4 topology where the receiver fulfills all packets.](/files/-M-Hum9qFmKeqGLnk9Tf)

In some infrastructures, the extra ILPv4 Prepare call from the Connector to the SPSP receiver is redundant when the accounts actually live inside of the Connector. Especially for very simple SPSP Receivers, it is often more economical to simply have the Connector fulfill any valid STREAM packets, as opposed to forwarding them to a separate runtime.

## Enabling Local Packet Termination

To enable this feature, it is necessary to configure three settings in the Connector, each of which is defined in a configuration property as outlined in [Properties: Local SPSP Termination](/configuration#properties-local-spsp-payment-fulfillment).

First, Local STREAM termination must be enabled. Next, the `serverSecret` for the SPSP receiver must be specified.&#x20;

Finally, the `addressPrefixSegment` must be specified. This last setting determines which ILP destination address prefixes will be intercepted by the connector and routed to the local SPSP/STREAM fulfillment endpoint. The default setting here is `spsp`, which means any address matching `{nodeIlpAddress}.spsp` will be routed to the local termination endpoint.&#x20;

For example, imagine a Connector with a `nodeIlpAddress` of `test.foo` . A packet with a destination address of `test.foo.spsp.alice.{anything}` will be routed to the SPSP termination endpoint and processed under the local account of `alice`.


# Running with Docker

Running with Docker

## Prerequisites

* Docker must be installed and running.

## Starting a connector (using in-memory database and in-memory Redis)

The connector requires a SQL database and Redis to run. By default, the docker image will run using an in-memory H2 database and in-memory Redis cache. This mode is intended to quickly get a connector up and running but all data will be lost on container restarts. As such, this mode should not be used for any real world applications.

To start the latest nightly image of the java-ilpv4-connector in an interactive terminal, run:

```
docker run -p 8080:8080 -it interledger4j/java-ilpv4-connector:nightly
```

You should see a log message like the following once the container has successfully started:

```
Started ConnectorApplication in 6.912 seconds
```

You can now send HTTP requests to the connector to verify it's working:

```
curl  http://localhost:8080/accounts -H 'Authorization: Basic YWRtaW46cGFzc3dvcmQ='
```

## Starting a connector (using external Postgres database and external Redis)

This mode requires having a Postgres database and Redis cache already running. This mode allows the java-ilpv4-connector to be restarted without loss of data (so long as the Postgres database and Redis cache are not lost).

### Running Postgres and Redis in docker

If you already have a Postgres database and Redis cache running, skip this section. Otherwise, we'll start up a Postgres container and Redis container in docker.

To start a Postgres database, run:

```
docker run --name connector-postgres -p 5432:5432 -e POSTGRES_PASSWORD=mysecretpassword -e POSTGRES_DB=connector -d postgres
```

{% hint style="danger" %}
Note that you should pick a password properly above.
{% endhint %}

To start a Redis cache, run:

```
docker run -d -p 6379:6379 redis
```

You can verify the containers are running via:

```
docker ps
```

### Configuring java-ilpv4-connector to connect to external Postgres and Redis instances:

The docker container needs to be configured with the postgres and redis connection details. This is done by passing environment variables in the docker run command. Docker supports passing each environment variable as a separate argument or by providing a env file that contains environment variable mappings.

For example, here is how to configure and run the connector using separate env args:

```
docker run -p 8080:8080 -e spring.profiles.active=insecure,postgres,migrate -e redis.host=host.docker.internal -e spring.datasource.url=jdbc:postgresql://host.docker.internal:5432/connector -e spring.datasource.username=postgres -e spring.datasource.password=postgres -it interledger4j/java-ilpv4-connector:nightly
```

Or more conveniently, we can put all the same args into a file named `connector.env` with the following contents:

```
spring.profiles.active=insecure,postgres,migrate
redis.host=host.docker.internal
spring.datasource.url=jdbc:postgresql://host.docker.internal:5432/connector
spring.datasource.username=postgres
spring.datasource.password=postgres
```

and start the connector via:

```
docker run -p 8080:8080 --env-file ~/connector.env -it interledger4j/java-ilpv4-connector:nightly
```

## Configuration flags available via docker

java-ilpv4-connector uses [Spring Boot for external configuration](https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config). Spring properties specific to the java-ilpv4-connector can be found under [Connector Configuration Properties](/configuration). Spring makes it easy to set/override a Spring property via environment variables. For example, a Spring property specified via yaml configuration like this

```
interledger:
    connector:
        nodeIlpAddress: test.xpring-dev.java1
```

can be set in an env file to docker like this:

```
interledger.connector.nodeIlpAddress=test.xpring-dev.java1
```

For Spring properties that use yaml list like:

```
interledger:
  globalRoutingSettings:
      staticRoutes:
        - targetPrefix: test.connie.alice
          peerAccountId: alice
```

The equivalent env-file override would be:

```
interledger.connector.globalRoutingSettings.staticRoutes.0.targetPrefix=test.connie.alice
interledger.connector.globalRoutingSettings.staticRoutes.0.peerAccountId=alice
```

### Configuring Java VM options with docker

[Java JVM](https://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html) options can be configured by setting the docker environment variable `_JAVA_OPTIONS`

For example, to configure the Java VM with a 512mb max heap and G1 garbage collector:

```
docker run -e _JAVA_OPTIONS="-XX:+UseG1GC -Xmx512m" -p 8080:8080 -it interledger4j/java-ilpv4-connector:nhartner
```

Or if using a ENV file, then add the following line to the file:

```
_JAVA_OPTIONS=-XX:+UseG1GC -Xmx512m
```


# Peering: ILP-over-HTTP

Connect to a peer using ILP, HTTP, and some love...

## Overview

This guide instructs you how to setup a peering relationship between your Connector and a peer. In addition, you'll also be able to verify connectivity in both directions using the ILP Ping.

This guide assumes you're operating the `test.alice` Connector. Once completed, your ILP network topology will look like this:

![](/files/-LmqJD4VoH7YEgbqQwGJ)

## Considerations

In order to create an actual Interledger peering relationship, you need to first determine the financial details of the relationship. This includes:

* The amount of credit to extend to your peer. This will be dictated by the `min_balance` value.
* The currency unit you will use to denominate the account relationship. This guide will use `USD` in all examples.
* Whether or not you want to rate-limit your peer.
* The network connection details you will use to communicate with your peer. This guide assumes ILP-over-HTTP, and as such will specify both incoming and outgoing Link settings using HTTP.

{% hint style="danger" %}
&#x20;This guide does not enable settlement. Read more in the [Settlement](/concepts/settlement-xrp-ledger) section for conceptual details, and consult [Settlement: XRP Leger](/settlement-xrp-ledger) for an example.
{% endhint %}

{% hint style="success" %}
Reference the [Connector Admin API](/api-references/admin-api) documentation for more details about actual payloads and their meanings.
{% endhint %}

## Accounts on the Alice Connector

On the `test.alice` Connector, we need to create two accounts: one for a hypothetical user named **Peter** and one for the peering relationship with the **Bob** Connector.

### Create Account: "bob"

In order to peer with the Bob Connector, we must first tell Alice about Bob. This is done by creating an account for Bob, on Alice. In this case, we want to use a relatively strong token scheme for security purposes, called `JWT_HS_256` (See [ILP-over-HTTP Auth Profiles](https://github.com/interledger/rfcs/blob/master/proposals/0000-http-auth-profiles.md) for more details). To effect this change, we can use the Connector Admin API by making the following call:

```javascript
curl --location --request POST 'http://alice.example.com/accounts' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data-raw '{
  "accountId": "bob",
  "accountRelationship": "PEER",
  "linkType": "ILP_OVER_HTTP",
  "assetCode": "USD",
  "assetScale": "3",
  "customSettings": {
    "ilpOverHttp.incoming.auth_type": "JWT_HS_256",
    "ilpOverHttp.incoming.token_subject":"bob",
    "ilpOverHttp.incoming.shared_secret": "enc:JKS:crypto.p12:secret0:1:aes_gcm:AAAADKZPmASojt1iayb2bPy4D-Toq7TGLTN95HzCQAeJtz0=",    	
    "ilpOverHttp.outgoing.auth_type": "JWT_HS_256",
    "ilpOverHttp.outgoing.token_subject": "alice",
    "ilpOverHttp.outgoing.shared_secret": "enc:JKS:crypto.p12:secret0:1:aes_gcm:AAAADKZPmASojt1iayb2bPy4D-Toq7TGLTN95HzCQAeJtz0=",
    "ilpOverHttp.outgoing.url": "https://bob.example.com/accounts/alice/ilp"
   }
}'
```

In the above example, the account is configured to send outgoing ILP-over-HTTP requests to URL indicated in `outgoing.url`, which should be a valid URL on the Bob Connector.

{% hint style="danger" %}
Note that the `shared_secret` above is encrypted using default keys packaged with the Connector in a Java Keystore (JKS) file meant for illustration purposes only.  The decrypted shared secret value is **`shh`** but in a real deployment, you should use a strong shared secret and a new set of encryption keys. \
\
See [Connector Security](/security-guide/crypto) for more details.
{% endhint %}

### Create Account: \`peter\`

Next, we need an account on the Alice Connector that can be used to initiate pings and payments. In this case, we want to use a simpler authentication scheme, so we choose `SIMPLE` (See [ILP-over-HTTP Auth Profiles](https://github.com/interledger/rfcs/blob/master/proposals/0000-http-auth-profiles.md) for more details). To effect this change, we can use the Connector Admin API by making the following call:

The following is a sample payload that can be used to create an account for Peter on the Alice Connector:

```javascript
curl --location --request POST 'http://alice.example.com/accounts' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data-raw '{
  "accountId": "peter",
  "accountRelationship": "CHILD",
  "linkType": "ILP_OVER_HTTP",
  "assetCode": "USD",
  "assetScale": "3",
  "customSettings": {
    "ilpOverHttp.incoming.auth_type": "SIMPLE",
    "ilpOverHttp.incoming.simple.auth_token": "shh"
   }
}'
```

{% hint style="info" %}
Note that the client authenticating as "Peter" may not be an HTTP server. In this case, Alice won't be able to send ILP packets to Peter. However, ILP-over-HTTP will still work from Peter to Alice as long as Alice because Alice's Connector is operating an ILP-over-HTTP server endpoint.
{% endhint %}

## Accounts on the Bob Connector

Next, let's mirror this setup on the Bob Connector.

### Create Account: \`alice\`

```javascript
curl --location --request POST 'http://bob.example.com/accounts' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data-raw '{
  "accountId": "alice",
  "accountRelationship": "PEER",
  "linkType": "ILP_OVER_HTTP",
  "assetCode": "USD",
  "assetScale": "3",
  "customSettings": {
    "ilpOverHttp.incoming.auth_type": "JWT_HS_256",
    "ilpOverHttp.incoming.token_subject":"alice",
    "ilpOverHttp.incoming.shared_secret": "enc:JKS:crypto.p12:secret0:1:aes_gcm:AAAADKZPmASojt1iayb2bPy4D-Toq7TGLTN95HzCQAeJtz0=",    	
    "ilpOverHttp.outgoing.auth_type": "JWT_HS_256",
    "ilpOverHttp.outgoing.token_subject": "bob",
    "ilpOverHttp.outgoing.shared_secret": "enc:JKS:crypto.p12:secret0:1:aes_gcm:AAAADKZPmASojt1iayb2bPy4D-Toq7TGLTN95HzCQAeJtz0=",
    "ilpOverHttp.outgoing.url": "https://alice.example.com/accounts/bob/ilp"
   }
}'
```

### Create Account: \`pauline\`

```javascript
curl --location --request POST 'http://bob.example.com/accounts' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data-raw '{
  "accountId": "pauline",
  "accountRelationship": "CHILD",
  "linkType": "ILP_OVER_HTTP",
  "assetCode": "USD",
  "assetScale": "3",
  "customSettings": {
    "ilpOverHttp.incoming.auth_type": "SIMPLE",
    "ilpOverHttp.incoming.simple.auth_token": "shh"
   }
}'
```

## Verify Connectivity

Now that we have accounts configured on both Connectors, we can use the Ping protocol to verify connectivity from Alice to Bob, and vice-versa.

### Ping Bob

Coming soon...

### Ping Alice

Coming soon...


# Settlement: XRP Ledger

Run two Connectors and two Settlement Engines to see Interledger Settlement on your laptop

## Before you begin...

Before running through this example tutorial, you should become familiar with Interledger Settlement concepts. Read more about that in [Settlement Overview](/concepts/settlement-xrp-ledger#overview).

## Step 1


# Running on GCP

This guide will walk through running a connector on Google Cloud Platform.

To run a connector on GCP, we'll make use of the following GCP products:

* Cloud SQL (postgres)
* Cloud Memory Store (redis)
* KMS
* GKE
* Cloud Run

This allow us to run a highly available an ILP Connector that is publicly accessible.

Whenever possible, `gcloud` cli will be used to provision GCP resources. Before getting started, you must have [gcloud cli installed](https://cloud.google.com/sdk/install) and run [gcloud auth login ](https://cloud.google.com/sdk/gcloud/reference/auth/login)to connect to your account.

## Creating Cloud SQL database

The connector uses a SQL database to store account settings and routes.&#x20;

We'll create a Cloud SQL Postgres database. There's no strict requirements on what region, cpu, memory to use. A typical connector's load on the database is light compared to most applications. One exceptions is that Java uses connection pooling so can have many connections open. The default max\_connections for Cloud SQL of 100 can be too small if running multiple instances of the connector.

We'll also enabled Private IP address via the `--network default` configuration flag. This will allow us to configure the connector to connect to our Cloud SQL address via a private IP.

```
gcloud beta sql instances create connector --cpu=1 --memory=4096MiB \
 --region=us-west1 --database-version=POSTGRES_11 --network default \
 --database-flags max-connections=500 	

```

Once the command has completed, you should see your database in Cloud [console](https://console.cloud.google.com/sql/instances). Note the private IP address as we'll need that later on.

![](/files/-M-phE5OrAtBo76jg40P)

### Setting password for the postgres user

```bash
gcloud sql users set-password postgres -i connector --password=<password>
```

### Creating a connector database

While not mandatory, it is recommended to create a separate database schema for the connector instead of using the default postgres schema. By default, the connector will try to connect using the schema `connector`. To create a connector user, run:

```bash
gcloud sql databases create connector -i connector
```

### Creating a connector user

While not mandatory, it is recommended to create a separate account for the connector instead of using the postgres admin user. By default, the connector will try to connect using the username `connector`. To create a connector user, run:

```bash
gcloud sql users create connector -i connector --password <password>
```

## Creating Cloud Memory Store

The connector uses Redis for tracking balances and for pub/sub messaging between connectors (if running multiple connector instances). A typical connector will not need a large amount of Redis storage so we'll create one with the minimum 1GB.

```bash
gcloud redis instances create connector --size=1 --region=us-west1 --redis-version=redis_4_0
```

Once created note, the IP address on the [Memorystore dashboard](https://console.cloud.google.com/memorystore/redis/instances)

![](/files/-M-pnlm3KIKUKfziF__A)

## Creating KMS keys

Java connector uses encryption keys to encrypt things like auth tokens and shared secrets for account, as well as other internally secured data. Java Keystore (JKS) and KMS are both supported. KMS is recommended because it is easier to manage and configure.

First we need to create a keyring to store connector keys:

```bash
gcloud kms keyrings create connector --location global
```

Now we can generate a key for the connector to use. The default key alias that the connector will use is `secret0`. We'll create a key with that alias:

```bash
gcloud kms keys create secret0 --location global --keyring connector \
 --purpose encryption
```

## Creating GCP Service Account

In order for the connector to be able to use KMS, it will need a GCP service account with KMS encrypt/decrypt permissions.

First we create the service account:

```bash
gcloud iam service-accounts create connector --display-name connector
```

Then we grant the cloudkms.cryptoKeyEncrypterDecrypter to the service account:

```bash
gcloud projects add-iam-policy-binding <gcp-project-id> \
  --member serviceAccount:connector@<gcp-project-id>.iam.gserviceaccount.com \
  --role roles/cloudkms.cryptoKeyEncrypterDecrypter
```

Note: you must replace both instances of `<gcp-project-id>` in the command above with your GCP project id.

### Exporting Service Account JSON in Base64

Later on when you configure your connector, you'll need to provide the GCP service account credentials as a base64 encoded string. This will be used by the connector to authenticate to GCP.

The following command will generate this value:

```bash
gcloud iam service-accounts keys create /dev/stdout --iam-account \
connector@xpring-dev-sandbox.iam.gserviceaccount.com \
--no-user-output-enabled | base64 && echo
```

## Creating Kubernetes Cluster

A docker image is published for the Java ILPv4 connector so the easiest way to run the connector is via docker. For running multiple instances of a connector behind a public load-balancer, Kubernetes with Cloud Run for Anthos provides a convenient setup. Note this will not be the cheapest option as the VM requirements for running Kubernetes are higher than a DIY setup.&#x20;

For this example, we'll run 2 instances of a connector on Kubernetes and deploy using Cloud Run. We'll size the Kubernetes cluster with 2 nodes, each node using the 2 cpu + 2 gb (high-cpu) e2 machine type.

Big gcloud command incoming....

```bash
gcloud beta container clusters create <connector-name> --zone "us-west1-a" \
 --no-enable-basic-auth --cluster-version "1.13.12-gke.25" \
  --machine-type "e2-highcpu-4" --image-type "COS" --disk-type "pd-standard" \
  --disk-size "10" --scopes "https://www.googleapis.com/auth/devstorage.read_only","https://www.googleapis.com/auth/logging.write","https://www.googleapis.com/auth/monitoring","https://www.googleapis.com/auth/servicecontrol","https://www.googleapis.com/auth/service.management.readonly","https://www.googleapis.com/auth/trace.append" \
  --num-nodes "2" --enable-stackdriver-kubernetes --enable-ip-alias \
  --network default --subnetwork default \
  --addons HorizontalPodAutoscaling,HttpLoadBalancing,CloudRun \
  --enable-autoupgrade --enable-autorepair
```

## Deploying the Java Connector via Cloud Run

To deploy the Java connector docker image, we'll use GCP's Cloud Run for Anthos. This will deploy the connector and configure networking so that it can be publicly accessible.

First we need to create a k8 yaml file to define the connector and configuration:

{% code title="connector-cloudrun.yaml" %}

```bash
apiVersion: serving.knative.dev/v1alpha1
kind: Service
metadata:
  name: connector
  namespace: default
spec:
  template:
    metadata:
      annotations:
        autoscaling.knative.dev/maxScale: '2'
        autoscaling.knative.dev/minScale: '2'
        run.googleapis.com/client-name: cloud-console
    spec:
      containerConcurrency: 80
      containers:
      - env:
        - name: spring_profiles_active
          value: migrate,jks,postgres,gcp-kms
        - name: redis_host
          value: <CLOUD_MEMORY_STORE_IP>          
        - name: spring_datasource_url
          value: jdbc:postgresql://<CLOUD_SQL_PRIVATE_IP>:5432/connector
        - name: spring_datasource_username
          value: connector
        - name: spring_datasource_password
          value: <DB_PASSWORD>
        - name: interledger_connector_adminPassword
          value: <ADMIN_PASSWORD>
        - name: interledger_connector_nodeIlpAddress
          value: test.<YOUR_CONNECTOR_NAME>
        - name: interledger_connector_globalPrefix
          value: test
        - name: interledger_connector_enabledFeatures_require32ByteSharedSecrets
          value: 'false'
        - name: spring_cloud_gcp_project_id
          value: <GCP_PROJECT_ID>
        - name: _JAVA_OPTIONS
          value: -Xmx512m  
        - name: spring_cloud_gcp_credentials_encoded_key
          value: <BASE64_ENCODED_SERVICE_ACCOUNT_JSON>
        image: docker.io/interledger4j/java-ilpv4-connector:0.2.0
        name: user-container
        ports:
        - containerPort: 8080
        readinessProbe:
          successThreshold: 1
        resources:
          limits:
            cpu: 768m
            memory: 768Mi
      timeoutSeconds: 300
  traffic:
  - latestRevision: true
    percent: 100


```

{% endcode %}

Save the file above as connector-cloudrun.yaml and replace the following placeholders:

* **\<CLOUD\_MEMORY\_STORE\_IP>**  - replace with the IP address of your Cloud Memorystore instance
* **\<DB\_PASSWORD>** - replace with the password you provided when creating the connector database on your Cloud SQL instance
* **\<CLOUD\_SQL\_PRIVATE\_IP>** - replace with the PRIVATE ip address shown for your Cloud SQL instance
* **\<ADMIN\_PASSWORD>** - replace with a password of your choosing. This will be used to authenticate as an admin to the REST API on your connector. This password does not have to be the same as your db password.
* **\<YOUR\_CONNECTOR\_NAME>** - the name by which your connector will be known on the ILP network. This will be the sub root of your connector's ILP addresses.
* **\<GCP\_PROJECT\_ID>** - your GCP project id
* **\<BASE64\_ENCODED\_SERVICE\_ACCOUNT\_JSON>** - replace a base64-encoded json for the service account you created above. See *Exporting Service Account JSON in Base64* section above for how to obtain this value. It should be 1 really long line of text.

Once you've created and edited connector-cloudrun.yaml, you'll deploy the connector using:

```bash
gcloud beta run services replace connector-cloudrun.yaml --platform gke --cluster-location us-west1-a --cluster connector
```

## Configuring DNS and SSL for the connector

If everything has gone well, you should now have connector running but in order to access it, you'll need to set up DNS. To keep things simple, we'll set up DNS to use a free DNS provider [xip.io](https://xip.io). This will get us up and running quickly without needing to set up buy domain name and configure DNS entries.

The following sets of commands require using Kubernetes. If you already have Kubernetes installed, you can use that, otherwise you can use GCP Cloud Shell. To launch Cloud Shell, navigate to <https://console.cloud.google.com/kubernetes> and click on the *Connect* button, then click on the *Run in Cloud Shell* button in the popup modal. This should launch a shell terminal modal in your browser.

In order to configure xip.io with a DNS mapping, we need to know the external IP address of your Kubernetes cluster. Run the following command to obtain thisL

```bash
kubectl get service -n gke-system istio-ingress
```

Replace "1.2.3.4" with your External IP address in following command:

```bash
kubectl -n knative-serving patch configmap config-domain \ 
--patch   '{"data": {"example.com": null, "1.2.3.4.xip.io": ""}}'
```

Now we will create a subdomain mapping for the connector (again replacing 1.2.3.4 with your kubernetes external IP address):

```bash
gcloud beta run domain-mappings create --service connector --platform gke \
--cluster connector --cluster-location us-west1-a \
--domain connector.1.2.3.4.xip.io
```

Lastly we will configure auto TLS/SSL certs to be generated:

```bash
kubectl patch cm config-domainmapping -n knative-serving \ 
-p '{"data":{"autoTLS":"Enabled"}}'
```

## The End

At this point your connector should be up and running and accessible via a URL like <https://connector.1.2.3.4.xip.io/>


# Connector Crypto

This Connector implementation supports various mechanism to support Encryption and Signing operations.

## Keystores

To use a Java Keystore as your location of any key material, first create a Keystore using the following commands:

```bash
> keytool -keystore ./crypto.p12 -storetype PKCS12 -genseckey -alias secret0 -keyalg aes -keysize 256
> keytool -keystore ./crypto.p12 -storetype PKCS12 -list
```

Note the JKS and secret0 password used.

Next, update the following properties in your `application.yml` file:

```yaml
jks:
  jks_filename: crypto.p12
  jks_password: password
  secret0_alias: secret0
  secret0_password: password
```

Finally, make sure the JKS file `crypto.pkcs12` is added to the runtime classpath of the Connector.

### JKS

### Google GCP

### Vault


# test-jwt.io

This file contains information that can be plugged-into <https://jwt.io> in order to experiment with token-types currently used by the BLAST (ILP-over-HTTP) protocol in this implementaiton:

## Headers

```javascript
{
  "alg": "HS256",
  "typ": "JWT"
}
```

## Payload

```javascript
{
  "sub": "alice",
  "aud": "https://connie.example.com/",
  "iss": "https://alice.example.com/",
  "iat": 1556751813
}
```


# Generating Keys

## Overview

This folder contains a Command-line-interface that can be used to encrypt and encode secret values in a format that can be used by the Java Connector.

For example, imagine the Connector needs to authenticate to a database using a password with a value of `shh`. This value can be encrypted using either the Google KMS (reccommended for productio usage) or a Java Keystore loaded from the runtime's filesystem (most useful for development purposes).

In either case, the secret value (i.e., `shh`) will be encrypted with a particular secret-key with a particular version of that key. The CLI will encode this value so that it can be parsed properly by the connector in order to determine the correct manner to locate keys for decryption.

Here is an example of a secret value that is both encrypted *and* encoded:

```
enc:JKS:crypto.p12:secret0:1:aes_gcm:AAAADKZPmASojt1iayb2bPy4D-Toq7TGLTN95HzCQAeJtz0=
```

This encoding indicates that the string represents and encoded value (because it begins with the prefix `enc`), was encrypted using a Java Keystore (i.e., the `JKS` keystore type) using a filename called `crypto.p12`, and using the key with an alias of `secret0` and the `aes_gcm` encryption algorithm (which is a particular variant supported by the Connector). Next, a cipher\_message encodes `cipher_text` as well as other meta-data used to decrypt the secret value (see [here](https://proandroiddev.com/security-best-practices-symmetric-encryption-with-aes-in-java-7616beaaade9) for more details).

## Running the CLI

Crypto CLI is available as a docker image. To run the CLI via docker, run:

```
docker run -it --rm interledger4j/crypto-cli
```

This will run using the default embedded JKS keystore which is only meant dev purposes. Here's an example of a CLI interaction with the to encrypt the secret `myEncryptionSecret`:

```bash
crypto-cli:> e mySecretToEncrypt
Encoded Encrypted Secret: enc:JKS:crypto.p12:secret0:1:aes_gcm:AAAADAaP9_AwM...
```

To see all the available commands and config flags, run the  `help` command inside the crypto cli.

### Using Custom JKS Keystore

To run with your own custom JKS keystore it must be mounted as as volume the docker container. For example, if you had a keystore file on your local machine under `/keystores/mykeystore.p12` you would run the container using:&#x20;

```bash
docker run -it --rm  -v /keystores/mykeystore.p12:/app/resources/mykeystore.p12 \
interledger4j/crypto-cli
```

Then in the CLI, you would switch the keystore to `mykeystore.p12`:

```bash
crypto-cli:> jks-filename mykeystore.p12
```

### Using GCP KMS

If you want to use GCP KMS instead of JKS, you must provide your [Google Service Account key](https://cloud.google.com/iam/docs/creating-managing-service-account-keys) file to the crypto-cli container. For example, if I generated and downloaded my service account key file to `/gcp/my-service-account.json` then I would provide my key file via the following docker command:

```bash
docker run -it --rm -v /gcp/my-service-account.json:/app/gcp-credentials.json \
interledger4j/crypto-cli
```

## Create a Keystore

To create a Keystore that the CLI can use, issue the following command to create a new keystore with an AES-256 SecretKey inside:

```bash
> keytool -keystore ./crypto.p12 -storetype PKCS12 -genseckey -alias secret0 -keyalg aes -keysize 256
> keytool -keystore ./crypto.p12 -storetype PKCS12 -list
```


# Spring Boot with TLS

***Note: These steps were taken from*** [***Secure Spring Boot Applications with TLS and HTTP/2***](https://blog.novatec-gmbh/%20.de/spring-boot-applications-tls-http2/)***. All Keys and CAs in these folders are provided for example purposes only and SHOULD not be used for any production purposes other than demonstrating capabilities.***

## Setting up a private Certificate Authority (CA)

### Certificate for Root CA

```
keytool -genkeypair -storetype pkcs12 -keyalg RSA -keysize 3072 -alias root-ca \
-dname "CN=My Root CA,OU=Development,O=My Organization,C=DE" \
-ext BC:c=ca:true -ext KU=keyCertSign -validity 3650 \
-keystore ./root-ca/ca.jks -storepass secret -keypass secret
```

```
keytool -exportcert -keystore ./root-ca/ca.jks -storepass secret \
-alias root-ca -rfc -file ./root-ca/ca.pem
```

### Signed Server Certificate

```
keytool -genkeypair -storetype pkcs12 -keyalg RSA -keysize 3072 \
-alias localhost -dname "CN=localhost,OU=Development,O=My Organization,C=DE" \
-ext BC:c=ca:false -ext EKU:c=serverAuth -ext "SAN:c=DNS:localhost,IP:127.0.0.1" \
-validity 3650 -keystore ./server/server.jks -storepass secret -keypass secret
```

```
keytool -certreq -keystore ./server/server.jks -storepass secret \
-alias localhost -keypass secret -file ./server/server.csr
```

```
keytool -gencert -storetype pkcs12 -keystore ./root-ca/ca.jks -storepass secret \
 -infile ./server/server.csr -alias root-ca -keypass secret \
 -ext BC:c=ca:false -ext EKU:c=serverAuth -ext "SAN:c=DNS:localhost,IP:127.0.0.1" \
 -validity 3650 -rfc -outfile ./server/server.pem
```

```
keytool -importcert -noprompt -keystore ./server/server.jks -storepass secret -alias root-ca -keypass secret -file ./root-ca/ca.pem \
keytool -importcert -noprompt -keystore ./server/server.jks -storepass secret -alias localhost -keypass secret -file ./server/server.pem
```

## Configure TLS in Spring Boot

To enable TLS put the following entries into your application.properties file.

```
server.port=8443
server.ssl.enabled=true
server.ssl.key-store=classpath:tls/server/server.jks
server.ssl.key-store-type=PKCS12
server.ssl.key-store-password=secret
server.ssl.key-alias=localhost
server.ssl.key-password=secret
```

With these property entries you will change the following behavior:

* The application is started on port 8443 instead of port 8080 (by convention this is the usual port for HTTPS connections).
* Use our new java key store server.jks which is of type PKCS12 and is opened with given store password
* Define the alias of public/private key to use for the server certificate with corresponding key password

Important: Please do not forget to copy the java key store file server.jks you have created in previous section into the src/main/resource folder of the new spring boot application.


# Admin API

Create and manage account on the Connector.

The Connector Admin API allows an administrator to configure the account by adding accounts, settings routes, and more. The API is documented using the [Open API v3 specification](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md).&#x20;

To view the documentation, navigate to <https://petstore.swagger.io/> and enter this URL into the "Explore" bar:&#x20;

`https://raw.githubusercontent.com/sappenin/java-ilpv4-connector/master/connector-server/swagger/connector-admin-open-api3.yaml`


# ILP TestNet: Getting Started

Create an account on the ILP TestNet to send and receive money.

## Overview

This tutorial describes how to:

1. Create an account at <https://faucet.ilpv4.dev>.
2. Grab an API token.
3. Fund your account using the TestNet Rainmaker.
4. Check your balance.
5. Pay a Friend.
6. Get paid.

## 1. Get Super Powers

Create a new, programmable TestNet account at <https://faucent.ilpv4.dev>.

{% hint style="warning" %}
If you want to experiment with a Wallet UI instead of a programmable account, you can experiment with <https://wallet.ilpv4.dev.&#x20>;

Note that this account is distinct from any accounts created by the faucet above, and wallet accounts ***do not*** support bearer-token programmability (only the faucet supports that type of interaction).
{% endhint %}

## 2. Make it Rain

To send your new faucet account faux XRP, issue the following command:

```
curl --location --request POST 'https://hermes-rest.ilpv4.dev/accounts/{your-account-id}/money' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data-raw ''
```

This will add 10 faux XRP to your faucet account.

{% hint style="info" %}
The Rainmaker is available to any anyone who asks - after all, this is just a TestNet!
{% endhint %}

If you prefer a UI instead, the testnet wallet at <https://wallet.ilpv4.dev> has a rainmaker button that you can use to send yourself some faux XRP. Click the button in that wallet to grant yourself some XRP.

{% hint style="danger" %}
As noted above, the Faucet and the Wallet UI accounts are distinct.
{% endhint %}

## 3. Grab an API Token

In the ilpv4.dev [Faucet](https://faucet.ilpv4.dev/), you can obtain an API token by pressing the `Generate ILP Testnet Credentials` button.

{% hint style="danger" %}
Make sure to capture the generated credentials because once you close your browser window, the API token and other account information will be lost, and is otherwise unrecoverable.
{% endhint %}

## 4. Check Your Balance

To see how much money is in your account, try the following call:

```bash
curl --location --request GET 'https://jc.ilpv4.dev/accounts/{your-faucet-account-id}/balance' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {auth_token}'
```

{% hint style="warning" %}
Be sure to replace **`{your-account-id}`**&#x61;n&#x64;**`{auth_token}`**&#x77;ith values from the ilpv4.dev [Faucet](https://faucet.ilpv4.dev).
{% endhint %}

This request will return a JSON payload similar to this one:

```javascript
{
    "assetCode": "XRP",
    "assetScale": "9",
    "accountBalance": {
        "accountId": "user_ykqwwe2b",
        "netBalance": "0",
        "clearingBalance": "0",
        "prepaidAmount": "0"
    }
}
```

## 5. Pay a Friend

Spread the love to a friend by making a payment to a payment pointer. In this case, try sending value to a different wallet on the testnet. Maybe someone at <https://rafiki.money>.

```bash
curl --location \
--request POST 'https://hermes-rest.ilpv4.dev/accounts/{your-account-id}/pay' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {auth_token}' \
--data-raw '{
  "amount": "1000000",
  "destinationPaymentPointer": "$rafiki.money/p/{receiver-email-address}"
}'
```

{% hint style="warning" %}
Be sure to replace **`{your-account-id}, {auth_token}, and {receiver-email-address}`**&#x77;ith appropriate values from Step 1 and from the Rafiki wallet.
{% endhint %}

This request will return JSON similar to the JSON below, representing 1,000 XRP drops paid:

```
{
    "originalAmount": "1000000",
    "amountDelivered": "1000000",
    "amountSent": "1000000",
    "successfulPayment": true
}
```

{% hint style="info" %}
Note the meaning of the following fields:

**originalAmount**: the amount that you wanted to send.\
**amountDelivered**:  the amount your friend actually received.\
**amountSent**: is the amount that actually got sent to your friend.
{% endhint %}

## 6. Get Paid

Try sending money back to your Faucet wallet using the PaymentPointer obtained in step 1. Then, check your balance programmatically to see that the money has arrived in your account.&#x20;


# Connector Development

Want to get involved in our engineering efforts? We welcome any and all submissions, whether it's a typo, bug fix, or new feature.

## Getting Started as a Contributor

### Project Build Requirements

This project the following software in order to build:

* **Java**: This project requires Java JDK8 or above. To install, follow the directions [here](https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html).
* **Maven**: This project uses Maven to manage dependencies and other aspects of the build. To install Maven, follow the instructions at <https://maven.apache.org/install.html>.

### Checkout & Build

To get started, download the code and then build the project:

```bash
$ git clone https://github.com/sappenin/java-ilpv4-connector
$ mvn clean install
```

### Checkstyle

The project uses checkstyle to keep code-style consistent. All Checkstyle checks are run by default during the build, but if you would like to run checkstyle checks independently, use the following command:

```bash
$ mvn checkstyle:checkstyle
```

### File an Issue

If you find a bug, have an idea, or even a question -- feel free to [create an issue in Github](https://github.com/sappenin/java-ilpv4-connector/issues) and we'll take a look as soon as possible.


# Project Testing

This project includes various tests to ensure the correctness of the product.&#x20;

Test are segmented into two broad categories, **Unit Tests** and **Integration Tests.** By default all unit tests are enabled, and *most* Integration tests are also enabled, although certain classes of integration tests only run inside of the [CI environment](https://circleci.com/gh/sappenin/java-ilpv4-connector).

## Unit Tests

Each class in this implementation should have high levels of unit test coverage. Execution of these tests is orchestrated by the [Maven Surefire Plugin](https://maven.apache.org/surefire/maven-surefire-plugin/), and can be enabled or disabled via command line-switches as detailed below. By default,&#x20;

## Integration Tests

This project includes a single module housing all integration tests: [ilpv4-connector-it](https://github.com/sappenin/java-ilpv4-connector/tree/master/ilpv4-connector-it). By default, most integration tests execute in the local build environment, whereas *all* Integration tests execute in the CI environment.

There are various types of Integration test:

* **Performance ITs**: Validate the performance characteristics of the product.
* **IlpOverHttp ITs**: Validate functionality of two or more nodes peering with each other using [ILP-over-Http](https://github.com/interledger/rfcs/blob/master/0035-ilp-over-http/0035-ilp-over-http.md).
* **Settlement ITs**: Validate functionality of the Settlement subsystems using multiple nodes.

## Project Build Switches

The following commands can be used to build the project while skipping various test suites.

### Run Default IT Suite

```
mvn verify
```

### Skip Unit Tests

```
mvn verify -DskipUTs
```

### Skip Integration Tests

```
mvn verify -DskipITs
```

### Skip All Tests

```
mvn verify -DskipTests
```

### Run Settlement ITs

```
mvn verify -Psettlement
```

### Run Performance ITs

```
mvn verify -Pperformance
```


# Changelog

This implementation follows [Semantic Versioning](https://semver.org/) as closely as possible. All release updates can be found in the project's Github [releases page](https://github.com/interledger4j/ilpv4-connector/releases).


