// 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 {}
}