This document explains how the CLI integrates with the BakoSafe SDK and how to use both together.
The Bako Vault CLI is a serverless alternative to the BakoSafe web application. It uses the same BakoSafe SDK under the hood, ensuring compatibility with vaults created in the web app.
{
"dependencies": {
"bakosafe": "^0.0.31",
"fuels": "^0.100.3"
}
}The wallet configuration in the CLI matches the SDK's IPredicateConfig:
// CLI wallet config (wallets/<name>.json)
{
"config": {
"SIGNATURES_COUNT": 2,
"SIGNERS": ["0x...", "0x..."],
"HASH_PREDICATE": "0x..."
},
"version": "0x..."
}
// Equivalent SDK usage
const vault = new Vault(provider, {
SIGNATURES_COUNT: 2,
SIGNERS: ["0x...", "0x..."],
HASH_PREDICATE: "0x..."
}, version);- Create a vault in BakoSafe web app
- Copy the vault configuration
- Create a wallet JSON file with the configuration
Transactions created with the CLI are compatible with BakoSafe:
- Same hash generation algorithm
- Same signature encoding
- Same predicate verification
| CLI Operation | SDK Method |
|---|---|
| Create vault instance | new Vault(provider, config, version) |
| Create transaction | vault.transaction({ assets }) |
| Encode signature | vault.encodeSignature(signer, signature) |
| Send transaction | vault.send(tx) |
| Get balance | vault.getBalance(assetId) |
| Get balances | vault.getBalances() |
SDK:
import { Provider } from 'fuels';
import { Vault } from 'bakosafe';
const provider = new Provider('https://testnet.fuel.network/v1/graphql');
const vault = new Vault(provider, {
SIGNATURES_COUNT: 2,
SIGNERS: ['0x...', '0x...'],
HASH_PREDICATE: '0x...',
}, '0xversion...');
console.log('Vault address:', vault.address.toB256());CLI:
# Create wallets/my-vault.json with the same config
bako-vault info my-vault -n testnet
# Shows: Address: 0x... (same as SDK)SDK:
const { tx, hashTxId } = await vault.transaction({
assets: [{
assetId: '0x...',
amount: '0.001',
to: '0xRecipient...',
}],
});
console.log('Hash to sign:', hashTxId);CLI:
bako-vault create-tx -w my-vault -n testnet -t 0xRecipient -a 0.001
# Shows: Hash to Sign: <same hash>SDK:
import { Wallet } from 'fuels';
const wallet = Wallet.fromPrivateKey('0x...');
const signature = await wallet.signMessage(hashTxId);CLI:
bako-vault sign -p 0x...
# Produces the same signatureSDK:
const encodedSig = vault.encodeSignature(signer, signature);
tx.witnesses = [encodedSig];
const response = await vault.send(tx);
const result = await response.waitForResult();CLI:
bako-vault sign -p 0x...
# When prompted, select 'Y' to send
# Or use send-tx with explicit signature- Create transaction in BakoSafe web app
- Copy the
hashTxId - Sign locally:
# The sign command uses the pending transaction's hashTxId # You can also sign manually: fuels wallet sign --message <hashTxId> --private-key <pk>
- Submit signature back to web app
- Create and send transaction with CLI
- Copy the transaction ID
- View in block explorer linked to BakoSafe
class Vault {
constructor(
provider: Provider,
config: IPredicateConfig,
version: string
);
address: Address;
version: string;
async transaction(params: {
assets: Array<{
assetId: string;
amount: string;
to: string;
}>;
}): Promise<{ tx: TransactionRequest; hashTxId: string }>;
encodeSignature(signer: string, signature: string): string;
async send(tx: TransactionRequest): Promise<TransactionResponse>;
async getBalance(assetId: string): Promise<BN>;
async getBalances(): Promise<{ balances: Array<{ assetId: string; amount: BN }> }>;
}interface IPredicateConfig {
SIGNATURES_COUNT: number;
SIGNERS: string[];
HASH_PREDICATE?: string;
}Ensure you're using the same:
- Predicate version
- Signer addresses
- Hash to sign (hashTxId)
The vault address is deterministic based on:
SIGNERSarray (order matters!)SIGNATURES_COUNTHASH_PREDICATEversion
All must match exactly.
When sending, the CLI recreates the transaction with the same parameters. Ensure:
- The pending transaction file hasn't been modified
- The network is accessible
- The vault has sufficient balance
- Keep configurations in sync: If you modify the vault in the web app, update the CLI config
- Use the same network: Don't mix testnet and mainnet configurations
- Verify before sending: Use
wallet-infoto check the vault state - Backup pending transactions: The
.pending-tx.jsonfile contains important state