RaylsApp
RaylsApp is the base contract for all cross-chain applications running in a Rayls Sovereign ledger. It provides the messaging primitives (_raylsSend, _raylsSendToResourceId) and the access control foundation used by every handler contract.
Inheritance: abstract contract. Extend it directly for custom arbitrary-message apps; token handlers inherit it transitively.
Constructor
constructor(
address _endpoint,
address _raylsNodeEndpoint,
address _userGovernance
)| Parameter | Description |
|---|---|
_endpoint | Endpoint in the Rayls Sovereign ledger, routing messages to other institutions through the Private Network Hub |
_raylsNodeEndpoint | Endpoint for the Rayls Public Chain, used when bridging to and from the public chain |
_userGovernance | RBAC contract that manages user roles and permissions within the Rayls Sovereign ledger |
Cross-chain messaging
_raylsSend, send by address
_raylsSend, send by addressfunction _raylsSend(
uint256 _dstChainId,
address _destination,
bytes memory _payload
) internal virtualSends a message to a specific contract address on another chain. Use it where you know the destination contract address.
_dstChainId, the destination chain ID, whether that is another institution's ledger or the Public Chain_destination, the contract address to call on the destination chain_payload, the ABI-encoded function call, for exampleabi.encodeWithSignature("myFunction(address,uint256)", to, amount)
_raylsSendToResourceId, send by resource ID
_raylsSendToResourceId, send by resource IDfunction _raylsSendToResourceId(
uint256 _dstChainId,
bytes32 _resourceId,
bytes memory _payload
) internal virtualRoutes by resourceId rather than by address. Use it where you do not know the exact contract address on the destination chain, since the endpoint resolves the address through the resource registry.
Atomic variant, with lock/revert payloads
function _raylsSendToResourceId(
uint256 _dstChainId,
bytes32 _resourceId,
bytes memory _payload,
bytes memory _lockData,
bytes memory _revertDataPayloadSender,
bytes memory _revertDataPayloadReceiver,
BridgedTransferMetadata memory transferMetadata
) internal virtualUsed by token handlers for atomic teleports. The extra payloads execute where a transfer has to be reverted, with _revertDataPayloadSender running on the source chain and _revertDataPayloadReceiver on the destination.
Access control
Rayls handlers use role-based access control (RaylsAccessManaged) rather than a single-owner pattern, and roles are enforced by the shared RaylsAccessManagerV1 in the Rayls Sovereign ledger.
The restricted modifier checks whether the caller holds the required role for that function selector:
modifier restricted() {
_checkCanCall(msg.sender, msg.sig);
_;
}Where the caller does not hold the role, the call reverts with RaylsAccessManaged__Unauthorized.
Standard roles
| Role | Who holds it | Typical functions |
|---|---|---|
| Owner | The institution that deployed the token | mint, burn, submitTokenUpdate |
| MESSAGE_EXECUTOR | The Rayls relayer | Cross-chain receive callbacks (receiveTeleport, receiveResourceId, unlock, etc.) |
| RELAYER | The Rayls relayer (DVP handlers and Enygma) | dvpSwapCompleted, crossMint, crossRevertMint, etc. |
Roles are registered automatically when a handler is deployed, through _registerAccessControl(address _owner) inside the constructor, so there is no manual role configuration for standard handlers.
onlyRegisteredUsers modifier
onlyRegisteredUsers modifiermodifier onlyRegisteredUsers()Restricts a function to callers registered with the user governance contract (_userGovernance) in the Rayls Sovereign ledger. It is used on teleportToPublicChain so that only approved users can bridge to the public chain.
Token registration lifecycle
After deploying any token handler, call registerToken on the TokenRegistryReplica system contract in the Rayls Sovereign ledger:
// Call on the TokenRegistryReplica system contract (not on your token)
TokenRegistryReplica.registerToken(
address tokenAddress,
SharedObjects.ErcStandard ercStandard,
bool isCustom
)This sends a cross-chain message to the TokenRegistry on the Private Network Hub. Once the Private Network Operator approves the registration, the relayer calls receiveResourceId() on your token contract automatically:
// Present in all handlers — called by the relayer after approval
function receiveResourceId(bytes32 _resourceId) public virtual restricted {
resourceId = _resourceId;
_registerResourceId(); // maps resourceId → address(this) on the endpoint
}Registration can be verified by reading the public resourceId variable, where a non-zero value means the token is registered. Teleport functions then work automatically once the registration message has been received.
Minimal custom cross-chain app
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
import "@rayls/contracts/RaylsApp.sol";
contract HelloWorldContract is RaylsApp {
string public message;
constructor(
address _endpoint,
address _raylsNodeEndpoint,
address _userGovernance
) RaylsApp(_endpoint, _raylsNodeEndpoint, _userGovernance) {}
// Send a greeting to a contract on another Rayls Sovereign
function sendGreeting(uint256 destChainId, address destContract, string memory _msg) external {
_raylsSend(
destChainId,
destContract,
abi.encodeWithSignature("receiveGreeting(string)", _msg)
);
}
// Receive a greeting — restrict to MESSAGE_EXECUTOR in production
function receiveGreeting(string memory _msg) public {
message = _msg;
}
}Important: In production, receive functions should be marked
restrictedand their selectors registered under theMESSAGE_EXECUTORrole, so that only the Rayls relayer can invoke them.
Updated 11 days ago
