> ## Documentation Index
> Fetch the complete documentation index at: https://docs.int3face.zone/llms.txt
> Use this file to discover all available pages before exploring further.

# ADR-20: Cross-Chain Transfers

* ADR
* ADR-020: Cross-Chain Transfers

## Status

In Progress

## Overview

### Types of Blockchains

1. **Int3face Chain** - Bridge blockchain that connects all other blockchains.
2. **IBC-Connected Chain** - Blockchain connected to Int3face Chain via IBC protocol.
3. **Bitfrost-Connected Chain** - Blockchain connected to Int3face Chain via the custom off-chain Bi\[t]frost protocol. We can refer here two types of chains in sort of asset origination:
   * **Native** - Native for the asset; as example, Dogecoin for DOGE or Solana for SOL. Asset is presented as a native token on the chain.
   * **Non-Native** - Not native for the asset; as example, Solana for DOGE or Solana for TON. Asset is presented as a self-deployed smart contract on the chain.

### Bridging Routes

#### Int3face as Bridge

| **Route**                          | **Description**                                                                                      | **Example**                                 |
| ---------------------------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------- |
| **Bitfrost → Int3face → IBC**      | Transfer of assets from a Bitfrost-connected chain to an IBC chain via the Int3face chain.           | Transfer of DOGE from Dogecoin to Osmosis.  |
| **IBC → Int3face → Bitfrost**      | Transfer of assets from an IBC-connected chain to a Bitfrost-connected chain via the Int3face chain. | Transfer of DOGE from Osmosis to Dogecoin.  |
| **Bitfrost → Int3face → Bitfrost** | Transfer of assets from a Bitfrost-connected to a Bitfrost-connected chain via the Int3face chain.   | Transfer of DOGE from Dogecoin to Solana.   |
| **IBC → Int3face → IBC**           | Transfer of assets from an IBC-connected chain to an IBC-connected chain via the Int3face chain.     | Transfer of DOGE from Osmosis to CosmosHub. |

#### Int3face as Target|Source

| **Route**               | **Description**                                                           | **Example**                                       |
| ----------------------- | ------------------------------------------------------------------------- | ------------------------------------------------- |
| **IBC → Int3face**      | Transfer of assets from a IBC-connected chain to the Int3face chain.      | Transfer of DOGE from Osmosis to Int3face Chain.  |
| **Int3face → IBC**      | Transfer of assets from the Int3face chain to an IBC-connected chain.     | Transfer of DOGE from Int3face Chain to Osmosis.  |
| **Bitfrost → Int3face** | Transfer of assets from a Bitfrost-connected chain to the Int3face chain. | Transfer of DOGE from Dogecoin to Int3face Chain. |
| **Int3face → Bitfrost** | Transfer of assets from the Int3face chain to a Bitfrost-connected chain. | Transfer of DOGE from Int3face Chain to Solana.   |

***

## Technical Outline

Int3face Bridge utilizes two protocols to facilitate cross-chain transfers:

* **IBC Protocol** - Inter-Blockchain Communication protocol that allows the transfer of assets between two
  Cosmos-compatible chains.
* **Bi\[t]frost Protocol** - Custom off-chain protocol that allows the transfer of assets between Non-Cosmos-compatible
  Chains and Int3face Chain.

### IBC Protocol

IBC Protocol is a standard protocol that allows the transfer of assets between two Cosmos-compatible chains. The
protocol consists of the following messages to sent and receive packets:

#### MsgRecvPacket

The incoming message that is sent from any IBC-compatible chain (like Osmosis) and received by the Int3face chain. If it
contains a valid memo field, the message is processed as cross-chain transfer.

```go theme={null}
type MsgRecvPacket struct {
    Packet  exported.Packet
    Proof   []byte
    ProofHeight clienttypes.Height
    Signer  string
}

type Packet struct {
	Sequence uint64
	SourcePort string
	SourceChannel string
	DestinationPort string
	DestinationChannel string
	Data []byte               // <----- FungibleTokenPacketData
	TimeoutHeight types.Height
	TimeoutTimestamp uint64
}

// Data field in Packet
type FungibleTokenPacketData struct {
	Denom string
	Amount string
	Sender string
	Receiver string
	Memo string // <----- IBCInboundMemo
}

// Memo field in FungibleTokenPacketData
type IBCInboundMemo struct {
	SourceChain     string  `json:"source-chain"`       // Source chain, for example: 'osmosis' <- if transfer is sent from Osmosis
	DestChain       string  `json:"dest-chain"`         // Destination chain, for example: 'dogecoin' <- if transfer is sent to Dogecoin
	DestAddress     string  `json:"dest-address"`       // Destination address, for example: 'D6Z26L69gdk9qYmMkVtL9bXGKp8Be7ZfL8' <- Dogecoin address
	RefundOnFailure bool    `json:"refund-on-failure"`  // Flag to indicate if the transfer should be refunded
}
```

#### MsgTransfer

The outgoing message that is sent by the Int3face chain to any IBC-compatible blockchain (like Osmosis). It contains the
memo field with the information about the cross-chain transfer.

```go theme={null}
type MsgTransfer struct {
    SourcePort string
    SourceChannel string
    Token sdk.Coin
    Sender string
    Receiver string
    TimeoutHeight clienttypes.Height
    TimeoutTimestamp uint64
    Memo string // <----- IBCOutboundMemo
}

// Memo field in MsgTransfer
type IBCOutboundMemo struct {
    OutboundTxHash string `json:"outbound_tx_hash"` // TxHash of outbound transfer on Int3face Chain
    IsRefund       bool   `json:"is_refund"`        // Flag to indicate if the transfer is a refund
	IsRetry        bool   `json:"is_retry"`         // Flag to indicate if the transfer is a retry
}
```

#### IBC Middleware

We have a custom middleware to process the incoming & outgoing IBC packets. It makes two important tasks:

