ERC20 Module
The ERC20 module lets existing bank denoms (IBC bridged tokens, USDC, TokenFactory and Peggy denoms) be used from the Injective EVM. It maintains a mapping between token pairs in its storage, associating an ERC20 contract address with its bank denom. The Bank precompile reads that mapping to resolve which denom an ERC20 call operates on. The module serves two purposes:- Storage: maps bank denom ↔ ERC20 address
- Message type: lets users establish new token pair mappings by issuing a chain message
Tokens deployed directly on the Injective EVM against the Bank precompile do not need a token pair. Their denom is derived from the contract address as
erc20:0x.... This page covers the pairing path for denoms that already exist on the native side. For the conceptual overview of both, see MultiVM Token Standard.Creating a Token Pair
Three types of bank denom can have an associated token pair, each with different rules:
Peggy and IBC pairing is permissionless, so the template is forced. That combination is deliberate: anyone can make a bridged token usable in the EVM, and nobody can attach their own contract to a denom they do not control.
The pair creator becomes the owner of a deployed
MintBurnBankERC20. On a governance created pair, that owner is the governance module address.
Prerequisite: the denom must have supply
Pair creation requires the bank denom to already exist with nonzero supply. Submitting before the first mint fails withErrUnknownBankDenom. For a TokenFactory launch, submit MsgCreateDenom, MsgMint and MsgCreateTokenPair as a single atomic transaction so the three cannot diverge.
Permissions namespaces force the fixed supply template
If the TokenFactory denom has a permissions namespace whose policy disablesMINT, BURN or SUPER_BURN, then:
- the chain deploys
FixedSupplyBankERC20instead ofMintBurnBankERC20, and - any custom ERC20 address in the message is rejected with
ErrInvalidERC20Address.
BURN still produces FixedSupplyBankERC20, which exposes no mint entrypoint at all.
This is driven by the namespace policy status for an action, not by role permissions. A namespace created without explicit policy statuses is backfilled with permissive defaults for every action, so defining roles alone does not force the fixed-supply template. Only an explicitly disabled policy does.
What Pair Creation Validates
When an ERC20 address is supplied, the module checks that:- no token pair already exists for either the bank denom or the ERC20 address,
- the account at that address exists and holds contract code,
- the derived
erc20:0x...denom has neither circulating supply nor bank metadata, otherwiseErrExistingERC20DenomSupply, - the contract answers a
symbol()call under a 300,000 gas cap, otherwiseErrInvalidERC20Address.
ErrExistingERC20DenomSupply fires on supply or metadata. A contract that wrote metadata in its constructor is rejected even with zero supply.
Custom Contracts for TokenFactory Denoms
A custom contract must route balance, supply, transfer, mint and burn through the Bank precompile. The practical way to guarantee that is to extendBankERC20 from Injective’s Solidity contracts, which implements exactly that delegation.
Deploy with empty metadata
BankERC20’s constructor calls bank.setMetadata whenever name or symbol is not empty, or decimals is nonzero. For an unpaired contract the precompile resolves the denom to erc20:0x<contract>, so that call writes metadata for a denom you do not want, and pair creation then fails with ErrExistingERC20DenomSupply.
Deploy with an empty name, an empty symbol and zero decimals. This is an enforced requirement for the pairing path, not a style preference.
BankERC20 is abstract and cannot be deployed on its own. After pairing, name(), symbol() and decimals() resolve through the precompile to the factory denom’s bank metadata, which the denom admin controls with MsgSetDenomMetadata.
Do not mint an independent erc20:0x... supply before pairing, for the same reason.
This is the opposite of a direct EVM deployment. There, setting metadata in the constructor and minting an
erc20:0x... supply is the intended path, because the contract’s own derived denom is the token. See MultiVM Token Standard.Mint and Burn Authority
ERC20 ownership and native TokenFactory authority are separate checks, and satisfying one does not satisfy the other. This is the most common surprise on this path.MintBurnBankERC20.mint() is onlyOwner, so the EVM caller must be the contract owner. The call then reaches the Bank precompile, which submits a native MsgMint with the ERC20 contract address as the sender, not the EVM caller. The native check therefore applies to the contract address:
Burns are stricter. An ERC20
burn() or burnFrom() reaches the chain as MsgBurn with the contract as sender and the holder as the burn-from address, which makes it a burn-from rather than a self-burn:
Changing the denom admin with
MsgChangeAdmin does not change the ERC20’s owner(), and transferring ERC20 ownership does not change the denom admin. If you rotate one, rotate the other.
Authorizing the contract
To mint through the paired ERC20, the contract’s address must be authorized on the native side. Convert the EVM address to its bech32 form first, since the two are the same account in different encodings:TOKEN_INJ with MsgChangeAdmin, or grant it a role carrying MINT in the permissions namespace. Transferring the admin gives the contract sole mint authority, so keep the ERC20 owner key safe: it becomes the only way to mint.
Metadata Authority by Origin
Peggy and IBC denoms arrive with no name, symbol or decimals, and no account on Injective has authority to set them directly. Plan the governance proposal as part of the launch rather than as cleanup after wallets already show a blank token.
Worked Example: Pairing a Custom Contract
This pairs a custom contract with an existing TokenFactory denom on testnet.--erc20 to let the chain deploy MintBurnBankERC20 instead.
Verify that both views agree:
failed to mint: unauthorized account. BankERC20 catches the precompile revert and prefixes it, so the
underlying cause is the TokenFactory authorization check, not the ERC20 onlyOwner modifier.
Authorize the contract as described above, then retry.
Gas
MsgCreateTokenPair gives template deployment a 2,000,000 EVM gas cap. That is the contract deployment budget, not the transaction total, which also covers ante handling and any other messages in the transaction. Use at least --gas 3000000 for a standalone pair creation. Below roughly 2.1M the transaction fails with a gas computation error. Simulate with POST /cosmos/tx/v1beta1/simulate and apply headroom rather than relying on a fixed number across releases.
Deleting a Token Pair
MsgDeleteTokenPair is restricted to governance. It removes the mapping only. It does not migrate, reconcile or burn balances on either side.
Reference
MultiVM Token Standard
Concepts, the four token origins, and which path applies to your token.
Bank Precompile
Interface, denom resolution, and the semantics behind each method.
ERC20 Module Messages
Native message and state specification.
TokenFactory Messages
Denom creation, mint, burn and admin semantics.
