veto
Docs

Veto is a vault for money that AI agents spend. Every payment an agent asks for has to pass two checks before it leaves: hard limits enforced by a NEAR smart contract, and a private AI screen running inside a secure enclave on NEAR AI Cloud. The AI can block a payment. It can never approve more than the limits allow.

A payment inside the limit, stopped by the AI screen before it reaches a lookalike address.

Why spending limits aren't enough

Agents can now pay invoices, buy services and move funds. The usual safeguard is a policy: a spending limit and an allowlist of payees. Caps and allowlists stop strangers. The theft that actually happens to businesses is small, looks routine, and often pays someone already on the list:

  • Lookalike addresses. An address that shares its first and last characters with a supplier's, so both look the same when shortened.
  • Changed payout details. An email from a lookalike domain says the supplier's wallet has changed.
  • Planted instructions. A web page or document the agent reads tells it to send money somewhere.
  • Duplicate invoices. A reminder for an invoice that was already paid, to the supplier's real address.
  • Padded amounts. A listed supplier paid more than the invoice says.

Every one of these fits inside a normal weekly limit. On Veto Bench, a plain policy (allowlist plus a per-payment cap) lets 17 of 50 attacks through, every one to a listed supplier, and blocks 8 honest payments to new suppliers the mandate allowed. Veto's screen, running in NEAR AI's enclave, catches all 50, including every one a plain policy lets through.

How a payment flows

  1. The agent proposes. It calls propose on the vault with the payee, amount and invoice number, and sends the evidence behind it (the email, the invoice) privately to the guardian. Only a hash of that evidence goes on-chain (the shared sandbox, whose emails are made up, also publishes them).
  2. The contract checks the hard limits. Per-payment and weekly caps, listed assets, agent allowed, vault not frozen. Anything over a cap is refused right here.
  3. The guardian screens it privately. It sends the mandate, the payee list, recent payments, deterministic risk signals (lookalike, new payee, duplicate) and the evidence to a model running in a TEE on NEAR AI Cloud. The model answers PASS or VETO with reason codes, and the enclave signs the exact request and response.
  4. The contract checks the verdict. It recovers the signer with ecrecover, checks it is an approved model key, checks the response names this exact proposal, then records the verdict.
  5. PASS pays, VETO blocks. A pass is re-checked against the caps and paid. A veto stays blocked unless the owner overrides it, which waits for a delay and can be cancelled. No verdict before the deadline means the payment expires.

The rule: the AI can only say no

The design keeps the AI out of the decision to move money. It can only add a no. That way an AI mistake can never cost more than the limits you already accepted.

What you rely on

  • The vault contract, which is public and tested.
  • The guardian service to send honest context to the model.
  • NEAR AI Cloud's TEE hardware for privacy and signatures.

What can't hurt you

  • A tricked or compromised agent: it can only propose.
  • A forged verdict: the contract rejects unapproved signers.
  • A wrong PASS: still capped. A wrong VETO: one override.

How anyone can check a decision

Every verdict on the vault records the model, the signer, the chat id and the hashes of what the model saw and said. To check one:

  1. Open the decision's Proof page in the app, or read it from the contract with get_proposal.
  2. The signer is the model's key, published in NEAR AI Cloud's attestation report and backed by an Intel TDX quote. The vault approved that key before any verdict.
  3. On the Proof page, Check the enclave now verifies that from scratch with a fresh random nonce: the TDX quote against Intel's certificates, the GPU evidence with NVIDIA's attestation service, that the quote binds the key and the nonce, the app the enclave runs, NEAR AI's gateway, and that the attested key signed this verdict. node bench/verify.ts --attested runs the same checks from a terminal.
  4. The signature covers model:sha256(request):sha256(response). In the shared sandbox the exact request and response bytes are published, and the Proof page re-hashes them in your browser: they match what the enclave signed and the vault checked, and the email inside the request matches the hash the agent put on-chain before screening. A vault someone owns keeps them private; the standalone guardian (services/guardian) keeps them in a private audit record, so an owner can show the exact prompt to an auditor.
  5. NEAR AI's own verifier confirms the signature independently, and Veto Bench results can be re-checked offline with node bench/verify.ts.

