Wallet Generation

Generate MPC wallets, securely store signing shares, confirm wallet readiness, and use a single wallet across multiple blockchain networks.

generateWallet() triggers the Tatum enclave to run MPC key generation. It produces one signing share per curve — SECP256K1 for EVM/Tron/Bitcoin and ED25519 for Solana/Stellar.

Generate a Wallet

const shares = await client.generateWallet();

// shares.SECP256K1 → { share: string, id: string }
// shares.ED25519   → { share: string, id: string }

Each share object contains:

  • share — the MPC share string (opaque, must be treated as a secret)
  • id — the signing share pair ID used for bookkeeping in Portal

These shares are shown once. Tatum does not store client shares. If you lose them, the wallet is unrecoverable unless you have a backup.

Store the Shares

Encrypt both shares immediately after generation and persist them:

import { createCipheriv, randomBytes } from "crypto";

function encryptShare(share: string, keyHex: string): string {
  const key = Buffer.from(keyHex, "hex");
  const iv = randomBytes(12);
  const cipher = createCipheriv("aes-256-gcm", key, iv);
  const ciphertext = Buffer.concat([cipher.update(share, "utf8"), cipher.final()]);
  const tag = cipher.getAuthTag();
  return Buffer.concat([iv, tag, ciphertext]).toString("base64");
}

const shares = await client.generateWallet();

await db.users.update(userId, {
  secp256k1Share: encryptShare(shares.SECP256K1.share, process.env.ENCRYPTION_KEY!),
  ed25519Share:   encryptShare(shares.ED25519.share,   process.env.ENCRYPTION_KEY!),
});

Confirm Shares Stored

After storing, call updateSigningSharePairs() to tell Portal that this client's shares are safely held. This step is required — Portal uses the status to track wallet readiness.

const details = await client.getClientDetails();

const signingSharePairIds = details.wallets!.flatMap(w =>
  (w.signingSharePairs ?? []).map(sp => sp.id!)
);

await client.updateSigningSharePairs({
  body: {
    signingSharePairIds,
    status: "STORED_CLIENT",
  },
});

Share Lifecycle

generateWallet() → shares returned to you
  ↓
You encrypt + store shares
  ↓
updateSigningSharePairs(status: "STORED_CLIENT")
  ↓
Sign / send using shares per request
  ↓
backupWallet() → backup shares → store encrypted
  ↓
updateBackupSharePairs(status: "STORED_CLIENT_BACKUP_SHARE")

One Wallet, All Chains

A single generateWallet() call produces shares that work across all supported chains. You use SECP256K1 for EVM/Tron/Bitcoin and ED25519 for Solana/Stellar — there is no per-chain key generation.