A TypeScript interface for Aleo, inspired by viem. Wraps existing Aleo wallets and SDKs behind a unified, familiar API — for human developers and AI agents alike.
Aleo allows users privacy in their assets and data and allows developers to build privacy into their Dapps.
Veil provides semantics familiar to what EVM developers and agents expect. If you've built on Ethereum with viem, you already know how to use veil — same patterns, same method names, applied to Aleo.
import { createPublicClient, createWalletClient, http } from '@provablehq/veil-core'
import { fromWalletAdapter } from '@provablehq/veil-aleo-wallet-adapter'
// A read-only client — point a transport at an Aleo node (viem's createPublicClient).
const client = createPublicClient({
transport: http('https://api.provable.com/v2'),
})
// Similar method names as in viem, now reading Aleo state.
const height = await client.getBlockNumber() // current chain height
const balance = await client.getBalance({ address: 'aleo1...' }) // public credits
// readContract reads a program mapping: mapping[key] in `credits.aleo`.
const value = await client.readContract({
programId: 'credits.aleo',
mapping: 'account',
key: 'aleo1...',
})
// For writes, a wallet client pairs a transport with an account — same as viem.
// A connected wallet supplies both; a local key path uses @provablehq/veil-aleo-sdk.
const { account, transport } = fromWalletAdapter(walletAdapter)
const wallet = createWalletClient({ account, transport })
// writeContract mirrors viem: name the program + function, pass typed inputs.
const txId = await wallet.writeContract({
program: 'my_program.aleo',
function: 'transfer',
inputs: ['aleo1...', '100u64'],
})👛 Wallet-connected dApps — browser apps where a user's wallet (Shield, Leo, Puzzle, Fox) holds the keys and proves. (@provablehq/veil-aleo-react-hooks)
🔭 Explorers, dashboards, and indexers — read blocks, transactions, mappings, staking, and network metrics with no keys and no proving. (@provablehq/veil-core)
💸 Payments and token flows — public or private credit transfers and ARC-0020 tokens, including confidential transfers.
📈 Shield Swap trading — private swaps, liquidity, and pool/price reads, from a frontend, a programmatic bot, or an agent. (@provablehq/shield-swap-sdk)
🤖 AI agents that use Aleo — expose Aleo as MCP tools or drop tool schemas into any agent framework; agents can also write viem-style code directly. (@provablehq/veil-core/agent, @provablehq/veil-core/mcp)
🖥️ Servers, CLIs, and custodial services — hold a private key and sign and prove locally, unattended. (@provablehq/veil-aleo-sdk)
📜 Typed clients for your own contracts — generate bindings from a program ABI and call it with typed reads and writes. (@provablehq/veil-codegen, getContract)
🦁 Leo program pipelines — build, deploy, and test programs against a local node, including in CI. (@provablehq/veil-leo, @provablehq/veil-aleo-devnode)
⚡ Viem-compatible API — getBalance, readContract, writeContract, deployContract, sendTransaction, signMessage, and more
🧩 Interface-first — core has zero hard dependencies on any SDK. Wallets and SDKs plug in via adapter packages.
🔑 Multiple account types — RPC accounts (wallet adapters), local accounts (private key, mnemonic), view-only accounts
🔌 Pluggable transports — http() for Aleo REST API, custom() for injected providers, fallback() for chaining
📜 Contract instances — getContract() parses Aleo program source and provides typed read/write methods
🔏 Proving as configuration — proving strategy is a client config concern (delegated or local), not a separate abstraction
🤖 Agent-first — every action ships with an MCP tool, agent tool schema, and structured JSON output. AI agents can call Aleo directly via tool use or write code against the library using viem patterns they already know.
@provablehq/veil-core is the base — every other package builds on its client, action,
and transport interfaces.
| Package | What it's for | When to reach for it |
|---|---|---|
@provablehq/veil-core |
Clients, actions, transports, types — the base SDK. Also ships LLM agent (/agent) and MCP (/mcp) bindings. |
Every Veil project — reading or writing Aleo, or as the base you extend. |
@provablehq/veil-aleo-sdk |
Local accounts, signing, and proving via @provablehq/sdk. Build a client from a private key. |
Your code holds a private key and must sign and prove itself — bots, servers, CLIs, tests. |
@provablehq/veil-aleo-wallet-adapter |
Bridge any Provable-standard wallet (Shield, Leo, Puzzle, Fox) into a Veil client. | You need wallet signing outside React, or a custom (non-React) wallet integration. |
@provablehq/veil-aleo-react-hooks |
VeilProvider + useVeilWallet() — wallet connection and clients for React apps. |
You're building a React dApp with wallet connection. |
@provablehq/shield-swap-sdk |
Client for the shield_swap AMM/DEX — private swaps, liquidity, and the DEX API. |
You're integrating the Shield Swap DEX — swaps, liquidity, or pool/price data. |
@provablehq/veil-codegen |
Generate typed bindings from an Aleo program ABI (library + veil-codegen CLI). |
You want typed reads and writes for a specific program's ABI. |
@provablehq/veil-aleo-devnode |
Run and drive a local Aleo devnode for tests. | You need a local Aleo node in tests or local development. |
@provablehq/veil-leo |
Typed wrapper around the leo CLI (build, deploy, …). |
You compile or deploy Leo programs — including during testing, where it pairs with @provablehq/veil-aleo-devnode. |
@provablehq/veil-aleo-bridges |
Cross-chain bridge client (preview). | Not yet — in preview, not published. |
import { createPublicClient, http } from '@provablehq/veil-core'
const client = createPublicClient({
transport: http('https://api.provable.com/v2'),
})
// Familiar viem-style actions
const height = await client.getBlockNumber()
const block = await client.getBlock({ height: 1000 })
const tx = await client.getTransaction({ id: 'at1...' })
const balance = await client.getBalance({ address: 'aleo1...' })
const source = await client.getCode({ programId: 'credits.aleo' })
const value = await client.readContract({
programId: 'credits.aleo',
mapping: 'account',
key: 'aleo1...',
})import { createWalletClient } from '@provablehq/veil-core'
import { fromWalletAdapter } from '@provablehq/veil-aleo-wallet-adapter'
const { account, transport } = fromWalletAdapter(walletAdapter)
const client = createWalletClient({ account, transport })
// writeContract or its alias executeTransaction
await client.writeContract({
program: 'my_program.aleo',
function: 'transfer',
inputs: ['aleo1...', '100u64'],
fee: 1000n,
})
await client.deployContract({
program: myProgramSource,
fee: 5000n,
})
await client.transfer({
to: 'aleo1...',
amount: 1_000_000n,
})import { loadNetwork } from '@provablehq/veil-aleo-sdk'
// loadNetwork builds the account, proving, and clients from a private key.
const aleo = await loadNetwork('testnet')
const { publicClient, walletClient } = aleo.createAleoClient({
privateKey: 'APrivateKey1...',
networkUrl: 'https://api.provable.com/v2',
provingMode: 'delegated', // or 'local' to prove in-process
proverUrl: 'https://api.provable.com/prove/testnet',
})import { getContract } from '@provablehq/veil-core'
const contract = getContract({
programSource: tokenProgramSource,
client: { public: publicClient, wallet: walletClient },
})
// Typed read/write from parsed program source
const balance = await contract.read.balances({ key: 'aleo1...' })
const txId = await contract.write.transfer({
inputs: ['aleo1...', '100u64'],
fee: 1000n,
})import { createPublicClient, http, viewOnlyAccount } from '@provablehq/veil-core'
const client = createPublicClient({
transport: http('https://api.provable.com/v2'),
})
const account = viewOnlyAccount({
address: 'aleo1...',
viewKey: 'AViewKey1...',
})
// Use the view key to decrypt records without signing authority@provablehq/veil-aleo-bridges moves value between Aleo and other chains (Solana, Ethereum and
other EVM networks, Bitcoin, Tron) through third-party swap providers. Aleo is
always one side of the pair. Amounts are decimal strings in display units, and
assets use the API's chain-qualified codes (ALEO_MAINNET, USDC_ETH),
though getQuotes and swap also accept plain symbols ('USDC') and chain
display names ('Ethereum') and resolve them for you. Don't hardcode
identifiers: bridge.getRoutes()
derives the candidate pairs ("what can move where"), filterable by symbol or
chain name, each side carrying its code, chain, human-readable chainName,
decimals, and address-validation regex; bridge.getAssets() is the raw
catalog underneath and bridge.getProviders() lists the providers. Chain
slots on swap accept ids or display names ('Solana'), and a provider
option pins the quote to one provider.
Bridging out is one call. The client carries the signing wallet, and
swap runs the whole chain: quote the route, create the order, sign and
broadcast the Aleo deposit, and (with poll) wait until the funds arrive:
import { createBridgeClient, httpBridge } from '@provablehq/veil-aleo-bridges'
const bridge = createBridgeClient({
transport: httpBridge('https://wallet.api.provable.com'),
wallet: walletClient, // @provablehq/veil-core WalletClient — signs the Aleo deposit
})
const result = await bridge.swap({
from: { asset: 'ALEO_MAINNET', amount: '100' },
to: { chain: 'SOLANA', asset: 'SOL_SOLANA', address: solAddress },
poll: true, // wait for COMPLETED
})
result.depositTxId // at1... — the Aleo depositBridging in starts on the other chain, so the deposit is signed there — from this SDK you quote the route and create the order, then pay the returned deposit instructions from the source-chain wallet:
const { quotes } = await bridge.getQuotes({
srcChain: 'EVM:1', srcAsset: 'USDC_ETH',
destChain: 'ALEO', destAsset: 'USDC_ALEO',
amountIn: '250',
recipientAddress: aleoAddress, // where the USDC lands on Aleo
refundAddress: ethAddress,
})
const q = quotes[0]
const order = await bridge.createOrder({
providerId: q.provider.id,
srcChain: q.srcChain, destChain: q.destChain,
srcAsset: q.srcAsset, destAsset: q.destAsset,
amountIn: q.amountIn,
walletAddress: aleoAddress,
quoteId: (q.quoteId ?? q.quoteOptionId)!,
})
// → pay order.depositAmount to order.depositAddress from the user's EVM
// wallet — that side is plain viem (an erc20 transfer via writeContract;
// see packages/bridge/README.md for the full snippet) — then
await bridge.waitForOrder({ id: order.orderId })Bridged-in assets are ordinary Aleo tokens — tradeable on the Shield Swap DEX
via @provablehq/shield-swap-sdk with the same wallet client. The live examples are the
e2e tests:
packages/bridge/test/integration/e2e.test.ts
runs the full outbound swap chain, and
packages/shield-swap/test/integration/bridgeRoundTrip.e2e.test.ts
chains bridge in → DEX swap → bridge out. See
packages/bridge/README.md for providers,
routes, and route discovery.
veil is designed for two audiences equally: human developers who write code against the TypeScript library, and AI agents that either write code using viem patterns or call tools directly.
Run the MCP server to expose all veil actions as tools:
import { createMcpServer } from '@provablehq/veil-core/mcp'
import { createPublicClient, http } from '@provablehq/veil-core'
const client = createPublicClient({
transport: http('https://api.provable.com/v2'),
})
await createMcpServer({ client })Agents can then call tools like aleo_get_balance, aleo_read_mapping, aleo_execute, aleo_describe_program, etc. All tools return structured JSON with parsed Aleo values.
Use agent tool schemas and handlers directly in any agent framework:
import { aleoAgentTools } from '@provablehq/veil-core/agent'
const tools = aleoAgentTools({
client: publicClient,
walletClient: walletClient,
})
// Each tool has { schema, handler } — plug into LangChain, Vercel AI SDK, etc.Code-writing agents use the TypeScript library directly. Since it follows viem patterns, agents trained on viem can use it with minimal guidance. Key differences from viem that agents should know:
- Programs are identified by name (
'credits.aleo'), not address - Inputs are Aleo-encoded strings (
'100u64'), not hex — useencodeValue(100n, 'u64') - Use
describeProgramto discover what a program can do before calling it writeContracthas an aliasexecuteTransactionconsistent with Aleo wallet adapter terminology
All values are returned as structured JSON rather than Aleo's native string encoding:
import { parseValue, encodeValue } from '@provablehq/veil-core'
parseValue('100u64') // → { value: 100n, type: 'u64' }
parseValue('aleo1abc...') // → { value: 'aleo1abc...', type: 'address' }
encodeValue(100n, 'u64') // → '100u64'Every error message is an instruction an agent can act on:
Program "my_program.aleo" not found. Verify the program ID is correct
and has been deployed: await client.getCode({ programId: 'my_program.aleo' })
┌─────────────────────────────────────────────────┐
│ Your dApp / AI Agent │
├─────────────────────────────────────────────────┤
│ PublicClient WalletClient │
│ (read-only) (sign + execute) │
├─────────────────────────────────────────────────┤
│ Actions │
│ getBlockNumber writeContract │
│ getBalance executeTransaction (alias) │
│ readContract deployContract │
│ getCode sendTransaction │
│ getBlock signMessage │
│ getRecords transfer │
│ describeProgram decrypt │
│ requestRecords │
├─────────────────────────────────────────────────┤
│ Contract Instances │
│ getContract({ programSource, client }) │
│ → contract.read.mappingName() │
│ → contract.write.functionName() │
├─────────────────────────────────────────────────┤
│ Agent Tooling │
│ @provablehq/veil-core/agent — tool schemas + handlers │
│ @provablehq/veil-core/mcp — MCP server │
├─────────────────────────────────────────────────┤
│ Accounts │
│ RpcAccount LocalAccount ViewOnlyAccount │
│ (wallet) (private key) (view key) │
├─────────────────────────────────────────────────┤
│ Transports │
│ http() custom() fallback() │
├─────────────────────────────────────────────────┤
│ Client Configuration │
│ proving: { mode, url, apiKey } │
│ records: config object or custom impl │
├─────────────────────────────────────────────────┤
│ Adapter Packages │
│ @provablehq/veil-aleo-wallet-adapter @provablehq/veil-aleo-sdk │
├─────────────────────────────────────────────────┤
│ Aleo Network / Wallet Adapter │
└─────────────────────────────────────────────────┘
veil defines interfaces. Implementations plug in.
- Transport — any object with a
request(method, params)function - Account — describes capabilities (can sign? has private key? has view key?), not origin
- Proving — a client configuration (
mode: 'delegated' | 'local'), not a standalone interface. Wallets handle proving internally; only SDK/local users configure it. - Records — config object for common cases (
{ mode: 'network', url }) or custom implementation ({ getRecords: ... }) for advanced use cases.
Core has zero hard dependencies. Adapter packages (@provablehq/veil-aleo-wallet-adapter, @provablehq/veil-aleo-sdk) bridge to the ecosystem's existing SDKs.
veil wraps these existing tools through its adapter packages:
- Aleo Wallet Adapter — Leo Wallet, Puzzle Wallet, Fox Wallet, Shield Mobile Wallet
- @provablehq/sdk — WASM-based SDK for browser/node
| Method | Description | Agent Tool |
|---|---|---|
getBlockNumber() |
Current chain height | aleo_get_block_number |
getBlock({ height?, hash? }) |
Fetch block by height or hash | aleo_get_block |
getTransaction({ id }) |
Fetch transaction by ID | aleo_get_transaction |
getBalance({ address }) |
Public credits balance | aleo_get_balance |
readContract({ programId, mapping, key }) |
Read a program mapping value | aleo_read_mapping |
getCode({ programId }) |
Fetch program source code | aleo_get_program_source |
describeProgram({ program }) |
Introspect program functions and mappings | aleo_describe_program |
getRecords({ program }) |
Fetch records (Aleo-native) | aleo_get_records |
getTransitionViewKeys({ transactionId }) |
Get transition view keys (Aleo-native) | aleo_get_transition_view_keys |
| Method | Description | Agent Tool |
|---|---|---|
sendTransaction({ transaction }) |
Broadcast a built transaction | aleo_send_transaction |
writeContract({ program, function, inputs, fee }) |
Execute a program transition | aleo_execute |
executeTransaction(...) |
Alias for writeContract |
aleo_execute |
deployContract({ program, fee }) |
Deploy a program | aleo_deploy |
signMessage({ message }) |
Sign an arbitrary message | — |
transfer({ to, amount }) |
Transfer credits (convenience) | aleo_transfer |
decrypt({ ciphertext }) |
Decrypt a ciphertext (Aleo-native) | — |
requestRecords({ program }) |
Request records (Aleo-native) | — |
waitForTransaction({ id }) |
Wait for confirmation | aleo_wait_for_transaction |
If viem has a name for the concept, veil uses it. Aleo-specific names are only used for concepts with no EVM equivalent (records, decrypt, transition view keys). executeTransaction is provided as an alias for writeContract to stay consistent with Aleo wallet adapter terminology.
| viem concept | veil equivalent |
|---|---|
getBalance |
getBalance — reads public credits |
readContract |
readContract — reads program mapping |
writeContract |
writeContract / executeTransaction — executes program transition |
deployContract |
deployContract — deploys program |
getCode |
getCode — fetches program source |
sendTransaction |
sendTransaction — broadcasts transaction |
signMessage |
signMessage — signs message |
getContract |
getContract — typed contract instance from program source |
veil/
├── packages/
│ ├── core/ # @provablehq/veil-core (zero dependencies)
│ │ └── src/
│ │ ├── clients/ # createPublicClient, createWalletClient
│ │ ├── accounts/ # rpcAccount, privateKeyToAccount, etc.
│ │ ├── transports/ # http, custom, fallback
│ │ ├── actions/ # public/ and wallet/ actions
│ │ ├── contract/ # getContract, parseProgram
│ │ ├── agent/ # Agent tool schemas + handlers (@provablehq/veil-core/agent)
│ │ ├── mcp/ # MCP server (@provablehq/veil-core/mcp)
│ │ ├── types/ # core type definitions
│ │ ├── errors/ # error types (actionable messages)
│ │ └── utils/ # address validation, credits, value parsing
│ ├── provable-sdk/ # @provablehq/veil-aleo-sdk (wraps @provablehq/sdk)
│ ├── wallet-adapter/ # @provablehq/veil-aleo-wallet-adapter (wraps wallet standard)
│ ├── react/ # @provablehq/veil-aleo-react-hooks (VeilProvider, useVeilWallet)
│ ├── shield-swap/ # @provablehq/shield-swap-sdk (shield_swap AMM/DEX client)
│ ├── codegen/ # @provablehq/veil-codegen (ABI → typed bindings + CLI)
│ ├── devnode/ # @provablehq/veil-aleo-devnode (local Aleo devnode for tests)
│ ├── leo/ # @provablehq/veil-leo (typed leo CLI wrapper)
│ └── bridge/ # @provablehq/veil-aleo-bridges (cross-chain bridge client, preview)
├── skills/ # Skill definitions for code-writing agents
├── site/ # Docusaurus documentation site
└── package.json
pnpm install
pnpm test
pnpm build
pnpm typecheckMIT