Skip to content

Overview

Contract Architecture

The Royal Protocol uses a gateway-registry pattern that separates policy from data storage. This enables flexible governance while maintaining data integrity.

Core Pattern

Each major system (Identities and Provenance) consists of two contracts:

  • A Registry contract that stores the data and enforces fundamental rules.
  • A Gateway contract that contains the authorization logic and policy decisions.

Loading graph...

graph TD
   User[User/Application]
   Gateway[Gateway Contract]
   Registry[Registry Contract]

   User -->|Writes| Gateway
   Gateway -->|Validated Changes| Registry
   User -->|Reads| Registry

The Registry only accepts changes from its designated Gateway, creating a clear security boundary. The Gateway handles all policy decisions like:

  • Fee structures
  • Authorization rules
  • Delegation validation
  • Gas sponsorship via signatures

Key Systems

Identity System

  • IdRegistry: Stores user identities and core relationships
  • IdGateway: Manages registration, transfers, and recovery

Provenance System

  • ProvenanceRegistry: Stores creation claims and NFT relationships
  • ProvenanceGateway: Handles claim registration and verification

Delegation Registry

A shared component that enables permission delegation between Royal IDs. This powers key features like automated registration and gas sponsorship.

Upgradeability

This separation serves a practical purpose with regards to upgradeability πŸ”—:

  • Registries store critical data and rarely need updates
  • Gateways contain policy logic that may need adjustment as the protocol evolves

All contracts are upgradeable, but Gateway upgrades are expected to be more common to adapt to community needs while Registry upgrades would only address critical issues.

Specific contracts

ContractSource codeContract on BaseContract on Base Sepolia
IdRegistrySolidity πŸ”—Base πŸ”—Base Sepolia πŸ”—
IdGatewaySolidity πŸ”—Base πŸ”—Base Sepolia πŸ”—
ProvenanceRegistrySolidity πŸ”—Base πŸ”—Base Sepolia πŸ”—
ProvenanceGatewaySolidity πŸ”—Base πŸ”—Base Sepolia πŸ”—
DelegateRegistrySolidity πŸ”—Base πŸ”—Base Sepolia πŸ”—

The data systems

There are two data systems in the Royal Protocol: Royal ID and ProvenanceClaim. In both cases, the data is stored in a registry contract, and can only be manipulated by a gateway contract.

Loading graph...

graph LR
   User@{ shape: rounded }
   subgraph Onchain
      Gateway@{ shape: rounded, label: "Gateway - authorization logic"}
      Registry@{ shape: rounded, label: "Registry - data store"}
   end

Gateway == Commands ==> Registry
User == Writes ==> Gateway
User -- Queries --> Registry
Registry -- Data --> User
User x-. Commands .-x Registry

The registry contract stores the data.

The registry has the address of its gateway, and will refuse requests to change data from any other source.

The gateway contract contains the authorization logic and policy parameters (fees, etc.). This logic is more likely to change in the future, so it is best to leave it as a separate contract to let it be upgraded independently.

Delegate registry

Additionally, there is a delegation registry contract that is inspired by the delegate.xyz delegation code πŸ”—. The delegation system is based on Royal IDs instead of addresses as the user identifier.

Gas sponsorship

There are two roadblocks to onboarding users who are not used to crypto.

  • Wallet installation
  • The need to hold ETH to initiate transactions

While the method of wallet installation may vary depending on the application layer (for example a self-custody or custodial wallet), all users must have a wallet in some form to interact with the protocol. However, protocol costs (user registration, content registration, address changes, etc.) don’t need to be paid directly in ETH. For example, a content creation tool could bundle registriation with the other services it provides. Gas sponsorship allows users to delegate transaction costs to a third party, while still keeping the authorization with the users’ wallets.

  1. The user specifies what to do on the web application.
  2. The web application asks the user to sign an EIP-712 πŸ”— message with the appropriate parameters.
  3. The user signs the request in the wallet (or through a smart wallet). Signing a request does not cost anything.
  4. The wallet sends the signature back to the website.
  5. The website sends the request, along with the signature, in an Ethereum transaction to the appropriate gateway contract. This costs money, but at present the cost is usually less than a cent.
  6. The gateway contract verifies the signature before it forwards the request to the registry.

Almost all the public facing functions in the Royal Protocol come with a ...For version to enable this functionality.

You can see this process illustrated in the create Royal ID flow.

How do we prevent signature abuse?

A potential problem with this pattern is that web sites can ask for a signature, and then instead of submitting the transaction immediately keep the signature, and submit it at a different time with results the user does not expect. To avoid this problem, all Royal Protocol signatures include a deadline beyond which they are no longer valid.

Additionally, users have a nonce (basically, a counter) on their signatures. A user can submit a protocol transaction using a different service, and that invalidates any previously signed, but unused, signature. Users can also issue a transaction πŸ”— to increase their nonce, invalidating any unused signature they created. Note that nonces are tracked separately between IdGateway and ProvenanceGateway, so to invalidate all unused Royal Protocol signatures a user needs to issue this transaction to both contracts.