Build on Valdium Testnet · v1.10 · all tests passing
Estimated read time: 10 minutes

Build a Token Contract

VRC-20: The Valdium token standard

VRC-20 is Valdium's fungible token standard — conceptually equivalent to ERC-20, but written in plain JavaScript. No pragma, no imports, no compiler. Just functions in a sandbox.

Full VRC-20 implementation

// vrc20.js — Valdium fungible token const BALANCE_PREFIX = 'b:'; const ALLOWANCE_PREFIX = 'a:'; ({ init(args) { assert(args.totalSupply, 'totalSupply required'); storage.set('name', args.name || 'Valdium Token'); storage.set('symbol', args.symbol || 'VRC'); storage.set('decimals', '18'); storage.set('supply', String(args.totalSupply)); storage.set(BALANCE_PREFIX + msg.sender, String(args.totalSupply)); emit('Transfer', { from: null, to: msg.sender, value: String(args.totalSupply) }); }, name() { return storage.get('name'); }, symbol() { return storage.get('symbol'); }, decimals() { return Number(storage.get('decimals')); }, totalSupply() { return storage.get('supply'); }, balanceOf(address) { return storage.get(BALANCE_PREFIX + address) || '0'; }, transfer(to, amount) { const from = msg.sender; const amt = BigInt(amount); assert(amt > 0n, 'amount must be positive'); const fromBal = BigInt(storage.get(BALANCE_PREFIX + from) || '0'); assert(fromBal >= amt, 'insufficient balance'); const toBal = BigInt(storage.get(BALANCE_PREFIX + to) || '0'); storage.set(BALANCE_PREFIX + from, String(fromBal - amt)); storage.set(BALANCE_PREFIX + to, String(toBal + amt)); emit('Transfer', { from, to, value: String(amt) }); return true; }, approve(spender, amount) { storage.set(ALLOWANCE_PREFIX + msg.sender + ':' + spender, String(amount)); emit('Approval', { owner: msg.sender, spender, value: String(amount) }); return true; }, allowance(owner, spender) { return storage.get(ALLOWANCE_PREFIX + owner + ':' + spender) || '0'; }, transferFrom(from, to, amount) { const spender = msg.sender; const amt = BigInt(amount); const allowed = BigInt(storage.get(ALLOWANCE_PREFIX + from + ':' + spender) || '0'); assert(allowed >= amt, 'allowance exceeded'); const fromBal = BigInt(storage.get(BALANCE_PREFIX + from) || '0'); assert(fromBal >= amt, 'insufficient balance'); const toBal = BigInt(storage.get(BALANCE_PREFIX + to) || '0'); storage.set(ALLOWANCE_PREFIX + from + ':' + spender, String(allowed - amt)); storage.set(BALANCE_PREFIX + from, String(fromBal - amt)); storage.set(BALANCE_PREFIX + to, String(toBal + amt)); emit('Transfer', { from, to, value: String(amt) }); return true; }, });

Deploy

valdium deploy vrc20.js --from alice --args '{"name":"My Token","symbol":"MTK","totalSupply":"1000000000000000000000000"}'

The totalSupply is in wei (1e18 = 1 token). 1,000,000 MTK = 1000000000000000000000000.

Interact

valdium call 0xContract... balanceOf 0xAlice... valdium call 0xContract... transfer 0xBob... 1000000000000000000 --from alice