Masque the disguise
Identity & attestation
A Masque is the on-chain credential that binds an agent to a principal. It is a PDA, so its existence and state are universally verifiable — any merchant, relayer, or peer agent can check whether a payer's Masque is active without calling any server.
Account shape
#[account]
pub struct Masque {
pub principal: Pubkey, // issuer — 32
pub agent: Pubkey, // holder — 32
pub scope_hash: [u8; 32], // off-chain scope policy digest
pub issued_at: i64,
pub expires_at: i64,
pub revoked_at: i64, // 0 = active
pub revocation_reason: u8,
pub action_count: u64,
pub reputation: u32, // bounded 0..=10_000
pub last_action_at: i64,
pub last_action_hash: [u8; 32],
}Lifecycle
Every Masque moves through this graph. The revoked state is terminal — there's no un-revoke. Principals issue a new Masque to rotate keys.
issue
[ ∅ ] ───────► [ active ]
│
┌────────┼─────────┐
│ │ │
attest rotate revoke
(N×) scope (terminal)
│ │ │
└────────┘ ▼
[ revoked ]Instructions
issue
Principal signs. Creates the PDA, sets expiration, initializes reputation to 100.
await masque.methods
.issue(agentPubkey, scopeHash, lifespanSeconds)
.accounts({ masque: masquePda, principal, systemProgram })
.rpc();attest
Agent signs. Records a 32-byte action digest and bumps reputation. Fails if the Masque is revoked or expired. The hash is arbitrary: typically the hash of the x402 descriptor that was settled, so the attestation graph indexes directly to real payment events.
await masque.methods
.attest(actionHash)
.accounts({ masque: masquePda, agent })
.signers([agentKeypair])
.rpc();revoke
Principal-only. Sets revoked_at = now. From the next slot, every downstream program checks this field and refuses. Reason codes are open-vocabulary (suggested: 1=rotation, 2=compromise, 3=misbehavior, 4=lifecycle end).
await masque.methods
.revoke(2) // reason: compromise
.accounts({ masque: masquePda, principal })
.rpc();Reputation
Reputation starts at 100 and gains +1 per attested action, capped at 10,000. It's intentionally simple at the protocol level. Sophisticated reputation markets (weighted by merchant category, settlement size, peer attestations) run off-chain on top of the Masque attestation stream — the chain stores the raw integrity signal and lets builders layer what they need.
Events emitted
#[event] pub struct MasqueIssued { principal, agent, expires_at }
#[event] pub struct ActionAttested { agent, action_hash, reputation }
#[event] pub struct MasqueRevoked { principal, agent, reason, at }Helius webhooks or any geyser plugin can surface these in real time to feed downstream reputation or fraud systems.