Enjin
Enjin Platform V3: Wallet Daemon Upgrade Guide
A practical Enjin Platform V3 guide covering Ubuntu wallet-daemon installation, V2 wallet migration, production authentication, security and verified migration quirks.
Guide Status
Work in progress, last verified 19 August 2026. The Ubuntu daemon installation and V2 wallet migration below have been completed successfully. Production Platform authentication is now working after adding the daemon VPS public IP address to the Platform account's IP allowlist. Verified GraphQL queries and mutations are documented separately in the Enjin Platform V3 Graph Book.
This is a field guide built from an actual Platform V3 upgrade. It records the commands that worked, the assumptions that failed and the differences between the public API and the daemon API. Never place a real seed phrase, KEY_PASS or Platform token in documentation, source control, screenshots or support messages.
Platform V3 Architecture and Endpoints
The Wallet Daemon is an outbound-only signer. An application submits a transaction through Enjin Platform, the daemon polls for pending work, signs with its local wallet and returns the signature for broadcast. The daemon does not need an inbound application port.
| Purpose | Production URL | Used by |
|---|---|---|
| Platform dashboard | https://platform.enjin.io | Developers and account administration |
| Public GraphQL API | https://platform.enjin.io/graphql | Application queries and mutations |
| Wallet Daemon GraphQL API | https://platform.enjin.io/graphql/daemon | Wallet registration, polling and signature submission |
The two GraphQL endpoints are not interchangeable. The public endpoint does not expose SetDaemonWalletAccount; the V3 daemon therefore correctly defaults to /graphql/daemon.
Install the V3 Wallet Daemon on Ubuntu 24.04
This installation was verified on Ubuntu 24.04.4 LTS, x86-64. Check the server before downloading a binary:
uname -m
lsb_release -ds
Install the download tools and inspect the latest official Enjin release rather than copying an old version from a tutorial:
apt update
apt install -y curl jq unzip
curl -fsSL https://api.github.com/repos/enjin/wallet-daemon/releases/latest \
| jq -r '.tag_name, (.assets[].browser_download_url)'
For the verified x86-64 installation, the latest release asset was wallet-daemon_v3.0.9_x86_64-unknown-linux-gnu.zip:
useradd --system \
--home-dir /opt/enjin-wallet-daemon \
--shell /usr/sbin/nologin \
enjin-daemon
install -d \
-o enjin-daemon \
-g enjin-daemon \
-m 700 \
/opt/enjin-wallet-daemon
cd /opt/enjin-wallet-daemon
curl -fLO \
https://github.com/enjin/wallet-daemon/releases/download/v3.0.9/wallet-daemon_v3.0.9_x86_64-unknown-linux-gnu.zip
unzip wallet-daemon_v3.0.9_x86_64-unknown-linux-gnu.zip
chown -R enjin-daemon:enjin-daemon /opt/enjin-wallet-daemon
chmod 700 /opt/enjin-wallet-daemon/wallet-daemon
Daemon Configuration
Create /opt/enjin-wallet-daemon/.env with permissions 600. Use the production daemon token created in Platform Account Settings. Store the real values privately:
KEY_PASS=YOUR_PRIVATE_WALLET_PASSWORD
PLATFORM_KEY=YOUR_PRIVATE_PLATFORM_TOKEN
SEED_PATH=/opt/enjin-wallet-daemon
chown enjin-daemon:enjin-daemon /opt/enjin-wallet-daemon/.env
chmod 600 /opt/enjin-wallet-daemon/.env
Do not prefix PLATFORM_KEY with Bearer; the daemon adds that prefix itself.
Migrate an Existing Platform V2 Daemon Wallet
Do not use the normal V3
wallet-daemon importcommand for a legacy V2 daemon wallet. Importing only its 12 words produced a valid but different public key in our test.
The reason is the legacy derivation. V2 loaded the mnemonic as a Substrate secret URI in the form mnemonic///KEY_PASS. V3's ordinary import encrypts and derives the supplied mnemonic without that legacy password junction. To preserve the original signing account, use V3's automatic legacy-file migration.
1. Recover the Original V2 Values
- The original 12-word mnemonic.
- The exact original
KEY_PASS. - The original public key, without its leading
0x.
On an old V2 server, the password may still be present in its .env file:
grep '^KEY_PASS=' /path/to/.env
Run that only in a trusted terminal. Do not paste the result into a chat or ticket.
2. Recreate the Legacy Seed File
Reconstruct the filename used by V2.1.1: 73723235 followed immediately by the 64-character lowercase public-key hex, without 0x:
73723235<PUBLIC_KEY_HEX_WITHOUT_0X>
V2.1.1 generated this name and treated it as a checksum: it derived the key from the mnemonic plus KEY_PASS, then required the filename to equal 73723235 plus that derived public key. V3.0.9's migration discovery is looser and currently checks only that the name starts with 73723235 and contains 72 characters in total. Preserve or reconstruct the authentic V2 filename rather than relying on that looser V3 check.
Create it with restrictive permissions:
cd /opt/enjin-wallet-daemon
install \
-o enjin-daemon \
-g enjin-daemon \
-m 600 \
/dev/null \
73723235<PUBLIC_KEY_HEX_WITHOUT_0X>
nano 73723235<PUBLIC_KEY_HEX_WITHOUT_0X>
The file must contain one line. The double quotation marks at both ends were required in the verified migration:
"word1 word2 word3 word4 word5 word6 word7 word8 word9 word10 word11 word12"
Check only the word count, without printing the mnemonic:
awk '{gsub(/"/,""); print "Word count:", NF}' \
73723235<PUBLIC_KEY_HEX_WITHOUT_0X>
3. Let V3 Perform the Migration
Make sure SEED_PATH points to the containing directory, not directly to a seed filename. Stop any test daemon and remove only the unwanted test wallet.seed before starting:
pkill -x wallet-daemon 2>/dev/null || true
rm -f -- /opt/enjin-wallet-daemon/wallet.seed
cd /opt/enjin-wallet-daemon
runuser -u enjin-daemon -- ./wallet-daemon
V3 detects the 73723235… file, applies the legacy password derivation, writes an encrypted wallet.seed, confirms that the encrypted replacement derives the same key as the legacy file, and removes the copied plaintext legacy file. V3.0.9 does not independently compare that key with the filename suffix. A successful run logs:
INFO wallet_daemon::wallet_loader: Successfully migrated seed to new format
Verify the Migrated Wallet
Compare the V3 public key and Matrixchain addresses with the old V2 daemon output. Different SS58 prefixes represent different Enjin networks, but all four addresses printed by V3 should decode to the same public key.
- Enjin Relaychain address
- Enjin Matrixchain address
- Canary Relaychain address
- Canary Matrixchain address
- 32-byte public key in hexadecimal
If the public key differs, stop. Do not fund the new address or submit transactions. Recheck the original password, exact mnemonic, quotation marks and the public-key-based legacy filename.
After migration, secure the new file:
chown enjin-daemon:enjin-daemon /opt/enjin-wallet-daemon/wallet.seed
chmod 600 /opt/enjin-wallet-daemon/wallet.seed
Platform IP Allowlisting and Authentication
IP allowlisting is optional in the Enjin Platform dashboard, but is highly recommended. When enabled, add the daemon VPS public IP address before starting the daemon.
To verify the allowlist behavior, we deliberately started the daemon from a VPS whose public IP had not yet been approved, using a valid newly rotated API token. We then added the VPS IP to the allowlist and repeated the test successfully.
- Confirm the daemon VPS has a stable public egress IP address.
- For stronger token security, enable IP allowlisting and add that address to the production Platform account.
- Keep the raw production daemon token in
PLATFORM_KEY, without aBearerprefix. - Start the daemon again from the approved VPS.
When IP allowlisting was enabled, a request from an unapproved IP produced the same GraphQL response normally associated with an invalid or missing token:
category: authorization
You must login to perform this action.
This error does not identify the allowlist as its cause. Before rotating a valid-looking token repeatedly, check all of the following:
- If IP allowlisting is enabled, the daemon VPS public IP is present in the Platform allowlist.
PLATFORM_KEYappears exactly once in.env.- The raw token has no
Bearerprefix, whitespace or carriage return. - No exported shell variable is overriding
.env. - The daemon is using
https://platform.enjin.io/graphql/daemon, not the public application endpoint.
After the correct VPS IP was approved, the same daemon wallet and production configuration authenticated successfully.
Security Checklist
- Permit inbound SSH only from trusted addresses where practical. The daemon itself requires no inbound port.
- Consider enabling the optional Platform IP allowlist; if used, add only the daemon server's stable public egress IP.
- Use a dedicated unprivileged service account.
- Keep the daemon directory at mode
700and secret files at600. - Back up
wallet.seedandKEY_PASSseparately. - Do not rotate
KEY_PASSfor an existing encryptedwallet.seed. - Never place the mnemonic directly in a shell command or shell history.
- Delete or securely isolate any plaintext legacy seed after a verified migration.
- Run only one daemon per Platform account.
- Start on Canary before submitting production transactions.
Known V3 Quirks Found During Setup
- Release/banner mismatch: the official v3.0.9 Linux asset currently prints
Enjin Wallet Daemon v3.0.8. The v3.0.9 tag still embeds package version 3.0.8. - Documentation version lag: Enjin's daemon documentation examples referenced v3.0.6 while the latest downloadable binary was v3.0.9.
- No
--versionflag: the binary rejectswallet-daemon --version; confirm the release from the downloaded asset and official release metadata. - V2 filename convention: V2.1.1 generated and checksum-validated
73723235<public-key-hex>. V3.0.9 migration discovery checks only that prefix and a total filename length of 72 characters, so preserve or reconstruct the authentic V2 name. The mnemonic required double quotes at both ends in the verified migration. - Normal import changes a V2 address:
wallet-daemon importis suitable for a normal V3 mnemonic import, but did not preserve the password-derived V2 signing key. - File permissions: check the generated
wallet.seedexplicitly and apply mode600. - Optional IP restriction: Platform IP allowlisting is optional but highly recommended. When it is enabled, a valid token from an unapproved VPS can return
You must login to perform this action.