Token Standards
ZENIQ Smart Chain inherits the token model of its smartBCH ancestor. Two things matter for developers:
- ZEN-20 — the fungible-token interface (the ZENIQ Smart Chain equivalent of ERC-20 / SEP-20). Any standard ERC-20 contract is a valid ZEN-20 token.
- The native ZENIQ token exposed through a ZEN-20 interface — a built-in pseudo-contract that lets you treat the native coin exactly like a token.
Compile token contracts with Solidity 0.8.19 (London EVM). See JSON-RPC → Gas & fees.
ZEN-20 fungible tokens
ZEN-20 is derived from ERC-20 (it is the same interface smartBCH calls SEP-20). A conformant token implements:
// Metadata
function name() external view returns (string);
function symbol() external view returns (string);
function decimals() external view returns (uint8);
// Core
function totalSupply() external view returns (uint256);
function balanceOf(address _owner) external view returns (uint256);
function transfer(address _to, uint256 _value) external returns (bool);
function transferFrom(address _from, address _to, uint256 _value) external returns (bool);
function approve(address _spender, uint256 _value) external returns (bool);
function allowance(address _owner, address _spender) external view returns (uint256);
// Convenience (recommended, guards against the approve race)
function increaseAllowance(address _spender, uint256 _delta) external returns (bool);
function decreaseAllowance(address _spender, uint256 _delta) external returns (bool);
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
Notes that differ from bare ERC-20:
symbol()anddecimals()are required, not optional.increaseAllowance/decreaseAllowanceare recommended to avoid the well-knownapprovefront-running race; callers should still set an allowance to0before changing it to a new non-zero value.- Callers must check the returned
bool— do not assumetransfer/transferFromnever returnfalse.
The easiest way to ship a compliant token is to inherit OpenZeppelin's
ERC20 (and ERC20Burnable / Ownable as needed) — it satisfies the ZEN-20
interface unchanged. Use the
OpenZeppelin Contracts Wizard
to generate one.
The native ZENIQ token as ZEN-20
On Ethereum, ETH is not an ERC-20 token, so DApps must special-case the native coin (or wrap it, à la WETH). ZENIQ Smart Chain solves this with a built-in pseudo-contract that presents the native ZENIQ coin through the full ZEN-20 interface — the same idea smartBCH ships as SEP-206.
It is pseudo because it is implemented natively in zeniqsmartd, not as EVM
bytecode, which lets it do something no ordinary contract can: move the native
coin. You call it exactly as you would any ZEN-20 token.
0x000000000000000000000000005a454e49510002
(The bytes 5a 45 4e 49 51 spell ZENIQ in ASCII.) This is the ZENIQ address —
it is not smartBCH's 0x…2711.
Behavioural specifics:
balanceOf(addr)returns the same value aseth_getBalance(addr).transfermoves the native coin directly.- The methods must be invoked via
call/staticcall;delegatecallandcallcodeare not allowed. - Allowances are stored natively; their slot is not readable with
eth_getStorageAt. - Calls cost a fixed amount of gas per method (e.g.
transfer32000,balanceOf20000,approve25000).
Example — read your native balance through the token interface with ethers.js:
const { ethers } = require("ethers");
const provider = new ethers.providers.JsonRpcProvider("https://api.zeniq.network");
const ZEN20_ABI = [
"function name() view returns (string)",
"function symbol() view returns (string)",
"function decimals() view returns (uint8)",
"function balanceOf(address) view returns (uint256)",
"function transfer(address,uint256) returns (bool)",
];
const native = new ethers.Contract(
"0x000000000000000000000000005a454e49510002",
ZEN20_ABI,
provider
);
const bal = await native.balanceOf("0x<your-address>");
console.log(ethers.utils.formatEther(bal), "ZENIQ");
Because this pseudo-contract satisfies the ZEN-20 interface, a DApp can handle the native coin and ordinary ZEN-20 tokens through a single code path.