Work with Salt SDK for MPC-orchestrated blockchain transactions. Use when handling Salt SDK operations, MPC wallets, Salt accounts, blockchain transactions via Salt orchestration, account creation participation, organization invitations, or debugging Salt transaction states (propose/sign/combine/broadcast). Critical for understanding two-network model (orchestration vs destination chain) and account identity (address vs publicKey).
CRITICAL: You need a wallet to interact with Salt. Before using any Salt commands:
Look for wallet configuration at one of these locations:
~/.openclaw/workspace/.agent-wallet.json.agent-wallet.json~/.salt-cli.jsonconst { ethers } = require('ethers');
const fs = require('fs');
// Generate new wallet
const wallet = ethers.Wallet.createRandom();
// Save configuration
const config = {
privateKey: wallet.privateKey,
address: wallet.address,
mnemonic: wallet.mnemonic.phrase
};
fs.writeFileSync('.agent-wallet.json', JSON.stringify(config, null, 2));
console.log('✅ Wallet created!');
console.log('Address:', wallet.address);
console.log('⚠️ SAVE YOUR MNEMONIC SECURELY!');
console.log('Mnemonic:', wallet.mnemonic.phrase);
IMPORTANT:
Testnet (Arbitrum Sepolia):
Mainnet (Arbitrum One):
Salt is an MPC orchestration system that coordinates distributed signing across multiple parties. Before using Salt, understand these non-negotiable concepts:
Every Salt transaction touches two networks:
Orchestration chain (from Salt({ environment })):
Destination chain (from submitTx({ chainId })):
Critical rule: Signer chain MUST match orchestration chain, NOT destination chain.
Salt accounts have two addresses - never confuse them:
account.address = vault/orchestration contract (internal coordination)account.publicKey = external receiving address (use this for receiving funds)For native token transfers:
'0.1', '1.5'For ERC20 transfers:
value: '0'const { Salt } = require('salt-sdk');
const { ethers } = require('ethers');
// 1. Setup
const provider = new ethers.providers.JsonRpcProvider(RPC_URL);
const signer = new ethers.Wallet(PRIVATE_KEY, provider);
// 2. Authenticate
const salt = new Salt({ environment: 'TESTNET' }); // or 'MAINNET'
await salt.authenticate(signer);
// 3. Get account
const orgs = await salt.getOrganisations();
const accounts = await salt.getAccounts(orgs[0]._id);
const account = accounts[0];
// 4. Submit transaction
const tx = await salt.submitTx({
accountId: account.id,
to: recipientAddress,
value: '0.01', // decimal string for native transfers
chainId: 421614, // destination chain
data: '0x',
signer: signer // MUST match orchestration chain
});
// 5. Wait for completion (ALWAYS!)
const result = await tx.wait();
console.log('State:', result.state); // 'success' or 'failure'
// 6. Extract transaction hash
const txHash = result.broadcastReceipt?.transactionHash;
const { invitations } = await salt.getOrganisationsInvitations();
for (const inv of invitations) {
await salt.acceptOrganisationInvitation(inv._id); // note: _id not id
}
const listener = await salt.listenToAccountNudges(signer);
// Monitor queue
setInterval(() => {
const queue = listener.getNudgeQueue();
const processing = listener.getIsProcessingNudge();
console.log('Pending:', queue.length, 'Processing:', processing);
}, 5000);
const { ethers } = require('ethers');
const erc20Abi = ['function transfer(address to, uint256 amount)'];
const iface = new ethers.utils.Interface(erc20Abi);
const amount = ethers.utils.parseUnits('10', 6); // 10 USDC (6 decimals)
const data = iface.encodeFunctionData('transfer', [recipient, amount]);
await salt.submitTx({
accountId,
to: tokenContractAddress,
value: '0', // MUST be '0' for ERC20
chainId: 421614,
data: data,
signer: signer
});
const tx = await salt.submitTx({
accountId,
to: null, // null for contract creation
value: '0',
chainId: 421614,
data: compiledBytecode,
signer: signer
});
const result = await tx.wait();
const contractAddress = result.broadcastReceipt?.contractAddress;
authenticate(signer) - Authenticate with SaltgetOrganisations() - List your organizationsgetAccounts(orgId) - List accounts in orggetAccount(accountId) - Get specific account detailssubmitTx(params) - Submit transaction (returns Transaction object)listenToAccountNudges(signer) - Participate in account creationgetOrganisationsInvitations() - Check pending invitationsacceptOrganisationInvitation(invitationId) - Accept invitationDo:
await tx.wait() before reporting resultsaccount.publicKey for receiving funds'0.1')Don't:
account.address as receiving addresssubmitTx() return value is final result0x0000...) for contract deployment.wait() callPROPOSE → SIGN → COMBINE → BROADCAST → SUCCESS / FAILURE
All states are lowercase strings. Always check result.state === 'success'.
A command-line tool for both humans and agents. Agents: read CLI_PATTERNS.md to interpret natural language requests.
salt status - Check Salt status: view invites, organizations, accounts, and balances
salt status -t # testnet
salt status -m # mainnet
salt submit - Universal transaction command
# Native send
salt submit --to 0x123... --value 0.01 -t
# ERC20/Contract call
salt submit --to 0xToken... --value 0 --data 0x... -t
# Deploy contract
salt submit --deploy --data 0x<bytecode> -t
salt invites - Manage invitations
salt invites list -t
salt invites accept --id <id> -t
salt invites accept-all -t
salt listen - Start nudge listener
salt listen -t # start listener
salt stop -t # stop listener
salt -help - Show all commands
Pre-built automation scripts for common DeFi workflows. These run as background processes and handle repetitive tasks automatically.
Monitors a Salt account for token deposits and automatically sweeps them into DeFi protocols (Aave, Compound, Uniswap, etc.).
Features:
Quick Start:
# Works from anywhere - uses relative paths to skill dependencies
SWEEPER=~/.openclaw/workspace/skills/salt-sdk/strategies/token-sweeper/sweeper.js
# Initialize config
node $SWEEPER --init
# Or use a template
cp ~/.openclaw/workspace/skills/salt-sdk/strategies/token-sweeper/protocols/aave-v3-arb-sepolia.json config.json
# Edit with your details
nano config.json
# Run sweeper
nohup node $SWEEPER > sweeper.log 2>&1 &
# Check status
node $SWEEPER --report
# Stop
node $SWEEPER --stop
Example Use Cases:
See strategies/token-sweeper/README.md for full documentation and protocol examples.
For complete troubleshooting, API details, and advanced patterns:
Read these as needed for complex scenarios or debugging.