Using Xome
Private payments.
Payments the public ledger cannot read, and an on-chain limit on what the agent is allowed to spend. Both powered by MagicBlock.
solana_send, solana_swap) are unchanged and still operate on mainnet.Why this exists
A normal Solana transfer is a permanent public record of who paid whom, how much, and when. For an agent that settles invoices or pays people on your behalf, that is a lot to publish. And in a normal setup the only thing standing between the agent and your balance is the approval sheet, which is code running in your own browser.
MagicBlock fixes both. Payments move inside an Ephemeral Rollup whose validator runs in an Intel TDX hardware enclave, so balances and transfers are confidential and readable only by the wallet that owns them. And because writing to that rollup is free and settles in milliseconds, your spending limits can live in a Solana program that every payment must clear first.
What stays private, and what does not
| Action | Visible on the public ledger? |
|---|---|
| Depositing into your private balance | Yes |
| Sending to someone privately | No |
| Swapping with private delivery | The swap, yes. Where the output went, no |
| Your private balance | No, only you can read it |
| Withdrawing back to your wallet | Yes |
So an observer sees you put money in and later take money out. What the agent did in between, and with whom, is not on the ledger.
Getting set up
- 1Connect your walletConnections, then Solana. Private payments use the same embedded wallet.
- 2Set your spend policySettings, then Agent spend policy. Choose a per-payment cap, a daily cap, which tokens are allowed, and an expiry. This creates an account on Solana that only your wallet can change.
- 3Authorize private readsConnections, then MagicBlock, then Authenticate. One signature proves the wallet is yours so the rollup will answer reads of your private balance. It lasts a day, and it is not a payment approval.
- 4Deposit something to spendAsk Xome to deposit, for example “move 50 USDC into my private balance”.
What the agent can do
| Ask | Tool | Approval |
|---|---|---|
| “what's my private balance?” | private_balance | None (read) |
| “what are my spend limits?” | agent_policy_get | None (read) |
| “move 50 USDC into private” | private_deposit | Always asks |
| “pay bob.sol 25 USDC privately” | private_send | Always asks |
| “swap 10 USDC to SOL privately” | private_swap | Always asks |
| “withdraw 40 USDC” | private_withdraw | Always asks |
- Money-moving tools are excluded from “always allow”. They show the approval sheet every time, by design.
private_sendacceptssplit(up to 15 sub-transfers) and a random delay, so a payment can be broken up and its timing blurred when you ask for that.- The agent can read its spend policy. It has no tool that can change one.
The spend policy
Your limits live in xome_agent_policy, a small Anchor program. Before any payment, Xome calls record_spend on it. The program checks every rule and either records the spend or refuses. If it refuses, Xome never builds the payment, so nothing moves.
| Rule | What it does |
|---|---|
| Per-payment cap | Rejects any single payment above the limit |
| Daily cap | Rejects anything that would push the rolling 24 hour total over |
| Allowed tokens | Rejects any mint you did not tick |
| Expiry | Stops the agent spending after a date you choose |
| Pause | Kill switch. Refuses everything, whatever the caps say |
The account also keeps a running count of every payment recorded, which is never reset, so the policy doubles as an audit trail you can read from any block explorer.
Why it is not just a setting in the app
Because a setting in the app is enforced by the same code that asks you for approval. A cap in a program is enforced by Solana. Even if the agent misbehaves, or the page it runs on is tampered with, the chain still says no.
The agent key
When you create a policy, your browser generates a small key and your wallet authorizes it as the agent. That key can do exactly one thing: record a spend against your policy, within limits you set. It cannot move funds and it cannot change limits. You can rotate or revoke it at any time from the policy page, and rotating instantly makes the old key useless.
Free checks, on the rollup
The policy account is delegated to a MagicBlock rollup, so recording a spend takes milliseconds and costs nothing, with no wallet prompt. State commits back to Solana every five minutes. Delegation is optional: without it, the same checks still run, just as ordinary Solana transactions.
Settlement is not instant
A private transfer with a split or a delay settles asynchronously. A confirmed source transaction proves you sent it, not that the recipient has been credited. Xome reports these as pending and returns a clientRefId you can reconcile against, rather than claiming a payment is done when it is not.
Self-hosting
Private payments need the policy program address. The devnet deployment is public, so no deploy of your own is required:
NEXT_PUBLIC_MAGICBLOCK_CLUSTER=devnet NEXT_PUBLIC_XOME_POLICY_PROGRAM_ID=4DmoEYQEhm55f7VgaPdzLnToz2bRjByXYv319RFhVQJw # Optional. The public devnet RPC rate limits hard. SOLANA_DEVNET_RPC_URL=
The program source and its tests live in the xome-contracts workspace. Building it yourself needs Anchor 1.0.2 and the Solana CLI.