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

# Step 7: Run a Transfer

> Run token transfers in both directions and validate the full packet relay flow end-to-end

With the bridge wired, the demo runs four scenarios end-to-end:

* **Cosmos → EVM**: burns IFT tokens on Cosmos and mints the equivalent ERC-20 balance on Besu.
* **EVM → Cosmos**: burns the ERC-20 on Besu and mints IFT tokens back on Cosmos.
* **Packet tracking**: polls the relayer's status API by transaction hash to show transfer state as it progresses.
* **Timeout path**: sends a packet with a short timeout while the relayer is paused, lets it expire, then resumes the relayer so it submits `MsgTimeout` and refunds the sender.

Run [`setup.sh`](https://github.com/cosmos/ibc-e2e-docs-example/blob/main/demo/cosmos-evm/setup.sh):

```bash theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
./setup.sh demo cosmos-evm   # Cosmos → EVM only
./setup.sh demo evm-cosmos   # EVM → Cosmos only
./setup.sh demo all          # all scenarios in sequence
```

## What the script does

### Cosmos → EVM transfer

1. Submit the transfer

```bash theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
sandboxd tx ift transfer $COSMOS_IFT_DENOM $COSMOS_CLIENT_ID $EVM_RECIPIENT $AMOUNT $TIMEOUT_TS
```

The Cosmos IFT module burns the tokens from the sender's account and sends a GMP packet directed to the counterparty IFT contract on the EVM chain.

2. Submit to relayer

The script posts the transaction hash to the relayer's gRPC Relay API:

```
skip.relayer.RelayerApiService/Relay { tx_hash, chain_id }
```

This triggers the relayer to pick up the packet immediately rather than waiting for its next poll cycle.

3. Relay delivery

The relayer fetches a proof from the Proof API, constructs a `MsgRecvPacket` transaction, and submits it to the EVM chain. The ICS-27 GMP contract on the EVM side decodes the packet payload and calls `iftMint` on the `IFTOwnable` contract, minting ERC-20 tokens to the recipient address.

4. Acknowledgement

The IBC contract emits a `WriteAcknowledgement` event. The relayer picks it up, fetches a proof from the Proof API, and submits a `MsgAcknowledgement` to Cosmos. This completes the packet lifecycle on the source chain.

5. Balance snapshot

The script polls the Cosmos bank balance (packet commit) and the ERC-20 balance (relay delivery) and prints before/after snapshots when the relay completes.

### EVM → Cosmos transfer

1. Submit the transfer

```
IFTOwnable.iftTransfer(
  clientId:         EVM_CLIENT_ID,
  receiver:         <cosmos_bech32_address>,
  amount:           1000000,
  timeoutTimestamp: <now + 1200s>
)
```

`iftTransfer` burns the ERC-20 tokens from the sender, uses the registered `CosmosIFTSendCallConstructor` to encode a `MsgIFTMint` GMP payload, and calls `ICS27GMP.sendCall` on `gmpport`.
The packet is committed in the `ICS26Router`.

2. Submit to relayer

The EVM transaction hash is posted to the relayer's Relay API to trigger immediate pickup.

3. Relay delivery

The relayer fetches an attestation proof from the Proof API, submits `MsgRecvPacket` to the Cosmos chain, and the GMP module executes the embedded `MsgIFTMint`, minting `COSMOS_IFT_DENOM` tokens to the receiver.

4. Acknowledgement

The Cosmos chain emits a `WriteAcknowledgement` event. The relayer picks it up, fetches a proof from the Proof API, and calls `ackPacket` on the `ICS26Router` on the EVM chain. This clears the packet commitment on the EVM side and completes the packet lifecycle.

### Packet tracking

After either transfer, the script polls the relayer's status API with the transaction hash:

```
skip.relayer.RelayerApiService/Status { tx_hash, chain_id }
```

The response includes the current transfer state. The script polls until the state reaches `TRANSFER_STATE_COMPLETE` or `TRANSFER_STATE_FAILED` and prints the full status JSON.

### Timeout path

This demo includes a script to simulate a timeout:

1. The relayer container is paused (`docker compose pause relayer`).
2. A transfer is submitted with a 60-second timeout.
3. The script waits for the timeout to expire.
4. The relayer is resumed (`docker compose unpause relayer`).
5. The relayer sees an expired packet, fetches a timeout proof from the Proof API, and submits `MsgTimeout` to Cosmos.
6. The Cosmos IFT module refunds the sender.

The script confirms the timeout path by checking that the status response includes a non-empty `timeoutTx.txHash`.

### Observability

The script samples the following without any additional setup:

| Endpoint                       | Content                                                                     |
| ------------------------------ | --------------------------------------------------------------------------- |
| `relayer:3000/health`          | Relayer HTTP health check                                                   |
| `relayer:9100/metrics`         | Prometheus metrics (packet counts, relay latency)                           |
| `attestor:9101`                | Attestor gRPC server (used by Proof API)                                    |
| `docker compose logs relayer`  | Structured JSON logs (fields: `msg`, `source_chain_id`, `tx_hash`, `state`) |
| `docker compose logs attestor` | OpenTelemetry spans (fields: `name`, `height`, `durationMs`, `status`)      |

## What you've built

At this point, you have a fully functioning IBC v2 bridge between a Cosmos chain and an EVM chain. Tokens burn on one side, a packet is committed, an attestor signs the state, the relayer delivers the proof, and tokens mint on the other side.

You can view more commands for this demo in the [Quickstart](/ibc/next/cosmos-evm/tutorial/quickstart).
