# Fiber Cross-Chain Payment Routing Specification
## Metadata
**Status**:: #x
**Zettel**:: #zettel/fleeting
**Created**:: [[2024-08-06]]
## Synopsis
This document focuses on sending payments through a known path in the Fiber P2P network. Finding the path and protecting privacy are not covered here, as they have their own specifications.
A path in the Fiber P2P network can be represented as a list of node public keys. For example, $\{N_0, N_1, N_2, N_3\}$ is a 3-hop path. $N_0$ is the origin node, $N_3$ is the destination node, and $N_1$, $N_2$ are intermediate nodes to forward messages. Nodes adjacent in the path have network connections and can send messages to each other. It takes 3 hops to send a message from the origin node $N_0$ to the destination node $N_3$ along the path: $N_0 \to N_1$, $N_1 \to N_2$, and $N_2 \to N_3$.
## General Routing Mechanism
In order to route a message, the origin node constructs the routing packet and send it to the next hop. The routing packet must contain the routing path and payloads for each hop.
The routing packet is constructed by the origin node, which knows the public keys of each intermediate node and of the final node. The origin node also packs the instructions for each hop in the packet. The packet constructed by the original node $N_0$ looks like:
$
\{ P_1, P_2, \ldots, P_k \}
$
The route path is $\{ N_0, N_1, N_2, \ldots, N_k \}$, and $P_i$ is the payload for the hop from $N_{i-1}$ to $N_i$.
Intermediate nodes forwarding the message can can learn which node they should forward the packet to and how to construct the message for the next hop. The node $i$ will receive the routing packet $\{ P_i, P_{i+1}, \ldots, P_k \}$. It acts upon the payload $P_i$, removes it from the routing packet, and send the remaining packet $\{ P_{i+1}, \ldots, P_k \}$ to the next node $N_{i+1}$.
See Sphinx to obfuscate the list of hops and instructions for each hop along the path, so the intermediate nodes can learn which node they should forward the packet but cannot learn the full path nor the payloads for other nodes.
## Payments Routing Specification
### Basic Payment Routing
#### Constructing Routing Packet
The origin node must find the routing path to send the payment. The route finding algorithm will be covered in its own document. Once the path is available, the origin node can send the `AddTlc` message to the next hop. The routing packet is added to `AddTlc` as a new field. The `route_packet` is a vector which index starts from 0. The payload `route_packet[i]` is the payload for the hop from $N_i$ to $N_{i+1}$.
```
table AddTlcRoutePayload {
// short id?
channel_id: Byte32,
amount_to_forward: Uint128,
outgoing_expiry: Uint64,
}
vector AddTlcRoutePacket <AddTlcRoutePayload>
table AddTlc {
channel_id: Byte32,
tlc_id: Uint64,
amount: Uint128,
payment_hash: Byte32,
expiry: Uint64,
hash_algorithm: byte,
route_packet: AddTlcRoutePacket,
}
```
The `amount` in `AddTlc` must include fees for all forwarding nodes. The fee for the first hop is `AddTlc.amount - AddTlc.route_packet[0].amount_to_forward`, and the fee for the hop from node $N_i$ to $N_{i+1}$ where $i > 0$ is `AddTlc.route_packet[i - 1].amount_to_forward - AddTlc.route_packet[i].amount_to_forward`.
The `channel_id` in `route_packet[i]` is the channel used by the node $N_{i+1}$ to forward the message to the next hop.
The field `expiry` in `route_packet[i]` is the expiry set by the node $N_{i+1}$ on the ongoing forwarded message.
For the last hop,
- `expiry`: set to the final expiry specified by the recipient.
- `amount_to_forward`: set to the final amount specified by the recipient.
When `route_packet` is empty or has only one payload, the message receiver is the final recipient.
#### Forwarding TLCs
When a node receives the `AddTlc` message, and there are more than 1 payload in `route_packet`, it should forward the message to the next hop.
Assume that the node has received the `AddTlc` message R, it should construct the outgoing `AddTlc` message S that:
- `S.channel_id`: set to `R.route_packet[0].channel_id`
- `S.tlc_id`: generated TLC id in the specified channel `S.channel_id`
- `S.amount`: set to `R.route_packet[0].amount_to_forward`
- `S.payment_hash`: set to `R.payment_hash`
- `S.expiry`: set to `R.route_packet[0].expiry`
- `S.hash_algorithm`: set to `R.hash_algorithm`
- `S.route_packet`: set to sub array of `R.route_packet` starting from `R.route_packet[1]` (inclusive) to the end.
When a node forwards a TLC, it must ensure the _outgoing_ TLC cannot be redeemed unless the _incoming_ TLC can be redeemed.
The respective addition/removal of an HTLC is considered irrevocably committed when:
The commitment transaction with/without it is committed to by both nodes, and any previous commitment transaction without/with it has been revoked, OR
The commitment transaction with/without it has been irreversibly committed to the blockchain.
Requirements
A node:
until an incoming HTLC has been irrevocably committed:
MUST NOT offer the corresponding outgoing HTLC (update_add_htlc) in response to that incoming HTLC.
until the removal of an outgoing HTLC is irrevocably committed, OR until the outgoing on-chain HTLC output has been spent via the HTLC-timeout transaction (with sufficient depth):
MUST NOT fail the incoming HTLC (update_fail_htlc) that corresponds to that outgoing HTLC.
once the cltv_expiry of an incoming HTLC has been reached, OR if cltv_expiry minus current_height is less than cltv_expiry_delta for the corresponding outgoing HTLC:
MUST fail that incoming HTLC (update_fail_htlc).
if an incoming HTLC's cltv_expiry is unreasonably far in the future:
SHOULD fail that incoming HTLC (update_fail_htlc).
upon receiving an update_fulfill_htlc for an outgoing HTLC, OR upon discovering the payment_preimage from an on-chain HTLC spend:
MUST fulfill the incoming HTLC that corresponds to that outgoing HTLC.
### Fiber to Lightning Routing Via Invoice
### Fiber to Lightning Routing Via Offer
### Lightning to Fiber Routing Via Invoice
### Lightning to Fiber Routing Via Offer