Skip to content

Testnet Setup

Complete procedure for wiping and setting up the testnet from scratch. This covers node deployment, genesis, and treasury distribution into multisig wallets.

Prerequisites

  • SSH access to all 5 nodes (3 bootstrap as root, 2 providers as ubuntu)
  • Go 1.24+ for building binaries and running setup scripts
  • The genesis treasury seed (stored offline)

Node inventory

Role Host SSH API
Bootstrap ldn.test.network root@ldn.test.network https://ldn.core.test.network
Bootstrap ffm.test.network root@ffm.test.network https://ffm.core.test.network
Bootstrap nyc.test.network root@nyc.test.network https://nyc.core.test.network
Provider 189.1.171.51 ubuntu@189.1.171.51
Provider 67.213.117.123 ubuntu@67.213.117.123

Step 1: Build

cd ~/workspace/xe-poc-2/core
GOOS=linux GOARCH=amd64 go build \
  -ldflags "-X main.version=$(git describe --tags --always)" \
  -o /tmp/xe ./cmd/xe/

Step 2: Stop all nodes

# Bootstrap nodes (pm2)
for host in ldn.test.network ffm.test.network nyc.test.network; do
  ssh root@$host "pm2 stop xe-node"
done

# Provider nodes (systemd)
ssh ubuntu@189.1.171.51 "sudo systemctl stop xe-node"
ssh ubuntu@67.213.117.123 "sudo systemctl stop xe-node"

Step 3: Deploy binary and wipe data

# Bootstrap nodes
for host in ldn.test.network ffm.test.network nyc.test.network; do
  scp /tmp/xe root@$host:/usr/local/bin/xe-node
  ssh root@$host "rm -rf /var/lib/xe-node/ledger"
done

# Provider nodes
for host in 189.1.171.51 67.213.117.123; do
  scp /tmp/xe ubuntu@$host:/tmp/xe-node
  ssh ubuntu@$host "sudo cp /tmp/xe-node /usr/local/bin/xe-node && \
    sudo chmod +x /usr/local/bin/xe-node && \
    sudo rm -rf /var/lib/xe-node/ledger"
done

Data wipe deletes libp2p keys

If you also delete /var/lib/xe-node/host.key, new peer IDs will be generated on startup and you must update all dial configurations. Only delete the ledger/ subdirectory to preserve peer IDs.

Step 4: Start nodes

# Bootstrap nodes
for host in ldn.test.network ffm.test.network nyc.test.network; do
  ssh root@$host "pm2 start xe-node"
done

# Provider nodes
ssh ubuntu@189.1.171.51 "sudo systemctl start xe-node"
ssh ubuntu@67.213.117.123 "sudo systemctl start xe-node"

Step 5: Verify genesis

Each node auto-applies the embedded genesis block on first boot, minting 100,000,000 XE to the treasury account.

for api in ldn.core.test.network ffm.core.test.network nyc.core.test.network; do
  echo -n "$api: "
  curl -s "https://$api/frontiers" | python3 -c \
    "import sys,json; d=json.load(sys.stdin); print(len(d), 'accounts')"
done

All nodes should show 1 account (the genesis treasury).

Step 6: Treasury distribution

The genesis block mints to a single-key account. The setup script distributes the supply into four 2-of-3 multisig wallets:

Wallet Amount Purpose
Treasury-A 50,000,000 XE Primary reserve
Treasury-B 30,000,000 XE Operations
Treasury-C 10,000,000 XE Grants / ecosystem
Treasury-D 10,000,000 XE Emergency reserve
cd ~/workspace/xe-poc-2/core
go run ./scripts/setup-treasury/ <genesis-seed-hex>

The script:

  1. Opens 4 multisig accounts (multisig_open, 2-of-3 threshold)
  2. Sends XE from genesis to each wallet
  3. Receives on each multisig wallet (1-of-N)
  4. Verifies all balances
  5. Prints key material for offline storage

Keys are deterministically derived from the genesis seed, so rerunning after a testnet wipe produces the same addresses.

Save key material

The script prints private seeds for all 12 multisig keys. Save these offline immediately. They are not stored anywhere else.

Optional: custom API endpoint

go run ./scripts/setup-treasury/ <genesis-seed-hex> https://ffm.core.test.network

Step 7: Verify

Check the explorer to confirm:

  • Genesis account has 0 XE remaining
  • Four multisig accounts exist with correct balances
  • Each multisig account shows "multisig 2 of 3" badge
  • Blocks propagated to all nodes (check frontiers)
# Quick verification
for api in ldn.core.test.network ffm.core.test.network nyc.core.test.network; do
  echo "$api:"
  curl -s "https://$api/frontiers" | python3 -c \
    "import sys,json; d=json.load(sys.stdin); print(f'  {len(d)} accounts')"
done

Should show 5 accounts on each node (1 genesis + 4 treasury wallets).

Token model summary

After setup, the testnet has:

Token Supply Source
XE 100,000,000 (fixed) Genesis block, distributed to 4 multisig wallets
XUSD Unlimited (faucet) 100 XUSD per claim, once per account per 24 hours
  • XE cannot be claimed. New XE enters circulation only via lease settlement (provider emission).
  • XUSD is the testnet faucet token. Any account can claim 100 XUSD per day via xe fund.
  • Voting weight is based on XUSD balance, not XE.

Peer ID recovery

If peer IDs change (full data wipe including host.key), get new multiaddrs from logs:

for host in ldn.test.network ffm.test.network nyc.test.network; do
  echo -n "$host: "
  ssh root@$host "pm2 logs xe-node --lines 200 --nostream --no-color 2>/dev/null" \
    | grep "Listening on: /ip4/" | grep -v "127.0.0.1\|172.17" | head -1 \
    | grep -oP '/ip4/.+'
done

Then update PM2 configs (bootstrap) and systemd unit files (providers) with the new -dial addresses.