SweeFiv0.4.2 · TypeScript

A payment SDK for AI agents on Sui, where the spending limit is a Move object the agent cannot edit and its human can revoke at any time.

Retired September 2026 in favor of x402, the open standard.


The problem

An agent’s spending limit usually lives inside the agent. It is a config value or a line in a prompt, sitting in the same process the model can be talked into. A prompt injection that reaches the payment call rewrites the limit and the payee together.

Two objects and one transaction

Mandate is a Sui object the agent owns, carrying max_per_tx, max_total and a running total_spent. RevocationRegistry is a shared object the human owns. mandatedPay puts the check and the transfer into a single programmable transaction block, so both commit or neither does.

Why it holds

Before reading the revocation flag, the contract asserts registry.owner == mandate.delegator. Without that one line a rogue delegate hands in an empty registry it created itself and the kill switch never fires — audit finding C-2. A test runs that exact attack on every build.

What it does not do

There is no third-party audit — every review so far is in-house — and the contracts are on Sui testnet only. A stolen delegate key still spends: the mandate bounds the size of a payment, never the intent behind it. It is a policy gate rather than custody, so it says nothing about coins the agent holds outside this call.

Retired · Sui testnet · 205 Move + 733 SDK tests green · unaudited · never on mainnet

PTB — the agent pays

const client = suiClient.$extend(sweefi())

tx.add(client.sweefi.mandate.mandatedPay({
  coinType: '0x2::sui::SUI',
  recipient: seller,
  amount: 250_000_000n,
  mandateId,
  registryId,
}))

Abort — the human revoked

MoveAbort(mandate, 405)

{
  code: 'MANDATE_REVOKED',
  retryable: false,
  requiresHumanAction: true,
  suggestedAction: 'Wait for the
                    user to respond.'
}

The refusal carries its own recovery rule — retry, or stop and go find the human — so the agent never has to guess which one this was.


The vocabulary

delegator
the human. The only address that can revoke
delegate
the agent. Transferring the object away changes nothing
max_per_tx
ceiling on one spend. Zero means none, not unlimited
max_total
lifetime ceiling, summed in u128 so overflow aborts cleanly
the registry
the kill switch. Passing it is mandatory — no unchecked path
abort 404
the registry was not the delegator’s. The bypass, caught

A fork, with an interrupt that lands mid-session

REVOKEcuts in mid-sessionSPENDagent wants to payalready authorized?yes — no interruptionSENTwithin the mandatenoASK THE PERSONthe interface problemWithdrawing an agent's authority while it isalready running. The hard part: it must landbefore the next call goes out, not after.The mandate answered thisahead of time, so the commoncase is silent.
The design work is telling the two branches apart fast enough that the lower one does not feel like an interruption. Drawing them at different depths says that: the yes path is a straight line, and every millimetre the no path travels is latency a person feels. Hover any dotted term for its definition.