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
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,
});
credits.aleo/transfer_private(record, receiver, amount) — record-to-record private send.await primaryWallet.proveTransaction({
programId: 'credits.aleo',
functionName: 'transfer_private',
inputs: [recordPlaintext, recipient, `${amount.toString()}u64`],
inputTypes: ['credits.record', 'address.private', 'u64.private'],
broadcast: true,
});
credits.aleo/transfer_private_to_public(record, receiver, amount) — spend a record, credit the recipient’s public balance.await primaryWallet.proveTransaction({
programId: 'credits.aleo',
functionName: 'transfer_private_to_public',
inputs: [recordPlaintext, recipient, `${amount.toString()}u64`],
inputTypes: ['credits.record', 'address.public', 'u64.public'],
broadcast: true,
});
credits.aleo/transfer_public_to_private(receiver, amount) — debit the sender’s public balance, mint a private record owned by receiver.The receiver gets a private record so the recipient address is address.private; the
debited amount is public so it’s u64.public. Stablecoin / ARC-21 variants take
u128.public (and ARC-21 additionally takes token_id + external_auth_required).await primaryWallet.proveTransaction({
programId: 'credits.aleo',
functionName: 'transfer_public_to_private',
inputs: [recipient, `${amount.toString()}u64`],
inputTypes: ['address.private', 'u64.public'],
broadcast: true,
});
For the common case of shielding to self (with Feemaster sponsorship checks and
per-token registry handling), prefer the shieldToken
helper below — it wraps this transition.
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}`),
});
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',
});
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:
transfer_private_to_public(record, SELF, amount) — unshield to the user’s own public
balance.
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