Non-custodial Architecture
This page explains how PayWarden keeps your funds safe — and why our architecture means we legally cannot take your money even if we wanted to.
The core principle
PayWarden never holds private keys. We run software infrastructure. You hold your funds.
This distinction matters legally and technically:
- Custodial services (hosted payment gateways, exchanges) hold your private keys → they are payment institutions and require licensing
- PayWarden only holds an encrypted seed on your server → it's software infrastructure, like Nginx or PostgreSQL
How addresses are derived
Your 24-word mnemonic
│
▼ BIP39 → 512-bit seed
│
▼ BIP32 master key
│
▼ BIP44 path: m/44'/195'/0'/0/{index}
│ │
│ └── TRON coin type = 195
▼
Unique TRON address for order #{index}For receiving payments, PayWarden uses only your extended public key (xpub). The xpub can derive all child public keys (and thus addresses) without ever exposing a private key.
Private keys are derived only during fund sweeping — when confirmed funds are moved from a payment address to your hot wallet. After the sweep transaction is signed and broadcast, the private key buffer is immediately overwritten:
// From fund-sweeper.ts
const privateKey = derivePrivateKey(mnemonic, index)
await broadcastTransaction(privateKey, ...)
privateKey.fill(0) // wipe from memory immediatelyVault encryption
Your mnemonic is stored encrypted on disk as vault.enc:
vault.enc = AES-256-GCM(
plaintext: mnemonic,
key: VAULT_KEY (from environment variable),
iv: random 12 bytes (stored with ciphertext),
tag: 16-byte authentication tag (detects tampering)
)The VAULT_KEY never touches the database or logs. It lives only in your environment variables. If an attacker steals vault.enc but not VAULT_KEY, they cannot decrypt your mnemonic.
What the server stores
| Data | Storage | Encrypted? |
|---|---|---|
| Mnemonic | vault.enc file | ✅ AES-256-GCM |
| xpub | PostgreSQL | ❌ (public key, safe to store) |
| Derived addresses | PostgreSQL | ❌ (public) |
| Private keys | RAM only, during sweep | ✅ wiped after use |
| API keys | PostgreSQL | ✅ HMAC hashed |
| Order data | PostgreSQL | ❌ |
Recovery scenario
If your server is completely destroyed:
- Restore
VAULT_KEYfrom your secure backup - Start a fresh PayWarden instance
- Re-initialize with your 24-word mnemonic
- Re-run
db:migrate - PayWarden re-derives all the same addresses deterministically
All historical orders can be reconstructed from blockchain data using your xpub.
Cloud version
The non-custodial guarantees described above apply to the self-hosted version, where your vault key and mnemonic never leave your server.
The cloud version (currently in beta) uses server-side envelope encryption: your mnemonic is encrypted with an AWS KMS-managed key. This protects data at rest, but the server holds the decryption capability — it does not yet implement a merchant-held second factor. See Cloud Architecture for details.
Our goal is to reach a true non-custodial model for the cloud version (merchant-held second factor, where neither party alone can decrypt the vault). This is on the roadmap but not yet implemented.