ERC20

Token pair management and conversion between Ontomir coins and ERC20 tokens

The x/erc20 module from Ontomir evm enables bidirectional conversion between Ontomir SDK coins and ERC20 tokens within the EVM runtime.

For conceptual understanding of Single Token Representation v2, see [Single Token Representation](/docs/evm/next/documentation/concepts/single-token-representation).

Parameters

The module parameters control token conversion and registration :

Parameter
Type
Default
Description

enable_erc20

bool

true

Enable token conversions globally

permissionless_registration

bool

false

Allow anyone to register ERC20 tokens

Parameter Details

Master switch for token conversions:

  • true: All conversions enabled (default)

  • false: Disables all conversions, registration still works

  • Use for emergency pause or maintenance

Controls who can register new ERC20 tokens:

  • false: Only governance can register (default, recommended)

  • true: Anyone can register via MsgRegisterERC20

  • Permissionless risks: spam tokens, malicious contracts

State

The module maintains token pair mappings and allowances :

Object
Key
Value
Description

TokenPair

0x01 + ID

TokenPair

Token pair configuration

TokenPairByERC20

0x02 + address

ID

Lookup by ERC20 address

TokenPairByDenom

0x03 + denom

ID

Lookup by denomination

Allowance

0x04 + hash

Allowance

ERC20 allowances

NativePrecompiles

0x05 + address

bool

Native precompile registry

DynamicPrecompiles

0x06 + address

bool

Dynamic precompile registry

Token Pair Structure

type TokenPair struct {
    Erc20Address  string  // Hex address of ERC20 contract
    Denom         string  // Ontomir coin denomination
    Enabled       bool    // Conversion enable status
    ContractOwner Owner   // OWNER_MODULE or OWNER_EXTERNAL
}

Token Pair Registration

Registration Methods

  1. Automatic Registration (IBC Tokens)

    • IBC tokens (denoms starting with "ibc/") are automatically registered on first receipt

    • No governance proposal or user action required

    • Creates ERC20 precompile at deterministic address

  2. Permissionless Registration (ERC20 Contracts)

    • When permissionless_registration parameter is true

    • Any user can register existing ERC20 contracts via MsgRegisterERC20

    • Useful for integrating existing ERC20 tokens

  3. Governance Registration

    • Always available regardless of parameter settings

    • Can register any ERC20 contract or create new token pairs

    • Required when permissionless_registration is false

Messages

MsgRegisterERC20

Register existing ERC20 contracts for conversion :

message MsgRegisterERC20 {
    string signer = 1;
    repeated string erc20addresses = 2;
}

Requirements:

  • permissionless_registration enabled OR sender is governance authority

  • Valid ERC20 contract at address

  • Contract not already registered

  • Contract implements standard ERC20 interface

MsgConvertCoin

Convert Ontomir coins to ERC20 tokens:

message MsgConvertCoin {
    Coin coin = 1;      // Amount and denom to convert
    string receiver = 2; // Hex address to receive ERC20
    string sender = 3;   // Bech32 address of sender
}

Validation:

  • Token pair exists and enabled

  • Sender has sufficient balance

  • Valid receiver address

MsgConvertERC20

Convert ERC20 tokens to Ontomir coins:

message MsgConvertERC20 {
    string contract_address = 1;  // ERC20 contract
    string amount = 2;            // Amount to convert
    string receiver = 3;          // Bech32 address
    string sender = 4;            // Hex address of sender
}

Validation:

  • Token pair exists and enabled

  • Sender has sufficient ERC20 balance

  • Valid receiver address

MsgToggleConversion

Enable/disable conversions for a token pair (governance only):

message MsgToggleConversion {
    string authority = 1;  // Must be governance account
    string token = 2;      // Address or denom
}

MsgUpdateParams

Update module parameters (governance only):

message MsgUpdateParams {
    string authority = 1;  // Must be governance account
    Params params = 2;     // New parameters
}

Conversion Flows

Native Coin → ERC20

UserModuleBankEVMMsgConvertCoinEscrow coinsMint ERC20ERC20 tokensUserModuleBankEVM

Steps:

  1. Validate token pair enabled

  2. Transfer coins to module account

  3. Mint equivalent ERC20 to receiver

  4. Emit conversion event

ERC20 → Native Coin

UserModuleEVMBankMsgConvertERC20Burn/Escrow tokensRelease coinsNative coinsUserModuleEVMBank

Steps:

  1. Validate token pair enabled

  2. For module-owned: burn ERC20

  3. For external: transfer to module

  4. Release native coins from escrow

  5. Emit conversion event

Precompile System

Native Precompiles

Automatically created for Ontomir coins at deterministic addresses:

// Address derivation
address = keccak256("erc20|<denom>")[:20]

Interface:

interface IERC20 {
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address recipient, uint256 amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
}

Dynamic Precompiles (WERC20)

Optional wrapped interface for registered tokens:

interface IWERC20 is IERC20 {
    function deposit() external payable;
    function withdraw(uint256 amount) external;
}

IBC Integration

IBC Middleware v1

Standard IBC transfer integration :

