Skip to Content
ConnectSmart contractsCredential lifecycle

Credential lifecycle

A credential is not a token. It is an entry in KeyringCore’s storage: an expiration timestamp for a (policyId, entity) pair, plus a blacklist flag. Nothing is minted and nothing is transferable.

createCredential;issuer-signed, paidblock.timestamp < expand not blacklistedtime passesblock.timestamp >= expIssuedValidExpiredblacklistEntityreversibleBlacklistedre-issue extends exp
Nothing is minted: a credential is an expiry timestamp for a (policyId, entity) pair plus a blacklist flag.

Issuance

After a successful verification, the extension hands the app a CredentialData object whose fields map directly onto createCredential(tradingAddress, policyId, chainId, validUntil, cost, key, signature, backdoor). The transaction pays cost in native units (msg.value must match exactly), and the issuer signature binds every parameter, including the chain ID.

The backdoor bytes accompany the credential on chain and are emitted with CredentialCreated. They contain the regime-encrypted identity described in Learn: credentials; the contract stores no identity data itself.

Validity

  • A credential is valid while block.timestamp < exp and the entity is not blacklisted.
  • Re-issuing extends exp; a new credential’s validUntil must exceed the current one. Validity windows are set by the policy, so different policies produce different credential durations.
  • Expiry is passive. Nothing needs to be revoked or cleaned up; checks simply begin returning false.

Frontends can read entityExp(policyId, entity) to warn holders ahead of expiry and route them through a refresh, which for an unexpired attestation does not require a new proof (see tracking state).

Revocation and blacklisting

Two mechanisms end a credential early:

  • Blacklisting (blacklistEntity) is policy-scoped and reversible. While blacklisted, an entity fails every check for that policy and cannot be issued a new credential.
  • Issuer key revocation (revokeKey) invalidates the issuing key for future credentials. Existing credentials keep their stored expirations.

Cost

The cost parameter is set per credential by the issuing policy and paid at creation. Fees accumulate in the contract; the operator role withdraws them with collectFees(recipient). A cost of zero is rejected.

Chain scoping

createCredential requires chainId == block.chainid, and the chain ID is inside the signed message. A credential is therefore only ever valid on the chain it was issued for; multi-chain apps run one verification per chain, and each chain’s gate reads its own deployment.

Last verified on