Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions docs/docs/01-ibc/03-apps/07-address-codec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
---
title: Address Codec
sidebar_label: Address Codec
sidebar_position: 7
slug: /ibc/apps/address-codec
---

# Custom Address Codec

## Overview

Starting in ibc-go `v10.4.0`, the IBC transfer module uses the application's configured address codec to parse sender and receiver addresses. This enables chains to accept multiple address formats in IBC packets—for example, both standard Cosmos bech32 addresses (`cosmos1...`) and Ethereum hex addresses (`0x...`).

## Interface

The Cosmos SDK defines a simple interface for converting between address representations:

```go
type Codec interface {
StringToBytes(text string) ([]byte, error)
BytesToString(bz []byte) (string, error)
}
```

Applications configure a codec implementation on the `AccountKeeper`. The IBC transfer module retrieves this codec via `accountKeeper.AddressCodec()` and uses it throughout packet processing—validating sender addresses when creating packets and parsing receiver addresses when delivering funds.

**Chain independence:** Each chain applies its own codec independently. The sending chain validates senders with its codec, the receiving chain validates receivers with its codec. This works seamlessly across chains with different codec configurations without any protocol changes.

## Implementation

A typical implementation composes the SDK's standard bech32 codec and extends it to parse hex addresses:

```go
type EvmCodec struct {
bech32Codec address.Codec
}

func (c *EvmCodec) StringToBytes(text string) ([]byte, error) {
if strings.HasPrefix(text, "0x") {
// Validate and parse hex address using go-ethereum/common
if !common.IsHexAddress(text) {
return nil, errors.New("invalid hex address")
}
addr := common.HexToAddress(text)
return addr.Bytes(), nil
}
// Default to bech32 parsing
return c.bech32Codec.StringToBytes(text)
}

func (c *EvmCodec) BytesToString(bz []byte) (string, error) {
// Always return bech32 format
return c.bech32Codec.BytesToString(bz)
}
```

This pattern accepts both address formats as input while consistently outputting bech32. This makes the codec a drop-in replacement for the standard codec—existing tooling continues to work unchanged while users gain the ability to specify hex addresses where convenient.

