Deploying Your Custom EVM Protocol

This guide provides step-by-step instructions on how to deploy your custom EVM protocol. By following these steps, you can successfully deploy your custom EVM protocol across multiple chains. If you encounter issues, refer to the Troubleshooting section of this guide and the How to Debug Sent Messages guide or reach out to us through our contact form.

Prerequisites

Before deployment, ensure you are familiar with payable functions in Solidity and have initiated a Hardhat project.

Package Installation

To streamline development, start by installing the Entangle Labs UIP Contracts NPM package. It includes ready-to-use code and interfaces for deployment.

npm install @entangle-labs/uip-contracts

Deployment Steps

1

Endpoint Contract Address

Obtain the endpoint contract address for the chain where you plan to deploy your protocol. You can find endpoint addresses for each connected chain in the Entangle Labs UIP Contracts NPM package.

For testnet, they are located in the following folder:

@entangle-labs/uip-contracts/addresses/testnet/

For mainnet, they are located in the following folder:

@entangle-labs/uip-contracts/addresses/mainnet/
2

Interfaces and Libraries

Ensure the following imports are included in your contract:

import {IEndpoint, TransmitterParams} from "@entangle-labs/uip-contracts/contracts/interfaces/endpoint/IEndpoint.sol";
import "@entangle-labs/uip-contracts/contracts/lib/SelectorLib.sol";
3

Default Selector Variable

To interact with the Endpoint properly, you need to send message with the correct selector to call its "execute" function. Make sure it's included in your contract like so:

bytes4 public constant DEFAULT_SELECTOR = bytes4(keccak256("execute(bytes calldata)"));
4

Payable Function to Send Proposals

Develop a payable function that interacts with the endpoint. For example, sending a message to the endpoint requires calling the propose function using the IEndpoint interface:

IEndpoint(endpoint).propose{value: msg.value}(
    chainID,
    SelectorLib.encodeDefaultSelector(DEFAULT_SELECTOR),
    encodedParams,
    destAddress,
    abi.encode(abi.encode(_msg), abi.encode(_msgSender()))
);
5

Receive and Execute Messages

The receiving contract must implement the MessageReceiver interface, which you can find in @entagle-labs/uip-contracts npm package — installed in the Package Installation step — specifically the execute function:

function execute(bytes calldata data) external override payable

The execute function processes the received payload. Note that the Endpoint contract should have access control to this function. Make sure that your contract imports MessageReceiver and inherits from it, for example:

import {MessageReceiver} from "@entangle-labs/uip-contracts/contracts/MessageReceiver.sol";
contract ExampleProtocol is MessageReceiver

Below, we provide the MessageReceiver code for convenience. Please refer to the package for the most up-to-date version.

MessageReceiver Code
abstract contract MessageReceiver {
    /**
     * @dev Executes a function call from a specified source chain and address.
     *
     * This external function is intended to be used for executing cross-chain
     * calls with the provided payload. It requires to be overridden by child contracts to execute the command
     * @param data The data payload to be sent along with the function call.
     *
     */
    function execute(bytes calldata data) external payable virtual {}

    function _decode(
        bytes calldata data
    )
        internal
        virtual
        returns (
            uint256 sourceChainId,
            bytes memory senderAddr,
            bytes memory payload
        )
    {
        (sourceChainId, senderAddr, payload) = abi.decode(
            data,
            (uint256, bytes, bytes)
        );
    }
}

Troubleshooting & Notes

This section provides information, tips, and solutions for common issues you may encounter while deploying the protocol.

Deployment Failure
  1. Check the signer account balance: Ensure the account has enough native currency on the target blockchain for deployment.

  2. Verify the credentials: Double-check that you've correctly pasted the mnemonic phrase or private key in the hardhat.config.ts file under the appropriate chain section.

  3. Compile before deploying: Run npx hardhat compile before deployment. If it fails, thoroughly check your contract for compilation errors.

Sending Message Failure
  1. Check the signer account balance: Ensure the account has sufficient native currency for transactions.

  2. Verify the installed package version: Make sure you have the latest version of the @entangle-labs/uip-contracts npm package installed. To check the latest version, visit the official npm page.

  3. Confirm function signature compliance: Ensure your contract correctly follows the propose function signature in the Endpoint contract:

    function propose(
        uint256 destChainID, 
        bytes32 selectorSlot, 
        bytes calldata transmitterParams, 
        bytes calldata destAddress, 
        bytes calldata payload
    ) external payable;
Message Not Reaching Destination Contract
  1. Check destination chain support: Ensure that the destination chain is currently supported.

  2. Retrieve message hash: Use the following command to obtain the TEIB transaction hash for your message: npx hardhat getMsgHash

  3. Check message status: Once you have the hash, use: getMsgStatusByHash

Message Status Explanations

  • NOT_INITIALIZED: This indicates that the message was not proposed by the Endpoint on the source chain. Verify that the Endpoint address in your contract matches the official Endpoint address for your source chain.

  • PROTOCOL_FAILED: This occurs when the destination protocol is incompatible with the destination Endpoint. Ensure that the destination protocol implements the MessageReceiver interface (as described in the Receiver Contract Requirements section).

  • UNDERESTIMATED: This status means that the source transaction’s msg.value was too low to cover gas costs on the destination chain. Try resending the message with a higher msg.value.

  • OUT_OF_GAS: This means that the customGasLimit in the source transaction was too low, causing the execution on the destination chain to consume more gas than provided. Try resending the message with a higher customGasLimit.

Transaction Delivery Fee and Currency

All transactions use the native currency of the chain you're working on. Themsg.value sent during the propose call is considered the combined delivery fee.

Package Referencing Issues

Ensure all configurations adhere to the latest documentation and libraries provided in the @entangle-labs/uip-contracts package.

Last updated

Was this helpful?