JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 2
  • Score
    100M100P100Q43521F

EVM Gateway Contract

Package Exports

    This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (evm-gateway-contract) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

    Readme

    Router EVM Gateway contracts

    Overview

    The Router EVM Gateway contract will bridge EVM chains with the Router Chain. We can deploy this gateway contract on any EVM-compatible chain. The gateway contract validates all incoming requests coming from the router chain using the validator set signatures. These signatures should have at-least 2/3 validator power. The current validator set(valset) can update the validator set to a new valset by invoking the updateValset function.

    The EVM gateway contract implements two ways to connect with other chains.

    1. Using the Router Chain contract as a middleware contract
    2. Directly calling the destination contract without any middleware contract

    The Router Chain contract as middleware flow

    In this scenario, The user application will have one contract on the Router chain. This router chain contract will behave as a middleware contract for the application. The EVM gateway contract implements the following functionalities for the user application.

    1. Send a request to the Router chain
    2. Handle requests from the Router chain

    Send a Request to the Router Chain

    To send a request to the router chain, the user contract needs to call the following function and needs to provide the bridge contract address & payload bytes

    # Gateway contract address variable
    Gateway public gatewayContract;
    
    # User/ Application contract constructor
    constructor(address gatewayAddress) {
        gatewayContract = Gateway(gatewayAddress);
    }
    
    # example of send request to the Router chain
    function sendRequestToRouter(bytes memory payload, string memory routerBridgeContract) public payable {
        # implement the business logic
        uint64 eventNonceIdentifier = gatewayContract.requestToRouter(payload, routerBridgeContract);
    }

    Handle Requests from the Router

    To handle requests coming from the router chain, the user contract needs to implement the following function in their contract

    function handleRequestFromRouter(string memory sender, bytes memory payload) external {
        # implement the business logic
    }

    In case of state update from the requestFromRouter function we are emitting the following event

    # This is OutBound Request Acknowledgement event
    event EventOutboundAck(
        string relayerRouterAddress,
        string outboundTxRequestedBy,
        string chainId,
        uint64 chainType,
        uint64 eventNonce,
        uint64 outboundTxNonce,
        bytes contractAckResponses,
        uint8 exeCode,
        bool status
    );

    Currently we are emitting this outbound acknowledgement event in two cases only. The ChainType, ChainId, and OutboundTxNonce will have same values in all cases.

    • When the txn is valid, but It is getting executed past the timeout. In this scenario, we will update the nonce mapping to 1 as executed and the event will have the following values

      emit EventOutboundAck(
          relayerRouterAddress,
          routerBridgeAddress,
          chainId,
          chainType,
          eventNonce,
          outboundTxNonce,
          "",
          1,
          false
      );
      
    • When the txn is valid and executed its handler calls to user contract In this scenario, we will update the nonce mapping to 1 as executed and the event will have the following values

      emit EventOutboundAck(
          relayerRouterAddress,
          routerBridgeAddress,
          chainId,
          chainType,
          eventNonce,
          outboundTxNonce,
          data,
          0,
          success
      );

      Here, data and success values are coming from the handlerExecuteCalls funciton. Data bytes can be decoded according to the success value. If it is true, then it will be array of bool values and if it is false, then it will string value.

    Directly calling the destination contract without any middleware contract

    In this scenario, Having a contract on the Router chain is not mandatory for a user application. The application can send or receive contract calls directly from the other chains. The EVM gateway contract implements the following functionalities for the user application.

    1. Send a request to the destination chain
    2. Handle requests from the source chain
    3. Send acknowledgment from the destination to the source chain
    4. Receive ack request on the source chain

    Send a Request to the Destination Chain

    To send a request to the destination chain, the user contract needs to call the following function and needs to provide the following payloads

    # Gateway contract address variable
    Gateway public gatewayContract;
    
    # User/ Application contract constructor
    constructor(address gatewayAddress) {
        gatewayContract = Gateway(gatewayAddress);
    }
    
    # example of send request to the Router chain
    function sendRequestToDestination(
        uint64 chainType,
        string memory chainId,
        address destinationContractAddress,
        string memory str
    ) public payable {
        # implement the application business logic
        bytes memory payload = abi.encode(str);
        uint64 timestamp = <timestamp value>;
        bytes[] memory addresses = new bytes[](1);
        addresses[0] = toBytes(destinationContractAddress);
        bytes[] memory payloads = new bytes[](1);
        payloads[0] = payload;
        uint64 eventIdentifier = gatewayContract.requestToDest(
            timestamp,
            <isAtomicCalls>,
            Utils.AckType.ACK_ON_SUCCESS,
            # provide the gas limit and price for the ack execution, in testnet it can be zero
            Utils.AckGasParams(
                0,
                0
            ),
            # provide the gas limit and price for the destination contract calls execution, in testnet it can be zero
            Utils.DestinationChainParams(
                0,
                0,
                chainType,
                chainId
            ),
            Utils.ContractCalls(
                payloads,
                addresses
            ));
        # implement the application business logic
    }

    Handle requests from the source chain

    To handle request coming from the source chain, the user contract needs to implement the following function in their contract

    function handleRequestFromSource(
        bytes memory srcContractAddress,
        bytes memory payload,
        string memory srcChainId,
        uint64 srcChainType
    ) external returns (bytes memory) {
        # It is recommended to verify the source caller contract address(srcContractAddress) 
        # Also, verify this funciton is invoked by the gateway address only
        require(msg.sender == address(gatewayContract));
    
        # implement the business logic
    }

    In case of state update from the requestFromSource function we are emitting the following event

    # This is CrossTalk Request Acknowledgement event
    // This is OutBound Request Acknowledgement event
    event CrossTalkAckEvent(
        string relayerRouterAddress,
        bytes srcContractAddress,
        string srcChainId,
        uint64 srcChainType,
        string chainId,
        uint64 chainType,
        uint64 eventIdentifier,
        uint64 crossTalkNonce,
        uint64 indexed eventNonce,
        bytes contractAckResponses,
        uint8 exeCode,
        bool status
    );

    Currently, we are emitting this outbound acknowledgment event in two cases only. In both cases, apart from contractAckResponses, execCode, and status all will have the same values.

    • When the txn is valid but It is getting executed past the timeout. In this scenario, we will update the nonce mapping to 1 as executed and the event will have the following values

      emit CrossTalkAckEvent(
          relayerRouterAddress,
          srcContractAddress,
          srcChainId,
          srcChainType,
          chainId,
          chainType,
          eventIdentifier,
          crossTalkNonce,
          eventNonce,
          "",
          1,
          false
      );
    • When the txn is valid and executed its handler calls to user contract In this scenario, we will update the nonce mapping to 1 as executed and the event will have the following values

      emit CrossTalkAckEvent(
          relayerRouterAddress,
          srcContractAddress,
          srcChainId,
          srcChainType,
          chainId,
          chainType,
          eventIdentifier,
          crossTalkNonce,
          eventNonce,
          data,
          0,
          success
      );

      Here, data and success values are coming from the handlerExecuteCalls funciton. Data bytes can be decoded according to the success value. If it is true, then it will be (bool[] & bytes[]) and if it is false, then it will custom error containing (bool[] & bytes[]).

    Send acknowledgement from the destination to the source chain

    Each valid cross-talk request will emit one acknowledgement event. But the application contract can decide whether they want to receive this ack or not. For that they can tell their condition while initiating this coss-talk request. The acknowledgement is sent back to the source application contract on basis of provided AckType and the execution result of the contractCalls on the destionation side.

    enum AckType {
        NO_ACK,
        ACK_ON_SUCCESS,
        ACK_ON_ERROR,
        ACK_ON_BOTH
    }

    Receive ack request on the source chain

    To receive the ack request on the source chain, the user contract need to implement the following function in the application contract

    # Gateway contract address variable
    Gateway public gatewayContract;
    
    # User/ Application contract constructor
    constructor(address gatewayAddress) {
        gatewayContract = Gateway(gatewayAddress);
    }
    
    function handleCrossTalkAck(
        uint64 eventIdentifier,
        bool[] memory execFlags,
        bytes[] memory execData
    ) external {
        # implement the business logic
    }

    Update Validator Set

    This is used to update validator set on the gateway contract. This will be called by the router chain validator set only.

    Please use the following instruction to setup, test and deploy the project

    Setup

    To run any command you need to have .env in your local

    cd router-gateway-contracts/evm
    cp .env.test .env

    then update the value in .env file.

    Compile Project

    cd router-gateway-contracts/evm
    npm install
    npx hardhat compile

    Run Tests

    Use the following commands to run the test cases:

    npx hardhat help
    npx hardhat test
    GAS_REPORT=true npx hardhat test

    Deploy Gateway Contract on live network

    Add gateway contract constructor arguments in args.json

    cd router-gateway-contracts/evm
    npx hardhat deploy:Gateway --network <network> --chaintype <chainType> --valsetnonce <valsetNonce> --validators <validators> --powers <powers>

    Upgrade Gateway Contract on live network

    cd router-gateway-contracts/evm
    npx hardhat upgrade:Gateway --network <network>

    Verify GateWay Contract on a network

    cd router-gateway-contracts/evm
    npx hardhat verify --constructor-args <args-file-path> <gateway-contract-address> --network <network-name>

    Example:-

    npx hardhat verify --constructor-args scripts/arguments.js 0x610aEe9387488398c25Aca6aDFBac662177DB24D --network polygonMumbai

    Generate ABIs, BIN and GO bindings of the Gateway Contract

    cd router-gateway-contracts
    npm install
    sh scripts/createBinding.sh