Skip to main content
Aleo support is embedded-only today. The methods below are exposed on wallet.* for Dynamic embedded (MPC) Aleo wallets and route through the iframe (the Aleo Feemaster + Provable’s Decentralized Proving Service). Wallet Adapter Aleo wallets expose a separate wallet.requestTransaction / wallet.requestRecords API and will throw if these embedded-only methods are called.
Aleo is a privacy-first L1 with two parallel state types:
  • Public — balances tracked on-chain like a standard ledger.
  • Private — balances held inside owned records (encrypted UTXOs). Spending a record reveals nothing about the rest of the wallet’s state.
The Dynamic Aleo wallet exposes operations across both states. All embedded-only operations sign through MPC and submit through the Provable DPS so the user’s view key never leaves the iframe.

Installation

npm i @dynamic-labs/aleo

Setup

Include the Aleo wallet connector in your provider configuration:
import { DynamicContextProvider } from '@dynamic-labs/sdk-react-core';
import { AleoWalletConnectors } from '@dynamic-labs/aleo';

<DynamicContextProvider
  settings={{
    walletConnectors: [AleoWalletConnectors],
    // ... other settings
  }}
>
  {/* Your app components */}
</DynamicContextProvider>;

Checking if a wallet is an Aleo wallet

import { isAleoWallet } from '@dynamic-labs/aleo';

if (!isAleoWallet(wallet)) {
  throw new Error('This wallet is not an Aleo wallet');
}

Sign a message

Available on every Aleo wallet (embedded and Wallet Adapter):
import { useDynamicContext } from '@dynamic-labs/sdk-react-core';
import { isAleoWallet } from '@dynamic-labs/aleo';

const { primaryWallet } = useDynamicContext();

if (!primaryWallet || !isAleoWallet(primaryWallet)) {
  throw new Error('This wallet is not an Aleo wallet');
}

const signature = await primaryWallet.signMessage('hello aleo');

Fetch private balances

For a per-token aggregated view of the wallet’s private balances (credits, stablecoins, ARC-21), use the usePrivateTokenBalances hook. It mirrors useTokenBalances and is the recommended way to render shielded balances next to public ones:
import {
  useTokenBalances,
  usePrivateTokenBalances,
} from '@dynamic-labs/sdk-react-core';

const { tokenBalances: publicBalances } = useTokenBalances();
const { tokenBalances: privateBalances, supportsPrivateBalances } =
  usePrivateTokenBalances();
Underneath the hook reads the wallet’s owned records through the iframe; the view key never leaves the iframe. See the hook reference for the full return shape and a composition example.

List owned records

If you need the raw owned records (rather than the per-token aggregation that usePrivateTokenBalances returns), call listOwnedRecords directly. Each entry carries program_name and record_name so you can group/display by token. Backed by Provable’s RecordScanner via the iframe — the view key never leaves the iframe.
import { useDynamicContext } from '@dynamic-labs/sdk-react-core';
import { isAleoWallet } from '@dynamic-labs/aleo';

const { primaryWallet } = useDynamicContext();

if (!primaryWallet || !isAleoWallet(primaryWallet)) {
  throw new Error('This wallet is not an Aleo wallet');
}

const { records } = await primaryWallet.listOwnedRecords();
// records[i].program_name      → e.g. 'credits.aleo'
// records[i].record_name        → e.g. 'credits' or 'Token'
// records[i].record_plaintext   → encrypted record plaintext

Execute a program transition (proveTransaction)

The generic Aleo entry point: signs through MPC, optionally injects a Sealance freeze-list proof for Sealance-compliant stablecoins, applies Feemaster sponsorship when covered, and submits to Provable DPS.
import { useDynamicContext } from '@dynamic-labs/sdk-react-core';
import { isAleoWallet } from '@dynamic-labs/aleo';

const { primaryWallet } = useDynamicContext();

if (!primaryWallet || !isAleoWallet(primaryWallet)) {
  throw new Error('This wallet is not an Aleo wallet');
}

