skills/compute/account-management/SKILL.md
# Account Management ## Metadata - **Category**: compute - **SDK**: `@0glabs/0g-serving-broker` ^0.6.5, `ethers` ^6.13.0 - **Activation Triggers**: "deposit", "transfer funds", "refund", "check balance", "account balance" ## Purpose Manage funds across the 0G Compute Network's dual-account system: Main Account (receives deposits) and Provider Sub-Accounts (one per provider, funds locked for that provider's services). ## Prerequisites - Node.js >= 22 - `@0glabs/0g-serving-broker` and `ether
npx skillsauth add 0gfoundation/0g-agent-skills skills/compute/account-managementInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
4 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
@0glabs/0g-serving-broker ^0.6.5, ethers ^6.13.0Manage funds across the 0G Compute Network's dual-account system: Main Account (receives deposits) and Provider Sub-Accounts (one per provider, funds locked for that provider's services).
@0glabs/0g-serving-broker and ethers installed.env with PRIVATE_KEY, RPC_URLYour Wallet
| deposit
v
Main Account
| transfer-fund
v
Provider Sub-Accounts (one per provider)
| service usage (auto-deducted)
| retrieve-fund (24h lock)
v
Main Account
| refund
v
Your Wallet
acknowledgeProviderSigner)processResponse() param order: (providerAddress, chatID, usageData)ZG-Res-Key header first, body as fallback (chatbot only)import { ethers } from 'ethers';
import { createZGComputeNetworkBroker } from '@0glabs/0g-serving-broker';
import 'dotenv/config';
async function checkBalance() {
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);
const broker = await createZGComputeNetworkBroker(wallet);
// getLedger() returns a tuple array: [address, totalBalance, availableBalance, ...]
const account = await broker.ledger.getLedger();
console.log(`Address: ${account[0]}`);
console.log(`Total Balance: ${ethers.formatEther(account[1])} 0G`);
console.log(`Available: ${ethers.formatEther(account[2])} 0G`);
return account;
}
async function fundProvider(providerAddress: string, amount: number) {
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);
const broker = await createZGComputeNetworkBroker(wallet);
// Deposit to Main Account
await broker.ledger.depositFund(amount);
console.log(`Deposited ${amount} 0G to Main Account`);
// Transfer to provider sub-account
const transferAmount = ethers.parseEther(String(amount));
await broker.ledger.transferFund(providerAddress, 'inference', transferAmount);
console.log(`Transferred ${amount} 0G to provider ${providerAddress}`);
}
async function checkSubAccount(providerAddress: string) {
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);
const broker = await createZGComputeNetworkBroker(wallet);
// getAccountWithDetail() returns [subAccountTuple, refundsArray]
// subAccount tuple: [0]=user, [1]=provider, [2]=balance, [3]=pendingRefund, ...
const [subAccount, refunds] = await broker.inference.getAccountWithDetail(providerAddress);
console.log(`Sub-account user: ${subAccount[0]}`);
console.log(`Sub-account provider: ${subAccount[1]}`);
console.log(`Sub-account balance: ${ethers.formatEther(subAccount[2])} 0G`);
if (refunds.length > 0) {
refunds.forEach((refund: any, i: number) => {
console.log(`Pending refund ${i + 1}:`, refund);
});
}
}
async function requestRefund() {
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);
const broker = await createZGComputeNetworkBroker(wallet);
// Step 1: Initiate refund (starts 24h lock)
await broker.ledger.retrieveFund('inference');
console.log('Refund requested — 24h lock period started');
// Step 2: After 24 hours, complete the refund
// await broker.ledger.retrieveFund('inference');
// console.log('Refund completed — funds returned to Main Account');
}
async function withdrawToWallet(amount: number) {
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);
const broker = await createZGComputeNetworkBroker(wallet);
await broker.ledger.refund(amount);
console.log(`Withdrew ${amount} 0G to wallet`);
}
async function setupForProvider(providerAddress: string) {
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);
const broker = await createZGComputeNetworkBroker(wallet);
// 1. Check current balance (tuple: [0]=addr, [1]=total, [2]=available)
const account = await broker.ledger.getLedger();
const available = parseFloat(ethers.formatEther(account[2]));
console.log(`Available balance: ${available} 0G`);
// 2. Deposit if needed
if (available < 5) {
await broker.ledger.depositFund(10);
console.log('Deposited 10 0G');
}
// 3. Transfer to provider
await broker.ledger.transferFund(providerAddress, 'inference', ethers.parseEther('5'));
console.log('Transferred 5 0G to provider');
// 4. Acknowledge provider
await broker.inference.acknowledgeProviderSigner(providerAddress);
console.log('Provider acknowledged');
console.log('Account setup complete — ready for inference');
}
async function safeFundProvider(providerAddress: string, amount: number) {
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);
const broker = await createZGComputeNetworkBroker(wallet);
try {
// Tuple: [0]=address, [1]=totalBalance, [2]=availableBalance
const account = await broker.ledger.getLedger();
const available = parseFloat(ethers.formatEther(account[2]));
if (available < amount) {
const depositNeeded = amount - available + 1; // +1 buffer
console.log(`Insufficient balance. Depositing ${depositNeeded} 0G...`);
await broker.ledger.depositFund(depositNeeded);
}
await broker.ledger.transferFund(
providerAddress,
'inference',
ethers.parseEther(String(amount)),
);
console.log(`Successfully funded provider with ${amount} 0G`);
} catch (error) {
console.error('Funding failed:', error);
throw error;
}
}
| Action | CLI Command |
| ----------------- | ----------------------------------------------------------- |
| Setup network | 0g-compute-cli setup-network |
| Login | 0g-compute-cli login |
| Deposit | 0g-compute-cli deposit --amount 10 |
| Check balance | 0g-compute-cli get-account |
| Check sub-account | 0g-compute-cli get-sub-account --provider <ADDR> |
| Transfer | 0g-compute-cli transfer-fund --provider <ADDR> --amount 5 |
| Refund (2-step) | 0g-compute-cli retrieve-fund |
| Withdraw | 0g-compute-cli refund --amount 5 |
// BAD: Not checking balance before operations
await broker.inference.getRequestHeaders(providerAddress);
// May fail with "insufficient balance"
// BAD: Trying to complete refund immediately
await broker.ledger.retrieveFund('inference'); // Start lock
await broker.ledger.retrieveFund('inference'); // Won't work — 24h lock!
// BAD: Locking all funds in one provider
await broker.ledger.transferFund(addr, 'inference', entireBalance);
// No flexibility to use other providers
// BAD: Hardcoding private keys
const wallet = new ethers.Wallet('0xabc123...', provider); // NEVER do this
// BAD: ethers v5 syntax
const provider = new ethers.providers.JsonRpcProvider(url); // v5!
| Error | Cause | Fix |
| --------------------------------- | -------------------- | ----------------------------------- |
| Insufficient balance | Main account empty | broker.ledger.depositFund(amount) |
| Not enough funds in sub-account | Sub-account empty | broker.ledger.transferFund() |
| Refund still locked | 24h lock not expired | Wait for lock period |
| Provider not acknowledged | First-time provider | acknowledgeProviderSigner() |
development
# Upload File to 0G Storage ## Metadata - **Category**: storage - **SDK**: `@0glabs/0g-ts-sdk` ^0.3.3, `ethers` ^6.13.0 - **Activation Triggers**: "upload file", "store on 0G", "ZgFile", "save to storage" ## Purpose Upload files to 0G decentralized storage using the ZgFile API and Indexer. Files are split into chunks, organized as a Merkle tree, and distributed across storage nodes. Returns a root hash for later retrieval. ## Prerequisites - Node.js >= 18 - `@0glabs/0g-ts-sdk` and `ethers`
development
# Merkle Verification ## Metadata - **Category**: storage - **SDK**: `@0glabs/0g-ts-sdk` ^0.3.3 - **Activation Triggers**: "verify file", "merkle proof", "data integrity", "root hash", "check file" ## Purpose Compute root hashes and verify data integrity for files stored on 0G Storage. Uses Merkle tree proofs to cryptographically verify that downloaded data matches what was originally uploaded. ## Prerequisites - Node.js >= 18 - `@0glabs/0g-ts-sdk` installed ## Quick Workflow 1. Create
development
# Download File from 0G Storage ## Metadata - **Category**: storage - **SDK**: `@0glabs/0g-ts-sdk` ^0.3.3, `ethers` ^6.13.0 - **Activation Triggers**: "download file", "retrieve from 0G", "get file", "fetch from storage" ## Purpose Download and verify files from 0G decentralized storage using a root hash. Supports verified downloads with Merkle proof validation to ensure data integrity. ## Prerequisites - Node.js >= 18 - `@0glabs/0g-ts-sdk` installed - Root hash of the file to download - `
development
# Storage + Chain Integration ## Metadata - **Category**: cross-layer - **SDK**: `@0glabs/0g-ts-sdk` ^0.3.3, `ethers` ^6.13.0 - **Activation Triggers**: "on-chain reference", "NFT metadata on 0G", "store hash on-chain", "registry contract", "chain and storage" ## Purpose Combine 0G Storage with 0G Chain smart contracts to create on-chain references to off-chain data. Common patterns include NFT metadata storage, content registries, and verifiable document systems. ## Prerequisites - Node