Build
Universal EVM
System Contract

The System Contract on ZetaChain serves as the caller for universal apps when they are called from connected chains.

NetworkSystem contract address
Testnet0xEdf1c3275d13489aCdC6cD6eD246E72458B8795B
Mainnet Beta0x91d18e54DAf4F677cB28167158d6dd21F6aB3921

The onlySystem modifier must be applied to the onCrossChainCall function to ensure that only the system contract can call this function.

Useful values and functions in the system contract:

  • wZetaContractAddress: wrapped ZETA address.
  • uniswapv2Router02Address: address of the Uniswap v2 router, which powers the internal liquidity pools.
  • uniswapv2FactoryAddress: address of the Uniswap v2 factory.
  • gasZetaPoolByChainId: returns a pool address of ZETA and a gas token of the specified chain.
  • gasCoinZRC20ByChainId: returns a ZRC-20 address of the gas token of the specified chain.
  • gasPriceByChainId: helper to estimate gas for transactions on connected chains.
  • zetaConnectorZEVMAddress: address of the connector contract. (please, note that this value is currently empty, but will be set with the actual connector address in the next protocol upgrade)

The system contract is inherited from ZetaChain, making it easily accessible from your universal app contract:

pragma solidity 0.8.7;
 
import "@zetachain/protocol-contracts/contracts/zevm/interfaces/IZRC20.sol";
import "@zetachain/protocol-contracts/contracts/zevm/interfaces/zContract.sol";
 
contract YourContract is zContract {
    function onCrossChainCall(
        zContext calldata context,
        address zrc20,
        uint256 amount,
        bytes calldata message
    ) external virtual override {
        // systemContract.gasCoinZRC20ByChainId(context.chainID)
    }
}

To get the system contract address in a client-side application or script, use the getAddress function:

import { getAddress } from "@zetachain/protocol-contracts";
 
const SYSTEM_CONTRACT = getAddress("systemContract", "zeta_testnet");