Abstract
This EIP defines a Permissioned Authorization Object (PPO): an EIP-712 typed struct describing a bounded, revocable permission to pull tokens from a grantor.
A PPO is:
- signed off-chain by the grantor,
- specifies the grantee, token, per-call cap, time window, and nonce,
- portable across chains and executors that adopt the same type,
- revocable prior to execution by invalidating the nonce.
It does not prescribe how transfers are executed; that is defined by a separate EIP ("Permissioned Pull", ERC-8102).
Motivation
Today, ERC-20 and related standards lack a canonical primitive for fine-grained pull permissions.
We have:
transfer— one-shot pushapprove/transferFrom— persistent allowance, but:- often infinite,
- not time-bounded,
- not natively portable across chains,
- approvals live in token contract state (harder to audit/rotate)
permit(EIP-2612) — signed approvals, but tightly coupled to token contracts
What is missing is a chain-agnostic, revocable authorization object that:
- encodes bounded consent in a single signed payload,
- can be verified by any compliant executor contract,
- is easy for wallets and AA stacks to reason about,
- can be revoked before use,
- composes with any ERC-20 token without requiring token changes.
This EIP specifies such an authorization struct and its hashing rules, so that:
- executors (ERC-8102) can implement a common verification model,
- registries and wallets can expose and revoke PPOs consistently,
- systems can build higher-level coordination (subscriptions, automation) on a shared authorization primitive.
Specification
EIP-712 Type Definition
The canonical type for a Permissioned Authorization Object is:
Authorization(
address grantor,
address grantee,
address token,
uint256 maxPerPull,
uint256 validAfter,
uint256 validBefore,
bytes32 nonce
)Where:
grantor: address providing consent (token owner).grantee: address allowed to initiate pulls under this authorization.token: ERC-20 token address.maxPerPull: maximum number oftokenunits that may be pulled per execution.validAfter: unix timestamp (seconds) from which this authorization becomes valid (inclusive).validBefore: unix timestamp (seconds) after which this authorization is no longer valid (exclusive).nonce: unique value chosen by the grantor for replay protection.
TYPEHASH (normative)
The canonical AUTH_TYPEHASH MUST be:
bytes32 public constant AUTH_TYPEHASH = keccak256(
"Authorization(address grantor,address grantee,address token,uint256 maxPerPull,uint256 validAfter,uint256 validBefore,bytes32 nonce)"
);Struct Hash (normative)
Given:
struct Authorization {
address grantor;
address grantee;
address token;
uint256 maxPerPull;
uint256 validAfter;
uint256 validBefore;
bytes32 nonce;
}The struct hash MUST be computed as:
function _authStructHash(Authorization memory a) internal pure returns (bytes32) {
return keccak256(
abi.encode(
AUTH_TYPEHASH,
a.grantor,
a.grantee,
a.token,
a.maxPerPull,
a.validAfter,
a.validBefore,
a.nonce
)
);
}The EIP-712 digest is then:
bytes32 digest = keccak256(
abi.encodePacked(
"\x19\x01",
domainSeparator,
_authStructHash(auth)
)
);where domainSeparator is as defined in EIP-712 by the verifying contract (typically the executor contract specified in ERC-8102).
Revocation Model
This EIP defines requirements on revocation semantics but does not prescribe storage layout. Implementations MAY use:
- local per-executor storage, and/or
- a shared registry contract, and/or
- wallet-maintained revocation maps.
Normative requirements:
-
Grantors MUST be able to revoke any unused
nonceprior to execution. -
Executors MUST check revocation status at execution time according to the mechanism adopted by the executor (e.g., local cancellation and/or shared registry).
-
Executors MUST reject revoked or canceled nonces.
Recommended events (names are illustrative):
event AuthorizationGranted(
address indexed grantor,
address indexed grantee,
address indexed token,
bytes32 nonce
);
event AuthorizationRevoked(
address indexed grantor,
bytes32 indexed nonce
);Wallets and registries MAY emit these upon signing or revoking PPOs.
Nonce Semantics
nonceMUST be treated as single-use in the context of a given grantor and domain separator.- Implementations SHOULD treat
(grantor, nonce)as a unique pair. - Nonce consumption MUST be race-safe: an executor MUST mark the nonce as used before or atomically with any external calls (e.g., token transfers).
Domain Binding
This EIP intentionally separates:
- the authorization object (defined herein), and
- the execution domain (ERC-8102, pull executor).
Domain binding is achieved in ERC-8102 by including the executor’s domainSeparator() in the EIP-712 digest.
This prevents signatures from being replayed across executors with different domains.
Executor Verification Requirements
Executors verifying PPOs MUST:
- enforce validity windows (
validAfter,validBefore) before execution, - enforce EIP-2 signature constraints (low-
s, validv), - bind verification to their own domain separator.
Rationale
- Separation of concerns: This proposal defines “what is consent?” while ERC-8102 defines “how is consent executed?”. This keeps wallets, AA stacks, and registries decoupled from any specific executor implementation.
- Stateless across chains:
maxPerPulland time windows keep each execution stateless; cumulative limits can be built on top, but are not required at the primitive level. - Nonce as bytes32: Allows flexible schemes (per-grantee, per-token, per-policy) while remaining compatible with simple counter-based patterns.
Backwards Compatibility
- Compatible with any ERC-20 token; no token changes required.
- Orthogonal to EIP-2612; PPOs are a different authorization path (pull-by-consent vs “permit as approve”).
Security Considerations
The rules required for safe execution are specified normatively in the Specification section. This section discusses implications:
- Revocation must be checked at execution time to avoid race conditions between revoke and pull.
- Wallet UX should make nonce scope and domain binding clear to users.
- Grantors should protect signing keys; leaked signatures remain valid until expiry or revocation.
Copyright
Copyright and related rights waived via CC0.