What this proves: the verdict came from that model inside a genuine enclave. It doesn't prove the model judged correctly, which is why the AI can only say no.

Paying suppliers on other chains

Suppliers hold USDC on many chains. The vault sits on NEAR and pays out through NEAR Intents: the owner sets a route (for example "base: USDC on NEAR to USDC on Base, fee at most 1%"), and when a cross-chain payment passes the screen the guardian brings a 1Click quote for exactly that amount to exactly that address.

The vault checks 1Click's ed25519 signature on the quote itself and confirms it pays the screened payee, on the screened chain, for the screened amount, refunds only to the vault and stays under the fee cap. The caps count what actually leaves the vault, fees included. Then it sends the deposit. A doctored quote is refused on-chain.

Or from the vault's own address

The vault can also hold its own address on an EVM chain through NEAR Chain Signatures. When a payment to a Base supplier passes, the vault builds the transfer itself: exactly the screened payee and amount, gas under the owner's cap. Then it asks NEAR's MPC network to sign that transaction's hash. The guardian only broadcasts the signed bytes and reports the hash, so the vault's Base address can never send anything that didn't pass both gates.

Agent wallets on OutLayer

Some agents don't pay from a vault at all. They hold an OutLayer wallet: keys inside a TEE, with an owner policy that can require approvals. Veto plugs in as one of those approvers, so the same screen covers a wallet it doesn't hold.

  1. The agent asks its wallet to pay. The wallet's policy needs an approval, so OutLayer holds the payment and returns an approval id. The agent hands that id and its evidence to the guardian.
  2. The vault records it. The guardian reads the held operation, checks OutLayer's hash of it, and records the payment on your vault with propose_external. Your caps apply exactly as they do to vault payments.
  3. It is screened and checked on-chain. The model screens it privately, and the vault checks the signed verdict. The OutLayer approval id and operation hash are part of the proposal hash the model must echo.
  4. Veto votes only after a pass. If the vault passes it, the guardian signs a yes on OutLayer and the wallet sends it. The guardian then checks that transaction on NEAR, and only then marks it paid. On a veto Veto never votes, so the wallet keeps holding it.

The owner is a second approver on the wallet. An override on the vault waits out the same delay, then Veto votes yes; the owner can also approve on OutLayer directly. Keeping the veto rejects it on OutLayer right away; an approval nobody signs expires after 24 hours.

NEAR Intents Agent API wallets

The NEAR Intents Agent API gives an AI agent its own account on NEAR Intents. The owner signs one policy, which is the hard limit: which actions, which assets, how much, and where money may go. Whoever is allowed to spend holds a grant.

  1. Veto holds the only grant. The AI agent has none, so it can't move money. It can only ask Veto.
  2. Veto screens the request. The same enclave model reads the agent's evidence against the mandate and the business's payment history, and Veto requires the verdict to be signed by a key the vault approves.
  3. Only a pass is sent. A supplier on NEAR gets a transfer; a salary is a withdrawal that NEAR Intents pays out on the chain the worker chose, Base in the demo. Veto calls the API with its grant, under an idempotency key tied to that screening, so a retry can never send twice. A veto never reaches the API.
  4. The owner's policy still decides. Even after a pass, the API refuses anything the policy doesn't allow: an unlisted payee, more than the per-payment or daily limit, or a frozen account. The demo's policy allows withdrawals only to Tunde Bello's saved Base address, so a “new wallet” would be refused there even if the screen missed it.

The demo's account lives on mainnet and holds a few real dollars, so the inbox's amounts are scaled 1:2000 on this path: the examples that pass cost $0.09 and $0.075, and the owner's policy allows at most $0.10 a payment. The sandbox vault is on testnet, so these decisions aren't recorded on it; the enclave's signed verdict and the API's own operation record are the trail.

