Skip to content

Give an AI agent funds with a daily cap, a time window, a recipient list, 2FA on withdrawals, and one-transaction revocation, all enforced by the chain.

An agent needs money it can spend without a human signing every transaction, and the human needs a hard ceiling on what can go wrong. The token standard gives two layers for this. A vault is a USDC-backed collection whose withdraw approval carries a daily cap, an optional 2FA check, and an emergency recovery path. A spending authorization is an outgoing approval on a human's own account that lets a delegate key move a bounded amount to allowed recipients for a bounded time.

Both are a few fields on an approval. No server holds the policy, so a compromised dashboard cannot raise the limit, and any third party can read the exact envelope on-chain.

What Makes It Work

RequirementToken-standard primitive
Agent holds a balance it can spendA backed token vault: deposit USDC, withdraw USDC, noForcefulPostMintTransfers: true
Daily capapprovalAmounts.perInitiatedByAddressApprovalAmount with resetTimeIntervals.intervalLength: "86400000". See Approval Trackers
Count capmaxNumTransfers with the same reset interval
Second factor on withdrawalsmustOwnTokens pointing at a custom 2FA collection whose tokens live five minutes. See Token Ownership
Only the agent key can initiateinitiatedByListId = the agent address on an outgoing approval. See Spending Authorization
Only approved recipientstoListId = one address or a stored address list
Expires on a datetransferTimes window
Revoke in one transactionMsgDeleteOutgoingApproval, or a manager-only emergency migration approval on the vault

The Fields That Matter

The withdraw approval of a vault with a 1000 USDC daily limit and a 2FA gate on collection 84:

json
{
  "approvalId": "vault-withdraw-7c1e",
  "fromListId": "!Mint",
  "toListId": "bb1backingaddress...",
  "initiatedByListId": "All",
  "approvalCriteria": {
    "mustPrioritize": true,
    "allowBackedMinting": true,
    "approvalAmounts": {
      "perInitiatedByAddressApprovalAmount": "1000000000",
      "amountTrackerId": "withdrawal-daily",
      "resetTimeIntervals": { "startTime": "1788739200000", "intervalLength": "86400000" }
    },
    "mustOwnTokens": [
      {
        "collectionId": "84",
        "amountRange": { "start": "1", "end": "18446744073709551615" },
        "tokenIds": [{ "start": "1", "end": "1" }],
        "ownershipTimes": [{ "start": "1", "end": "18446744073709551615" }],
        "overrideWithCurrentTime": true
      }
    ]
  }
}
Token Ownership Requirements
On
  • Own 1 or more of token IDs 1 in collection 84
Coin Transfers per Use
Off
No payment attached
Merkle Challenges
Off
No proof required
Predetermined Balances
Off
Any amount in range
Amount Restrictions
On
Per initiator: 1000000000
Resets every day
Max Transfers
Off
Unlimited uses
Address Checks
Off
No initiator check
Sender and Recipient Approvals
Off
Must satisfy the sender's outgoing approvals
Must satisfy the recipient's incoming approvals

The withdraw approval on bitbadges.io: a per-initiator limit in base units that resets daily, plus the 2FA ownership check.

Amounts are base units: "1000000000" is 1000 USDC at 6 decimals. overrideWithCurrentTime: true makes the 2FA check use the block time, so an expired 2FA token fails.

bash
bb build vault --backing-coin USDC --symbol vUSDC --daily-withdraw-limit 1000 --require-2fa 84 \
  --emergency-recovery bb1zc268nctj8xwslgw7q22cahs6k4y048agr6fvf \
  --uri ipfs://bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi/collection.json

This emits a Smart Token + Vault collection with the deposit approval, the withdraw approval above, an emergency migration approval that only the recovery address can run, and every permission frozen so the manager cannot loosen the rules after funds arrive.

Variations

  • Delegate instead of vault: keep funds in the controller's wallet and give the agent an outgoing approval with approvalAmounts, maxNumTransfers, toListId, and transferTimes. The full message is on Spending Authorization.
  • Business hours only: altTimeChecks.offlineHours and offlineDays block transfers outside a schedule. See Alt Time Checks.
  • Human co-sign above a threshold: a second withdraw approval with a higher cap and a votingChallenges entry for the controller.
  • Per-agent budgets from one treasury: one outgoing approval per agent key, each with its own tracker ID.
  • Audit: every tracker tally is a public query, so a monitor can read "spent today" without indexing events.

Build It

text
Load the smart-token skill. Build a USDC vault for my trading agent with a 500 USDC daily withdraw limit, 2FA from collection 84 on every withdrawal, no peer-to-peer transfers, and bb1zc268nctj8xwslgw7q22cahs6k4y048agr6fvf as the emergency recovery address. Validate, review, simulate, then give me the review link.

Edit this page on GitHub