* validation of incoming packets with memo field and creation of outbound transfers directly in the Int3face x/bridge
  module.
* finalization of the outgoing transfers sent via IBC.

```go theme={null}
// When the inbound IBC packet is RECEIVED.
func (im IBCMiddleware) OnRecvPacket(
    ctx sdk.Context,
    packet channeltypes.Packet,
    relayer sdk.AccAddress,
) ibcexported.Acknowledgement {
    // Validate the packet data
    if err := im.validatePacketData(ctx, data); err != nil {
        return ibc.NewEmitErrorAcknowledgement(err)
    }
    
    // Process outbound transfer
    if err := im.bridgeKeeper.OutboundTransfer(ctx, data); err != nil {
        return nil, nil, err
    }

    // Pass the packet to the next middleware
    return im.next.OnRecvPacket(ctx, packet, data)
}

// When the outbound IBC packet is ACKNOWLEDGED.
func (im IBCMiddleware) OnAcknowledgementPacket(
    ctx sdk.Context,
    packet channeltypes.Packet,
    ack ibcexported.Acknowledgement,
    relayer sdk.AccAddress,
) error {
    // Parse packet memo
    memo, err := im.parsePacketMemo(packet)
    if err != nil {
        return err
    }
    
    if memo.IsRefund {
        // Refund the outbound transfer
        if err := im.bridgeKeeper.SetOutboundTransferRefunded(ctx, memo.OutboundTxHash); err != nil {
            return err
        }
    }
    
    // Finalize the outbound transfer
    if err := im.bridgeKeeper.SetOutboundTransferFinalized(ctx, memo.OutboundTxHash); err != nil {
        return err
    }

    // Pass the packet to the next middleware
    return im.next.OnAcknowledgementPacket(ctx, packet, ack, relayer)
}
```

**Incoming IBC Execution Order:**

```markdown theme={null}
Transfer(tokens_unlocked) -> IBCMiddleware(outbound_validated_and_sent)
```

### Bi\[t]frost Protocol

Bi\[t]frost Protocol is a custom off-chain protocol that allows the transfer of assets between Non-Cosmos-compatible
Chains and Int3face Chain.
The protocol is fully-decentralized and relies on the **TSS** as well as **Threshold Voting** mechanism to process the
cross-chain transfers.

#### MsgInboundTransfer

The message is actually a **vote** posted by the Int3face chain Observers to process the incoming transfer.
When observers witness the deposit on the **vault address** they construct and broadcast Tx to vote to mint the tokens on the Int3face chain.
When the threshold of votes is reached, the tokens are minted and the transfer is considered as finalized.

```protobuf theme={null}
message MsgInboundTransfer {
  // ExternalId is a unique ID of the transfer coming from outside.
  // Serves the purpose of uniquely identifying the transfer in another chain
  // (e.g., this might be the BTC tx hash)
  string external_id = 1;
  // ExternalHeight is the height at which the transfer occurred in the external
  // chain
  uint64 external_height = 2;
  // Sender is a sender's address
  string sender = 3;
  // DestAddr is a destination Int3face address
  string dest_addr = 4;
  // AssetID is the ID of the asset being transferred
  AssetID asset_id = 5;
  // Amount of coins to transfer
  string amount = 6;
  // DestChainId is a destination chain of the transfer. If this id is not
  // Int3face chain, we need to perform forwarding of the tokens to the
  // destination chain.
  string dest_chain_id = 7;
  // SrcChainId is a source chain of the transfer origin.
  string src_chain_id = 8;
}
```

#### MsgInboundTransferRetry

The message can be sent by any user to retry the failed inbound transfer. The message is observed and processed by the Observers to retry the transfer.
Each observer will try to find the transfer on the external chain and vote to mint the tokens on the Int3face chain sending **MsgInboundTransfer** again.

Inbound is retriable when received via:

* BITFROST - **YES**
* IBC - **NO**

```protobuf theme={null}
message MsgInboundTransferRetry {
  // ExternalId is a unique ID of the transfer coming from outside.
  // Serves the purpose of uniquely identifying the transfer in another chain
  // (e.g., this might be the BTC tx hash)
  string external_id = 1;
  // ExternalHeight is the height at which the transfer occurred in the external chain.
  uint64 external_height = 2;
}
```

#### MsgInboundTransferPushBack

The message is a vote on designated Inbound Transfer to push it back. The message is constructed and broadcasted by the Observers to Int3face chain to push back the transfer in case of invalid memo or impossibility to process the inbound.

```protobuf theme={null}
message MsgInboundTransferPushBack {
  // ExternalId is a unique ID of the transfer coming from outside.
  required string external_id = 1;
  // ExternalHeight is the height at which the transfer occurred in the external chain.
  required uint64 external_height = 2;
}
```

#### MsgInboundTransferRefunded

The message is a vote on designated Inbound Transfer to refund it. The message is constructed and broadcasted by the Observers to Int3face chain to refund the transfer.
As soon as the threshold of votes is reached, the transfer is considered as refunded.

```protobuf theme={null}
message MsgInboundTransferRefunded {
  // ExternalId is a unique ID of the transfer coming from outside.
  required string external_id = 1;
  // ExternalHeight is the height at which the transfer occurred in the external chain.
  required uint64 external_height = 2;
}
```

#### MsgInboundTransferRefundFailed

The message is a vote on designated Inbound Transfer to mark it as refund failed. The message is constructed and broadcasted by the Observers to Int3face chain to mark the transfer as refund failed if the refund is not possible.
As soon as the threshold of votes is reached, the transfer is considered as refund failed.

```protobuf theme={null}
message MsgInboundTransferRefundFailed {
  // ExternalId is a unique ID of the transfer coming from outside.
  required string external_id = 1;
  // ExternalHeight is the height at which the transfer occurred in the external chain.
  required uint64 external_height = 2;
  // Reason is a reason of the failure.
  required string reason = 3;
}
```

