Skip to main content

Documentation Index

Fetch the complete documentation index at: https://www.dynamic.xyz/docs/llms.txt

Use this file to discover all available pages before exploring further.

Aleo support is embedded-only today. The methods below are exposed on wallet.* for Dynamic embedded (MPC) Aleo wallets and route through the iframe (Sodot MPC + 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');

List owned records (private balances)

Returns the wallet’s owned Aleo records across every program (credits, stablecoins, ARC-21). 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)
  });
}

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