ETH Price: $2,018.28 (+3.45%)

Contract Diff Checker

Contract Name:
GlacisClientSample

Contract Source Code:

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: Apache-2.0

pragma solidity 0.8.18;

import {GlacisCommons} from "../commons/GlacisCommons.sol";
import {IGlacisAccessControlClient} from "../interfaces/IGlacisAccessControlClient.sol";

/// @title Glacis Access Control Client
/// @dev This contract encapsulates Glacis Access Control client logic. Contracts inheriting this will have access to
/// Glacis Access control features  
abstract contract GlacisAccessControlClient is GlacisCommons, IGlacisAccessControlClient {
    mapping(uint256 => mapping(bytes32 => mapping(address => bool))) public allowedRoutes;

    bytes32 constant internal WILD_BYTES = bytes32(uint256(WILDCARD));
    address constant internal WILD_ADDR = address(WILDCARD);

    /// @notice Adds an allowed route for this client
    /// @param route Route to be added
    function _addAllowedRoute(
        GlacisRoute memory route
    ) internal {
        allowedRoutes[route.fromChainId][route.fromAddress][route.fromAdapter] = true;
    }

    /// @notice Removes an allowed route for this client
    /// @param route Allowed route to be removed
    function _removeAllowedRoute(
        GlacisRoute calldata route
    ) internal {
        allowedRoutes[route.fromChainId][route.fromAddress][route.fromAdapter] = false;
    }

    /// @notice Queries if a route from path GMP+Chain+Address is allowed for this client
    /// @param route_ Incoming message route
    /// @return True if route is allowed, false otherwise
    function isAllowedRoute(
        GlacisRoute memory route_,
        bytes memory // payload
    ) public view override returns (bool) {
        return
            allowedRoutes[route_.fromChainId][route_.fromAddress][route_.fromAdapter] ||
            allowedRoutes[WILDCARD][route_.fromAddress][route_.fromAdapter] ||
            allowedRoutes[WILDCARD][WILD_BYTES][route_.fromAdapter] ||
            allowedRoutes[route_.fromChainId][WILD_BYTES][route_.fromAdapter] ||
            (uint160(route_.fromAdapter) <= GLACIS_RESERVED_IDS && (
                allowedRoutes[route_.fromChainId][route_.fromAddress][WILD_ADDR] ||
                allowedRoutes[route_.fromChainId][WILD_BYTES][WILD_ADDR] ||
                allowedRoutes[WILDCARD][WILD_BYTES][WILD_ADDR]
            ));
    }
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: Apache-2.0

pragma solidity 0.8.18;

import {IGlacisRouter} from "../interfaces/IGlacisRouter.sol";
import {IGlacisClient} from "../interfaces/IGlacisClient.sol";
import {GlacisAccessControlClient} from "../client/GlacisAccessControlClient.sol";
error GlacisClient__CanOnlyBeCalledByRouter();
error GlacisClient__InvalidRouterAddress();

/// @title Glacis Client
/// @dev This contract encapsulates Glacis client side logic, contracts inheriting this will have access to all
/// Glacis features
abstract contract GlacisClient is GlacisAccessControlClient, IGlacisClient {
    address public immutable GLACIS_ROUTER;

    event GlacisClient__MessageRouted(
        bytes32 indexed messageId,
        uint256 toChainId,
        bytes32 to
    );
    
    event GlacisClient__MessageArrived(
        address[] fromAdapters,
        uint256 fromChainId,
        bytes32 fromAddress
    );

    /// @param _glacisRouter This chain's deployment of the GlacisRouter  
    /// @param _quorum The initial default quorum for this client. If dynamic quorum is to be implemented (depending on payload)
    /// this value can be ignored and set to 0  
    constructor(
        address _glacisRouter,
        uint256 _quorum
    ) GlacisAccessControlClient() IGlacisClient(_quorum) {
        if (_glacisRouter == address(0))
            revert GlacisClient__InvalidRouterAddress();
        GLACIS_ROUTER = _glacisRouter;
    }

    /// @notice Routes the payload to the specific address on destination chain through GlacisRouter using a single specified GMP
    /// @param chainId Destination chain (Glacis chain ID)
    /// @param to Destination address on remote chain
    /// @param payload Payload to be routed
    /// @param adapter Glacis ID of the GMP to be used for the routing
    /// @param refundAddress Address to refund excess gas payment
    /// @param gasPayment Amount of gas to cover source and destination gas fees (excess will be refunded)
    function _routeSingle(
        uint256 chainId,
        bytes32 to,
        bytes memory payload,
        address adapter,
        address refundAddress,
        uint256 gasPayment
    ) internal returns (bytes32) {
        address[] memory adapters = new address[](1);
        adapters[0] = adapter;
        CrossChainGas[] memory fees = new CrossChainGas[](1);
        fees[0] = CrossChainGas({ 
            gasLimit: 0,
            nativeCurrencyValue: uint128(gasPayment)
        });
        (bytes32 messageId,) = IGlacisRouter(GLACIS_ROUTER).route{
            value: gasPayment
        }(chainId, to, payload, adapters, fees, refundAddress, false);
        emit GlacisClient__MessageRouted(messageId, chainId, to);
        return messageId;
    }

    /// @notice Routes the payload to the specific address on destination chain through GlacisRouter using
    /// specified GMPs.
    /// @param chainId Destination chain (Glacis chain ID)
    /// @param to Destination address on remote chain
    /// @param payload Payload to be routed
    /// @param adapters The adapters to use for redundant routing
    /// @param fees Payment for each GMP to cover source and destination gas fees (excess will be refunded)
    /// @param refundAddress Address to refund excess gas payment
    /// @param gasPayment Amount of gas to cover source and destination gas fees (excess will be refunded)
    function _routeRedundant(
        uint256 chainId,
        bytes32 to,
        bytes memory payload,
        address[] memory adapters,
        CrossChainGas[] memory fees,
        address refundAddress,
        uint256 gasPayment
    ) internal returns (bytes32) {
        (bytes32 messageId,) = IGlacisRouter(GLACIS_ROUTER).route{
            value: gasPayment
        }(chainId, to, payload, adapters, fees, refundAddress, false);
        emit GlacisClient__MessageRouted(messageId, chainId, to);
        return messageId;
    }

    /// @notice Routes the payload to the specific address on destination chain through GlacisRouter using GMPs
    /// specified in gmps array
    /// @param chainId Destination chain (Glacis chain ID)
    /// @param to Destination address on remote chain
    /// @param payload Payload to be routed
    /// @param adapters An array of custom adapters to be used for the routing
    /// @param fees Payment for each GMP to cover source and destination gas fees (excess will be refunded)
    /// @param refundAddress Address to refund excess gas payment
    /// @param retryable True to enable retry feature for this message
    /// @param gasPayment Amount of gas to cover source and destination gas fees (excess will be refunded)
    function _route(
        uint256 chainId,
        bytes32 to,
        bytes memory payload,
        address[] memory adapters,
        CrossChainGas[] memory fees,
        address refundAddress,
        bool retryable,
        uint256 gasPayment
    ) internal returns (bytes32,uint256) {
        (bytes32 messageId,uint256 nonce) = IGlacisRouter(GLACIS_ROUTER).route{
            value: gasPayment
        }(chainId, to, payload, adapters, fees, refundAddress, retryable);
        emit GlacisClient__MessageRouted(messageId, chainId, to);
        return (messageId,nonce);
    }

    /// @notice Routes the payload to the specific address on destination chain through GlacisRouter using GMPs
    /// specified in gmps array
    /// @param chainId Destination chain (Glacis chain ID)
    /// @param to Destination address on remote chain
    /// @param payload Payload to be routed
    /// @param adapters An array of adapters to be used for the routing
    /// @param fees Payment for each GMP to cover source and destination gas fees (excess will be refunded)
    /// @param refundAddress Address to refund excess gas payment
    /// @param messageId The message ID of the message to retry
    /// @param nonce The nonce emitted by the original sent message
    /// @param gasPayment Amount of gas to cover source and destination gas fees (excess will be refunded)
    function _retryRoute(
        uint256 chainId,
        bytes32 to,
        bytes memory payload,
        address[] memory adapters,
        CrossChainGas[] memory fees,
        address refundAddress,
        bytes32 messageId,
        uint256 nonce,
        uint256 gasPayment
    ) internal returns (bytes32) {
        IGlacisRouter(GLACIS_ROUTER).routeRetry{value: gasPayment}(
            chainId,
            to,
            payload,
            adapters,
            fees,
            refundAddress,
            messageId,
            nonce
        );
        emit GlacisClient__MessageRouted(messageId, chainId, to);
        return messageId;
    }

    /// @notice Receives message from GMP(s) through GlacisRouter
    /// @param fromAdapters addresses of the adapters sent this message (that reached quorum requirements)
    /// @param fromChainId Source chain (Glacis chain ID)
    /// @param fromAddress Source address on source chain
    /// @param payload Routed payload
    function receiveMessage(
        address[] memory fromAdapters,
        uint256 fromChainId,
        bytes32 fromAddress,
        bytes memory payload
    ) external virtual override {
        if (msg.sender != GLACIS_ROUTER)
            revert GlacisClient__CanOnlyBeCalledByRouter();
        _receiveMessage(fromAdapters, fromChainId, fromAddress, payload);
        emit GlacisClient__MessageArrived(fromAdapters, fromChainId, fromAddress);
    }

    /// @notice Receives message from GMP(s) through GlacisRouter
    /// @param fromAdapters Adapter addresses
    /// @param fromChainId Source chain (Glacis chain ID)
    /// @param fromAddress Source address on source chain
    /// @param payload Routed payload
    function _receiveMessage(
        address[] memory fromAdapters,
        uint256 fromChainId,
        bytes32 fromAddress,
        bytes memory payload
    ) internal virtual {}
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: Apache-2.0

pragma solidity 0.8.18;

import {GlacisClient} from "./GlacisClient.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {GlacisCommons} from "../commons/GlacisCommons.sol";

/// @title Glacis Ownable Client
/// @dev This contract encapsulates Glacis client side logic, contracts inheriting this will have access to all
/// Glacis features  
/// @notice This contract is ownable  
abstract contract GlacisClientOwnable is GlacisClient, Ownable {

    /// @param _glacisRouter This chain's deployment of the GlacisRouter  
    /// @param _quorum The default quorum that you would like. If you implement dynamic quorum, this value can be ignored and 
    /// set to 0  
    /// @param _owner The owner of this contract  
    constructor(
        address _glacisRouter,
        uint256 _quorum,
        address _owner
    ) GlacisClient(_glacisRouter, _quorum) {
        _transferOwnership(_owner);
    }

    /// @notice Add an allowed route for this client
    /// @param allowedRoute Route to be added
    function addAllowedRoute(
        GlacisCommons.GlacisRoute memory allowedRoute
    ) external onlyOwner {
        _addAllowedRoute(allowedRoute);
    }

    /// @notice Removes an allowed route for this client
    /// @param route Allowed route to be removed
    function removeAllowedRoute(
        GlacisCommons.GlacisRoute calldata route
    ) external onlyOwner {
        _removeAllowedRoute(route);
    }
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: Apache-2.0

pragma solidity 0.8.18;

/// @title Glacis Commons
/// @dev Contract for utility functions and structures common to Glacis Client and Infrastructure
contract GlacisCommons {
    struct GlacisData {
        bytes32 messageId;
        uint256 nonce;
        bytes32 originalFrom;
        bytes32 originalTo;
    }

    struct GlacisTokenData {
        address glacisToken;
        uint256 glacisTokenAmount;
    }

    struct GlacisRoute {
        uint256 fromChainId; // WILDCARD means any chain
        bytes32 fromAddress; // WILDCARD means any address
        address fromAdapter; // WILDCARD means any GMP, can also hold address
    }

    struct CrossChainGas {
        uint128 gasLimit;
        uint128 nativeCurrencyValue;
    }

    uint160 constant public WILDCARD = type(uint160).max;
    uint256 constant public GLACIS_RESERVED_IDS = 248;
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;
import {GlacisCommons} from "../commons/GlacisCommons.sol";

/// @title IGlacisAccessControlClient
/// @notice An interface that determines Glacis' required access control
interface IGlacisAccessControlClient {
    /// @notice Adds an allowed route for this client
    /// @notice Queries if a route from path GMP+Chain+Address is allowed for this client
    /// @param route The origin route for the message
    /// @param payload The payload of a message
    /// @return True if route is allowed, false otherwise
    function isAllowedRoute(
        GlacisCommons.GlacisRoute memory route,
        bytes memory payload
    ) external view returns (bool);
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import {GlacisCommons} from "../commons/GlacisCommons.sol";
import {IGlacisAccessControlClient} from "../interfaces/IGlacisAccessControlClient.sol";

/// @title IGlacisClient
/// @notice An interface that defines the GMP modules (adapters) that the GlacisRouter interacts with.
abstract contract IGlacisClient is IGlacisAccessControlClient {
    uint256 private immutable DEFAULT_QUORUM;

    /// @param _defaultQuorum The default quorum that you would like. If you implement dynamic quorum, this value can be ignored 
    /// and set to 0  
    constructor(uint256 _defaultQuorum) {
        DEFAULT_QUORUM = _defaultQuorum;
    }

    /// @notice Receives message from GMP(s) through GlacisRouter
    /// @param fromAdapters Used adapters that sent this message (that reached quorum requirements)
    /// @param fromChainId Source chain (Glacis chain ID)
    /// @param fromAddress Source address on source chain
    /// @param payload Routed payload
    function receiveMessage(
        address[] calldata fromAdapters,
        uint256 fromChainId,
        bytes32 fromAddress,
        bytes calldata payload
    ) external virtual;

    /// @notice The quorum of messages that the contract expects with a specific message
    function getQuorum(
        GlacisCommons.GlacisData memory,    // glacis data
        bytes memory,                       // payload
        uint256                             // unique messages received so far (for dynamic quorum, usually unused)
    ) public view virtual returns (uint256) {
        return DEFAULT_QUORUM;
    }
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: Apache-2.0

pragma solidity 0.8.18;

import {GlacisCommons} from "../commons/GlacisCommons.sol";

/// @title IGlacisRouterEvents
/// @notice An interface that defines a GlacisRouter's events
abstract contract IGlacisRouterEvents is GlacisCommons
{
    event GlacisAbstractRouter__MessageIdCreated(
        bytes32 indexed messageId,
        bytes32 indexed sender,
        uint256 nonce
    );
    event GlacisAbstractRouter__AdapterRegistered(
        uint8 indexed gmpId,
        address indexed adapterAddress,
        address indexed previousAddress
    );
    event GlacisAbstractRouter__AdapterUnregistered(
        uint8 indexed gmpId,
        address indexed adapterAddress
    );
    event GlacisRouter__ReceivedMessage(
        bytes32 indexed messageId,
        bytes32 indexed from,
        uint256 indexed fromChainId,
        address adapter,
        bytes32 to
    );
    event GlacisRouter__ExecutedMessage(
        bytes32 indexed messageId,
        bytes32 indexed from,
        uint256 indexed fromChainId,
        address adapter,
        bytes32 to
    );
    event GlacisRouter__MessageDispatched(
        bytes32 indexed messageId,
        bytes32 indexed from,
        uint256 indexed toChainId,
        bytes32 to,
        bytes data,
        address[] adapters,
        CrossChainGas[] fees,
        address refundAddress,
        bool retryable
    );
    event GlacisRouter__MessageRetried(
        bytes32 indexed messageId,
        bytes32 indexed from,
        uint256 indexed toChainId,
        bytes32 to,
        bytes data,
        address[] adapters,
        CrossChainGas[] fees,
        address refundAddress
    );
}

/// @title IGlacisRouter
/// @notice An interface that defines an interface that sends and receives messages across chains
interface IGlacisRouter {
    /// @notice Routes the payload to the specific address on the destination chain
    /// using specified adapters
    /// @param chainId Destination chain (EIP-155)
    /// @param to Destination address on remote chain
    /// @param payload Payload to be routed
    /// @param adapters An array of adapters to be used for the routing (addresses 0x01-0xF8 for Glacis adapters 
    /// or specific addresses for custom adapters)
    /// @param fees Array of fees to be sent to each GMP & custom adapter for routing (must be same length as gmps)
    /// @param refundAddress An address for native currency to be sent to that are greater than fees charged. If it is a 
    /// contract it needs to support receive function, reverted otherwise
    /// @param retryable True if this message could pottentially be retried
    /// @return A tuple with a bytes32 messageId and a uint256 nonce
    function route(
        uint256 chainId,
        bytes32 to,
        bytes memory payload,
        address[] memory adapters,
        GlacisCommons.CrossChainGas[] memory fees,
        address refundAddress,
        bool retryable
    ) external payable returns (bytes32, uint256);

    /// @notice Retries routing the payload to the specific address on destination chain
    /// using specified GMPs and quorum
    /// @param chainId Destination chain (EIP-155)
    /// @param to Destination address on remote chain
    /// @param payload Payload to be routed
    /// @param adapters An array of adapters to be used for the routing (addresses 0x01-0xF8 for Glacis adapters 
    /// or specific addresses for custom adapters)
    /// @param fees Array of fees to be sent to each GMP & custom adapter for routing (must be same length as gmps)
    /// @param refundAddress An address for native currency to be sent to that are greater than fees charged. If it is a 
    /// contract it needs to support receive function, tx will revert otherwise
    /// @param messageId The messageId to retry
    /// @param nonce Unique value for this message routing
    /// @return A tuple with a bytes32 messageId and a uint256 nonce
    function routeRetry(
        uint256 chainId,
        bytes32 to,
        bytes memory payload,
        address[] memory adapters,
        GlacisCommons.CrossChainGas[] memory fees,
        address refundAddress,
        bytes32 messageId,
        uint256 nonce
    ) external payable returns (bytes32, uint256);

    /// @notice Receives a cross chain message from an IGlacisAdapter.
    /// @param fromChainId Source chain (EIP-155)
    /// @param glacisPayload Received payload with embedded GlacisData
    function receiveMessage(
        uint256 fromChainId,
        bytes memory glacisPayload
    ) external;
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;
import {GlacisClientOwnable} from "../../../contracts/client/GlacisClientOwnable.sol";
import {GlacisCommons} from "../../../contracts/commons/GlacisCommons.sol";

contract GlacisClientSample is GlacisClientOwnable {
    uint256 public value;

    constructor(
        address glacisRouter_,
        address owner_
    ) GlacisClientOwnable(glacisRouter_, 1, owner_) {}

    function setRemoteValue__execute(
        uint256 toChainId,
        bytes32 to,
        address adapter,
        bytes calldata payload
    ) external payable returns (bytes32) {
        return _routeSingle(toChainId, to, payload, adapter, msg.sender, msg.value);
    }

    function setRemoteValue__redundancy(
        uint256 toChainId,
        bytes32 to,
        address[] memory adapters,
        CrossChainGas[] memory fees,
        bytes calldata payload
    ) external payable returns (bytes32) {
        return
            _routeRedundant(
                toChainId,
                to,
                payload,
                adapters,
                fees,
                msg.sender,
                msg.value
            );
    }

    function setRemoteValue__retriable(
        uint256 chainId,
        bytes32 to,
        address[] memory adapters,
        CrossChainGas[] memory fees,
        bytes memory payload
    ) external payable returns (bytes32,uint256) {
        return
            _route(
                chainId,
                to,
                payload,
                adapters,
                fees,
                msg.sender,
                true,
                msg.value
            );
    }

    function setRemoteValue(
        uint256 chainId,
        bytes32 to,
        bytes memory payload,
        address[] memory adapters,
        CrossChainGas[] memory fees,
        address refundAddress,
        bool retryable,
        uint256 gasPayment
    ) external payable returns (bytes32,uint256 ) {
        return
            _route(
                chainId,
                to,
                payload,
                adapters,
                fees,
                refundAddress,
                retryable,
                gasPayment
            );
    }

    function setRemoteValue__retry(
        uint256 chainId,
        bytes32 to,
        address[] memory adapters,
        CrossChainGas[] memory fees,
        bytes memory payload,
        bytes32 messageId,
        uint256 nonce
    ) external payable returns (bytes32) {
        return
            _retryRoute(
                chainId,
                to,
                payload,
                adapters,
                fees,
                msg.sender,
                messageId,
                nonce,
                msg.value
            );
    }

    event ValueChanged(uint256 indexed value);

    function _receiveMessage(
        address[] memory, // fromGmpId,
        uint256, // fromChainId,
        bytes32, // fromAddress,
        bytes memory payload
    ) internal override {
        // NOTE: changed += to test for redundant messages
        if (payload.length > 0) (value) += abi.decode(payload, (uint256));
    }

    // Setup of custom quorum (for testing purposes)

    uint256 internal customQuorum = 1;

    function setQuorum(uint256 q) external onlyOwner {
        customQuorum = q;
    }

    function getQuorum(
        GlacisCommons.GlacisData memory,
        bytes memory,
        uint256
    ) public view override returns (uint256) {
        return customQuorum;
    }
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;
import {GlacisClientOwnable} from "../../../contracts/client/GlacisClientOwnable.sol";
import {GlacisCommons} from "../../../contracts/commons/GlacisCommons.sol";

contract GlacisClientTextSample is GlacisClientOwnable {
    string public value;

    constructor(
        address glacisRouter_,
        address owner_
    ) GlacisClientOwnable(glacisRouter_, 0, owner_) {}

    function setRemoteValue__execute(
        uint256 toChainId,
        bytes32 to,
        address adapter,
        bytes calldata payload
    ) external payable returns (bytes32) {
        return _routeSingle(toChainId, to, payload, adapter, msg.sender, msg.value);
    }

    function setRemoteValue__redundancy(
        uint256 toChainId,
        bytes32 to,
        address[] memory adapters,
        CrossChainGas[] memory fees,
        bytes calldata payload
    ) external payable returns (bytes32) {
        return
            _routeRedundant(
                toChainId,
                to,
                payload,
                adapters,
                fees,
                msg.sender,
                msg.value
            );
    }

    function setRemoteValue__retriable(
        uint256 chainId,
        bytes32 to,
        address[] memory adapters,
        CrossChainGas[] memory fees,
        bytes memory payload
    ) external payable returns (bytes32,uint256) {
        return
            _route(
                chainId,
                to,
                payload,
                adapters,
                fees,
                msg.sender,
                true,
                msg.value
            );
    }

    function setRemoteValue(
        uint256 chainId,
        bytes32 to,
        bytes memory payload,
        address[] memory adapters,
        CrossChainGas[] memory fees,
        address refundAddress,
        bool retryable,
        uint256 gasPayment
    ) external payable returns (bytes32,uint256) {
        return
            _route(
                chainId,
                to,
                payload,
                adapters,
                fees,
                refundAddress,
                retryable,
                gasPayment
            );
    }

    function setRemoteValue__retry(
        uint256 chainId,
        bytes32 to,
        address[] memory adapters,
        CrossChainGas[] memory fees,
        bytes memory payload,
        bytes32 messageId,
        uint256 nonce
    ) external payable returns (bytes32) {
        return
            _retryRoute(
                chainId,
                to,
                payload,
                adapters,
                fees,
                msg.sender,
                messageId,
                nonce,
                msg.value
            );
    }

    function _receiveMessage(
        address[] memory, // fromGmpId,
        uint256, // fromChainId,
        bytes32, // fromAddress,
        bytes memory payload
    ) internal override {
        (value) = abi.decode(payload, (string));
    }

    // Setup of custom quorum (for testing purposes)

    uint256 internal customQuorum = 1;

    function setQuorum(uint256 q) external onlyOwner {
        customQuorum = q;
    }

    function getQuorum(
        GlacisCommons.GlacisData memory,
        bytes memory,
        uint256
    ) public view override returns (uint256) {
        return customQuorum;
    }
}

Please enter a contract address above to load the contract details and source code.

Context size (optional):