**Note:** A recommended address codec implementation is available in the [cosmos/evm repository](https://github.com/cosmos/evm/blob/main/encoding/address/address_codec.go).

### Application Wiring

After initializing your transfer keeper, configure the codec using the `SetAddressCodec` method:

```go
app.TransferKeeper.SetAddressCodec(evmaddress.NewEvmCodec(sdk.GetConfig().GetBech32AccountAddrPrefix()))
```

For a complete example showing the transfer keeper initialization and address codec configuration, see [evmd app.go](https://github.com/cosmos/evm/blob/vlad/erc20-address-codec/evmd/app.go#L483-L494).

## Usage

Once configured, the chain accepts IBC transfers with receiver addresses in either format:

```bash
# Standard bech32 address
gaiad tx ibc-transfer transfer transfer channel-0 \
cosmos1p9p6h9m8jcn8f7l6h3k2wq9g6yx0l8a9u2n4lr 1000uatom --from sender

# Ethereum hex address
gaiad tx ibc-transfer transfer transfer channel-0 \
0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb 1000uatom --from sender
```

Both formats resolve to the same on-chain account when derived from the same private key. The codec handles conversion to the internal byte representation transparently.

## Reference Implementation

The cosmos/evm repository provides a complete implementation in `utils/address_codec.go` with integration examples in the `evmd` reference chain:

- [**Implementation PR**](https://github.com/cosmos/evm/pull/665)
- [**Example integration**](https://github.com/cosmos/evm/tree/main/evmd)
4 changes: 2 additions & 2 deletions docs/docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@ const config = {
// Exclude template markdown files from the docs
exclude: ["**/*.template.md"],
// Select the latest version
lastVersion: "v10.1.x",
lastVersion: "v10.4.x",
// Assign banners to specific versions
versions: {
current: {
path: "main",
banner: "unreleased",
},
"v10.1.x": {
"v10.4.x": {
path: "v10",
banner: "none",
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
---
title: Address Codec
sidebar_label: Address Codec
sidebar_position: 7
slug: /ibc/apps/address-codec
---

# Custom Address Codec

## Overview

Starting in ibc-go `v10.4.0`, the IBC transfer module uses the application's configured address codec to parse sender and receiver addresses. This enables chains to accept multiple address formats in IBC packets—for example, both standard Cosmos bech32 addresses (`cosmos1...`) and Ethereum hex addresses (`0x...`).

## Interface

The Cosmos SDK defines a simple interface for converting between address representations:

```go
type Codec interface {
StringToBytes(text string) ([]byte, error)
BytesToString(bz []byte) (string, error)
}
```

Applications configure a codec implementation on the `AccountKeeper`. The IBC transfer module retrieves this codec via `accountKeeper.AddressCodec()` and uses it throughout packet processing—validating sender addresses when creating packets and parsing receiver addresses when delivering funds.

**Chain independence:** Each chain applies its own codec independently. The sending chain validates senders with its codec, the receiving chain validates receivers with its codec. This works seamlessly across chains with different codec configurations without any protocol changes.

## Implementation

A typical implementation composes the SDK's standard bech32 codec and extends it to parse hex addresses:

```go
type EvmCodec struct {
bech32Codec address.Codec
}

func (c *EvmCodec) StringToBytes(text string) ([]byte, error) {
if strings.HasPrefix(text, "0x") {
// Validate and parse hex address using go-ethereum/common
if !common.IsHexAddress(text) {
return nil, errors.New("invalid hex address")
}
addr := common.HexToAddress(text)
return addr.Bytes(), nil
}
// Default to bech32 parsing
return c.bech32Codec.StringToBytes(text)
}

func (c *EvmCodec) BytesToString(bz []byte) (string, error) {
// Always return bech32 format
return c.bech32Codec.BytesToString(bz)
}
```

This pattern accepts both address formats as input while consistently outputting bech32. This makes the codec a drop-in replacement for the standard codec—existing tooling continues to work unchanged while users gain the ability to specify hex addresses where convenient.

**Note:** A recommended address codec implementation is available in the [cosmos/evm repository](https://github.com/cosmos/evm/blob/main/encoding/address/address_codec.go).

### Application Wiring

After initializing your transfer keeper, configure the codec using the `SetAddressCodec` method:

```go
app.TransferKeeper.SetAddressCodec(evmaddress.NewEvmCodec(sdk.GetConfig().GetBech32AccountAddrPrefix()))
```

For a complete example showing the transfer keeper initialization and address codec configuration, see [evmd app.go](https://github.com/cosmos/evm/blob/vlad/erc20-address-codec/evmd/app.go#L483-L494).

## Usage

Once configured, the chain accepts IBC transfers with receiver addresses in either format:

```bash
# Standard bech32 address
gaiad tx ibc-transfer transfer transfer channel-0 \
cosmos1p9p6h9m8jcn8f7l6h3k2wq9g6yx0l8a9u2n4lr 1000uatom --from sender

# Ethereum hex address
gaiad tx ibc-transfer transfer transfer channel-0 \
0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb 1000uatom --from sender
```

Both formats resolve to the same on-chain account when derived from the same private key. The codec handles conversion to the internal byte representation transparently.

## Reference Implementation

The cosmos/evm repository provides a complete implementation in `utils/address_codec.go` with integration examples in the `evmd` reference chain:

- [**Implementation PR**](https://github.com/cosmos/evm/pull/665)
- [**Example integration**](https://github.com/cosmos/evm/tree/main/evmd)
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ v0.1.1-0.20231213092633-b306e7a706e1 => v0.1.0+ibc-go-v7.3-wasmvm-v1.5

- The `Initialize`, `Status`, `GetTimestampAtHeight`, `GetLatestHeight`, `VerifyMembership`, `VerifyNonMembership`, `VerifyClientMessage`, `UpdateState` and `UpdateStateOnMisbehaviour` functions in `ClientState` have been removed and all their logic has been moved to functions of the `LightClientModule`.
- The `MigrateContract` function has been removed from `ClientState`.
- The `VerifyMembershipMsg` and `VerifyNonMembershipMsg` payloads for `SudoMsg` have been modified. The `Path` field of both structs has been updated from `v1.MerklePath` to `v2.MerklePath`. The new `v2.MerklePath` field contains a `KeyPath` of `[][]byte` as opposed to `[]string`, see [23-commitment](../../05-migrations/13-v8-to-v9.md#23-commitment). This supports proving values stored under keys which contain non-utf8 encoded symbols. As a result, the JSON field `path` containing `key_path` of both messages will marshal elements as a base64 encoded bytestrings. This is a breaking change for 08-wasm client contracts and they should be migrated to correctly support deserialisation of the `v2.MerklePath` field.
- The `VerifyMembershipMsg` and `VerifyNonMembershipMsg` payloads for `SudoMsg` have been modified. The `Path` field of both structs has been updated from `v1.MerklePath` to `v2.MerklePath`. The new `v2.MerklePath` field contains a `KeyPath` of `[][]byte` as opposed to `[]string`. This supports proving values stored under keys which contain non-utf8 encoded symbols. As a result, the JSON field `path` containing `key_path` of both messages will marshal elements as a base64 encoded bytestrings. This is a breaking change for 08-wasm client contracts and they should be migrated to correctly support deserialisation of the `v2.MerklePath` field.
- The `ExportMetadataMsg` struct has been removed and is no longer required for contracts to implement. Core IBC will handle exporting all key/value's written to the store by a light client contract.
- The `ZeroCustomFields` interface function has been removed from the `ClientState` interface. Core IBC only used this function to set tendermint client states when scheduling an IBC software upgrade. The interface function has been replaced by a type assertion.
- The `MaxWasmByteSize` function has been removed in favor of the `MaxWasmSize` constant.
Expand Down
2 changes: 1 addition & 1 deletion docs/versions.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[
"v10.1.x",
"v10.4.x",
"v8.5.x",
"v7.8.x",
"v6.3.x",
Expand Down
Loading