📩Message Passing in Smart Contracts

The requirements and interface for your contract to receive messages along with tokens when bridging.

You can pass a custom message of your choice along with the tokens that will be bridged. Your receiving contract must implement a custom interface that can be found in the docs. Your receiving contract address must be whitelisted on our system, after security checks and confirmation by our technical team. It is not possible to pass messages without tokens.

To use message passing, your receiving contract address must be whitelisted on our smart contracts, after security checks and confirmation by our technical team.

You can see a sample smart contract that in this link, which can act as sender as well as a receiver contract. Note: This sample contract is just for demonstration purposes and should not be used in production. Do not rely on this sample for security, functionality or logic.

Your receiver contract should implement `IRangoMessageReceiver` interface (Link).

interface IRangoMessageReceiver {
    enum ProcessStatus { SUCCESS, REFUND_IN_SOURCE, REFUND_IN_DESTINATION }

    function handleRangoMessage(
        address token,
        uint amount,
        ProcessStatus status,
        bytes memory message
    ) external;
}

How Rango contracts interact with your contract:

To understand how the contract is called, check below code (Source). First the token is sent to your contract, then your contract is checked for being whitelisted by us for message passing. Then, your contract is called through handleRangoMessage function wrapped in a try/catch block.

Therefore, when handleRangoMessage function is called on your contract, the bridged tokens are in your control as they are already sent to your contract.

Important Note: The call to your contract is wrapped in try/catch block. Therefore, if any exceptions or failures happen in your contract, the transaction does not revert and the tokens that previously sent to your contract, will stay in your contract. Make sure to consider this in your security considerations.

    ...
    if (_token == LibSwapper.ETH) {
        LibSwapper._sendNative(immediateReceiver, _amount);
    } else {
        SafeERC20.safeTransfer(IERC20(_token), immediateReceiver, _amount);
    }

    if (thereIsAMessage) {
        require(
            messagingStorage.whitelistMessagingContracts[_dAppReceiverContract],
            "3rd-party contract not whitelisted"
        );

        try IRangoMessageReceiver(_dAppReceiverContract)
            .handleRangoMessage(_token, _amount, processStatus, _dAppMessage)
        {
            emit CrossChainMessageCalled(_dAppReceiverContract, _token, _amount, processStatus, _dAppMessage, true, "");
        } catch Error(string memory reason) {
            emit CrossChainMessageCalled(_dAppReceiverContract, _token, _amount, processStatus, _dAppMessage, false, reason);
        } catch (bytes memory lowLevelData) {
            emit CrossChainMessageCalled(_dAppReceiverContract, _token, _amount, processStatus, _dAppMessage, false, LibSwapper._getRevertMsg(lowLevelData));
        }
    }

Last updated