EAS_POLICY
Require the transaction sender to hold a valid EAS attestation under a specified schema. The KYC/KYB enforcement gate.
Gates a transaction on whether the sender holds a valid (non-expired, non-revoked) attestation issued under a specific EAS schema. The canonical primitive for KYC, KYB, accreditation, and any credential-based gate. Resolves attestations through the chain's x/eas module, which reads the EAS and Indexer contracts with view calls wherever PCL evaluates the policy — before execution, during execution (in the PCL preCall / postCall hooks or the policy-aware Privacy precompile), or after execution.
Solidity struct + ABI
From
IPcl.sol:struct EasPolicy {
address easContract; // EAS deployment to query
address indexContract; // EAS Indexer (powers O(1) reverse lookups)
bytes32 schemaUid; // schema the sender must have an attestation under
} ABI tuple shorthand:
Encode for
(address easContract, address indexContract, bytes32 schemaUid).Encode for
PolicySet.policy:import {
EasPolicy, PolicySet, LogicalPolicy, ForEachPolicy, LogicalQuantifier, ForEachQuantifier,
ForEachSubject, VolumePolicy, VolumeUnitPolicy, PeriodicVolumePolicy, UnitPeriodicVolumePolicy,
ContractPolicyConfig, GlobalPolicyConfig, DenylistPolicy
} from "@maroo-chain/contracts/precompiles/pcl/IPcl.sol";
EasPolicy memory ep = EasPolicy({
easContract: 0x1000000000000000000000000000000000000007, // EAS preinstall
indexContract: 0x1000000000000000000000000000000000000008, // EAS Indexer preinstall
schemaUid: 0x5f3a2b0e1d5c9a7f6e3b4a1d2c8f7b6a5e4d3c2b1a0f9e8d7c6b5a4938271605 // your KYC schema UID
});
bytes memory policyBytes = abi.encode(ep);
// PolicySet.templateId = "EAS_POLICY" The
easContract and indexContract addresses are typically the canonical Maroo preinstalls — you can resolve them at deploy time via the EAS precompile's getParams() instead of hard-coding.Evaluation
For each transaction it evaluates, PCL checks the sender:
1. Asks the EAS Indexer (
2. Rejects if the Indexer lists none:
3. Fetches that attestation from the EAS contract and validates it:
- lookup fails? →
- revoked? →
- expired (
4. Otherwise → admit. Only that most recently indexed attestation is checked: if it is revoked or expired, an older valid one does not admit the sender — issue and index a new one.
1. Asks the EAS Indexer (
indexContract) for the most recently indexed attestation the sender has received under schemaUid. Only indexed attestations count: a plain EAS attest does not index itself, so after attesting, call the Indexer's indexAttestation(uid) (open to any caller; isAttestationIndexed(uid) confirms it), unless the schema's resolver indexes attestations as they are made.2. Rejects if the Indexer lists none:
EasNoAttestationReceived(sender).3. Fetches that attestation from the EAS contract and validates it:
- lookup fails? →
EasAttestationLookupFailed(sender)- revoked? →
EasAttestationRevoked(sender)- expired (
expirationTime != 0 && expirationTime <= now)? → EasAttestationExpired(sender)4. Otherwise → admit. Only that most recently indexed attestation is checked: if it is revoked or expired, an older valid one does not admit the sender — issue and index a new one.
ReasonCodes on rejection
EasNoAttestationReceived(address sender)— the EAS Indexer lists no attestation the sender received under this schema: none was issued, or it was issued but never indexed.EasAttestationRevoked(address sender)— they had one, but it was revoked.EasAttestationExpired(address sender)— they had one, but it has expired.EasAttestationLookupFailed(address sender)— the attestation the Indexer listed could not be read fromeasContract; check that the policy names the right EAS contract.
EasAttestationRequired(address sender) is declared in the same error set, but EAS_POLICY does not raise it.Wallet UX: route the user to the appropriate KYC/KYB onboarding partner. Once a fresh attestation is issued and indexed in the EAS Indexer, the same transaction succeeds.
Typical usage
- KYC gate at the global level (
GlobalPolicyConfig): "only KYC-attested accounts may use the regulated path". - Higher-tier features: a
ContractPolicyConfigrequiring an institutional KYB schema for DeFi pool access. - Tiered models: put
EAS_POLICYand aVOLUME_POLICYcap under oneLOGICAL_POLICYwith theOrquantifier, so attested senders pass and un-attested ones are held to the cap — typically more useful than a hard yes/no gate. The testnet's own global policy works this way: without an attestation, a transaction is capped at 2,000,000 OKRW.