> ## 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 Embedded Wallets

<Card title="Recommended: JavaScript SDK with React Hooks" icon="react" href="/javascript/reference/react-quickstart" color="#4779FE">
  For new React apps, we recommend the JavaScript SDK with React Hooks (`@dynamic-labs-sdk/react-hooks`) instead of the legacy React SDK documented here. The JS SDK comes with many benefits such as a much smaller bundle size and other optimizations. Use the [React quickstart (JavaScript SDK)](/javascript/reference/react-quickstart) to get started.
</Card>

<Info>
  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.
</Info>

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

```bash theme={"system"}
npm i @dynamic-labs/aleo
```

## Setup

Include the Aleo wallet connector in your provider configuration:

```tsx theme={"system"}
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

```tsx theme={"system"}
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):

```tsx theme={"system"}
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`](/react/reference/hooks/useprivatetokenbalances) hook. It mirrors [`useTokenBalances`](/react/reference/hooks/usetokenbalances) and is the recommended way to render shielded balances next to public ones:

```tsx theme={"system"}
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](/react/reference/hooks/useprivatetokenbalances) 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.

```tsx theme={"system"}
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.

```tsx theme={"system"}
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

<Tabs>
  <Tab title="Public transfer">
    `credits.aleo/transfer_public(receiver: address, amount: u64)` — public→public credits transfer.

    ```tsx theme={"system"}
    await primaryWallet.proveTransaction({
      programId: 'credits.aleo',
      functionName: 'transfer_public',
      inputs: [recipient, `${amount.toString()}u64`],
      inputTypes: ['address.public', 'u64.public'],
      broadcast: true,
    });
    ```
  </Tab>

  <Tab title="Private transfer">
    `credits.aleo/transfer_private(record, receiver, amount)` — record-to-record private send.

    ```tsx theme={"system"}
    await primaryWallet.proveTransaction({
      programId: 'credits.aleo',
      functionName: 'transfer_private',
      inputs: [recordPlaintext, recipient, `${amount.toString()}u64`],
      inputTypes: ['credits.record', 'address.private', 'u64.private'],
      broadcast: true,
    });
    ```
  </Tab>

  <Tab title="Unshield (private → public)">
    `credits.aleo/transfer_private_to_public(record, receiver, amount)` — spend a record, credit the recipient's *public* balance.

    ```tsx theme={"system"}
    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,
    });
    ```
  </Tab>

  <Tab title="Shield (public → private)">
    `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`).

    ```tsx theme={"system"}
    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`](#shield-a-token-public-private)
    helper below — it wraps this transition.
  </Tab>
</Tabs>

## 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.

```tsx theme={"system"}
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)
  });
}
```

<Note>
  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`](/react/reference/hooks/usetokenbalances)
  and [`usePrivateTokenBalances`](/react/reference/hooks/useprivatetokenbalances) reflect the
  optimistic state, and reconcile silently once the new record is indexed.
</Note>

## 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.

```tsx theme={"system"}
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".

```tsx theme={"system"}
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

* [Aleo Network documentation](https://docs.explorer.provable.com/)
* [Provable DPS overview](https://docs.explorer.provable.com/dps)
* [Sealance compliance protocol](https://github.com/SealanceProject)
* [SLIP-44 coin type 2147483965 (Aleo)](https://github.com/satoshilabs/slips/blob/master/slip-0044.md)