#### MsgOutboundTransfer

The message can be sent by any Int3face account, and it's not a cross-chain actually, because it's a message to burn the tokens on the Int3face chain from the account of sender.
The message is observed and processed by the Observers to construct and broadcast the transfer on the destination chain.

```protobuf theme={null}
message MsgOutboundTransfer {
  // Sender is a sender's Int3face address
  string sender = 1;
  // DestAddr is a destination address
  string dest_addr = 2;
  // AssetID is the ID of the asset being transferred
  AssetID asset_id = 3;
  // Amount of coins to transfer
  string amount = 4;
  // DestChainId is a destination chain of the transfer.
  string dest_chain_id = 5;
}
```

#### MsgOutboundTransferRetry

The message can be sent by any user to retry the failed outbound transfer. The message is observed and processed by the Observers to retry the transfer.
Each observer will try to find the transfer on the destination chain and if transfer is not found, observer will broadcast the transfer again and vote to finalize the transfer sending **MsgOutboundTransferFinalized** again.

Outbound is retriable in case of sent via:

* BITFROST - **YES**
* IBC - **YES**

```protobuf theme={null}
message MsgOutboundTransferRetry {
  // TxHash is a hash of Outbound Transfer on the Int3face chain.
  string tx_hash = 1;
}
```

#### MsgOutboundTransferFinalized

The message is a vote on designated Outbound Transfer to finalize it. The message is constructed and broadcasted by the Observers to Int3face chain to finalize the transfer once the broadcasted transfer is confirmed on the destination chain.
As soon as the threshold of votes is reached, the transfer is considered as finalized.

```protobuf theme={null}
message MsgOutboundTransferFinalized {
  // TxHash is a hash of Outbound Transfer on the Int3face chain.
  string tx_hash = 1;
  // BroadcastedTxHash is a hash of the broadcasted transaction on the destination chain.
  string broadcasted_tx_hash = 2;
}
```

#### MsgOutboundTransferFailed

The message is a vote on designated Outbound Transfer to mark it as failed. The message is constructed and broadcasted by the Observers to Int3face chain to mark the transfer as failed if the broadcasted transfer is not confirmed on the destination chain.
As soon as the threshold of votes is reached, the transfer is considered as failed.

```protobuf theme={null}
message MsgOutboundTransferFailed {
  // TxHash is a hash of Outbound Transfer on the Int3face chain.
  string tx_hash = 1;
  // Reason is a reason of the failure.
  string reason = 2;
}
```

### Int3face Bridge State & Params

Int3face Bridge (x/bridge module) contains the two main structures stored in the state to process cross-chain transfers:

#### Bridge: Params

Int3face bridge module (x/bridge) has configured assets inside the module params.

**Query** - You can query all bridge params via:

```bash theme={null}
int3faced q bridge params
```

```protobuf theme={null}
// Asset is a representation of the asset.
message Asset {
  // ID is the asset's primary key
  AssetID id = 1;
  // Status is a current status of the asset
  AssetStatus status = 2;
  // Exponent represents the power of 10 used for coin representation
  uint64 exponent = 3;
  // ExternalConfirmations is a number of the confirmations on the external
  // chain needed to consider the transfer confirmed
  uint64 external_confirmations = 4;
  // Minimal amount of tokens for transfer
  string min_transfer_amount = 5;
  // ExecutionPeriod defines how long transfer for the given asset required to
  // be in the execution until it can be retried.
  uint64 execution_period = 6;
  // GracePeriod defines how long after the execution period transfer for the
  // given asset can be retried.
  uint64 grace_period = 7;
  // BridgingRoutes defines the list of the chain identifiers where the asset can be transferred.
  repeated BridgingRoute bridging_routes = 8;
}

message AssetID {
  // SourceChain is a source chain name
  string source_chain = 1;
  // Denom is the SourceChain denom
  string denom = 2;
}

enum AssetStatus {
  ASSET_STATUS_UNSPECIFIED = 0;
  ASSET_STATUS_OK = 1;
  ASSET_STATUS_BLOCKED_INBOUND = 2;
  ASSET_STATUS_BLOCKED_OUTBOUND = 3;
  ASSET_STATUS_BLOCKED_BOTH = 4;
}

message BridgingRoute {
  // SourceChain is a source chain name
  string source_chain = 1;
  // DestinationChain is a destination chain name
  string destination_chain = 2;
  // RefundEnabled indicates whether the asset can be refunded back to the source chain by this route
  bool refund_enabled = 3;
}
```

#### Bridge: Inbound Transfers

