
Veil
- 14 installs
- 1.2k repo stars
- Updated August 1, 2026
- bankrbot/moltbot-skills
Veil is a Claude Code skill for privacy and shielded transactions on Base via Veil Cash, letting an agent deposit, withdraw and transfer ETH or USDC privately using ZK proofs.
About
Veil is a Claude skill for private, shielded transactions on Base using Veil Cash. An agent uses it to deposit ETH or USDC into private pools and then withdraw or transfer funds privately with zero-knowledge proofs, plus manage Veil keypairs and check private and queue balances. It wraps the @veil-cash/sdk CLI and submits deposits through the Bankr signing API.
- Private, shielded ETH and USDC transactions on Base via Veil Cash
- Deposit, withdraw, transfer and merge using ZK proofs
- Wraps the @veil-cash/sdk CLI and signs deposits via Bankr
Veil by the numbers
- 14 all-time installs (skills.sh)
- Ranked #280 of 479 Web3 & Blockchain skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
veil capabilities & compatibility
- Capabilities
- private transfer · shielded deposit · zk privacy
- Works with
- openai
- Use cases
- security audit
- Runs
- Runs locally
- Pricing
- Bring your own API key
What veil says it does
This skill wraps the `@veil-cash/sdk` CLI to make Veil operations agent-friendly.
npx skills add https://github.com/bankrbot/moltbot-skills --skill veilAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 14 |
|---|---|
| repo stars | ★ 1.2k |
| Last updated | August 1, 2026 |
| Repository | bankrbot/moltbot-skills ↗ |
What it does
Make anonymous, ZK-shielded ETH or USDC deposits, withdrawals and transfers on Base from an agent.
Who is it for?
Anonymous or private transfers and ZK-based shielded balances on Base.
Skip if: Assets other than ETH and USDC, or chains other than Base.
When should I use this skill?
The user wants anonymous or private transactions, shielded transfers, or ZK-based privacy on Base.
What you get
Shielded deposits and private withdrawals or transfers executed with ZK proofs.
- Veil keypair
- Shielded deposit
- Private withdrawal or transfer
By the numbers
- Supports 2 assets (ETH, USDC)
- 11-step quick start
Files
Veil
This skill wraps the @veil-cash/sdk CLI to make Veil operations agent-friendly.
Supported Assets
| Asset | Decimals | Description |
|---|---|---|
| ETH | 18 | Native ETH (via WETH) |
| USDC | 6 | USDC on Base |
What it does
- Key management: generate and store a Veil keypair locally
- Status check: verify configuration, registration, and relay health
- Balances:
veil balance(queue + private) — supports--pool eth|usdc - Deposits via Bankr: build Bankr-compatible unsigned transactions and ask Bankr to sign & submit (handles ERC20 approve + deposit for USDC)
- Private actions:
withdraw,transfer,mergefor ETH or USDC — executed locally usingVEIL_KEY(ZK/proof flow)
File locations (recommended)
- Veil keys:
~/.clawdbot/skills/veil/.env.veil(chmod 600) - Bankr API key:
~/.clawdbot/skills/bankr/config.json
Quick start
1) Install the Veil SDK
Option A: Global npm install (recommended)
npm install -g @veil-cash/sdkOption B: Clone from GitHub
mkdir -p ~/.openclaw/workspace/repos
cd ~/.openclaw/workspace/repos
git clone https://github.com/veildotcash/veildotcash-sdk.git
cd veildotcash-sdk
npm ci && npm run build2) Configure Base RPC (recommended)
Veil queries a lot of blockchain data (UTXOs, merkle proofs, etc.), so public RPCs will likely hit rate limits. A dedicated RPC from Alchemy, Infura, or similar is recommended.
Put RPC_URL=... in one of these:
~/.clawdbot/skills/veil/.env(preferred)- or the SDK repo
.env(less ideal)
Example:
mkdir -p ~/.clawdbot/skills/veil
cat > ~/.clawdbot/skills/veil/.env << 'EOF'
RPC_URL=https://base-mainnet.g.alchemy.com/v2/YOUR_KEY
EOF
chmod 600 ~/.clawdbot/skills/veil/.env3) Make scripts executable
chmod +x scripts/*.sh4) Generate your Veil keypair
scripts/veil-init.sh
scripts/veil-keypair.sh5) Check your setup
scripts/veil-status.sh6) Find your Bankr Base address
scripts/veil-bankr-prompt.sh "What is my Base wallet address? Respond with just the address."7) Check balances
# ETH pool (default)
scripts/veil-balance.sh --address 0xYOUR_BANKR_ADDRESS
# USDC pool
scripts/veil-balance.sh --address 0xYOUR_BANKR_ADDRESS --pool usdc8) Deposit via Bankr (sign & submit)
# Deposit ETH
scripts/veil-deposit-via-bankr.sh ETH 0.011 --address 0xYOUR_BANKR_ADDRESS
# Deposit USDC (auto-handles approve + deposit)
scripts/veil-deposit-via-bankr.sh USDC 100 --address 0xYOUR_BANKR_ADDRESS9) Withdraw (private to public)
scripts/veil-withdraw.sh ETH 0.007 0xYOUR_BANKR_ADDRESS
scripts/veil-withdraw.sh USDC 50 0xRECIPIENT10) Transfer privately
scripts/veil-transfer.sh ETH 0.01 0xRECIPIENT
scripts/veil-transfer.sh USDC 25 0xRECIPIENT11) Merge UTXOs
scripts/veil-merge.sh ETH 0.1
scripts/veil-merge.sh USDC 100References
- SDK Reference — CLI commands, environment variables, error codes
- Troubleshooting — Common issues and debugging tips
Notes
- For Bankr signing, this skill uses Bankr's Agent API via your local
~/.clawdbot/skills/bankr/config.json. - For USDC deposits via Bankr, the skill automatically submits the ERC20 approval transaction first, then the deposit transaction.
- For privacy safety: never commit
.env.veilor.envfiles to git.
Veil skill
Wraps the @veil-cash/sdk CLI and optionally uses Bankr Agent API to sign & submit unsigned deposit/register transactions. Supports ETH and USDC privacy pools on Base.
Assumptions
- Veil SDK is installed via one of these methods:
Option A: Global npm install (recommended)
npm install -g @veil-cash/sdkThis makes the veil CLI available globally.
Option B: Clone from GitHub
mkdir -p ~/.openclaw/workspace/repos
cd ~/.openclaw/workspace/repos
git clone https://github.com/veildotcash/veildotcash-sdk.git
cd veildotcash-sdk
npm ci && npm run build- Bankr skill is configured:
~/.clawdbot/skills/bankr/config.json
- Veil secrets are stored outside git:
~/.clawdbot/skills/veil/.env.veil(chmod 600)~/.clawdbot/skills/veil/.envforRPC_URL(recommended — Veil queries a lot of blockchain data, so public RPCs will likely hit rate limits)
Usage
cd veil
# Generate keypair
scripts/veil-init.sh
# Print keypair JSON
scripts/veil-keypair.sh
# Ask Bankr for address
scripts/veil-bankr-prompt.sh "What is my Base wallet address? Respond with just the address."
# Check balances (ETH pool — default)
scripts/veil-balance.sh --address 0x...
# Check balances (USDC pool)
scripts/veil-balance.sh --address 0x... --pool usdc
# Deposit via Bankr — ETH (build unsigned tx + submit)
scripts/veil-deposit-via-bankr.sh ETH 0.011 --address 0x...
# Deposit via Bankr — USDC (auto-handles approve + deposit)
scripts/veil-deposit-via-bankr.sh USDC 100 --address 0x...
# Withdraw / transfer / merge (local VEIL_KEY required)
scripts/veil-withdraw.sh ETH 0.007 0x...
scripts/veil-withdraw.sh USDC 50 0x...
scripts/veil-transfer.sh ETH 0.001 0x...
scripts/veil-transfer.sh USDC 25 0x...
scripts/veil-merge.sh ETH 0.001
scripts/veil-merge.sh USDC 100Notes
veil-bankr-prompt.shimplements the same submit/poll loop as the Bankr skill, but localized here so this skill is self-contained.- For USDC deposits via Bankr,
veil-deposit-via-bankr.shautomatically submits the ERC20 approval transaction first, then the deposit transaction. - All action scripts take asset as the first argument:
ETHorUSDC.
Veil SDK Reference
Full documentation: https://github.com/veildotcash/veildotcash-sdk
Installation
npm install -g @veil-cash/sdk
# or local: npm install @veil-cash/sdk (yarn/pnpm equivalent)Supported Assets
| Asset | Decimals | Token Contract |
|---|---|---|
| ETH | 18 | Native ETH (via WETH) |
| USDC | 6 | 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 |
CLI Commands
veil init
Generate a new Veil keypair.
# Recommended for Bankr: derive from a pre-computed EIP-191 signature
veil init --json --signature 0x...
# Derive from wallet key (same keypair as frontend login)
veil init --json --sign-message --wallet-key 0x...
# Random keypair (no wallet derivation)
veil init --json
# Other options
veil init # Interactive, saves to .env.veil
veil init --force # Overwrite existing without prompting
veil init --no-save # Print keypair without savingJSON output:
{
"veilKey": "0x...",
"veilPrivateKey": "0x...",
"depositKey": "0x...",
"derivation": "provided-signature"
}derivation can be: "wallet-signature", "provided-signature", or "random".
Note on key field names:veilKeyandveilPrivateKeyare the same value (the Veil private key). Both are included for backward compatibility;veil keypairusesveilPrivateKey. Scripts should preferveilPrivateKeywith a fallback:.veilPrivateKey // .veilKey.
veil keypair
Show current Veil keypair as JSON (from VEIL_KEY env).
veil keypair
# {"veilPrivateKey":"0x...","depositKey":"0x..."}veil status
Check configuration and service status.
veil statusOutput:
{
"walletKey": { "found": true, "address": "0x..." },
"veilKey": { "found": true },
"depositKey": { "found": true, "key": "0x1234...abcd" },
"rpcUrl": { "found": false, "url": "https://mainnet.base.org" },
"registration": {
"checked": true,
"registered": true,
"matches": true,
"onChainKey": "0x..."
},
"relay": {
"checked": true,
"healthy": true,
"status": "ok",
"network": "mainnet"
}
}veil register
Register or update your deposit key on-chain.
veil register # Register (first time)
veil register --json # JSON output
veil register --unsigned --address 0x... # Unsigned payload for agents
# Change deposit key (if already registered with a different key)
veil register --force # Change to local deposit key
veil register --force --unsigned # Unsigned change payload for agentsIf already registered with the same key, the command exits successfully. If registered with a different key (e.g. after veil init --sign-message), use --force to update it on-chain.
veil deposit <asset> <amount>
Deposit ETH or USDC into the privacy pool. For USDC, the CLI automatically handles ERC20 approval before depositing.
veil deposit ETH 0.1 # Deposit ETH
veil deposit USDC 100 # Approve + deposit USDC
veil deposit ETH 0.1 --unsigned # Unsigned payload for agents
veil deposit USDC 100 --unsigned # Unsigned: outputs [approve, deposit] array
veil deposit ETH 0.1 --quiet # Suppress progress outputOutput (signed mode):
{
"success": true,
"hash": "0x...",
"asset": "ETH",
"amount": "0.1",
"blockNumber": "12345678",
"gasUsed": "150000"
}Output (--unsigned, ETH — single object):
{
"step": "deposit",
"to": "0x...",
"data": "0x...",
"value": "100000000000000000",
"chainId": 8453
}Output (--unsigned, USDC — array):
[
{
"step": "approve",
"to": "0x...",
"data": "0x...",
"value": "0",
"chainId": 8453
},
{
"step": "deposit",
"to": "0x...",
"data": "0x...",
"value": "0",
"chainId": 8453
}
]veil balance
Show both queue and private balances.
veil balance # All pools (default)
veil balance --pool eth # ETH pool only
veil balance --pool usdc # USDC pool only
veil balance --quiet # Suppress progress outputOutput:
{
"address": "0x...",
"pool": "ETH",
"symbol": "ETH",
"depositKey": "0x...",
"totalBalance": "0.15",
"totalBalanceWei": "150000000000000000",
"private": {
"balance": "0.10",
"balanceWei": "100000000000000000",
"utxoCount": 2,
"utxos": [
{ "index": 5, "amount": "0.05" },
{ "index": 8, "amount": "0.05" }
]
},
"queue": {
"balance": "0.05",
"balanceWei": "50000000000000000",
"count": 1,
"deposits": [
{ "nonce": 42, "amount": "0.05", "status": "pending" }
]
}
}veil withdraw <asset> <amount> <recipient>
Withdraw from the privacy pool to any public address.
veil withdraw ETH 0.05 0xRecipientAddress
veil withdraw USDC 50 0xRecipientAddress
veil withdraw ETH 0.05 0xRecipientAddress --quietOutput:
{
"success": true,
"transactionHash": "0x...",
"blockNumber": 12345678,
"asset": "ETH",
"amount": "0.05",
"recipient": "0x..."
}veil transfer <asset> <amount> <recipient>
Transfer privately to another registered Veil user.
veil transfer ETH 0.02 0xRecipientAddress
veil transfer USDC 25 0xRecipientAddress
veil transfer ETH 0.02 0xRecipientAddress --quietOutput:
{
"success": true,
"transactionHash": "0x...",
"blockNumber": 12345678,
"asset": "ETH",
"amount": "0.02",
"recipient": "0x...",
"type": "transfer"
}veil merge <asset> <amount>
Consolidate multiple small UTXOs into one (self-transfer).
veil merge ETH 0.1
veil merge USDC 100
veil merge ETH 0.1 --quietOutput:
{
"success": true,
"transactionHash": "0x...",
"blockNumber": 12345678,
"asset": "ETH",
"amount": "0.1",
"type": "merge"
}Environment Variables
The CLI uses two config files:
| File | Purpose |
|---|---|
.env.veil | Veil keypair (VEIL_KEY, DEPOSIT_KEY) — created by veil init |
.env | Wallet config (WALLET_KEY, RPC_URL) — your existing config |
| Variable | Description |
|---|---|
| VEIL_KEY | Your Veil private key (for ZK proofs, withdrawals, transfers) |
| DEPOSIT_KEY | Your Veil deposit key (public, for register/deposit) |
| WALLET_KEY | Ethereum wallet private key (for signing transactions) |
| RPC_URL | Base RPC URL (optional, defaults to public RPC) |
Error Handling
Commands that fail output JSON with standardized error codes:
{
"success": false,
"errorCode": "VEIL_KEY_MISSING",
"error": "VEIL_KEY required. Use --veil-key or set VEIL_KEY env"
}Error Codes
| Code | Description |
|---|---|
| VEIL_KEY_MISSING | VEIL_KEY not provided |
| WALLET_KEY_MISSING | WALLET_KEY not provided |
| DEPOSIT_KEY_MISSING | DEPOSIT_KEY not provided |
| INVALID_ADDRESS | Invalid Ethereum address format |
| INVALID_AMOUNT | Invalid or below minimum amount |
| INSUFFICIENT_BALANCE | Not enough ETH balance |
| USER_NOT_REGISTERED | Recipient not registered in Veil |
| NO_UTXOS | No unspent UTXOs available |
| RELAY_ERROR | Error from relayer service |
| RPC_ERROR | RPC/network error |
| CONTRACT_ERROR | Smart contract reverted |
| UNKNOWN_ERROR | Unexpected error |
For AI Agents
All commands output JSON and support non-interactive usage.
Key initialization (recommended: Bankr signature flow)
# 1. Get a personal_sign signature from Bankr's /agent/sign endpoint
# (sign the VEIL_SIGNED_MESSAGE constant)
# 2. Derive keypair from that signature
veil init --json --signature 0x<BANKR_SIGNATURE>
# Returns: { "veilKey": "0x...", "veilPrivateKey": "0x...", "depositKey": "0x...", "derivation": "provided-signature" }
# Fallback: random keypair (no wallet derivation)
veil init --jsonParse the private key defensively: .veilPrivateKey // .veilKey
Unsigned transaction payloads
veil register --unsigned --address 0x...
veil deposit ETH 0.1 --unsigned
veil deposit USDC 100 --unsigned # Outputs [approve, deposit] arrayUse --unsigned to get Bankr-compatible transaction payloads:
veil deposit ETH 0.1 --unsigned
# {"step":"deposit","to":"0x...","data":"0x...","value":"100000000000000000","chainId":8453}
veil deposit USDC 100 --unsigned
# [{"step":"approve","to":"0x...","data":"0x...","value":"0","chainId":8453},{"step":"deposit","to":"0x...","data":"0x...","value":"0","chainId":8453}]Querying
veil balance --quiet
veil balance --pool usdc --quiet
veil withdraw ETH 0.05 0xRecipient --quietUse --quiet to suppress progress output for clean JSON parsing.
Troubleshooting
Common Issues
RPC Rate Limits
Symptom: Requests failing, slow responses, or "rate limit exceeded" errors.
Cause: Veil queries a lot of blockchain data (UTXOs, merkle proofs, deposit queues). Public RPCs have strict rate limits.
Solution: Use a dedicated RPC from Alchemy, Infura, or similar:
mkdir -p ~/.clawdbot/skills/veil
echo "RPC_URL=https://base-mainnet.g.alchemy.com/v2/YOUR_KEY" > ~/.clawdbot/skills/veil/.env
chmod 600 ~/.clawdbot/skills/veil/.envVEIL_KEY_MISSING
Symptom: Error VEIL_KEY required
Solution: Run veil init to generate a keypair, or ensure your .env.veil file exists:
scripts/veil-init.shUSER_NOT_REGISTERED
Symptom: Transfer fails with "recipient not registered"
Cause: The recipient address hasn't registered their deposit key with Veil.
Solution: The recipient must run veil register before they can receive private transfers.
NO_UTXOS
Symptom: Withdraw/transfer fails with "no UTXOs available"
Cause: Your deposits are still in the queue (pending) and haven't been processed into the privacy pool yet.
Solution: Wait for the Veil deposit engine to process your deposits. Check status with:
scripts/veil-balance.sh --address 0xYOUR_ADDRESS
scripts/veil-balance.sh --address 0xYOUR_ADDRESS --pool usdcLook at the queue vs private balances in the output.
INSUFFICIENT_BALANCE
Symptom: Transaction fails due to insufficient balance
Solution: Check your balances and ensure you have enough in the private pool (not just the queue):
scripts/veil-balance.sh --address 0xYOUR_ADDRESS
scripts/veil-balance.sh --address 0xYOUR_ADDRESS --pool usdcERC20 Approval Failures (USDC)
Symptom: USDC deposit fails at the approval step.
Cause: The wallet may not have enough USDC balance, or there may be an existing allowance conflict.
Solution: 1. Verify you have sufficient token balance in your Bankr wallet. 2. If depositing via Bankr, the veil-deposit-via-bankr.sh script automatically sends the approval transaction first. Ensure the first (approve) transaction completes before the second (deposit) is submitted. 3. If using --unsigned directly, note that USDC returns a JSON array of two transactions — submit the step: "approve" tx first, wait for confirmation, then submit the step: "deposit" tx.
Wrong Pool / Asset Mismatch
Symptom: Balance shows zero but you know you deposited.
Cause: You may be checking the wrong pool. ETH deposits go to the ETH pool, USDC to the USDC pool, etc.
Solution: Specify the correct pool:
scripts/veil-balance.sh --address 0xYOUR_ADDRESS --pool usdcBankr API Errors
Symptom: apiKey missing or authentication errors
Solution: Ensure Bankr is configured:
cat ~/.clawdbot/skills/bankr/config.json
# Should contain: {"apiKey": "bk_...", "apiUrl": "https://api.bankr.bot"}Scripts Not Executable
Symptom: Permission denied when running scripts
Solution:
chmod +x scripts/*.shDebugging Tips
1. Check balances first — Most issues stem from funds being in queue vs private pool 2. Check the right pool — Use --pool usdc to check USDC balances 3. Use `--quiet` flag — Suppresses progress output for cleaner JSON parsing 4. Check Bankr job status — If a deposit via Bankr hangs, the job ID is printed for manual status checks 5. Verify RPC connectivity — curl -s YOUR_RPC_URL -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' 6. ERC20 deposits need two txs — For USDC, ensure the approval tx confirms before the deposit tx is submitted
Getting Help
- Veil SDK: https://github.com/veildotcash/veildotcash-sdk
- Bankr: https://bankr.bot
#!/usr/bin/env bash
set -euo pipefail
# Paths
OPENCLAW_WORKSPACE_DEFAULT="$HOME/.openclaw/workspace"
OPENCLAW_WORKSPACE="${OPENCLAW_WORKSPACE:-$OPENCLAW_WORKSPACE_DEFAULT}"
SDK_REPO="${VEIL_SDK_REPO:-$OPENCLAW_WORKSPACE/repos/veildotcash-sdk}"
VEIL_DIR="$HOME/.clawdbot/skills/veil"
VEIL_ENV="$VEIL_DIR/.env.veil"
VEIL_ENV_EXTRA="$VEIL_DIR/.env" # optional (RPC_URL, etc)
BANKR_CONFIG="${BANKR_CONFIG:-$HOME/.clawdbot/skills/bankr/config.json}"
need_bin() {
command -v "$1" >/dev/null 2>&1 || { echo "Missing required binary: $1" >&2; exit 1; }
}
# Check if global veil CLI is available (npm install -g @veil-cash/sdk)
has_global_veil() {
command -v veil >/dev/null 2>&1
}
# Check if local SDK repo exists and is built
has_local_sdk() {
[[ -d "$SDK_REPO" ]] && [[ -f "$SDK_REPO/dist/cli/index.cjs" ]]
}
ensure_sdk() {
if has_global_veil || has_local_sdk; then
return 0
fi
echo "Veil SDK not found. Install via one of:" >&2
echo " npm install -g @veil-cash/sdk" >&2
echo " OR clone & build: https://github.com/veildotcash/veildotcash-sdk" >&2
exit 1
}
load_envs() {
# Export variables from env files if present
set -a
[[ -f "$VEIL_ENV" ]] && source "$VEIL_ENV"
[[ -f "$VEIL_ENV_EXTRA" ]] && source "$VEIL_ENV_EXTRA"
set +a
}
veil_cli() {
ensure_sdk
load_envs
# Prefer global veil CLI, fall back to local SDK repo
if has_global_veil; then
veil "$@"
else
node "$SDK_REPO/dist/cli/index.cjs" "$@"
fi
}
ensure_veil_dir() {
mkdir -p "$VEIL_DIR"
chmod 700 "$VEIL_DIR" 2>/dev/null || true
}
ensure_veil_env_perms() {
[[ -f "$VEIL_ENV" ]] && chmod 600 "$VEIL_ENV" 2>/dev/null || true
[[ -f "$VEIL_ENV_EXTRA" ]] && chmod 600 "$VEIL_ENV_EXTRA" 2>/dev/null || true
}
need_bankr() {
# Prefer Bankr CLI
if command -v bankr >/dev/null 2>&1; then
return 0
fi
# Fall back to config file for curl-based scripts
if [[ -f "$BANKR_CONFIG" ]]; then
need_bin jq
need_bin curl
return 0
fi
echo "Bankr CLI not found. Install with: bun install -g @bankr/cli && bankr login" >&2
exit 1
}
# Legacy alias
need_bankr_config() {
need_bankr
}
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/_common.sh"
# Pass-through flags like: --address 0x...
veil_cli balance --quiet "$@"
#!/usr/bin/env bash
# Submit a prompt to Bankr and return the response.
# Delegates to the Bankr CLI when available, falls back to curl.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/_common.sh"
need_bankr
PROMPT="$*"
if [[ -z "$PROMPT" ]]; then
echo "Usage: $0 <prompt>" >&2
exit 1
fi
# CLI path (preferred) — need_bankr already verified one of these is available
if command -v bankr >/dev/null 2>&1; then
exec bankr prompt "$PROMPT"
fi
# Curl fallback — config file was validated by need_bankr
API_KEY=$(jq -r '.apiKey // empty' "$BANKR_CONFIG")
API_URL=$(jq -r '.apiUrl // "https://api.bankr.bot"' "$BANKR_CONFIG")
if [[ -z "$API_KEY" ]]; then
echo "apiKey missing in $BANKR_CONFIG" >&2
exit 1
fi
# Submit
SUBMIT=$(curl -sf -X POST "$API_URL/agent/prompt" \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d "$(jq -nc --arg prompt "$PROMPT" '{prompt: $prompt}')")
JOB_ID=$(echo "$SUBMIT" | jq -r '.jobId // empty')
if [[ -z "$JOB_ID" ]]; then
echo "$SUBMIT" | jq . >&2
echo "Failed to get jobId from Bankr" >&2
exit 1
fi
# Poll
ATTEMPT=0
MAX_ATTEMPTS=150
LAST_STATUS=""
while [[ $ATTEMPT -lt $MAX_ATTEMPTS ]]; do
sleep 2
STATUS=$(curl -sf -X GET "$API_URL/agent/job/$JOB_ID" -H "X-API-Key: $API_KEY") || {
echo "Failed to poll Bankr job status (attempt $((ATTEMPT+1))/$MAX_ATTEMPTS)" >&2
ATTEMPT=$((ATTEMPT+1))
continue
}
LAST_STATUS="$STATUS"
# Validate response is JSON
if ! echo "$STATUS" | jq empty 2>/dev/null; then
echo "Bankr returned non-JSON response: $STATUS" >&2
ATTEMPT=$((ATTEMPT+1))
continue
fi
STATE=$(echo "$STATUS" | jq -r '.status')
case "$STATE" in
completed)
echo "$STATUS" | jq .
exit 0
;;
failed|cancelled)
ERROR_DETAIL=$(echo "$STATUS" | jq -r '.error // .message // .reason // empty')
echo "Bankr job $STATE: $JOB_ID" >&2
[[ -n "$ERROR_DETAIL" ]] && echo "Detail: $ERROR_DETAIL" >&2
echo "$STATUS" | jq . >&2
exit 1
;;
pending|processing)
:
;;
*)
echo "Unexpected Bankr job status '$STATE' for job $JOB_ID" >&2
echo "$STATUS" | jq . >&2
;;
esac
ATTEMPT=$((ATTEMPT+1))
done
echo "Timed out waiting for Bankr job: $JOB_ID (after $MAX_ATTEMPTS attempts)" >&2
if [[ -n "$LAST_STATUS" ]]; then
LAST_STATE=$(echo "$LAST_STATUS" | jq -r '.status // "unknown"')
echo "Last known status: $LAST_STATE" >&2
echo "$LAST_STATUS" | jq . >&2
fi
exit 1
#!/usr/bin/env bash
# Submit an unsigned EVM tx JSON to Bankr for signing+submission.
# Input: JSON on stdin or a file path as $1.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/_common.sh"
need_bankr_config
if [[ $# -gt 0 ]]; then
TX_JSON=$(cat "$1")
else
TX_JSON=$(cat)
fi
# Validate required fields exist
if ! echo "$TX_JSON" | jq -e '.to and .data and .value and .chainId' >/dev/null 2>&1; then
echo "Invalid transaction JSON. Required fields: to, data, value, chainId" >&2
echo "Received: $TX_JSON" >&2
exit 1
fi
PROMPT=$'Submit this transaction (do not change any fields):\n'
PROMPT+="$TX_JSON"
"$SCRIPT_DIR/veil-bankr-prompt.sh" "$PROMPT"
#!/usr/bin/env bash
# Build a Bankr-compatible unsigned deposit tx JSON (no signing).
# Usage: veil-deposit-unsigned.sh <asset> <amount> [extra flags...]
# asset: ETH or USDC
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/_common.sh"
ASSET="${1:?asset required (ETH, USDC)}"
AMOUNT="${2:?amount required}"
shift 2 || true
veil_cli deposit "$ASSET" "$AMOUNT" --unsigned --quiet "$@"
#!/usr/bin/env bash
# Build unsigned deposit tx JSON and submit via Bankr.
# For ETH: single tx. For USDC: approve tx first, then deposit tx.
# Usage: veil-deposit-via-bankr.sh <asset> <amount> [extra flags...]
# asset: ETH or USDC
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/_common.sh"
need_bin jq
ASSET="${1:?asset required (ETH, USDC)}"
AMOUNT="${2:?amount required}"
shift 2 || true
PAYLOAD=$(veil_cli deposit "$ASSET" "$AMOUNT" --unsigned --quiet "$@")
# Validate CLI output is valid JSON
if ! echo "$PAYLOAD" | jq empty 2>/dev/null; then
echo "CLI did not return valid JSON:" >&2
echo "$PAYLOAD" >&2
exit 1
fi
# Check if payload is an array (ERC20: approve + deposit) or single object (ETH)
IS_ARRAY=$(echo "$PAYLOAD" | jq -r 'if type == "array" then "true" else "false" end')
if [[ "$IS_ARRAY" == "true" ]]; then
ARRAY_LEN=$(echo "$PAYLOAD" | jq 'length')
if [[ "$ARRAY_LEN" -ne 2 ]]; then
echo "Expected 2 transactions (approve + deposit), got $ARRAY_LEN" >&2
echo "$PAYLOAD" >&2
exit 1
fi
APPROVE_TX=$(echo "$PAYLOAD" | jq -c '.[0]')
DEPOSIT_TX=$(echo "$PAYLOAD" | jq -c '.[1]')
echo "Submitting approval transaction..." >&2
APPROVE_RESULT=$(echo "$APPROVE_TX" | "$SCRIPT_DIR/veil-bankr-submit-tx.sh") || {
echo "Approval transaction failed" >&2
echo "$APPROVE_RESULT" >&2
exit 1
}
# Validate approval result is JSON
if ! echo "$APPROVE_RESULT" | jq empty 2>/dev/null; then
echo "Approval result is not valid JSON:" >&2
echo "$APPROVE_RESULT" >&2
exit 1
fi
APPROVE_STATUS=$(echo "$APPROVE_RESULT" | jq -r '.status // empty')
if [[ "$APPROVE_STATUS" != "completed" ]]; then
echo "Approval transaction not completed (status: ${APPROVE_STATUS:-unknown})" >&2
ERROR_MSG=$(echo "$APPROVE_RESULT" | jq -r '.error // .message // .reason // empty')
[[ -n "$ERROR_MSG" ]] && echo "Error: $ERROR_MSG" >&2
echo "$APPROVE_RESULT" >&2
exit 1
fi
echo "Submitting deposit transaction..." >&2
echo "$DEPOSIT_TX" | "$SCRIPT_DIR/veil-bankr-submit-tx.sh"
else
# ETH deposit: single tx
echo "$PAYLOAD" | "$SCRIPT_DIR/veil-bankr-submit-tx.sh"
fi
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=_common.sh
source "$SCRIPT_DIR/_common.sh"
need_bin jq
ensure_veil_dir
ensure_sdk
HAS_FORCE=false
for arg in "$@"; do [[ "$arg" == "--force" ]] && HAS_FORCE=true; done
if [[ -f "$VEIL_ENV" ]]; then
echo "Veil env already exists: $VEIL_ENV" >&2
echo "(delete it to regenerate, or pass --force)" >&2
if [[ "$HAS_FORCE" != "true" ]]; then
exit 0
fi
echo "Overwriting (--force)..." >&2
fi
VEIL_SIGNED_MESSAGE="Sign this message to create your Veil Wallet private key. This will be used to decrypt your balances. Ensure you are signing this message on the Veil Cash website."
# Try Bankr signature-based derivation first, fall back to random.
KP_JSON=""
try_bankr_signature() {
local api_key api_url sign_resp sig
# Need Bankr config for the signing API
if ! [[ -f "$BANKR_CONFIG" ]]; then
return 1
fi
api_key=$(jq -r '.apiKey // empty' "$BANKR_CONFIG")
api_url=$(jq -r '.apiUrl // "https://api.bankr.bot"' "$BANKR_CONFIG")
if [[ -z "$api_key" ]]; then
return 1
fi
echo "Requesting wallet signature from Bankr..." >&2
sign_resp=$(curl -sf -X POST "$api_url/agent/sign" \
-H "X-API-Key: $api_key" \
-H "Content-Type: application/json" \
-d "$(jq -nc --arg msg "$VEIL_SIGNED_MESSAGE" '{signatureType: "personal_sign", message: $msg}')" 2>/dev/null) || return 1
sig=$(echo "$sign_resp" | jq -r '.signature // empty' 2>/dev/null)
if [[ -z "$sig" || "$sig" == "null" ]]; then
echo "Bankr signing returned no signature, falling back to random keypair" >&2
return 1
fi
echo "Deriving keypair from Bankr wallet signature..." >&2
KP_JSON=$(veil_cli init --json --signature "$sig" "$@")
}
if ! try_bankr_signature "$@" 2>/dev/null; then
echo "Using random keypair generation..." >&2
KP_JSON=$(veil_cli init --json "$@")
fi
# Validate JSON
if ! echo "$KP_JSON" | jq empty 2>/dev/null; then
echo "CLI did not return valid JSON:" >&2
echo "$KP_JSON" >&2
exit 1
fi
VEIL_KEY=$(echo "$KP_JSON" | jq -r '.veilPrivateKey // .veilKey')
DEPOSIT_KEY=$(echo "$KP_JSON" | jq -r '.depositKey')
if [[ -z "$VEIL_KEY" || "$VEIL_KEY" == "null" ]]; then
echo "Failed to parse private key from CLI output" >&2
echo "$KP_JSON" >&2
exit 1
fi
if [[ -z "$DEPOSIT_KEY" || "$DEPOSIT_KEY" == "null" ]]; then
echo "Failed to parse deposit key from CLI output" >&2
echo "$KP_JSON" >&2
exit 1
fi
cat > "$VEIL_ENV" << EOF
# Veil Cash Configuration
# Generated by: veil-init.sh
VEIL_KEY=$VEIL_KEY
DEPOSIT_KEY=$DEPOSIT_KEY
EOF
chmod 600 "$VEIL_ENV"
echo "Wrote: $VEIL_ENV" >&2
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/_common.sh"
ensure_veil_dir
ensure_veil_env_perms
veil_cli keypair
#!/usr/bin/env bash
# Merge/consolidate UTXOs by self-transfer.
# Usage: veil-merge.sh <asset> <amount>
# asset: ETH or USDC
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/_common.sh"
ASSET="${1:?asset required (ETH, USDC)}"
AMOUNT="${2:?amount required}"
veil_cli merge "$ASSET" "$AMOUNT" --quiet
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/_common.sh"
need_bin jq
# Extract private balance from unified veil balance output
veil_cli balance --quiet "$@" | jq '.private'
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/_common.sh"
need_bin jq
# Extract queue balance from unified veil balance output
veil_cli balance --quiet "$@" | jq '.queue'
#!/usr/bin/env bash
# Check Veil configuration and service status.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/_common.sh"
veil_cli status "$@"
#!/usr/bin/env bash
# Private transfer within the pool to another registered address.
# Usage: veil-transfer.sh <asset> <amount> <recipient>
# asset: ETH or USDC
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/_common.sh"
ASSET="${1:?asset required (ETH, USDC)}"
AMOUNT="${2:?amount required}"
RECIPIENT="${3:?recipient address required}"
veil_cli transfer "$ASSET" "$AMOUNT" "$RECIPIENT" --quiet
#!/usr/bin/env bash
# Withdraw from private pool to a public address (executes locally using VEIL_KEY).
# Usage: veil-withdraw.sh <asset> <amount> <recipient>
# asset: ETH or USDC
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/_common.sh"
ASSET="${1:?asset required (ETH, USDC)}"
AMOUNT="${2:?amount required}"
RECIPIENT="${3:?recipient address required}"
veil_cli withdraw "$ASSET" "$AMOUNT" "$RECIPIENT" --quiet
# Optional Veil skill config (recommended)
# Stored at: ~/.clawdbot/skills/veil/.env
# DO NOT commit this file to version control!
# Base RPC URL
RPC_URL=https://mainnet.base.org
# Veil Cash Configuration
# Stored at: ~/.clawdbot/skills/veil/.env.veil
# DO NOT commit this file to version control!
# Your Veil private key (for ZK proofs, withdrawals, transfers)
VEIL_KEY=0x...
# Your deposit key (public, for register/deposit commands)
DEPOSIT_KEY=0x...
Related skills
FAQ
Which assets does Veil support?
ETH (18 decimals, via WETH) and USDC (6 decimals) on Base.
How are deposits signed?
The skill builds Bankr-compatible unsigned transactions and asks Bankr to sign and submit them.