AGENT_OKRW_TRANSFER_LIMIT_POLICY
Per-tx OKRW transfer cap for agent wallets, with the limit read from on-chain agent metadata (TransferLimit) — no policy parameters.
Caps a single OKRW transfer made by an agent wallet using a limit value 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 put in metadata. Skipped for non-agent senders. Used to bound how much value an agent (an automated key) can move per transaction without holding it back from human-controlled accounts.
Solidity struct & ABI tuple
From
IPcl.sol:// Limit is enforced from agent "TransferLimit" metadata only. Solidity disallows
// empty structs; `reserved` is ignored by the chain (callers may pass 0).
struct AgentOkrwTransferLimitPolicy {
uint256 reserved;
} ABI tuple shorthand:
Encode for
(uint256 reserved).Encode for
PolicySet.policy:AgentOkrwTransferLimitPolicy memory p = AgentOkrwTransferLimitPolicy({
reserved: 0 // ignored — present only because Solidity forbids empty structs
});
bytes memory policyBytes = abi.encode(p);
// PolicySet.templateId = "AGENT_OKRW_TRANSFER_LIMIT_POLICY" The per-agent limit is not in the policy. It's set by writing a 32-byte uint256 into IdentityRegistry metadata under key
"TransferLimit" for that agent ID.How the policy is evaluated
For each native OKRW transfer:
1. Look up the agent IDs registered to the sender's wallet (via the Agent precompile /
2. If the sender owns no agent IDs → skip (this template is a no-op for non-agent wallets).
3. For each owned agent ID, read
4. The effective cap is the minimum across all agent IDs the wallet owns (most restrictive wins).
5. If
Non-OKRW assets are skipped — this template only meters the native denom.
1. Look up the agent IDs registered to the sender's wallet (via the Agent precompile /
x/agent index).2. If the sender owns no agent IDs → skip (this template is a no-op for non-agent wallets).
3. For each owned agent ID, read
IdentityRegistry.getMetadata(agentId, "TransferLimit") and parse it as a 32-byte uint256.4. The effective cap is the minimum across all agent IDs the wallet owns (most restrictive wins).
5. If
value > cap → reject with ExceededAgentTransferLimit(maxLimit, value).Non-OKRW assets are skipped — this template only meters the native denom.
Rejection reason codes
ExceededAgentTransferLimit(uint256 maxLimit, uint256 value)— agent'sTransferLimitmetadata enforced. Wallet UX: "this agent's per-transaction cap is X; raise the cap from the owner's account, or use a different signer".AgentTransferLimitMetadataInvalid(string reason)— the metadata exists but isn't a parseable 32-byte uint256, or is empty when the policy expected a value. Almost always a setup bug; surface to the operator, not the end user.AgentKeeperRequired()— internal: PCL was invoked without the agent keeper wired in (chain misconfiguration).
Setting the limit
The cap is configured per-agent on the IdentityRegistry, not per-policy:
// from the agent owner's wallet
IIdentityRegistry registry = IIdentityRegistry(0x8004000000000000000000000000000000000001);
// 1,000,000 OKRW cap, encoded as 32-byte big-endian uint256
bytes32 limit = bytes32(uint256(1_000_000 ether));
registry.setMetadata(agentId, "TransferLimit", abi.encodePacked(limit)); Clearing the metadata (or setting it to zero) means the agent has no transfer limit enforced by this template — but other policies (
OKRW_EAS_TRANSFER_LIMIT_POLICY, VOLUME_POLICY) still apply if registered.Typical usage
- Agent budget caps: agent wallet for an automated trading or treasury bot, capped at e.g. 10,000,000 OKRW per transfer so a compromised key can't drain the principal in one tx.
- Owner-controlled tuning: the cap moves with metadata, so the human owner can dial it up or down without going through PCL governance.
- Combine with
OKRW_EAS_PERIODIC_VOLUME_LIMIT_POLICYfor a per-tx + cumulative-period two-layer guard on agent wallets.