Appearance
How to read a native token from EVM
Goal: prove that a token minted through the SVM (see Issue a native token) is the same token an EVM contract sees — by reading its ERC-20 totalSupply() over eth_call.
This is the N-VM shared state in action: no bridge, no wrapper. See N-VM shared state for the why.
1. Derive the synthetic ERC-20 address
Every native mint is auto-registered at a deterministic EVM address:
erc20_address = sha256("erc20-addr:" || mint_id)[12..32] // last 20 bytespython
import hashlib
mint_id = bytes.fromhex("<your 32-byte mint id hex>")
addr = hashlib.sha256(b"erc20-addr:" + mint_id).digest()[12:32]
print("0x" + addr.hex())2. eth_call the standard ERC-20 selectors
bash
RPC=https://testnet.acechain.io/rpc
ADDR=0x<erc20_address>
# totalSupply() selector 0x18160ddd
curl -s -X POST $RPC -H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","method":"eth_call","params":[{"to":"'$ADDR'","data":"0x18160ddd"},"latest"],"id":1}'
# decimals() selector 0x313ce567
curl -s -X POST $RPC -H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","method":"eth_call","params":[{"to":"'$ADDR'","data":"0x313ce567"},"latest"],"id":1}'balanceOf(address) works too — selector 0x70a08231 followed by the 32-byte left-padded EVM address.
3. Worked example (verified on testnet)
A native mint of 1,000,000,000 tokens at 9 decimals returns:
totalSupply() → 0x0000000000000000000000000000000000000000000000000de0b6b3a7640000
= 1000000000000000000 (1e18 base units = 1e9 × 10^9) ✓
decimals() → 0x0000000000000000000000000000000000000000000000000000000000000009
= 9 ✓The value read from EVM matches exactly what was minted from the SVM — one balance, two execution environments.
From a contract
Any Solidity contract can treat the address as a normal IERC20 and call transfer / transferFrom / balanceOf — see NativeTokenVault.sol.