```go // Automatic registration and conversion on receive OnRecvPacket(packet) { // Auto-register new IBC tokens (with "ibc/" prefix) if !tokenPairExists && hasPrefix(denom, "ibc/") { RegisterERC20Extension(denom) }

  // Auto-convert to ERC20 for Ethereum addresses
  if isEthereumAddress(receiver) {
      convertToERC20(voucher, receiver)
  }

}

// Automatic conversion on acknowledgment OnAcknowledgementPacket(packet, ack) { if wasConverted { convertBackToOntomir(refund) } }

</Expandable>

**Automatic Registration:**

* IBC tokens (denoms starting with "ibc/") are automatically registered on first receipt
* Factory tokens (denoms starting with "factory/") are skipped
* Native chain tokens require explicit registration

### IBC Middleware v2

Enhanced IBC v2 support ([source](https://github.com/Ontomir/evm/blob/v0.4.1/x/erc20/v2/ibc_middleware.go)):

* New packet format support
* Improved error handling
* Multi-hop awareness
* Backward compatibility

## Events

### Registration Events

| Event                     | Attributes                     | When Emitted          |
| ------------------------- | ------------------------------ | --------------------- |
| `register_erc20`          | `erc20_address`, `Ontomir_coin` | Token pair registered |
| `toggle_token_conversion` | `erc20_address`, `Ontomir_coin` | Conversion toggled    |

### Conversion Events

| Event           | Attributes                                                   | When Emitted |
| --------------- | ------------------------------------------------------------ | ------------ |
| `convert_coin`  | `sender`, `receiver`, `amount`, `Ontomir_coin`, `erc20_token` | Coin → ERC20 |
| `convert_erc20` | `sender`, `receiver`, `amount`, `Ontomir_coin`, `erc20_token` | ERC20 → Coin |

### IBC Events

| Event                     | Attributes                              | When Emitted               |
| ------------------------- | --------------------------------------- | -------------------------- |
| `ibc_transfer_conversion` | `sender`, `receiver`, `denom`, `amount` | Auto-conversion during IBC |

## Queries

### gRPC

```protobuf
service Query {
  // Get module parameters
  rpc Params(QueryParamsRequest) returns (QueryParamsResponse);

  // Get all token pairs
  rpc TokenPairs(QueryTokenPairsRequest) returns (QueryTokenPairsResponse);

  // Get specific token pair
  rpc TokenPair(QueryTokenPairRequest) returns (QueryTokenPairResponse);
}

CLI

```bash Query-Params # Query module parameters evmd query erc20 params ```

# Query all registered token pairs
evmd query erc20 token-pairs

# Query specific token pair
evmd query erc20 token-pair test
evmd query erc20 token-pair 0x80b5a32e4f032b2a058b4f29ec95eefeeb87adcd
# Convert Ontomir coin to ERC20
evmd tx erc20 convert-coin 100test 0xReceiverAddress --from mykey

# Convert ERC20 to Ontomir coin
evmd tx erc20 convert-erc20 0xTokenAddress 100000000000000000000 Ontomir1receiver --from mykey
# Register ERC20 token (if permissionless)
evmd tx erc20 register-erc20 0xContractAddress --from mykey

# Via governance (if permissioned)
evmd tx gov submit-proposal register-erc20-proposal.json --from mykey

Integration Examples

DeFi Protocol Integration

// Using precompiled ERC20 interface for IBC tokens
const ibcToken = new ethers.Contract(
    "0x80b5a32e4f032b2a058b4f29ec95eefeeb87adcd", // Precompile address
    ERC20_ABI,
    signer
);

// Standard ERC20 operations work seamlessly
await ibcToken.approve(dexRouter, amount);
await dexRouter.swapExactTokensForTokens(...);

Automatic IBC Conversion

// IBC transfer automatically converts to ERC20
const packet = {
    sender: "Ontomir1...",
    receiver: "0x...",  // EVM address triggers conversion
    token: { denom: "test", amount: "1000000" }
};
// Token arrives as ERC20 in receiver's EVM account

Manual Conversion Flow

// Convert native to ERC20
await client.signAndBroadcast(address, [
    {
        typeUrl: "/Ontomir.evm.erc20.v1.MsgConvertCoin",
        value: {
            coin: { denom: "test", amount: "1000000" },
            receiver: "0xEthereumAddress",
            sender: "Ontomir1..."
        }
    }
]);

Best Practices

Chain Integration

  1. Token Registration Review

    • Audit contracts before registration

    • Verify standard compliance

    • Check for malicious behavior

  2. Precompile Configuration

    • Enable precompiles for frequently used tokens

    • Monitor gas consumption

    • Set appropriate gas costs

  3. IBC Setup

    • Configure middleware stack correctly

    • Test auto-conversion flows

    • Monitor conversion events

Security Considerations

  1. Contract Validation

    // Verify standard interface
    IERC20(token).totalSupply();
    IERC20(token).balanceOf(address(this));
  2. Event Monitoring

    • Track conversion events

    • Monitor for unusual patterns

    • Alert on large conversions

  3. Emergency Response

    • Disable conversions via governance

    • Toggle specific token pairs

    • Have incident response plan

Troubleshooting

Common Issues

Issue
Cause
Solution

"token pair not found"

Token not registered

Register via governance

"token pair disabled"

Conversions toggled off

Enable via governance

"insufficient balance"

Low balance for conversion

Check balance in correct format

"invalid recipient"

Wrong address format

Use hex for EVM, bech32 for Ontomir

"module disabled"

enable_erc20 = false

Enable via governance

Debug Commands

# Check if token is registered
evmd query erc20 token-pair test

# Check module parameters
evmd query erc20 params

# Check account balance (both formats)
evmd query bank balances Ontomir1...
evmd query vm balance 0x...

最后更新于