Skip to Content

KeyringCore reference

KeyringCore is the on-chain credential registry. It stores, per (policyId, entity) pair, an expiration and a blacklist flag, and it accepts new credentials whose issuer signature verifies against a registered key. Solidity 0.8.22, OpenZeppelin 5.2.0, deployed behind a UUPS proxy.

Data model

struct EntityData { bool blacklisted; uint64 exp; // credential expiration timestamp } struct KeyEntry { bool isValid; uint64 validFrom; uint64 validTo; // issuer key validity window }

Credential creation

function createCredential( address tradingAddress, uint256 policyId, uint256 chainId, uint256 validUntil, uint256 cost, bytes calldata key, bytes calldata signature, bytes calldata backdoor ) external payable;

createCredential enforces, in order:

  • msg.value equals cost exactly, and cost is non-zero and fits uint128
  • chainId equals block.chainid, which blocks cross-chain replay
  • the issuer signature verifies over the packed message via the configured signature checker
  • validUntil is in the future and greater than the entity’s current expiration (credentials only ever extend)
  • the entity is not blacklisted for the policy

On success it stores the new expiration and emits CredentialCreated(policyId, entity, exp, backdoor). Fees accumulate in the contract and are withdrawable by the operator role. In the normal Connect flow this call is made with parameters handed over by the extension (CredentialData in the SDK reference).

Signature checking

Signature verification is delegated to a pluggable ISignatureChecker, chosen once at initialization. The choice decides how every credential signature is proven authentic, so it matters to anyone deploying or auditing a KeyringCore instance: a deployment with the wrong checker accepts forged credentials.

RSASignatureChecker
PKCS#1 v1.5 SHA-256 RSA signatures via the modexp precompile; the key parameter is the RSA modulus.
EIP191SignatureChecker
personal_sign ECDSA; the key parameter is the expected signer address.
AlwaysValidSignatureChecker
Accepts everything except a sentinel; development only.

The signed message packs tradingAddress, policyId, block.chainid, validUntil, cost, and the backdoor bytes. A signature therefore commits to every credential parameter on one specific chain, and cannot be replayed for a different entity, policy, or chain. This is the same guarantee createCredential enforces by rejecting any chainId other than block.chainid.

Roles

DEFAULT_ADMIN_ROLE
Manage roles, reinitialize on upgrade.
KEY_MANAGER_ROLE
Register and revoke issuer keys.
BLACKLIST_MANAGER_ROLE
Blacklist and unblacklist entities.
OPERATOR_ROLE
Collect accumulated fees.
UPGRADER_ROLE
Authorize UUPS upgrades.

Key registry

Issuer keys are registered with a validity window and revoked by hash:

function registerKey(uint256 validFrom, uint256 validTo, bytes memory key) external; // KEY_MANAGER_ROLE function revokeKey(bytes32 keyHash) external; // KEY_MANAGER_ROLE function keyExists(bytes32 keyHash) external view returns (bool); function keyValidTo(bytes32 keyHash) external view returns (uint256); function keyDetails(bytes32 keyHash) external view returns (KeyEntry memory); function getKeyHash(bytes calldata key) external pure returns (bytes32);

Blacklist

function blacklistEntity(uint256 policyId, address entity) external; // BLACKLIST_MANAGER_ROLE function unblacklistEntity(uint256 policyId, address entity) external; // BLACKLIST_MANAGER_ROLE

Blacklisting zeroes the entity’s expiration and makes every checkCredential answer false for that policy until the entity is unblacklisted and issues a new credential.

Events

event KeyRegistered(bytes32 indexed keyHash, uint256 indexed validFrom, uint256 indexed validTo, bytes publicKey); event KeyRevoked(bytes32 indexed keyHash); event CredentialCreated(uint256 indexed policyId, address indexed entity, uint256 indexed exp, bytes backdoor); event CredentialRevoked(uint256 indexed policyId, address indexed entity); event EntityBlacklisted(uint256 indexed policyId, address indexed entity); event EntityUnblacklisted(uint256 indexed policyId, address indexed entity);

Errors

error ErrAddressZero(); error ErrInvalidSignatureChecker(); error ErrAlreadyInitialized(); error ErrInvalidKeyRegistration(string reason); error ErrKeyNotFound(bytes32 keyHash); error ErrFailedSendOfValue(); error ErrInvalidCredential(uint256 policyId, address entity, string reason); error ErrCostNotSufficient(uint256 policyId, address entity, string reason); error PolicyOverflows();

Upgrades

KeyringCore follows the UUPS pattern; only UPGRADER_ROLE can authorize a new implementation, and the implementation tracks an internal version with a reinitialize step gated to the admin role.

Last verified on