RaylsErc721DvpHandler

RaylsErc721DvpHandler is the abstract base contract for ERC721 NFTs that participate in cross-chain Delivery vs. Payment (DvP) swaps on a Rayls Privacy Node. The seller deposits an NFT and initiates a swap offering it in exchange for Enygma tokens from a buyer on a different Privacy Node.

Inheritance: RaylsApp, ERC721, Initializable, ReentrancyGuard, RaylsAccessManaged

See Privacy Node Internal DvP for the full cross-chain DvP flow overview.


Minimal implementation

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

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

contract MyDvpNFT is RaylsErc721DvpHandler {
    constructor(
        string memory _uri,
        string memory _name,
        string memory _symbol,
        address _endpoint,
        address _raylsNodeEndpoint,
        address _userGovernance,
        address _owner
    )
        RaylsErc721DvpHandler(
            _uri,
            _name,
            _symbol,
            _endpoint,
            _raylsNodeEndpoint,
            _userGovernance,
            _owner,
            false
        )
    {}
}

Constructor parameters

ParameterDescription
_uriBase URI for token metadata
_nameERC721 collection name
_symbolERC721 collection symbol
_endpointPrivacy Node endpoint — routes messages to other Privacy Nodes via the Private Network Hub
_raylsNodeEndpointPrivacy Node endpoint for the Rayls Public Chain
_userGovernanceRBAC contract that manages user roles and permissions within the Privacy Node
_ownerAddress granted the Owner role

Token registration lifecycle

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

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

Once approved, the relayer calls receiveResourceId() on your contract automatically. After that, the token can participate in DvP swaps.


DvP flow

Step 1 — Deposit the NFT

The seller locks their token into the DvP contract before initiating a swap.

function depositIntoDvp(uint256 _tokenId) public virtual nonReentrant

After this call, lockedForDvp[msg.sender][_tokenId] is set to true. The NFT cannot be transferred until the swap is completed or cancelled.

Step 2 — Initiate the cross-chain swap

function swapWithDvpForEnygma(
    uint256 _tokenId,
    bytes memory tokenDataParam,
    uint256 _enygmaAmount,
    bytes32 _enygmaResourceId,
    uint256 _destChainId,
    bytes32 _sharedId,
    SharedObjects.DvpProgramability calldata _msg,
    uint64 _validityTime
) public virtual nonReentrant
ParameterDescription
_tokenIdID of the locked NFT to offer
tokenDataParamOptional extra data for the NFT
_enygmaAmountAmount of Enygma tokens requested from buyer
_enygmaResourceIdResource ID of the Enygma contract on buyer's PN
_destChainIdChain ID of the buyer's Privacy Node
_sharedIdUnique identifier shared by both swap legs
_msgOptional programmability data (custom payload after settlement)
_validityTimeSeconds until the swap expires (pass 0 for the contract default)

Step 3a — Swap completed (relayer-triggered)

Called automatically by the relayer when both legs succeed. Do not call this directly.

// restricted — RELAYER role only
function dvpSwapCompleted(
    SharedObjects.DvpSwapCompletedParams memory params,
    address from,
    bytes memory data
) public virtual restricted nonReentrant

When executed: the NFT is burned from the seller, minted on the buyer's PN, and the Enygma payment is released.

Step 3b — Cancel the swap

Call cancelSwap if the swap has expired or the counterparty did not respond.

function cancelSwap(
    bytes32 _sharedId,
    uint256 _toChainId,
    uint256 _tokenId,
    bytes32 _enygmaResourceId,
    uint256 _enygmaAmount
) public virtual nonReentrant

Then call withdrawFromDvp to recover the locked NFT:

function withdrawFromDvp(uint256 _tokenId) public virtual nonReentrant

The relayer finalises the unlock by calling unlockFromDvp, returning the NFT to the seller's available balance.


Mint and burn

// Owner role only
function mint(address to, uint256 id, bytes memory data, SharedObjects.DvpExtraData memory extraData)
    public virtual restricted nonReentrant

// Owner role only
function burn(uint256 _id) public virtual restricted nonReentrant

Swap validity time

// Owner role only
function setSwapValidityTime(uint64 _validityTime) public virtual restricted

Access control summary

RoleFunctions
Ownermint, burn, submitTokenUpdate, setSwapValidityTime
RELAYERdvpSwapCompleted, unlockFromDvp, notifySenderWithPNCommunicator, notifySenderAndReceiverWithPNCommunicator
MESSAGE_EXECUTORunlock, receiveResourceId, MintFromSwapDvp
Any addressdepositIntoDvp, swapWithDvpForEnygma, cancelSwap, withdrawFromDvp