Skip to main content

Getting Started

Installation

Every setup starts with the base package.

npm install @provablehq/veil-core

A browser dApp adds the React hooks package, which pulls in the wallet adapter bridge:

npm install @provablehq/veil-core @provablehq/veil-aleo-react-hooks

A Node process holding its own private key adds the local-signing package instead, which pulls in @provablehq/sdk:

npm install @provablehq/veil-core @provablehq/veil-aleo-sdk

A read-only integration — an explorer, an indexer, a price feed — needs only @provablehq/veil-core; no account or signing package is required.

Read-only client

Create a public client and start reading. No account, wallet, or private key is involved anywhere in this path.

import { createPublicClient, http } from '@provablehq/veil-core'

const client = createPublicClient({
transport: http('https://api.provable.com/v2', { network: 'mainnet' }),
})

// Current chain height
const height = await client.getBlockNumber()

// Public credits balance
const balance = await client.getBalance({
address: 'aleo1q6qstg8q8shwqf5m6q5fcenuwsdqsvp4hhsgfnx5chzjm3secyzqt9mxm8',
})

// A program mapping value — Aleo's public key/value storage
const raw = await client.readContract({
programId: 'credits.aleo',
mapping: 'account',
key: 'aleo1q6qstg8q8shwqf5m6q5fcenuwsdqsvp4hhsgfnx5chzjm3secyzqt9mxm8',
})

Browser dApp with a connected wallet

VeilProvider auto-configures every known Aleo wallet adapter (Shield, Leo, Puzzle, Fox) and useVeilWallet returns a public client that works immediately and a wallet client that becomes available once the user connects.

import { VeilProvider, useVeilWallet } from '@provablehq/veil-aleo-react-hooks'

function Root() {
return (
<VeilProvider network="testnet" programs={['my_program.aleo']}>
<App />
</VeilProvider>
)
}

function App() {
const { publicClient, walletClient, address, connect } = useVeilWallet()

async function checkBalance() {
// Reads work before a wallet connects.
return publicClient.getBalance({ address: 'aleo1...' })
}

async function sendTransfer() {
// Writes require a connected wallet — walletClient is undefined until then.
if (!walletClient) return
return walletClient.writeContract({
program: 'my_program.aleo',
function: 'transfer',
inputs: ['aleo1...', '100u64'],
})
}

return (
<div>
{address ? address : <button onClick={() => connect('Shield Wallet')}>Connect</button>}
</div>
)
}

programs declares which programs the dApp calls; wallets like Shield require it at connection time and reject calls to programs not listed there.

Node process with a local private key

loadNetwork loads the Aleo WASM binaries for one network and returns a handle carrying account derivation and proving configuration bound to it. The handle's privateKeyToAccount and createProvingConfig build the pieces a wallet client needs to sign, prove, and broadcast without a browser wallet in the loop.

import { createPublicClient, createWalletClient, http } from '@provablehq/veil-core'
import { loadNetwork } from '@provablehq/veil-aleo-sdk'

const transport = http('https://api.provable.com/v2', { network: 'testnet' })

// Public client for reads — same interface as the read-only path above.
const publicClient = createPublicClient({ transport })

const aleo = await loadNetwork('testnet')
const account = aleo.privateKeyToAccount('APrivateKey1...')

const walletClient = createWalletClient({
account,
transport,
proving: aleo.createProvingConfig({
mode: 'delegated',
networkUrl: 'https://api.provable.com/v2',
proverUrl: 'https://api.provable.com',
consumerId: '<consumer-id>',
apiKey: '<api-key>',
account,
}),
})

const txId = await walletClient.writeContract({
program: 'my_program.aleo',
function: 'my_function',
inputs: ['aleo1...', '100u64'],
})

mode: 'delegated' sends the proving work to a remote prover at proverUrl instead of proving in-process; pass mode: 'local' to prove with the handle's own WASM binaries instead, dropping proverUrl, consumerId, and apiKey. consumerId and apiKey authenticate against the delegated prover and come from registering with the Provable API — see the "Registering with the Provable API" section of the repository's AGENTS.md for the one-time registration call.

Next steps