What stays private

Private

  • The emails, invoices and pages the agent acted on. Only the guardian that sends them to the model, and the model in its enclave, read them.
  • The full prompt the model saw, in a vault someone owns. The shared sandbox, whose emails are made up or written by visitors who were told, publishes it.
  • Inference runs in a TEE: NEAR AI's hosts can't read it.

Public on-chain

  • The payment itself: payee, amount, invoice number.
  • The verdict, reason codes and signatures.
  • Hashes of the evidence and the prompt.

Try it on testnet

The live demo is at veto-beta.vercel.app, with nothing to install. The shared sandbox is treasury.veto-rhwe0krb.testnet, a made-up business called Lagoon Goods that holds test USDC and pays three suppliers (two on NEAR, one on Base) and a member of staff. Anyone can act as its owner, and it goes back to its default rules for each new visitor. For a vault only you control, start with step 1.

  1. Do open Create your vault, connect a NEAR testnet wallet (Meteor Wallet at meteorwallet.app makes a testnet account for free; switch it to testnet first), name your business and sign. A new wallet starts with no NEAR, so Veto sends it 0.3 test NEAR for gas when it connects. See your own vault live in a few seconds, with $5,000 test USDC, two suppliers and its own test agent. From here on, overrides, freezes and rule changes need your wallet's signature.
  2. Do open the app and press Try it (the green V on a phone, Try the agent at the top of the sidebar on desktop). See the agent's inbox: a real invoice, a real salary and four scams that look ordinary.
  3. Do let the agent pay the real Kano Cotton Mills invoice. See "Agent proposed", "Screening privately", then Paid, with testnet transaction links.
  4. Do let it pay "Updated payment details". See Vetoed: a lookalike address, a new payee and changed payout details, while the payment was inside the weekly limit.
  5. Do open the decision, then Proof. See the signer, the hashes and the on-chain check, then the exact bytes the model saw, re-hashed in your browser.
  6. Do on that page, press Check the enclave now. See eight checks of NEAR AI's enclave run live: Intel's quote, NVIDIA's GPUs and the key that signed the verdict.
  7. Do open Activity and press Download CSV. See one row per payment, ready for an accountant: date, payee, amount, status, reference, verdict and reasons, the payout transaction and a link to its proof.
  8. Do press Override (your wallet signs it in your own vault; in the sandbox anyone can). See a countdown; the override pays only after the delay and can be cancelled.
  9. Do in the sandbox, switch Pay from to OutLayer wallet and repeat. See the paid invoice approved by Veto on OutLayer and sent by the wallet; the scam stays held, and Keep it blocked rejects it there for good.
  10. Do press Write your own email and write the agent an invoice, or a scam. See a real AI agent on NEAR AI read it and propose whatever it asks for, then Veto screen that payment like any other.
  11. Do in the sandbox, let the agent pay Tunde Bello's salary. See Paid on Base, the chain Tunde chose, sent from the vault's own Base Sepolia address with NEAR Chain Signatures, with a Base explorer link.
  12. Do let it pay “New wallet for my salary”. See Vetoed: the address imitates Tunde's saved one, it has never been paid, and the request came from outside the company.

Verdicts are signed by Qwen3-VL-30B inside NEAR AI's enclave, and each decision's Proof page shows which key signed it (a few early sandbox decisions were signed by a labelled test key). The sandbox and the vaults you create trust only the enclave key, so without an answer the payment expires unpaid.

For developers

An agent connects with a key that can only call propose:

import { Veto, toUnits } from "@veto/sdk";

const veto = new Veto({
  vaultId: "treasury.veto-rhwe0krb.testnet",
  agentAccountId: "buyer.<your-account>.testnet",
  agentKey: process.env.AGENT_KEY,      // a propose-only key
  guardianUrl: "http://localhost:8799",
});

