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.valueequalscostexactly, andcostis non-zero and fitsuint128chainIdequalsblock.chainid, which blocks cross-chain replay- the issuer
signatureverifies over the packed message via the configured signature checker validUntilis 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_ROLEBlacklisting 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.