const { txId } = await primaryWallet.proveTransaction({
  programId: 'credits.aleo',
  functionName: 'transfer_public',
  inputs: ['aleo1recipient...', '1000000u64'],
  inputTypes: ['address.public', 'u64.public'],
  broadcast: true,
});

Common transitions

credits.aleo/transfer_public(receiver: address, amount: u64) — public→public credits transfer.
await primaryWallet.proveTransaction({
  programId: 'credits.aleo',
  functionName: 'transfer_public',
  inputs: [recipient, `${amount.toString()}u64`],
  inputTypes: ['address.public', 'u64.public'],
  broadcast: true,
});

Shield a token (public → private)

The shield operation maps a public balance into a fresh private record owned by the user. The helpers below let you check eligibility and Feemaster sponsorship before dispatching.
import { useDynamicContext } from '@dynamic-labs/sdk-react-core';
import { isAleoWallet } from '@dynamic-labs/aleo';

const { primaryWallet } = useDynamicContext();

if (!primaryWallet || !isAleoWallet(primaryWallet)) {
  throw new Error('This wallet is not an Aleo wallet');
}

// 1. Is this token registered as shieldable on the current Aleo network?
const canShield = primaryWallet.canShieldToken({
  address: 'credits.aleo',
  isNative: true,
});

// 2. Does the Aleo Feemaster currently sponsor the shield call?
const sponsored = await primaryWallet.isShieldSponsored({
  address: 'credits.aleo',
  isNative: true,
});

// 3. Dispatch the shield. Recipient is always self.
if (canShield) {
  const txId = await primaryWallet.shieldToken({
    tokenAddress: 'credits.aleo',
    isNative: true,
    amount: 1_000_000n, // atomic units (microcredits for credits, 10^decimals for SPL-style tokens)
  });
}
The SDK applies optimistic updates the moment shieldToken resolves: the public balance is debited and a synthesised record is added to the private balance, so the UI reacts immediately without waiting for the indexer. Both useTokenBalances and usePrivateTokenBalances reflect the optimistic state, and reconcile silently once the new record is indexed.

Merge owned records (joinRecords)

Pairwise-merges owned records down to one per program by recursively running <program>/join. Sponsored by Feemaster for credits.aleo today; stablecoin / ARC-21 fall through to user-paid if Feemaster doesn’t yet cover the pair. Programs the connector doesn’t recognise (no registered join shape) are reported as skipped: 'unsupported' in results rather than thrown — iterate the results to surface what merged vs. what didn’t.
import { useDynamicContext } from '@dynamic-labs/sdk-react-core';
import { isAleoWallet } from '@dynamic-labs/aleo';

const { primaryWallet } = useDynamicContext();

if (!primaryWallet || !isAleoWallet(primaryWallet)) {
  throw new Error('This wallet is not an Aleo wallet');
}

// Merge every owned program that has ≥2 records.
const { results } = await primaryWallet.joinRecords();

// …or scope to a specific program.
await primaryWallet.joinRecords({ programIds: ['credits.aleo'] });

// …or ARC-21 with a token_id filter (records of different token_ids cannot be merged).
await primaryWallet.joinRecords({
  programIds: ['token_registry.aleo'],
  filterRecord: (r) => r.record_plaintext?.includes(`token_id: ${tokenId}`),
});

Check Feemaster sponsorship (generic)

For any (programId, functionName) pair on the currently-selected Aleo network. Useful to decide whether to dispatch silently or surface a user-paid fee confirmation. Never throws — returns false on any failure so callers can default to “show modal”.
const sponsored = await primaryWallet.isFeemasterSponsored({
  programId: 'credits.aleo',
  functionName: 'join',
});

Send flow widget integration

The Dynamic Widget’s “Send” button on Aleo wallets is driven by createUiTransaction, which exposes two modes:
  • Individual<program>/transfer_private (record-to-record).
  • Exchange — orchestrated two-step:
    1. transfer_private_to_public(record, SELF, amount) — unshield to the user’s own public balance.
    2. transfer_public(EXCHANGE, amount) — public→public to the exchange recipient.
Auto-shield is paused for the in-flight token during the Exchange flow, so the just- unshielded amount isn’t immediately re-shielded by the background optimisation.

Resources