Installing the Rayls SDK

Prerequisites

The SDK must be installed in a project targeting a Rayls Privacy Node \u2014 an EVM-compatible chain with a Rayls endpoint smart contract configured.

If you have any questions, contact us here.


Installation

# npm
npm install @rayls/contracts

# pnpm
pnpm add @rayls/contracts

Current version: 2.6.3-nightly.2

All contracts must use the fixed pragma:

pragma solidity 0.8.24;

What the SDK provides

The SDK is a set of abstract Solidity contracts you inherit to build tokens and cross-chain apps on Rayls Privacy Nodes:

ContractPurpose
RaylsAppBase for all cross-chain apps — provides _raylsSend and _raylsSendToResourceId
RaylsErc20HandlerERC20 token with teleport support
RaylsErc721HandlerERC721 NFT with teleport support
RaylsErc1155HandlerERC1155 multi-token with teleport support
RaylsEnygmaHandlerEnygma settlement token with batch cross-chain transfers and DvP
RaylsErc721DvpHandlerERC721 DvP asset-leg handler
RaylsErc1155DvpHandlerERC1155 DvP asset-leg handler

See Building using Rayls SDK for the full contract reference.


Setting up a token

Extend RaylsErc20Handler and pass all required params to the parent constructor:

// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import "@rayls/contracts/tokens/RaylsErc20Handler.sol";

contract MyToken is RaylsErc20Handler {
    constructor(
        string memory _name,
        string memory _symbol,
        address _endpoint,
        address _raylsNodeEndpoint,
        address _userGovernance,
        address _owner
    )
        RaylsErc20Handler(
            _name,
            _symbol,
            _endpoint,
            _raylsNodeEndpoint,
            _userGovernance,
            _owner,
            false   // isCustom: false for standard tokens
        )
    {
        // optional: mint initial supply
        // _mint(msg.sender, 1_000_000 * 10 ** 18);
    }
}

The constructor parameters:

ParameterDescription
_endpointPrivacy Node endpoint for cross-PN messaging
_raylsNodeEndpointEndpoint for Public Chain bridging
_userGovernanceRBAC contract for user roles within the PN
_ownerAddress granted the Owner role (mint, burn)

Token registration

After deploying, call registerToken on the Privacy Node's TokenRegistryReplica system contract:

TokenRegistryReplica.registerToken(tokenAddress, ErcStandard.ERC20, false)

Once the Private Hub operator approves it, the relayer calls receiveResourceId() on your contract automatically. After that, teleport functions are ready to use.


Minting tokens

// Owner role only — also notifies the Private Hub's TokenRegistry
function mint(address to, uint256 value) public virtual restricted

mint and burn are protected by restricted (role-based access control). The Owner role is granted to the address passed as _owner at deployment.

Access control: Rayls uses RaylsAccessManaged instead of Ownable. Privileged functions use the restricted modifier, which checks roles via the Privacy Node's RaylsAccessManagerV1. There is no onlyOwner in the current SDK.


Teleporting tokens

Vanilla teleport (VT20)

Burns on source, mints on destination. No revert mechanism.

function teleport(address to, uint256 value, uint256 chainId) public virtual returns (bool)

Atomic teleport (AT20)

Tokens are locked on destination until confirmed. If the destination fails, the relayer reverts and returns tokens to sender.

function teleportAtomic(address to, uint256 value, uint256 destinationChainId) public virtual returns (bool)

Sending arbitrary messages

For custom cross-chain logic that doesn't involve tokens, extend RaylsApp directly:

// 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) {}

    function sendGreeting(uint256 destChainId, address destContract, string memory _msg) external {
        _raylsSend(
            destChainId,
            destContract,
            abi.encodeWithSignature("receiveGreeting(string)", _msg)
        );
    }

    // In production: mark restricted and register selector under MESSAGE_EXECUTOR
    function receiveGreeting(string memory _msg) public {
        message = _msg;
    }
}

The sender deploys this contract on their Privacy Node, the receiver deploys it on theirs. The sender calls sendGreeting with the receiver's chain ID and contract address. The relayer delivers the payload and calls receiveGreeting on the receiver.

Security: Receive functions should be marked restricted in production so only the Rayls relayer (MESSAGE_EXECUTOR role) can invoke them. See RaylsApp for details.


What’s Next