Generating Wallets
Generate a unique deposit wallet per customer or per transaction:
async function createDepositWallet(userId, chain = "polygon") {
const wallet = await fetch(
"https://secureapi.gridlog.io/api/v1/crypto/wallets/generate",
{
method: "POST",
headers: {
"X-API-Key": process.env.MYAZA_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({ chain }),
},
).then((r) => r.json());
// Encrypt and store — never log private keys
await db.wallets.create({
userId,
chain,
address: wallet.address,
encryptedPrivateKey: encrypt(wallet.privateKey),
encryptedMnemonic: encrypt(wallet.mnemonic),
createdAt: new Date(),
});
// Only return the public address
return wallet.address;
}
Encrypting Private Keys
Never store private keys in plaintext. Use AES-256 with a key stored in a secrets manager (AWS Secrets Manager, HashiCorp Vault, etc.):
const crypto = require("crypto");
const ENCRYPTION_KEY = Buffer.from(process.env.WALLET_ENCRYPTION_KEY, "hex"); // 32 bytes
const IV_LENGTH = 16;
function encrypt(text) {
const iv = crypto.randomBytes(IV_LENGTH);
const cipher = crypto.createCipheriv("aes-256-cbc", ENCRYPTION_KEY, iv);
const encrypted = Buffer.concat([cipher.update(text), cipher.final()]);
return iv.toString("hex") + ":" + encrypted.toString("hex");
}
function decrypt(text) {
const [ivHex, encryptedHex] = text.split(":");
const iv = Buffer.from(ivHex, "hex");
const encrypted = Buffer.from(encryptedHex, "hex");
const decipher = crypto.createDecipheriv("aes-256-cbc", ENCRYPTION_KEY, iv);
return Buffer.concat([
decipher.update(encrypted),
decipher.final(),
]).toString();
}
Checking Balances
async function getWalletBalance(address, chain) {
return fetch(
`https://secureapi.gridlog.io/api/v1/crypto/${chain}/address/${address}/balance`,
{ headers: { "X-API-Key": process.env.MYAZA_API_KEY } },
).then((r) => r.json());
}
Sweeping Funds
After a customer sends to a deposit address, sweep the funds to a central treasury wallet:
async function sweepToTreasury(depositAddress, chain, token) {
const { privateKey: encryptedKey } = await db.wallets.findOne({
address: depositAddress,
});
const privateKey = decrypt(encryptedKey);
// Check balance first
const balance = await getWalletBalance(depositAddress, chain);
const tokenBalance = balance.tokens.find((t) => t.symbol === token);
if (!tokenBalance || parseFloat(tokenBalance.balance) === 0) return;
// Estimate gas
const gasEstimate = await fetch(
`https://secureapi.gridlog.io/api/v1/crypto/gas-fee/estimate?chain=${chain}&fromAddress=${depositAddress}&toAddress=${process.env.TREASURY_ADDRESS}&amount=${tokenBalance.balance}&tokenSymbol=${token}`,
{ headers: { "X-API-Key": process.env.MYAZA_API_KEY } },
).then((r) => r.json());
// Transfer
const transfer = await fetch(
"https://secureapi.gridlog.io/api/v1/crypto/transfer",
{
method: "POST",
headers: {
"X-API-Key": process.env.MYAZA_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
chain,
fromAddress: depositAddress,
fromPrivateKey: privateKey,
toAddress: process.env.TREASURY_ADDRESS,
amount: tokenBalance.balance,
tokenSymbol: token,
}),
},
).then((r) => r.json());
return transfer.txHash;
}
Autosweep (Recommended)
Instead of manually sweeping, configure Autosweep to automatically consolidate incoming funds to your treasury wallet. Contact the Myaza team to set this up.
Security Checklist
Private keys encrypted at rest with AES-256
Encryption key stored in a secrets manager, not environment variables
Private keys never logged or included in error messages
Access to wallet decryption limited to sweep/transfer services only
Separate wallets per customer (not shared deposit addresses)
Treasury wallet on hardware wallet or MPC custody