diff --git a/contracts/script/actions/SubmitRequest.s.sol b/contracts/script/actions/SubmitRequest.s.sol index 0ed77e9..c3154d8 100644 --- a/contracts/script/actions/SubmitRequest.s.sol +++ b/contracts/script/actions/SubmitRequest.s.sol @@ -2,20 +2,22 @@ pragma solidity 0.8.24; import {Script} from "forge-std/Script.sol"; -import {CAIP2} from "openzeppelin-contracts/contracts/utils/CAIP2.sol"; -import {Strings} from "openzeppelin-contracts/contracts/utils/Strings.sol"; -import {ERC7786Base} from "../../src/ERC7786Base.sol"; +import {GlobalTypes} from "../../src/libraries/GlobalTypes.sol"; +import {RIP7755Base} from "../../src/RIP7755Base.sol"; import {RIP7755Outbox} from "../../src/RIP7755Outbox.sol"; import {HelperConfig} from "../HelperConfig.s.sol"; -contract SubmitRequest is Script, ERC7786Base { - using Strings for uint256; - - HelperConfig public helperConfig; +contract SubmitRequest is Script, RIP7755Base { + using GlobalTypes for address; + bytes4 internal constant _REWARD_ATTRIBUTE_SELECTOR = 0xa362e5db; // reward(bytes32,uint256) rewardAsset, rewardAmount + bytes4 internal constant _DELAY_ATTRIBUTE_SELECTOR = 0x84f550e0; // delay(uint256,uint256) finalityDelaySeconds, expiry + bytes4 internal constant _L2_ORACLE_ATTRIBUTE_SELECTOR = 0x7ff7245a; // l2Oracle(address) bytes32 private constant _NATIVE_ASSET = 0x000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee; + HelperConfig public helperConfig; + constructor() { helperConfig = new HelperConfig(); } @@ -29,31 +31,27 @@ contract SubmitRequest is Script, ERC7786Base { RIP7755Outbox outbox = RIP7755Outbox(outboxAddr); - (string memory destinationChain, Message[] memory messages, bytes[] memory attributes) = + (bytes32 destinationChain, bytes32 receiver, Call[] memory calls, bytes[] memory attributes) = _initMessage(destinationChainId, duration); vm.startBroadcast(config.deployerKey); - outbox.sendMessages{value: 0.0002 ether}(destinationChain, messages, attributes); + outbox.sendMessage{value: 0.0002 ether}(destinationChain, receiver, abi.encode(calls), attributes); vm.stopBroadcast(); } function _initMessage(uint256 destinationChainId, uint256 duration) private - returns (string memory, Message[] memory, bytes[] memory) + returns (bytes32, bytes32, Call[] memory, bytes[] memory) { HelperConfig.NetworkConfig memory dstConfig = helperConfig.getConfig(destinationChainId); // HelperConfig.NetworkConfig memory srcConfig = helperConfig.getConfig(block.chainid); - Message[] memory calls = new Message[](1); - bytes[] memory messageAttributes = new bytes[](1); - messageAttributes[0] = abi.encodeWithSelector(_VALUE_ATTRIBUTE_SELECTOR, 0.0001 ether); - calls[0] = Message({ - receiver: Strings.toChecksumHexString(0x8C1a617BdB47342F9C17Ac8750E0b070c372C721), - payload: "", - attributes: messageAttributes - }); + Call[] memory calls = new Call[](1); + calls[0] = + Call({to: 0x8C1a617BdB47342F9C17Ac8750E0b070c372C721.addressToBytes32(), data: "", value: 0.0001 ether}); - string memory destinationChain = CAIP2.format("eip155", destinationChainId.toString()); + bytes32 destinationChain = bytes32(destinationChainId); + bytes32 receiver = dstConfig.inbox.addressToBytes32(); bytes[] memory attributes = new bytes[](3); attributes[0] = abi.encodeWithSelector(_REWARD_ATTRIBUTE_SELECTOR, _NATIVE_ASSET, 0.0002 ether); @@ -61,7 +59,7 @@ contract SubmitRequest is Script, ERC7786Base { attributes[2] = abi.encodeWithSelector(_L2_ORACLE_ATTRIBUTE_SELECTOR, dstConfig.l2Oracle); // attributes[2] = abi.encodeWithSelector(_SHOYU_BASHI_ATTRIBUTE_SELECTOR, srcConfig.shoyuBashi); - return (destinationChain, calls, attributes); + return (destinationChain, receiver, calls, attributes); } // Including to block from coverage report diff --git a/contracts/script/actions/SubmitToInbox.s.sol b/contracts/script/actions/SubmitToInbox.s.sol index 8d55b00..c9e7b53 100644 --- a/contracts/script/actions/SubmitToInbox.s.sol +++ b/contracts/script/actions/SubmitToInbox.s.sol @@ -2,31 +2,40 @@ pragma solidity 0.8.24; import {Script} from "forge-std/Script.sol"; -import {CAIP2} from "openzeppelin-contracts/contracts/utils/CAIP2.sol"; -import {ERC7786Base} from "../../src/ERC7786Base.sol"; +import {GlobalTypes} from "../../src/libraries/GlobalTypes.sol"; +import {RIP7755Base} from "../../src/RIP7755Base.sol"; import {RIP7755Inbox} from "../../src/RIP7755Inbox.sol"; -contract SubmitToInbox is Script, ERC7786Base { +contract SubmitToInbox is Script, RIP7755Base { + using GlobalTypes for address; + + bytes4 internal constant _REWARD_ATTRIBUTE_SELECTOR = 0xa362e5db; // reward(bytes32,uint256) rewardAsset, rewardAmount + bytes4 internal constant _DELAY_ATTRIBUTE_SELECTOR = 0x84f550e0; // delay(uint256,uint256) finalityDelaySeconds, expiry + bytes4 internal constant _NONCE_ATTRIBUTE_SELECTOR = 0xce03fdab; // nonce(uint256) + bytes4 internal constant _REQUESTER_ATTRIBUTE_SELECTOR = 0x3bd94e4c; // requester(bytes32) + bytes4 internal constant _SHOYU_BASHI_ATTRIBUTE_SELECTOR = 0xda07e15d; // shoyuBashi(bytes32) + function run() external { uint256 pk = vm.envUint("PRIVATE_KEY"); RIP7755Inbox inbox = RIP7755Inbox(payable(0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512)); + address fulfiller = 0x23214A0864FC0014CAb6030267738F01AFfdd547; - (string memory sourceChain, string memory sender, Message[] memory messages, bytes[] memory attributes) = - _initMessage(); + (bytes32 sourceChain, bytes32 sender, bytes memory payload, bytes[] memory attributes) = _initMessage(); vm.startBroadcast(pk); - inbox.executeMessages(sourceChain, sender, messages, attributes); + inbox.fulfill(sourceChain, sender, payload, attributes, fulfiller); vm.stopBroadcast(); } // Using dummy values for local testing - function _initMessage() private pure returns (string memory, string memory, Message[] memory, bytes[] memory) { - Message[] memory calls = new Message[](0); + function _initMessage() private pure returns (bytes32, bytes32, bytes memory, bytes[] memory) { + Call[] memory calls = new Call[](0); - string memory sourceChain = CAIP2.format("eip155", "31337"); - string memory sender = "0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496"; - bytes[] memory attributes = new bytes[](6); + bytes32 sourceChain = bytes32(uint256(31337)); + bytes32 sender = 0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496.addressToBytes32(); + bytes memory payload = abi.encode(calls); + bytes[] memory attributes = new bytes[](5); attributes[0] = abi.encodeWithSelector( _REWARD_ATTRIBUTE_SELECTOR, 0x000000000000000000000000f62849f9a0b5bf2913b396098f7c7019b51a820a, 1 ether @@ -36,13 +45,11 @@ contract SubmitToInbox is Script, ERC7786Base { attributes[3] = abi.encodeWithSelector( _REQUESTER_ATTRIBUTE_SELECTOR, 0x000000000000000000000000328809bc894f92807417d2dad6b7c998c1afdac6 ); - attributes[4] = - abi.encodeWithSelector(_FULFILLER_ATTRIBUTE_SELECTOR, 0x23214A0864FC0014CAb6030267738F01AFfdd547); - attributes[5] = abi.encodeWithSelector( + attributes[4] = abi.encodeWithSelector( _SHOYU_BASHI_ATTRIBUTE_SELECTOR, 0x0000000000000000000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f ); - return (sourceChain, sender, calls, attributes); + return (sourceChain, sender, payload, attributes); } // Including to block from coverage report diff --git a/contracts/src/ERC7786Base.sol b/contracts/src/ERC7786Base.sol deleted file mode 100644 index 3baf4d4..0000000 --- a/contracts/src/ERC7786Base.sol +++ /dev/null @@ -1,121 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.24; - -/// @title ERC7786Base -/// -/// @author Coinbase (https://github.com/base-org/RIP-7755-poc) -/// -/// @notice This contract contains the selectors for the RIP-7755-supported attributes of the ERC7786 standard -contract ERC7786Base { - /// @notice A struct representing an individual call within a 7755 request - struct Message { - /// @dev The CAIP-10 account address of the receiver (not including the chain identifier) - string receiver; - /// @dev The calldata for the call to be made to the receiver - bytes payload; - /// @dev The attributes to be included in the message (should be empty) - bytes[] attributes; - } - - /// @notice The selector for the precheck attribute - bytes4 internal constant _PRECHECK_ATTRIBUTE_SELECTOR = 0xfa1e5831; // precheck(address) - - /// @notice The selector for the nonce attribute - bytes4 internal constant _NONCE_ATTRIBUTE_SELECTOR = 0xce03fdab; // nonce(uint256) - - /// @notice The selector for the reward attribute - bytes4 internal constant _REWARD_ATTRIBUTE_SELECTOR = 0xa362e5db; // reward(bytes32,uint256) rewardAsset, rewardAmount - - /// @notice The selector for the delay attribute - bytes4 internal constant _DELAY_ATTRIBUTE_SELECTOR = 0x84f550e0; // delay(uint256,uint256) finalityDelaySeconds, expiry - - /// @notice The selector for the requester attribute - bytes4 internal constant _REQUESTER_ATTRIBUTE_SELECTOR = 0x3bd94e4c; // requester(bytes32) - - /// @notice The selector for the fulfiller attribute - bytes4 internal constant _FULFILLER_ATTRIBUTE_SELECTOR = 0x138a03fc; // fulfiller(address) - - /// @notice The selector for the l2Oracle attribute - bytes4 internal constant _L2_ORACLE_ATTRIBUTE_SELECTOR = 0x7ff7245a; // l2Oracle(address) - - /// @notice The selector for the shoyuBashi attribute - bytes4 internal constant _SHOYU_BASHI_ATTRIBUTE_SELECTOR = 0xda07e15d; // shoyuBashi(bytes32) - - /// @notice The selector for the inbox attribute - bytes4 internal constant _INBOX_ATTRIBUTE_SELECTOR = 0xbd362374; // inbox(bytes32) - - /// @notice The selector for the destinationChain attribute - bytes4 internal constant _DESTINATION_CHAIN_SELECTOR = 0xdff49bf1; // destinationChain(bytes32) - - /// @notice The selector for the value attribute - bytes4 internal constant _VALUE_ATTRIBUTE_SELECTOR = 0xc5a46ee6; // value(uint256) - - /// @notice The selector for the isUserOp attribute. Used to designate a request designated to be a destination - /// chain ERC-4337 User Operation - bytes4 internal constant _USER_OP_ATTRIBUTE_SELECTOR = 0xd45448dd; // isUserOp(bool) - - /// @notice This error is thrown if an attribute is not found in the attributes array - /// - /// @param selector The selector of the attribute that was not found - error AttributeNotFound(bytes4 selector); - - /// @notice This error is thrown when the call attributes array contains more than one element - error MaxOneAttributeExpected(); - - /// @notice Locates an attribute in the attributes array - /// - /// @custom:reverts If the attribute is not found - /// - /// @param attributes The attributes array to search - /// @param selector The selector of the attribute to find - /// - /// @return attribute The attribute found - function _locateAttribute(bytes[] calldata attributes, bytes4 selector) internal pure returns (bytes calldata) { - (bool found, bytes calldata attribute) = _locateAttributeUnchecked(attributes, selector); - - if (!found) { - revert AttributeNotFound(selector); - } - - return attribute; - } - - /// @notice Locates an attribute in the attributes array without checking if the attribute is found - /// - /// @param attributes The attributes array to search - /// @param selector The selector of the attribute to find - /// - /// @return found Whether the attribute was found - /// @return attribute The attribute found - function _locateAttributeUnchecked(bytes[] calldata attributes, bytes4 selector) - internal - pure - returns (bool found, bytes calldata attribute) - { - for (uint256 i; i < attributes.length; i++) { - if (bytes4(attributes[i]) == selector) { - return (true, attributes[i]); - } - } - return (false, attributes[0]); - } - - /// @notice Locates an attribute value in the attributes array - /// - /// @param attributes The attributes array to search - /// - /// @return value The value of the attribute found - function _locateAttributeValue(bytes[] calldata attributes) internal pure returns (uint256) { - if (attributes.length > 1) { - revert MaxOneAttributeExpected(); - } - - uint256 value; - - if (attributes.length == 1 && bytes4(attributes[0]) == _VALUE_ATTRIBUTE_SELECTOR) { - value = abi.decode(attributes[0][4:], (uint256)); - } - - return value; - } -} diff --git a/contracts/src/RIP7755Base.sol b/contracts/src/RIP7755Base.sol new file mode 100644 index 0000000..53667b1 --- /dev/null +++ b/contracts/src/RIP7755Base.sol @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +/// @title ERC7786Base +/// +/// @author Coinbase (https://github.com/base-org/RIP-7755-poc) +/// +/// @notice This contract contains the selectors for the RIP-7755-supported attributes of the ERC7786 standard +contract RIP7755Base { + /// @notice Low-level call specs representing the desired transaction on destination chain + struct Call { + /// @dev The address to call + bytes32 to; + /// @dev The calldata to call with + bytes data; + /// @dev The native asset value of the call + uint256 value; + } + + /// @notice The selector for the precheck attribute + bytes4 internal constant _PRECHECK_ATTRIBUTE_SELECTOR = 0xfa1e5831; // precheck(address) + + /// @notice The selector for the isUserOp attribute. Used to designate a request designated to be a destination + /// chain ERC-4337 User Operation + bytes4 internal constant _USER_OP_ATTRIBUTE_SELECTOR = 0xd45448dd; // isUserOp(bool) + + /// @notice This error is thrown if an attribute is not found in the attributes array + /// + /// @param selector The selector of the attribute that was not found + error AttributeNotFound(bytes4 selector); + + /// @notice Returns the keccak256 hash of a message request + /// + /// @dev Filters out the fulfiller attribute from the attributes array + /// + /// @param sourceChain The source chain identifier + /// @param sender The account address of the sender + /// @param destinationChain The destination chain identifier + /// @param receiver The account address of the receiver + /// @param payload The encoded calls to be included in the request + /// @param attributes The attributes to be included in the message + /// + /// @return _ The keccak256 hash of the message request + function getRequestId( + bytes32 sourceChain, + bytes32 sender, + bytes32 destinationChain, + bytes32 receiver, + bytes calldata payload, + bytes[] calldata attributes + ) public pure returns (bytes32) { + return keccak256(abi.encode(sourceChain, sender, destinationChain, receiver, payload, attributes)); + } + + /// @notice Locates an attribute in the attributes array + /// + /// @custom:reverts If the attribute is not found + /// + /// @param attributes The attributes array to search + /// @param selector The selector of the attribute to find + /// + /// @return attribute The attribute found + function _locateAttribute(bytes[] calldata attributes, bytes4 selector) internal pure returns (bytes calldata) { + (bool found, bytes calldata attribute) = _locateAttributeUnchecked(attributes, selector); + + if (!found) { + revert AttributeNotFound(selector); + } + + return attribute; + } + + /// @notice Locates an attribute in the attributes array without checking if the attribute is found + /// + /// @param attributes The attributes array to search + /// @param selector The selector of the attribute to find + /// + /// @return found Whether the attribute was found + /// @return attribute The attribute found + function _locateAttributeUnchecked(bytes[] calldata attributes, bytes4 selector) + internal + pure + returns (bool found, bytes calldata attribute) + { + for (uint256 i; i < attributes.length; i++) { + if (bytes4(attributes[i]) == selector) { + return (true, attributes[i]); + } + } + return (false, attributes[0]); + } +} diff --git a/contracts/src/RIP7755Inbox.sol b/contracts/src/RIP7755Inbox.sol index f6f6efb..f014b36 100644 --- a/contracts/src/RIP7755Inbox.sol +++ b/contracts/src/RIP7755Inbox.sol @@ -2,12 +2,10 @@ pragma solidity 0.8.24; import {IEntryPoint} from "account-abstraction/interfaces/IEntryPoint.sol"; -import {CAIP10} from "openzeppelin-contracts/contracts/utils/CAIP10.sol"; -import {CAIP2} from "openzeppelin-contracts/contracts/utils/CAIP2.sol"; -import {Strings} from "openzeppelin-contracts/contracts/utils/Strings.sol"; import {IPrecheckContract} from "./interfaces/IPrecheckContract.sol"; -import {ERC7786Base} from "./ERC7786Base.sol"; +import {GlobalTypes} from "./libraries/GlobalTypes.sol"; +import {RIP7755Base} from "./RIP7755Base.sol"; import {Paymaster} from "./Paymaster.sol"; /// @title RIP7755Inbox @@ -16,12 +14,13 @@ import {Paymaster} from "./Paymaster.sol"; /// /// @notice An inbox contract within RIP-7755. This contract's sole purpose is to route requested transactions on /// destination chains and store record of their fulfillment. -contract RIP7755Inbox is ERC7786Base, Paymaster { - using Strings for string; +contract RIP7755Inbox is RIP7755Base, Paymaster { + using GlobalTypes for bytes32; + using GlobalTypes for address; struct MainStorage { - /// @notice A mapping from the keccak256 hash of a `CrossChainRequest` to its `FulfillmentInfo`. This can only - /// be set once per call + /// @notice A mapping from the keccak256 hash of a 7755 request to its `FulfillmentInfo`. This can only be set + /// once per call mapping(bytes32 requestHash => FulfillmentInfo) fulfillmentInfo; } @@ -33,23 +32,13 @@ contract RIP7755Inbox is ERC7786Base, Paymaster { address fulfiller; } - /// @notice A message structure used for internal processing - struct InternalMessage { - /// @dev The fulfiller address allowed to claim on source chain - address fulfiller; - /// @dev Boolean value specifying if the request represents an ERC-4337 UserOp - bool isUserOp; - /// @dev Address of the specified precheck contract. This is optional. - address precheckContract; - } - /// @notice Main storage location used as the base for the fulfillmentInfo mapping following EIP-7201. Derived from /// the equation keccak256(abi.encode(uint256(keccak256(bytes("RIP-7755"))) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant _MAIN_STORAGE_LOCATION = 0xfd1017d80ffe8da8a74488ee7408c9efa1877e094afa95857de95797c1228500; /// @notice Event emitted when a cross chain call is fulfilled /// - /// @param requestHash The keccak256 hash of a `CrossChainRequest` + /// @param requestHash The keccak256 hash of a 7755 request /// @param fulfilledBy The account that fulfilled the cross chain call event CallFulfilled(bytes32 indexed requestHash, address indexed fulfilledBy); @@ -57,9 +46,6 @@ contract RIP7755Inbox is ERC7786Base, Paymaster { /// fulfilled error CallAlreadyFulfilled(); - /// @notice This error is thrown when an invalid caller is detected - error InvalidCaller(); - /// @notice This error is thrown when a User Operation is detected during an `executeMessages` call error UserOp(); @@ -70,85 +56,60 @@ contract RIP7755Inbox is ERC7786Base, Paymaster { /// @notice Delivery of a message sent from another chain. /// - /// @param sourceChain The CAIP-2 source chain identifier - /// @param sender The CAIP-10 account address of the sender - /// @param messages The messages to be included in the request - /// @param globalAttributes The attributes to be included in the message - /// - /// @return selector The selector of the function - function executeMessages( - string calldata sourceChain, - string calldata sender, - Message[] calldata messages, - bytes[] calldata globalAttributes - ) external payable returns (bytes4) { - InternalMessage memory m = _processAttributes(globalAttributes); - - if (m.fulfiller == address(0)) { - revert AttributeNotFound(_FULFILLER_ATTRIBUTE_SELECTOR); - } + /// @param sourceChain The source chain identifier + /// @param sender The account address of the sender + /// @param payload The encoded calls to be included in the request + /// @param attributes The attributes to be included in the message + /// @param fulfiller The account address of the fulfiller + function fulfill( + bytes32 sourceChain, + bytes32 sender, + bytes calldata payload, + bytes[] calldata attributes, + address fulfiller + ) external payable { + (bool isUserOp, address precheckContract) = _processAttributes(attributes); - if (m.isUserOp) { + if (isUserOp) { revert UserOp(); } - bytes32 messageId = getRequestId(sourceChain, sender, messages, globalAttributes); + bytes32 messageId = getRequestId( + sourceChain, sender, bytes32(block.chainid), address(this).addressToBytes32(), payload, attributes + ); - _runPrecheck(sourceChain, sender, messages, globalAttributes, m.precheckContract); + _runPrecheck(sourceChain, sender, payload, attributes, precheckContract); if (_getFulfillmentInfo(messageId).timestamp != 0) { revert CallAlreadyFulfilled(); } - _setFulfillmentInfo(messageId, m.fulfiller); + _setFulfillmentInfo(messageId, fulfiller); - _sendCallsAndValidateMsgValue(messages); + _sendCallsAndValidateMsgValue(payload); - emit CallFulfilled({requestHash: messageId, fulfilledBy: m.fulfiller}); - - return 0x675b049b; // this function's sig + emit CallFulfilled({requestHash: messageId, fulfilledBy: fulfiller}); } /// @notice Returns the stored fulfillment info for a passed in call hash /// - /// @param requestHash A keccak256 hash of a CrossChainRequest + /// @param requestHash A keccak256 hash of a 7755 request /// /// @return _ Fulfillment info stored for the call hash function getFulfillmentInfo(bytes32 requestHash) external view returns (FulfillmentInfo memory) { return _getFulfillmentInfo(requestHash); } - /// @notice Returns the keccak256 hash of a message request - /// - /// @dev Filters out the fulfiller attribute from the attributes array - /// - /// @param sourceChain The CAIP-2 source chain identifier - /// @param sender The CAIP-10 account address of the sender - /// @param messages The messages to be included in the request - /// @param attributes The attributes to be included in the message - /// - /// @return _ The keccak256 hash of the message request - function getRequestId( - string calldata sourceChain, - string calldata sender, - Message[] calldata messages, - bytes[] calldata attributes - ) public view returns (bytes32) { - string memory combinedSender = CAIP10.format(sourceChain, sender); - string memory destinationChain = CAIP2.local(); - return keccak256(abi.encode(combinedSender, destinationChain, messages, _filterOutFulfiller(attributes))); - } - - function _sendCallsAndValidateMsgValue(Message[] calldata messages) private { + function _sendCallsAndValidateMsgValue(bytes calldata payload) private { + Call[] memory calls = abi.decode(payload, (Call[])); uint256 valueSent; - for (uint256 i; i < messages.length; i++) { - address to = messages[i].receiver.parseAddress(); - uint256 value = _locateAttributeValue(messages[i].attributes); - _call(to, messages[i].payload, value); + for (uint256 i; i < calls.length; i++) { + address to = calls[i].to.bytes32ToAddress(); + _call(to, calls[i].data, calls[i].value); unchecked { - valueSent += value; + valueSent += calls[i].value; } } @@ -158,14 +119,10 @@ contract RIP7755Inbox is ERC7786Base, Paymaster { } function _call(address to, bytes memory data, uint256 value) private { - bytes memory result; - /// @solidity memory-safe-assembly - assembly { - result := mload(0x40) - if iszero(call(gas(), to, value, add(data, 0x20), mload(data), codesize(), 0x00)) { - // Bubble up the revert if the call reverts. - returndatacopy(result, 0x00, returndatasize()) - revert(result, returndatasize()) + (bool success, bytes memory result) = to.call{value: value}(data); + if (!success) { + assembly ("memory-safe") { + revert(add(result, 32), mload(result)) } } } @@ -178,9 +135,9 @@ contract RIP7755Inbox is ERC7786Base, Paymaster { } function _runPrecheck( - string calldata sourceChain, // [CAIP-2] chain identifier - string calldata sender, // [CAIP-10] account address - Message[] calldata messages, + bytes32 sourceChain, + bytes32 sender, + bytes calldata payload, bytes[] calldata attributes, address precheck ) private view { @@ -188,7 +145,7 @@ contract RIP7755Inbox is ERC7786Base, Paymaster { return; } - IPrecheckContract(precheck).precheckCall(sourceChain, sender, messages, attributes, msg.sender); + IPrecheckContract(precheck).precheckCall(sourceChain, sender, payload, attributes, msg.sender); } function _getFulfillmentInfo(bytes32 requestHash) private view returns (FulfillmentInfo memory) { @@ -196,34 +153,19 @@ contract RIP7755Inbox is ERC7786Base, Paymaster { return $.fulfillmentInfo[requestHash]; } - function _processAttributes(bytes[] calldata attributes) private pure returns (InternalMessage memory) { - InternalMessage memory message; + function _processAttributes(bytes[] calldata attributes) private pure returns (bool, address) { + bool isUserOp; + address precheckContract; for (uint256 i; i < attributes.length; i++) { - if (bytes4(attributes[i]) == _FULFILLER_ATTRIBUTE_SELECTOR) { - message.fulfiller = abi.decode(attributes[i][4:], (address)); - } else if (bytes4(attributes[i]) == _USER_OP_ATTRIBUTE_SELECTOR) { - message.isUserOp = abi.decode(attributes[i][4:], (bool)); + if (bytes4(attributes[i]) == _USER_OP_ATTRIBUTE_SELECTOR) { + isUserOp = abi.decode(attributes[i][4:], (bool)); } else if (bytes4(attributes[i]) == _PRECHECK_ATTRIBUTE_SELECTOR) { - message.precheckContract = abi.decode(attributes[i][4:], (address)); + precheckContract = abi.decode(attributes[i][4:], (address)); } } - return message; - } - - function _filterOutFulfiller(bytes[] calldata attributes) private pure returns (bytes[] memory) { - bytes[] memory filteredAttributes = new bytes[](attributes.length - 1); - uint256 filteredIndex; - for (uint256 i; i < attributes.length; i++) { - if (bytes4(attributes[i]) != _FULFILLER_ATTRIBUTE_SELECTOR) { - filteredAttributes[filteredIndex] = attributes[i]; - unchecked { - filteredIndex++; - } - } - } - return filteredAttributes; + return (isUserOp, precheckContract); } function _getMainStorage() private pure returns (MainStorage storage $) { diff --git a/contracts/src/RIP7755Outbox.sol b/contracts/src/RIP7755Outbox.sol index a9ec0db..11cd6f1 100644 --- a/contracts/src/RIP7755Outbox.sol +++ b/contracts/src/RIP7755Outbox.sol @@ -3,10 +3,9 @@ pragma solidity ^0.8.0; import {SafeERC20, IERC20} from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol"; import {Address} from "openzeppelin-contracts/contracts/utils/Address.sol"; -import {CAIP10} from "openzeppelin-contracts/contracts/utils/CAIP10.sol"; import {GlobalTypes} from "./libraries/GlobalTypes.sol"; -import {ERC7786Base} from "./ERC7786Base.sol"; +import {RIP7755Base} from "./RIP7755Base.sol"; import {RIP7755Inbox} from "./RIP7755Inbox.sol"; /// @title RIP7755Outbox @@ -15,12 +14,11 @@ import {RIP7755Inbox} from "./RIP7755Inbox.sol"; /// /// @notice A source contract for initiating RIP-7755 Cross Chain Requests as well as reward fulfillment to Fulfillers /// that submit the cross chain calls to destination chains. -abstract contract RIP7755Outbox is ERC7786Base { +abstract contract RIP7755Outbox is RIP7755Base { using Address for address payable; using SafeERC20 for IERC20; using GlobalTypes for address; using GlobalTypes for bytes32; - using CAIP10 for address; /// @notice An enum representing the status of an RIP-7755 cross chain call enum CrossChainCallStatus { @@ -30,6 +28,24 @@ abstract contract RIP7755Outbox is ERC7786Base { Completed } + /// @notice The selector for the nonce attribute + bytes4 internal constant _NONCE_ATTRIBUTE_SELECTOR = 0xce03fdab; // nonce(uint256) + + /// @notice The selector for the reward attribute + bytes4 internal constant _REWARD_ATTRIBUTE_SELECTOR = 0xa362e5db; // reward(bytes32,uint256) rewardAsset, rewardAmount + + /// @notice The selector for the delay attribute + bytes4 internal constant _DELAY_ATTRIBUTE_SELECTOR = 0x84f550e0; // delay(uint256,uint256) finalityDelaySeconds, expiry + + /// @notice The selector for the requester attribute + bytes4 internal constant _REQUESTER_ATTRIBUTE_SELECTOR = 0x3bd94e4c; // requester(bytes32) + + /// @notice The selector for the l2Oracle attribute + bytes4 internal constant _L2_ORACLE_ATTRIBUTE_SELECTOR = 0x7ff7245a; // l2Oracle(address) + + /// @notice The selector for the inbox attribute + bytes4 internal constant _INBOX_ATTRIBUTE_SELECTOR = 0xbd362374; // inbox(bytes32) + /// @notice A mapping from the keccak256 hash of a message request to its current status mapping(bytes32 messageId => CrossChainCallStatus status) private _messageStatus; @@ -54,12 +70,22 @@ abstract contract RIP7755Outbox is ERC7786Base { /// @notice Event emitted when a user sends a message to the `RIP7755Inbox` /// /// @param outboxId The keccak256 hash of the message request - /// @param destinationChain The CAIP-2 chain identifier of the destination chain - /// @param sender The CAIP-10 account address of the sender - /// @param messages The messages to be included in the request - /// @param globalAttributes The attributes to be included in the message - event MessagesPosted( - bytes32 indexed outboxId, string destinationChain, string sender, Message[] messages, bytes[] globalAttributes + /// @param sourceChain The chain identifier of the source chain + /// @param sender The account address of the sender + /// @param destinationChain The chain identifier of the destination chain + /// @param receiver The account address of the receiver + /// @param payload The messages to be included in the request + /// @param value The native asset value of the call + /// @param attributes The attributes to be included in the message + event MessagePosted( + bytes32 indexed outboxId, + bytes32 sourceChain, + bytes32 sender, + bytes32 destinationChain, + bytes32 receiver, + bytes payload, + uint256 value, + bytes[] attributes ); /// @notice Event emitted when a cross chain call is successfully completed @@ -136,36 +162,24 @@ abstract contract RIP7755Outbox is ERC7786Base { /// /// @return messageId The generated request id function sendMessage( - string calldata destinationChain, - string calldata receiver, + bytes32 destinationChain, + bytes32 receiver, bytes calldata payload, bytes[] calldata attributes ) external payable returns (bytes32) { - Message[] memory messages = new Message[](1); - messages[0] = Message({receiver: receiver, payload: payload, attributes: new bytes[](0)}); - return _sendMessages(destinationChain, messages, attributes); - } + bytes[] memory expandedAttributes = _processAttributes(attributes); + bytes32 sender = address(this).addressToBytes32(); + bytes32 sourceChain = bytes32(block.chainid); - /// @notice Initiates the sending of a 7755 request containing multiple messages - /// - /// @custom:reverts If the attributes array length is less than 3 - /// @custom:reverts If a required attribute is missing from the global attributes array. Required attributes are: - /// - Reward attribute - /// - Delay attribute - /// - Inbox attribute - /// @custom:reverts If an unsupported attribute is provided - /// - /// @param destinationChain The CAIP-2 chain identifier of the destination chain - /// @param messages The messages to be included in the request - /// @param globalAttributes The attributes to be included in the message - /// - /// @return messageId The generated request id - function sendMessages( - string calldata destinationChain, - Message[] calldata messages, - bytes[] calldata globalAttributes - ) external payable returns (bytes32) { - return _sendMessages(destinationChain, messages, globalAttributes); + bytes32 messageId = + getRequestIdMemory(sourceChain, sender, destinationChain, receiver, payload, expandedAttributes); + _messageStatus[messageId] = CrossChainCallStatus.Requested; + + emit MessagePosted( + messageId, sourceChain, sender, destinationChain, receiver, payload, msg.value, expandedAttributes + ); + + return messageId; } /// @notice To be called by a Filler that successfully submitted a cross chain request to the destination chain and @@ -176,24 +190,26 @@ abstract contract RIP7755Outbox is ERC7786Base { /// @custom:reverts If finality delay seconds have not passed since the request was fulfilled on destination chain /// @custom:reverts If the reward attribute is not found in the attributes array /// - /// @param sender The CAIP-10 account address of the sender - /// @param destinationChain The CAIP-2 chain identifier of the destination chain - /// @param messages The messages to be included in the request + /// @param destinationChain The chain identifier of the destination chain + /// @param receiver The account address of the receiver + /// @param payload The encoded calls array /// @param expandedAttributes The attributes to be included in the message /// @param proof A proof that cryptographically verifies that `fulfillmentInfo` does, indeed, exist in /// storage on the destination chain /// @param payTo The address the Filler wants to receive the reward function claimReward( - string calldata sender, - string calldata destinationChain, - Message[] calldata messages, + bytes32 destinationChain, + bytes32 receiver, + bytes calldata payload, bytes[] calldata expandedAttributes, bytes calldata proof, address payTo ) external { - bytes32 messageId = getRequestIdCalldata(sender, destinationChain, messages, expandedAttributes); + bytes32 sender = address(this).addressToBytes32(); + bytes32 sourceChain = bytes32(block.chainid); + bytes32 messageId = getRequestId(sourceChain, sender, destinationChain, receiver, payload, expandedAttributes); bytes memory storageKey = abi.encode(keccak256(abi.encodePacked(messageId, _VERIFIER_STORAGE_LOCATION))); - address inbox = _getInboxAddress(expandedAttributes); + (address inbox, bytes32 rewardAsset, uint256 rewardAmount) = _getInboxAndReward(expandedAttributes); _checkValidStatus({requestHash: messageId, expectedStatus: CrossChainCallStatus.Requested}); @@ -201,7 +217,7 @@ abstract contract RIP7755Outbox is ERC7786Base { _messageStatus[messageId] = CrossChainCallStatus.Completed; - _sendReward(expandedAttributes, payTo); + _sendReward(payTo, rewardAsset, rewardAmount); emit CrossChainCallCompleted(messageId, msg.sender); } @@ -215,24 +231,24 @@ abstract contract RIP7755Outbox is ERC7786Base { /// @custom:reverts If the current block timestamp is less than the expiry timestamp plus the cancel delay seconds /// @custom:reverts If the reward attribute is not found in the attributes array /// - /// @param sender The CAIP-10 account address of the sender /// @param destinationChain The CAIP-2 chain identifier of the destination chain - /// @param messages The messages to be included in the request + /// @param receiver The account address of the receiver + /// @param payload The encoded calls to be included in the request /// @param expandedAttributes The attributes to be included in the message function cancelMessage( - string calldata sender, - string calldata destinationChain, - Message[] calldata messages, + bytes32 destinationChain, + bytes32 receiver, + bytes calldata payload, bytes[] calldata expandedAttributes ) external { - bytes32 messageId = getRequestIdCalldata(sender, destinationChain, messages, expandedAttributes); + bytes32 sender = address(this).addressToBytes32(); + bytes32 sourceChain = bytes32(block.chainid); + bytes32 messageId = getRequestId(sourceChain, sender, destinationChain, receiver, payload, expandedAttributes); _checkValidStatus({requestHash: messageId, expectedStatus: CrossChainCallStatus.Requested}); - bytes calldata requesterAttribute = _locateAttribute(expandedAttributes, _REQUESTER_ATTRIBUTE_SELECTOR); - bytes calldata delayAttribute = _locateAttribute(expandedAttributes, _DELAY_ATTRIBUTE_SELECTOR); - (, uint256 expiry) = abi.decode(delayAttribute[4:], (uint256, uint256)); - bytes32 requester = abi.decode(requesterAttribute[4:], (bytes32)); + (bytes32 requester, uint256 expiry, bytes32 rewardAsset, uint256 rewardAmount) = + _getRequesterAndExpiryAndReward(expandedAttributes); if (msg.sender.addressToBytes32() != requester) { revert InvalidCaller({caller: msg.sender, expectedCaller: requester.bytes32ToAddress()}); @@ -247,7 +263,7 @@ abstract contract RIP7755Outbox is ERC7786Base { _messageStatus[messageId] = CrossChainCallStatus.Canceled; // Return the stored reward back to the original requester - _sendReward(expandedAttributes, requester.bytes32ToAddress()); + _sendReward(requester.bytes32ToAddress(), rewardAsset, rewardAmount); emit CrossChainCallCanceled(messageId); } @@ -272,36 +288,23 @@ abstract contract RIP7755Outbox is ERC7786Base { /// @notice Returns the keccak256 hash of a message request /// + /// @param sourceChain The source chain identifier /// @param sender The CAIP-10 account address of the sender /// @param destinationChain The CAIP-2 chain identifier of the destination chain - /// @param messages The messages to be included in the request + /// @param receiver The account address of the receiver + /// @param payload The messages to be included in the request /// @param attributes The attributes to be included in the message /// /// @return _ The keccak256 hash of the message request - function getRequestId( - string memory sender, - string calldata destinationChain, - Message[] memory messages, + function getRequestIdMemory( + bytes32 sourceChain, + bytes32 sender, + bytes32 destinationChain, + bytes32 receiver, + bytes calldata payload, bytes[] memory attributes ) public pure returns (bytes32) { - return keccak256(abi.encode(sender, destinationChain, messages, attributes)); - } - - /// @notice Returns the keccak256 hash of a message request - /// - /// @param sender The CAIP-10 account address of the sender - /// @param destinationChain The CAIP-2 chain identifier of the destination chain - /// @param messages The messages to be included in the request - /// @param attributes The attributes to be included in the message - /// - /// @return _ The keccak256 hash of the message request - function getRequestIdCalldata( - string calldata sender, - string calldata destinationChain, - Message[] calldata messages, - bytes[] calldata attributes - ) public pure returns (bytes32) { - return keccak256(abi.encode(sender, destinationChain, messages, attributes)); + return keccak256(abi.encode(sourceChain, sender, destinationChain, receiver, payload, attributes)); } /// @notice Validates storage proofs and verifies fill @@ -341,22 +344,6 @@ abstract contract RIP7755Outbox is ERC7786Base { return fulfillmentInfo; } - function _sendMessages( - string calldata destinationChain, - Message[] memory messages, - bytes[] calldata globalAttributes - ) private returns (bytes32) { - bytes[] memory expandedAttributes = _processAttributes(globalAttributes); - string memory sender = address(this).local(); - - bytes32 messageId = getRequestId(sender, destinationChain, messages, expandedAttributes); - _messageStatus[messageId] = CrossChainCallStatus.Requested; - - emit MessagesPosted(messageId, destinationChain, sender, messages, expandedAttributes); - - return messageId; - } - function _processAttributes(bytes[] calldata attributes) private returns (bytes[] memory) { if (attributes.length < _EXPECTED_ATTRIBUTE_LENGTH) { revert InvalidAttributeLength(_EXPECTED_ATTRIBUTE_LENGTH, attributes.length); @@ -425,10 +412,7 @@ abstract contract RIP7755Outbox is ERC7786Base { } } - function _sendReward(bytes[] calldata attributes, address to) private { - bytes calldata rewardAttribute = _locateAttribute(attributes, _REWARD_ATTRIBUTE_SELECTOR); - (bytes32 rewardAsset, uint256 rewardAmount) = abi.decode(rewardAttribute[4:], (bytes32, uint256)); - + function _sendReward(address to, bytes32 rewardAsset, uint256 rewardAmount) private { if (rewardAsset == _NATIVE_ASSET) { payable(to).sendValue(rewardAmount); } else { @@ -452,14 +436,47 @@ abstract contract RIP7755Outbox is ERC7786Base { } } - function _isOptionalAttribute(bytes4 selector) private pure returns (bool) { + function _isOptionalAttribute(bytes4 selector) internal pure virtual returns (bool) { return selector == _PRECHECK_ATTRIBUTE_SELECTOR || selector == _L2_ORACLE_ATTRIBUTE_SELECTOR - || selector == _SHOYU_BASHI_ATTRIBUTE_SELECTOR || selector == _DESTINATION_CHAIN_SELECTOR; + || selector == _USER_OP_ATTRIBUTE_SELECTOR; + } + + function _getInboxAndReward(bytes[] calldata attributes) private pure returns (address, bytes32, uint256) { + bytes32 inbox; + bytes32 rewardAsset; + uint256 rewardAmount; + + for (uint256 i; i < attributes.length; i++) { + if (bytes4(attributes[i]) == _INBOX_ATTRIBUTE_SELECTOR) { + inbox = abi.decode(attributes[i][4:], (bytes32)); + } else if (bytes4(attributes[i]) == _REWARD_ATTRIBUTE_SELECTOR) { + (rewardAsset, rewardAmount) = abi.decode(attributes[i][4:], (bytes32, uint256)); + } + } + + return (inbox.bytes32ToAddress(), rewardAsset, rewardAmount); } - function _getInboxAddress(bytes[] calldata attributes) private pure returns (address) { - bytes calldata inboxAttribute = _locateAttribute(attributes, _INBOX_ATTRIBUTE_SELECTOR); - bytes32 inbox = abi.decode(inboxAttribute[4:], (bytes32)); - return inbox.bytes32ToAddress(); + function _getRequesterAndExpiryAndReward(bytes[] calldata attributes) + private + pure + returns (bytes32, uint256, bytes32, uint256) + { + bytes32 requester; + uint256 expiry; + bytes32 rewardAsset; + uint256 rewardAmount; + + for (uint256 i; i < attributes.length; i++) { + if (bytes4(attributes[i]) == _REQUESTER_ATTRIBUTE_SELECTOR) { + requester = abi.decode(attributes[i][4:], (bytes32)); + } else if (bytes4(attributes[i]) == _DELAY_ATTRIBUTE_SELECTOR) { + (, expiry) = abi.decode(attributes[i][4:], (uint256, uint256)); + } else if (bytes4(attributes[i]) == _REWARD_ATTRIBUTE_SELECTOR) { + (rewardAsset, rewardAmount) = abi.decode(attributes[i][4:], (bytes32, uint256)); + } + } + + return (requester, expiry, rewardAsset, rewardAmount); } } diff --git a/contracts/src/interfaces/IPrecheckContract.sol b/contracts/src/interfaces/IPrecheckContract.sol index adf83cb..b05fad9 100644 --- a/contracts/src/interfaces/IPrecheckContract.sol +++ b/contracts/src/interfaces/IPrecheckContract.sol @@ -1,30 +1,27 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import {ERC7786Base} from "../ERC7786Base.sol"; - /// @title IPrecheckContract /// /// @author Coinbase (https://github.com/base-org/7755-poc) /// -/// @notice A standardized interface for a valid Precheck Contract compatible with RIP-7755. A cross-chain-call can -/// optionally specify a Precheck Contract used to verify some arbitrary fulfillment condition during the -/// `fulfill` transaction. To specify a Precheck contract, set its address in a global request attribute using -/// the `_PRECHECK_ATTRIBUTE_SELECTOR` prefix. In order for the cross chain call to succeed with a precheck, -/// the Precheck contract must inherit this interface and implement `precheckCall`. +/// @notice A Precheck Contract interface compatible with RIP-7755. A cross-chain-call can optionally specify a Precheck +/// Contract used to verify some arbitrary fulfillment condition during the `fulfill` transaction. To specify a +/// Precheck contract, set its address in a global request attribute using the `_PRECHECK_ATTRIBUTE_SELECTOR` +/// prefix. interface IPrecheckContract { /// @notice A precheck function declaration. /// - /// @param sourceChain The CAIP-2 chain identifier of the source chain. - /// @param sender The CAIP-10 account address of the sender. - /// @param messages The messages to be included in the request. - /// @param globalAttributes The attributes array. - /// @param caller The address of the filler account that submitted the transaction to RIP7755Inbox. + /// @param sourceChain The chain identifier of the source chain. + /// @param sender The account address of the sender. + /// @param payload The encoded calls to be included in the request. + /// @param attributes The attributes array. + /// @param caller The address of the filler account that submitted the transaction to RIP7755Inbox. function precheckCall( - string calldata sourceChain, - string calldata sender, - ERC7786Base.Message[] calldata messages, - bytes[] calldata globalAttributes, + bytes32 sourceChain, + bytes32 sender, + bytes calldata payload, + bytes[] calldata attributes, address caller ) external view; } diff --git a/contracts/src/outboxes/RIP7755OutboxToHashi.sol b/contracts/src/outboxes/RIP7755OutboxToHashi.sol index 6e79fd6..8817c61 100644 --- a/contracts/src/outboxes/RIP7755OutboxToHashi.sol +++ b/contracts/src/outboxes/RIP7755OutboxToHashi.sol @@ -16,6 +16,12 @@ contract RIP7755OutboxToHashi is RIP7755Outbox { using HashiProver for bytes; using GlobalTypes for bytes32; + /// @notice The selector for the shoyuBashi attribute + bytes4 internal constant _SHOYU_BASHI_ATTRIBUTE_SELECTOR = 0xda07e15d; // shoyuBashi(bytes32) + + /// @notice The selector for the destinationChain attribute + bytes4 internal constant _DESTINATION_CHAIN_SELECTOR = 0xdff49bf1; // destinationChain(bytes32) + /// @notice This error is thrown when fulfillmentInfo.timestamp is less than request.finalityDelaySeconds from /// current destination chain block timestamp. error FinalityDelaySecondsInProgress(); @@ -72,4 +78,9 @@ contract RIP7755OutboxToHashi is RIP7755Outbox { bytes32 shoyuBashiBytes32 = abi.decode(shoyuBashiBytes[4:], (bytes32)); return shoyuBashiBytes32.bytes32ToAddress(); } + + function _isOptionalAttribute(bytes4 selector) internal pure override returns (bool) { + return selector == _SHOYU_BASHI_ATTRIBUTE_SELECTOR || selector == _DESTINATION_CHAIN_SELECTOR + || super._isOptionalAttribute(selector); + } } diff --git a/contracts/test/ArbitrumProver.t.sol b/contracts/test/ArbitrumProver.t.sol index bce45c8..bcd6083 100644 --- a/contracts/test/ArbitrumProver.t.sol +++ b/contracts/test/ArbitrumProver.t.sol @@ -2,8 +2,6 @@ pragma solidity 0.8.24; import {stdJson} from "forge-std/StdJson.sol"; -import {CAIP10} from "openzeppelin-contracts/contracts/utils/CAIP10.sol"; -import {CAIP2} from "openzeppelin-contracts/contracts/utils/CAIP2.sol"; import {Strings} from "openzeppelin-contracts/contracts/utils/Strings.sol"; import {GlobalTypes} from "../src/libraries/GlobalTypes.sol"; @@ -17,7 +15,6 @@ import {BaseTest} from "./BaseTest.t.sol"; contract ArbitrumProverTest is BaseTest { using stdJson for string; using GlobalTypes for address; - using CAIP10 for address; using Strings for address; MockArbitrumProver prover; @@ -46,7 +43,7 @@ contract ArbitrumProverTest is BaseTest { } function test_reverts_ifFinalityDelaySecondsStillInProgress() external fundAlice(_REWARD_AMOUNT) { - (string memory sourceChain, string memory sender, Message[] memory calls, bytes[] memory attributes) = + (string memory sourceChain, string memory sender, Call[] memory calls, bytes[] memory attributes) = _initMessage(_REWARD_AMOUNT); bytes32 messageId = _getMessageId(sourceChain, sender, calls, attributes); attributes[1] = abi.encodeWithSelector(_DELAY_ATTRIBUTE_SELECTOR, type(uint256).max - 1 ether, 1828828574); @@ -60,7 +57,7 @@ contract ArbitrumProverTest is BaseTest { } function test_reverts_ifInvalidL1State() external fundAlice(_REWARD_AMOUNT) { - (string memory sourceChain, string memory sender, Message[] memory calls, bytes[] memory attributes) = + (string memory sourceChain, string memory sender, Call[] memory calls, bytes[] memory attributes) = _initMessage(_REWARD_AMOUNT); bytes32 messageId = _getMessageId(sourceChain, sender, calls, attributes); @@ -73,7 +70,7 @@ contract ArbitrumProverTest is BaseTest { } function test_reverts_ifUnconfirmed() external fundAlice(_REWARD_AMOUNT) { - (string memory sourceChain, string memory sender, Message[] memory calls, bytes[] memory attributes) = + (string memory sourceChain, string memory sender, Call[] memory calls, bytes[] memory attributes) = _initMessage(_REWARD_AMOUNT); bytes32 messageId = _getMessageId(sourceChain, sender, calls, attributes); @@ -86,7 +83,7 @@ contract ArbitrumProverTest is BaseTest { } function test_reverts_ifInvalidRLPHeaders() external fundAlice(_REWARD_AMOUNT) { - (string memory sourceChain, string memory sender, Message[] memory calls, bytes[] memory attributes) = + (string memory sourceChain, string memory sender, Call[] memory calls, bytes[] memory attributes) = _initMessage(_REWARD_AMOUNT); bytes32 messageId = _getMessageId(sourceChain, sender, calls, attributes); @@ -99,7 +96,7 @@ contract ArbitrumProverTest is BaseTest { } function test_reverts_ifInvalidL2Storage() external fundAlice(_REWARD_AMOUNT) { - (string memory sourceChain, string memory sender, Message[] memory calls, bytes[] memory attributes) = + (string memory sourceChain, string memory sender, Call[] memory calls, bytes[] memory attributes) = _initMessage(_REWARD_AMOUNT); bytes32 messageId = _getMessageId(sourceChain, sender, calls, attributes); @@ -112,7 +109,7 @@ contract ArbitrumProverTest is BaseTest { } function test_proveArbitrumSepoliaStateFromBaseSepolia() external fundAlice(_REWARD_AMOUNT) { - (string memory sourceChain, string memory sender, Message[] memory calls, bytes[] memory attributes) = + (string memory sourceChain, string memory sender, Call[] memory calls, bytes[] memory attributes) = _initMessage(_REWARD_AMOUNT); bytes32 messageId = _getMessageId(sourceChain, sender, calls, attributes); @@ -174,20 +171,19 @@ contract ArbitrumProverTest is BaseTest { function _initMessage(uint256 rewardAmount) private view - returns (string memory, string memory, Message[] memory, bytes[] memory) + returns (string memory, string memory, Call[] memory, bytes[] memory) { string memory sourceChain = _remote(31337); string memory sender = address(this).toChecksumHexString(); - Message[] memory calls = new Message[](0); - bytes[] memory attributes = new bytes[](6); + Call[] memory calls = new Call[](0); + bytes[] memory attributes = new bytes[](5); attributes[0] = abi.encodeWithSelector(_REWARD_ATTRIBUTE_SELECTOR, address(mockErc20).addressToBytes32(), rewardAmount); attributes[1] = abi.encodeWithSelector(_DELAY_ATTRIBUTE_SELECTOR, 10, 1828828574); attributes[2] = abi.encodeWithSelector(_NONCE_ATTRIBUTE_SELECTOR, 1); attributes[3] = abi.encodeWithSelector(_REQUESTER_ATTRIBUTE_SELECTOR, ALICE.addressToBytes32()); - attributes[4] = abi.encodeWithSelector(_FULFILLER_ATTRIBUTE_SELECTOR, FILLER); - attributes[5] = + attributes[4] = abi.encodeWithSelector(_L2_ORACLE_ATTRIBUTE_SELECTOR, 0x042B2E6C5E99d4c521bd49beeD5E99651D9B0Cf4); // Arbitrum Rollup on Sepolia return (sourceChain, sender, calls, attributes); diff --git a/contracts/test/BaseTest.t.sol b/contracts/test/BaseTest.t.sol index a662ec9..d686eb8 100644 --- a/contracts/test/BaseTest.t.sol +++ b/contracts/test/BaseTest.t.sol @@ -7,11 +7,11 @@ import {CAIP2} from "openzeppelin-contracts/contracts/utils/CAIP2.sol"; import {CAIP10} from "openzeppelin-contracts/contracts/utils/CAIP10.sol"; import {Strings} from "openzeppelin-contracts/contracts/utils/Strings.sol"; -import {ERC7786Base} from "../src/ERC7786Base.sol"; +import {RIP7755Base} from "../src/RIP7755Base.sol"; import {MockBeaconOracle} from "./mocks/MockBeaconOracle.sol"; -contract BaseTest is Test, ERC7786Base { +contract BaseTest is Test, RIP7755Base { ERC20Mock mockErc20; MockBeaconOracle mockBeaconOracle; @@ -30,6 +30,30 @@ contract BaseTest is Test, ERC7786Base { uint256 constant _REWARD_AMOUNT = 1 ether; bytes32 constant _VERIFIER_STORAGE_LOCATION = 0xfd1017d80ffe8da8a74488ee7408c9efa1877e094afa95857de95797c1228500; + /// @notice The selector for the nonce attribute + bytes4 internal constant _NONCE_ATTRIBUTE_SELECTOR = 0xce03fdab; // nonce(uint256) + + /// @notice The selector for the reward attribute + bytes4 internal constant _REWARD_ATTRIBUTE_SELECTOR = 0xa362e5db; // reward(bytes32,uint256) rewardAsset, rewardAmount + + /// @notice The selector for the delay attribute + bytes4 internal constant _DELAY_ATTRIBUTE_SELECTOR = 0x84f550e0; // delay(uint256,uint256) finalityDelaySeconds, expiry + + /// @notice The selector for the requester attribute + bytes4 internal constant _REQUESTER_ATTRIBUTE_SELECTOR = 0x3bd94e4c; // requester(bytes32) + + /// @notice The selector for the l2Oracle attribute + bytes4 internal constant _L2_ORACLE_ATTRIBUTE_SELECTOR = 0x7ff7245a; // l2Oracle(address) + + /// @notice The selector for the shoyuBashi attribute + bytes4 internal constant _SHOYU_BASHI_ATTRIBUTE_SELECTOR = 0xda07e15d; // shoyuBashi(bytes32) + + /// @notice The selector for the inbox attribute + bytes4 internal constant _INBOX_ATTRIBUTE_SELECTOR = 0xbd362374; // inbox(bytes32) + + /// @notice The selector for the destinationChain attribute + bytes4 internal constant _DESTINATION_CHAIN_SELECTOR = 0xdff49bf1; // destinationChain(bytes32) + function _setUp() internal { mockErc20 = new ERC20Mock(); @@ -67,28 +91,14 @@ contract BaseTest is Test, ERC7786Base { return CAIP2.format("eip155", Strings.toString(chainId)); } - function _filterOutFulfiller(bytes[] memory attributes) internal pure returns (bytes[] memory) { - bytes[] memory filteredAttributes = new bytes[](attributes.length - 1); - uint256 filteredIndex; - for (uint256 i; i < attributes.length; i++) { - if (bytes4(attributes[i]) != _FULFILLER_ATTRIBUTE_SELECTOR) { - filteredAttributes[filteredIndex] = attributes[i]; - unchecked { - filteredIndex++; - } - } - } - return filteredAttributes; - } - function _getMessageId( string memory sourceChain, string memory sender, - Message[] memory calls, + Call[] memory calls, bytes[] memory attributes ) internal pure returns (bytes32) { string memory combinedSender = CAIP10.format(sourceChain, sender); - return keccak256(abi.encode(combinedSender, _remote(111112), calls, _filterOutFulfiller(attributes))); + return keccak256(abi.encode(combinedSender, _remote(111112), calls, attributes)); } // Including to block from coverage report diff --git a/contracts/test/ERC7786Base.t.sol b/contracts/test/ERC7786Base.t.sol index 537543e..4506632 100644 --- a/contracts/test/ERC7786Base.t.sol +++ b/contracts/test/ERC7786Base.t.sol @@ -6,30 +6,30 @@ import {BaseTest} from "./BaseTest.t.sol"; contract ERC7786BaseTest is BaseTest { function test_locateAttribute_returnsAttribute() external view { bytes[] memory attributes = new bytes[](1); - attributes[0] = abi.encodeWithSelector(_FULFILLER_ATTRIBUTE_SELECTOR, FILLER); - bytes memory returnedAttribute = this.submitAttributes(attributes, _FULFILLER_ATTRIBUTE_SELECTOR); + attributes[0] = abi.encodeWithSelector(_DESTINATION_CHAIN_SELECTOR, FILLER); + bytes memory returnedAttribute = this.submitAttributes(attributes, _DESTINATION_CHAIN_SELECTOR); assertEq(returnedAttribute, attributes[0]); } function test_locateAttribute_revertsIfAttributeNotFound() external { bytes[] memory attributes = new bytes[](1); - attributes[0] = abi.encodeWithSelector(_FULFILLER_ATTRIBUTE_SELECTOR, FILLER); + attributes[0] = abi.encodeWithSelector(_DESTINATION_CHAIN_SELECTOR, FILLER); vm.expectRevert(abi.encodeWithSelector(AttributeNotFound.selector, _PRECHECK_ATTRIBUTE_SELECTOR)); this.submitAttributes(attributes, _PRECHECK_ATTRIBUTE_SELECTOR); } function test_locateAttributeUnchecked_returnsAttribute() external view { bytes[] memory attributes = new bytes[](1); - attributes[0] = abi.encodeWithSelector(_FULFILLER_ATTRIBUTE_SELECTOR, FILLER); + attributes[0] = abi.encodeWithSelector(_DESTINATION_CHAIN_SELECTOR, FILLER); (bool found, bytes memory returnedAttribute) = - this.locateAttributeUnchecked(attributes, _FULFILLER_ATTRIBUTE_SELECTOR); + this.locateAttributeUnchecked(attributes, _DESTINATION_CHAIN_SELECTOR); assertTrue(found); assertEq(returnedAttribute, attributes[0]); } function test_locateAttributeUnchecked_returnsFalseIfAttributeNotFound() external view { bytes[] memory attributes = new bytes[](1); - attributes[0] = abi.encodeWithSelector(_FULFILLER_ATTRIBUTE_SELECTOR, FILLER); + attributes[0] = abi.encodeWithSelector(_DESTINATION_CHAIN_SELECTOR, FILLER); (bool found, bytes memory returnedAttribute) = this.locateAttributeUnchecked(attributes, _PRECHECK_ATTRIBUTE_SELECTOR); assertFalse(found); diff --git a/contracts/test/HashiProver.t.sol b/contracts/test/HashiProver.t.sol index 5b081f4..d006f5a 100644 --- a/contracts/test/HashiProver.t.sol +++ b/contracts/test/HashiProver.t.sol @@ -36,10 +36,22 @@ contract HashiProverTest is BaseTest { validProof = vm.readFile(path); } + function test_isOptionalAttribute_shoyuBashi() external view { + assert(prover.isOptionalAttribute(_SHOYU_BASHI_ATTRIBUTE_SELECTOR)); + } + + function test_isOptionalAttribute_destinationChain() external view { + assert(prover.isOptionalAttribute(_DESTINATION_CHAIN_SELECTOR)); + } + + function test_isOptionalAttribute_precheck() external view { + assert(prover.isOptionalAttribute(_PRECHECK_ATTRIBUTE_SELECTOR)); + } + function test_reverts_ifFinalityDelaySecondsStillInProgress() external fundAlice(_REWARD_AMOUNT) { - (string memory sender, string memory destinationChain, Message[] memory calls, bytes[] memory attributes) = + (string memory sender, string memory destinationChain, Call[] memory calls, bytes[] memory attributes) = _initMessage(_REWARD_AMOUNT); - bytes32 messageId = prover.getRequestId(sender, destinationChain, calls, attributes); + bytes32 messageId = _getMessageId(sender, destinationChain, calls, attributes); HashiProver.RIP7755Proof memory proof = _buildProof(validProof); bytes memory inboxStorageKey = _deriveStorageKey(messageId); @@ -51,9 +63,9 @@ contract HashiProverTest is BaseTest { } function test_reverts_ifInvaldBlockHeader() external fundAlice(_REWARD_AMOUNT) { - (string memory sender, string memory destinationChain, Message[] memory calls, bytes[] memory attributes) = + (string memory sender, string memory destinationChain, Call[] memory calls, bytes[] memory attributes) = _initMessage(_REWARD_AMOUNT); - bytes32 messageId = prover.getRequestId(sender, destinationChain, calls, attributes); + bytes32 messageId = _getMessageId(sender, destinationChain, calls, attributes); HashiProver.RIP7755Proof memory proof = _buildProof(validProof); (, uint256 blockNumber,) = proof.rlpEncodedBlockHeader.extractStateRootBlockNumberAndTimestamp(); @@ -70,9 +82,9 @@ contract HashiProverTest is BaseTest { function test_reverts_ifInvalidStorage() external fundAlice(_REWARD_AMOUNT) { bytes memory wrongStorageValue = "0x23214a0864fc0014cab6030267738f01affdd547000000000000000067444860"; - (string memory sender, string memory destinationChain, Message[] memory calls, bytes[] memory attributes) = + (string memory sender, string memory destinationChain, Call[] memory calls, bytes[] memory attributes) = _initMessage(_REWARD_AMOUNT); - bytes32 messageId = prover.getRequestId(sender, destinationChain, calls, attributes); + bytes32 messageId = _getMessageId(sender, destinationChain, calls, attributes); HashiProver.RIP7755Proof memory proof = _buildProof(validProof); proof.dstAccountProofParams.storageValue = wrongStorageValue; @@ -84,9 +96,9 @@ contract HashiProverTest is BaseTest { } function test_proveGnosisChiadoStateFromBaseSepolia() external fundAlice(_REWARD_AMOUNT) { - (string memory sender, string memory destinationChain, Message[] memory calls, bytes[] memory attributes) = + (string memory sender, string memory destinationChain, Call[] memory calls, bytes[] memory attributes) = _initMessage(_REWARD_AMOUNT); - bytes32 messageId = prover.getRequestId(sender, destinationChain, calls, attributes); + bytes32 messageId = _getMessageId(sender, destinationChain, calls, attributes); HashiProver.RIP7755Proof memory proof = _buildProof(validProof); bytes memory inboxStorageKey = _deriveStorageKey(messageId); @@ -117,21 +129,20 @@ contract HashiProverTest is BaseTest { function _initMessage(uint256 rewardAmount) private view - returns (string memory, string memory, Message[] memory, bytes[] memory) + returns (string memory, string memory, Call[] memory, bytes[] memory) { string memory sender = address(this).local(); string memory destinationChain = _remote(HASHI_DOMAIN_DST_CHAIN_ID); - Message[] memory calls = new Message[](0); - bytes[] memory attributes = new bytes[](7); + Call[] memory calls = new Call[](0); + bytes[] memory attributes = new bytes[](6); attributes[0] = abi.encodeWithSelector(_REWARD_ATTRIBUTE_SELECTOR, address(mockErc20).addressToBytes32(), rewardAmount); attributes[1] = abi.encodeWithSelector(_DELAY_ATTRIBUTE_SELECTOR, 10, 1828828574); attributes[2] = abi.encodeWithSelector(_NONCE_ATTRIBUTE_SELECTOR, 1); attributes[3] = abi.encodeWithSelector(_REQUESTER_ATTRIBUTE_SELECTOR, ALICE.addressToBytes32()); - attributes[4] = abi.encodeWithSelector(_FULFILLER_ATTRIBUTE_SELECTOR, FILLER); - attributes[5] = abi.encodeWithSelector(_SHOYU_BASHI_ATTRIBUTE_SELECTOR, address(shoyuBashi).addressToBytes32()); - attributes[6] = abi.encodeWithSelector(_DESTINATION_CHAIN_SELECTOR, bytes32(HASHI_DOMAIN_DST_CHAIN_ID)); + attributes[4] = abi.encodeWithSelector(_SHOYU_BASHI_ATTRIBUTE_SELECTOR, address(shoyuBashi).addressToBytes32()); + attributes[5] = abi.encodeWithSelector(_DESTINATION_CHAIN_SELECTOR, bytes32(HASHI_DOMAIN_DST_CHAIN_ID)); return (sender, destinationChain, calls, attributes); } diff --git a/contracts/test/OPStackProver.t.sol b/contracts/test/OPStackProver.t.sol index 4e65b9a..e5f387f 100644 --- a/contracts/test/OPStackProver.t.sol +++ b/contracts/test/OPStackProver.t.sol @@ -2,10 +2,8 @@ pragma solidity 0.8.24; import {stdJson} from "forge-std/StdJson.sol"; -import {CAIP10} from "openzeppelin-contracts/contracts/utils/CAIP10.sol"; import {OPStackProver} from "../src/libraries/provers/OPStackProver.sol"; -import {GlobalTypes} from "../src/libraries/GlobalTypes.sol"; import {StateValidator} from "../src/libraries/StateValidator.sol"; import {RIP7755OutboxToOPStack} from "../src/outboxes/RIP7755OutboxToOPStack.sol"; @@ -14,7 +12,6 @@ import {BaseTest} from "./BaseTest.t.sol"; contract OPStackProverTest is BaseTest { using stdJson for string; - using GlobalTypes for address; MockOPStackProver prover; @@ -36,7 +33,7 @@ contract OPStackProverTest is BaseTest { } function test_validate_reverts_ifFinalityDelaySecondsInProgress() external fundAlice(_REWARD_AMOUNT) { - (string memory sourceChain, string memory sender, Message[] memory calls, bytes[] memory attributes) = + (string memory sourceChain, string memory sender, Call[] memory calls, bytes[] memory attributes) = _initMessage(_REWARD_AMOUNT); bytes32 messageId = _getMessageId(sourceChain, sender, calls, attributes); attributes[1] = abi.encodeWithSelector(_DELAY_ATTRIBUTE_SELECTOR, type(uint256).max - 1 ether, 1735681520); @@ -50,7 +47,7 @@ contract OPStackProverTest is BaseTest { } function test_validate_reverts_ifBeaconRootCallFails() external fundAlice(_REWARD_AMOUNT) { - (string memory sourceChain, string memory sender, Message[] memory calls, bytes[] memory attributes) = + (string memory sourceChain, string memory sender, Call[] memory calls, bytes[] memory attributes) = _initMessage(_REWARD_AMOUNT); bytes32 messageId = _getMessageId(sourceChain, sender, calls, attributes); @@ -65,7 +62,7 @@ contract OPStackProverTest is BaseTest { } function test_validate_reverts_ifInvalidBeaconRoot() external fundAlice(_REWARD_AMOUNT) { - (string memory sourceChain, string memory sender, Message[] memory calls, bytes[] memory attributes) = + (string memory sourceChain, string memory sender, Call[] memory calls, bytes[] memory attributes) = _initMessage(_REWARD_AMOUNT); bytes32 messageId = _getMessageId(sourceChain, sender, calls, attributes); @@ -80,7 +77,7 @@ contract OPStackProverTest is BaseTest { } function test_validate_reverts_ifInvalidL1StateRoot() external fundAlice(_REWARD_AMOUNT) { - (string memory sourceChain, string memory sender, Message[] memory calls, bytes[] memory attributes) = + (string memory sourceChain, string memory sender, Call[] memory calls, bytes[] memory attributes) = _initMessage(_REWARD_AMOUNT); bytes32 messageId = _getMessageId(sourceChain, sender, calls, attributes); @@ -95,7 +92,7 @@ contract OPStackProverTest is BaseTest { } function test_validate_reverts_ifInvalidL1Storage() external fundAlice(_REWARD_AMOUNT) { - (string memory sourceChain, string memory sender, Message[] memory calls, bytes[] memory attributes) = + (string memory sourceChain, string memory sender, Call[] memory calls, bytes[] memory attributes) = _initMessage(_REWARD_AMOUNT); bytes32 messageId = _getMessageId(sourceChain, sender, calls, attributes); @@ -108,7 +105,7 @@ contract OPStackProverTest is BaseTest { } function test_validate_reverts_ifInvalidL2StateRoot() external fundAlice(_REWARD_AMOUNT) { - (string memory sourceChain, string memory sender, Message[] memory calls, bytes[] memory attributes) = + (string memory sourceChain, string memory sender, Call[] memory calls, bytes[] memory attributes) = _initMessage(_REWARD_AMOUNT); bytes32 messageId = _getMessageId(sourceChain, sender, calls, attributes); @@ -121,7 +118,7 @@ contract OPStackProverTest is BaseTest { } function test_validate_reverts_ifInvalidL2Storage() external fundAlice(_REWARD_AMOUNT) { - (string memory sourceChain, string memory sender, Message[] memory calls, bytes[] memory attributes) = + (string memory sourceChain, string memory sender, Call[] memory calls, bytes[] memory attributes) = _initMessage(_REWARD_AMOUNT); bytes32 messageId = _getMessageId(sourceChain, sender, calls, attributes); @@ -134,7 +131,7 @@ contract OPStackProverTest is BaseTest { } function test_validate_proveOptimismSepoliaStateFromBaseSepolia() external fundAlice(_REWARD_AMOUNT) { - (string memory sourceChain, string memory sender, Message[] memory calls, bytes[] memory attributes) = + (string memory sourceChain, string memory sender, Call[] memory calls, bytes[] memory attributes) = _initMessage(_REWARD_AMOUNT); bytes32 messageId = _getMessageId(sourceChain, sender, calls, attributes); @@ -183,13 +180,13 @@ contract OPStackProverTest is BaseTest { function _initMessage(uint256 rewardAmount) private - view - returns (string memory, string memory, Message[] memory, bytes[] memory) + pure + returns (string memory, string memory, Call[] memory, bytes[] memory) { string memory sourceChain = _remote(31337); string memory sender = "0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496"; - Message[] memory calls = new Message[](0); - bytes[] memory attributes = new bytes[](6); + Call[] memory calls = new Call[](0); + bytes[] memory attributes = new bytes[](5); attributes[0] = abi.encodeWithSelector( _REWARD_ATTRIBUTE_SELECTOR, 0x000000000000000000000000f62849f9a0b5bf2913b396098f7c7019b51a820a, rewardAmount @@ -199,8 +196,7 @@ contract OPStackProverTest is BaseTest { attributes[3] = abi.encodeWithSelector( _REQUESTER_ATTRIBUTE_SELECTOR, 0x000000000000000000000000328809bc894f92807417d2dad6b7c998c1afdac6 ); - attributes[4] = abi.encodeWithSelector(_FULFILLER_ATTRIBUTE_SELECTOR, FILLER); - attributes[5] = + attributes[4] = abi.encodeWithSelector(_L2_ORACLE_ATTRIBUTE_SELECTOR, 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512); return (sourceChain, sender, calls, attributes); diff --git a/contracts/test/RIP7755Inbox.t.sol b/contracts/test/RIP7755Inbox.t.sol index 3a4c007..30ad726 100644 --- a/contracts/test/RIP7755Inbox.t.sol +++ b/contracts/test/RIP7755Inbox.t.sol @@ -1,8 +1,6 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.24; -import {CAIP2} from "openzeppelin-contracts/contracts/utils/CAIP2.sol"; -import {Strings} from "openzeppelin-contracts/contracts/utils/Strings.sol"; import {EntryPoint} from "account-abstraction/core/EntryPoint.sol"; import {GlobalTypes} from "../src/libraries/GlobalTypes.sol"; @@ -15,13 +13,12 @@ import {BaseTest} from "./BaseTest.t.sol"; contract RIP7755InboxTest is BaseTest { using GlobalTypes for address; - using Strings for address; struct TestMessage { bytes32 messageId; - string sourceChain; - string sender; - Message[] messages; + bytes32 sourceChain; + bytes32 sender; + bytes payload; bytes[] attributes; } @@ -42,25 +39,18 @@ contract RIP7755InboxTest is BaseTest { _setUp(); } - function test_executeMessages_reverts_ifNoFulfiller() external { - TestMessage memory m = _initMessage(false, true); - - vm.expectRevert(abi.encodeWithSelector(AttributeNotFound.selector, _FULFILLER_ATTRIBUTE_SELECTOR)); - inbox.executeMessages(m.sourceChain, m.sender, m.messages, _filterOutFulfiller(m.attributes)); - } - - function test_executeMessages_reverts_userOp() external { + function test_fulfill_reverts_userOp() external { TestMessage memory m = _initMessage(false, true); vm.expectRevert(RIP7755Inbox.UserOp.selector); - inbox.executeMessages(m.sourceChain, m.sender, m.messages, m.attributes); + inbox.fulfill(m.sourceChain, m.sender, m.payload, m.attributes, FILLER); } - function test_executeMessages_storesFulfillment_withSuccessfulPrecheck() external { + function test_fulfill_storesFulfillment_withSuccessfulPrecheck() external { TestMessage memory m = _initMessage(true, false); - vm.prank(FILLER); - inbox.executeMessages(m.sourceChain, m.sender, m.messages, m.attributes); + vm.prank(FILLER, FILLER); + inbox.fulfill(m.sourceChain, m.sender, m.payload, m.attributes, FILLER); RIP7755Inbox.FulfillmentInfo memory info = inbox.getFulfillmentInfo(m.messageId); @@ -68,109 +58,76 @@ contract RIP7755InboxTest is BaseTest { assertEq(info.timestamp, block.timestamp); } - function test_executeMessages_reverts_failedPrecheck() external { + function test_fulfill_reverts_failedPrecheck() external { TestMessage memory m = _initMessage(true, false); vm.expectRevert(); - inbox.executeMessages(m.sourceChain, m.sender, m.messages, m.attributes); + inbox.fulfill(m.sourceChain, m.sender, m.payload, m.attributes, FILLER); } - function test_executeMessages_reverts_callAlreadyFulfilled() external { + function test_fulfill_reverts_callAlreadyFulfilled() external { TestMessage memory m = _initMessage(false, false); vm.prank(FILLER); - inbox.executeMessages(m.sourceChain, m.sender, m.messages, m.attributes); + inbox.fulfill(m.sourceChain, m.sender, m.payload, m.attributes, FILLER); vm.prank(FILLER); vm.expectRevert(RIP7755Inbox.CallAlreadyFulfilled.selector); - inbox.executeMessages(m.sourceChain, m.sender, m.messages, m.attributes); + inbox.fulfill(m.sourceChain, m.sender, m.payload, m.attributes, FILLER); } - function test_executeMessages_callsTargetContract(uint256 inputNum) external { + function test_fulfill_callsTargetContract(uint256 inputNum) external { TestMessage memory m = _initMessage(false, false); - _appendMessage( + _appendCall( m, - Message({ - receiver: address(target).toChecksumHexString(), - payload: abi.encodeWithSelector(target.target.selector, inputNum), - attributes: new bytes[](0) + Call({ + to: address(target).addressToBytes32(), + data: abi.encodeWithSelector(target.target.selector, inputNum), + value: 0 }) ); vm.prank(FILLER); - inbox.executeMessages(m.sourceChain, m.sender, m.messages, m.attributes); + inbox.fulfill(m.sourceChain, m.sender, m.payload, m.attributes, FILLER); assertEq(target.number(), inputNum); } - function test_executeMessages_sendsEth(uint256 amount) external { + function test_fulfill_sendsEth(uint256 amount) external { TestMessage memory m = _initMessage(false, false); - bytes[] memory attributes = new bytes[](1); - attributes[0] = abi.encodeWithSelector(_VALUE_ATTRIBUTE_SELECTOR, amount); - - _appendMessage(m, Message({receiver: ALICE.toChecksumHexString(), payload: "", attributes: attributes})); + _appendCall(m, Call({to: ALICE.addressToBytes32(), data: "", value: amount})); vm.deal(FILLER, amount); vm.prank(FILLER); - inbox.executeMessages{value: amount}(m.sourceChain, m.sender, m.messages, m.attributes); + inbox.fulfill{value: amount}(m.sourceChain, m.sender, m.payload, m.attributes, FILLER); assertEq(ALICE.balance, amount); } - function test_executeMessages_doesntSendsEth(uint256 amount) external { - TestMessage memory m = _initMessage(false, false); - - bytes[] memory attributes = new bytes[](1); - attributes[0] = abi.encodeWithSelector(_FULFILLER_ATTRIBUTE_SELECTOR, FILLER); - - _appendMessage(m, Message({receiver: ALICE.toChecksumHexString(), payload: "", attributes: attributes})); - - vm.deal(FILLER, amount); - vm.prank(FILLER); - inbox.executeMessages(m.sourceChain, m.sender, m.messages, m.attributes); - - assertEq(ALICE.balance, 0); - } - - function test_executeMessages_reverts_tooManyAttributes(uint256 amount) external { - TestMessage memory m = _initMessage(false, false); - - bytes[] memory attributes = new bytes[](2); - - _appendMessage(m, Message({receiver: ALICE.toChecksumHexString(), payload: "", attributes: attributes})); - - vm.deal(FILLER, amount); - vm.prank(FILLER); - vm.expectRevert(MaxOneAttributeExpected.selector); - inbox.executeMessages(m.sourceChain, m.sender, m.messages, m.attributes); - - assertEq(ALICE.balance, 0); - } - - function test_executeMessages_reverts_ifTargetContractReverts() external { + function test_fulfill_reverts_ifTargetContractReverts() external { TestMessage memory m = _initMessage(false, false); - _appendMessage( + _appendCall( m, - Message({ - receiver: address(target).toChecksumHexString(), - payload: abi.encodeWithSelector(target.shouldFail.selector), - attributes: new bytes[](0) + Call({ + to: address(target).addressToBytes32(), + data: abi.encodeWithSelector(target.shouldFail.selector), + value: 0 }) ); vm.prank(FILLER); vm.expectRevert(MockTarget.MockError.selector); - inbox.executeMessages(m.sourceChain, m.sender, m.messages, m.attributes); + inbox.fulfill(m.sourceChain, m.sender, m.payload, m.attributes, FILLER); } - function test_executeMessages_storesFulfillment() external { + function test_fulfill_storesFulfillment() external { TestMessage memory m = _initMessage(false, false); vm.prank(FILLER); - inbox.executeMessages(m.sourceChain, m.sender, m.messages, m.attributes); + inbox.fulfill(m.sourceChain, m.sender, m.payload, m.attributes, FILLER); RIP7755Inbox.FulfillmentInfo memory info = inbox.getFulfillmentInfo(m.messageId); @@ -178,55 +135,58 @@ contract RIP7755InboxTest is BaseTest { assertEq(info.timestamp, block.timestamp); } - function test_executeMessages_reverts_ifMsgValueTooHigh() external { + function test_fulfill_reverts_ifMsgValueTooHigh() external { TestMessage memory m = _initMessage(false, false); vm.deal(FILLER, 1); vm.prank(FILLER); vm.expectRevert(abi.encodeWithSelector(Paymaster.InvalidValue.selector, 0, 1)); - inbox.executeMessages{value: 1}(m.sourceChain, m.sender, m.messages, m.attributes); + inbox.fulfill{value: 1}(m.sourceChain, m.sender, m.payload, m.attributes, FILLER); } - function test_executeMessages_emitsEvent() external { + function test_fulfill_emitsEvent() external { TestMessage memory m = _initMessage(false, false); vm.prank(FILLER); vm.expectEmit(true, true, false, false); emit CallFulfilled({requestHash: m.messageId, fulfilledBy: FILLER}); - inbox.executeMessages(m.sourceChain, m.sender, m.messages, m.attributes); + inbox.fulfill(m.sourceChain, m.sender, m.payload, m.attributes, FILLER); } function _initMessage(bool isPrecheck, bool isUserOp) private view returns (TestMessage memory) { - string memory sourceChain = CAIP2.local(); - string memory sender = address(this).toChecksumHexString(); - bytes[] memory attributes = new bytes[](isPrecheck ? 7 : 6); + bytes32 sourceChain = bytes32(block.chainid); + bytes32 sender = address(this).addressToBytes32(); + bytes memory payload = abi.encode(new Call[](0)); + bytes[] memory attributes = new bytes[](isPrecheck ? 6 : 5); attributes[0] = abi.encodeWithSelector(_REWARD_ATTRIBUTE_SELECTOR, bytes32(0), uint256(0)); attributes[1] = abi.encodeWithSelector(_DELAY_ATTRIBUTE_SELECTOR, 10, block.timestamp + 11); attributes[2] = abi.encodeWithSelector(_NONCE_ATTRIBUTE_SELECTOR, 1); attributes[3] = abi.encodeWithSelector(_REQUESTER_ATTRIBUTE_SELECTOR, ALICE.addressToBytes32()); - attributes[4] = abi.encodeWithSelector(_FULFILLER_ATTRIBUTE_SELECTOR, FILLER); - attributes[5] = abi.encodeWithSelector(_USER_OP_ATTRIBUTE_SELECTOR, isUserOp); + attributes[4] = abi.encodeWithSelector(_USER_OP_ATTRIBUTE_SELECTOR, isUserOp); if (isPrecheck) { - attributes[6] = abi.encodeWithSelector(_PRECHECK_ATTRIBUTE_SELECTOR, address(precheck)); + attributes[5] = abi.encodeWithSelector(_PRECHECK_ATTRIBUTE_SELECTOR, address(precheck)); } return TestMessage({ - messageId: inbox.getRequestId(sourceChain, sender, new Message[](0), attributes), + messageId: inbox.getRequestId( + sourceChain, sender, bytes32(block.chainid), address(inbox).addressToBytes32(), payload, attributes + ), sourceChain: sourceChain, sender: sender, - messages: new Message[](0), + payload: payload, attributes: attributes }); } - function _appendMessage(TestMessage memory m, Message memory message) private pure { - Message[] memory messages = new Message[](m.messages.length + 1); - for (uint256 i = 0; i < m.messages.length; i++) { - messages[i] = m.messages[i]; + function _appendCall(TestMessage memory m, Call memory call) private pure { + Call[] memory currentCalls = abi.decode(m.payload, (Call[])); + Call[] memory newCalls = new Call[](currentCalls.length + 1); + for (uint256 i; i < currentCalls.length; i++) { + newCalls[i] = currentCalls[i]; } - messages[m.messages.length] = message; - m.messages = messages; + newCalls[currentCalls.length] = Call({to: call.to, value: call.value, data: call.data}); + m.payload = abi.encode(newCalls); } } diff --git a/contracts/test/RIP7755Outbox.t.sol b/contracts/test/RIP7755Outbox.t.sol index 7076a77..bacd0bf 100644 --- a/contracts/test/RIP7755Outbox.t.sol +++ b/contracts/test/RIP7755Outbox.t.sol @@ -1,10 +1,6 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.24; -import {CAIP2} from "openzeppelin-contracts/contracts/utils/CAIP2.sol"; -import {CAIP10} from "openzeppelin-contracts/contracts/utils/CAIP10.sol"; -import {Strings} from "openzeppelin-contracts/contracts/utils/Strings.sol"; - import {GlobalTypes} from "../src/libraries/GlobalTypes.sol"; import {RIP7755Outbox} from "../src/RIP7755Outbox.sol"; @@ -13,13 +9,13 @@ import {BaseTest} from "./BaseTest.t.sol"; contract RIP7755OutboxTest is BaseTest { using GlobalTypes for address; - using CAIP10 for address; - using Strings for address; struct TestMessage { - string destinationChain; - string sender; - Message[] messages; + bytes32 sourceChain; + bytes32 destinationChain; + bytes32 sender; + bytes32 receiver; + bytes payload; bytes[] attributes; } @@ -27,8 +23,15 @@ contract RIP7755OutboxTest is BaseTest { bytes32 private constant _NATIVE_ASSET = 0x000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee; - event MessagesPosted( - bytes32 indexed outboxId, string destinationChain, string sender, Message[] messages, bytes[] globalAttributes + event MessagePosted( + bytes32 indexed outboxId, + bytes32 sourceChain, + bytes32 sender, + bytes32 destinationChain, + bytes32 receiver, + bytes payload, + uint256 value, + bytes[] attributes ); event CrossChainCallCompleted(bytes32 indexed requestHash, address submitter); event CrossChainCallCanceled(bytes32 indexed callHash); @@ -47,36 +50,21 @@ contract RIP7755OutboxTest is BaseTest { vm.prank(ALICE); vm.expectEmit(true, false, false, true); - emit MessagesPosted(messageId, m.destinationChain, m.sender, m.messages, adjustedAttributes); - outbox.sendMessage(m.destinationChain, m.messages[0].receiver, m.messages[0].payload, m.attributes); - - adjustedAttributes[3] = abi.encodeWithSelector(_NONCE_ATTRIBUTE_SELECTOR, 2); - messageId = outbox.getRequestIdCalldata(m.sender, m.destinationChain, m.messages, adjustedAttributes); - - vm.prank(ALICE); - vm.expectEmit(true, false, false, true); - emit MessagesPosted(messageId, m.destinationChain, m.sender, m.messages, adjustedAttributes); - outbox.sendMessage(m.destinationChain, m.messages[0].receiver, m.messages[0].payload, m.attributes); - } - - function test_sendMessages_incrementsNonce(uint256 rewardAmount) external fundAlice(rewardAmount) { - TestMessage memory m = _initMessage(rewardAmount / 2, false); - bytes32 messageId = _deriveMessageId(m); - - bytes[] memory adjustedAttributes = _getAdjustedAttributes(m); - - vm.prank(ALICE); - vm.expectEmit(true, false, false, true); - emit MessagesPosted(messageId, m.destinationChain, m.sender, m.messages, adjustedAttributes); - outbox.sendMessages(m.destinationChain, m.messages, m.attributes); + emit MessagePosted( + messageId, m.sourceChain, m.sender, m.destinationChain, m.receiver, m.payload, 0, adjustedAttributes + ); + outbox.sendMessage(m.destinationChain, m.receiver, m.payload, m.attributes); adjustedAttributes[3] = abi.encodeWithSelector(_NONCE_ATTRIBUTE_SELECTOR, 2); - messageId = outbox.getRequestIdCalldata(m.sender, m.destinationChain, m.messages, adjustedAttributes); + messageId = + outbox.getRequestId(m.sourceChain, m.sender, m.destinationChain, m.receiver, m.payload, adjustedAttributes); vm.prank(ALICE); vm.expectEmit(true, false, false, true); - emit MessagesPosted(messageId, m.destinationChain, m.sender, m.messages, adjustedAttributes); - outbox.sendMessages(m.destinationChain, m.messages, m.attributes); + emit MessagePosted( + messageId, m.sourceChain, m.sender, m.destinationChain, m.receiver, m.payload, 0, adjustedAttributes + ); + outbox.sendMessage(m.destinationChain, m.receiver, m.payload, m.attributes); } function test_sendMessage_reverts_ifInvalidNativeCurrency(uint256 rewardAmount) external fundAlice(rewardAmount) { @@ -85,16 +73,7 @@ contract RIP7755OutboxTest is BaseTest { vm.prank(ALICE); vm.expectRevert(abi.encodeWithSelector(RIP7755Outbox.InvalidValue.selector, rewardAmount, 0)); - outbox.sendMessage(m.destinationChain, m.messages[0].receiver, m.messages[0].payload, m.attributes); - } - - function test_sendMessages_reverts_ifInvalidNativeCurrency(uint256 rewardAmount) external fundAlice(rewardAmount) { - rewardAmount = bound(rewardAmount, 1, type(uint256).max); - TestMessage memory m = _initMessage(rewardAmount, true); - - vm.prank(ALICE); - vm.expectRevert(abi.encodeWithSelector(RIP7755Outbox.InvalidValue.selector, rewardAmount, 0)); - outbox.sendMessages(m.destinationChain, m.messages, m.attributes); + outbox.sendMessage(m.destinationChain, m.receiver, m.payload, m.attributes); } function test_sendMessage_reverts_ifMissingAttributes(uint256 rewardAmount) external fundAlice(rewardAmount) { @@ -103,16 +82,7 @@ contract RIP7755OutboxTest is BaseTest { vm.prank(ALICE); vm.expectRevert(abi.encodeWithSelector(RIP7755Outbox.InvalidAttributeLength.selector, 3, 0)); - outbox.sendMessage(m.destinationChain, m.messages[0].receiver, m.messages[0].payload, new bytes[](0)); - } - - function test_sendMessages_reverts_ifMissingAttributes(uint256 rewardAmount) external fundAlice(rewardAmount) { - vm.assume(rewardAmount > 0); - TestMessage memory m = _initMessage(rewardAmount, false); - - vm.prank(ALICE); - vm.expectRevert(abi.encodeWithSelector(RIP7755Outbox.InvalidAttributeLength.selector, 3, 0)); - outbox.sendMessages(m.destinationChain, m.messages, new bytes[](0)); + outbox.sendMessage(m.destinationChain, m.receiver, m.payload, new bytes[](0)); } function test_sendMessage_reverts_ifNativeCurrencyIncludedUnnecessarily(uint256 rewardAmount) @@ -125,20 +95,7 @@ contract RIP7755OutboxTest is BaseTest { vm.prank(ALICE); vm.expectRevert(abi.encodeWithSelector(RIP7755Outbox.InvalidValue.selector, 0, 1)); - outbox.sendMessage{value: 1}(m.destinationChain, m.messages[0].receiver, m.messages[0].payload, m.attributes); - } - - function test_sendMessages_reverts_ifNativeCurrencyIncludedUnnecessarily(uint256 rewardAmount) - external - fundAlice(rewardAmount) - { - if (rewardAmount < 2) return; - - TestMessage memory m = _initMessage(rewardAmount, false); - - vm.prank(ALICE); - vm.expectRevert(abi.encodeWithSelector(RIP7755Outbox.InvalidValue.selector, 0, 1)); - outbox.sendMessages{value: 1}(m.destinationChain, m.messages, m.attributes); + outbox.sendMessage{value: 1}(m.destinationChain, m.receiver, m.payload, m.attributes); } function test_sendMessage_reverts_ifExpiryTooSoon(uint256 rewardAmount) external fundAlice(rewardAmount) { @@ -147,33 +104,14 @@ contract RIP7755OutboxTest is BaseTest { vm.prank(ALICE); vm.expectRevert(RIP7755Outbox.ExpiryTooSoon.selector); - outbox.sendMessage(m.destinationChain, m.messages[0].receiver, m.messages[0].payload, m.attributes); - } - - function test_sendMessages_reverts_ifExpiryTooSoon(uint256 rewardAmount) external fundAlice(rewardAmount) { - TestMessage memory m = _initMessage(rewardAmount, false); - m.attributes = _setDelay(m.attributes, 10, block.timestamp + 10 - 1); - - vm.prank(ALICE); - vm.expectRevert(RIP7755Outbox.ExpiryTooSoon.selector); - outbox.sendMessages(m.destinationChain, m.messages, m.attributes); + outbox.sendMessage(m.destinationChain, m.receiver, m.payload, m.attributes); } function test_sendMessage_setMetadata_erc20Reward(uint256 rewardAmount) external fundAlice(rewardAmount) { TestMessage memory m = _initMessage(rewardAmount, false); vm.prank(ALICE); - outbox.sendMessage(m.destinationChain, m.messages[0].receiver, m.messages[0].payload, m.attributes); - - RIP7755Outbox.CrossChainCallStatus status = outbox.getMessageStatus(_deriveMessageId(m)); - assert(status == RIP7755Outbox.CrossChainCallStatus.Requested); - } - - function test_sendMessages_setMetadata_erc20Reward(uint256 rewardAmount) external fundAlice(rewardAmount) { - TestMessage memory m = _initMessage(rewardAmount, false); - - vm.prank(ALICE); - outbox.sendMessages(m.destinationChain, m.messages, m.attributes); + outbox.sendMessage(m.destinationChain, m.receiver, m.payload, m.attributes); RIP7755Outbox.CrossChainCallStatus status = outbox.getMessageStatus(_deriveMessageId(m)); assert(status == RIP7755Outbox.CrossChainCallStatus.Requested); @@ -187,21 +125,7 @@ contract RIP7755OutboxTest is BaseTest { m.attributes = _addAttribute(m.attributes, _PRECHECK_ATTRIBUTE_SELECTOR); vm.prank(ALICE); - outbox.sendMessage(m.destinationChain, m.messages[0].receiver, m.messages[0].payload, m.attributes); - - RIP7755Outbox.CrossChainCallStatus status = outbox.getMessageStatus(_deriveMessageId(m)); - assert(status == RIP7755Outbox.CrossChainCallStatus.Requested); - } - - function test_sendMessages_setMetadata_withOptionalPrecheckAttribute(uint256 rewardAmount) - external - fundAlice(rewardAmount) - { - TestMessage memory m = _initMessage(rewardAmount, false); - m.attributes = _addAttribute(m.attributes, _PRECHECK_ATTRIBUTE_SELECTOR); - - vm.prank(ALICE); - outbox.sendMessages(m.destinationChain, m.messages, m.attributes); + outbox.sendMessage(m.destinationChain, m.receiver, m.payload, m.attributes); RIP7755Outbox.CrossChainCallStatus status = outbox.getMessageStatus(_deriveMessageId(m)); assert(status == RIP7755Outbox.CrossChainCallStatus.Requested); @@ -215,74 +139,20 @@ contract RIP7755OutboxTest is BaseTest { m.attributes = _addAttribute(m.attributes, _L2_ORACLE_ATTRIBUTE_SELECTOR); vm.prank(ALICE); - outbox.sendMessage(m.destinationChain, m.messages[0].receiver, m.messages[0].payload, m.attributes); - - RIP7755Outbox.CrossChainCallStatus status = outbox.getMessageStatus(_deriveMessageId(m)); - assert(status == RIP7755Outbox.CrossChainCallStatus.Requested); - } - - function test_sendMessages_setMetadata_withOptionalL2OracleAttribute(uint256 rewardAmount) - external - fundAlice(rewardAmount) - { - TestMessage memory m = _initMessage(rewardAmount, false); - m.attributes = _addAttribute(m.attributes, _L2_ORACLE_ATTRIBUTE_SELECTOR); - - vm.prank(ALICE); - outbox.sendMessages(m.destinationChain, m.messages, m.attributes); - - RIP7755Outbox.CrossChainCallStatus status = outbox.getMessageStatus(_deriveMessageId(m)); - assert(status == RIP7755Outbox.CrossChainCallStatus.Requested); - } - - function test_sendMessage_setMetadata_withOptionalShoyuBashiAttribute(uint256 rewardAmount) - external - fundAlice(rewardAmount) - { - TestMessage memory m = _initMessage(rewardAmount, false); - m.attributes = _addAttribute(m.attributes, _SHOYU_BASHI_ATTRIBUTE_SELECTOR); - - vm.prank(ALICE); - outbox.sendMessage(m.destinationChain, m.messages[0].receiver, m.messages[0].payload, m.attributes); - - RIP7755Outbox.CrossChainCallStatus status = outbox.getMessageStatus(_deriveMessageId(m)); - assert(status == RIP7755Outbox.CrossChainCallStatus.Requested); - } - - function test_sendMessages_setMetadata_withOptionalShoyuBashiAttribute(uint256 rewardAmount) - external - fundAlice(rewardAmount) - { - TestMessage memory m = _initMessage(rewardAmount, false); - m.attributes = _addAttribute(m.attributes, _SHOYU_BASHI_ATTRIBUTE_SELECTOR); - - vm.prank(ALICE); - outbox.sendMessages(m.destinationChain, m.messages, m.attributes); + outbox.sendMessage(m.destinationChain, m.receiver, m.payload, m.attributes); RIP7755Outbox.CrossChainCallStatus status = outbox.getMessageStatus(_deriveMessageId(m)); assert(status == RIP7755Outbox.CrossChainCallStatus.Requested); } function test_sendMessage_reverts_ifUnsupportedAttribute(uint256 rewardAmount) external fundAlice(rewardAmount) { + bytes4 selector = 0x11111111; TestMessage memory m = _initMessage(rewardAmount, false); - m.attributes = _addAttribute(m.attributes, _FULFILLER_ATTRIBUTE_SELECTOR); - - vm.prank(ALICE); - vm.expectRevert( - abi.encodeWithSelector(RIP7755Outbox.UnsupportedAttribute.selector, _FULFILLER_ATTRIBUTE_SELECTOR) - ); - outbox.sendMessage(m.destinationChain, m.messages[0].receiver, m.messages[0].payload, m.attributes); - } - - function test_sendMessages_reverts_ifUnsupportedAttribute(uint256 rewardAmount) external fundAlice(rewardAmount) { - TestMessage memory m = _initMessage(rewardAmount, false); - m.attributes = _addAttribute(m.attributes, _FULFILLER_ATTRIBUTE_SELECTOR); + m.attributes = _addAttribute(m.attributes, selector); vm.prank(ALICE); - vm.expectRevert( - abi.encodeWithSelector(RIP7755Outbox.UnsupportedAttribute.selector, _FULFILLER_ATTRIBUTE_SELECTOR) - ); - outbox.sendMessages(m.destinationChain, m.messages, m.attributes); + vm.expectRevert(abi.encodeWithSelector(RIP7755Outbox.UnsupportedAttribute.selector, selector)); + outbox.sendMessage(m.destinationChain, m.receiver, m.payload, m.attributes); } function test_sendMessage_reverts_ifMissingRewardAttribute(uint256 rewardAmount) external fundAlice(rewardAmount) { @@ -293,21 +163,7 @@ contract RIP7755OutboxTest is BaseTest { vm.expectRevert( abi.encodeWithSelector(RIP7755Outbox.MissingRequiredAttribute.selector, _REWARD_ATTRIBUTE_SELECTOR) ); - outbox.sendMessage(m.destinationChain, m.messages[0].receiver, m.messages[0].payload, m.attributes); - } - - function test_sendMessages_reverts_ifMissingRewardAttribute(uint256 rewardAmount) - external - fundAlice(rewardAmount) - { - TestMessage memory m = _initMessage(rewardAmount, false); - m.attributes[0] = abi.encodeWithSelector(_PRECHECK_ATTRIBUTE_SELECTOR); - - vm.prank(ALICE); - vm.expectRevert( - abi.encodeWithSelector(RIP7755Outbox.MissingRequiredAttribute.selector, _REWARD_ATTRIBUTE_SELECTOR) - ); - outbox.sendMessages(m.destinationChain, m.messages, m.attributes); + outbox.sendMessage(m.destinationChain, m.receiver, m.payload, m.attributes); } function test_sendMessage_reverts_ifMissingDelayAttribute(uint256 rewardAmount) external fundAlice(rewardAmount) { @@ -318,18 +174,7 @@ contract RIP7755OutboxTest is BaseTest { vm.expectRevert( abi.encodeWithSelector(RIP7755Outbox.MissingRequiredAttribute.selector, _DELAY_ATTRIBUTE_SELECTOR) ); - outbox.sendMessage(m.destinationChain, m.messages[0].receiver, m.messages[0].payload, m.attributes); - } - - function test_sendMessages_reverts_ifMissingDelayAttribute(uint256 rewardAmount) external fundAlice(rewardAmount) { - TestMessage memory m = _initMessage(rewardAmount, false); - m.attributes[1] = abi.encodeWithSelector(_PRECHECK_ATTRIBUTE_SELECTOR); - - vm.prank(ALICE); - vm.expectRevert( - abi.encodeWithSelector(RIP7755Outbox.MissingRequiredAttribute.selector, _DELAY_ATTRIBUTE_SELECTOR) - ); - outbox.sendMessages(m.destinationChain, m.messages, m.attributes); + outbox.sendMessage(m.destinationChain, m.receiver, m.payload, m.attributes); } function test_sendMessage_reverts_ifMissingInboxAttribute(uint256 rewardAmount) external fundAlice(rewardAmount) { @@ -340,18 +185,7 @@ contract RIP7755OutboxTest is BaseTest { vm.expectRevert( abi.encodeWithSelector(RIP7755Outbox.MissingRequiredAttribute.selector, _INBOX_ATTRIBUTE_SELECTOR) ); - outbox.sendMessage(m.destinationChain, m.messages[0].receiver, m.messages[0].payload, m.attributes); - } - - function test_sendMessages_reverts_ifMissingInboxAttribute(uint256 rewardAmount) external fundAlice(rewardAmount) { - TestMessage memory m = _initMessage(rewardAmount, false); - m.attributes[2] = abi.encodeWithSelector(_PRECHECK_ATTRIBUTE_SELECTOR); - - vm.prank(ALICE); - vm.expectRevert( - abi.encodeWithSelector(RIP7755Outbox.MissingRequiredAttribute.selector, _INBOX_ATTRIBUTE_SELECTOR) - ); - outbox.sendMessages(m.destinationChain, m.messages, m.attributes); + outbox.sendMessage(m.destinationChain, m.receiver, m.payload, m.attributes); } function test_sendMessage_setStatusToRequested_nativeAssetReward(uint256 rewardAmount) @@ -361,22 +195,7 @@ contract RIP7755OutboxTest is BaseTest { TestMessage memory m = _initMessage(rewardAmount, true); vm.prank(ALICE); - outbox.sendMessage{value: rewardAmount}( - m.destinationChain, m.messages[0].receiver, m.messages[0].payload, m.attributes - ); - - RIP7755Outbox.CrossChainCallStatus status = outbox.getMessageStatus(_deriveMessageId(m)); - assert(status == RIP7755Outbox.CrossChainCallStatus.Requested); - } - - function test_sendMessages_setStatusToRequested_nativeAssetReward(uint256 rewardAmount) - external - fundAlice(rewardAmount) - { - TestMessage memory m = _initMessage(rewardAmount, true); - - vm.prank(ALICE); - outbox.sendMessages{value: rewardAmount}(m.destinationChain, m.messages, m.attributes); + outbox.sendMessage{value: rewardAmount}(m.destinationChain, m.receiver, m.payload, m.attributes); RIP7755Outbox.CrossChainCallStatus status = outbox.getMessageStatus(_deriveMessageId(m)); assert(status == RIP7755Outbox.CrossChainCallStatus.Requested); @@ -388,18 +207,10 @@ contract RIP7755OutboxTest is BaseTest { vm.prank(ALICE); vm.expectEmit(true, false, false, true); - emit MessagesPosted(messageId, m.destinationChain, m.sender, m.messages, _getAdjustedAttributes(m)); - outbox.sendMessage(m.destinationChain, m.messages[0].receiver, m.messages[0].payload, m.attributes); - } - - function test_sendMessages_emitsEvent(uint256 rewardAmount) external fundAlice(rewardAmount) { - TestMessage memory m = _initMessage(rewardAmount, false); - bytes32 messageId = _deriveMessageId(m); - - vm.prank(ALICE); - vm.expectEmit(true, false, false, true); - emit MessagesPosted(messageId, m.destinationChain, m.sender, m.messages, _getAdjustedAttributes(m)); - outbox.sendMessages(m.destinationChain, m.messages, m.attributes); + emit MessagePosted( + messageId, m.sourceChain, m.sender, m.destinationChain, m.receiver, m.payload, 0, _getAdjustedAttributes(m) + ); + outbox.sendMessage(m.destinationChain, m.receiver, m.payload, m.attributes); } function test_sendMessage_pullsERC20FromUserIfUsed(uint256 rewardAmount) external fundAlice(rewardAmount) { @@ -408,20 +219,7 @@ contract RIP7755OutboxTest is BaseTest { uint256 aliceBalBefore = mockErc20.balanceOf(ALICE); vm.prank(ALICE); - outbox.sendMessage(m.destinationChain, m.messages[0].receiver, m.messages[0].payload, m.attributes); - - uint256 aliceBalAfter = mockErc20.balanceOf(ALICE); - - assertEq(aliceBalBefore - aliceBalAfter, rewardAmount); - } - - function test_sendMessages_pullsERC20FromUserIfUsed(uint256 rewardAmount) external fundAlice(rewardAmount) { - TestMessage memory m = _initMessage(rewardAmount, false); - - uint256 aliceBalBefore = mockErc20.balanceOf(ALICE); - - vm.prank(ALICE); - outbox.sendMessages(m.destinationChain, m.messages, m.attributes); + outbox.sendMessage(m.destinationChain, m.receiver, m.payload, m.attributes); uint256 aliceBalAfter = mockErc20.balanceOf(ALICE); @@ -434,20 +232,7 @@ contract RIP7755OutboxTest is BaseTest { uint256 contractBalBefore = mockErc20.balanceOf(address(outbox)); vm.prank(ALICE); - outbox.sendMessage(m.destinationChain, m.messages[0].receiver, m.messages[0].payload, m.attributes); - - uint256 contractBalAfter = mockErc20.balanceOf(address(outbox)); - - assertEq(contractBalAfter - contractBalBefore, rewardAmount); - } - - function test_sendMessages_pullsERC20IntoContractIfUsed(uint256 rewardAmount) external fundAlice(rewardAmount) { - TestMessage memory m = _initMessage(rewardAmount, false); - - uint256 contractBalBefore = mockErc20.balanceOf(address(outbox)); - - vm.prank(ALICE); - outbox.sendMessages(m.destinationChain, m.messages, m.attributes); + outbox.sendMessage(m.destinationChain, m.receiver, m.payload, m.attributes); uint256 contractBalAfter = mockErc20.balanceOf(address(outbox)); @@ -466,7 +251,7 @@ contract RIP7755OutboxTest is BaseTest { RIP7755Outbox.CrossChainCallStatus.None ) ); - outbox.claimReward(m.sender, m.destinationChain, m.messages, m.attributes, storageProofData, FILLER); + outbox.claimReward(m.destinationChain, m.receiver, m.payload, m.attributes, storageProofData, FILLER); } function test_claimReward_reverts_requestAlreadyCompleted(uint256 rewardAmount) external fundAlice(rewardAmount) { @@ -475,7 +260,7 @@ contract RIP7755OutboxTest is BaseTest { vm.prank(FILLER); outbox.claimReward( - m.sender, m.destinationChain, m.messages, _getAdjustedAttributes(m), storageProofData, FILLER + m.destinationChain, m.receiver, m.payload, _getAdjustedAttributes(m), storageProofData, FILLER ); vm.prank(FILLER); @@ -487,7 +272,7 @@ contract RIP7755OutboxTest is BaseTest { ) ); outbox.claimReward( - m.sender, m.destinationChain, m.messages, _getAdjustedAttributes(m), storageProofData, FILLER + m.destinationChain, m.receiver, m.payload, _getAdjustedAttributes(m), storageProofData, FILLER ); } @@ -497,7 +282,7 @@ contract RIP7755OutboxTest is BaseTest { vm.warp(this.extractExpiry(_getAdjustedAttributes(m)) + outbox.CANCEL_DELAY_SECONDS()); vm.prank(ALICE); - outbox.cancelMessage(m.sender, m.destinationChain, m.messages, _getAdjustedAttributes(m)); + outbox.cancelMessage(m.destinationChain, m.receiver, m.payload, _getAdjustedAttributes(m)); vm.prank(FILLER); vm.expectRevert( @@ -508,7 +293,7 @@ contract RIP7755OutboxTest is BaseTest { ) ); outbox.claimReward( - m.sender, m.destinationChain, m.messages, _getAdjustedAttributes(m), storageProofData, FILLER + m.destinationChain, m.receiver, m.payload, _getAdjustedAttributes(m), storageProofData, FILLER ); } @@ -520,7 +305,7 @@ contract RIP7755OutboxTest is BaseTest { emit CrossChainCallCompleted(_deriveMessageId(m), FILLER); vm.prank(FILLER); outbox.claimReward( - m.sender, m.destinationChain, m.messages, _getAdjustedAttributes(m), storageProofData, FILLER + m.destinationChain, m.receiver, m.payload, _getAdjustedAttributes(m), storageProofData, FILLER ); } @@ -533,7 +318,7 @@ contract RIP7755OutboxTest is BaseTest { vm.prank(FILLER); outbox.claimReward( - m.sender, m.destinationChain, m.messages, _getAdjustedAttributes(m), storageProofData, FILLER + m.destinationChain, m.receiver, m.payload, _getAdjustedAttributes(m), storageProofData, FILLER ); RIP7755Outbox.CrossChainCallStatus status = outbox.getMessageStatus(_deriveMessageId(m)); @@ -545,15 +330,13 @@ contract RIP7755OutboxTest is BaseTest { bytes memory storageProofData = abi.encode(true); vm.prank(ALICE); - outbox.sendMessage{value: rewardAmount}( - m.destinationChain, m.messages[0].receiver, m.messages[0].payload, m.attributes - ); + outbox.sendMessage{value: rewardAmount}(m.destinationChain, m.receiver, m.payload, m.attributes); uint256 fillerBalBefore = FILLER.balance; vm.prank(FILLER); outbox.claimReward( - m.sender, m.destinationChain, m.messages, _getAdjustedAttributes(m), storageProofData, FILLER + m.destinationChain, m.receiver, m.payload, _getAdjustedAttributes(m), storageProofData, FILLER ); uint256 fillerBalAfter = FILLER.balance; @@ -569,15 +352,13 @@ contract RIP7755OutboxTest is BaseTest { bytes memory storageProofData = abi.encode(true); vm.prank(ALICE); - outbox.sendMessage{value: rewardAmount}( - m.destinationChain, m.messages[0].receiver, m.messages[0].payload, m.attributes - ); + outbox.sendMessage{value: rewardAmount}(m.destinationChain, m.receiver, m.payload, m.attributes); uint256 contractBalBefore = address(outbox).balance; vm.prank(FILLER); outbox.claimReward( - m.sender, m.destinationChain, m.messages, _getAdjustedAttributes(m), storageProofData, FILLER + m.destinationChain, m.receiver, m.payload, _getAdjustedAttributes(m), storageProofData, FILLER ); uint256 contractBalAfter = address(outbox).balance; @@ -593,7 +374,7 @@ contract RIP7755OutboxTest is BaseTest { vm.prank(FILLER); outbox.claimReward( - m.sender, m.destinationChain, m.messages, _getAdjustedAttributes(m), storageProofData, FILLER + m.destinationChain, m.receiver, m.payload, _getAdjustedAttributes(m), storageProofData, FILLER ); uint256 fillerBalAfter = mockErc20.balanceOf(FILLER); @@ -609,7 +390,7 @@ contract RIP7755OutboxTest is BaseTest { vm.prank(FILLER); outbox.claimReward( - m.sender, m.destinationChain, m.messages, _getAdjustedAttributes(m), storageProofData, FILLER + m.destinationChain, m.receiver, m.payload, _getAdjustedAttributes(m), storageProofData, FILLER ); uint256 contractBalAfter = mockErc20.balanceOf(address(outbox)); @@ -627,7 +408,7 @@ contract RIP7755OutboxTest is BaseTest { RIP7755Outbox.CrossChainCallStatus.None ) ); - outbox.cancelMessage(m.sender, m.destinationChain, m.messages, m.attributes); + outbox.cancelMessage(m.destinationChain, m.receiver, m.payload, _getAdjustedAttributes(m)); } function test_cancelMessage_reverts_requestAlreadyCanceled(uint256 rewardAmount) external fundAlice(rewardAmount) { @@ -635,7 +416,7 @@ contract RIP7755OutboxTest is BaseTest { vm.warp(this.extractExpiry(_getAdjustedAttributes(m)) + outbox.CANCEL_DELAY_SECONDS()); vm.prank(ALICE); - outbox.cancelMessage(m.sender, m.destinationChain, m.messages, _getAdjustedAttributes(m)); + outbox.cancelMessage(m.destinationChain, m.receiver, m.payload, _getAdjustedAttributes(m)); vm.expectRevert( abi.encodeWithSelector( @@ -644,7 +425,7 @@ contract RIP7755OutboxTest is BaseTest { RIP7755Outbox.CrossChainCallStatus.Canceled ) ); - outbox.cancelMessage(m.sender, m.destinationChain, m.messages, _getAdjustedAttributes(m)); + outbox.cancelMessage(m.destinationChain, m.receiver, m.payload, _getAdjustedAttributes(m)); } function test_cancelMessage_reverts_requestAlreadyCompleted(uint256 rewardAmount) @@ -656,7 +437,7 @@ contract RIP7755OutboxTest is BaseTest { vm.prank(FILLER); outbox.claimReward( - m.sender, m.destinationChain, m.messages, _getAdjustedAttributes(m), storageProofData, FILLER + m.destinationChain, m.receiver, m.payload, _getAdjustedAttributes(m), storageProofData, FILLER ); vm.expectRevert( @@ -666,7 +447,7 @@ contract RIP7755OutboxTest is BaseTest { RIP7755Outbox.CrossChainCallStatus.Completed ) ); - outbox.cancelMessage(m.sender, m.destinationChain, m.messages, _getAdjustedAttributes(m)); + outbox.cancelMessage(m.destinationChain, m.receiver, m.payload, _getAdjustedAttributes(m)); } function test_cancelMessage_reverts_invalidCaller(uint256 rewardAmount) external fundAlice(rewardAmount) { @@ -674,7 +455,7 @@ contract RIP7755OutboxTest is BaseTest { vm.prank(FILLER); vm.expectRevert(abi.encodeWithSelector(RIP7755Outbox.InvalidCaller.selector, FILLER, ALICE)); - outbox.cancelMessage(m.sender, m.destinationChain, m.messages, _getAdjustedAttributes(m)); + outbox.cancelMessage(m.destinationChain, m.receiver, m.payload, _getAdjustedAttributes(m)); } function test_cancelMessage_reverts_requestStillActive(uint256 rewardAmount) external fundAlice(rewardAmount) { @@ -690,7 +471,7 @@ contract RIP7755OutboxTest is BaseTest { ) ); vm.prank(ALICE); - outbox.cancelMessage(m.sender, m.destinationChain, m.messages, _getAdjustedAttributes(m)); + outbox.cancelMessage(m.destinationChain, m.receiver, m.payload, _getAdjustedAttributes(m)); } function test_cancelMessage_reverts_ifInvalidCaller(uint256 rewardAmount) external fundAlice(rewardAmount) { @@ -699,7 +480,7 @@ contract RIP7755OutboxTest is BaseTest { vm.warp(this.extractExpiry(_getAdjustedAttributes(m)) + outbox.CANCEL_DELAY_SECONDS()); vm.prank(FILLER); vm.expectRevert(abi.encodeWithSelector(RIP7755Outbox.InvalidCaller.selector, FILLER, ALICE)); - outbox.cancelMessage(m.sender, m.destinationChain, m.messages, _getAdjustedAttributes(m)); + outbox.cancelMessage(m.destinationChain, m.receiver, m.payload, _getAdjustedAttributes(m)); } function test_cancelMessage_setsStatusAsCanceled(uint256 rewardAmount) external fundAlice(rewardAmount) { @@ -707,7 +488,7 @@ contract RIP7755OutboxTest is BaseTest { vm.warp(this.extractExpiry(_getAdjustedAttributes(m)) + outbox.CANCEL_DELAY_SECONDS()); vm.prank(ALICE); - outbox.cancelMessage(m.sender, m.destinationChain, m.messages, _getAdjustedAttributes(m)); + outbox.cancelMessage(m.destinationChain, m.receiver, m.payload, _getAdjustedAttributes(m)); RIP7755Outbox.CrossChainCallStatus status = outbox.getMessageStatus(_deriveMessageId(m)); assert(status == RIP7755Outbox.CrossChainCallStatus.Canceled); @@ -720,7 +501,7 @@ contract RIP7755OutboxTest is BaseTest { vm.expectEmit(true, false, false, false); emit CrossChainCallCanceled(_deriveMessageId(m)); vm.prank(ALICE); - outbox.cancelMessage(m.sender, m.destinationChain, m.messages, _getAdjustedAttributes(m)); + outbox.cancelMessage(m.destinationChain, m.receiver, m.payload, _getAdjustedAttributes(m)); } function test_cancelMessage_returnsNativeCurrencyToRequester(uint256 rewardAmount) @@ -730,15 +511,13 @@ contract RIP7755OutboxTest is BaseTest { TestMessage memory m = _initMessage(rewardAmount, true); vm.prank(ALICE); - outbox.sendMessage{value: rewardAmount}( - m.destinationChain, m.messages[0].receiver, m.messages[0].payload, m.attributes - ); + outbox.sendMessage{value: rewardAmount}(m.destinationChain, m.receiver, m.payload, m.attributes); uint256 aliceBalBefore = ALICE.balance; vm.warp(this.extractExpiry(_getAdjustedAttributes(m)) + outbox.CANCEL_DELAY_SECONDS()); vm.prank(ALICE); - outbox.cancelMessage(m.sender, m.destinationChain, m.messages, _getAdjustedAttributes(m)); + outbox.cancelMessage(m.destinationChain, m.receiver, m.payload, _getAdjustedAttributes(m)); uint256 aliceBalAfter = ALICE.balance; @@ -752,15 +531,13 @@ contract RIP7755OutboxTest is BaseTest { TestMessage memory m = _initMessage(rewardAmount, true); vm.prank(ALICE); - outbox.sendMessage{value: rewardAmount}( - m.destinationChain, m.messages[0].receiver, m.messages[0].payload, m.attributes - ); + outbox.sendMessage{value: rewardAmount}(m.destinationChain, m.receiver, m.payload, m.attributes); uint256 contractBalBefore = address(outbox).balance; vm.warp(this.extractExpiry(_getAdjustedAttributes(m)) + outbox.CANCEL_DELAY_SECONDS()); vm.prank(ALICE); - outbox.cancelMessage(m.sender, m.destinationChain, m.messages, _getAdjustedAttributes(m)); + outbox.cancelMessage(m.destinationChain, m.receiver, m.payload, _getAdjustedAttributes(m)); uint256 contractBalAfter = address(outbox).balance; @@ -774,7 +551,7 @@ contract RIP7755OutboxTest is BaseTest { vm.warp(this.extractExpiry(_getAdjustedAttributes(m)) + outbox.CANCEL_DELAY_SECONDS()); vm.prank(ALICE); - outbox.cancelMessage(m.sender, m.destinationChain, m.messages, _getAdjustedAttributes(m)); + outbox.cancelMessage(m.destinationChain, m.receiver, m.payload, _getAdjustedAttributes(m)); uint256 aliceBalAfter = mockErc20.balanceOf(ALICE); @@ -788,7 +565,7 @@ contract RIP7755OutboxTest is BaseTest { vm.warp(this.extractExpiry(_getAdjustedAttributes(m)) + outbox.CANCEL_DELAY_SECONDS()); vm.prank(ALICE); - outbox.cancelMessage(m.sender, m.destinationChain, m.messages, _getAdjustedAttributes(m)); + outbox.cancelMessage(m.destinationChain, m.receiver, m.payload, _getAdjustedAttributes(m)); uint256 contractBalAfter = mockErc20.balanceOf(address(outbox)); @@ -807,8 +584,10 @@ contract RIP7755OutboxTest is BaseTest { function test_getMessageId_returnsSameValue_asGetMessageIdCalldata() external view { TestMessage memory m = _initMessage(100, false); - bytes32 messageId = outbox.getRequestId(m.sender, m.destinationChain, m.messages, m.attributes); - bytes32 messageIdCalldata = outbox.getRequestIdCalldata(m.sender, m.destinationChain, m.messages, m.attributes); + bytes32 messageId = + outbox.getRequestId(m.sourceChain, m.sender, m.destinationChain, m.receiver, m.payload, m.attributes); + bytes32 messageIdCalldata = + outbox.getRequestIdMemory(m.sourceChain, m.sender, m.destinationChain, m.receiver, m.payload, m.attributes); assertEq(messageId, messageIdCalldata); } @@ -816,17 +595,16 @@ contract RIP7755OutboxTest is BaseTest { TestMessage memory m = _initMessage(rewardAmount, false); vm.prank(ALICE); - outbox.sendMessage(m.destinationChain, m.messages[0].receiver, m.messages[0].payload, m.attributes); + outbox.sendMessage(m.destinationChain, m.receiver, m.payload, m.attributes); return m; } function _initMessage(uint256 rewardAmount, bool isNativeAsset) private view returns (TestMessage memory) { - string memory destinationChain = CAIP2.local(); - string memory sender = address(outbox).local(); - Message[] memory messages = new Message[](1); - messages[0] = - Message({receiver: address(outbox).toChecksumHexString(), payload: "", attributes: new bytes[](0)}); + bytes32 destinationChain = bytes32(block.chainid); + bytes32 sender = address(outbox).addressToBytes32(); + Call[] memory calls = new Call[](1); + calls[0] = Call({to: address(outbox).addressToBytes32(), data: "", value: 0}); bytes[] memory attributes = new bytes[](3); if (isNativeAsset) { @@ -840,9 +618,11 @@ contract RIP7755OutboxTest is BaseTest { attributes[2] = abi.encodeWithSelector(_INBOX_ATTRIBUTE_SELECTOR, bytes32(0)); return TestMessage({ + sourceChain: bytes32(block.chainid), destinationChain: destinationChain, sender: sender, - messages: messages, + receiver: sender, + payload: abi.encode(calls), attributes: attributes }); } @@ -872,7 +652,8 @@ contract RIP7755OutboxTest is BaseTest { function _deriveMessageId(TestMessage memory m) private view returns (bytes32) { bytes[] memory adjustedAttributes = _getAdjustedAttributes(m); - return outbox.getRequestIdCalldata(m.sender, m.destinationChain, m.messages, adjustedAttributes); + return + outbox.getRequestId(m.sourceChain, m.sender, m.destinationChain, m.receiver, m.payload, adjustedAttributes); } function _getAdjustedAttributes(TestMessage memory m) private view returns (bytes[] memory) { diff --git a/contracts/test/data/HashiProverProof.json b/contracts/test/data/HashiProverProof.json index bec933d..0d902e3 100644 --- a/contracts/test/data/HashiProverProof.json +++ b/contracts/test/data/HashiProverProof.json @@ -1,24 +1,23 @@ { - "rlpEncodedBlockHeader": "0xf90224a0c6f0aac8a97706a4da04e3e28230b18d0f209f42da21f0261ae8b0f075a4d561a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794a4b000000000000000000073657175656e636572a0c6634a0f41939aed52e151127902fe0acf9f4d40e5b35513fc6f5fbdaf08a4a8a00a48445e6307dabb37b262535e323c4b8a2c2331509a37015664eff673114787a0766a84a78507c580ff1bc15258c3877c47f5f1aaa5700b4c75411ece5a2dc473b9010000800000002000000000000000000000000008000000000000000000201000000000000000000000000000000000040000000000000000000000200000000000000004000000000000000000000000000000010000000000000000000000200800000001000000000000000000000000001000000801004000000002020000000000000000000000000008000000000000001000000008000000000000000000000000000000040000080000000000000000480040000000000000000008000000000000000000000010000000000000000000000000000002100000000000000000000000000000000200040000008000000000000000000000080000000000018406ffc194870400000000000083094bf58467939b8ca0e92c752a2347b0566c45e9bb9351606c753c02887d468ead9f3c65f7c39e09a9a0000000000000ef6200000000007360920000000000000020000000000000000088000000000014336e8405f5e100", "dstAccountProofParams": { - "storageKey": "0x44a258f736b4e2dd02b9cdc2b770bae1603ec8114a00855d2c7f6c74299a3b04", - "storageValue": "0x23214a0864fc0014cab6030267738f01affdd54700000000000000006792d3b2", + "storageKey": "0xba7439c27bf27579a628d4596c0d8b9fecb3977568df8913e6d7c2a8feb45ea8", + "storageValue": "0x23214a0864fc0014cab6030267738f01affdd547000000000000000067a2be38", "accountProof": [ - "0xf90211a09a1d47ea4d5cef8dcc03ed2c3276af2a5fca8f3d0659720d351cd292cf748056a0ba2014ac13dd8339f9832d5b50885f2a9646312ac8d1805c6322981bb7d4c107a0741ed7ee91e51bd2917683d233f7c0a165827433a2260c7ada86e75d28ed6196a019ba6621784854bd9154e54d099b1898e38daf3ff03edb8dcdd187308bfb394ea0d503c622cc06edbcf2330ee85c29240ae8a556f2292d9d2290f2cfbb70264eb0a04c7bb89489dcd05d825c8870bd12dcd0614e45cf6ee267706c93aa620c94707ba0d4188520090bdbf2f7708b53b067d0889549e7e55518bbb48b2d7821ef4a3316a0fb260033790cdb231cdb752fc47e13cffdb37af505cd99ee8259f7402a7f244fa0745add006a4b583405442207b49123176fe89b25687b93af14a8c7022a21bc31a0a30718a64968782de37e081f2fea3a32ff18296b30a982add1b719f70ad2ceefa08bdf7af0a65c19be6ff8fa4824dda4aa3627d45a9b73d52d196bc63dd602dc3da082b962b4d67a941bda66940f419862e0a43cf073ca1d898fa35859036d3dc252a0ca1a28ca45842b26cf0114e015454e160b39f64c7c9328f4d38b52726e39b3a9a0d906e417f76fb1f353838e06b92c82e6717de73f384bb39e3c2d5aa8aef1da10a0200740717c74d407c91f56ff6ed28da355c0bff8a54d70ec5754e4ebf2d4acb8a07cdb55d661a53614dae17c794b21c30f2519cef648417ebbbca734b4135add3d80", - "0xf90211a00f1204f74890bb8dad8206e681e6bb8890d4ec8b80fa1bca124a26236dafb327a0219eb2b9f8a2ca75eb781d7d4d751510f1088f16e4370fb76c9cb7328e2e5407a0ebdf4ae886858cdf46eeba6f86a81c3083293d27cf115fea6a2bfded6c163241a00c71bccf4d15e745ade6cc740cbb8473911e0b604f3b38f06bdfe09285bad222a09ee43987bb715278fa7973ac1a073ee8030212dfc7333fecac004fb3e37607fba09d9567aaae800db115e701c850eac17f6c350aac2b926d33155b870ce6eba872a0fef6e973a7a2c7f9f66b779ddc5f2dff04c6e8d7038ddfcd39384d94af63179aa0f856e9730cf9de9223ffc0180f4a714ced1235c3928b306b5b982074203dc7faa060e8b42a829d8896f9494bf946a25f72104646c20c7844879723625d4538afeda0641cce035ac8c270d8a53e76b8255857a8d190fc4a161965fde01d8cc3d9bae1a03af50ad74825c524f76511fd6af177e6427bc6ae1cc52951423064273dd2bbfda0a2b3ca0e2faddf7e724de96a2dfa89f86900a78d0a3ef647bd7f44fdb1ca855ea0cfb6c94fb5840ff18dbfa687ef083aacd11683f70fe8cf38f3ae0f67220187f8a089fb53f3e79f7f24cb47fad169f836ecd4562326a1e2850b129e1220bc8fc8c6a05ee5b7cf01d3fdfdc707218230e5252d82a02d245f5d4dbc767503e361f640b0a0b8ef207487e8c9b5abb2391a2ef2751da7dc662deedaf0c029c76c82c2b5630880", - "0xf90211a0684b277c64b3204fa63ac98bcfe37c2b1b9b7eb89dd71c7586e8a80fc10d00b7a0b5bafc964dab24b385ff62376a3be53f0c8b32ed095d55838d7c032287851208a08c645c534f9512d6ef6580b12525d14ea8d327c3ab27f87ced0ee33e2e1003ffa0b697f90ee24a0648dda7ac2e3b22feb153285873409207f1fe25ca288bdbdbbaa0e228f32d7531df2df22041176b0933c02cbd4259ec3a7f6eb0cf7be5be92f91aa0eafc21996c5d2cb3a1c95d15de520a47f774be128a8cb00c16b1e7d4d4a8dc43a0fc0471c21c5de6d46f2c8e1ac672e255783960b405b128e797400c136b4d3daaa0bd171f14896e4f8ae8fd449dad85d6007193db9c27c8b9289fa61e05eefd1b77a08d31f0bdde9bdf0c63a4105966870bfa90f4ec14ab1adff773d75b0a5b1afe26a006ead439766533c6be48716c5f93b113b779c8fd788e1cd41cd004efe761c148a0c5c8770ee510f3aa2738e784071823e53b4cb5a184a3875d215db837f5b63a37a0c9ea2b314fa1eeeb35f497a0b5a41352ca3816964c25eb58e18b24231ba26a79a0f7b6fadec491ed79ccc55a01ee03a221fae936d11c40001437eec5052fc34e05a0f8720149601aff9b085108271419b6e3f309b10e7b53c688920609f6b698c5bea0465a645826556dda7b257e1858fb94bc2cb55193decec9ae496f86167df78bbfa047468d22cc9289313d235102da83f298b749ce2633e5a01d2f49f5d24457f29080", - "0xf90211a033995ce359b156c0a35a482c54588d9f04b2a0f001e0181b01f438f4bb3556eaa094508d60d15bb93fdd88263915ad975f43be67e397538c5b96af0ff7df5f6442a03f781c246b2f7f5375ed5d3bc4ee3735f47fb7d812e99005bc9b5f445a801b82a01aa518592b700124ba0e87d4cdbef25840f05985e60a3099e563296a1d710b86a03096b264da00350608918eae41745bb7a64fed596172120589f825ac77463566a0eb7f5fb8b77cf299117d78bac290b1c17389e072217395e1a1e535ef5c10fc08a0db470a64fce35a6a0c1b72ecfce0236cb5e1f79f6a92a81a6e113c03abcb180ba0318c556adfe4ad2489ce3dc7b973b4af382ec3da7f752cae92a41cc76fb558e7a0893aa80c0670adf00781a2ef7cda3c4c9040b7bdfc1a3cdcf33c145c166b1e95a0ed11f04ac523e34a88d53b0932b6d8514465c9e25dc825cd77eff45a8b354aeda0f297ad1ce8ab5f783b7b3875379170ca94437a6894896a52c44aab95ae7c24c0a09ff9dd382f3d062524cc905b1d04b5eda693ae400c8553afd71ead9d000d128ea0ac90e48d4d2c8fb86132f8ab81dfd34b4970967e6a4b7d10886606582421055ba04f7c258f9dfb1f6c689549e49328efe8e794ed5ed09d7a4878a9daf2c11cdad4a02954961ca43e75e9a8dff361ed2ef026684b0c7c54cbdbc24fce464f673efd3aa08f8c7a6d068ee9bcd600b3b0153dfef37638a0a5aab34b18dd124a4a44a5003180", - "0xf90211a0c33a3aef02f0cdfc587234ddc72d7f7210c4c51ab449407b8c7d9e5009752204a0f74405d8684b8c4dc11f3797831ceb767602d2274848b2c674d74c75010c52a7a0a888e6d884e3f19125a4f0be69fc9e96487fbe3a82b51156c1eb8010ae2922fda076f66a01ccb8810a1d53ba35d7e6f9485b35271cdaed524f795f13a4cb3d7e50a02567f3d54ec8410d39526b59e0edf41514521f2900a841fed03a2766a6398567a05d5d019be3eb75306dd43c0bf161078a6966209f6fa9b11e4df00f3963b9289aa09dde0a4c70504b243c4df09de16373cea892554019216e30624af8b506367ae2a0bd6a5b35be3d6f4db4528cf34615301aaaef0aec07ab8e124d4ea3892de2211aa052013c439a5b48aa7f9c445ebe69155ce4fe035d15fb9c69caf4c34cea18dc8ca0ef71338ec8083932023ed2b1918c1024f753ed6d58411a36df1a044802a7946da05da038fe5f71907b0fe858d60362f25153e240545667b02700bada2c0a380725a0fa8844caac2767403acb642e43785ae00e5cf86fbeba81bca1d6e62ae3b6a018a0e4a8ce72e0cd36991395e022965dedaac5bee42d7fec7c8d6f68e3243ffb0303a0939c009f529e98d782009346858b710356f7d71e6f033885b8227b9655e327bba0bf86fa5b310dcf1f526cf71f2ab769146711672dca325840f59721bb1fbced1fa0336f91720cb2e440cc2f005c609c495c714482427d46d9b907b90fe41bb43ea180", - "0xf90211a0d37c85f21a4bfea14793fc1d7cc245445e971d0e3a5a5b2686694275d649e2e3a00d591bf8971b215bcfcfcfd7393ba7052a94e8599025d8b95c2dfb7f1b3af264a0f4c8a6d4b44bb61d421645a4dc78fdb3291ec2929da9f5819f24fc7229229feba003caf581627f387743c2f371aa63e0efbf20eb439358206da9e1073c07ee32eba0f5d9727fe5c47e36b5707e4109ab680f4e50288ea7a7a0d42a3bedd2cb674274a0c3c439f07ea1c91d529934b4dfc0cce331e329f8f71ada218f896ba46fce2492a09a9f2ad89d5d27728919fa6b7b706a6536f2a45a52f0cfa2a743b1174cf4ac85a061240bf10197f20b6752c175b3831887425f2069607ef333c9d59b6012e33ffea0e7a765c1a40764727b6dc7e7bc70da7ed72e6e9f0d85492de35286c7db35b83ba09eeac76e4a2d313e79afe7276d4b6c4034b19c4acb11cc422afe5a210ac56ceda05a8511d0968b3f2f828fea63c05c9fd1aa9b36ede8b4d5e2c81307f23aad1199a081542aeb9a1716e132d2a09822b5af85ef7c2444a3b798cdb67014d8fda4f80aa04c83984331fdb04ab174888d6694e6d5c7674143b3ed9a58a6fe78d2aa423624a0fa594a0c9dbe12507173ae441ceb532ebae089de2d349d8e0602d6bae0da16c7a0b9e006d9358766a61f1dcbecfc2cd20d675366a06149ad138ba282064b087edaa066c961f0737704084a76a831f99482b1235ece6a2f9c73a57aa1850acbfb3cb080", - "0xf891a07c2471136970c6670bbaaadfcb3ade1db043cc28b3392ee8d9a081038e70d8bf8080808080a046a978d81051baab3c6bd74f3405f9c4ae98313f59a8e762d3c7d4261a246efba05128ca624ce54cf99d03f15fe1c17530a71279a6f340bacf6f93902c7ec40eee808080a02d306fc303caa66f7ff8f2a8d9bf0657e0ac049ae23eb81e77b7170605daa9a98080808080", - "0xe21ca0f5d5d62a8571ba3ea99302a2d0df35ae5f676cf5720c420d56637b76a312a8a4", - "0xf85180808080a009df4b0ee6921f6a9a01e54071f3103e49d45157e4735c3f754dff2b79db6eb7808080a0e2192c4e60fa15999f4667e47c51f58f985f9ef729c308f5bc66e18dd53cac008080808080808080", - "0xf8659c3afc9af249ad6044ee4c8efcfff5cafe0c35b8dd55cd1a9839fa89bdb846f8440180a082a34dbae74163d6b48abd62215da3dfd69636cdcf70ec0a781cc229c1e0530aa013d1ed3f7d2abb5f64c3ae636043d5f3ad0899d03edae19093624c23b9ba4561" + "0xf90211a0ff53165c99104c8884ae4f07eb187c669e1c56cf489557bb008adc050aafbe13a0a5814dcec51e00a0550b87fc3465936314b872b1ab7d70e4aa33baa164d27485a076a3bc92f8c82f49b65282d78130c8ee5ff95517300719b7d46b279ee13f94b8a098ec2b244d22acc83641d6a97f463f37713111def162db04a97b81b2bc55b02ba00a4f45a95c8c525b09579d30c727210492b1e33b43a3c43da802dc8dc9e7b363a0f6a70d25ff92895b0d14da353c471b5289ef32a75635bff543466622450d4fbca0323e3a3a7ef8a8d0fff800be232ac1327d6b0abda3a0e3b2316d061e5f3143c0a060a6a85d884a8c6f2c3c2f16cc446f56c6dbdcb599f58bcf05d1e0778bf18271a05e36b8aed5ef3f8f2839d27bd13bb78e8a8ab6e372bf322f611f3c255f870524a015ad0dfb75bc2183caaf51e50a78cba2e9b06648590d38602602870d015131c4a02c765ed66d77534cb34f1f07609251559a169401bb4b22e73cc4214ffee8fda7a078d4e475dd0f71dc48683faab2d5faaf3fc8238a43775a9f99fc19adc2670093a015b313ef100896bfbbe2589e27f909f7ff9be3f9fdc122c94cf924ff3b9e16e0a0f16b687639f65eb3ffce5ca4f69c37548afd3af1481b4440317490708fa9e3d9a02de46756c3dffd1d876e208d0364fadd605aaf55dd69b2ec3dfa672093009a93a06c8d8120444bd03ec0124b9ef87b56c9e56ffc2a30c446d0201677032574ce8380", + "0xf90211a0d86989a38d2f7b4b2b3a33bc1094eeeec5d54ffc50717703c11f6dbddabc70e1a0568130078dc003cd705dfc9473cafa0bc11442098f74c9172b6b703e74c5c490a0ec2ca3f99dbfad8a32b16827f7beac7e04febe5f2c0411edaaed50542a06dd74a0e21875c0b9509bd23271200849b6c4f4acc94419d5f527e8da82c2f8a1757446a0f943cfd7fb186e3d5540005bb5fde07a4ebfbe28f186037f58c4b3644935657ca0b517b0e7c67fe6f8468e02f59085ffec7b7f4a5e8e30ba8edfb16e97a227aaf6a091c9aa55833d1e5813bf043da4246e7de09dbdf4ca5ce05b0a214dfaadd675bca0fd52936d64102ea1b51a3e55b1fac551be404224b91abf3ae401e2976020f090a00d45cf6aa95878b5c15765e168c91d8db2cb61a833c8b90b1d6c6e642e51e5cfa09bd0f9e5586886aba0060e08cf1ce16c944e005ad618098ede1532f108f0fdcaa03ae6d866e95f46e392b48a9173ba7d3afe8b2fb7242b66e046b81a42763d92bca078b2d06a814d5d43f7a4f8c19ad62f482904cacb50912b40bd6006079cd0d321a040db0c91ec364b1ccb5dbbc9963e3e6e3ba5a5f2e0f2b78e422724773740a2b1a0a41162ebfaf415f1feb86dfa5ad99bddb97b4d279387a1803a8a8516111b389ca06bec8c449e4911118f841a2f77563675ebd3d9b0035a38fae98ab073dbf8f6baa08fad265779ca9dbc275d909ef972f2a3898b72e6d9907cc852ae2ee613c9a80d80", + "0xf90211a0acc591b23d6f9d8b9c7fc1f2b1923d316a47532345ea2444c94394594d6d3ac5a0fc8a9bd7ce3f77f7440378fb648ccd9bfdab107cfe20e3b54709452c002f39baa00f1158fc367a7592ef18343110f149e92a0380347214a5da3262e735016a60caa009097562ae0f467f33dceede92fba73b2c91e3a12bf00fa62b252b143557c666a07dd4afc1804c01b6b272444c392c7556fda1dc62e9287eaba8c28db272aac9afa0f4164d5e84eec3faafcedfb24f4c519095c3c18eb522e8f18d5bcabe8fd76427a0d0723b638f35ba8912bfd94583a6fb975e34f38d64a59269711ac7546ac9debaa036121cba2609b4682fc876b4baf158e9d6644677a48f7b05f7f8ead49773757ba05bfb41ad1c11c6f3bcb758ff408f6f500905ae91e98a25770a44fd2f1aa7cd07a04ef56f3706194f241d5857c86a49c7869e344e0ce9f91ec8c70150c05af0de09a0f4e0070258b6455242fd06cce9700577e91fd223f3b88b550ac9fb2cdd9c6b5aa026bd7700ebf04defa598cee5c095ddc76517d4785177854a6af6bd8ea8e7f14fa06088b1a29cf720bf378113a735b61b2ba5309b9bc7da9c64360d6cc3a2b39261a02c4ac066b3a703a009637f85b892511f1faceda5198d7566c0695bf23ddf0671a092c176e838c250118eca2fe35bf6e9b22513d59576dd0b20fd1f26a8590e6a60a0a7ec9898d26f2b58d0388af4aefaf023b89f860cd3f1c2a7f2dacd529a97e8ba80", + "0xf90211a0b765c10df4f3d49be307ef072f0dd57b3cc192a0c43558f038358e314f87ab35a0e223f493b0e3443eaaa4483b5055b3744a6aad5af3d67eec6adc3277b611be1da0d1c08a45d28032bbce2f3e24402f6199c2b560681aca0490c8b0c2537d0db710a0aa26406755807ec828f6c7868b8cb58c34780c7caeb8cf283367596fcfe5ed12a02d700eba433efe74e5f62f3fe71d46a94a78e8282988a073bba99fc6beaa0a56a01e5050b3e345334ee1e314347f533fa58bb31d88288ffa8193e93a3439b621a5a07d6f25d5a46ef7bae924507d7fc09490924ac72f8dd2df235fce023d18fe3fe2a07b15d64e7dd4066744342abe016d5c6d43725cc0ee8f22a31287a4a3c4219452a0c3d558d843723dc89229fedbb0be95f3849375d6ebddc1e73c832f0faf172b37a051523ac54478f8262af2780f44d2427373b5ee0fe96a0f8bee41b3d104466462a01e9e17e82119bd0831297a8eb0d7b11ef4ccdf6d36d856bf379a4485efe37666a00f5a4a49ba2c4a5faadbf31ba742af044f822e44a760fc4ab1cc64b7b37c3ef8a00259360d39bc57c209b300dfe5bb4ee270abdf2d866589e4bac8feadd15a5d42a01c0cf035240192ebdf4c07df3b0053b8e3cd2cdf287b178b75131c8bd0b9ff00a0c68ba53d8bdc537cc1bb5539a384614a2bf37f0f35eb9a809ed83471f943ae7fa0035a4de90363640ef7bfdc49cf1ddfa3ded06f613b258ba14994c8e4b1a6c96780", + "0xf90211a0c33a3aef02f0cdfc587234ddc72d7f7210c4c51ab449407b8c7d9e5009752204a08872fcea4c0541e681656a249eccc78df8cb778f91237fc28e9e9a5741aa5a09a0ffaaf674be8d6639c28687bff6aca0f2a28afb1cd8dd7df5a3a31bb70653c441a094608590c7f0bf27689b3fadee0404f6aff174af3432bdbbd36a668772a49c62a02567f3d54ec8410d39526b59e0edf41514521f2900a841fed03a2766a6398567a05d5d019be3eb75306dd43c0bf161078a6966209f6fa9b11e4df00f3963b9289aa09c98d61a6c3bf072ef0bcaf9f84878e22fbb49903f323a9a65bb4d14964bdbb6a097fe03b329433dacdd61c3e06bee91212bd13376ad97029fca4363b347ef9396a052013c439a5b48aa7f9c445ebe69155ce4fe035d15fb9c69caf4c34cea18dc8ca0ef71338ec8083932023ed2b1918c1024f753ed6d58411a36df1a044802a7946da0d26f59905490aef8f486a6b97d9eb3731a74a60cf0d9628c0f461972b0a5283ba0fa8844caac2767403acb642e43785ae00e5cf86fbeba81bca1d6e62ae3b6a018a0e4a8ce72e0cd36991395e022965dedaac5bee42d7fec7c8d6f68e3243ffb0303a0b63871f178cce436dc7edd0290356e4441fe26f43633f8f8823460f22ac2d985a0bf86fa5b310dcf1f526cf71f2ab769146711672dca325840f59721bb1fbced1fa0ae39db10ad475dfbdd0a142dd11904d2ca26b43d10972b0e1133a1e19f9d4d5480", + "0xf90211a0d37c85f21a4bfea14793fc1d7cc245445e971d0e3a5a5b2686694275d649e2e3a00d591bf8971b215bcfcfcfd7393ba7052a94e8599025d8b95c2dfb7f1b3af264a0f4c8a6d4b44bb61d421645a4dc78fdb3291ec2929da9f5819f24fc7229229feba003caf581627f387743c2f371aa63e0efbf20eb439358206da9e1073c07ee32eba0f5d9727fe5c47e36b5707e4109ab680f4e50288ea7a7a0d42a3bedd2cb674274a0c3c439f07ea1c91d529934b4dfc0cce331e329f8f71ada218f896ba46fce2492a09a9f2ad89d5d27728919fa6b7b706a6536f2a45a52f0cfa2a743b1174cf4ac85a061240bf10197f20b6752c175b3831887425f2069607ef333c9d59b6012e33ffea0e7a765c1a40764727b6dc7e7bc70da7ed72e6e9f0d85492de35286c7db35b83ba09eeac76e4a2d313e79afe7276d4b6c4034b19c4acb11cc422afe5a210ac56ceda05a8511d0968b3f2f828fea63c05c9fd1aa9b36ede8b4d5e2c81307f23aad1199a08d4d962753ccb8128aa2265e6dc02e51d575c14157495b307954f2dba26781eca04c83984331fdb04ab174888d6694e6d5c7674143b3ed9a58a6fe78d2aa423624a0fa594a0c9dbe12507173ae441ceb532ebae089de2d349d8e0602d6bae0da16c7a0b9e006d9358766a61f1dcbecfc2cd20d675366a06149ad138ba282064b087edaa066c961f0737704084a76a831f99482b1235ece6a2f9c73a57aa1850acbfb3cb080", + "0xf891a07c2471136970c6670bbaaadfcb3ade1db043cc28b3392ee8d9a081038e70d8bf8080808080a046a978d81051baab3c6bd74f3405f9c4ae98313f59a8e762d3c7d4261a246efba05128ca624ce54cf99d03f15fe1c17530a71279a6f340bacf6f93902c7ec40eee808080a04432ab13b99fcb3c3cd3d9de7e3e46bc0de4e008b172f4fcdc69267fa9b533c98080808080", + "0xe21ca0b920aaa45fd6aa64ca1debfa34ccb4e2f09e058e4b1f949ffef61d60edc884e4", + "0xf85180808080a05e67158a45c4bfb0de84d3cb20a51ca5d85eefdf70ba52bbff2c837bc9d5cb8f808080a0e2192c4e60fa15999f4667e47c51f58f985f9ef729c308f5bc66e18dd53cac008080808080808080", + "0xf8659c3afc9af249ad6044ee4c8efcfff5cafe0c35b8dd55cd1a9839fa89bdb846f8440180a0937817d636da3228ed040c42d897bdf44818e4b4d1cc3e833d1c4ba8c9849b8fa013d1ed3f7d2abb5f64c3ae636043d5f3ad0899d03edae19093624c23b9ba4561" ], "storageProof": [ - "0xe210a0ad7af73a5c0fe23f14e580ceea674ac923f7d3e1326e15c9921b4680c4e8b901", - "0xf8518080808080a01da77fcec8ba4aa058e909be98b8750d3eff0aa216aac8e7f62ccd22bb9cf1238080808080a095de4565c60950230bf6515020cf840a08ad310ab18d2f784c1f06f211dbab178080808080", - "0xf843a020ee8fcafe2a072fd7e20fa292a63ddc485da4d6a6fd47bb5104d602103f46a8a1a023214a0864fc0014cab6030267738f01affdd54700000000000000006792d3b2" + "0xf851a0ad7af73a5c0fe23f14e580ceea674ac923f7d3e1326e15c9921b4680c4e8b90180808080808080808080808080a0cd87f3be9cd1df956bde768dde01eb2fca2d469566fab8bf7c8e60fb9cdbb3568080", + "0xf843a03493dc18fa5336e9f631e46c6f7bb84e70fe18538bc7db9acb4985e4c7bc6f99a1a023214a0864fc0014cab6030267738f01affdd547000000000000000067a2be38" ] - } + }, + "rlpEncodedBlockHeader": "0xf90224a0caef1b1c8d1a7b53150eb61a53c738f9ea1900dfcdb7dca1c0ce21576cb5e34ba01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794a4b000000000000000000073657175656e636572a021e76da1be961376faa36347f35de6f2d32dd16b71f397c1cb24a9d1f6916745a0b782176066d180de017b38b715d83edc2cabc501156a9dfb6dab28ece4185713a0c78928ab42ce7865a644ce7f9588b4d1558b96774e0129503e48dbf14e97c52bb9010000000000000000020000000000000004000000000000000000000040000000000000000000000000002000000000000000000000000000000000001000000000000000000000000000000008400000000000000000000000000000000840000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000001000000000000002000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000002000000400000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000004000018407381c1d8704000000000000830ade0f8467a2ca17a093f6af18c73e8af497c8e1eacd9041eabfd1de461d03c16503d8d5cfd0f5c49da0000000000000fa0f0000000000749bc60000000000000020000000000000000088000000000014af088405f5e100" } diff --git a/contracts/test/mocks/MockHashiProver.sol b/contracts/test/mocks/MockHashiProver.sol index 9563985..c709861 100644 --- a/contracts/test/mocks/MockHashiProver.sol +++ b/contracts/test/mocks/MockHashiProver.sol @@ -11,6 +11,10 @@ contract MockHashiProver is RIP7755OutboxToHashi { _validateProof(storageKey, inbox, attributes, proof); } + function isOptionalAttribute(bytes4 selector) external pure returns (bool) { + return _isOptionalAttribute(selector); + } + // Including to block from coverage report function test() external {} } diff --git a/contracts/test/mocks/MockPrecheck.sol b/contracts/test/mocks/MockPrecheck.sol index 0c0921b..2b55a02 100644 --- a/contracts/test/mocks/MockPrecheck.sol +++ b/contracts/test/mocks/MockPrecheck.sol @@ -2,20 +2,10 @@ pragma solidity 0.8.24; import {IPrecheckContract} from "../../src/interfaces/IPrecheckContract.sol"; -import {ERC7786Base} from "../../src/ERC7786Base.sol"; -contract MockPrecheck is ERC7786Base, IPrecheckContract { - function precheckCall( - string calldata, // [CAIP-2] chain identifier - string calldata, // [CAIP-10] account address - Message[] calldata, - bytes[] calldata attributes, - address caller - ) external pure { - bytes calldata fulfillerAttribute = _locateAttribute(attributes, _FULFILLER_ATTRIBUTE_SELECTOR); - address expectedCaller = abi.decode(fulfillerAttribute[4:], (address)); - - if (expectedCaller != caller) { +contract MockPrecheck is IPrecheckContract { + function precheckCall(bytes32, bytes32, bytes calldata, bytes[] calldata, address caller) external view { + if (caller != tx.origin) { revert(); } }