const { id } = await veto.propose({
  payee: "kano-cotton.<your-account>.testnet",
  asset: "usdc.<your-account>.testnet",
  amount: toUnits("180", 6),
  memo: "INV-2290",
  evidence: { source: "email", body: "…" },  // stays off-chain
});

const decision = await veto.decision(id); // Paid, Vetoed, Expired…

Contract methods

MethodWhoWhat it does
factory: create_vault(name, label, mandate?)AnyoneCreates <name>.<factory>, owned by the caller, with starter test funds, caps, suppliers and the enclave model's key, plus its own agent and screening accounts, holding the hosted app's agent and guardian keys as function-call keys that can only call this vault.
factory: send_gas(account)The factory's own keySends an empty testnet wallet 0.3 test NEAR for gas, once per wallet. The web app holds a key that can call only this, and calls it when an empty wallet connects.
propose(request, context_hash)AgentAsks to pay. Checked against the caps at once; then waits for the screen.
submit_verdict(id, model_id, chat_id, request_hash, response, signature, quote?)GuardianRecords the signed verdict. PASS pays if the caps still allow it; VETO blocks.
expire(id)AnyoneEnds a screening with no verdict after the deadline. No verdict means no payment.
override_veto(id) / cancel_override(id)OwnerSchedules a vetoed payment to pay after the delay, or cancels that.
keep_blocked(id)OwnerCloses a veto for good. For an OutLayer wallet, Veto then rejects the held payment there.
execute_override(id, quote?)AnyonePays an override once its delay has passed. Still inside the caps.
freeze() / unfreeze()OwnerStops every payment and cancels pending overrides.
set_policy(asset, policy)OwnerLowering a limit applies now; raising one waits for the raise delay.
set_mandate, add_payee, remove_payee, add_agent, set_agent_activeOwnerWhat the agent may do, in plain words and as lists.
add_signer(address, model_id)OwnerApproves a model's signing key. Check its TEE attestation first (every Proof page and verify.ts --attested do it); the contract itself doesn't.
set_route(chain, route)OwnerLets the vault pay suppliers on another chain through NEAR Intents.
set_evm_route(chain, route)OwnerLets the vault pay on an EVM chain from its own Chain Signatures address, with a cap on gas fees.
settle_evm(id, tx_hash)GuardianRecords the chain's transaction once the guardian has broadcast a payout the MPC network signed.
add_wallet(provider, wallet, name)OwnerLets the guardian screen payments from an external agent wallet, such as an OutLayer wallet.
propose_external(request, context_hash, external)GuardianRecords a payment the wallet is holding for approval. Same caps; then it is screened like any other.
settle_external(id, paid, tx_hash)GuardianMarks it paid once the wallet's transaction is final on NEAR, or releases the spend if it failed.

Run it yourself

pnpm install
pnpm test                         # core, contract and factory tests
pnpm build:contracts              # the contracts, as wasm
node scripts/check-deployed.ts    # the code on testnet is exactly this build
node bench/verify.ts bench/results/Qwen_Qwen3-VL-30B-A3B-Instruct.json --attested
pnpm build && pnpm start          # the app on http://localhost:3000, reading the live sandbox
pnpm demo:setup                   # optional: your own testnet sandbox from the faucet (see the README)

Built on NEAR

  • NEAR AI Cloud. Models in TEEs (Intel TDX and NVIDIA confidential GPUs) that sign every answer; the vault checks that signature on-chain.
  • NEAR Intents (1Click). Pays suppliers on other chains; the vault verifies the signed quote before sending.
  • Access keys. Function-call keys limited to one vault and a few methods: the agent can only propose, the guardian can only record verdicts and settle payments.
  • Global contracts. The vault code is deployed once (NEP-591); every vault the factory creates runs it by hash and stores only its own state.
  • Named accounts and sub-accounts. treasury., buyer., guardian. under one owner account, so roles are readable on-chain.
  • NEP-141 tokens and contract events. USDC payments, with every decision emitted as a NEP-297 event.

What works today

  • Live on testnet
    Vault contract: caps, verdict check, overrides, freeze

    48 contract tests; deployed on NEAR testnet.

  • Live on testnet
    Your own vault, owned by your wallet

    A factory creates a vault for any NEAR testnet account in one transaction its wallet signs. The vault code is deployed once as a NEAR global contract, so each new vault stores only its own state (about 1.6 KB). Its agent and screening accounts are its own too, each holding one key that can only call that vault. Every owner action is signed by the owner's wallet.

  • Live on testnet
    OutLayer agent wallets

    Veto is an approver on an OutLayer wallet's policy. Pass, veto and override all run on testnet, settled against the wallet's real transactions.

  • Live on mainnet
    NEAR Intents Agent API wallet

    An agent account on mainnet whose owner-signed policy is the hard limit. Veto holds its only grant, screens each request with the same enclave model, and sends only a pass: a transfer to a supplier, or a salary withdrawn to the worker's address on Base. Each payment is a few cents of real USDC, and runs while the wallet holds some.

  • Live on testnet
    Payroll: staff paid on the chain they chose

    Staff sit on the payee list with their own wallet and chain. The sandbox pays a salary in test ETH on Base from the vault's Chain Signatures address and vetoes a fake request to send it to a new wallet.

  • Live on testnet
    Agent inbox and guardian screening

    Real proposals and verdicts on testnet, screened by Qwen3-VL-30B inside NEAR AI's enclave. The sandbox trusts only the enclave key, like every vault you create: if NEAR AI can't answer, the payment expires unpaid.

  • Live on testnet
    Owner actions in the app

    In your own vault, only your wallet. In the shared sandbox, a demo-owner key limited to the owner methods, so anyone can try it without a wallet. The sandbox goes back to its default rules for each new visitor.

  • Live on testnet
    Private AI screen on NEAR AI Cloud

    Qwen3-VL-30B runs in an Intel TDX enclave on NEAR AI Cloud and signs each verdict in about 1.5 s. The vault checks the signature on-chain against the model's attested key.

  • Live on testnet
    Enclave verification

    Every Proof page re-checks NEAR AI's enclave live with a fresh nonce: Intel's TDX quote, NVIDIA's GPU evidence, the key and nonce bound into the quote, the app it runs, the gateway, and that the attested key signed the verdict. Tested offline on a captured real quote.

  • Live on testnet
    Activity export

    Download CSV gives one row per payment, ready for an accountant: date, payee, amount, status, reference, verdict and reasons, payout transaction and a link to its proof.

  • Built and tested
    Paying suppliers on other chains (NEAR Intents)

    The vault verifies 1Click's signed quote on-chain, tested against a real executable quote. The mainnet payout is scripted and runs once the mainnet vault is funded.

  • Live on testnet
    Veto Bench

    100 scenarios. Qwen3-VL-30B catches 50 of 50 attacks and blocks 8 of 50 honest payments; all 100 signatures re-verify offline. Plain-policy and rules-only baselines are published beside it.

  • Built and tested
    Shield incident check before cross-chain payouts

    Holds a payout while a NEAR Intents Shield incident touches its chain, bridge, token or payee; fails closed if it outlasts the deadline. Runs when the Shield key is added.

  • Live on testnet
    The vault's own Base address via Chain Signatures

    The vault builds each passed transfer and NEAR's MPC network signs exactly that; the contract tests include byte-for-byte checks against ethers.

Questions

Is this real, or a simulation?

Real, on NEAR testnet. Every vault is a deployed contract, every payment is a testnet transaction you can open on NearBlocks, and every verdict's signature is checked by the contract against a key the owner approved: NEAR AI's enclave key, the only one the sandbox and your vaults trust. The tokens are test tokens. The shared sandbox lets anyone act as its owner so it can be tried without a wallet, and goes back to its default rules for each new visitor; a vault you create belongs to your wallet, and nothing changes its rules without your signature.

