HelloWeb3.sol

A simple use case

HelloWeb3 is an omnichain interoperable contract that sends and receives greetings across multiple blockchains. This HelloWeb3 contract can modify the remoteGreetings storage of others on remote blockchains.

Implementation details

To perform in an omnichain manner, a contract deployer should have built an AMT bridge on BOOLScan. Recap that an AMT bridge should consist of at least two deployed Anchor contracts which are respectively controlled by two distinct committees in BOOLNetwork.

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

import {IMessengerFee} from "../../interfaces/messenger/IMessengerFee.sol";
import {IAnchor} from "../../interfaces/IAnchor.sol";
import {BoolConsumerBase} from "../../base/BoolConsumerBase.sol";

contract HelloWeb3 is BoolConsumerBase {
    // srcChainId => recipient => sender => greeting
    mapping(uint32 => mapping(bytes32 => mapping(bytes32 => string))) private _greetings;

    constructor(address anchor_) BoolConsumerBase(anchor_) {}

    event GreetingSent(
        uint32 indexed dstChainId,
        bytes32 indexed recipient,
        bytes32 indexed sender
    );
    event GreetingReceived(
        uint32 indexed srcChainId,
        bytes32 indexed recipient,
        bytes32 indexed sender
    );

    function sendGreeting(
        uint32 dstChainId,
        bytes32 recipient,
        string memory greeting
    ) external payable {
        address sender = msg.sender;
        bytes memory payload = _encodePayload(recipient, sender, greeting);
        _sendAnchor(msg.value, payable(sender), PURE_MESSAGE, bytes(""), dstChainId, payload);
        emit GreetingSent(dstChainId, recipient, _addressToBytes32(sender));
    }

    function receiveFromAnchor(
        bytes32 txUniqueIdentification,
        bytes memory payload
    ) external override onlyAnchor {
        /** Get Local ChainId */
        uint32 srcChainId;
        bytes memory crossId = abi.encode(txUniqueIdentification);
        assembly {
            srcChainId := mload(add(crossId, 4))
        }
        /** Decode Payload */
        (bytes32 recipient, bytes32 sender, string memory greeting) = _decodePayload(payload);
        /** Receive Greeting */
        _receiveGreeting(srcChainId, recipient, sender, greeting);
    }

    /** View/Pure Functions */
    function fetchGreeting(
        uint32 srcChainId,
        bytes32 recipient,
        bytes32 sender
    ) external view returns (string memory greeting) {
        greeting = _greetings[srcChainId][recipient][sender];
    }

    function estimateCrossFee(
        uint32 dstChainId,
        bytes32 recipient,
        string memory greeting
    ) public view returns (uint256 fee) {
        address srcAnchor = _anchor;
        bytes memory payload = _encodePayload(recipient, msg.sender, greeting);
        fee = IMessengerFee(IAnchor(srcAnchor).messenger()).cptTotalFee(
            srcAnchor,
            dstChainId,
            uint32(payload.length),
            PURE_MESSAGE,
            bytes("0x")
        );
    }

    /** Internal/Private Functions */
    function _encodePayload(
        bytes32 recipient,
        address sender,
        string memory greeting
    ) private pure returns (bytes memory payload) {
        payload = abi.encode(recipient, _addressToBytes32(sender), greeting);
    }

    function _decodePayload(
        bytes memory payload
    ) private pure returns (bytes32 recipient, bytes32 sender, string memory greeting) {
        (recipient, sender, greeting) = abi.decode(payload, (bytes32, bytes32, string));
    }

    function _addressToBytes32(address account) private pure returns (bytes32) {
        return bytes32(uint256(uint160(account)));
    }

    function _receiveGreeting(
        uint32 srcChainId,
        bytes32 recipient,
        bytes32 sender,
        string memory greeting
    ) private {
        /** Update Greeting */
        _greetings[srcChainId][recipient][sender] = greeting;

        /** Emit Received Event */
        emit GreetingReceived(srcChainId, recipient, sender);
    }
}

Last updated