--- eip: 8406 title: Fungible Agent Tokens description: AI agents as on-chain economic entities that issue equity, act within owner-set boundaries, and attest reasoning for every action. author: Ashton (@AshtonMagic) discussions-to: https://ethereum-magicians.org/t/erc-8406-fungible-agent-tokens/29220 status: Draft type: Standards Track category: ERC created: 2026-04-24 requires: 20, 165 --- ## Abstract **FAT (Fungible Agent Tokens)** is an equity standard that defines AI agents as on-chain economic entities. A FAT Agent is not a container that holds funds — it is an autonomous actor: it **issues** Shares representing equity in its own economic activity, **acts autonomously** within a boundary set for it, and leaves a **tamper-evident reasoning record** for every action it takes. The protocol unifies these three layers in a single interface: - **Autonomous Execution** — the agent acts on-chain through its Executor, interacting with external protocols and deploying its own funds; - **Equity Issuance** — the agent issues fungible **Shares** representing a claim on its economic performance, entered and exited at a standard exchange rate; - **Reasoning Attestation** — off-chain metadata and per-action reasoning records anchor the agent's identity, strategy, model, and the rationale behind every decision to its on-chain identity. With this, any agent can be **born, capitalized, and self-operating** as an independent economic entity — a composable on-chain primitive for the entire ecosystem. Concretely, FAT Agents are smart contracts that - accept capital contributions denominated in a single **Accept Token** (an immutable [ERC-20](./eip-20.md) chosen at deployment) through a two-phase request-then-claim flow, and issue fungible **Shares** against them, - allow Holders to exit by requesting redemption and later claiming the Accept Token for their escrowed Shares, which are burned at settlement, - expose a canonical on-chain **exchange rate** between Shares and the Accept Token, - carry a mutable **Agent URI** pointing to off-chain metadata (name, description, image, etc.), - allow a designated off-chain **Executor** to call third-party protocols on behalf of the Agent via a low-level dispatch primitive, subject to a `DELEGATECALL` prohibition and an Owner-set `isInScope` scope gate, and - decide on mints and redemptions through **reasoned settlement** (`settleMint` / `settleRedeem`) — admitting, pricing, or declining each contribution and exit is a deliberate act of the agent itself — and attach a **tamper-evident reasoning record** (`reasoningHash` + `reasoningURI`) to every on-chain agent action. Here, the **Fungible Agent Tokens** are the fungible Shares that represent economic participation in the Agent — not the Agent's off-chain identity, model, or behavior. Those are not excluded from the standard; they are simply **not represented as fungible Shares**: the attestation layer anchors them on-chain through the **Agent URI** and `reasoningHash` / `reasoningURI`. The standard fixes these interface surfaces but deliberately leaves to the implementer: the exact share-pricing formula, the fee structure, share transferability, the ownership-transfer mechanism, whether and how the Agent can be paused, whether and how Holders realize returns beyond what the exchange rate reflects, and — importantly — **any restriction on what the Executor may call through `execute`**. Policy is separated from interface. ## Motivation AI agents increasingly act on-chain — trading, staking, lending, managing capital — yet there is no standard that makes an agent *itself* an on-chain economic entity: one that can be capitalized, self-operating, and composed by the ecosystem, with its behavior and reasoning legible to anyone. Representing pooled capital as fungible shares is already well understood; what has no standard is the agent part — how it *acts* on external protocols, and how the off-chain reasoning behind those actions is *anchored* on-chain. What FAT defines is not a container for funds — it is how an on-chain economic entity comes into existence. A FAT Agent holds a persistent on-chain identity, commands its own capital, acts autonomously within a constitutional boundary set by its Owner, and signs a verifiable record for every action it takes. Buying shares is not hiring a tool that executes on your behalf — it is investing in the agent's own economic activity: participating in its growth and sharing in its outcomes. Share accounting is therefore only one of three layers — equity issuance — alongside the agent's autonomous execution and the off-chain attestation of its identity and reasoning. For this class of system to compose and to be auditable, the behavior layer needs a standard: a single interface that tooling, indexers, wallets, and auditors can rely on regardless of the specific economic model the Agent chooses. This standard makes the *agent itself* first-class. Its **reaction** (reasoned settlement, so mint and redeem are the Agent's own deliberate acts rather than passive bookkeeping), its **reasoning** (a tamper-evident, indexable record bound to every on-chain action), and its **bounded spending** (an Owner-set Scope the Agent cannot widen) are standardized surfaces in their own right, so that what the Agent *decides* and *may do* is as legible and auditable as what it holds. Beyond behavior, a tokenized Agent also needs: - A fixed **unit of account** — the single **Accept Token**, chosen at deployment and immutable thereafter — so that share pricing and redemption are unambiguous. - A **standard exit path** — the `requestRedeem` / `redeem` flow — so a Holder can exit any Agent through one interface that portfolio tooling can rely on. - A **discoverable metadata pointer** — the **Agent URI**, analogous to [ERC-721](./eip-721.md) `tokenURI` — so explorers and marketplaces can render an Agent's identity without per-project integration. Because settlement may be asynchronous — the user requests first and claims once the Agent is ready — Shares are minted and redeemed through a two-phase request-then-claim lifecycle rather than a single synchronous call. This specification defines all of the above as a minimal, composable standard. ## Specification The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. ### 1. Conformance A contract is **FAT-compliant** if it implements the `IAgent` interface defined in §4, emits the events defined in §5, respects the role semantics defined in §3, satisfies the normative requirements in §6, and advertises support via [ERC-165](./eip-165.md) interface detection (see [Backwards Compatibility](#backwards-compatibility)). (§6.8 reentrancy is a security recommendation, not a conformance requirement.) A FAT-compliant contract additionally: - implements `settleMint`, `settleRedeem`, `isInScope`, and the reasoning-carrying `execute` (§4); - carries a non-zero `reasoningHash` and a non-empty, resolvable `reasoningURI` on every `settleMint` / `settleRedeem` / `execute`, and emits the corresponding reasoning-bearing event (§6.2); - enforces `isInScope` on `execute`, with the Scope configurable only by the Owner (§6.6.7–8). A compliant Agent MUST also implement [ERC-20](./eip-20.md) for its Share token. The Share token MAY be the Agent contract itself or a distinct contract; either way, `shareToken()` MUST return its address. ### 2. Terminology - **Agent** — a FAT-compliant contract: the on-chain embodiment of an off-chain agent, an economic entity that owns assets, issues equity, acts autonomously, and attests to its own behavior. The Agent contract **is** the agent's on-chain account — a persistent, stable address that commands its own capital, issues the Shares that represent it, acts through its Executor(s), and presents its identity. Together with its `agentURI` attestation, it is what identifies the on-chain agent — the account that acts, plus the off-chain record of what it is. (An Executor is merely a key authorized to drive this account, not the identity itself.) - **Share** — a unit of equity issued by the Agent, representing participation in its economic performance, implemented as [ERC-20](./eip-20.md). - **Accept Token** — the *single* [ERC-20](./eip-20.md) the Agent accepts as payment for newly minted Shares and pays out on redemption. **Fixed at construction and immutable for the lifetime of the Agent.** - **Owner** — the Agent's constitution-setter and guardian: it defines the boundary the agent cannot loosen for itself (the Scope), appoints and removes Executors, and maintains the Agent URI. MAY be an EOA, multisig, or governance contract. The protocol does not prescribe whether or how an Owner exits — see §6.7, §7; an Agent whose Owner has renounced runs fully autonomously within its frozen constitution. - **Executor** — the on-chain channel of the agent's will: it settles contributions and exits via `settleMint` / `settleRedeem`, and submits the agent's actions via `execute`. Every such action carries reasoning (§6.2). An Agent MAY have zero or more Executors. An address MAY simultaneously be Owner and Executor. The Executor cannot change the Scope or the Owner. Because `execute` forwards arbitrary calldata to any Executor-chosen target (with only the `DELEGATECALL` prohibition of §6.6.2), the Executor is an effectively unconstrained role over every asset the Agent holds and every approval the Agent can grant — bounded only by the Owner-configured Scope (`isInScope`, §6.6.7–8). - **Holder** — any address with a non-zero Share balance. - **Request** — a pending or claimable mint or redeem operation. Requests are fungible per requester: a requester MAY open many over time, but they are tracked in aggregate (a pending balance and a claimable balance) rather than individually addressed. See §6.3, §6.4. - **Requester** — the address that opens requests (the caller of `requestMint` / `requestRedeem`) and to which the claim pays out. Distinct from the Agent **Owner** role. - **Epoch** — an implementer-defined settlement-batch sequence number surfaced in the lifecycle events (`MintRequested`, `SharesMinted`, `RedeemRequested`, `SharesRedeemed`) so indexers can correlate requests and claims with the settlement round they belong to. Per-request or fixed-price Agents that do not batch MAY use a monotonic counter or `0`; the protocol mandates no epoch or batching mechanism (§6.3.3). - **Agent URI** — an off-chain URI (typically `ipfs://`, `https://`, `ar://`, or a `data:` URI) resolving to JSON metadata describing the Agent (its identity, strategy, model, etc.) — the agent's off-chain attestation. See §6.5. - **Exchange Rate** — the canonical price of one Share denominated in the Accept Token, scaled by `1e18`; a valuation / NAV reference read via `exchangeRate()`. Formally, `exchangeRate()` returns `R` such that `x` Share base-units (wei) are worth `x * R / 1e18` Accept-Token base-units (wei) — a wei-to-wei fixed-point ratio with 18 decimals of scaling. The claimable share count / payout is fixed at settlement and reported by `queryMintStatus` / `queryRedeemStatus`, which MAY diverge from this rate. - **Reasoning record** — the off-chain content a `reasoningURI` resolves to, committed on-chain by `reasoningHash` (§6.2). - **Scope** — the Owner-configured boundary within which the Executor may spend via `execute`, enforced by `isInScope` (§6.6.7–8). ### 3. Roles FAT defines exactly three roles. Implementations MAY add additional roles (e.g., Guardian, Fee Recipient, Pauser, Policy Oracle) but MUST NOT weaken the normative permissions of the three below. | Role | Required Capabilities | Trust premise borne by users | |----------|---------------------------------------------------------------------------|------------------------------| | Owner | Set/unset executors; set Agent URI; configure the Executor's spend Scope. | Holders and Requesters trust the Owner not to enable a malicious Executor or point the Agent URI at misleading metadata. | | Executor | Settle pending requests (`settleMint` / `settleRedeem`) and invoke `execute` on the Agent's behalf — every such action carries reasoning; `execute` must pass the Owner-set Scope. | Effectively unconstrained over every asset the Agent holds and every approval it can grant (§2, §6.6), bounded by the Owner-set Scope; integrators must trust the Executor's operational posture. | | Holder | Hold and (at the implementer's option) transfer Shares. | — | The mint/redeem lifecycle has two phases — opening a request and later claiming it — and neither requires a privileged-role grant (no Owner or Executor permission), but the two differ in *who* may call them. **Opening** a request is self-only and bounded by what the caller already owns: `requestMint` spends the caller's own Accept Token, and `requestRedeem` escrows the caller's own Shares (so a redeem requester must already be a Holder). There is no way to open a request on another address's behalf — that would require authorization, which is deliberately out of scope (see §7 and [Rationale](#rationale)). The address that opens a request is the **Requester** of §2. **Claiming**, by contrast, is a permissionless crank: `mint(user)` / `redeem(user)` MAY be called by any address, but always pay out to `user` (the owed party), so the caller gains nothing and no authorization is needed. A mint requester need not already be a Holder (a pending mint holds no Shares yet); a Requester implicitly accepts the settlement price the Agent fixes at settlement, since the claim carries no slippage guard (§6.3, §6.4, §7). The standard does not elevate the Requester to a separate trust role, which is why exactly three are enumerated. The roles are capabilities, not mutually exclusive principals: the protocol does not require them to be held by distinct addresses, so one address can hold several at once. Owner and Executor are *privileged, trusted* roles; being a Holder or Requester is *permissionless*. Concentrating the privileged roles — Owner and Executor — in one address, or giving an Owner/Executor its own Holder/Requester stake, maximizes the trust an Agent's external Holders must extend and creates a self-dealing incentive around settlement; see [Security Considerations](#security-considerations). Implementations MAY restrict which combinations they permit as a matter of policy; the standard neither mandates nor forbids a particular separation. The Executor's spending through `execute` is bounded by the Scope the Owner configures (enforced by `isInScope`, §6.6.7–8), and every agent action — settlement and execution alike — carries reasoning (§6.2). ### 4. Interface All compliant Agents MUST implement the following Solidity interface. Function signatures, parameter order, and return types are normative. ```solidity // SPDX-License-Identifier: CC0-1.0 pragma solidity >=0.8.20; interface IAgent { // ---------- Immutable configuration ---------- /// @notice The single ERC-20 accepted for share purchase and paid out on redemption. /// @dev MUST return the same address for the lifetime of the Agent. function acceptToken() external view returns (address); /// @notice Address of the ERC-20 Share token. /// @dev MAY return `address(this)` if the Agent contract itself is the ERC-20. function shareToken() external view returns (address); // ---------- Share minting (two-phase) ---------- /// @notice Phase 1. Deposit `amount` of the Accept Token, adding to the caller's pending mint balance. /// @dev MUST pull exactly `amount` via ERC-20 `transferFrom`; MUST NOT accept native ether. /// The share count is determined later, at settlement. MUST emit `MintRequested`. /// @param amount The amount of Accept Token to deposit (in its smallest unit). function requestMint(uint256 amount) external; /// @notice Phase 2. Claim ALL currently-claimable shares for `user`. Permissionless: any caller MAY /// trigger the claim, but the shares are always minted to `user` (the owed party), so the /// caller only pays gas and gains nothing. /// @dev MUST mint `user`'s entire claimable-share balance to `user`, zero that balance, /// and emit `SharesMinted`. The settlement price is accepted implicitly (no slippage /// guard; the share count was already fixed at settlement — see §6.3). /// @param user The owed party whose claimable shares are minted (to itself). Pass your own address to self-claim. /// @return shares The number of shares minted to `user` (may be 0 if nothing is claimable). function mint(address user) external returns (uint256 shares); /// @notice Agent reaction. Settle `requester`'s pending mint request, with reasoning attached. /// @dev Executor only. Settles some, all, or none of `requester`'s pendingAssets into /// claimableShares; the amount/accept/price is computed by the implementation inside. /// MUST emit `Settled`. `reasoningHash`/`reasoningURI` per §6.2. /// @param requester The request to settle. /// @param reasoningHash keccak256 of the bytes at `reasoningURI`; MUST be non-zero. /// @param reasoningURI Resolvable pointer to the reasoning record; MUST be non-empty. function settleMint(address requester, bytes32 reasoningHash, string calldata reasoningURI) external; /// @notice Aggregate mint status for `user`. /// @return pendingAssets Accept Token deposited but not yet settled. /// @return claimableShares Settled shares awaiting a `mint` claim. function queryMintStatus(address user) external view returns (uint256 pendingAssets, uint256 claimableShares); // ---------- Share redemption (two-phase) ---------- /// @notice Phase 1. Escrow `shares`, adding to the caller's pending redeem balance. /// @dev MUST pull (escrow) exactly `shares` of the Share token from `msg.sender`. /// Settled shares are burned at settlement; payout is priced then. MUST emit `RedeemRequested`. /// @param shares The number of shares to redeem. function requestRedeem(uint256 shares) external; /// @notice Phase 2. Claim ALL currently-claimable Accept Token for `user`. Permissionless: any caller /// MAY trigger the claim, but the Accept Token is always paid to `user` (the owed party), so the /// caller only pays gas and gains nothing. /// @dev MUST transfer `user`'s entire claimable-token balance to `user`, zero that balance, /// and emit `SharesRedeemed`. The settlement price is accepted implicitly (no slippage /// guard; the payout was already fixed at settlement — see §6.4). /// @param user The owed party who is paid the Accept Token. Pass your own address to self-claim. /// @return tokens Accept Token transferred to `user` (may be 0 if nothing is claimable). function redeem(address user) external returns (uint256 tokens); /// @notice Agent reaction. Settle `requester`'s pending redeem request, with reasoning attached. /// @dev Executor only. Symmetric to `settleMint`: settles pendingShares into claimableTokens, /// burning settled Shares. MUST emit `Settled`. function settleRedeem(address requester, bytes32 reasoningHash, string calldata reasoningURI) external; /// @notice Aggregate redeem status for `user`. /// @return pendingShares Shares escrowed but not yet settled. /// @return claimableTokens Settled Accept Token awaiting a `redeem` claim. function queryRedeemStatus(address user) external view returns (uint256 pendingShares, uint256 claimableTokens); // ---------- Exchange rate ---------- /// @notice Canonical valuation rate: how many Accept Tokens one Share is worth right now, scaled by 1e18. /// @dev A share-valuation / NAV reference for tooling and holdings valuation. For a fixed-price /// Agent this MAY be constant; for a NAV-based Agent it varies over time. This is NOT a /// predictor of mint/redeem trade outcomes — those are fixed at settlement and reported by /// `queryMintStatus` / `queryRedeemStatus`. /// @return rate Accept-Token base-units per 1e18 Share base-units (wei-to-wei), 18-decimal fixed point: /// `x` Share base-units are worth `x * rate / 1e18` Accept-Token base-units. function exchangeRate() external view returns (uint256 rate); // ---------- Agent metadata ---------- /// @notice URI pointing to off-chain JSON metadata describing the Agent. function agentURI() external view returns (string memory); /// @notice Set the Agent URI. Owner only. MUST emit `AgentURIUpdated`. function setAgentURI(string calldata uri) external; // ---------- Executor dispatch ---------- /// @notice Executor dispatch, with reasoning and scope enforcement. /// @dev MUST revert unless `msg.sender` is an Executor. /// MUST NOT dispatch via `DELEGATECALL` (see §6.6.2). /// MUST NOT be `payable`; `value` is paid from the Agent's own balance (see §6.6.4). /// MUST call `isInScope(target, value, data)` and revert if it returns false (see §6.6.7). /// MUST bubble the revert data unchanged on failure (and emits no event then). /// MUST emit `Executed` (carrying the reasoning) on success. /// `reasoningHash`/`reasoningURI` per §6.2. /// Beyond the Executor check, the `DELEGATECALL` prohibition, and the `isInScope` /// gate, implementers MAY layer any further policy (target allowlist, selector filter, /// parameter filter, session key, signed-policy engine, rate limiter, external policy /// contract, etc.) on top of this function. function execute( address target, uint256 value, bytes calldata data, bytes32 reasoningHash, string calldata reasoningURI ) external returns (bytes memory returnData); // ---------- Owner administration ---------- /// @notice Enable or disable `account` as an Executor. Owner only. MUST emit `ExecutorUpdated`. function setExecutor(address account, bool enabled) external; // ---------- Views ---------- /// @notice Address currently authorized to invoke Owner-gated functions. /// @dev The mechanism by which this value changes is outside the scope of this specification. function owner() external view returns (address); function isExecutor(address account) external view returns (bool); /// @notice Whether an `execute` to (`target`, `value`, `data`) is within the Agent's spend scope. /// @dev Implementer-defined predicate; `execute` MUST consult it (§6.6.7). The scope it reflects /// is Owner-configurable only (§6.6.8). Also usable as an off-chain audit query. function isInScope(address target, uint256 value, bytes calldata data) external view returns (bool); } ``` ### 5. Events All events below are normative. From `MintRequested`, `SharesMinted`, `RedeemRequested`, `SharesRedeemed`, `Settled`, and `Executed` (plus the Share token's [ERC-20](./eip-20.md) events), indexers can track every deposit, settlement, claim, and executor call. Agent reasoning is anchored on `Settled` and `Executed` via their `reasoningHash` / `reasoningURI` fields (and, for implementer-defined agent-facing functions, via `Reasoned`). Because settlement MAY be reported in aggregate rather than per requester (§6.3, §6.4), a requester's current `pendingAssets` / `claimableShares` (resp. `pendingShares` / `claimableTokens`) are read authoritatively from `queryMintStatus` / `queryRedeemStatus` rather than reconstructed solely from events. The immutable `acceptToken()` and `shareToken()` are part of deployment data and do not require a runtime event. Ownership-transfer events and pause/unpause events, if any, are defined by each implementation (§6.7, §7). ```solidity event MintRequested( address indexed requester, uint256 assets, // Accept Token deposited uint64 indexed epoch, // settlement-batch sequence (§2); MAY be 0 uint256 timestamp // block.timestamp at emission ); event RedeemRequested( address indexed requester, uint256 shares, // Shares escrowed uint64 indexed epoch, // settlement-batch sequence (§2); MAY be 0 uint256 timestamp // block.timestamp at emission ); event SharesMinted( // emitted on claim address indexed requester, uint256 assets, // Accept Token that produced the claimed shares uint256 shares, // shares minted to the requester uint64 indexed epoch, // most recent settlement epoch included; MAY be 0 uint256 sharePrice, // effective settled rate: assets * 1e18 / shares uint256 timestamp // block.timestamp at emission ); event SharesRedeemed( // emitted on claim address indexed requester, uint256 shares, // shares redeemed to produce the payout uint256 assets, // Accept Token paid out uint64 indexed epoch, // most recent settlement epoch included; MAY be 0 uint256 sharePrice, // effective settled rate: assets * 1e18 / shares uint256 timestamp // block.timestamp at emission ); /// SHOULD be emitted whenever `exchangeRate()` changes (e.g. at NAV settlement). /// A constant-rate (fixed-price) Agent need never emit it. This is the O(1) /// settlement signal for NAV-priced Agents — see §6.3.4 / §6.4.4. event ExchangeRateUpdated(uint256 newRate); event AgentURIUpdated(string newURI); event Executed( address indexed executor, address indexed target, uint256 value, bytes4 indexed selector, // first 4 bytes of calldata; 0x00000000 if data.length < 4 bytes returnData, bytes32 reasoningHash, string reasoningURI ); /// Emitted when an Executor settles a pending request (§6.3, §6.4). event Settled( address indexed requester, uint8 kind, // 0 = mint, 1 = redeem uint256 amount, // shares (mint) or tokens (redeem) made claimable bytes32 indexed reasoningHash, string reasoningURI ); /// SHOULD be emitted by an implementer's own agent-facing functions to attach reasoning /// uniformly. Standard ops (settleMint/settleRedeem/execute) carry reasoning in their own events. event Reasoned( address indexed actor, bytes4 indexed action, bytes32 indexed reasoningHash, string reasoningURI ); event ExecutorUpdated(address indexed executor, bool enabled); ``` `SharesMinted` / `SharesRedeemed` are emitted when a claim is made for the requester — via `mint(user)` / `redeem(user)`, which any address MAY call (see §6.3.5, §6.4.5); the indexed address is always the owed party. A deposit / redemption becomes claimable only once an Executor settles it via `settleMint` / `settleRedeem` (§6.3, §6.4), reported by `queryMintStatus` / `queryRedeemStatus`. Because a claim collects the requester's *entire* claimable balance, which MAY span more than one settlement, the `assets` / `shares` / `sharePrice` / `epoch` fields on these two events report the aggregate: `assets` and `shares` are the totals the claim converts between, `sharePrice` is the effective rate `assets * 1e18 / shares` (`0` when `shares` is `0`), and `epoch` is the most recent settlement epoch included. On all four lifecycle events `timestamp` is `block.timestamp` at emission — an indexing convenience that duplicates the log metadata. ### 6. Normative Requirements #### 6.1 Invariants 1. `acceptToken()` and `shareToken()` MUST each return the same address for the entire lifetime of the Agent. 2. The Accept Token is a single [ERC-20](./eip-20.md); the Agent MUST NOT accept native ether as payment for Shares (§6.3.1). 3. The role semantics of §3 MUST remain enforceable for the lifetime of the Agent: `owner()` MUST always report the current admin, and `execute` MUST always enforce the Executor check (§6.6.1), the `DELEGATECALL` prohibition (§6.6.2), and the `isInScope` gate (§6.6.7). #### 6.2 Reasoned agent actions Certain functions are **agent actions**: state-changing calls the Executor makes on the Agent's behalf — `settleMint`, `settleRedeem`, `execute`, and any implementer-defined agent-facing function. Each standard agent action carries `bytes32 reasoningHash` and `string reasoningURI`: 1. `reasoningHash` MUST be non-zero and MUST equal `keccak256(b)`, where `b` is the exact byte string `reasoningURI` resolves to. 2. `reasoningURI` MUST be non-empty and MUST resolve to that content at the time of the action. Deferred reveal is not supported; for private-then-public reasoning use a content-addressed scheme (`ipfs://`, `ar://`) and publish before or at action time. 3. `reasoningURI` follows the Agent URI conventions of §6.5 (schemes; content-addressed RECOMMENDED). It SHOULD resolve to a UTF-8 JSON document carrying an envelope marker `"schema": "fat-reasoning/1"`; consumers MUST ignore unknown fields. Domain fields (`model`, `prompt`, `inputs`, `trace`, `decision`, …) are implementer-defined. 4. The reasoning MUST be anchored in the action's standard event (`Settled` for settlement, `Executed` for `execute`). Implementer-defined agent functions SHOULD emit `Reasoned`. 5. Reasoning is a tamper-evident audit trail, not an enforced guarantee: it proves a reasoning record was committed and unaltered, not that the action followed from it (see [Security Considerations](#security-considerations)). #### 6.3 Share minting (two-phase: `requestMint` → `mint`) 1. `requestMint(amount)` MUST pull exactly `amount` of `acceptToken()` from `msg.sender` via [ERC-20](./eip-20.md) `transferFrom`. It MUST NOT accept native ether. If the Accept Token is a fee-on-transfer or rebasing token, the amount actually received MAY differ from `amount`; an Agent that supports such tokens MUST document how it reconciles a requester's `pendingAssets` with the balance actually received, and an Agent that does not MUST document that fee-on-transfer / rebasing Accept Tokens are unsupported. 2. `requestMint` MUST add `amount` to the caller's pending mint balance and emit `MintRequested(msg.sender, amount, epoch, block.timestamp)`, where `epoch` is the Agent's current settlement epoch (§2; MAY be `0`). Requests are not individually addressed; a requester's pending deposits are tracked in aggregate and reported by `queryMintStatus` as `pendingAssets`. 3. When and how pending deposits become claimable — operator fulfilment, a time delay, a NAV/epoch close, liquidity becoming available — is implementer-defined and outside the scope of this specification (§7). 4. Settlement of a requester's pending mint is performed by an Executor calling `settleMint(requester, reasoningHash, reasoningURI)`, carrying reasoning per §6.2. It settles some, all, or none of the requester's `pendingAssets` into `claimableShares` (settling none = reject/defer; the request stays pending or is refunded via the optional cancellation path of §6.4.6). The formula mapping the settled deposit to `shares` (price/quota/accept) is implementer-defined and computed inside `settleMint`; it MAY retain an Owner fee out of the deposit (whether a fee is charged, and its magnitude and destination, are implementer-defined, §7). Because the amount is computed by contract logic rather than supplied by the caller, the Executor cannot mint an arbitrary amount. On settlement the resulting `shares` MUST be fixed, and `queryMintStatus(requester)` MUST reflect the settled amount moving from `pendingAssets` to `claimableShares`. `settleMint` MUST emit `Settled(requester, 0, shares, reasoningHash, reasoningURI)`. An Agent whose `exchangeRate()` changes at settlement SHOULD emit `ExchangeRateUpdated`. Per-request settlement is intentional — it enables the Executor to apply KYC, risk, or differentiated pricing to each requester — and settlement gas scales with the number of requests; implementations MAY add an implementer-defined batch wrapper to amortize this cost. 5. `mint(user)` MAY be called by any address (a permissionless claim crank); it MUST mint `user`'s entire claimable-share balance to `user`, MUST zero that balance, and MUST emit `SharesMinted(user, assets, shares, epoch, sharePrice, block.timestamp)` (fields per §5). Because the payout always goes to `user` (the owed party), the caller gains nothing and no authorization is required. It takes no slippage guard: the `shares` were already fixed at settlement (item 4), so the claim merely collects what `user` is owed and `mint(user)` MUST NOT revert on the settled amount. If `user` has nothing claimable, `mint(user)` returns `0`. #### 6.4 Share redemption (two-phase: `requestRedeem` → `redeem`) 1. `requestRedeem(shares)` MUST pull (escrow) exactly `shares` of the Share token from `msg.sender` into the Agent and add them to the caller's pending redeem balance. 2. `requestRedeem` MUST emit `RedeemRequested(msg.sender, shares, epoch, block.timestamp)`, where `epoch` is the Agent's current settlement epoch (§2; MAY be `0`). Requests are not individually addressed; a requester's pending escrowed shares are tracked in aggregate and reported by `queryRedeemStatus` as `pendingShares`. 3. When and how pending escrowed shares become claimable is implementer-defined and outside the scope of this specification (§6.3.3, §7). An Agent that cannot yet satisfy a redemption (e.g., all Accept Token is deployed to external protocols) simply leaves the shares pending until liquidity allows settlement; this two-phase flow is the protocol's deferred-liquidity mechanism. The protocol does NOT mandate any particular settlement timing, queue, or buffer; the Requester's worst case is bounded instead by the reclaim-or-disclose requirement of item 6. 4. Settlement of a requester's pending redeem is performed by an Executor calling `settleRedeem(requester, reasoningHash, reasoningURI)`, carrying reasoning per §6.2. It settles some, all, or none of the requester's `pendingShares` into `claimableTokens` (settling none = reject/defer; the request stays pending or is refunded via the optional cancellation path of §6.4.6), burning the settled Shares (in aggregate at settlement or at the corresponding claim). The formula mapping `shares` to `tokens` is implementer-defined and computed inside `settleRedeem`; it MAY retain an Owner fee (whether a fee is charged, and its magnitude, are implementer-defined, §7). Because the amount is computed by contract logic rather than supplied by the caller, the Executor cannot pay out an arbitrary amount. On settlement the resulting `tokens` MUST be fixed, and `queryRedeemStatus(requester)` MUST reflect the settled amount moving from `pendingShares` to `claimableTokens`. `settleRedeem` MUST emit `Settled(requester, 1, tokens, reasoningHash, reasoningURI)`. An Agent whose `exchangeRate()` changes at settlement SHOULD emit `ExchangeRateUpdated`. As with minting (§6.3.4), per-request settlement is intentional (KYC / risk / differentiated pricing) and settlement gas scales with the number of requests; implementations MAY add an implementer-defined batch wrapper to amortize this cost. 5. `redeem(user)` MAY be called by any address (a permissionless claim crank); it MUST transfer `user`'s entire claimable-token balance of `acceptToken()` to `user`, MUST zero that balance, and MUST emit `SharesRedeemed(user, shares, tokens, epoch, sharePrice, block.timestamp)` (fields per §5). Because the payout always goes to `user` (the owed party), the caller gains nothing and no authorization is required. It takes no slippage guard: the `tokens` were already fixed at settlement (item 4), so the claim merely collects what `user` is owed and `redeem(user)` MUST NOT revert on the settled amount. If `user` has nothing claimable, `redeem(user)` returns `0`. 6. **Reclaim-or-disclose.** So that the worst case of a pending request is legible to Holders and integrators (e.g., lending protocols modeling Shares as collateral), an Agent MUST do at least one of the following: - provide a **reclaim path**: a requester-callable function through which the Requester recovers their still-pending deposited Accept Token (mint) and still-pending escrowed Shares (redeem) once a disclosed horizon has elapsed since their most recent request. The function signature and the horizon are implementer-defined, but both MUST be disclosed via the `reclaim` metadata field (§6.5.3). Because the reclaim returns the deposit / the escrowed Shares themselves, it requires no settlement liquidity and MUST remain executable for still-pending balances regardless of the Agent's deployment state; or - **disclose irrevocability**: declare via the `reclaim` metadata field (`"reclaim": "none"`, §6.5.3) that requests, once submitted, cannot be withdrawn by the Requester. A reclaiming or expiring Agent MUST return still-pending balances only — already-settled (claimable) balances are unaffected — and SHOULD define its own reclaim/cancellation event. Beyond this floor, richer cancellation and expiry / TTL mechanisms remain implementer-defined (§7). 7. While balances are pending, the deposited Accept Token (mint) sits in the Agent and the escrowed Shares (redeem) are held but not yet burned. How these in-flight balances are accounted for in `exchangeRate()` / NAV during the pending window is implementer-defined (§7); implementations SHOULD document their treatment so valuation is unambiguous. **Detecting an outstanding claim.** A caller (e.g., a frontend) determines whether a separate `mint` / `redeem` call is still needed by reading `queryMintStatus(user)` / `queryRedeemStatus(user)`: a positive `claimableShares` / `claimableTokens` means a claim is available to collect now; a positive `pendingAssets` / `pendingShares` means settlement is still pending (claim later); both zero means nothing is outstanding (already claimed, or never requested) (§6.3.3, §6.4.3). #### 6.5 Agent URI 1. `agentURI()` MUST return the current URI string for the Agent. An Agent MAY be deployed with an initial empty string (`""`); Owners SHOULD set a non-empty URI before public use. 2. `setAgentURI(uri)` MUST be callable only by Owner and MUST emit `AgentURIUpdated(uri)`. 3. The URI SHOULD resolve to a UTF-8 JSON document. Consumers MUST ignore unknown fields. The document SHOULD include at minimum: ```json { "name": "string, human-readable Agent name", "description": "string, short description of the Agent", "image": "string, URI for a representative image", "external_url": "string, optional — project homepage or dossier", "reclaim": "\"none\", or { \"horizon\": seconds, \"method\": \"function signature\" } — reclaim-or-disclose per §6.4.6", "properties": { "key": "implementation-defined free-form fields" } } ``` 4. The URI scheme SHOULD be one of `ipfs://`, `https://`, `ar://`, or a `data:application/json;base64,…` URI for fully on-chain metadata. Agents MUST NOT require a particular scheme; consumers MUST accept any well-formed URI. Implementers SHOULD prefer a reference URI (`ipfs://`, `ar://`, `https://`) over a large `data:` URI so that update gas stays bounded; a content-addressed scheme (`ipfs://`, `ar://`) is RECOMMENDED where immutability of a given metadata revision matters. 5. Because `setAgentURI` is Owner-controlled and mutable, consumers SHOULD treat the URI as untrusted input and SHOULD surface URI change history via `AgentURIUpdated`. #### 6.6 Executor dispatch 1. `execute` MUST revert unless `msg.sender` is a currently-enabled Executor. 2. Implementations MUST NOT dispatch `execute` via `DELEGATECALL`. Delegatecall would grant the target full access to the Agent's storage — executor set, ownership slot, Share balances, Agent URI — and defeat the Agent's storage safety regardless of any higher-level policy the implementer layers on top. The default dispatch MUST be the plain EVM `CALL` opcode; an implementation MAY expose a separate `STATICCALL`-based read path under a different function name if desired, but the normative `execute` semantics are `CALL`. 3. If the underlying call fails, the Agent MUST bubble the revert data unchanged to the caller. 4. `value` MUST be transferred from the Agent's own balance; the Executor MUST NOT be required to send ether with the transaction. 5. Beyond the Executor check (§6.6.1), the `DELEGATECALL` prohibition (§6.6.2), and the `isInScope` gate (§6.6.7), the protocol imposes NO further normative restriction on `target` or `data`. Implementations MAY impose additional restrictions — target allowlists, function-selector filters, parameter filters, session keys, signed-policy enforcement, external policy contracts, rate limiters, circuit breakers, etc. — but any policy beyond those three requirements is **not** part of the standard and MUST NOT be relied upon by integrators as protocol guarantees. Integrators assessing an Agent's operational safety SHOULD inspect the concrete implementation and the Executor's operational posture. 6. `Executed` MUST be emitted only on a successful underlying call. A failed call reverts (§6.6.3) and emits no event; integrators therefore cannot observe failed Executor attempts through `Executed` and MUST rely on the reverted transaction itself for that signal. 7. `execute` MUST call `isInScope(target, value, data)` before dispatching and MUST revert if it returns `false`. The predicate's logic (target allowlist, per-asset caps, scenario rules, external policy contract, rate limits, …) is implementer-defined; the standard fixes only that the hook exists and is enforced. `isInScope` is a required `view` and doubles as an off-chain audit query. 8. Whatever backs `isInScope` (allowlist, caps, policy address) MUST be configurable only by the Owner (or Owner-designated governance) — NEVER by the Executor. The Agent operates within a boundary it cannot widen. Scope-configuration changes SHOULD emit an implementer-defined event. #### 6.7 Owner role 1. `owner()` MUST return the address currently authorized to invoke the Owner-gated functions defined by this specification (`setExecutor`, `setAgentURI`, and any finer-grained additions by the implementation). 2. The mechanism by which ownership is transferred — single-step, two-step, multisig rotation, governance-contract binding, or none at all — is outside the scope of this standard. Implementations MAY offer any such mechanism or none. Implementations that support ownership transfer SHOULD emit an event upon each change so that indexers can track the Owner over time; the exact event signature is implementer-defined. 3. Implementations MAY additionally expose a pause mechanism, granular per-function gating, guardian roles, Executor restriction policies, or other governance surface. These are out of scope for this standard; see §7. #### 6.8 Reentrancy (security consideration) 1. `execute` inevitably calls untrusted external code, so reentrancy is the most prominent risk this standard introduces. Implementations SHOULD protect all user-facing state-mutating entry points — `requestMint`, `mint`, `requestRedeem`, `redeem`, `execute`, and admin setters — so that a malicious external target cannot reenter them to operate on a stale exchange rate or in-flight request state (e.g. via reentrancy guards or the checks-effects-interactions pattern). This is a security recommendation, not a conformance requirement; integrators SHOULD verify an Agent's reentrancy posture in its concrete implementation (§6.6.5). 2. Read-only reentrancy into view functions (`isExecutor`, `queryMintStatus`, `queryRedeemStatus`, `exchangeRate`, [ERC-20](./eip-20.md) `balanceOf`) is not forbidden; implementers SHOULD ensure any values exposed by views are consistent with the Agent's post-transaction invariants. ### 7. What the protocol does NOT specify The following are explicitly out of scope. Implementations MAY choose any behavior consistent with the interface and MUST document their choices: - The share pricing formula for `mint` and the share-to-token conversion formula for `redeem`. - Whether `mint` or `redeem` levy an Owner fee, and its magnitude. - Whether Shares are transferable. A compliant Agent MAY override [ERC-20](./eip-20.md) transfers to restrict, pause, or tax them. Such restrictions MUST NOT block the lifecycle this standard itself requires: the redeem escrow pull of §6.4.1, the settlement burn, the claim mint of §6.3.5, and any cancellation return of escrowed Shares (§6.4.6) must always remain possible. - The **pricing/quota/accept logic computed inside settlement**, and **when** an Executor chooses to settle. Settlement itself is now a standardized agent action — `settleMint` / `settleRedeem` (§6.3 / §6.4) — so *whether* settlement is a standard operation is fixed, not implementer-defined. What remains implementer-defined is the pricing/quota/accept formula computed inside it (how much of a pending deposit / escrowed share becomes claimable, and at what price) and the Executor's timing in calling it — operator fulfilment, time delay, NAV/epoch close, liquidity availability. - The **reasoning-record fields and format beyond the §6.2 envelope** — the domain fields inside the JSON that a `reasoningURI` resolves to (model, prompt, trace, tool calls, scores, etc.). §6.2 fixes only the envelope (the on-chain `reasoningHash` binding, a non-empty resolvable URI, the `"schema"` marker, and ignore-unknown-fields), not the record's contents. - **Request cancellation** and **request expiry / TTL** (including any `deadline` parameter) beyond the §6.4.6 reclaim-or-disclose floor — the reclaim function's signature, its horizon, and any associated cancellation/expiry event. - **Batched / epoch-aggregated settlement** of multiple requests. - **Slippage / price protection on the settled outcome.** The claim (`mint` / `redeem`) is unconditional and accepts the settlement price implicitly — it carries no slippage guard, because the share count / payout is fixed at settlement, well before the claim, and a claim-time guard could only block the caller from collecting what they are already owed (it cannot refund the deposit). Any protection against an unfavorable settlement price — a max-price / min-rate honored by the settlement mechanism, a cancellation path before settlement, etc. — is implementer-defined. - Any other additional exit mechanics — fixed redemption windows, lockup periods, withdrawal-fee tiers, minimum-balance rules, etc. - Whether `exchangeRate()` is constant (fixed-price Agent) or varies over time (NAV-based Agent). - Whether and how Holders realize returns beyond what the exchange rate already reflects — a separate dividend / reward / yield-claim channel, periodic Merkle distributions, NFT vouchers, etc. — is fully implementer-defined. - **The Scope policy content enforced by `isInScope`** — which targets, function selectors, parameters, per-asset caps, rate limits, or scenarios the Owner-configured Scope allows, and how it is expressed (allowlists, session keys, signature-based pre-authorization, on-chain policy contracts, off-chain policy enforcers, etc.) — is implementer-defined. What is **not** implementer-optional: `execute` is no longer a fully unconstrained dispatch primitive — the standard requires the `isInScope` gate (§6.6.7), mandates that `execute` enforce it (reverting when it returns `false`), and requires its configuration to be Owner-controlled only, never Executor-settable (§6.6.8). The existence, enforcement, and Owner-control of the gate are fixed by the standard; only the policy the gate encodes is layered on top by the implementation. - Whether the Agent supports multiple Executors, rotating Executors, session-key-style delegation, or signature-based (meta-transaction) Executor calls. - **Any meta-transaction / signature-based wrapper** that lets a relayer submit requests or Executor calls on a user's behalf (e.g., signed intents or meta-transaction forwarders). The standard defines only the direct-`msg.sender` semantics of each function; a relayer/forwarder layer MAY be added on top but is not part of this standard. - **Whether and how the Agent is upgradeable** — proxy upgradeability, contract migration, or full immutability — is implementer-defined. An upgradeable Agent SHOULD document the upgrade authority and its constraints. - **Whether Owner-gated functions are subject to a timelock or delay.** The protocol does not mandate any delay on `setExecutor`, `setAgentURI`, or other admin actions; implementations MAY add one. - The Agent URI metadata schema beyond the mandatory minimum in §6.5.3. - **Whether and how the Agent can be paused** — granular per-function pausing, global pause, time-locked pause, guardian-controlled pause, or no pause at all — is fully implementer-defined. - **The ownership-transfer mechanism** — single-step, two-step, renounceable, bound to a governance contract, or non-transferable — is fully implementer-defined. The protocol only requires that `owner()` report the current admin. - **Whether and how the Agent exposes an emergency asset-rescue ("sweep") mechanism** — its function signature, who can call it (Owner only, Owner + Guardian, dual-key), whether it can touch the Accept Token or Share token, whether it is timelocked or rate-limited, and which assets it can move — is fully implementer-defined. Agents that accumulate airdrops, wrong-token sends, or dust SHOULD document their recovery story; Agents designed for full immutability MAY deliberately omit any rescue path. - **Whether the Agent exposes atomic batched executor dispatch** (often named `executeBatch` or `multicall`) is implementer-defined. Contract-wallet Executors already achieve atomicity by bundling multiple `execute` calls inside their own transaction; EOA Executors that need batching can use a minimal adapter contract configured as the Executor. Implementations that add their own batch primitive remain compliant as long as each sub-call still passes the same `onlyExecutor` check and `DELEGATECALL` prohibition defined by `execute` in §6.6. ## Rationale **Why settlement is a reasoned agent action — the litmus test of this standard's agency.** A contract that merely books deposits is a container; a contract that makes an explicit decision on every contribution and exit, and must sign a reasoning record for that decision, is an actor. Making the agent's reaction (`settleMint` / `settleRedeem`) an explicit, standardized operation — instead of an opaque implementer step — makes the economic decision legible, attributable, and indexable. Because the settled amount is computed by contract logic inside the call rather than supplied by the caller, the Executor cannot mint or pay out an arbitrary amount. **Why a two-phase request-then-claim lifecycle instead of synchronous mint/redeem.** An Agent's capital is typically deployed into external protocols, so a deposit cannot always be priced — and a redemption cannot always be paid — in the same transaction it is requested. The two-phase flow lets a requester commit first and claim once the Agent has settled (priced the deposit, or freed the liquidity), which is the protocol's deferred-liquidity mechanism. Even an instant Agent settles via a separate, prompt Executor `settleMint` / `settleRedeem` transaction rather than inside `requestMint` — settlement is always an explicit reasoned agent action (see below). **Why there is no delegation or operator model.** The standard keeps per-requester accounting to a single address — the one that opens the request — and pays every claim out to that same owed address. A full delegation model — where a third party could open requests for a user, or redirect a claim to a different recipient — is deliberately left out to keep the interface minimal. What the standard *does* allow without any authorization is a permissionless claim (next point), which covers the common "let someone else finalize my claim" need; what is left out is redirection — paying a claim to a recipient other than the owed party — because that would require the owed party's authorization. **Why `mint` / `redeem` take an `address` and MAY be called by anyone.** The two-phase design forces a second transaction to collect a settled claim. Making that claim a permissionless crank — `mint(user)` / `redeem(user)` callable by any address but always paying the owed `user` — lets keepers, dApps, or the Agent operator finalize claims and sponsor gas, with no authorization needed: since the payout can only go to the owed party, an arbitrary caller gains nothing by calling it. Opening a request stays self-only, because `requestMint` / `requestRedeem` move the caller's own funds or Shares and so cannot be done for another address without authorization. **Why `mint` / `redeem` take no slippage parameter.** The share count (mint) and payout (redeem) are fixed at settlement, which happens before the claim. A claim-time slippage guard could therefore only block a requester from collecting what they are already owed — it could not refund the original deposit. Protection against an unfavorable *settlement* price (a max-price/min-rate honored by the settlement mechanism, or a pre-settlement cancellation path) is the meaningful place for such guards and is left to the implementer (§7). **Why `exchangeRate()` is a valuation reference, not a trade predictor.** Separating valuation from execution lets fixed-price and NAV-based Agents share one interface, and lets tooling value holdings without implying that a mint/redeem will settle at that rate. Actual settled outcomes are reported by `queryMintStatus` / `queryRedeemStatus`. **Why reentrancy protection is a recommendation, not a conformance requirement.** This standard fixes an interface, not an implementation technique; mandating a specific reentrancy-protection mechanism would over-constrain implementers. The risk is real (§6.8), so it is documented as a strong recommendation and surfaced in [Security Considerations](#security-considerations), and integrators are directed to verify each Agent's concrete posture. (Whether to restore a conformance-level MUST is an open design question for the standard's editors.) **Why a single immutable Accept Token.** Fixing the unit of account at deployment makes share pricing and redemption unambiguous and lets every Agent be valued and exited through one legible path. **Why `execute` is a thin primitive gated by three invariants.** Policy is separated from interface: the standard guarantees the `onlyExecutor` check, the `DELEGATECALL` prohibition, and the mandatory `isInScope` gate (§6.6.7), and every further layer of confinement (allowlists, selector filters, session keys, policy contracts) is composed on top by the implementer. This keeps the behavior layer itself standard while leaving its safety envelope — the concrete Scope policy included — to each Agent. **Why reasoning is a hash plus a resolvable URI, published now.** Anchoring `keccak256` of the reasoning on-chain makes the record tamper-evident; requiring a non-empty, immediately-resolvable `reasoningURI` keeps it discoverable. Deferred reveal is unnecessary: a content-addressed scheme (`ipfs://`, `ar://`) lets an agent commit the CID before publishing, so private-then-public reasoning needs no protocol machinery. **Why `execute` enforces an `isInScope` hook rather than a fixed scope shape.** Standardizing the enforcement point (every spend passes a predicate) — not the policy (what the predicate allows) — gives teeth without locking the scope representation. Because `isInScope` is a required `view`, integrators get boundary auditability for free. **Why the Scope is Owner-only and settlement never happens inside `requestMint`.** If the Executor could widen its own Scope, the boundary would be meaningless, so Scope config is Owner-only. And every settlement must be an attributable reasoned agent action, so the standard does not permit settling inside `requestMint` — settlement is always a separate `settleMint` / `settleRedeem` call. ## Backwards Compatibility FAT is a new standard and has no backwards-compatibility constraints. It composes orthogonally with: - **[ERC-20](./eip-20.md)** — required for the Share token. - **[ERC-165](./eip-165.md)** — implementers MUST advertise FAT support via [ERC-165](./eip-165.md) (`supportsInterface`), using the XOR of the function selectors in §4, so that indexers, wallets, and composing contracts get a protocol-level discoverability guarantee. The canonical interface ID will be fixed when this spec leaves Draft. Agents SHOULD NOT attempt to "conform" to FAT by implementing a subset of the interface; partial conformance is defined as non-conformance for the purposes of this standard. ## Security Considerations This section catalogs the risks inherent to a FAT Agent so that implementers and integrators can weigh and disclose them. Except where it restates a normative requirement from §6, it is advisory: it describes considerations and recommended disclosures rather than adding new conformance requirements. **Executor is a highly trusted role, bounded only by its Scope.** At the protocol layer `execute` is gated by the Executor check (§6.6.1), the `DELEGATECALL` prohibition (§6.6.2), and the Owner-set `isInScope` gate (§6.6.7). Within its Scope an enabled Executor can move every asset the Agent holds and grant any approval on its behalf. Integrators MUST treat "is a FAT Agent" as carrying no guarantee about what the Executor may do *within that Scope*, and SHOULD assess the concrete Scope policy (allowlists, selector/parameter filters, session keys, policy contracts), who can change it (§6.6.8), and the Executor's operational posture (key custody, automation) before trusting an Agent. **Role concentration and insider self-dealing.** The §3 roles may all be held by one address. Concentrating Owner and Executor in a single key gives it unilateral control over the Agent's assets, executor set, and metadata — the maximal-trust configuration for any external Holder. Separately, an Executor or Owner that also holds Shares or opens requests has an incentive to use its privileges — `execute`-driven NAV moves, or discretion over settlement timing — to favor its own position over other Holders (a special case of the front-running and settlement-timing risks below). Agents intended for external capital SHOULD separate these privileged roles (e.g., a multisig Owner, a distinct Executor, timelocked admin actions) and SHOULD disclose the separation — or its absence — in the Agent URI metadata. **Reentrancy.** `execute` calls untrusted external code, so reentrancy is the most prominent risk the standard introduces. §6.8 recommends protecting all user-facing state-mutating entry points (e.g., via reentrancy guards or checks-effects-interactions) and warns about read-only reentrancy into view functions. Because §6.8 is a recommendation rather than a conformance requirement, integrators SHOULD verify an Agent's reentrancy posture in its concrete implementation; a wrong assumption here has historically led to large losses across DeFi. **Settlement front-running.** When an Agent settles in aggregate (e.g., at a single batch/NAV price), a party who learns the upcoming settlement price can front-run it: `requestMint` just before a favorable NAV update to capture upside at the stale price, or `requestRedeem` just before an unfavorable one to exit at the stale price — in both cases at the expense of existing Holders. Implementers SHOULD mitigate with one of: (1) a settlement price that is not observable until commit-reveal / on-chain oracle / time-lock resolves it; (2) separation of the request window from the settlement window (request cutoff precedes price determination); or (3) prompt per-request settlement — the Executor settles each request in its own `settleMint`/`settleRedeem` call with no aggregation window. **Settlement-timing centralization.** §6.3.3 / §6.4.3 leave the settlement trigger to the implementer. If that trigger is concentrated in the Owner or Executor, that party can choose *when* to settle and thereby transfer value between minters and redeemers (settling redemptions at a low NAV, mints at a high NAV, or vice versa) — effectively an implicit fee channel. Agents SHOULD disclose the settlement-trigger mechanism (automatic, periodic, Owner-manual, oracle-driven, …) and its timing-discretion risk in the Agent URI metadata. **Implicit acceptance of the settlement price.** Because the claim (`mint` / `redeem`) carries no slippage guard, a Requester accepts whatever price the Agent fixes at settlement, with the decision made after the request is submitted (§6.3, §6.4, §7). This is a different trust model from synchronous, slippage-guarded swaps: at request time the Requester is trusting the Agent's settlement mechanism. Any protection against an unfavorable settlement price (a max-price/min-rate honored at settlement, or a pre-settlement cancellation path) is implementer-defined. **Stranded pending requests.** While balances are pending, a requester's deposited Accept Token (mint) sits in the Agent and their escrowed Shares (redeem) are held but not yet burned. If settlement never triggers — the Owner abandons the Agent, the Executor key is lost, or the contract is bricked — those balances would be stranded with no claim path, and for a pending mint the requester is not even a Holder. §6.4.6 therefore requires every Agent to either provide a requester-callable reclaim path after a disclosed horizon, or machine-readably disclose that requests are irrevocable. Integrators SHOULD read the `reclaim` metadata field before modeling a Share's exit: an Agent that discloses `"none"` has a discretionary lockup and is correspondingly harder to price as collateral. **Agent URI is mutable and untrusted.** `setAgentURI` is Owner-controlled (§6.5.5), so metadata — including any disclosures referenced above — can change at any time. Consumers SHOULD treat the URI as untrusted input and surface its change history via `AgentURIUpdated`. **Accept Token assumptions.** Exact-amount accounting (§6.3.1) assumes a standard [ERC-20](./eip-20.md). Fee-on-transfer and rebasing Accept Tokens can break that assumption; an Agent either supports them with documented reconciliation or documents that it does not (§6.3.1). **Reasoning is descriptive, not enforced.** `reasoningHash`/`reasoningURI` prove that the Executor committed a reasoning record and that it was not tampered with — not that the reasoning is sound or that the action actually followed from it. Integrators treat reasoning as an audit trail, not a guarantee. **Scope is only as tight as `isInScope`.** A permissive predicate gives weak bounds. Auditors SHOULD exercise `isInScope` across the intended target set and check who can change the Scope configuration (it MUST be Owner-only, §6.6.8) before trusting an Agent's spending boundary. **Reasoning availability.** Because deferred reveal is unsupported, a `reasoningURI` that fails to resolve (dead link, unpinned content) breaks after-the-fact audit even though the on-chain `reasoningHash` still stands. Content-addressed, pinned storage (`ipfs://`, `ar://`) is RECOMMENDED. ## Copyright Copyright and related rights waived via [CC0](../LICENSE.md).