Skip to main content

Quickstart

This guide walks through all client operations for the Merces private payments system using TACEO's hosted infrastructure — no contract deployment required.

Testnet only

The current deployment uses test tokens with no real-world value. Do not use mainnet private keys or real funds.

You will:

  1. Install the Merces2 client.
  2. Create a client and register your wallet.
  3. Deposit ERC-20 tokens into your private account.
  4. Check your balances.
  5. Send private and confidential payments.
  6. Withdraw back to ERC-20.
  7. Retrieve transaction history.

Prerequisites

  • Node.js 20+ (TypeScript) or Rust 1.91+ (Rust)

Step 1: Install the package

npm install @taceo/merces2-client viem

Step 2: Create a client

import { createWalletClient, createPublicClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { plasmaTestnet } from 'viem/chains';
import { Client } from '@taceo/merces2-client';

const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);

const walletClient = createWalletClient({
account,
chain: plasmaTestnet,
transport: http("https://testnet-rpc.plasma.to"),
});

const publicClient = createPublicClient({
chain: plasmaTestnet,
transport: http("https://testnet-rpc.plasma.to"),
});

const client = new Client({
idRegistryUrl: 'https://id-registry.merces2.taceo.io',
gatewayUrl: 'wss://gateway.merces2.taceo.io',
nodeUrls: [
'https://node0.merces2.taceo.io',
'https://node1.merces2.taceo.io',
'https://node2.merces2.taceo.io',
],
contractAddress: '0x<MERCES_CONTRACT>',
tokenAddress: '0x<USDT_ADDRESS>',
vaultAddress: '0x<VAULT_ADDRESS>',
token: 'EIP3009',
walletClient,
publicClient,
});

// Register the wallet with the id registry (idempotent)
await client.register();

Step 3: Deposit ERC-20 tokens into your private account

Merces supports two privacy modes. Choose one per deposit:

ModeWhat's hidden
ConfidentialAmounts and balances; sender/receiver addresses remain visible
Fully privateAmounts, balances, sender, and receiver
import { parseUnits } from 'viem';

const decimals = await client.getDecimals();
const amount = parseUnits('100', decimals);

// Confidential mode: amounts hidden, addresses visible
const txHash = await client.confidentialDeposit(amount);
console.log('Confidential deposit confirmed:', txHash);

// Fully private mode: amounts and addresses hidden
// const txHash = await client.privateDeposit(amount);
// console.log('Private deposit confirmed:', txHash);

Step 4: Check balances

import { formatUnits } from 'viem';

const decimals = await client.getDecimals();

// ERC-20 balance (public, on-chain)
const erc20Balance = await client.getErc20Balance();
console.log('ERC-20 balance: ', formatUnits(erc20Balance, decimals));

// Private balance (secret-shared across MPC nodes)
const privateBalance = await client.getPrivateBalance();
console.log('Private balance: ', formatUnits(privateBalance, decimals));

Step 5: Send payments

Confidential transfer

Amounts and balances are hidden; sender and receiver wallet addresses remain visible on-chain. Use this mode when settling to a known counterparty wallet while keeping amounts private.

import { parseUnits } from 'viem';

const decimals = await client.getDecimals();
const receiver = '0x<RECEIVER_ADDRESS>';

const txHash = await client.confidentialTransfer(receiver, parseUnits('50', decimals));
console.log('Confidential transfer confirmed:', txHash);

Fully private transfer

Amounts, balances, sender, and receiver are all hidden. Use this for consumer payments, sensitive treasury moves, or any flow requiring full transaction-graph privacy.

import { parseUnits } from 'viem';

const decimals = await client.getDecimals();
const receiver = '0x<RECEIVER_ADDRESS>';

const txHash = await client.privateTransfer(receiver, parseUnits('50', decimals));
console.log('Private transfer confirmed:', txHash);

Step 6: Withdraw back to ERC-20

Exit the private system and return funds to a standard on-chain ERC-20 balance.

import { parseUnits, formatUnits } from 'viem';

const decimals = await client.getDecimals();
const amount = parseUnits('50', decimals);

// Confidential withdraw (matching confidential deposit/transfer)
const txHash = await client.confidentialWithdraw(amount);
console.log('Confidential withdraw confirmed:', txHash);

// Fully private withdraw (matching private deposit/transfer)
// const txHash = await client.privateWithdraw(amount);
// console.log('Private withdraw confirmed:', txHash);

const newErc20Balance = await client.getErc20Balance();
console.log('New ERC-20 balance:', formatUnits(newErc20Balance, decimals));

Step 7: Retrieve transaction history

Fetch and decrypt the transaction history for an address.

// Full history
const history = await getTxHistory(
'https://id-registry.merces2.taceo.io',
'https://orchestrator.merces2.taceo.io',
client.address(),
);

console.log(`${history.length} transactions`);
for (const tx of history) {
console.log(tx);
}

Next steps