> ## Documentation Index
> Fetch the complete documentation index at: https://cosmos-docs-pfm-updates.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Example Flows

> This document outlines some example flows leveraging packet forward middleware and formats of the memo field.

This document outlines some example flows leveraging packet forward middleware and formats of the memo field.

## Example Scenarios

### Successful Transfer forwarding through chain B

```mermaid theme={null}
sequenceDiagram
    autonumber
    Chain A ->> Chain B: Send PFM transfer
    Chain B ->> Chain C: Forward
    Chain C ->> Chain B: ACK
    Chain B ->> Chain A: ACK
```

### Memo for simple forward

* The packet-forward-middleware integrated on Chain B.
* The packet data `receiver` for the `MsgTransfer` on Chain A is set to `"pfm"` or some other invalid bech32 string.\*
* The packet `memo` is included in `MsgTransfer` by user on Chain A.

```json theme={null}
{
  "forward": {
    "receiver": "chain-c-bech32-address",
    "port": "transfer",
    "channel": "channel-123"
  }
}
```

### Error on Forwarding Hop, Refund to A

```mermaid theme={null}
sequenceDiagram
    autonumber
    Chain A ->> Chain B: PFM transfer
    Chain B ->> Chain C: Forward
    Chain C ->> Chain B:  ACK error
    Chain B ->> Chain A:  ACK error
```

### Forwarding with Retry and Timeout Logic

```mermaid theme={null}
sequenceDiagram
    autonumber
    Chain A ->> Chain B: PFM transfer
    Chain B ->> Chain C: Forward
    Chain C --x Chain B: Timeout
    Chain B ->> Chain C: Retry forward
    Chain C --x Chain B: Timeout
    Chain B ->> Chain A:  ACK error
```

### Multi-hop Transfer A → B → C → D (full success)

```mermaid theme={null}
sequenceDiagram
    autonumber
    Chain A ->> Chain B: PFM transfer
    Chain B --> Chain B: recv_packet
    Chain B ->> Chain C: forward
    Chain C --> Chain C: recv_packet
    Chain C ->> Chain D: forward
    Chain D --> Chain D: recv_packet
    Chain D ->> Chain C: ack
    Chain C ->> Chain B: ack
    Chain B ->> Chain A: ack
```

### Multi-hop Transfer A → B → C → D (error at D, refund to A)

```mermaid theme={null}
sequenceDiagram
    autonumber
    Chain A ->> Chain B: PFM transfer
    Chain B --> Chain B: recv_packet
    Chain B ->> Chain C: forward
    Chain C --> Chain C: recv_packet
    Chain C ->> Chain D: forward
    Chain D --> Chain D: recv_packet (error)
    Chain D ->> Chain C: ACK error
    Chain C ->> Chain B: ACK error
    Chain B ->> Chain A: ACK error
```

### A -> B -> C full success

1. `A` This sends packet over underlying ICS-004 wrapper with memo as is.
2. `B` This receives packet and parses it into ICS-020 packet.
3. `B` Validates `forward` packet on this step, return `ACK` error if fails.
4. `B` If other middleware not yet called ICS-020, call it and ACK error on fail. Tokens minted or unescrowed here.
5. `B` Handle denom. If denom prefix matches the source chain's (counterparty, A's) port/channel, remove it (path-unwind). If not — add `B`'s port/channel as prefix.
6. `B` Create new ICS-004 packet with timeout from forward for next step, and remaining inner `memo`.
7. `B` Send transfer to `C` with parameters obtained from `memo`. Tokens burnt or escrowed here.
8. `B` Store tracking `in flight packet` under next `(channel, port, ICS-20 transfer sequence)`, do not `ACK` packet yet.
9. `C` Handle ICS-020 packet as usual.
10. `B` On ICS-020 ACK from `C` find `in flight packet`, delete it and write `ACK` for original packet from `A`.
11. `A` Handle ICS-020 `ACK` as usual

[Example](https://mintscan.io/osmosis-testnet/txs/FAB912347B8729FFCA92AC35E6B1E83BC8169DE7CC2C254A5A3F70C8EC35D771?height=3788973) of USDC transfer from Osmosis -> Noble -> Sei

### A -> B -> C with C error ACK

10. `B` On ICS-020 error `ACK` from `C`, find the `in flight packet` and delete it.
11. `B` reverses the tokens it moved when forwarding, refunding them toward `A`.
12. `B` writes an error `ACK` for the original packet from `A`.
13. `A` handles the error `ACK` (a refund) as usual.

Same behavior in case of timeout on `C`

### A packet timeouts on B before C timeouts packet from B

10. `A` Cannot timeout because `in flight packet` has proof on `B` of packet inclusion.
11. `B` waits for ACK or timeout from `C`.
12. `B` timeout from `C` becomes fail `ACK` on `B` for `A`
13. `A` receives success or fail `ACK`, but not timeout

In this case `A` assets `hang` until final hop timeouts or ACK.

### Memo for Retry and Timeout Logic, with Nested Memo (2 forwards)

* The packet-forward-middleware integrated on Chain B and Chain C.
* The packet data `receiver` for the `MsgTransfer` on Chain A is set to `"pfm"` or some other invalid bech32 string.
* The forward metadata `receiver` for the hop from Chain B to Chain C is set to `"pfm"` or some other invalid bech32 string.
* The packet `memo` is included in `MsgTransfer` by user on Chain A.
* A packet timeout of 10 minutes and 2 retries is set for both forwards.

In the case of a timeout after 10 minutes for either forward, the packet would be retried up to 2 times, afterwards an error ack would be written to issue a refund on the prior chain.

`next` is the `memo` to pass to the next transfer hop. Provide it either as a nested JSON object or as an escaped JSON string; PFM accepts both forms and re-serializes the value for the next hop.

`next` as JSON

```json theme={null}
{
  "forward": {
    "receiver": "pfm",
    "port": "transfer",
    "channel": "channel-123",
    "timeout": "10m",
    "retries": 2,
    "next": {
      "forward": {
        "receiver": "chain-d-bech32-address",
        "port": "transfer",
        "channel": "channel-234",
        "timeout": "10m",
        "retries": 2
      }
    }
  }
}
```

`next` as escaped JSON string

```json theme={null}
{
  "forward": {
    "receiver": "pfm",
    "port": "transfer",
    "channel": "channel-123",
    "timeout": "10m",
    "retries": 2,
    "next": "{\"forward\":{\"receiver\":\"chain-d-bech32-address\",\"port\":\"transfer\",\"channel\":\"channel-234\",\"timeout\":\"10m\",\"retries\":2}}"
  }
}
```

## Intermediate Address Security

Intermediate chains don’t need a valid receiver address. Instead, they derive a secure address from the packet’s sender and channel, preventing users from forwarding tokens to arbitrary accounts.

To avoid accidental transfers to chains without PFM, use an invalid bech32 address (e.g., "pfm") for intermediate receivers.
