Skip to main content
Setup examples use React with @dynamic-labs-sdk/react-hooks, but the Aleo calls (requestRecords, requestTransaction) live on the wallet provider from @dynamic-labs-sdk/aleo and work in any framework. Before this: create and initialize a Dynamic client (see Creating a Dynamic Client, Initializing the Dynamic Client).
Aleo is a privacy-first L1 where balances live inside encrypted records rather than public account state. A private transfer consumes one record and produces two new ones (one for the recipient, one returning the change to the sender), without revealing the sender, recipient, or amount on-chain. On Aleo there is no one-call transfer helper. You pick one of the wallet’s own records, then submit a credits.aleo/transfer_private transition through requestTransaction. The embedded wallet proves and broadcasts it for you.

How it works

  1. User logs in with email OTP (or any auth method you configure in the dashboard).
  2. An embedded Aleo wallet is created automatically via MPC. The private key never leaves Dynamic’s wallet service.
  3. Your app lists the records the wallet owns and picks one that covers the amount.
  4. requestTransaction() sends the transition to the wallet service, which generates the zero-knowledge proof and broadcasts the transaction.
Proving is slower than a normal signed transaction, so the call takes several seconds. Surface a loading state so users know it’s working. The network fee is sponsored, so you do not pass a fee.

Setup

Dashboard configuration

In the Dynamic dashboard, enable Aleo under Chains & Networks, enable Embedded wallets under Wallets, and turn on automatic wallet creation so a wallet is provisioned the moment a user logs in. Skipping this step is the most common reason useGetWalletAccounts() returns no Aleo account. It’s a dashboard setting, not a code issue.

Install dependencies

@tanstack/react-query is a required peer dependency of @dynamic-labs-sdk/react-hooks. Every hook is built on TanStack Query.

Environment variables

.env.local
Your environment ID is in the Dynamic dashboard under Developer Settings → SDK & API Keys.

Initialize Dynamic

Create src/lib/dynamicClient.ts:
src/lib/dynamicClient.ts

Wire the provider

src/app/providers.tsx

Auto-create wallets on login

Place this component inside <DynamicProvider> so an Aleo wallet is provisioned as soon as the user authenticates:
src/lib/WaasBootstrap.tsx

Step 1: Get the Aleo wallet and its provider

The Aleo methods live on the wallet provider, so you need both the account and the provider. isAleoWalletAccount picks the Aleo account out of a mixed-chain list, and isAleoWalletProvider narrows the provider to the Aleo surface.

Step 2: Read the public balance

getNativeBalance returns the wallet’s public credits balance as a human-readable string (credits, not microcredits). Private records are not included: they are only visible to the wallet that owns them, which is what Step 3 reads.

Step 3: Find a record that covers the amount

requestRecords returns the credits.aleo records the wallet owns. Pass plaintext: true to get the decrypted record strings, which carry the microcredits amount you need to compare against. A private transfer spends exactly one record, so you need a single record worth at least the amount you are sending.
src/lib/findAleoRecord.ts
requestRecords is optional on the Aleo wallet provider type, so call it with ?. as above. It is implemented for embedded wallets; external wallets implement it only if the extension supports record enumeration.

Step 4: Send the private transfer

Build a single transfer_private transition and pass it to requestTransaction. Supply inputTypes explicitly: the record and the private inputs cannot be inferred from their string values, and the wallet service needs the types to build the proving circuit. requestTransaction returns the on-chain transaction id (at1...).
getAleoExplorerTxUrl builds the Provable explorer URL and validates the transaction id. Pass the active networkId so testnet transactions link to the testnet explorer (0 is mainnet, 1 is testnet).
src/lib/getAleoTxLink.ts

Current limits

On embedded Aleo wallets today:
  • One transition per transaction. Batching several transitions atomically is not exposed yet.
  • signMessage and decrypt throw AleoFeatureUnsupportedError. Aleo’s MPC signer has no arbitrary-message primitive, and the view key stays inside the wallet service.
  • There is no record merging in the JavaScript SDK, so a payment is capped by the largest single record the wallet owns.
  • The chain-agnostic transferAmount helper is not implemented for Aleo yet, so it throws for an Aleo wallet account. Use requestTransaction as shown above. When Aleo support lands, transferAmount becomes the one-call path for public transfers; private transfers still need a record, so Steps 3 and 4 stay relevant.

Common issues

See also

Last modified on September 9, 2026