Skip to content

Instantly share code, notes, and snippets.

@zengzengzenghuy
Last active November 1, 2023 09:55
Show Gist options
  • Save zengzengzenghuy/2bcd1ecc04efd5ff317f753fc246e2a9 to your computer and use it in GitHub Desktop.
Save zengzengzenghuy/2bcd1ecc04efd5ff317f753fc246e2a9 to your computer and use it in GitHub Desktop.
YahoMessageDispatcher
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.17;
interface IHashiExecutor {
function onMessage(bytes data, bytes32 messageId, uint256 fromChainId, address from);
}
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.17;
struct Message {
address to;
address from;
uint256 toChainId;
uint256 fromChainId;
bytes data;
}
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.17;
interface IMessageExecutor {
error MessageIdAlreadyExecuted(bytes32 messageId);
error MessageFailure(bytes32 messageId,bytes errorData);
event MessageIdExecuted(uint256 indexed fromChainId, bytes32 indexed messageId);
function onMessage(bytes data, bytes32 messageId, uint256 fromChainId, address from);
}
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.17;
import { IMessageRelay } from "./interfaces/IMessageRelay.sol";
import { IMessageDispatcher, Message } from "./interfaces/IMessageDispatcher.sol";
import { MessageHashCalculator } from "./utils/MessageHashCalculator.sol";
contract Yaho is IMessageDispatcher, MessageHashCalculator {
mapping(uint256 => bytes32) public hashes;
uint256 private count;
error NoMessagesGiven(address emitter);
error NoMessageIdsGiven(address emitter);
error NoAdaptersGiven(address emitter);
error UnequalArrayLengths(address emitter);
/// @dev Dispatches a batch of messages, putting their into storage and emitting their contents as an event.
/// @param messages An array of Messages to be dispatched.
/// @return messageIds An array of message IDs corresponding to the dispatched messages.
function dispatchMessages(Message[] memory messages) public payable returns (bytes32[] memory) {
if (messages.length == 0) revert NoMessagesGiven(address(this));
bytes32[] memory messageIds = new bytes32[](messages.length);
for (uint256 i = 0; i < messages.length; i++) {
bytes32 id = keccak256(bytes.concat(bytes32(count),bytes32(block.chainid)));
hashes[id] = calculateHash(block.chainid, id, address(this), msg.sender, messages[i]);
messageIds[i] = id;
emit MessageDispatched(id, msg.sender, messages[i].toChainId, messages[i].to, messages[i].data);
count++;
}
return messageIds;
}
/// @dev Relays hashes of the given messageIds to the given adapters.
/// @param messageIds Array of IDs of the message hashes to relay to the given adapters.
/// @param adapters Array of relay adapter addresses to which hashes should be relayed.
/// @param destinationAdapters Array of oracle adapter addresses to receive hashes.
/// @return adapterReciepts Reciepts from each of the relay adapters.
function relayMessagesToAdapters(
uint256[] memory messageIds,
address[] memory adapters,
address[] memory destinationAdapters,
uint256 gas
) external payable returns (bytes32[] memory) {
if (messageIds.length == 0) revert NoMessageIdsGiven(address(this));
if (adapters.length == 0) revert NoAdaptersGiven(address(this));
if (adapters.length != destinationAdapters.length) revert UnequalArrayLengths(address(this));
bytes32[] memory adapterReciepts = new bytes32[](adapters.length);
for (uint256 i = 0; i < adapters.length; i++) {
adapterReciepts[i] = IMessageRelay(adapters[i]).relayMessages(messageIds, destinationAdapters[i], gas);
}
return adapterReciepts;
}
/// @dev Dispatches an array of messages and relays their hashes to an array of relay adapters.
/// @param messages An array of Messages to be dispatched.
/// @param adapters Array of relay adapter addresses to which hashes should be relayed.
/// @param destinationAdapters Array of oracle adapter addresses to receive hashes.
/// @return messageIds An array of message IDs corresponding to the dispatched messages.
/// @return adapterReciepts Reciepts from each of the relay adapters.
function dispatchMessagesToAdapters(
Message[] memory messages,
address[] memory adapters,
address[] memory destinationAdapters,
uint256 gas
) external payable returns (bytes32[] memory messageIds, bytes32[] memory) {
if (adapters.length == 0) revert NoAdaptersGiven(address(this));
messageIds = dispatchMessages(messages);
uint256[] memory uintIds = new uint256[](messageIds.length);
for (uint256 i = 0; i < messageIds.length; i++) {
uintIds[i] = uint256(messageIds[i]);
}
bytes32[] memory adapterReciepts = new bytes32[](adapters.length);
for (uint256 i = 0; i < adapters.length; i++) {
adapterReciepts[i] = IMessageRelay(adapters[i]).relayMessages(uintIds, destinationAdapters[i], gas);
}
return (messageIds, adapterReciepts);
}
}
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.17;
import { IHashi, IOracleAdapter } from "./interfaces/IHashi.sol";
import { Message } from "./interfaces/IMessage.sol";
import { IMessageExecutor } from "./interfaces/IMessageExecutor.sol";
import { MessageHashCalculator } from "./utils/MessageHashCalculator.sol";
contract Yaru is IMessageExecutor, MessageHashCalculator {
IHashi public immutable hashi;
address public immutable yaho;
uint256 public immutable chainId;
mapping(bytes32 => bool) public executed;
address public sender;
error ReentranceNotAllowed(address);
error UnequalArrayLengths(address emitter);
error InvalidSender(address emitter, address sender);
error HashMismatch(address emitter, uint256 id, bytes32 reportedHash, bytes32 calculatedHash);
/// @param _hashi Address of the Hashi contract.
/// @param _yaho Address of the Yaho contract
constructor(IHashi _hashi, address _yaho, uint256 _chainId) {
hashi = _hashi;
yaho = _yaho;
chainId = _chainId;
}
/// @dev Executes messages validated by a given set of oracle adapters
/// @param messages Array of messages to execute.
/// @param messageIds Array of corresponding messageIds to query for hashes from the given oracle adapters.
/// @param senders Array of addresses that sent the corresponding messages.
/// @param oracleAdapters Array of oracle adapters to query.
/// @return returnDatas Array of data returned from each executed message.
function executeMessages(
Message[] memory messages,
uint256[] memory messageIds,
address[] memory senders,
IOracleAdapter[] memory oracleAdapters
) public returns (bytes[] memory) {
if (sender != address(0)) revert ReentranceNotAllowed(address(0));
if (messages.length != senders.length || messages.length != messageIds.length)
revert UnequalArrayLengths(address(this));
bytes[] memory returnDatas = new bytes[](messages.length);
for (uint256 i = 0; i < messages.length; i++) {
bytes32 id = messageIds[i];
if (executed[id]) revert MessageIdAlreadyExecuted(id);
if (senders[i] == address(0)) revert InvalidSender(address(this), senders[i]);
executed[id] = true;
Message memory message = messages[i];
sender = senders[i];
bytes32 reportedHash = hashi.getHash(chainId, id, oracleAdapters);
bytes32 calculatedHash = calculateHash(chainId, id, yaho, sender, message);
if (reportedHash != calculatedHash) revert HashMismatch(address(this), id, reportedHash, calculatedHash);
(bool success, bytes memory returnData) = (message.to).call(message.data);
if (!success) revert MessageFailure(id, bytes("Message call Failed");
delete sender;
returnDatas[i] = returnData;
emit MessageIdExecuted(message.fromChainId, bytes32(id));
}
return returnDatas;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment