A library and demo app for fetching and joining Aleo records using the Provable SDK. Supports credits.aleo and token registry programs on both testnet and mainnet.
The library lives in src/aleo/ and provides two main building blocks:
AleoClient— wraps the Provable SDK to handle network initialization, JWT auth, record scanning, and delegated proving.AutoJoinClient— orchestrates joining records using a pluggableJoinStrategy.
A JoinStrategy controls how records are joined. Two strategies are included:
Calls the standard join(recordA, recordB) transition directly on the token's own program. Works with any token that exposes a join transition.
Timing: Joins records in pairs across parallel rounds. Reducing N records requires ⌈log₂ N⌉ rounds of on-chain confirmations (e.g. 16 records → 4 rounds). The rounds execute multiple join transactions with a total of: 8 + 4 + 2 + 1 = 15 transactions.
Calls join_N transitions on dedicated batch wrapper programs (e.g. autojoin_credits_2_10.aleo) that accept 2–16 records in a single transaction.
Supported programs: Same base set as BasicAutoJoinStrategy, but only programs that have deployed batch wrappers on-chain. Arbitrary tokens with a join transition are not supported. More on chain programs can be deployed to support batch joining of other tokens. We expect to deploy a generic "dynamic dispatch" batch join program later this year (2026).
Timing: Up to 16 records collapse in one transaction. Most joins complete in a single confirmation round, making this significantly faster than BasicAutoJoinStrategy for large record sets. Ex. 32 records can be joined in 2 rounds of 3 total transactions.
Cost: The batch programs introduce a small gas fee cost overhead over just using the built-in join calls, however in practice this is very small in absolute terms due to the low cost of the Aleo network transactions.
BasicAutoJoinStrategy | BatchAutoJoinStrategy | |
|---|---|---|
Works with any join token | Yes | No — requires batch wrapper programs |
| Records per transaction | 2 | 2–16 |
| Rounds to join N records | ⌈log₂ N⌉ | ⌈log₁₆ N⌉ |
You can provide your own strategy by implementing the interface:
interfaceJoinStrategy{isSupportedProgram(programName: string): boolean;joinRecords(records: AleoRecord[]): Promise<AleoRecord>;}import{AleoClient}from'./src/aleo/aleoClient';import{AutoJoinClient}from'./src/aleo/autojoin/autoJoinClient';import{BasicAutoJoinStrategy}from'./src/aleo/autojoin/strategies/basicAutoJoinStrategy';constaleoClient=newAleoClient('testnet',{apiKey: 'YOUR_API_KEY',consumerId: 'YOUR_CONSUMER_ID',apiRoot: 'https://api.provable.com',// optional, this is the default});// Must be called before any other operationsawaitaleoClient.initNetwork();constaccount=aleoClient.accountFromPrivateKey('APrivateKey1zkp...');Registers the account's view key with the record scanner. Idempotent — safe to call multiple times.
awaitaleoClient.registerAccountForRecordScanning(account);constrecords=awaitaleoClient.fetchUnspentRecords(account,['credits.aleo'],// one or more program names to filter byaccount.address().to_string()// optional; derived from account if omitted);for(constrecordofrecords){console.log(record.programName);// e.g. 'credits.aleo'console.log(record.transactionId);// transaction that created this recordconsole.log(record.amount);// microcredits as a string, undefined if not parseable}Reduces any number of records down to one by pairing and joining them in parallel rounds.
constautoJoinClient=newAutoJoinClient(aleoClient,account,BasicAutoJoinStrategy);constjoinedRecord=awaitautoJoinClient.joinRecords(records);console.log('Final record tx:',joinedRecord.transactionId);joinRecords validates that all records share the same program, are owned by the same address, are supported by the strategy, and each have a transactionId. It throws a descriptive error if any condition is not met or if on-chain confirmation times out.
The React demo app lets you enter a private key, browse unspent records for a selected program, and trigger a join across all loaded records.
Copy the environment template and fill in your credentials:
cp .env.example .env| Variable | Description |
|---|---|
VITE_PROVABLE_API_KEY | Your Provable API key |
VITE_PROVABLE_CONSUMER_ID | Your Provable consumer ID |
VITE_PROVABLE_API_ROOT | API root URL (optional, defaults to https://api.provable.com) |
VITE_DEFAULT_PKEY | Pre-fills the private key input (optional, development only) |
# Install dependencies
pnpm install
# Start the development server (http://localhost:5173)
pnpm dev
# Type-check and build for production
pnpm build
# Preview the production build locally
pnpm preview