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:
interface JoinStrategy {
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';
const aleoClient = new AleoClient('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 operations
await aleoClient.initNetwork();const account = aleoClient.accountFromPrivateKey('APrivateKey1zkp...');Registers the account's view key with the record scanner. Idempotent — safe to call multiple times.
await aleoClient.registerAccountForRecordScanning(account);const records = await aleoClient.fetchUnspentRecords(
account,
['credits.aleo'], // one or more program names to filter by
account.address().to_string() // optional; derived from account if omitted
);
for (const record of records) {
console.log(record.programName); // e.g. 'credits.aleo'
console.log(record.transactionId); // transaction that created this record
console.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.
const autoJoinClient = new AutoJoinClient(aleoClient, account, BasicAutoJoinStrategy);
const joinedRecord = await autoJoinClient.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