Skip to main content

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;
}
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