Write a Smart Contract
From the moment you decide to create a dApp on Chiliz Chain, you need to take the specifics of our blockchain into account.
While Chiliz Chain is EVM-compatible, treating it exactly like Ethereum can lead to usability issues, specifically regarding token decimals and gas mechanics.
Let's explore!
Prerequisites
Environment
Before you start writing your contract, make sure that your environment is ready.
First, you must have a wallet configured for Spicy Testnet (for development) or Chiliz Chain Mainnet (for production).
Connect to Chiliz ChainSecond, you will need need $CHZ to pay for gas deployment on both Testnet and Mainnet. While you can buy Mainnet $CHZ on any crypto exchange, you can rely on faucets for Testnet tokens.
Testnet FaucetsIn terms of tooling, you can rely on Hardhat or Remix. See for instance:
Deploy with RemixFinally, Chiliz Chain contracts are written in the Solidity language:
Fan Tokens / CAP-20
The most specific aspect of Chiliz Chain is the CAP-20 standard, used for Fan Tokens.
While technically identical to the ERC-20 standard code-wise, CAP-20 tokens have a specific configuration for decimals. In short: It uses 0 decimals, while regular ERC-20 token use 18 decimals.
About Fan TokensTherefore, if you deploy a Fan Token with 18 decimals, it may not display correctly in ecosystem wallets or be compatible with future Socios.com integrations.
Best practices in writing a smart contract
Use Battle-Tested Libraries (OpenZeppelin)
Do not start from creating your contract from scratch. The single most effective security practice is to base your code on community-audited standards, to reduce the risk of vulnerabilities
For Chiliz Chain development, we strongly recommend using OpenZeppelin Contracts. They provide secure and community-vetted implementations for tokens contracts.
By using standard contracts, your ensure that your tokens are compatible with known wallets (like MetaMask) and the Chiliz ecosystem (Socios.com).
General EVM Best Practices
Regardless of the chain, these three patterns are non-negotiable for secure Solidity development.
The "Checks-Effects-Interactions" Pattern
This is your primary defense against Reentrancy Attacks. Always structure your functions in this exact order:
Checks: Validate inputs and conditions (e.g.,
requirestatements).Effects: Update the contract state (e.g., reduce balances).
Interactions: Interact with other contracts or send funds (e.g.,
transfer).
Robust Access Control
Never leave sensitive functions unprotected. If a function mints tokens, changes fees, or upgrades logic, it must be restricted.
Simple: Use
Ownablefor single-admin contracts.Complex: Use
AccessControlfor contracts requiring multiple roles (e.g.,MINTER_ROLE,ADMIN_ROLE).
Input Validation
Assume all input is malicious. Use require() statements at the very beginning of your functions to validate parameters.
For instance:
Check for zero addresses (
address(0)).Check for zero amounts when transferring.
Verify array lengths match if passing multiple arrays.
etc.
Chiliz-Specific Implementation Details
While Chiliz Chain is EVM-compatible, certain "local rules" apply, specifically regarding token decimals and EVM versions.
CAP-20 Compliance (Fan Tokens)
If you are writing a contract that interacts with Fan Tokens (e.g., a Staking Pool for $PSG or $BAR), you must handle 0 decimals.
This means:
Do not assume
1 Token = 10^18 units. For Fan Tokens,1 Token = 1 unit.Avoid hardcoding
1e18in your math if your contract is meant to be generic. Use thetoken.decimals()function dynamically.
EVM Version & Compiler
Chiliz Chain is compatible with the "Shanghai" EVM version.
The recommended Solidity Version is 0.8.24.
Gas Optimization on Chiliz
Transactions on Chiliz Chain are significantly cheaper than Ethereum, but unoptimized code can still lead to congestion or failed transactions during high-traffic events (e.g., during a live match).
Here are three ways to save on gas:
Use Custom Errors: Instead of long string messages in
require, useerrordefinitions to save gas.Order your state variables to fit into 32-byte slots. Put
uint128,address, andboolnext to each other where possible.Prefer
externalfor functions that are never called internally by the contract itself.
Last updated
Was this helpful?