Skip to main content
The EVM contract suite is built with OpenZeppelin Contracts v5. Every contract uses the UUPS upgradeable proxy pattern — you own the proxy addresses and the upgrade authority. The SDK bundles minimal ABI fragments for runtime use, and full typed bindings are generated from the compiled artifacts for advanced integrations.

Contract descriptions

AnkaraChainBaseToken

The abstract ERC-20 base inherited by all six token templates. Extends OpenZeppelin’s ERC20Upgradeable, ERC20PausableUpgradeable, OwnableUpgradeable, and UUPSUpgradeable. Adds:
  • assetId — immutable bytes32 identifier set at initialization
  • countryCode — ISO 3166-1 alpha-2 string (e.g. "NG", "KE")
  • status — AssetStatus enum (DRAFT=0, ACTIVE=1, SUSPENDED=2, REDEEMED=3, EXPIRED=4)
  • identityVerifier — optional IIdentityVerifier that gates transfers and minting
  • metadataVersion — increments on every metadata update for off-chain indexing

TokenFactory

Deploys ERC-1967 proxies against registered template implementations. Key functions:
Emits TokenDeployed(uint8 template, address tokenAddress, address deployer, bytes32 assetId, string countryCode, uint256 timestamp).

Six template contracts

All six share the AnkaraChainBaseToken interface (mint, burn, pause, unpause, setStatus, setIdentityVerifier, getMetadata).

WhitelistVerifier

Implements the IIdentityVerifier interface. An admin-managed address allowlist. Attach it to any token at deploy time via identityVerifier in BaseDeployOptions, or update it later via setIdentityVerifier.

Upgrade pattern

The contracts use UUPS (Universal Upgradeable Proxy Standard, EIP-1822) with OpenZeppelin v5. Under UUPS, the upgrade logic lives in the implementation contract itself — not the proxy. This means the implementation can enforce authorization (only the owner can upgrade) and can be replaced without changing the proxy address your users interact with. To upgrade a deployed token:
  1. Deploy a new implementation contract (e.g. FarmlandTokenV2).
  2. Call upgradeToAndCall on the proxy address from the owner wallet.
The TokenFactory deploys proxies using OpenZeppelin’s ERC1967Proxy. The upgradeToAndCall function is available on any proxy address and can be called from the owner wallet.

Roles and access control

Role management is handled by OpenZeppelin’s OwnableUpgradeable. The owner of a token (the admin address set at deployment, defaulting to the deployer) controls:
  • Minting: mint(address to, uint256 amount) — owner only
  • Burning: burn(uint256 amount) — token holder (anyone burns their own tokens)
  • Status updates: setStatus(uint8 newStatus) — owner only
  • Metadata updates: updateValuation, updateTitleDocument, etc. — owner only
  • Pause / unpause: pause() / unpause() — owner only
  • Identity verifier: setIdentityVerifier(address verifier) — owner only
  • Upgrades: upgradeToAndCall — owner only
The owner can transfer ownership to a multisig or DAO contract at any time via OpenZeppelin’s standard transferOwnership.

Compiling and testing locally

Clone the repository and install dependencies, then use these commands from the repo root or from packages/contracts-evm:
Environment variables required for testnet deployment (copy from .env.example in packages/contracts-evm):

Deployment with the CLI

For production deployments, use the npx ankara CLI rather than running Hardhat scripts directly.
Run npx ankara init first to generate an ankara.config.json in your project. The CLI reads this file for the network, signer, and factory address so you don’t need to pass flags every time.

Source code

The EVM contracts are open source under the MIT License: github.com/ankarachain/ankara-core/tree/main/packages/contracts-evm The package is @ankarachain/contracts-evm (private — not published to npm). Build with Hardhat ^2.22.0 and OpenZeppelin Contracts ^5.0.0.