Skip to main content

Omnichain Smart Contracts vs. Messaging

As you start in developing your idea, you might wonder: how should I build my dApp? Here are some considerations to help inform decisions about your application architecture:

Deciding on an architecture

The older solution—message passing—uses ZetaChain only as a relay to forward messages to another blockchain; e.g. Ethereum → BSC. A dApp would deploy at least one contract on each connected chain. The states & logic of the dApp is scattered across all of these contracts on these chains which are connected by asynchronous messages. This makes sense for certain applications that only need unidirectional and asynchronous logic/effects and that don’t need or benefit from a unified state.

The novel architecture using Omnichain Smart Contracts and ZRC-20 tokens has a very different topology: only one contract on zEVM is needed for a dApp; no dApp contracts are needed on foreign chains. The zEVM manages foreign coins via the ZRC-20 contracts.

dApps can leverage either one of these solutions based on the following considerations:

dApp complexity

More complicated dApps may prefer Omnichain Smart Contracts because the logic & state is more centralized, whereas with messaging, you must broadcast messages and state sync across many contracts on different chains, which can lead to substantially more attack surface and more gas fees (each message requires additional gas to be paid, and the number of messages you must send to maintain a full state sync scales).

Building on top of existing EVM contracts

Common applications like Uniswap V2/V3, Curve, Aave, Compound, and so on that have been audited and battle-tested on Ethereum can easily be deployed and built on top of in ZetaChain. One can extend these applications by adding in compatibility with ZRC-20, but those changes are minimal and the majority of logic may remain the same, and users may interact with these applications in single-step transactions just as they would on Ethereum. On the other hand, with messaging, in many situations (especially those that are more complex), a developer must “recreate the wheel” — recreating the logic in a completely different, asynchronous messaging and state-sync system; messaging cannot leverage existing applications in the same way.

Support of less-smart-contract chains

ZRC-20 can easily support Bitcoin/Algorand/Cardano/XRP which do not have capability or efficiency to support general purpose smart contracts for applications like swapping, lending, etc. Messaging cannot work for these chains, because messaging requires smart contracts on any connected chain.

Foreign gas cost

ZRC-20 may cost significantly less gas than message passing in many use cases because its interactions with foreign chains are confined to fungible coins (standard value transfer of ETH/BNB/MATIC costs 21k gas, moving ERC20 tokens costs around 60k gas; no logic/state on foreign chains means much less gas). Message passing inherently requires processing message data on the source/destination chains which adds additional gas costs for things such as validation, verification, parsing, and so on.

Unifying liquidity

With omnichain smart contracts, you can pair and trade native asset liquidity directly against each other. This minimizes steps to trade native assets (a single step), and neither involves a bridge or wrapping step nor sending complex messages. For example, you could trade Ethereum ETH directly for Polygon USDC through a unified pool in a single transaction. With messages, you can leverage existing liquidity like Uniswap pools on existing chains, and trade via burning/minting ZETA through ZetaChain. This approach may be more complex (more transactions involved, more gas), but doesn’t rely on liquidity within ZetaChain’s ecosystem. While omnichain smart contracts and messaging both provide approaches to unified liquidity, it's up tot he developer to choose based on his system requirements.

Exception handling:

With ZRC-20/zEVM, exception/revert handling is much simpler, as foreign interaction is confined to either a standard ERC-20/contract interaction (success) or no contract interaction (failure) immediately as the transaction is processed. In comparison, although messaging supports reverts, a dApp (and user) must blindly wait for and handle errors in an asynchronous/event-driven way.

Examples of messaging vs. zEVM smart contracts

These two rough examples demonstrate the difference between building with omnichain smart contracts and building with messaging.

Curve/Multi-asset Pool Example

First, let's examine Curve. Imagine creating a Curve pool on Ethereum with Bitcoin BTC, Polygon MATIC, and Ethereum ETH.

  1. You would need to bridge BTC and MATIC to Ethereum (creating new wrapped assets wBTC and wMATIC or attempting to swap for some native/existing asset that represents BTC and MATIC — depending on a bridge vault)
  2. Deposit into a pool created for these assets
  3. To withdraw liquidity, you would need to withdraw from the pool to receive these wrapped versions of your assets
  4. Unwrap them by bridging them individually back to Polygon and Bitcoin.
  5. If anyone swaps through this pool, they receive wrapped assets and subsequently unwrap/bridge the assets to where they ultimately want to send them.

Instead, with an omnichain smart contract that manages BTC, MATIC, and ETH natively, you could have a system where:

  1. You can deposit assets BTC, MATIC, and ETH natively into the pool on ZetaChain in a single step, via simple transfer (or equivalent) transactions.
  2. You can withdraw to all of your addresses on respective native chains in a single transaction on ZetaChain.
  3. If anyone wants to swap through this pool then they can trade by sending native assets, and they'll receive native assets directly into a destination (i. e. BTC sent directly to a Bitcoin address), all in a single step.

With an omnichain multi-asset pool, you have:

  • Fewer steps for both LPs and users who are swapping (less gas, less time spent)
  • Minimized slippage, since the swaps + withdrawals happen in a single transaction and don’t depend on asynchronous timing with messaging or bridging.
  • Significantly reduced risk profile since user assets are not susceptible to bridge/wrapped asset vault exploits.

Lending Example

Omnichain smart contract capabilities may be even more advantageous for complex applications such as cross-chain lending. If you imagine a basic borrow flow, you have the following steps with messages to/from different chains (of course, there are many ways to implement this):

  1. Deposit collateral of asset A on Chain 1
  2. Request to borrow B on Chain 2 against collateral A on Chain 1
  3. Protocol must send a message to verify collateral amount on Chain 1
  4. Protocol must send a message back to Chain 2 in verification of the original request
  5. Protocol allows certain amount of B on Chain 2 to be borrowed based on (some oracle) price of A / B based on the message received from Chain 1.
  6. Protocol sends an amount to borrow requester

Instead, with an omnichain-enabled lending smart contract on ZetaChain, lending could have the following steps.

  1. Deposit collateral into an Aave-like contract pool on zEVM that manages asset A on Chain 1 and asset B on Chain 2.
  2. Borrower requests to borrow asset B against that collateral A based on an oracle check, all within a single synchronous function, which is sent to a target destination.