Zarchain user guide
Everything you need to use the Zarchain iOS app and web tools during the test programme. Zarchain is an educational proof-of-work network: the coins (ZAR, and USD) have no monetary value and the chain may be reset between test rounds.
1. Getting started
- Install the app. Accept the TestFlight invitation on your iPhone (iOS 17 or newer), install TestFlight from the App Store if prompted, then install Zarchain.
- Create a wallet. On first launch choose Create new wallet. A P-256 key pair is generated on your phone and stored in the iOS Keychain (device-only, protected by your passcode / Face ID).
- Back up your recovery key. Settings → Wallet → Show recovery key. Keep it private; anyone holding it controls the wallet. You can restore it on another phone with Import wallet.
- Check the node. The app is pre-configured with the test node URL. Settings → Network shows connection status; tap Test connection if anything looks wrong.
2. Your wallet & keys
Your address looks like zar4269889431e3131966fcaf6a457141943ed2c35b: the prefix zar followed by 40 hex characters derived from your public key (SHA-256 of the uncompressed key, first 20 bytes). Share your address freely — it is how people pay you.
| Term | Meaning |
|---|---|
| Balance | Confirmed coins on-chain, kept separately per currency (ZAR and USD). The wallet shows one currency at a time — switch with the currency menu on the balance card or in Settings. |
| Available | Balance minus what you have already sent that is still pending. This is what you can spend right now. |
| Pending | A transaction accepted by the node but not yet included in a block. It is confirmed at the next block (auto-mined roughly every 15s when there is something to mine, or immediately when anyone taps Mine). |
| Confirmed | Included in a block. The explorer shows the block number. |
3. Claiming test coins (Faucet)
- Wallet tab → Faucet.
- Choose an amount up to the current maximum (1000 ZAR) and tap Claim.
- The grant is a signed transfer from the network treasury, queued and credited when the next block is mined. Your balance updates automatically.
Each address can claim once per 60 seconds. The admin can change limits or disable the faucet; the app shows the current rules. The faucet pays out of the treasury's reserve (seeded with 1,000,000 ZAR · 50,000 USD), so if the reserve runs dry the faucet says so instead of inventing coins — ask the admin to top it up. The faucet only pays ZAR; get USD at the exchange desk (next section).
4. Sending & receiving
Receive
Wallet tab → Receive shows your QR code and address with Copy and Share buttons. The QR encodes zarchain:<address> and can optionally include an amount and currency.
Send
- Wallet tab → Send. Enter a recipient by pasting an address or tapping the camera icon to scan their QR code.
- Pick the currency (ZAR or USD — it defaults to the wallet's current one), enter a whole-number amount and an optional memo (visible on-chain, max 280 characters).
- Review the summary. Tap Confirm and authenticate with Face ID / Touch ID / passcode.
- The app signs the transaction locally and submits it. It appears as pending in Activity and confirms at the next block.
The app will refuse to send more than your available balance, to send to yourself, or to send to a malformed address; the node enforces the same rules independently.
5. Currencies & the exchange desk
Zarchain keeps two currencies on one chain. ZAR is the native coin: it is what mining creates and what the faucet pays. USD is a second ledger currency: it exists only because the treasury was seeded with it, and it moves by the same signed transfers. Every address has a balance in each; every transaction is denominated in exactly one.
Changing currency in the wallet
Tap the currency on the balance card (or Settings → Wallet → Currency) to switch the wallet between ZAR and USD. The balance, the Send screen and your QR code follow the selection; Activity always shows every currency. A QR code can carry a currency and amount (zarchain:<address>?amount=25¤cy=USD), so the sender only has to confirm.
Changing money at the desk
- Wallet tab → Exchange. Choose the direction (ZAR → USD or USD → ZAR) and an amount.
- The app shows the treasury's quote — currently 18 ZAR per USD — and exactly what you will receive. ZAR → USD amounts are rounded down to a multiple of the rate so nothing is lost; USD → ZAR is exact.
- Confirm with Face ID. The app signs one exchange transaction with the quote inside it; the node refuses it if the quote has changed since, so you never get a different price than the one you saw.
- Both legs settle in the same block: your ZAR goes to the treasury and its USD comes to you (or the reverse). Until then both show as pending.
The desk can only sell what the treasury holds (— right now) and the admin can close it or change the quote at any time; the app shows the current state.
6. Mining
Mine tab → Mine a block. The node performs proof-of-work on your behalf (finding a hash with 4 leading zeros) and credits the 50 ZAR block reward to your address, together with any pending transactions in that block. Mining also confirms everyone's pending transactions, which makes it a useful thing to do during a test session.
The node additionally auto-mines whenever the mempool is non-empty so nobody's payment waits forever; those rewards go to the treasury. Mining only ever creates ZAR — there is no USD coinbase.
7. Explorer
The in-app Explorer tab and the web explorer show the same live data: network stats, the newest blocks, the mempool and an activity feed. Tap a block for its transactions, tap a transaction for its signature and public key, or search any block height, block hash, transaction id or address.
8. Security model
- Keys never leave the device. Generation, storage (Keychain,
WhenUnlockedThisDeviceOnly) and signing happen on the phone. The node only ever sees public keys and signatures. - Every transfer is signed with ECDSA P-256 over SHA-256 of
sender|recipient|amount|payload|memo|timestamp|nonce— with|USDappended for a dollar transfer and|ZAR>USD@18(from, to, rate) for an exchange, so the currency and the quote are covered by the signature too. The node verifies the signature, checks the public key hashes to the sender address, and rejects anything tampered with. - Replay protection. A transaction id is the hash of its signed content. The node rejects any id already pending or confirmed, and any signed transaction older than 15 minutes.
- No double spend. The mempool tracks pending outflows per address, so you cannot spend the same ZAR twice even before confirmation. Blocks are re-validated against balances when received from peers.
- Transport. Production nodes serve HTTPS (Let's Encrypt via
--acme-domain). Local test nodes may use plain HTTP on the LAN; the app allows this only for private addresses. - Biometric confirmation. Sending and revealing the recovery key require Face ID / Touch ID or the device passcode.
- Rate limiting. Faucet, mining and transaction endpoints are rate-limited per client and the admin can pause the network.
What Zarchain is not: a Sybil-resistant public blockchain. Peers are trusted operators, and new coins (the treasury seed, an admin mint, mining rewards) are issued by the node itself. It is a safe, realistic sandbox — not real money.
9. Test scenarios for the beta
If you are helping test, try to complete these and note anything surprising:
- Onboarding: create a wallet, back up the key, delete the app, reinstall and import the key. Balance should be identical.
- Faucet: claim, wait for confirmation, claim again immediately (expect a cooldown message with a countdown).
- Send to a friend: scan their QR, send 25 ZAR with a memo. Both phones should show the pending → confirmed transition without pulling to refresh.
- Overspend: try to send more than available. The Send button should stay disabled with a clear reason.
- Two quick sends: send 60 then 60 from a 100 ZAR wallet before the first confirms. The second must be refused as insufficient.
- Mining: mine a block and check the reward lands and your pending transactions confirm.
- Exchange: change 180 ZAR into USD, then send 5 USD to a friend, then change it back. Check both legs of each exchange in the explorer.
- Currency switch: switch the wallet to USD; Send should refuse more USD than you hold even though you have plenty of ZAR.
- Offline: enable Airplane mode, open the app (cached data with an offline banner), then reconnect.
- Explorer: find your transaction in the web explorer by pasting its id or your address.
- Accessibility: use larger Dynamic Type and VoiceOver on the wallet screen.
10. Troubleshooting
| Symptom | What to do |
|---|---|
| "Cannot reach node" | Check Settings → Network URL. On a LAN node your phone must be on the same Wi‑Fi. Tap Test connection. |
| Faucet says cooldown | Wait for the countdown, or ask the admin to grant to your address. |
| "the faucet is dry" | The treasury has paid out its whole reserve. The admin seeds or mints more; nothing is wrong with your wallet. |
| "rate changed" when exchanging | The admin moved the quote between your review and your confirm. Reopen Exchange to get the new one. |
| "amount must be a multiple of the rate" | ZAR → USD only converts whole dollars. The app rounds down for you; other clients must send a multiple of the rate. |
| Transaction stuck pending | Tap Mine, or wait for auto-mine. If the network is paused the app shows a banner. |
| "insufficient balance" but I have coins | Your available balance excludes pending sends. Wait for confirmation. |
| "transaction timestamp too old" | Your phone clock is wrong. Enable Set Automatically in iOS Date & Time. |
| Balance went to zero | The admin reset the chain for a new test round. Claim from the faucet again. |
11. Admin guide
Open /admin and sign in with the admin token (printed at node start, or ZARCHAIN_ADMIN_TOKEN). From the console you can:
- Pause / resume the network with a broadcast message.
- Tune mining: difficulty (1–7), public mining on/off, auto-mine and its interval.
- Tune the faucet: enable, per-request maximum, per-address cooldown. It pays from the treasury.
- Run the exchange desk: open/close it and set the ZAR-per-USD quote. Pending exchanges keep the quote they were signed with.
- Seed the treasury (mints the configured
ZARCHAIN_SEED_ZAR/ZARCHAIN_SEED_USDin one block — a fresh chain and a reset do this on their own), grant from the treasury or mint new coins in either currency to any address, and mine blocks manually. - Inspect & drop pending transactions, manage peers and force a sync.
- Export a full chain snapshot, and reset to genesis for a fresh round (the treasury is re-seeded in block #1).
Running a node
go build -o zarchain ./cmd/node ./zarchain --port 8080 --data-dir /var/lib/zarchain --self-url https://zarchain.example.com # public HTTPS with automatic certificates: ./zarchain --acme-domain zarchain.example.com --acme-email you@example.com --data-dir /var/lib/zarchain # docker: docker compose up -d --build
Chain, settings, the node wallet and the admin token live in the data directory. Back it up to preserve state across upgrades.
12. API reference
Amounts are whole units. A transaction without a currency field is ZAR; USD transactions carry "currency":"USD". An exchange additionally carries toCurrency and rate, and its recipient is the treasury.
| Endpoint | Description |
|---|---|
GET /status | Height, difficulty, supply per currency, treasury address and what it can pay out, exchange desk state and quotes, faucet/mining rules, pause state, message. |
GET /blocks?limit=&before= | Block summaries, newest first. |
GET /block/{index|hash|latest} | Full block with transactions. |
GET /tx/{id} | Transaction with confirmation status. |
GET /address/{addr} | Balance, available, pending in/out (ZAR in the flat fields, every currency under balances), history. |
GET /supply | Supply per currency, treasury balances. |
GET /pending | Mempool. |
GET /search?q= | Resolve a height, hash, tx id or address. |
GET /events | Server-sent events: status, block, tx, settings. |
POST /transactions | Submit a signed transfer: {sender, recipient, amount, payload, memo, timestamp, nonce, signature, publicKey, currency?}. An exchange adds toCurrency and rate (the desk's current quote) with the treasury as recipient; 409 if the quote moved, 503 if the desk is closed. |
POST /faucet | {address, amount} — queue a ZAR grant from the treasury (503 when it is dry). |
POST /mine | {minerAddress} — mine one block, reward to miner. |
GET /peers, POST /peers | Peer list / announce. |
/admin/api/* | Admin endpoints (Bearer token): overview, settings (incl. exchange), mine, mint {address, amount, currency?, memo?, mineNow?}, grant (same body, paid from the treasury), seed {"confirm":"SEED"}, mempool, peers, balances ?currency=, activity, export, reset. |
Signing (for other clients)
message = sender + "|" + recipient + "|" + amount + "|" + payload + "|" + memo + "|" + timestamp + "|" + nonce
+ ("|" + currency if currency != "ZAR") // e.g. "|USD"
+ ("|" + from + ">" + to + "@" + rate if exchange) // e.g. "|ZAR>USD@18"
digest = SHA-256(message)
signature = base64( DER( ECDSA-P256-sign(digest) ) )
publicKey = base64( 0x04 || X || Y ) // X9.63 uncompressed
address = "zar" + hex( SHA-256(publicKey bytes)[0:20] )
id = hex( SHA-256(message) )
Test vector: private scalar AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA= → address zar4269889431e3131966fcaf6a457141943ed2c35b. Exchange vector: …|1800|||1700000000|42|ZAR>USD@18 converts to 100 USD; a ZAR → USD amount must be a multiple of the rate.
13. FAQ
Is ZAR (or USD) real money? No. Both are test tokens with no value; balances can be reset.
Where does the money come from? The treasury is seeded once (1,000,000 ZAR and 50,000 USD by default) and every faucet claim, grant and exchange moves value from that reserve. Only mining rewards, the seed and an explicit admin mint create new coins.
Is the exchange rate real? No — it is a whole-rand quote the admin sets (18 ZAR per USD by default), not a market rate.
Can I have more than one wallet? One wallet per app install. Use Import to switch, after backing up the current key.
What if I lose my recovery key? The coins are unrecoverable — exactly like a real blockchain. Ask the admin to mint new test coins to a new wallet.
Why did my send fail with "invalid signature"? The app signed with a different key than the address (e.g. after importing another wallet mid-send). Retry from the Send screen.
Where is the source? Ask the project owner; the node is Go, the app is SwiftUI.