Encrypt wallet in memory
ChainGate's in-memory encryption safeguards private keys and recovery phrases while your wallet application is active. This security layer requires user authentication whenever sensitive data is accessed, preventing unauthorized use if your application's memory is compromised.
In-memory encryption is mainly relevant for browser or apps. If you're working in a secure backend environment, you might not need it — see When is in-memory encryption needed? below.
Think of encrypting your wallet like buying a new safe: you set a combination (password), and the safe always requires it. Even if someone inspects your device's memory, they can't access your private key or recovery phrase without that password.
Encrypt your wallet
To enable in-memory encryption, call wallet.encrypt() after creating or importing a wallet. You provide a password and an askForPassword callback that the library will invoke whenever it needs to access secret material (e.g., when signing a transaction).
import { importWallet } from 'chaingate'
const wallet = importWallet({ phrase: 'your recovery phrase here...' })
// Encrypt the wallet
await wallet.encrypt('Tr0ub4dor&3', async () => {
return prompt('Enter your wallet password:')
})
The askForPassword callback should return:
- The password string if the user provides it.
nullto cancel the operation (throwsDecryptionCancelledError).
Never store or log user passwords in plain text. This can expose them to attackers and completely undermine your wallet's security.
Example: Signing and broadcasting a Bitcoin transaction
import { importWallet, ChainGate } from 'chaingate'
const wallet = importWallet({ phrase: 'your phrase here...' })
// Encrypt the wallet
await wallet.encrypt('my-password', async () => {
return prompt('Enter password:')
})
const cg = new ChainGate({ apiKey: 'your-api-key' })
const bitcoin = cg.connect(cg.networks.bitcoin, wallet)
// Create a transfer
const amount = cg.networks.bitcoin.amount('0.001')
const tx = await bitcoin.transfer(amount, 'bc1q...')
// Signing requires the private key — askForPassword() is called
tx.setFee('normal')
const broadcasted = await tx.signAndBroadcast()
console.log('TX ID:', broadcasted.transactionId)
During signAndBroadcast(), your askForPassword function will be invoked if the private key is not currently decrypted. Once the correct password is entered, the transaction is signed and sent to the network.
Check encryption status
console.log(wallet.encrypted) // true or false
Automatic caching for non-sensitive data
ChainGate reduces repeated prompts by caching non-sensitive data (e.g., public keys, addresses, derivation paths) once decrypted:
- You typically only enter your password once per session or until the system deems it necessary to re-prompt.
- Public information is stored in a readily accessible manner, while private data (like private keys) always requires decryption.
This design strikes a balance between user experience and security:
- You won't be prompted for a password every time you ask for an address or public key.
- You will be prompted whenever the private key or recovery phrase is directly accessed (e.g., signing a transaction).
When is in-memory encryption needed?
Use it in browser-based applications or apps
In browser environments or apps, memory is more exposed:
- Malicious browser extensions
- Compromised third-party scripts
- Memory inspection tools
- Shared access on a compromised machine
In these cases, sensitive data stored in memory (like private keys) could be at risk. In-memory encryption protects against this by requiring a password before anything critical is decrypted.
Not required in most backend environments
If you're using ChainGate in a backend environment (e.g., a Node.js server or cloud function with restricted access):
- Only your own trusted code runs
- The OS and runtime prevent outside access to memory
- Users never interact directly with the server's memory
In such environments, you typically don't need in-memory encryption, and omitting it can simplify your implementation. However, if untrusted plugins, sandboxed logic, or shared runtimes are involved, adding this layer may still offer useful protection.
Key takeaways
wallet.encrypt(password, askForPassword): Encrypts the wallet's secret material in memory.- Secure defaults: ChainGate uses AES-256-GCM and PBKDF2 under the hood, providing robust encryption for sensitive data in memory.
- Convenient caching: Public data (e.g., addresses) is cached to reduce how often the password is needed, without compromising security for private data.
- Safeguard your password: Always choose a strong password and handle user input securely — never log or expose the entered password.
- Error handling:
AlreadyEncryptedErroris thrown if you try to encrypt a wallet that is already encrypted.DecryptionCancelledErroris thrown ifaskForPasswordreturnsnull.