AGENT_OKRW_TRANSFER_LIMIT_POLICY
Per-transaction OKRW transfer cap for agent wallets — the limit is read from the agent's on-chain TransferLimit metadata, and applies both when the agent is the direct sender and (globally) when the agent is the initiating principal.
Caps a single OKRW transfer originating from an agent wallet using a limit stored as on-chain metadata on the ERC-8004 IdentityRegistry — specifically getMetadata(agentId, "TransferLimit"). The policy struct itself has no configurable fields; the cap is whatever the agent's owner has written into the metadata slot. The evaluator attributes the transfer to the agent both when the agent is the direct msg.sender and, under global-scope policies, when the agent is the initiating principal forwarded by the PCL proxy hook — so a contract that pulls funds from an agent principal still hits the same cap. If the resulting attributed value exceeds the configured TransferLimit, the transaction reverts with ExceededAgentTransferLimit(maxLimit, value).
Parameter struct
AgentOkrwTransferLimitPolicy carries a single reserved field that the chain ignores. Encode zero and move on:import { AgentOkrwTransferLimitPolicy, PolicySet } from "@maroo-chain/contracts/precompiles/pcl/IPcl.sol";
AgentOkrwTransferLimitPolicy memory p = AgentOkrwTransferLimitPolicy({ reserved: 0 });
PolicySet memory ps = PolicySet({
templateId: "AGENT_OKRW_TRANSFER_LIMIT_POLICY",
policy: abi.encode(p),
selector: ""
}); Where the limit comes from
0x8004000000000000000000000000000000000001. Look up the numeric string keyed by "TransferLimit" — the value is an OKRW amount denominated in aokrw (18-decimal base units, so 10,000,000 OKRW = 10000000000000000000000000 aokrw). The agent's owner writes it via the IdentityRegistry's metadata setter. If the metadata slot is missing or invalid, the evaluator reverts with the plain string reason "invalid agent transfer limit metadata" (or "invalid agent transfer limit metadata: <reason>") — which is not a decodable typed error.Who is attributed the transfer
- Direct sender: the agent wallet itself calls a function that moves OKRW out (typical MAWS flow).
- Global-scope principal: a contract performs the outbound transfer, but the PCL proxy hook has forwarded the initiating principal (the wallet that entered the regulated path). When that principal is the agent, the global-scope evaluation still attributes the transfer to the agent.
Under contract-scope evaluation, only the direct sender attribution applies — contract-scoped policies do not re-attribute to the principal for this template.
Failure semantics
TransferLimit, the transaction reverts with the typed custom error ExceededAgentTransferLimit(uint256 maxLimit, uint256 value). Decode it client-side to display the offending amount and the configured cap:import { decodeErrorResult } from "viem";
import { pclAbi } from "./abis";
try {
await wallet.writeContract({ /* agent-initiated OKRW transfer of 10_000_000 OKRW */ });
} catch (err: any) {
if (err?.data) {
const decoded = decodeErrorResult({ abi: pclAbi, data: err.data });
if (decoded.errorName === "ExceededAgentTransferLimit") {
const [maxLimit, value] = decoded.args as [bigint, bigint];
console.error(`agent transfer limit exceeded: max=${maxLimit} value=${value}`);
}
}
} Composing with other caps
PolicyConfig.policies array — for example, add DENYLIST_POLICY to block sanctioned counterparties and OKRW_EAS_PERIODIC_VOLUME_LIMIT_POLICY to enforce a 10,000,000 OKRW / 24 h regulatory reporting threshold on un-attested transfers. Because each PolicySet is evaluated independently, a single agent-initiated transfer of 10,000,000 OKRW can be rejected either by its agent metadata cap or by an unrelated periodic volume cap — whichever fires first.