polytone-evm 0.3.0

Core interfaces for Polytone Interchain accounts and queries.
Documentation
// SPDX-License-Identifier: Apache
pragma solidity ^0.8.24;

import {EvmMsg, ExecuteResult, CallMessage, EvmMsgType} from "./Requests.sol";

/**
 * @title Polytone Proxy
 * @dev the Proxy account (speaker) that will be dispatching calls on behalf of the sender on the other chain.
 * This contract represents the "sender" from another chain on this chain. It is able to:
 * - execute messages
 * - hold native eth
 * - Send / receive native eth
 */
contract PolytoneProxy {
    // --------------------- Data Structure --------------------- //

    // Owner is going to be the evm-voice
    address immutable owner;

    // --------------------- Errors --------------------- //
    error UnknownExecuteMessage(EvmMsgType msgType);
    error NotAnOwner();
    error AbstractProxyCallReverted();
    error AbstractProxyDelegateCallReverted();

    // ---------------------Events --------------------- //
    event ExecuteCallReceived(address to, bytes data, uint256 value);
    event ExecuteCallResult(bool success, bytes data);
    // --------------------- Modifiers --------------------- //

    modifier onlyOwner() {
        if (msg.sender != address(owner)) {
            revert NotAnOwner();
        }
        _;
    }

    // --------------------- Functions --------------------- //

    constructor(address _owner) {
        owner = _owner;
    }

    /**
     * @dev Execute a message on behalf of the user.
     * @custom:oz-upgrades-unsafe-allow-reachable delegatecall
     * @notice We mark this function as payable to save a `msg.value == 0` check.
     */
    function execute(EvmMsg[] calldata evmMsgs)
        external
        payable
        onlyOwner
        returns (ExecuteResult[] memory returnData)
    {
        uint256 length = evmMsgs.length;
        returnData = new ExecuteResult[](length);

        for (uint256 i = 0; i < length;) {
            EvmMsgType msgType = evmMsgs[i].msgType;
            CallMessage memory callMessage = abi.decode(evmMsgs[i].message, (CallMessage));
            ExecuteResult memory result = returnData[i];

            emit ExecuteCallReceived(callMessage.to, callMessage.data, callMessage.value);

            if (msgType == EvmMsgType.Call) {
                (result.success, result.data) = callMessage.to.call{value: callMessage.value}(callMessage.data);

                if (!callMessage.allowFailure && !result.success) {
                    revert AbstractProxyCallReverted();
                }
            } else if (msgType == EvmMsgType.DelegateCall) {
                (result.success, result.data) = callMessage.to.delegatecall(callMessage.data);

                if (!callMessage.allowFailure && !result.success) {
                    revert AbstractProxyDelegateCallReverted();
                }
            } else {
                revert UnknownExecuteMessage(msgType);
            }

            emit ExecuteCallResult(result.success, result.data);

            unchecked {
                ++i;
            }
        }
    }

    receive() external payable {}
}