VeilPay Agent Skill
VeilPay enables fully private payments on Solana mainnet. The sender and recipient are never linked on-chain — a Groth16 ZK proof breaks any cryptographic connection between deposit and withdrawal.
⚠️ Full Runtime Preparation — Run Before Any Script
Never assume the environment is ready. ZK-SNARK skills have complex peer dependencies, binary requirements, and browser-vs-Node.js conflicts that must be resolved before first execution.
Phase 1: Dependency Installation
bash
cd <skill-directory>
rm -rf node_modules # clean slate avoids partial-install conflicts
npm install --legacy-peer-deps
is
required — the Umbra SDK and the ZK prover have conflicting peer dependency requirements. Standard
fails.
is pinned to — do not upgrade it. After v4, bs58 changed its export structure. Higher versions silently break scripts with
TypeError: bs58.encode is not a function
.
Phase 2: Smoke Test
Verify critical runtime dependencies before running any command:
bash
node -e "require('snarkjs'); require('bs58'); console.log('Runtime Ready')"
Phase 3: Reliability & Troubleshooting
- Authorization Format: VeilPay servers require "Shielded UTXO" (Receiver-Claimable) payments. generates a 3-part header:
X-402-Payment: x402 <proofAccountSig>:<utxoSig>:<invoiceId>
.
- SDK Response Mapping: The script correctly maps
createProofAccountSignature
and from the Umbra SDK to the authorization header.
- Indexer Lag: Shielded transactions are not immediately visible to the Umbra indexer. includes a mandatory 15-second sleep after broadcast to ensure the server can verify the payment on-chain.
- Mainnet-only: All scripts default to Solana mainnet. Use only for development — devnet SOL and token accounts are not real.
Command Reference
Create Agent Wallet
Generates a new Solana keypair and stores it at
.
bash
node scripts/wallet.cjs create
Perform Shielded x402 Payment
Fulfills an x402 invoice by depositing into the Umbra Shielded Pool.
Supports SOL, USDC, USDT, UMBRA, and CASH.
Note: Includes a mandatory 15-second wait for indexer sync.
⚠️ STRICT POLICY FOR x402 PAYMENTS:
- ONLY use . NEVER use (confidential transfer) for x402 invoices.
- DOUBLE BILLING PROTECTION: The script caches successful payments in . If you provide the same , it will return the cached header without billing you again.
- ERROR HANDLING: If a payment script fails with a technical error (RPC timeout, network issue), DO NOT RETRY AUTOMATICALLY.
- First, check to see if a record was created.
- If no record exists but you suspect funds were moved, ASK THE USER TO CONFIRM before retrying.
- If the server rejects a proof that was already paid (and is in the ledger), DO NOT RE-PAY. Share the transaction IDs from the ledger with the user.
bash
# invoice_json: The "invoice" object from a 402 response
node scripts/pay-invoice.cjs '<invoice_json>'
Create Private Payment Link
Generates a shareable ZK-shielded payment URL. Supports SOL, USDC, USDT, UMBRA, CASH.
bash
node scripts/create-link.cjs --amount 0.5 --token SOL
node scripts/create-link.cjs --amount 1.00 --token USDC
Claim Private Payment Link
Autonomously claims funds from a link into the agent's wallet.
bash
node scripts/claim-link.cjs --link "<url>"
Withdraw Encrypted Balance
Moves funds from the agent's shielded vault to its public wallet.
bash
# Withdraw specific amount
node scripts/withdraw.cjs --token SOL --amount 0.1
# Withdraw full balance
node scripts/withdraw.cjs --token SOL --all
Query Premium Data (x402)
Fetches system-wide data from the VeilPay API by fulfilling a shielded payment challenge.
bash
# Query links table
node scripts/premium.cjs --table links
# Query merchant requests
node scripts/premium.cjs --table merchant-requests
# Query payment history
node scripts/premium.cjs --table payments
Flawless Agent Checklist
□ Is snarkjs installed? node -e "require('snarkjs')"
□ Is bs58 version 4.0.1? node -e "console.log(require('bs58/package.json').version)"
□ Is wallet.json in base64? node scripts/wallet.cjs show
□ Is SOL balance ≥ 0.05? node scripts/wallet.cjs balance
□ Is indexer sync wait active? (Default in pay-invoice.cjs)
□ Correct network (mainnet)? Scripts default to mainnet; use --network devnet only for dev