Smart contracts in the Rayls Sovereign ledger

Overview

A Rayls Sovereign ledger arrives with a set of contracts already deployed. They fall into two families according to what they communicate with: the contracts that carry traffic to other institutions through the Private Network Hub, and the contracts that carry traffic directly to a public chain.

This page is the inventory and the design patterns. For the interface of any individual handler, see the handler pages in the Developer Reference, beginning with Rayls ERC-20 Handler.


Contracts for the Private Network path

EndpointV1

The entry point for all cross-chain communication with the Private Network Hub. It dispatches outgoing messages to other institutions, executes incoming messages, manages message identifiers so that a message cannot be replayed, and appends the EIP-5164 context to the call data.

Its principal operations are send() to dispatch a message, receivePayload() to process an incoming message, and isExecuted() to check whether a message has already been processed.

Registry replicas

Local copies of the Private Network Hub registries, kept in step through cross-chain messages, so that the Rayls Sovereign ledger can validate locally without querying the Hub on every operation.

TokenRegistryReplicaV1 syncs token data from the Hub token registry, tracks freeze status for compliance, maps resource identifiers to local token addresses, and validates tokens before a cross-chain operation begins.

ParticipantStorageReplicaV1 syncs participant data from the Hub participant storage, holds the public keys used for encryption, enables local participant validation, and updates automatically when a participant joins or changes.

Token handlers

Each handler processes cross-chain token operations for one token standard or one protocol.

HandlerBehaviour
RaylsErc20HandlerBurns on the source and mints on the destination, supporting both standard and atomic teleports
RaylsErc721HandlerLocks or burns the NFT on the source and mints with the same token identifier on the destination, preserving metadata
RaylsErc1155HandlerBatch transfers of multiple token types, burning on the source and minting on the destination
RaylsEnygmaHandlerPrivacy-preserving transfers with hidden amounts, working with zero-knowledge proofs
RaylsErc721DvpHandlerDeposits NFTs into DvP escrow and participates in atomic cross-chain swaps
RaylsErc1155DvpHandlerThe ERC-1155 equivalent, supporting batch deposits and withdrawals

The handlers are implemented as abstract contracts in the protocol SDK, which is why an institution's own token contract extends a handler rather than calling one.


Contracts for the public chain path

The RN-prefixed contracts handle the one-to-one path between the Rayls Sovereign ledger and a single public chain. They are covered in Connecting Rayls Sovereign to the Rayls Public Chain, and in summary they comprise RNEndpointV1 for coordination, RNMessageDispatcherV1 and RNMessageExecutorV1 for the EIP-5164 dispatcher and executor pair, RNContractFactoryV1 for deterministic deployment, and RNTokenGovernanceV1 and RNUserGovernanceV1 for token and user governance on that path.


Design patterns

EIP-5164 cross-chain execution

Both paths implement EIP-5164. The dispatching side calls dispatchMessage with the destination chain, the recipient contract and the encoded call, and the executing side calls executeMessage with the target, the call data, the message identifier, the source chain and the original sender. The endpoint appends 84 bytes of context to the call data, comprising a 32-byte message identifier, a 32-byte source chain identifier and a 20-byte sender address. Receiving contracts extract that context through helper functions, behind a modifier that restricts the receiving function to the endpoint.

Upgradeability

Production contracts use the UUPS upgradeable proxy standard, inheriting Initializable and UUPSUpgradeable, with upgrade authorisation gated by the access manager. The proxy holds state and the implementation holds logic, so an upgrade changes behaviour without losing state.

Deterministic addresses

RNContractFactoryV1 deploys using CREATE2, which produces the same contract address across chains and is what allows a token to be addressed consistently wherever it appears.

Modular facades and contract size

Complex contracts delegate to specialised modules behind a top-level facade. Part of the reason is the 24 KB code size limit that applies on the Private Network Hub and on public chains. The Rayls Sovereign ledger client raises that limit well above the Ethereum default, but contracts destined for the Hub or a public chain are engineered to 24 KB regardless, so the modular pattern is not optional for them.

Resource identifiers

Tokens are identified network-wide by 32-byte resource identifiers, which keep the same asset consistent across chains and enable automatic token mapping. A token receives its resourceID when it is registered and approved in a Rayls Private Network, as described in Registering a token within a Private Network.


Access control

Authorisation is centralised rather than distributed through per-contract modifiers.

RaylsAccessManagerV1 is the central authority. It owns all authorisation state: the roles, who holds them, which function maps to which role, the managed-contract configuration and any scheduled operations. RaylsAccessManaged is the abstract base that consumer contracts inherit, and it provides a single restricted modifier that delegates every decision back to the manager.

The practical consequence is that no consumer contract stores role information, so adding a role, changing who can call what, or pausing a contract are administrative transactions against the manager, with no recompilation and no redeployment.

Each chain deploys its own independent manager with its own role registry, so a role identifier in one institution's ledger has no relationship to a role identifier in another's, and the Rayls Sovereign ledger's manager is separate from the Private Network Hub's.

Roles fall into three categories.

  • Built-in roles are compile-time constants: ADMIN, the superuser and the only role with implicit permission inheritance; PUBLIC, a function-level marker that makes a function callable by anyone and that cannot be granted to an address; and TOKEN_OWNER, granted contract-scoped to a token deployer so that it controls that token's owner functions and no others.
  • Infrastructure roles are registered during deployment and are required for the protocol to operate, including ENDPOINT_SENDER, RELAYER, FACTORY_ADMIN and the message executor and receiver roles, with variations by chain.
  • Business roles can be activated at runtime through administrative transactions with no Solidity changes, and include institution-level personas such as PRIVACY_NODE_OPERATOR, BANK_EMPLOYEE, AUDITOR, COMPLIANCE_OFFICER and ANALYST, alongside third-party integration roles such as COMPLIANCE_TOOL, CUSTODY_MANAGER and TOKENIZER.

The hierarchy uses an administers relationship rather than permission inheritance, so if role A administers role B then A can grant and revoke membership in B without itself being able to call B's functions. Only ADMIN inherits permissions.

Roles are global by default, and the manager also supports target-scoped grants, so a role can be bound to one specific contract rather than to every contract of that kind.


Tooling

The contracts are written in Solidity 0.8.24, targeting the Paris EVM with the optimiser enabled. The build uses Hardhat with Forge underneath, and Foundry and forge-std for testing. OpenZeppelin contracts and contracts-upgradeable provide the upgradeable base, poseidon-solidity provides zero-knowledge-friendly hashing, and ethers v6 with TypeChain provides typed bindings.


Did this page help you?