What are we trying to do?
Building a React Native Midnight wallet that queries shielded balance data using the indexer GraphQL API. Need to generate valid viewing keys for the connect() mutation to establish authenticated sessions
and subscribe to shieldedTransactions.
What’s not working or unclear?
All viewing key candidates fail with “decode viewing key” GraphQL errors. After examining the indexer source code (viewing_key.rs and bech32-codec.ts), viewing keys use ChaCha20Poly1305 encryption and
wallet-ID association, suggesting they may be server-issued rather than client-derived. Unclear if viewing keys can be generated from wallet seeds or require a different acquisition flow.
What have we tried so far?
- Implemented official Bech32m format from bech32-codec.ts: mn_shield-esk_test1 HRP with network ID prefix (testnet=2)
- HD wallet key derivation: Generated proper X25519 encryption keys from BIP-32 paths using @midnight-ntwrk/wallet-sdk-hd
- Multiple role keys: Tested Zswap, NightExternal, and Dust role encryption secret keys
- Various payload formats: Tried raw 32-byte keys, structured with version headers, and network-ID-prefixed payloads
- Verified address generation works: Successfully created working addresses accepted by testnet faucet (received 1000 tDUST)
Any relevant code or error messages?
// HD wallet X25519 key derivation
const hdWalletResult = HDWallet.fromSeed(seedBytes);
const accountKey = hdWalletResult.hdWallet.selectAccount(0);
const roleKey = accountKey.selectRole(Roles.Zswap);
const keyResult = roleKey.deriveKeyAt(0);
// Create X25519 encryption keys
const integratedKeys = await createIntegratedKeySet(keyResult.key, ‘Zswap’);
const encryptionSecretKey = integratedKeys.x25519.privateKey; // Uint8Array(32)
// Format with official structure
const payloadWithNetworkId = new Uint8Array(34);
payloadWithNetworkId[0] = 2; // testnet network ID
payloadWithNetworkId[1] = 0x00;
payloadWithNetworkId.set(encryptionSecretKey, 2);
// Encode with official HRP
const hrp = ‘mn_shield-esk_test1’;
const viewingKey = encodeBech32m(hrp, payloadWithNetworkId);
// Result: mn_shield-esk_test11qgqrvyhyw6zrrdc7xcyp…
GraphQL Error:
{
“errors”: [{
“message”: “decode viewing key”,
“locations”: [{“line”: 3, “column”: 13}],
“path”: [“connect”]
}]
}
Working in React Native environment (WASM libraries not supported) trying to implement balance fetching functionality similar to Lace wallet, without access to full @midnight-ntwrk/zswap WASM modules.
Tags
sdk error-help tooling best-practices learning
Core question: Are viewing keys derived from wallet seeds using cryptographic functions, or are they issued by the indexer service through an authentication flow? The ChaCha20Poly1305 encryption in the
source suggests they might be authorization tokens rather than derivable keys.