> ## 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.

# ERC20

> ERC-20 token representation and conversion for native Cosmos tokens

The ERC20 module (`x/erc20`) implements Single Token Representation v2 (STRv2), ensuring seamless interoperability between Cosmos coins and EVM ERC-20 tokens. It automatically creates ERC-20 representations for IBC tokens and maintains bidirectional conversion.

## Module Overview

**Purpose**: Provide unified token representation across Cosmos and EVM environments

**Key Functionality**:

* Automatic ERC-20 wrapper creation for Cosmos coins and IBC tokens
* Bidirectional token conversion (Cosmos  EVM)
* Native token precompiles at deterministic addresses
* Dynamic precompile generation for IBC tokens
* ERC-20 allowance tracking for cross-environment compatibility
* Single token representation prevents fragmentation

**Source Code**: [x/erc20](https://github.com/cosmos/evm/tree/main/x/erc20)
**Parameter Defaults**: [x/erc20/types/params.go](https://github.com/cosmos/evm/blob/main/x/erc20/types/params.go#L24-L29)

***

## Single Token Representation v2 (STRv2)

### Problem Solved

Without STRv2, tokens exist in separate "worlds":

* **Cosmos side**: Bank module tracks `ibc/ABC...` denominations
* **EVM side**: Separate ERC-20 contracts with different addresses
* **Result**: Token fragmentation, broken liquidity, complex accounting

### STRv2 Solution

STRv2 ensures a single token representation:

1. **IBC token arrives** → Automatically gets ERC-20 wrapper at deterministic address
2. **User wants EVM access** → Convert bank balance to ERC-20 (same total supply)
3. **User wants Cosmos access** → Convert ERC-20 back to bank balance
4. **Result**: Same token, accessible from both environments, unified liquidity

**Implementation**: [token\_pair.go:18-29](https://github.com/cosmos/evm/blob/main/x/erc20/types/token_pair.go#L18-L29)

***

## Configuration Methods

The ERC20 module is configured through genesis.json before chain launch.

### Method 1: Direct JSON Editing

Edit `~/.evmd/config/genesis.json` directly:

```json theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
{
  "app_state": {
    "erc20": {
      "params": {
        "enable_erc20": true,
        "permissionless_registration": true
      },
      "token_pairs": [
        {
          "erc20_address": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
          "denom": "atest",
          "enabled": true,
          "contract_owner": 1
        }
      ],
      "native_precompiles": ["0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"],
      "dynamic_precompiles": [],
      "allowances": []
    }
  }
}
```

### Method 2: Using jq Command-Line Tool

From [local\_node.sh:247-248](https://github.com/cosmos/evm/blob/main/local_node.sh#L247-L248):

```bash theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
GENESIS="$HOME/.evmd/config/genesis.json"
TMP="$HOME/.evmd/config/tmp_genesis.json"

# Set native precompile for native token
jq '.app_state.erc20.native_precompiles=["0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"]' \
  "$GENESIS" >"$TMP" && mv "$TMP" "$GENESIS"

# Create token pair for native token
jq '.app_state.erc20.token_pairs=[{
  contract_owner:1,
  erc20_address:"0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
  denom:"atest",
  enabled:true
}]' "$GENESIS" >"$TMP" && mv "$TMP" "$GENESIS"
```

***

## Parameters

### enable\_erc20

**What It Does**: Master switch to enable/disable the entire ERC20 module functionality.

**Type**: `bool`

**Valid Values**:

* `true` - Enable ERC-20 conversions and token pairs (recommended)
* `false` - Disable all ERC-20 functionality

**Default**: `true` ([params.go:26](https://github.com/cosmos/evm/blob/main/x/erc20/types/params.go#L26))

**Configuration**:

```json theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
{
  "erc20": {
    "params": {
      "enable_erc20": true
    }
  }
}
```

**Impact**:

* When `true`: Users can convert between Cosmos and ERC-20 representations
* When `false`: All conversions disabled, tokens stay in their native format
* Cannot be changed after genesis without governance proposal

**Use Cases**:

* `true` - Standard for EVM-compatible chains
* `false` - Pure Cosmos chain without EVM token bridging

***

### permissionless\_registration

**What It Does**: Controls who can register new token pairs (create ERC-20 wrappers for Cosmos tokens).

**Type**: `bool`

**Valid Values**:

* `true` - Anyone can register token pairs (recommended for public chains)
* `false` - Only governance can register token pairs (permissioned)

**Default**: `true` ([params.go:27](https://github.com/cosmos/evm/blob/main/x/erc20/types/params.go#L27))

**Configuration**:

```json theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
{
  "erc20": {
    "params": {
      "permissionless_registration": true
    }
  }
}
```

**Impact**:

**When `true` (permissionless)**:

* Any user can call `RegisterCoin` or `RegisterERC20` messages
* IBC tokens automatically get ERC-20 wrappers
* Fastest UX for new tokens
* Standard Ethereum-like behavior

**When `false` (permissioned)**:

* Only governance proposals can create token pairs
* More control over which tokens get ERC-20 representations
* Slower onboarding for new tokens
* Useful for curated token lists

**Recommendation**: Use `true` for public chains to match Ethereum UX

***

## Genesis State

### token\_pairs

**What It Does**: Defines the mappings between Cosmos denominations and ERC-20 contract addresses.

**Type**: Array of `TokenPair` objects

**Structure**: ([token\_pair.go:32-39](https://github.com/cosmos/evm/blob/main/x/erc20/types/token_pair.go#L32-L39))

```protobuf theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
message TokenPair {
  string erc20_address = 1;   // ERC-20 contract address (hex)
  string denom = 2;            // Cosmos denomination
  bool enabled = 3;            // Whether conversions are active
  Owner contract_owner = 4;    // Who owns the ERC-20 contract
}
```

**Contract Owner Types**:

* `OWNER_MODULE = 1` - Owned by erc20 module (native Cosmos token)
* `OWNER_EXTERNAL = 2` - Owned by external EOA (native ERC-20 token)

**Configuration**:

```bash theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
# Using jq (from local_node.sh:248)
jq '.app_state.erc20.token_pairs=[{
  contract_owner:1,
  erc20_address:"0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
  denom:"atest",
  enabled:true
}]' genesis.json > tmp.json && mv tmp.json genesis.json
```

```json theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
{
  "erc20": {
    "token_pairs": [
      {
        "erc20_address": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
        "denom": "atest",
        "enabled": true,
        "contract_owner": 1
      }
    ]
  }
}
```

**Special Address**: `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE` - Standard address for native token (matches Ethereum convention)

**Validation**: ([genesis.go:30-46](https://github.com/cosmos/evm/blob/main/x/erc20/types/genesis.go#L30-L46))

* No duplicate ERC-20 addresses
* No duplicate denominations
* Valid Cosmos denom format
* Valid Ethereum address format

***

### native\_precompiles

**What It Does**: List of ERC-20 contract addresses that should be accessible as stateful precompiles for native Cosmos tokens.

**Type**: Array of hex addresses (strings)

**Purpose**: Enable EVM smart contracts to interact with native Cosmos tokens at deterministic addresses

**Configuration**:

```bash theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
# Using jq (from local_node.sh:247)
jq '.app_state.erc20.native_precompiles=["0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"]' \
  genesis.json > tmp.json && mv tmp.json genesis.json
```

```json theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
{
  "erc20": {
    "native_precompiles": [
      "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"
    ]
  }
}
```

**Requirements**:

* Each precompile address MUST have a corresponding enabled token pair ([genesis.go:54-56](https://github.com/cosmos/evm/blob/main/x/erc20/types/genesis.go#L54-L56))
* Precompile provides ERC-20 interface backed by bank module

**Use Case**: Enable Solidity contracts to call `IERC20(0xEeee...).transfer()` for native token

***

### dynamic\_precompiles

**What It Does**: Similar to native\_precompiles but for IBC tokens that arrive dynamically after genesis.

**Type**: Array of hex addresses (strings)

**Default**: `[]` (empty at genesis, populated automatically during IBC transfers)

**Configuration**:

```json theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
{
  "erc20": {
    "dynamic_precompiles": []
  }
}
```

**How It Works**:

1. IBC token arrives via `ibc/transfer` module
2. ERC20 module automatically creates token pair with deterministic address
3. Address is derived from IBC denom hash ([token\_pair.go:18-29](https://github.com/cosmos/evm/blob/main/x/erc20/types/token_pair.go#L18-L29))
4. Dynamic precompile address added to list
5. EVM contracts can now interact with IBC token

**Address Derivation**: Uses `utils.GetIBCDenomAddress(denom)` to compute deterministic address from IBC denom

**Example**:

* IBC denom: `ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2`
* Derived ERC-20 address: `0x...` (deterministic from denom hash)

***

### allowances

**What It Does**: Stores ERC-20 allowances (approve/transferFrom) that need to persist across Cosmos-EVM conversions.

**Type**: Array of `Allowance` objects

**Structure**:

```protobuf theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
message Allowance {
  string erc20_address = 1;  // ERC-20 contract
  string owner = 2;          // Token owner address
  string spender = 3;        // Approved spender address
  string amount = 4;         // Approved amount
}
```

**Default**: `[]` (empty at genesis)

**Configuration**:

```json theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
{
  "erc20": {
    "allowances": [
      {
        "erc20_address": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
        "owner": "0x1234...",
        "spender": "0x5678...",
        "amount": "1000000000000000000"
      }
    ]
  }
}
```

**Why Needed**: When users convert tokens between Cosmos/EVM, allowances must be preserved for DeFi protocols to work correctly.

**Validation**: ([genesis.go:59-74](https://github.com/cosmos/evm/blob/main/x/erc20/types/genesis.go#L59-L74))

* No duplicate allowances
* Allowance must reference existing token pair
* Valid addresses and amounts

***

## Complete Configuration Example

Based on [local\_node.sh:247-248](https://github.com/cosmos/evm/blob/main/local_node.sh#L247-L248):

```bash theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
#!/bin/bash

GENESIS="$HOME/.evmd/config/genesis.json"
TMP="$HOME/.evmd/config/tmp_genesis.json"

# Configure ERC20 module for native token (atest)
jq '.app_state.erc20.native_precompiles=["0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"]' \
  "$GENESIS" >"$TMP" && mv "$TMP" "$GENESIS"

jq '.app_state.erc20.token_pairs=[{
  contract_owner:1,
  erc20_address:"0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
  denom:"atest",
  enabled:true
}]' "$GENESIS" >"$TMP" && mv "$TMP" "$GENESIS"

# Validate genesis
evmd genesis validate-genesis --home "$HOME/.evmd"
```

Or in genesis.json directly:

```json theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
{
  "app_state": {
    "erc20": {
      "params": {
        "enable_erc20": true,
        "permissionless_registration": true
      },
      "token_pairs": [
        {
          "erc20_address": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
          "denom": "atest",
          "enabled": true,
          "contract_owner": 1
        }
      ],
      "native_precompiles": [
        "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"
      ],
      "dynamic_precompiles": [],
      "allowances": []
    }
  }
}
```

***

## Runtime Operations

### Query Token Pairs

```bash theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
# List all token pairs
evmd query erc20 token-pairs

# Query specific token pair by denom
evmd query erc20 token-pair atest

# Query specific token pair by ERC-20 address
evmd query erc20 token-pair-by-address 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE
```

### Convert Tokens

```bash theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
# Convert Cosmos coin to ERC-20
evmd tx erc20 convert-coin 1000000000000000000atest 0xRecipientAddress \
  --from mykey --chain-id mychain-1

# Convert ERC-20 back to Cosmos coin
evmd tx erc20 convert-erc20 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE \
  1000000000000000000 cosmos1recipient... --from mykey --chain-id mychain-1
```

### Register New Token Pair

```bash theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
# Register Cosmos coin (if permissionless_registration=true)
evmd tx erc20 register-coin ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2 \
  --from mykey --chain-id mychain-1

# Register ERC-20 token (if permissionless_registration=true)
evmd tx erc20 register-erc20 0xTokenAddress --from mykey --chain-id mychain-1
```

***

## EVM Integration

### Using Native Token in Solidity

```solidity theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract MyDeFiProtocol {
    // Native token precompile address
    IERC20 constant NATIVE_TOKEN = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);

    function depositNative(uint256 amount) external {
        // Transfer native Cosmos token (atest) using ERC-20 interface
        NATIVE_TOKEN.transferFrom(msg.sender, address(this), amount);

        // ... DeFi logic ...
    }

    function withdrawNative(uint256 amount) external {
        // Transfer back to user
        NATIVE_TOKEN.transfer(msg.sender, amount);
    }
}
```

### Using IBC Token in Solidity

```solidity theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
// IBC token addresses are deterministic from denom
// Query the address: evmd query erc20 token-pair ibc/ABC...

IERC20 ibcToken = IERC20(0xDeterministicAddressFromIBCDenom);
ibcToken.transfer(recipient, amount);
```

***

## Common Issues and Solutions

### Issue: Token Pair Not Found

**Symptom**: `error: token pair not found for denom X`

**Cause**: No ERC-20 wrapper exists for the Cosmos token

**Solution**:

```bash theme={"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}}
# If permissionless_registration=true:
evmd tx erc20 register-coin <denom> --from mykey

# If permissionless_registration=false:
# Submit governance proposal to register token pair
```

### Issue: Conversion Disabled

**Symptom**: `error: token pair is not enabled`

**Cause**: Token pair exists but `enabled=false`

**Solution**: Submit governance proposal to enable token pair

### Issue: Precompile Not Accessible

**Symptom**: EVM calls to precompile address fail or return no code

**Cause**: Address not in `native_precompiles` or `dynamic_precompiles`

**Solution**:

* For native tokens: Add to `native_precompiles` in genesis
* For IBC tokens: Ensure token pair exists and is enabled

### Issue: IBC Token No ERC-20 Address

**Symptom**: IBC token arrives but no ERC-20 wrapper created

**Cause**: `enable_erc20=false` or module not properly initialized

**Solution**:

* Check `enable_erc20` parameter is `true`
* Check module is in app.go and BeginBlockers/EndBlockers

***

## Related Documentation

* [Building Your Chain Guide](/evm/latest/documentation/getting-started/build-a-chain/overview) - Main configuration walkthrough
* [VM Module](/evm/latest/documentation/cosmos-sdk/modules/vm) - EVM configuration
* [IBC Module](/evm/latest/documentation/cosmos-sdk/modules/ibc) - IBC token handling

***

## Source Code References

* **Module Implementation**: [x/erc20](https://github.com/cosmos/evm/tree/main/x/erc20)
* **Parameter Types**: [x/erc20/types/params.go](https://github.com/cosmos/evm/blob/main/x/erc20/types/params.go)
* **Genesis State**: [x/erc20/types/genesis.go](https://github.com/cosmos/evm/blob/main/x/erc20/types/genesis.go)
* **Token Pair Logic**: [x/erc20/types/token\_pair.go](https://github.com/cosmos/evm/blob/main/x/erc20/types/token_pair.go)
* **IBC Callbacks**: [x/erc20/keeper/ibc\_callbacks.go](https://github.com/cosmos/evm/blob/main/x/erc20/keeper/ibc_callbacks.go)
* **Precompile Management**: [x/erc20/keeper/precompiles.go](https://github.com/cosmos/evm/blob/main/x/erc20/keeper/precompiles.go)
* **Genesis Setup**: [local\_node.sh:247-248](https://github.com/cosmos/evm/blob/main/local_node.sh#L247-L248)
* **ERC-20 Bytecode**: [x/erc20/types/constants.go:8](https://github.com/cosmos/evm/blob/main/x/erc20/types/constants.go#L8)