Structure to store the information about the inbound transfers. It\`s created after the first vote on the **MsgInboundTransfer** and contains the information about the votes and finalization status.

**Key** - The key of the inbound transfer is a hash of the external transaction ID and the external chain height.

Bitfrost Inbound:
Key = sha256(external\_id + external\_height)

IBC Inbound:
Key = sha256(source\_channel + destination\_channel + sequence)

**Query** - You can query inbound transfers via:

Bitfrost Inbound:

```bash theme={null}
int3faced q bridge inbound-transfer [external-id/external-height]
```

IBC Inbound:

```bash theme={null}
int3faced q bridge inbound-transfer [source-channel/dest-channel/sequence]
```

All Inbound transfers:

```bash theme={null}
int3faced q bridge inbound-transfers --limit 100
```

```protobuf theme={null}
message InboundTransfer {
  // Status is a current status of the inbound transfer
  required InboundTransferStatus status = 1;
  // ExternalId is a unique ID of the transfer coming from outside.
  // Serves the purpose of uniquely identifying the transfer in another chain
  // (e.g., this might be the BTC tx hash).
  // Or in case of IBC transfer, it's a {source_channel}-{destination_channel}-{sequence}
  // Example: channel-8836-channel-0-234
  required string external_id = 2;
  // ExternalHeight is the height at which the transfer occurred in the external chain.
  // In case of IBC transfer, it will be zero, because IBC doesn't have the height in transfer data.
  required uint64 external_height = 3;
  // AssetID is the ID of the asset being transferred
  required AssetID asset_id = 4;
  // Amount of coins to transfer
  required string amount = 5;
  // SrcAddr is a source address to refund the tokens in case of the transfer failure.
  required string src_addr = 6;
  // SrcChainId is a source chain of the transfer origin.
  required string src_chain_id = 7;
  // DestAddr is a destination address
  required string dest_addr = 8;
  // DestChainId is a destination chain of the transfer. If this id is not
  // Int3face chain, we need to perform outbound transfer of the tokens to the destination chain.
  required string dest_chain_id = 9;
  // RefundOnFailure indicates whether the transfer can be refunded in case of failure.
  // Tokens will be refunded on the SrcChainId to the SrcAddr.
  required bool refund_on_failure = 10;
  // Voters is a list of validators signed this transfer
  required InboundTransferVotes votes = 11;
  // FinalizedTxHash is a hash of the final int3face transaction which finalized the transfer and minted the tokens.
  required string finalized_tx_hash = 12;
  // ReceivedVia is a channel that was used to receive the transfer.
  required TransferProtocol received_via = 13;
  // CreationTimestamp is a timestamp when the inbound transfer was created
  required uint64 creation_timestamp = 14;
  // LastUpdateAt is a timestamp when the inbound transfer was updated
  required uint64 last_update_timestamp = 15;
}

message AssetID {
  // SourceChain is a source chain name
  required string source_chain = 1;
  // Denom is the SourceChain denom
  required string denom = 2;
}

message InboundTransferVotes {
  // Finalized is a list of validators signed this transfer on finalization
  repeated VoteOnFinalization finalized = 1;
  // PushBack is a list of validators signed this transfer on push back (in case of invalid memo and impossibility to process inbound)
  repeated VoteOnPushBack push_back = 2;
  // Refunded is a list of validators signed this transfer on refunding
  repeated VoteOnRefund refunded = 3;
  // RefundFailed is a list of validators signed this transfer on refunding failure
  repeated VoteOnFailure refund_failed = 4;
}

message VoteOnFinalization {
  // Voter is a validator signed this transfer on finalization
  required string voter = 1;
}

message VoteOnPushBack {
  // Voter is a validator signed this transfer on push back
  required string voter = 1;
  // Reason is a reason of the push back
  required string reason = 2;
}

message VoteOnRefund {
  // Voter is a validator signed this transfer on refunding
  required string voter = 1;
  // BroadcastedTxHash is a hash of the broadcasted transaction on the source chain
  required string broadcasted_tx_hash = 2;
}

message VoteOnFailure {
  // Voter is a validator signed this transfer on refunding
  required string voter = 1;
  // Reason is a reason of the refunding
  required string reason = 2;
}

enum TransferProtocol {
  IBC = 0;
  BITFROST = 1;
}

enum InboundTransferStatus {
  PROCESSING = 0;
  FINALIZED = 1;
  REFUNDING = 2;
  REFUNDED = 3;
  REFUND_FAILED = 4;
}
```

#### Bridge: Outbound Transfers

Structure to store the information about the outbound transfers. It\`s created after the first vote on the **MsgOutboundTransfer** and contains the information about the votes and finalization status.

**Key** - The key of the outbound transfer is a hash of the int3face transaction where the outbound transfer was created.

OutboundTransferKey = sha256(int3face-tx-hash)

⚠️ **Important Note:** We are relaying on only one outbound transfer per int3face transaction. If we have multiple outbound transfers in one transaction, first finalized transfer will overwrite the others.

**Query** - You can query outbound transfers via:

```bash theme={null}
int3faced q bridge outbound-transfer [int3face-tx-hash]
```

```bash theme={null}
int3faced q bridge outbound-transfers --limit 100
```

```protobuf theme={null}

message OutboundTransfer {
  // Status is a current status of the outbound transfer
  required OutboundTransferStatus status = 1;
  // SentVia is a protocol used for the transfer to sent
  required TransferProtocol sent_via = 2;
  // SrcChainId is a source chain of the transfer origin.
  required string src_chain_id = 3;
  // DestChainId is a destination chain of the transfer
  required string dest_chain_id = 4;
  // DestAddr is a destination address on the destination chain
  required string dest_addr = 5;
  // AssetId is the asset is being transferred
  required AssetID asset_id = 6;
  // Amount of coins to transfer
  required string amount = 7;
  // CreationTimestamp is a timestamp when the outbound transfer was created
  required uint64 creation_timestamp = 8;
  // ResolutionTimestamp is a timestamp when the outbound transfer was updated last time
  required uint64 last_update_timestamp = 9;
  // OutboundTransferVotes is a list of different votes collected during the outbound transfer lifecycle
  required OutboundTransferVotes votes = 10;
  // RefundOnFailure indicates whether the transfer can be refunded in case of failure
  required bool refund_on_failure = 11;
  // InboundContext is a context of the inbound transfer that was used to create the outbound transfer
  optional InboundTransferContext inbound_context = 11;
}

message AssetID {
  // SourceChain is a source chain name
  required string source_chain = 1;
  // Denom is the SourceChain denom
  required string denom = 2;
}

message InboundTransferContext {
  // ExternalId is a unique ID of the transfer coming from outside.
  // Serves the purpose of uniquely identifying the transfer in another chain
  // (e.g., this might be the BTC tx hash).
  // Or in case of IBC transfer, it's a {source_channel}-{destination_channel}-{sequence}
  // Example: channel-8836-channel-0-234
  required string external_id = 1;
  // ExternalHeight is the height at which the transfer occurred in the external chain.
  // in case of IBC transfer, it will be zero, because IBC doesn't have the height in transfer data.
  optional uint64 external_height = 2;
}

