This page covers the basics of CW20s and the limitations around performing cross-chain actions with CW20 tokens — compared to tokenfactory and “native” Cosmos assets (aka Bank Module assets).

CW20 Token Denom Formatting In API Requests

To use CW20 tokens in the Skip Go API, specify the denom as “cw20:” + the token contract address.

Example denom for Astro on Terra2: cw20:terra1nsuqsk6kh58ulczatwev87ttq2z6r3pusulg9r24mfj2fvtzd4uq3exn26

Background

What is a CW20 token?

CW20 is the fungible token spec for the CosmWasm (i.e. CW) VM. CosmWasm is the most popular smart contract VM among CosmosSDK blockchains today. At a high-level, CW20 is very similar to ERC20 (the popular EVM fungible token standard).

Contracts that comply with the standard implement the following functionalities:

  • Transferring tokens from one account to another
  • Sending tokens to a contract along with a message (similar to callContractWithToken)
  • Tracking balances
  • Delegating balance spending to other accounts and contracts

ASTRO (Astroport’s governance token) is one CW20 token issued on Terra2.

How do CW20 tokens interact with IBC?

CW20-ICS20 converter contracts make a CW20 token compatible with the ICS20 token transfer standard, so they can be sent to other chains over normal ICS20 transfer channels. When they arrive on the destination chain, they’re indistinguishable from bank module and tokenfactory tokens.

These converter contracts are the source of much difficulty when attempting to perform cross-chain actions with CW20s:

  • Different converter contracts implement different versions of the ICS20 standard (e.g. Some don’t support memos, which are required for post-transfer contract calls and multi-hop transfers)
  • On transfer failure, converter contracts just return assets to sender. That means if one of our contracts attempts to send tokens on your behalf unsuccessfully, it will receive the tokens. We can’t atomically send them to you.

How do CW20 tokens compare to “native” (aka bank module) tokens?

“Native” tokens are tokens where minting, burning, balances, and transfer functionality are managed by the bank module, instead of by contracts. Unlike CW20s, native tokens are directly compatible with ICS20 and IBC modules. One can send a native token to another chain over a transfer channel just using a MsgTransfer — no conversion contracts or anything of the sort required.

The downside of native tokens is that they’re permissioned and deeply ingrained into the chain’s state machine. As a result, issuing a new native token requires a chain upgrade. Issuing a CW20 on the other hand, only requires deploying a new contract (just a transaction).

How do CW20 tokens compare to “tokenfactory” tokens?

Tokenfactory tokens are created with the tokenfactory module. They’re designed to have the best of both worlds of CW20 and native tokens:

  • Like CW20s, they’re permissionless and users can create new ones just by submitting transactions — no need to modify the chain’s state machine
  • Like native tokens, they’re directly compatible with IBC out-of-the-box, and the bank module manages their balances + transferring functionality.

This combination of traits leads many to see tokenfactory as a strict improvement on CW20 that devs should prefer in the vast majority of cases. We strongly agree with this conclusion.

Unlike CW20s , tokenfactory tokens have no limitations in the cross-chain functionality Skip Go API can offer for them.

What limitations do CW20 tokens have within the Skip Go API?

At a high-level, basically any multi-chain action—in which the token is on the chain where it was issued for one stage of the action—requires multiple transactions.

In particular, this means you cannot perform the following actions in 1 transaction:

  • IBC transfer after purchasing a cw20 asset
Chain 1 is the origin chain where the cw20 token can be swapped freely, but it cannot be transferred to another chain in the same transaction.

Chain 1 is the origin chain where the cw20 token can be swapped freely, but it cannot be transferred to another chain in the same transaction.

  • Call a contract on a remote chain after purchasing a cw20 asset (e.g. since this requires an IBC transfer under the hood)
Chain 1 is the origin chain, where the token can be used freely for post-route actions, but it cannot be used in post-route actions on other chains.

Chain 1 is the origin chain, where the token can be used freely for post-route actions, but it cannot be used in post-route actions on other chains.

  • IBC transfer from a remote chain to the CW20’s origin chain then perform a swap or any other post-route action on that chain
Chain 2 is the origin chain. The token can be transferred back there, but it can't be used or swapped for anything in the same transaction.

Chain 2 is the origin chain. The token can be transferred back there, but it can't be used or swapped for anything in the same transaction.

In principle, you can use the Skip Go API to construct any of these action sequences across multiple transactions, but it will be more challenging for you and your end users.

Want to help us get better? Have questions or feedback?

You can reach us easily by joining our Discord and grabbing the “Skip Go Developer” role.