MLH: Best use of Solana
Agents pay in USDC on Solana devnet, without ever holding the key
GurtOS gives every box an agent wallet on Solana. When an agent needs a paid API, the box signs an SPL token transfer of devnet USDC from a wallet in its root-only vault, a facilitator pays the network fee and submits it, and the box checks the transaction is confirmed on chain before it records the receipt. Agents only ever see results. All of it is devnet USDC, which has no value.
Proof The wallet's whole history is public on Solana Explorer: one 20 USDC faucet deposit, then 36 x402 payments of $0.01 or $0.03 made by agents on the box, 0.76 USDC in all, every one a finalized SPL TransferChecked whose fee was paid by the facilitator, never by the wallet.
What Solana asked for
MLH's Solana prize asks only that the project uses Solana. Quoted from the project's track plan.
Use Solana in the project.
MetEvery agent payment on the box is an SPL
TransferCheckedof Circle's devnet USDC (mint4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU), signed by the box's wallet through@x402/svm, submitted by a facilitator, and checked for confirmation on devnet before the box logs it.Best use of Solana.
MetSolana's fee-payer model is what lets an agent wallet hold only USDC: the facilitator signs as fee payer, so the box never needs SOL. Cent-sized transfers that settle in about 1.5 s from the 402 to the 200 fit pay-per-call APIs; the box's budget and approval sit on top.
Screenshots


Open it yourself
- The box's agent wallet on Solana ExplorerPublic, no sign-in. Address
6PyiR71c9aw3e8bgnxmcLvJECL5zHE5jMSWqJoVjPTxU; its USDC balance and every transfer. - A $0.03 payment settled by Coinbase's CDP facilitator
- A $0.03 report an agent bought while shopping
- The 20 USDC faucet deposit that funded the wallet
- The wallet track's code and README
- Docs: let agents pay for APIs
Evidence
On chain, checked Oct 23 at 10:40 PM PT. We read the wallet's history from devnet RPC
(getSignaturesForAddress, then getTransaction for each one) and checked every transaction:
| What | Count | Detail |
|---|---|---|
| Faucet deposit | 1 | 20 USDC from Circle's faucet, Oct 23, 6:58 PM PT |
| Agent payments | 36 | $0.01 or $0.03 each to the test API's payee, 0.76 USDC in all, every one finalized |
| Fee paid by the wallet | 0 | Every payment's fee payer is a facilitator account |
| Balance | 19.24 USDC on Oct 24, 12:18 AM PT | Devnet USDC, test money |
A few of them:
| Time (PT, Oct 23) | Amount | What | Transaction |
|---|---|---|---|
| 7:58 PM | $0.03 | A shopping agent buys a report it needs | 5PCwxRVP... |
| 8:26 PM | $0.01 | Wallet live run: a joke, within budget | 423EmHPv... |
| 8:26 PM | $0.03 | Wallet live run: a report, after the owner's OK | Urd99HES... |
| 8:46 PM | $0.03 | The latest payment | 4CyWjmnQ... |
Each payment we opened has four instructions: two Compute Budget instructions, the token program's TransferChecked,
and a Memo with a 32-character nonce. The fee was 0.000010001 SOL in each.
The live merge-gate run, DEMO_LIVE=wallet ./demo, passed on Oct 23 on the x86 and ARM64 test VMs. Its last
checks read the chain:
ok the box's agent wallet 6PyiR71c9aw3e8bgnxmcLvJECL5zHE5jMSWqJoVjPTxU holds 19.65 USDC on Solana devnet (test money)
ok GET /joke answered 402 Payment Required: $0.01 devnet USDC to 39w7W3SB...
ok the wallet paid $0.01 and got the joke: An agent walks into a bar. The bar answers 402.
ok the $0.03 report is over the $0.02 budget, so the task waits: "Spend $0.03 on wallet.pay? Budget $0.02, spent $0.01."
ok approved, it paid $0.03 and got the report
ok both transactions, settled by Coinbase's CDP facilitator, are confirmed on Solana devnet: https://explorer.solana.com/tx/Urd99HES...?cluster=devnet
ok neither the wallet's key nor the CDP secret is anywhere in the task's log
How it works
- TaskAn agent needs a paid APIIt calls
wallet.quoteandwallet.paythrough its broker. No key, no route to the vault. - YouOver budget? Your OKWithin the task's budget it goes straight through. Above it, the task waits for you on the portal or phone.
- GurtOS coreThe box builds the transferAn SPL
TransferCheckedof devnet USDC from its wallet to the payee's token account, at exactly the quoted price, with a random memo nonce. Signed with the key from the vault. - OutsideThe facilitator submits itIt adds its signature as fee payer, pays the fee and sends the transaction to Solana devnet.
- OutsideSolana devnet confirmsThe transaction is finalized. The API gets paid and returns its content.
- GurtOS coreReceipt with an explorer linkThe box records the amount, payee, task and signature in the action log, labelled devnet test money.
- Task
- its own Linux user, its own copy of the files, no keys
- GurtOS core
- the GurtOS service on the box, root, the only part that reads the vault
- Outside
- a service outside the box
- You
- a person, on the portal, a phone, Jira or a chat
Why an agent wallet on Solana can hold only USDC. In an x402 payment on Solana, the facilitator names itself as
the fee payer (extra.feePayer) and signs the transaction as fee payer. The box signs only the token transfer. So the
wallet needs no SOL, which matters for a box running unattended: there is one balance to watch, in dollars.
What the box refuses to sign. The wallet pays only the exact scheme on Solana devnet in devnet USDC, at exactly
the price the agent quoted and the owner saw. It reaches only hosts on the task's list and refuses redirects. Before
signing it writes a durable mark for the call, so a box that loses power mid-payment never pays twice.
Where the key lives. WALLET_SOLANA_KEY is in /etc/box/vault.env, readable by root only. Only the
wallet.pay tool, inside the box's own process, reads it. Tasks run as their own Linux users and get back the
content and a receipt with the signature. The merge gate checks the key is nowhere in the task's log.
Try it
- Make a wallet on a box:
node --experimental-strip-types tracks/wallet/keygen.ts | sudo sh -c 'cat >> /etc/box/vault.env'. It prints the address on stderr. - Fund it at faucet.circle.com: USDC, Solana Devnet, Send 20 USDC. No SOL needed.
- Run
DEMO_LIVE=wallet ./demofrom the repo root. It pays $0.01 and $0.03, waits for an approval on the second, and checks both are confirmed on devnet. - Open the wallet's address on Solana Explorer (devnet) and find the two new transfers.
Live, test and simulated
| Part | State | Details |
|---|---|---|
| Solana transactions | Test money | Real, finalized transactions on Solana devnet. Devnet USDC has no value. |
| Wallet funding | Test money | Circle's devnet USDC faucet, 20 USDC per address every 2 hours. |
| Network fees | Live | Paid by the facilitator (Coinbase's CDP facilitator, or x402.org without CDP keys). The wallet holds no SOL. |
| The paid API | Simulated | Our own x402 test API, standing in for a real paid API: $0.01 for a joke, $0.03 for a report. |
| Mainnet | Not built | Devnet only, by design. Mainnet needs a different network and asset in the wallet code, real USDC and a review. |
Limits
- Devnet only. The network and the asset are fixed in
tracks/wallet/track.ts. - x402 cannot pay an address that has no USDC token account yet. The test API's payee got one from the faucet.
- After a power cut mid-payment, the call fails instead of checking the chain for whether the payment went through. The owner checks the wallet on the explorer.
- The box holds the key. A CDP wallet would let Coinbase hold it; that needs a CDP wallet secret the box does not have.