message OutboundTransferVotes {
  // Finalized is a list of validators signed this transfer on finalization
  repeated VoteOnFinalization finalized = 1;
  // Failed is a list of validators signed this transfer on failure
  repeated VoteOnFailure failed = 2;
}

message VoteOnFinalization {
  // Voter is a validator signed this transfer on finalization
  required string voter = 1;
  // BroadcastedTxHash is a hash of the broadcasted transaction on the destination chain
  required string broadcasted_tx_hash = 2;
}

message VoteOnFailure {
  // Voter is a validator signed this transfer on refunding
  required string voter = 1;
  // Reason is a reason of the refunding
  required string reason = 2;
}

enum OutboundTransferStatus {
  PROCESSING = 0;
  FINALIZED = 1;
  FAILED = 2;
  REFUNDED = 3;
}

enum TransferProtocol {
  IBC = 0;
  BITFROST = 1;
}
```

***

## Bitfrost Observer: Points of reaction

Bitfrost observer constantly scans and monitors the Int3face chain blocks for the events related to transfers and reacts on the following Messages:

| **Message Type**               | **Target Action**  | **Conditions**                                                                                               | **Processing**                                                                                    |
| ------------------------------ | ------------------ | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------- |
| **MsgOutboundTransfer**        | OUTBOUND\_TRANSFER | Always                                                                                                       | Create and broadcast the `withdrawal` transaction on the destination chain.                       |
| **MsgInboundTransfer**         | OUTBOUND\_TRANSFER | Inbound transfer is `finalized` and destination\_chain is not `int3face`.                                    | Create and broadcast the `withdrawal` transaction on the destination chain.                       |
| **MsgRecvPacket**              | OUTBOUND\_TRANSFER | Packet is received via IBC                                                                                   | Create and broadcast the `withdrawal` transaction on the destination chain.                       |
| **MsgInboundTransferPushBack** | REFUND             | Inbound transfer is `refunding` (enough votes to push back)                                                  | Create and broadcast the `withdrawal` transaction on the source chain.                            |
| **MsgOutboundTransferFailed**  | REFUND             | Outbound transfer is `failed`, route is `refundable`, and `refund_on_failure` is true                        | Create and broadcast the `withdrawal` transaction on the source chain.                            |
| **MsgInboundTransferRetry**    | INBOUND\_TRANSFER  | Inbound transfer is not `finalized` or `refunded`, `execution_period` is gone, and `grace period` is active  | Create and broadcast the `MsgInboundTransfer` message again to vote on the transfer finalization. |
| **MsgOutboundTransferRetry**   | OUTBOUND\_TRANSFER | Outbound transfer is not `finalized` or `refunded`, `execution_period` is gone, and `grace period` is active | Create and broadcast the `withdrawal` transaction on the destination chain.                       |

***

## Bridging Implementation

### **Bitfrost -> Int3face -> IBC**

#### **1. Inbound Transfer Processing**

* **Inbound Transfer Initiation:**
  * **User Action:**\
    Deposits tokens to a UTXO Vault address or a Smart Contract address on the source chain.
  * **Observers:**\
    Witness the deposit transaction and submit votes via the **MsgInboundTransfer** to mint/unlock the corresponding tokens on the Int3face chain.
  * **Status Update:**\
    The transfer is marked as **PROCESSING** once the inbound transfer is created.

* **Finalization of Inbound Transfer**
  * **Threshold Achievement:**\
    Once the required number of votes is reached, the **InboundTransfer** status updates to **FINALIZED**.
  * **Token Minting/Unlock:**\
    Tokens are minted/unlocked on the Int3face chain vault address.

<img src="https://mintcdn.com/bitfrst/PNBlJ--Erkkbd-1N/docs/ADR/docs/assets/images/bitfrost-int3face-ibc/inbound-transfer.png?fit=max&auto=format&n=PNBlJ--Erkkbd-1N&q=85&s=04962e462ee79f700c3c25a8c4f2f790" alt="Inbound Transfer Processing" width="853" height="550" data-path="docs/ADR/docs/assets/images/bitfrost-int3face-ibc/inbound-transfer.png" />

#### **2. Outbound Transfer Processing**

* **Outbound Transfer Initiation:**
  * **Bridge Module Action:**\
    After the **Inbound Transfer** is **FINALIZED**, the bridge module triggers a **MsgTransfer** to send tokens to the IBC-connected chain. This includes a designated memo field (`IBCOutboundMemo: { OutboundTxHash, IsRefund }`).
  * **Status Update:**\
    The outbound transfer is created in the x/bridge module with the status **PROCESSING**.
* **Finalization of Outbound Transfer**
  * **Acknowledgement Receipt:**\
    Upon receiving the IBC transfer acknowledgement, the **OutboundTransfer** status updates to **FINALIZED**.

<img src="https://mintcdn.com/bitfrst/PNBlJ--Erkkbd-1N/docs/ADR/docs/assets/images/bitfrost-int3face-ibc/outbound-transfer.png?fit=max&auto=format&n=PNBlJ--Erkkbd-1N&q=85&s=3e9d91fbd4bcccbb7669217ae579247e" alt="Outbound Transfer Processing" width="420" height="246" data-path="docs/ADR/docs/assets/images/bitfrost-int3face-ibc/outbound-transfer.png" />

#### **3. PushBack and Refund Mechanisms**

* **PushBack for Inbound Transfers:**
  * **Invalid Memo Handling:**\
    If an inbound transfer has an invalid memo, Observers send a **MsgInboundTransferPushBack** message to return the transfer to the sender.
  * **Status Update:**\
    Once the push-back vote threshold is met, the status changes to **REFUNDING**.
  * **Refund Process:**
    * **Success:**\
      Observers send **MsgInboundTransferRefunded** to mark as **REFUNDED**.
    * **Failure:**\
      Observers send **MsgInboundTransferRefundFailed** to mark as **REFUND\_FAILED**.

* **Refund for Outbound/Inbound Transfers:**
  * **Failure Handling:**
    If an **OutboundTransfer** fails (due to timeout or acknowledgement failure) and is refundable with the `refund_on_failure` flag enabled, tokens are unlocked on the Int3face chain.
  * **Status Update:**
    * The Outbound transfer is marked as **REFUNDED**.
    * The Inbound transfer is marked as **REFUNDING**.
  * **Refund Process:**
    * **Success:**\
      Observers send **MsgInboundTransferRefunded** to mark the InboundTransfer as **REFUNDED**.
    * **Failure:**\
      Observers send **MsgInboundTransferRefundFailed** to mark the InboundTransfer as **REFUND\_FAILED**.

<img src="https://mintcdn.com/bitfrst/PNBlJ--Erkkbd-1N/docs/ADR/docs/assets/images/bitfrost-int3face-ibc/pushback-refund.png?fit=max&auto=format&n=PNBlJ--Erkkbd-1N&q=85&s=7251ae4a51859f8256f90d20a0f5dfe6" alt="PushBack and Refund Mechanisms" width="1183" height="1560" data-path="docs/ADR/docs/assets/images/bitfrost-int3face-ibc/pushback-refund.png" />

#### **4. Retry Mechanisms**

* **Inbound Transfer Retry:**
  * **Eligibility:**\
    Transfer finalized on external (source) chain. Transfer can be retried if not **FINALIZED** or **REFUNDED**, and the execution period has elapsed with an active grace period.
  * **User Action:**\
    Sends **MsgInboundTransferRetry**.
  * **Observer Action:**\
    Votes to mint tokens again on the Int3face chain.
  * **Finalization:**\
    Upon reaching the vote threshold, the status updates to **FINALIZED**.

* **Inbound Refund Retry:**
  * **Eligibility:**\
    Applicable if the status is not **FINALIZED** or **REFUNDED**, and within the grace period.
  * **User Action:**\
    Retries using the TxHash from **MsgInboundTransferRefundFailed** or **MsgInboundTransferPushBack**.
  * **Observer Action:**\
    Witnesses **MsgOutboundTransferRetry** on the Int3face chain and initiates a refund transaction.
  * **Refund Process:**
    * **Success:**\
      Marks as **REFUNDED**.
    * **Failure:**\
      Marks as **REFUND\_FAILED**.

* **Outbound Transfer Retry:**
  * **Eligibility:**\
    Transfer can be retried if not **FINALIZED** or **REFUNDED** and within the grace period.
  * **User Action:**\
    Sends **MsgOutboundTransferRetry**.
  * **Bridge Module Action:**\
    Initiates another IBC transfer.
  * **Finalization:**\
    Upon acknowledgement, status updates to **FINALIZED**; otherwise, marked as **FAILED**.

<img src="https://mintcdn.com/bitfrst/PNBlJ--Erkkbd-1N/docs/ADR/docs/assets/images/bitfrost-int3face-ibc/retry.png?fit=max&auto=format&n=PNBlJ--Erkkbd-1N&q=85&s=e1e72c4e76d5f34ed83e080540c874a1" alt="Retry Mechanisms" width="1073" height="1420" data-path="docs/ADR/docs/assets/images/bitfrost-int3face-ibc/retry.png" />

### **IBC -> Int3face -> Bitfrost**

#### **1. Inbound Transfer Processing**

* **Inbound Transfer Initiation & Finalization:**
  * **IBC Packet Processing:**\
    User sends an IBC packet with the designated memo field.
  * **Int3face Node Action:**\
    Processes the IBC packet and creates the **InboundTransfer** in the x/bridge module.
  * **Status Update:**\
    Once transfer is created, the transfer is marked as **FINALIZED**.

<img src="https://mintcdn.com/bitfrst/PNBlJ--Erkkbd-1N/docs/ADR/docs/assets/images/ibc-int3face-bitfrost/inbound-transfer.png?fit=max&auto=format&n=PNBlJ--Erkkbd-1N&q=85&s=8034ff2084d0ed5ecbed5f9f9ee6a6de" alt="Inbound Transfer Processing" width="685" height="485" data-path="docs/ADR/docs/assets/images/ibc-int3face-bitfrost/inbound-transfer.png" />

#### **3. Outbound Transfer Processing**

* **Outbound Transfer Initiation:**
  * **Bridge Module Action:**\
    Once tokens are unlocked, the bridge module creates the **OutboundTransfer** in the x/bridge module with the status **PROCESSING**.
* **Broadcast and Feedback**
  * **Observer Broadcasting:**\
    Observers witness the OutboundTransfer and then create and broadcast withdrawal transactions to send the tokens to the destination chain.
  * **Feedback Collection:**
    * **Success:**\
      Observers send **MsgOutboundTransferFinalized** to finalize the OutboundTransfer.
    * **Failure:**\
      Observers send **MsgOutboundTransferFailed** to mark the OutboundTransfer as failed.

<img src="https://mintcdn.com/bitfrst/PNBlJ--Erkkbd-1N/docs/ADR/docs/assets/images/ibc-int3face-bitfrost/outbound-transfer.png?fit=max&auto=format&n=PNBlJ--Erkkbd-1N&q=85&s=dac49908e307fe30e8b43882e265daec" alt="Outbound Transfer Processing" width="655" height="591" data-path="docs/ADR/docs/assets/images/ibc-int3face-bitfrost/outbound-transfer.png" />

#### **3. PushBack and Refund Mechanism**

* **PushBack for Inbound Transfers:**
  * **Invalid Memo Handling:**\
    If the receiver is the Int3face vault address and the memo is invalid, the InboundTransfer is NOT CREATED an IBC packet pushed back to the sender via IBC protocol.

* **Refund for Outbound/Inbound Transfers:**
  * **Failure Handling:**\
    If an **OutboundTransfer** fails (due to withdrawal tx failures) and is refundable with the `refund_on_failure` flag enabled, tokens are minted back to the Int3face chain.
  * **Status Update:**
    * The Outbound transfer is marked as **REFUNDED**.
    * The Inbound transfer is marked as **REFUNDING**.
  * **Bridge Module Action:**\
    Initiates a refund IBC transaction.
  * **Refund Process:**
    * **Success:**\
      Observers send **MsgInboundTransferRefunded** to mark the InboundTransfer as **REFUNDED**.
    * **Failure:**\
      Observers send **MsgInboundTransferRefundFailed** to mark the InboundTransfer as **REFUND\_FAILED**.

<img src="https://mintcdn.com/bitfrst/PNBlJ--Erkkbd-1N/docs/ADR/docs/assets/images/ibc-int3face-bitfrost/pushback-refund.png?fit=max&auto=format&n=PNBlJ--Erkkbd-1N&q=85&s=138609fff77d38f9144ffe2a3dad578a" alt="PushBack and Refund Mechanisms" width="1146" height="874" data-path="docs/ADR/docs/assets/images/ibc-int3face-bitfrost/pushback-refund.png" />

#### **4. Retry Mechanisms**

* **Outbound Transfer Retry:**
  * **Eligibility:**\
    Transfer can be retried if not **FINALIZED** or **REFUNDED** and within the grace period.
  * **User Action:**\
    Sends **MsgOutboundTransferRetry** using the TxHash from **MsgRecvPacket**.
  * **Bridge Module Action:**\
    Initiates another Outbound Transfer.
  * **Observer Action:**\
    Witnesses the retry and initiates a refund transaction if the route is refundable.
  * **Finalization:**
    Upon acknowledgement, status updates to **FINALIZED**; otherwise, marked as **FAILED**.

* **Inbound Refund Retry:**
  * **Eligibility:**\
    Applicable if the status is not **FINALIZED** or **REFUNDED**, and within the grace period.
  * **User Action:**\
    Sends **MsgOutboundTransferRetry** using the TxHash from final **MsgOutboundTransferFailed**.
  * **Bridge Module Action:**\
    Initiates new IBC refund transaction.
  * **Refund Process:**
    * **Success:**\
      Marks as **REFUNDED** when the refund is IBC packet acknowledged.
    * **Failure:**\
      Marks as **REFUND\_FAILED** if IBC packet acknowledgment fails or times out.

<img src="https://mintcdn.com/bitfrst/PNBlJ--Erkkbd-1N/docs/ADR/docs/assets/images/ibc-int3face-bitfrost/retry.png?fit=max&auto=format&n=PNBlJ--Erkkbd-1N&q=85&s=effbed45e006c9b20551445efc60c261" alt="Retry Mechanisms" width="874" height="992" data-path="docs/ADR/docs/assets/images/ibc-int3face-bitfrost/retry.png" />

### **Bitfrost -> Int3face -> Bitfrost**

#### **1. Inbound Transfer Processing**

* **Inbound Transfer Initiation:**
  * **User Action:**\
    Deposits tokens to a Vault address or a Smart Contract address on the Bitfrost chain.
  * **Observers:**\
    Witness the deposit transaction and submit votes via the **MsgInboundTransfer** to mint/unlock the corresponding tokens on the Int3face chain.
  * **Status Update:**\
    The transfer is marked as **PROCESSING** once the inbound transfer is created.

* **Finalization of Inbound Transfer:**
  * **Threshold Achievement:**\
    Once the required number of votes is reached, the **InboundTransfer** status updates to **FINALIZED**.
  * **Token Unlocking:**\
    Tokens are minted/unlocked on the Int3face chain vault address.

#### **2. Outbound Transfer Processing**

* **Outbound Transfer Initiation:**
  * **Bridge Module Action:**\
    Once tokens are minted/unlocked, the bridge module creates the **OutboundTransfer** in the x/bridge module with the status **PROCESSING**.
* **Broadcast and Feedback**
  * **Observer Broadcasting:**\
    Observers witness the OutboundTransfer and then create and broadcast `withdrawal` transactions to send the tokens to the destination chain.
  * **Feedback Collection:**
    * **Success:**\
      Observers send **MsgOutboundTransferFinalized** to finalize the OutboundTransfer.
    * **Failure:**\
      Observers send **MsgOutboundTransferFailed** to mark the OutboundTransfer as failed.

#### **3. PushBack and Refund Mechanisms**

* **PushBack for Inbound Transfers:**
  * **Invalid Memo Handling:**\
    If an inbound transfer has an invalid memo, Observers send a **MsgInboundTransferPushBack** message to return the transfer to the sender.
  * **Status Update:**\
    Once the push-back vote threshold is met, the status changes to **REFUNDING**.
  * **Refund Process:**
    * **Success:**\
      Observers send **MsgInboundTransferRefunded** to mark as **REFUNDED**.
    * **Failure:**\
      Observers send **MsgInboundTransferRefundFailed** to mark as **REFUND\_FAILED**.

* **Refund for Outbound/Inbound Transfers:**
  * **Failure Handling:**\
    If an **OutboundTransfer** fails (due to timeout or acknowledgement failure) and is refundable with the `refund_on_failure` flag enabled, tokens are unlocked on the Int3face chain.
  * **Status Update:**
    * The Outbound transfer is marked as **REFUNDED**.
    * The Inbound transfer is marked as **REFUNDING**.
  * **Refund Process:**
    * **Success:**\
      Observers send **MsgInboundTransferRefunded** to mark the InboundTransfer as **REFUNDED**.
    * **Failure:**\
      Observers send **MsgInboundTransferRefundFailed** to mark the InboundTransfer as **REFUND\_FAILED**.

#### **4. Retry Mechanisms**

* **Inbound Transfer Retry:**
  * **Eligibility:**\
    Transfer can be retried if not **FINALIZED** or **REFUNDED**, and the execution period has elapsed with an active grace period.
  * **User Action:**\
    Sends **MsgInboundTransferRetry**.
  * **Observer Action:**\
    Votes to mint/unlock tokens again on the Int3face chain.
  * **Finalization:**\
    Upon reaching the vote threshold, the status updates to **FINALIZED**.

* **Inbound Refund Retry:**
  * **Eligibility:**\
    Applicable if the status is not **FINALIZED** or **REFUNDED**, and the execution period has elapsed with an active grace period.
  * **User Action:**\
    Retries using the TxHash from **MsgInboundTransferRefundFailed** or **MsgInboundTransferPushBack**.
  * **Observer Action:**\
    Witnesses **MsgOutboundTransferRetry** on the Int3face chain and initiates a refund transaction to the source chain.
  * **Refund Process:**
    * **Success:**\
      Marks as **REFUNDED**.
    * **Failure:**\
      Marks as **REFUND\_FAILED**.

* **Outbound Transfer Retry:**
  * **Eligibility:**\
    Transfer can be retried if not **FINALIZED** or **REFUNDED** and the execution period has elapsed with an active grace period.
  * **User Action:**\
    Sends **MsgOutboundTransferRetry**.
  * **Observer Action:**\
    Witnesses **MsgOutboundTransferRetry** on the Int3face chain and initiates a retry transaction to the destination chain.
  * **Retry Process:**
    * **Success:**\
      Marks as **FINALIZED**.
    * **Failure:**\
      Marks as **FAILED**.

### **IBC -> Int3face -> IBC**

#### **1. Inbound Transfer Processing**

* **Inbound Transfer Initiation:**
  * **User Action:**\
    Initiates a transfer by sending an IBC packet with the designated memo field (`IBCInboundMemo: { SourceChain, DestChain, DestAddress, RefundOnFailure }`) from the IBC-connected source chain.
  * **Int3face Node Action:**\
    Processes the incoming IBC packet and creates an **InboundTransfer** entry in the `x/bridge` module on the Int3face chain.
  * **Status Update:**\
    The transfer is marked as **PROCESSING** once the **InboundTransfer** is created.

* **Finalization of Inbound Transfer:**
  * **Threshold Achievement:**\
    Observers submit votes via the **MsgInboundTransfer**. Once the required number of votes is reached, the **InboundTransfer** status updates to **FINALIZED**.
  * **Token Unlocking:**\
    Tokens are unlocked on the Int3face chain vault address, making them available to the user.

#### **2. Outbound Transfer Processing**

* **Outbound Transfer Initiation:**
  * **Bridge Module Action:**\
    After the **Inbound Transfer** is **FINALIZED**, the bridge module triggers a **MsgTransfer** to send tokens back to the IBC-connected destination chain. This includes a designated memo field (`IBCOutboundMemo: { OutboundTxHash, IsRefund }`).
  * **Status Update:**\
    The outbound transfer is created in the `x/bridge` module with the status **PROCESSING**.

* **Finalization of Outbound Transfer:**
  * **Acknowledgement Receipt:**\
    Upon receiving the IBC transfer acknowledgement from the destination chain, the **OutboundTransfer** status updates to **FINALIZED**.

#### **3. PushBack and Refund Mechanisms**

* **PushBack for Inbound Transfers:**
  * **Invalid Memo Handling:**\
    If the receiver is the Int3face vault address and the memo is invalid, the InboundTransfer is NOT CREATED an IBC packet pushed back to the sender via IBC protocol.

* **Refund for Outbound/Inbound Transfers:**
  * **Failure Handling:**\
    If an **OutboundTransfer** fails (due to timeout or acknowledgement failure) and is refundable with the `refund_on_failure` flag enabled, tokens are unlocked on the Int3face chain.
  * **Status Update:**
    * The **OutboundTransfer** is marked as **REFUNDED**.
    * The **InboundTransfer** is marked as **REFUNDING**.
  * **Refund Process:**
    * **Success:**\
      Observers send **MsgInboundTransferRefunded** to mark the **InboundTransfer** as **REFUNDED**.
    * **Failure:**\
      Observers send **MsgInboundTransferRefundFailed** to mark the **InboundTransfer** as **REFUND\_FAILED**.

#### **4. Retry Mechanisms**

* **Inbound Transfer Retry:**
  * **Eligibility:**\
    Transfer can be retried if it is not **FINALIZED** or **REFUNDED**, and the execution period has elapsed with an active grace period.
  * **User Action:**\
    Sends **MsgInboundTransferRetry**.
  * **Observer Action:**\
    Votes to unlock tokens again on the Int3face chain.
  * **Finalization:**\
    Upon reaching the vote threshold, the status updates to **FINALIZED**.

* **Inbound Refund Retry:**
  * **Eligibility:**\
    Applicable if the status is not **FINALIZED** or **REFUNDED**, and within the grace period.
  * **User Action:**\
    Retries using the `TxHash` from **MsgInboundTransferRefundFailed** or **MsgInboundTransferPushBack**.
  * **Observer Action:**\
    Witnesses **MsgOutboundTransferRetry** on the Int3face chain and initiates a refund transaction to the source chain.
  * **Refund Process:**
    * **Success:**\
      Marks as **REFUNDED**.
    * **Failure:**\
      Marks as **REFUND\_FAILED**.

* **Outbound Transfer Retry:**
  * **Eligibility:**\
    Transfer can be retried if it is not **FINALIZED** or **REFUNDED**, and the execution period has elapsed with an active grace period.
  * **User Action:**\
    Sends **MsgOutboundTransferRetry**.
  * **Bridge Module Action:**\
    Initiates another IBC transfer to the destination chain.
  * **Finalization:**\
    Upon acknowledgement, status updates to **FINALIZED**; otherwise, marked as **FAILED**.
