diff --git a/solidity/src/Base7683.sol b/solidity/src/Base7683.sol index e7eb2d7..8df453f 100644 --- a/solidity/src/Base7683.sol +++ b/solidity/src/Base7683.sol @@ -46,7 +46,7 @@ abstract contract Base7683 is IOriginSettler, IDestinationSettler { mapping(bytes32 orderId => OrderData orderData) public orders; - mapping(bytes32 orderId => address filler) public orderFiller; + mapping(bytes32 orderId => bytes fillerData) public orderFillerData; mapping(bytes32 orderId => OrderStatus status) public orderStatus; @@ -57,7 +57,7 @@ abstract contract Base7683 is IOriginSettler, IDestinationSettler { // ============ Events ============ event Filled(bytes32 orderId, bytes originData, bytes fillerData); - event Settle(bytes32[] orderIds, bytes32[] receivers); + event Settle(bytes32[] orderIds, bytes[] ordersFillerData); event Refund(bytes32[] orderIds); event Settled(bytes32 orderId, address receiver); event Refunded(bytes32 orderId, address receiver); @@ -73,10 +73,8 @@ abstract contract Base7683 is IOriginSettler, IDestinationSettler { error InvalidOrderDomain(); error InvalidOrderStatus(); error InvalidSenderNonce(); - error InvalidOrderFiller(); error OrderFillNotExpired(); error InvalidDomain(); - error InvalidOrdersLength(); error InvalidSender(); // ============ Constructor ============ @@ -182,8 +180,9 @@ abstract contract Base7683 is IOriginSettler, IDestinationSettler { /// @notice Fills a single leg of a particular order on the destination chain /// @param _orderId Unique order identifier for this order /// @param _originData Data emitted on the origin to parameterize the fill - /// NOT USED fillerData Data provided by the filler to inform the fill or express their preferences - function fill(bytes32 _orderId, bytes calldata _originData, bytes calldata) external virtual { + /// @param _fillerData Data provided by the filler to inform the fill or express their preferences. It should + /// contain the bytes32 encoded address of the receiver which is the used at settlement time + function fill(bytes32 _orderId, bytes calldata _originData, bytes calldata _fillerData) external virtual { OrderData memory orderData = OrderEncoder.decode(_originData); if (_orderId != _getOrderId(orderData)) revert InvalidOrderId(); @@ -194,30 +193,29 @@ abstract contract Base7683 is IOriginSettler, IDestinationSettler { orders[_orderId] = orderData; orderStatus[_orderId] = OrderStatus.FILLED; - orderFiller[_orderId] = msg.sender; + orderFillerData[_orderId] = _fillerData; - emit Filled(_orderId, _originData, new bytes(0)); + emit Filled(_orderId, _originData, _fillerData); IERC20(TypeCasts.bytes32ToAddress(orderData.outputToken)).safeTransferFrom( msg.sender, TypeCasts.bytes32ToAddress(orderData.recipient), orderData.amountOut ); } - function settle(bytes32[] calldata _orderIds, bytes32[] calldata _receivers) external payable { - if (_orderIds.length != _receivers.length) revert InvalidOrdersLength(); - + function settle(bytes32[] calldata _orderIds) external payable { + bytes[] memory ordersFillerData = new bytes[](_orderIds.length); for (uint256 i = 0; i < _orderIds.length; i += 1) { if (orderStatus[_orderIds[i]] != OrderStatus.FILLED) revert InvalidOrderStatus(); - if (orderFiller[_orderIds[i]] != msg.sender) revert InvalidOrderFiller(); // not necessary to check the localDomain and counterpart since the fill function already did it orderStatus[_orderIds[i]] = OrderStatus.SETTLED; + ordersFillerData[i] = orderFillerData[_orderIds[i]]; } - _handleSettlement(_orderIds, _receivers); + _handleSettlement(_orderIds, ordersFillerData); - emit Settle(_orderIds, _receivers); + emit Settle(_orderIds, ordersFillerData); } function refund(OrderData[] memory _ordersData) external payable { bytes32[] memory orderIds = new bytes32[](_ordersData.length); @@ -397,7 +395,7 @@ abstract contract Base7683 is IOriginSettler, IDestinationSettler { * @dev This function is called during `settle` to handle the settlement of the orders, it is meant to be * implemented by the inheriting contract with specific settlement logic. i.e. sending a cross-chain message */ - function _handleSettlement(bytes32[] memory _orderIds, bytes32[] memory _receivers) internal virtual; + function _handleSettlement(bytes32[] memory _orderIds, bytes[] memory _ordersFillerData) internal virtual; /** * @dev This function is called during `refund` to handle the refund of the orders, it is meant to be diff --git a/solidity/src/Router7683.sol b/solidity/src/Router7683.sol index fde087c..b172c1d 100644 --- a/solidity/src/Router7683.sol +++ b/solidity/src/Router7683.sol @@ -45,14 +45,14 @@ contract Router7683 is GasRouter, Base7683 { // ============ Internal Functions ============ function _handle(uint32 _origin, bytes32, bytes calldata _message) internal virtual override { - (bool _settle, bytes32[] memory _orderIds, bytes32[] memory _receivers) = Router7683Message.decode(_message); + (bool _settle, bytes32[] memory _orderIds, bytes[] memory _ordersFillerData) = Router7683Message.decode(_message); for (uint i = 0; i < _orderIds.length; i++) { // check if the order is opened to ensure it belongs to this domain, skip otherwise if (orderStatus[_orderIds[i]] != OrderStatus.OPENED) continue; if (_settle) { - _settleOrder(_orderIds[i], _receivers[i], _origin); + _settleOrder(_orderIds[i], abi.decode(_ordersFillerData[i], (bytes32)), _origin); } else { _refundOrder(_orderIds[i], _origin); @@ -60,9 +60,9 @@ contract Router7683 is GasRouter, Base7683 { } } - function _handleSettlement(bytes32[] memory _orderIds, bytes32[] memory _receivers) internal virtual override { + function _handleSettlement(bytes32[] memory _orderIds, bytes[] memory _ordersFillerData) internal virtual override { uint32 originDomain = orders[_orderIds[0]].originDomain; - _GasRouter_dispatch(originDomain, msg.value, Router7683Message.encodeSettle(_orderIds, _receivers), address(hook)); + _GasRouter_dispatch(originDomain, msg.value, Router7683Message.encodeSettle(_orderIds, _ordersFillerData), address(hook)); } function _handleRefund(bytes32[] memory _orderIds) internal virtual override { diff --git a/solidity/src/libs/Route7683Message.sol b/solidity/src/libs/Route7683Message.sol index 7275327..b636bd7 100644 --- a/solidity/src/libs/Route7683Message.sol +++ b/solidity/src/libs/Route7683Message.sol @@ -9,19 +9,19 @@ library Router7683Message { * @dev This function should only be used in memory message construction. * @param _settle Flag to indicate if the message is a settlement or refund * @param _orderIds The orderIds to settle or refund - * @param _receivers The address of the receivers when settling + * @param _ordersFillerData Each element should contain the bytes32 encoded address of the settlement receiver. * @return Formatted message body */ function encode( bool _settle, bytes32[] memory _orderIds, - bytes32[] memory _receivers + bytes[] memory _ordersFillerData ) internal pure returns (bytes memory) { - return abi.encode(_settle, _orderIds, _receivers); + return abi.encode(_settle, _orderIds, _ordersFillerData); } /** @@ -32,20 +32,20 @@ library Router7683Message { function decode(bytes calldata _message) internal pure - returns (bool, bytes32[] memory, bytes32[] memory) + returns (bool, bytes32[] memory, bytes[] memory) { - return abi.decode(_message, (bool, bytes32[], bytes32[])); + return abi.decode(_message, (bool, bytes32[], bytes[])); } function encodeSettle( bytes32[] memory _orderIds, - bytes32[] memory _receivers + bytes[] memory _ordersFillerData ) internal pure returns (bytes memory) { - return encode(true, _orderIds, _receivers); + return encode(true, _orderIds, _ordersFillerData); } function encodeRefund( @@ -55,6 +55,6 @@ library Router7683Message { pure returns (bytes memory) { - return encode(false, _orderIds, new bytes32[](0)); + return encode(false, _orderIds, new bytes[](0)); } } diff --git a/solidity/test/Base7683.t.sol b/solidity/test/Base7683.t.sol index 8676286..01e6c5b 100644 --- a/solidity/test/Base7683.t.sol +++ b/solidity/test/Base7683.t.sol @@ -21,7 +21,7 @@ import { Base7683 } from "../src/Router7683.sol"; event Open(bytes32 indexed orderId, ResolvedCrossChainOrder resolvedOrder); event Filled(bytes32 orderId, bytes originData, bytes fillerData); -event Settle(bytes32[] orderIds, bytes32[] receivers); +event Settle(bytes32[] orderIds, bytes[] ordersFillerData); event Refund(bytes32[] orderIds); event Settled(bytes32 orderId, address receiver); event Refunded(bytes32 orderId, address receiver); @@ -31,7 +31,7 @@ contract Base7683ForTest is Base7683 { bytes32[] public refundedOrderIds; bytes32[] public settledOrderIds; - bytes32[] public settledReceivers; + bytes[] public settledReceivers; uint32 internal immutable _origin; uint32 internal immutable _destination; @@ -53,7 +53,7 @@ contract Base7683ForTest is Base7683 { _refundOrder(_orderId, _destination); } - function _handleSettlement(bytes32[] memory _orderIds, bytes32[] memory receivers) internal override { + function _handleSettlement(bytes32[] memory _orderIds, bytes[] memory receivers) internal override { settledOrderIds = _orderIds; settledReceivers = receivers; } @@ -462,13 +462,15 @@ contract Base7683Test is Test, DeployPermit2 { vm.startPrank(vegeta); outputToken.approve(address(base), amount); + bytes memory fillerData = abi.encode(TypeCasts.addressToBytes32(vegeta)); + vm.expectEmit(false, false, false, true); - emit Filled(orderId, OrderEncoder.encode(orderData), new bytes(0)); + emit Filled(orderId, OrderEncoder.encode(orderData), fillerData); - base.fill(orderId, OrderEncoder.encode(orderData), new bytes(0)); + base.fill(orderId, OrderEncoder.encode(orderData), fillerData); assertOrder(orderId, orderData, balancesBefore, outputToken, vegeta, karpincho, Base7683.OrderStatus.FILLED); - assertEq(base.orderFiller(orderId), vegeta); + assertEq(base.orderFillerData(orderId), fillerData); vm.stopPrank(); } @@ -481,23 +483,25 @@ contract Base7683Test is Test, DeployPermit2 { bytes32 orderId = OrderEncoder.id(orderData); + bytes memory fillerData = abi.encode(TypeCasts.addressToBytes32(karpincho)); + vm.startPrank(vegeta); outputToken.approve(address(base), amount); - base.fill(orderId, OrderEncoder.encode(orderData), new bytes(0)); + base.fill(orderId, OrderEncoder.encode(orderData), fillerData); bytes32[] memory orderIds = new bytes32[](1); orderIds[0] = orderId; - bytes32[] memory receivers = new bytes32[](1); - receivers[0] = TypeCasts.addressToBytes32(karpincho); + bytes[] memory ordersFillerData = new bytes[](1); + ordersFillerData[0] = fillerData; vm.expectEmit(false, false, false, true); - emit Settle(orderIds, receivers); + emit Settle(orderIds, ordersFillerData); - base.settle(orderIds, receivers); + base.settle(orderIds); assertTrue(base.orderStatus(orderId) == Base7683.OrderStatus.SETTLED); assertEq(base.settledOrderIds(0), orderId); - assertEq(base.settledReceivers(0), TypeCasts.addressToBytes32(karpincho)); + assertEq(base.settledReceivers(0), fillerData); vm.stopPrank(); } diff --git a/solidity/test/Router7683.t.sol b/solidity/test/Router7683.t.sol index e864107..e06232a 100644 --- a/solidity/test/Router7683.t.sol +++ b/solidity/test/Router7683.t.sol @@ -33,7 +33,7 @@ import { Base7683 } from "../src/Router7683.sol"; event Open(bytes32 indexed orderId, ResolvedCrossChainOrder resolvedOrder); event Filled(bytes32 orderId, bytes originData, bytes fillerData); -event Settle(bytes32[] orderIds, bytes32[] receivers); +event Settle(bytes32[] orderIds, bytes[] ordersFillerData); event Refund(bytes32[] orderIds); event Settled(bytes32 orderId, address receiver); event Refunded(bytes32 orderId, address receiver); @@ -145,8 +145,6 @@ contract Router7683BaseTest is Test, DeployPermit2 { testIsm = new TestIsm(); - uint32[] memory domains = new uint32[](0); - originRouter = deployProxiedRouter( environment.mailboxes(origin), owner @@ -322,28 +320,30 @@ contract Router7683Test is Router7683BaseTest { vm.recordLogs(); originRouter.open(order); - (bytes32 orderId, ResolvedCrossChainOrder memory resolvedOrder) = getOrderIDFromLogs(); + (bytes32 orderId,) = getOrderIDFromLogs(); vm.stopPrank(); + bytes memory fillerData = abi.encode(TypeCasts.addressToBytes32(vegeta)); + vm.startPrank(vegeta); outputToken.approve(address(destinationRouter), amount); - destinationRouter.fill(orderId, OrderEncoder.encode(orderData), new bytes(0)); + destinationRouter.fill(orderId, OrderEncoder.encode(orderData), fillerData); bytes32[] memory orderIds = new bytes32[](1); orderIds[0] = orderId; - bytes32[] memory receivers = new bytes32[](1); - receivers[0] = TypeCasts.addressToBytes32(vegeta); + bytes[] memory ordersFillerData = new bytes[](1); + ordersFillerData[0] = fillerData; uint256[] memory balancesBefore = balances(inputToken); vm.expectEmit(false, false, false, true, address(destinationRouter)); - emit Settle(orderIds, receivers); + emit Settle(orderIds, ordersFillerData); vm.deal(vegeta, gasPaymentQuote); uint256 balanceBefore = address(vegeta).balance; - destinationRouter.settle{value: gasPaymentQuote}(orderIds, receivers); + destinationRouter.settle{value: gasPaymentQuote}(orderIds); vm.expectEmit(false, false, false, true, address(originRouter)); emit Settled(orderId, vegeta); @@ -375,7 +375,7 @@ contract Router7683Test is Router7683BaseTest { vm.recordLogs(); originRouter.open(order); - (bytes32 orderId, ResolvedCrossChainOrder memory resolvedOrder) = getOrderIDFromLogs(); + (bytes32 orderId,) = getOrderIDFromLogs(); vm.warp(orderData.fillDeadline + 1);