Interledger packets are pieces of data that can be sent from one ledger user to another either as a message or attached to a transfer.
Each ILP packet consists of a series of headers. All headers start with a common eight byte preamble which looks as follows:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type (16) | Length (16) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
Type:
A 16-bit numeric ID identifying the type of header. The values are well-known IDs which map to a URI header type.
The type field has bits with special meaning which are defined below.
-
Length:
Length of the header in bytes. (Does not include the size of the Type and Length fields themselves.)
If the first bit of the type is zero, the header is called a required header. Required headers must be understood by all participants. If a participant encounters a required header that they do not understand, they MUST reject the entire transfer/message.
If the first bit of the header is one, the header is called an optional header. Optional headers may not be understood by all participants. If a participant encounters an optional header that they do not understand, they MUST ignore the header and process the rest of the transfer/message.
For optional headers, the second bit of the type is ignored. This bit is called the Partial bit. If a participant encounters an optional header that they do not understand and the Partial bit is unset, they MUST set the Partial bit before forwarding the packet.
Some header types can only appear as the first element in the message. All primary headers MUST also be required headers. When a participant encounters a primary header that appears after another header, it MUST reject/discard the entire message.
Range | Used for |
---|---|
0...16383 |
Globally unique required types |
16384...32767 |
Primary header-dependent required types |
32768...40959 |
Globally unique optional types |
40960...49151 |
Primary header-dependent optional types |
49152...65535 |
Reserved for partial flag |
Main header attached to ILP payments. Used for routing.
- Primary header: Yes
- Required header: Yes
- Can appear on transfers: Yes
- Can appear on messages: No
- Multiple instances allowed: No
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type (16) | Length (16) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ DestinationAmount (64) +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ DestinationAccount (*) +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
Type
Always
0x0000
; maps to"https://interledger.org/rel/ilp"
-
Length
Length of the ILP header in bytes. (Does not include the size of the Type and Length fields.)
-
DestinationAmount
Destination ILP amount. This is the amount that should be delivered to the destination account. Uses a 64-bit fixed-precision, floating-point decimal format (see Generic Data Types.) Implementations MUST reject negative values.
-
DestinationAccount
Destination ILP account. Connectors should route the payment to this address. The length of this field equals the length of the ILP header minus 8 bytes.
ILP senders can optionally specify their address by including this header. If they wish to include their address, but not the SourceAmount, they MUST set the SourceAmount to the special value of s = 0, e = -128.
- Type: 0x4000 (Primary: 0x0000 / ILP Header)
- Primary header: No
- Required header: Yes
- Can appear on transfers: Yes
- Can appear on messages: No
- Multiple instances allowed: No
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type (16) | Length (16) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ SourceAmount (64) +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ SourceAccount (*) +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
Type
Always
0x4000
; maps to"https://interledger.org/rel/ilp/source"
-
Length
Length of the ILP Source header in bytes. (Does not include the size of the Type and Length fields.)
-
SourceAmount
Source ILP amount. Uses the Amount format (see Generic Data Types.)
-
SourceAccount
Source ILP account. The length of this field equals the length of the ILP header minus 8 bytes.
ILP senders may wish to know what path their payment is taking as it is being processed. This is important for debugging routing issues.
NOTE: More work is needed to evaluate the security and privacy implications of this feature. However, we recognize the need for good debug tools as a critical component of a successful routing architecture.
For more information about the contents of trace packets, please see: https://gist.github.com/justmoon/8e732663c53e39405cac379998e5c46c
- Type: 0x4001 (Primary: 0x0000 / ILP Header)
- Primary header: No
- Required header: Yes
- Can appear on transfers: Yes
- Can appear on messages: No
- Multiple instances allowed: Yes
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type (16) | Length (16) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ +
| |
+ UniqueUUID (128) +
| |
+ +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ +
| |
+ TraceHostIP (128) +
| |
+ +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| TraceHostPort (16) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
Type
Always
0x4001
; maps to"https://interledger.org/rel/ilp/trace"
-
Length
Length of the ILP Trace header in bytes. (Does not include the size of the Type and Length fields.)
-
UniqueUUID
Unique identifier to associate this trace request.
-
TraceHostIP
Host IPv6 that trace packets should be sent to.
-
TraceHostPort
UDP port number where trace packets should be delivered.
Used by senders and connectors to request a quote from a connector.
- Primary header: Yes
- Required header: Yes
- Can appear on transfers: Yes
- Can appear on messages: Yes
- Multiple instances allowed: No
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type (16) | Length (16) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ +
| |
+ QuoteId (128) +
| |
+ +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| DestinationExpiryDuration (32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SourceExpiryDuration (32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ +
| |
+ DestinationAddress (*) +
| |
+ +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
Type
Always
0x0020
; maps to"https://interledger.org/rel/ilqp/quote_request"
-
Length
Length of the ILQP Quote Request header in bytes. (Does not include the size of the Type and Length fields.)
-
QuoteId
ID to identify the quote request.
-
DestinationExpiryDuration
TODO
-
SourceExpiryDuration
TODO
-
DestinationAddress
ILP Address of the destination.
Note that the source address is always implied to be the address of the account
that sent the quote_request
message.
Used by connectors to fulfill a quote request.
- Primary header: Yes
- Required header: Yes
- Can appear on transfers: No
- Can appear on messages: Yes
- Multiple instances allowed: No
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type (16) | Length (16) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
Type
Always
0x0021
; maps to"https://interledger.org/rel/ilqp/quote_response"
-
Length
Length of the ILQP Quote Request header in bytes. (Does not include the size of the Type and Length fields.)
This message is used by two peered connectors to perform an initial handshake before they start exchanging actual routing information.
- Primary header: Yes
- Required header: Yes
- Can appear on transfers: No
- Can appear on messages: Yes
- Multiple instances allowed: No
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type (16) | Length (16) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| MLP Length (16) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ My Ledger Prefix (*) +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
Type
Always
0x0040
; maps to"https://interledger.org/rel/ccp/open"
-
Length
Length of the ILP Trace header in bytes. (Does not include the size of the Type and Length fields.)
This message is used by a connector to update its peer with changes to its published routes.
- Primary header: Yes
- Required header: Yes
- Can appear on transfers: Yes
- Can appear on messages: Yes
- Multiple instances allowed: No
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type (16) | Length (16) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
***TODO***
-
Type
Always
0x0041
; maps to"https://interledger.org/rel/ccp/update"
-
Length
Length of the CCP Update header in bytes. (Does not include the size of the Type and Length fields.)
Simple decimal format consisting of two integers - significand and exponent - with a well-defined range.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Significand (56) |
+ +-+-+-+-+-+-+-+-+
| | Exponent (8) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
Exponent
Signed (two's complement) 8-bit integer signifying the exponent e (base 10) of the amount. The amount is calculated as s * 10^e. The allowed range for e is -127 to 127. The special value e = -128 is reserved.
-
Significand
Signed (two's complement) 56-bit integer representing the integer part of the amount aka the significand s. The amount is calculated as s * 10^e. The allowed range for s is -36,028,797,018,963,968 .. 36,028,797,018,963,967.
There are 255 valid representations of zero. Implementations MUST accept all of them, but MUST produce only the value where s = 0, e = 0.
Generally, applications receiving amounts expressed in this format SHOULD convert them into a suitable arbitrary-precision decimal. This amount format is not intended to be used for calculations directly, however implementors MAY choose to do so for performance reasons if they take appropriate care.
Applications generating amounts in this format SHOULD choose the value closest to the actual value they are trying to represent and round as necessary. Higher-level protocols MAY specify the rounding behavior to be used in a given context.
The authors would have preferred to use an existing standard encoding and strongly considered using the decimal64 format from IEEE 754-2008. Unfortunately, it is significantly more complex to parse than the format presented here and not widely supported enough to make up for the complexity.
Liquidity curves are used to represent the relationship between the input and output amounts of some connector or chain of connectors. It consists of a series of points where the x-axis is denominated in units of the input asset and the y-axis is denominated in units of the output asset. The y-coordinate of a point represents the output amount for a given x amount of input.
Each successive point's x and y values must be greater than the point before it. Coordinates must all be positive.
Between points the curve is thought to be linearly interpolated. Beyond the first and last points the curve is thought to be undefined and transactions in
Local ledger transfer with an ILP header in JSON:
{
"from": "connector",
"to": "sharafian",
"amount": "100",
"data": [{
"type": "https://interledger.org/rel/ilp",
"destination_amount": "100",
"destination_account": "us.nexus.sharafian"
},{
"type": "https://interledger.org/rel/ilp/source",
"source_amount": "104.3",
"source_account": "us.sharafian.justmoon"
}]
}
{
"from": "lila",
"to": "connector",
"data": [{
"type": "https://interledger.org/rel/ilqp/quote_request",
"id": "721e4126-98a1-4974-b35a-8a8f4655f934",
"destination_address": "example.usd-ledger.bob",
"source_expiry_duration": "6000",
"destination_expiry_duration": "5000"
}]
}
{
"from": "connector",
"to": "lila",
"data": [{
"type": "https://interledger.org/rel/ilqp/quote_response",
"id": "721e4126-98a1-4974-b35a-8a8f4655f934",
"source_connector_account": "mark",
"source_ledger": "example.eur-ledger.",
"source_amount": "100.25",
"source_expiry_duration": "6000",
"destination_ledger": "example.usd-ledger.",
"destination_amount": "105.71",
"destination_expiry_duration": "5000",
"liquidity_curve": [
[ 0, 0 ],
[ 100000000, 99799999.99 ]
]
}]
}
A connector wants to tell a peer about a new route.
{
"ledger":"peer.sZapq.usd.",
"from": "peer.sZapq.usd.bVHMFFYfda6f-_obQuqqW2Vo5W15o3ov5MeZldxWCWk",
"to": "peer.sZapq.usd.hMhQUg-lLvVgb3z10jAsxfHw_h-ljkavH9Fxr8vyTQc",
"data": [{
"type": "https://interledger.org/rel/ccp/update",
"new_routes": [{
"source_ledger": "peer.sZapq.usd.",
"destination_ledger": "us.usd.ilptestblah.",
"points": [
[ 0, 0 ],
[ 100000000, 99799999.99 ]
],
"min_message_window": 1,
"source_account": "peer.sZapq.usd.bVHMFFYfda6f-_obQuqqW2Vo5W15o3ov5MeZldxWCWk"
}],
"withdrawn_routes": [
"old.destination."
]
}]
}
57-k
ways to represent anyk
-figure integer number, fork>0
.