Where do the payment requests come from?

From what the agent reads. The inbox holds example emails (a supplier's invoice and a salary, both genuine, and four common scams), and Write your own email sends the agent anything you type: a real model on NEAR AI reads it and proposes whatever it asks for, the way an accounts-payable agent would. In production that is the agent's own inbox, a supplier portal or a web page. Veto never trusts the request; it screens the payment against the evidence.

Which model screens the payments?

Qwen3-VL-30B-A3B-Instruct, hosted by NEAR AI Cloud inside an Intel TDX enclave. It answers directly without a reasoning phase, so a verdict takes about 1.5 seconds and always arrives in full. The owner approves a model by its attested signing key (add_signer), so any other enclave-hosted model can be used instead; Veto Bench compares them on the same 100 scenarios.

What if the AI gets it wrong?

If it misses an attack, the payment is still inside the hard caps, so you're no worse off than with a plain spending limit. If it blocks a good payment, the owner overrides it; the override waits for a delay and can be cancelled. The AI never decides alone that money should move.

What if the screening service is compromised?

The vault only accepts verdicts from the registered guardian account, signed by an approved model key, echoing this exact proposal. A compromised guardian still can't pay more than the caps allow, can't change payees or limits, and can't move money anywhere the agent didn't propose. The guardian does choose the evidence the model reads: the enclave proves which model judged which input, not that the input was the real email. In this demo one server runs both the demo agent and the guardian, so it holds both roles and could propose and pass a payment to any address inside the caps; an owner can close that by requiring listed payees on-chain (set_require_listed_payee). Running the guardian itself inside a TEE is the next step that removes this trust.

How is this different from a policy wallet?

A policy wallet enforces caps and an allowlist, and Veto's contract does the same. Those rules stop payments to strangers. They can't stop a payment to a listed supplier for an invoice that was already paid, or for more than was billed, and a strict allowlist blocks every new supplier. Veto adds a private screen that reads the evidence behind each payment and can only say no, so the two work together rather than compete. On an OutLayer wallet that is literal: Veto is an approver on the wallet's policy.

Can it run payroll?

Yes. Staff go on the payee list with the wallet and chain each one chose, and the agent pays salaries like any other payment: inside the caps, screened privately. In the sandbox, Tunde Bello is paid in test ETH on Base from the vault's own address, signed by NEAR's MPC network; on the Agent API path, the salary is USDC withdrawn through NEAR Intents and paid out on Base, to the one address the owner's policy allows for Tunde, once the demo wallet holds USDC. The most common payroll scam, an email asking to send someone's salary to a new wallet, is vetoed: the address is new and imitates the saved one.

Can Veto guard a swarm of agents?

Yes. A vault takes any number of agents (the sandbox runs one), each with its own key that can only propose a payment, and the owner can pause one without stopping the rest. Agents running in OutLayer TEE wallets or NEAR Intents Agent API wallets go through the same gate: every payment from any of them gets the same private AI review. Agents on the vault and OutLayer wallets also meet the vault's contract caps; an Agent API wallet meets its owner's signed policy instead. Separate budgets for each agent are next.

Why not just use a card with limits?

Cards stop at a spending limit and a merchant category. Most theft against businesses and agents is small and looks routine: a lookalike address, changed payout details, a duplicate invoice, an instruction planted in a web page. Veto reads the evidence behind each payment, works across chains and assets, and leaves a public, checkable record of every decision.

Why NEAR?

Three things in one place: NEAR AI Cloud runs models inside TEEs and signs every answer, NEAR Intents pays out on almost any chain from one balance, and NEAR's account model lets each key do one narrow job (the agent can only propose, the guardian can only record verdicts and settle payments).

Who pays for gas?

Each account pays for its own calls: the agent for proposing, the guardian for submitting verdicts, the owner for owner actions. On testnet that's free test NEAR from the faucet.