diff --git a/v2/src/evm/ERC20Custody.sol b/v2/src/evm/ERC20Custody.sol index c33df59a..d3f09e81 100644 --- a/v2/src/evm/ERC20Custody.sol +++ b/v2/src/evm/ERC20Custody.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.26; -import "./interfaces//IGatewayEVM.sol"; import "./interfaces/IERC20Custody.sol"; +import { IGatewayEVM } from "./interfaces/IGatewayEVM.sol"; import "@openzeppelin/contracts/access/AccessControl.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; diff --git a/v2/src/evm/ZetaConnectorBase.sol b/v2/src/evm/ZetaConnectorBase.sol index 89422576..655057ca 100644 --- a/v2/src/evm/ZetaConnectorBase.sol +++ b/v2/src/evm/ZetaConnectorBase.sol @@ -7,7 +7,7 @@ import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/utils/Pausable.sol"; import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; -import "src/evm/interfaces/IGatewayEVM.sol"; +import { IGatewayEVM, IGatewayEVMErrors, IGatewayEVMEvents } from "src/evm/interfaces/IGatewayEVM.sol"; import "src/evm/interfaces/IZetaConnector.sol"; /// @title ZetaConnectorBase diff --git a/v2/src/evm/interfaces/IGatewayEVM.sol b/v2/src/evm/interfaces/IGatewayEVM.sol index 0b98e89c..76578238 100644 --- a/v2/src/evm/interfaces/IGatewayEVM.sol +++ b/v2/src/evm/interfaces/IGatewayEVM.sol @@ -47,7 +47,14 @@ interface IGatewayEVMEvents { /// @param asset The address of the ERC20 token (zero address if ETH). /// @param payload The calldata passed with the deposit. /// @param revertOptions Revert options. - event Deposit(address indexed sender, address indexed receiver, uint256 amount, address asset, bytes payload, RevertOptions revertOptions); + event Deposit( + address indexed sender, + address indexed receiver, + uint256 amount, + address asset, + bytes payload, + RevertOptions revertOptions + ); /// @notice Emitted when an omnichain smart contract call is made without asset transfer. /// @param sender The address of the sender. diff --git a/v2/src/zevm/GatewayZEVM.sol b/v2/src/zevm/GatewayZEVM.sol index e8cd25cf..9bc93a40 100644 --- a/v2/src/zevm/GatewayZEVM.sol +++ b/v2/src/zevm/GatewayZEVM.sol @@ -117,12 +117,24 @@ contract GatewayZEVM is /// @param receiver The receiver address on the external chain. /// @param amount The amount of tokens to withdraw. /// @param zrc20 The address of the ZRC20 token. - function withdraw(bytes memory receiver, uint256 amount, address zrc20) external nonReentrant whenNotPaused { + /// @param revertOptions Revert options. + function withdraw( + bytes memory receiver, + uint256 amount, + address zrc20, + RevertOptions calldata revertOptions + ) + external + nonReentrant + whenNotPaused + { if (receiver.length == 0) revert ZeroAddress(); if (amount == 0) revert InsufficientZRC20Amount(); uint256 gasFee = _withdrawZRC20(amount, zrc20); - emit Withdrawal(msg.sender, 0, receiver, zrc20, amount, gasFee, IZRC20(zrc20).PROTOCOL_FLAT_FEE(), ""); + emit Withdrawal( + msg.sender, 0, receiver, zrc20, amount, gasFee, IZRC20(zrc20).PROTOCOL_FLAT_FEE(), "", revertOptions + ); } /// @notice Withdraw ZRC20 tokens and call a smart contract on an external chain. @@ -130,11 +142,13 @@ contract GatewayZEVM is /// @param amount The amount of tokens to withdraw. /// @param zrc20 The address of the ZRC20 token. /// @param message The calldata to pass to the contract call. + /// @param revertOptions Revert options. function withdrawAndCall( bytes memory receiver, uint256 amount, address zrc20, - bytes calldata message + bytes calldata message, + RevertOptions calldata revertOptions ) external nonReentrant @@ -144,17 +158,36 @@ contract GatewayZEVM is if (amount == 0) revert InsufficientZRC20Amount(); uint256 gasFee = _withdrawZRC20(amount, zrc20); - emit Withdrawal(msg.sender, 0, receiver, zrc20, amount, gasFee, IZRC20(zrc20).PROTOCOL_FLAT_FEE(), message); + emit Withdrawal( + msg.sender, 0, receiver, zrc20, amount, gasFee, IZRC20(zrc20).PROTOCOL_FLAT_FEE(), message, revertOptions + ); } /// @notice Withdraw ZETA tokens to an external chain. /// @param amount The amount of tokens to withdraw. - function withdraw(uint256 amount, uint256 chainId) external nonReentrant whenNotPaused { + /// @param revertOptions Revert options. + function withdraw( + uint256 amount, + uint256 chainId, + RevertOptions calldata revertOptions + ) + external + nonReentrant + whenNotPaused + { if (amount == 0) revert InsufficientZetaAmount(); _transferZETA(amount, FUNGIBLE_MODULE_ADDRESS); emit Withdrawal( - msg.sender, chainId, abi.encodePacked(FUNGIBLE_MODULE_ADDRESS), address(zetaToken), amount, 0, 0, "" + msg.sender, + chainId, + abi.encodePacked(FUNGIBLE_MODULE_ADDRESS), + address(zetaToken), + amount, + 0, + 0, + "", + revertOptions ); } @@ -162,10 +195,12 @@ contract GatewayZEVM is /// @param amount The amount of tokens to withdraw. /// @param chainId Chain id of the external chain. /// @param message The calldata to pass to the contract call. + /// @param revertOptions Revert options. function withdrawAndCall( uint256 amount, uint256 chainId, - bytes calldata message + bytes calldata message, + RevertOptions calldata revertOptions ) external nonReentrant @@ -175,17 +210,35 @@ contract GatewayZEVM is _transferZETA(amount, FUNGIBLE_MODULE_ADDRESS); emit Withdrawal( - msg.sender, chainId, abi.encodePacked(FUNGIBLE_MODULE_ADDRESS), address(zetaToken), amount, 0, 0, message + msg.sender, + chainId, + abi.encodePacked(FUNGIBLE_MODULE_ADDRESS), + address(zetaToken), + amount, + 0, + 0, + message, + revertOptions ); } /// @notice Call a smart contract on an external chain without asset transfer. /// @param receiver The receiver address on the external chain. /// @param message The calldata to pass to the contract call. - function call(bytes memory receiver, uint256 chainId, bytes calldata message) external nonReentrant whenNotPaused { + /// @param revertOptions Revert options. + function call( + bytes memory receiver, + uint256 chainId, + bytes calldata message, + RevertOptions calldata revertOptions + ) + external + nonReentrant + whenNotPaused + { if (receiver.length == 0) revert ZeroAddress(); - emit Call(msg.sender, chainId, receiver, message); + emit Call(msg.sender, chainId, receiver, message, revertOptions); } /// @notice Deposit foreign coins into ZRC20. diff --git a/v2/src/zevm/interfaces/IGatewayZEVM.sol b/v2/src/zevm/interfaces/IGatewayZEVM.sol index 3ade59b1..2379651c 100644 --- a/v2/src/zevm/interfaces/IGatewayZEVM.sol +++ b/v2/src/zevm/interfaces/IGatewayZEVM.sol @@ -3,6 +3,16 @@ pragma solidity 0.8.26; import "./zContract.sol"; +/// @notice Struct containing revert options +/// @param revertAddress Address to receive revert. +/// @param callOnRevert Flag if onRevert hook should be called. +/// @pararm abortAddress Address to receive funds if aborted. +struct RevertOptions { + address revertAddress; + bool callOnRevert; + address abortAddress; +} + /// @title IGatewayZEVM /// @notice Interface for the GatewayZEVM contract. /// @dev Defines functions for cross-chain interactions and token handling. @@ -11,30 +21,60 @@ interface IGatewayZEVM { /// @param receiver The receiver address on the external chain. /// @param amount The amount of tokens to withdraw. /// @param zrc20 The address of the ZRC20 token. - function withdraw(bytes memory receiver, uint256 amount, address zrc20) external; + /// @param revertOptions Revert options. + function withdraw( + bytes memory receiver, + uint256 amount, + address zrc20, + RevertOptions calldata revertOptions + ) + external; /// @notice Withdraw ZETA tokens to an external chain. /// @param amount The amount of tokens to withdraw. - function withdraw(uint256 amount, uint256 chainId) external; + /// @param revertOptions Revert options. + function withdraw(uint256 amount, uint256 chainId, RevertOptions calldata revertOptions) external; /// @notice Withdraw ZRC20 tokens and call a smart contract on an external chain. /// @param receiver The receiver address on the external chain. /// @param amount The amount of tokens to withdraw. /// @param zrc20 The address of the ZRC20 token. /// @param message The calldata to pass to the contract call. - function withdrawAndCall(bytes memory receiver, uint256 amount, address zrc20, bytes calldata message) external; + /// @param revertOptions Revert options. + function withdrawAndCall( + bytes memory receiver, + uint256 amount, + address zrc20, + bytes calldata message, + RevertOptions calldata revertOptions + ) + external; /// @notice Withdraw ZETA tokens and call a smart contract on an external chain. /// @param amount The amount of tokens to withdraw. /// @param chainId Chain id of the external chain. /// @param message The calldata to pass to the contract call. - function withdrawAndCall(uint256 amount, uint256 chainId, bytes calldata message) external; + /// @param revertOptions Revert options. + function withdrawAndCall( + uint256 amount, + uint256 chainId, + bytes calldata message, + RevertOptions calldata revertOptions + ) + external; /// @notice Call a smart contract on an external chain without asset transfer. /// @param receiver The receiver address on the external chain. /// @param chainId Chain id of the external chain. /// @param message The calldata to pass to the contract call. - function call(bytes memory receiver, uint256 chainId, bytes calldata message) external; + /// @param revertOptions Revert options. + function call( + bytes memory receiver, + uint256 chainId, + bytes calldata message, + RevertOptions calldata revertOptions + ) + external; /// @notice Deposit foreign coins into ZRC20. /// @param zrc20 The address of the ZRC20 token. @@ -124,7 +164,10 @@ interface IGatewayZEVMEvents { /// @param chainId Chain id of external chain. /// @param receiver The receiver address on the external chain. /// @param message The calldata passed to the contract call. - event Call(address indexed sender, uint256 indexed chainId, bytes receiver, bytes message); + /// @param revertOptions Revert options. + event Call( + address indexed sender, uint256 indexed chainId, bytes receiver, bytes message, RevertOptions revertOptions + ); /// @notice Emitted when a withdrawal is made. /// @param sender The address from which the tokens are withdrawn. @@ -135,6 +178,7 @@ interface IGatewayZEVMEvents { /// @param gasfee The gas fee for the withdrawal. /// @param protocolFlatFee The protocol flat fee for the withdrawal. /// @param message The calldata passed to the contract call. + /// @param revertOptions Revert options. event Withdrawal( address indexed sender, uint256 indexed chainId, @@ -143,7 +187,8 @@ interface IGatewayZEVMEvents { uint256 value, uint256 gasfee, uint256 protocolFlatFee, - bytes message + bytes message, + RevertOptions revertOptions ); } diff --git a/v2/test/GatewayEVMZEVM.t.sol b/v2/test/GatewayEVMZEVM.t.sol index c066ef4f..8c7a47d4 100644 --- a/v2/test/GatewayEVMZEVM.t.sol +++ b/v2/test/GatewayEVMZEVM.t.sol @@ -8,19 +8,24 @@ import "./utils/ReceiverEVM.sol"; import "./utils/TestERC20.sol"; import "src/evm/ERC20Custody.sol"; -import "src/evm/GatewayEVM.sol"; +import { GatewayEVM } from "src/evm/GatewayEVM.sol"; import "src/evm/ZetaConnectorNonNative.sol"; import "./utils/SenderZEVM.sol"; import "./utils/SystemContractMock.sol"; -import "src/zevm/GatewayZEVM.sol"; +import { GatewayZEVM } from "src/zevm/GatewayZEVM.sol"; +import { IGatewayZEVM } from "src/zevm/GatewayZEVM.sol"; +import { IGatewayZEVMErrors } from "src/zevm/GatewayZEVM.sol"; +import { IGatewayZEVMEvents } from "src/zevm/GatewayZEVM.sol"; + +import { IGatewayEVMErrors } from "src/evm/GatewayEVM.sol"; +import { IGatewayEVMEvents } from "src/evm/GatewayEVM.sol"; + import "src/zevm/ZRC20.sol"; import "./utils/IReceiverEVM.sol"; -import "src/evm/interfaces/IGatewayEVM.sol"; -import "src/zevm/interfaces/IGatewayZEVM.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; @@ -56,6 +61,8 @@ contract GatewayEVMZEVMTest is ZRC20 zrc20; address ownerZEVM; + RevertOptions revertOptions; + function setUp() public { // evm ownerEVM = address(this); @@ -108,6 +115,9 @@ contract GatewayEVMZEVMTest is zrc20.approve(address(gatewayZEVM), 1_000_000); vm.deal(tssAddress, 1 ether); + + revertOptions = + RevertOptions({ revertAddress: address(0x321), callOnRevert: true, abortAddress: address(0x321) }); } function testCallReceiverEVMFromZEVM() public { @@ -121,8 +131,8 @@ contract GatewayEVMZEVMTest is bytes memory message = abi.encodeWithSelector(receiverEVM.receivePayable.selector, str, num, flag); vm.prank(ownerZEVM); vm.expectEmit(true, true, true, true, address(gatewayZEVM)); - emit Call(address(ownerZEVM), chainId, abi.encodePacked(receiverEVM), message); - gatewayZEVM.call(abi.encodePacked(receiverEVM), chainId, message); + emit Call(address(ownerZEVM), chainId, abi.encodePacked(receiverEVM), message, revertOptions); + gatewayZEVM.call(abi.encodePacked(receiverEVM), chainId, message, revertOptions); // Call execute on evm vm.deal(address(gatewayEVM), value); @@ -141,8 +151,13 @@ contract GatewayEVMZEVMTest is // Encode the function call data and call on zevm bytes memory message = abi.encodeWithSelector(receiverEVM.receivePayable.selector, str, num, flag); - bytes memory data = - abi.encodeWithSignature("call(bytes,uint256,bytes)", abi.encodePacked(receiverEVM), chainId, message); + bytes memory data = abi.encodeWithSignature( + "call(bytes,uint256,bytes,(address,bool,address))", + abi.encodePacked(receiverEVM), + chainId, + message, + revertOptions + ); vm.expectCall(address(gatewayZEVM), 0, data); vm.prank(ownerZEVM); senderZEVM.callReceiver(abi.encodePacked(receiverEVM), chainId, str, num, flag); @@ -174,10 +189,11 @@ contract GatewayEVMZEVMTest is 1_000_000, 0, zrc20.PROTOCOL_FLAT_FEE(), - message + message, + revertOptions ); vm.prank(ownerZEVM); - gatewayZEVM.withdrawAndCall(abi.encodePacked(receiverEVM), 1_000_000, address(zrc20), message); + gatewayZEVM.withdrawAndCall(abi.encodePacked(receiverEVM), 1_000_000, address(zrc20), message, revertOptions); // Check the balance after withdrawal uint256 balanceOfAfterWithdrawal = zrc20.balanceOf(ownerZEVM); @@ -203,11 +219,12 @@ contract GatewayEVMZEVMTest is uint256 senderBalanceBeforeWithdrawal = IZRC20(zrc20).balanceOf(address(senderZEVM)); bytes memory message = abi.encodeWithSelector(receiverEVM.receivePayable.selector, str, num, flag); bytes memory data = abi.encodeWithSignature( - "withdrawAndCall(bytes,uint256,address,bytes)", + "withdrawAndCall(bytes,uint256,address,bytes,(address,bool,address))", abi.encodePacked(receiverEVM), 1_000_000, address(zrc20), - message + message, + revertOptions ); vm.expectCall(address(gatewayZEVM), 0, data); vm.prank(ownerZEVM); diff --git a/v2/test/GatewayZEVM.t.sol b/v2/test/GatewayZEVM.t.sol index 6532ae04..1b038781 100644 --- a/v2/test/GatewayZEVM.t.sol +++ b/v2/test/GatewayZEVM.t.sol @@ -26,6 +26,7 @@ contract GatewayZEVMInboundTest is Test, IGatewayZEVMEvents, IGatewayZEVMErrors address owner; address addr1; address fungibleModule; + RevertOptions revertOptions; error ZeroAddress(); error LowBalance(); @@ -62,6 +63,9 @@ contract GatewayZEVMInboundTest is Test, IGatewayZEVMEvents, IGatewayZEVMErrors zetaToken.deposit{ value: 10 }(); zetaToken.approve(address(gateway), 10); vm.stopPrank(); + + revertOptions = + RevertOptions({ revertAddress: address(0x321), callOnRevert: true, abortAddress: address(0x321) }); } function testWithdrawZRC20() public { @@ -69,8 +73,10 @@ contract GatewayZEVMInboundTest is Test, IGatewayZEVMEvents, IGatewayZEVMErrors uint256 ownerBalanceBefore = zrc20.balanceOf(owner); vm.expectEmit(true, true, true, true, address(gateway)); - emit Withdrawal(owner, 0, abi.encodePacked(addr1), address(zrc20), amount, 0, zrc20.PROTOCOL_FLAT_FEE(), ""); - gateway.withdraw(abi.encodePacked(addr1), amount, address(zrc20)); + emit Withdrawal( + owner, 0, abi.encodePacked(addr1), address(zrc20), amount, 0, zrc20.PROTOCOL_FLAT_FEE(), "", revertOptions + ); + gateway.withdraw(abi.encodePacked(addr1), amount, address(zrc20), revertOptions); uint256 ownerBalanceAfter = zrc20.balanceOf(owner); assertEq(ownerBalanceBefore - amount, ownerBalanceAfter); @@ -85,7 +91,7 @@ contract GatewayZEVMInboundTest is Test, IGatewayZEVMEvents, IGatewayZEVMErrors zrc20.updateGasLimit(10); vm.expectRevert(LowBalance.selector); - gateway.withdraw(abi.encodePacked(addr1), amount, address(zrc20)); + gateway.withdraw(abi.encodePacked(addr1), amount, address(zrc20), revertOptions); } function testWithdrawZRC20FailsIfNoBalanceForTransfer() public { @@ -94,17 +100,17 @@ contract GatewayZEVMInboundTest is Test, IGatewayZEVMEvents, IGatewayZEVMErrors zrc20.transfer(address(0x123), ownerBalance - 1); vm.expectRevert(LowBalance.selector); - gateway.withdraw(abi.encodePacked(addr1), amount, address(zrc20)); + gateway.withdraw(abi.encodePacked(addr1), amount, address(zrc20), revertOptions); } function testWithdrawZRC20FailsIsAmountIs0() public { vm.expectRevert(InsufficientZRC20Amount.selector); - gateway.withdraw(abi.encodePacked(addr1), 0, address(zrc20)); + gateway.withdraw(abi.encodePacked(addr1), 0, address(zrc20), revertOptions); } function testWithdrawZRC20FailsIfReceiverIsZeroAddress() public { vm.expectRevert(ZeroAddress.selector); - gateway.withdraw(abi.encodePacked(""), 1, address(zrc20)); + gateway.withdraw(abi.encodePacked(""), 1, address(zrc20), revertOptions); } function testWithdrawZRC20FailsIfNoAllowance() public { @@ -116,7 +122,7 @@ contract GatewayZEVMInboundTest is Test, IGatewayZEVMEvents, IGatewayZEVMErrors zrc20.approve(address(gateway), 0); vm.expectRevert(); - gateway.withdraw(abi.encodePacked(addr1), amount, address(zrc20)); + gateway.withdraw(abi.encodePacked(addr1), amount, address(zrc20), revertOptions); // Check that balance didn't change uint256 ownerBalanceAfter = zrc20.balanceOf(owner); @@ -126,13 +132,13 @@ contract GatewayZEVMInboundTest is Test, IGatewayZEVMEvents, IGatewayZEVMErrors function testWithdrawAndCallZRC20FailsIfReceiverIsZeroAddress() public { bytes memory message = abi.encodeWithSignature("hello(address)", addr1); vm.expectRevert(ZeroAddress.selector); - gateway.withdrawAndCall(abi.encodePacked(""), 1, address(zrc20), message); + gateway.withdrawAndCall(abi.encodePacked(""), 1, address(zrc20), message, revertOptions); } function testWithdrawAndCallZRC20FailsIfAmountIsZero() public { bytes memory message = abi.encodeWithSignature("hello(address)", addr1); vm.expectRevert(InsufficientZRC20Amount.selector); - gateway.withdrawAndCall(abi.encodePacked(addr1), 0, address(zrc20), message); + gateway.withdrawAndCall(abi.encodePacked(addr1), 0, address(zrc20), message, revertOptions); } function testWithdrawZRC20WithMessageFailsIfNoAllowance() public { @@ -145,7 +151,7 @@ contract GatewayZEVMInboundTest is Test, IGatewayZEVMEvents, IGatewayZEVMErrors bytes memory message = abi.encodeWithSignature("hello(address)", addr1); vm.expectRevert(); - gateway.withdrawAndCall(abi.encodePacked(addr1), amount, address(zrc20), message); + gateway.withdrawAndCall(abi.encodePacked(addr1), amount, address(zrc20), message, revertOptions); // Check that balance didn't change uint256 ownerBalanceAfter = zrc20.balanceOf(owner); @@ -159,9 +165,17 @@ contract GatewayZEVMInboundTest is Test, IGatewayZEVMEvents, IGatewayZEVMErrors bytes memory message = abi.encodeWithSignature("hello(address)", addr1); vm.expectEmit(true, true, true, true, address(gateway)); emit Withdrawal( - owner, 0, abi.encodePacked(addr1), address(zrc20), amount, 0, zrc20.PROTOCOL_FLAT_FEE(), message + owner, + 0, + abi.encodePacked(addr1), + address(zrc20), + amount, + 0, + zrc20.PROTOCOL_FLAT_FEE(), + message, + revertOptions ); - gateway.withdrawAndCall(abi.encodePacked(addr1), amount, address(zrc20), message); + gateway.withdrawAndCall(abi.encodePacked(addr1), amount, address(zrc20), message, revertOptions); uint256 ownerBalanceAfter = zrc20.balanceOf(owner); assertEq(ownerBalanceBefore - amount, ownerBalanceAfter); @@ -169,13 +183,13 @@ contract GatewayZEVMInboundTest is Test, IGatewayZEVMEvents, IGatewayZEVMErrors function testWithdrawZETAFailsIfAmountIsZero() public { vm.expectRevert(InsufficientZetaAmount.selector); - gateway.withdraw(0, 1); + gateway.withdraw(0, 1, revertOptions); } function testWithdrawAndcallZETAFailsIfAmountIsZero() public { bytes memory message = abi.encodeWithSignature("hello(address)", addr1); vm.expectRevert(InsufficientZetaAmount.selector); - gateway.withdrawAndCall(0, 1, message); + gateway.withdrawAndCall(0, 1, message, revertOptions); } function testWithdrawZETA() public { @@ -186,8 +200,10 @@ contract GatewayZEVMInboundTest is Test, IGatewayZEVMEvents, IGatewayZEVMErrors uint256 chainId = 1; vm.expectEmit(true, true, true, true, address(gateway)); - emit Withdrawal(owner, chainId, abi.encodePacked(fungibleModule), address(zetaToken), amount, 0, 0, ""); - gateway.withdraw(amount, chainId); + emit Withdrawal( + owner, chainId, abi.encodePacked(fungibleModule), address(zetaToken), amount, 0, 0, "", revertOptions + ); + gateway.withdraw(amount, chainId, revertOptions); uint256 ownerBalanceAfter = zetaToken.balanceOf(owner); assertEq(ownerBalanceBefore - 1, ownerBalanceAfter); @@ -211,7 +227,7 @@ contract GatewayZEVMInboundTest is Test, IGatewayZEVMEvents, IGatewayZEVMErrors zetaToken.approve(address(gateway), 0); vm.expectRevert(); - gateway.withdraw(amount, chainId); + gateway.withdraw(amount, chainId, revertOptions); // Verify balances not changed uint256 ownerBalanceAfter = zetaToken.balanceOf(owner); @@ -230,7 +246,7 @@ contract GatewayZEVMInboundTest is Test, IGatewayZEVMEvents, IGatewayZEVMErrors uint256 chainId = 1; vm.expectRevert(); - gateway.withdraw(amount, chainId); + gateway.withdraw(amount, chainId, revertOptions); } function testWithdrawZETAWithMessage() public { @@ -242,8 +258,10 @@ contract GatewayZEVMInboundTest is Test, IGatewayZEVMEvents, IGatewayZEVMErrors uint256 chainId = 1; vm.expectEmit(true, true, true, true, address(gateway)); - emit Withdrawal(owner, chainId, abi.encodePacked(fungibleModule), address(zetaToken), amount, 0, 0, message); - gateway.withdrawAndCall(amount, chainId, message); + emit Withdrawal( + owner, chainId, abi.encodePacked(fungibleModule), address(zetaToken), amount, 0, 0, message, revertOptions + ); + gateway.withdrawAndCall(amount, chainId, message, revertOptions); uint256 ownerBalanceAfter = zetaToken.balanceOf(owner); assertEq(ownerBalanceBefore - 1, ownerBalanceAfter); @@ -268,7 +286,7 @@ contract GatewayZEVMInboundTest is Test, IGatewayZEVMEvents, IGatewayZEVMErrors zetaToken.approve(address(gateway), 0); vm.expectRevert(); - gateway.withdrawAndCall(amount, chainId, message); + gateway.withdrawAndCall(amount, chainId, message, revertOptions); // Verify balances not changed uint256 ownerBalanceAfter = zetaToken.balanceOf(owner); @@ -283,7 +301,7 @@ contract GatewayZEVMInboundTest is Test, IGatewayZEVMEvents, IGatewayZEVMErrors function testCallFailsIfReceiverIsZeroAddress() public { bytes memory message = abi.encodeWithSignature("hello(address)", addr1); vm.expectRevert(ZeroAddress.selector); - gateway.call(abi.encodePacked(""), 1, message); + gateway.call(abi.encodePacked(""), 1, message, revertOptions); } function testCall() public { @@ -291,8 +309,8 @@ contract GatewayZEVMInboundTest is Test, IGatewayZEVMEvents, IGatewayZEVMErrors vm.expectEmit(true, true, true, true, address(gateway)); uint256 chainId = 1; - emit Call(owner, chainId, abi.encodePacked(addr1), message); - gateway.call(abi.encodePacked(addr1), chainId, message); + emit Call(owner, chainId, abi.encodePacked(addr1), message, revertOptions); + gateway.call(abi.encodePacked(addr1), chainId, message, revertOptions); } } diff --git a/v2/test/ZetaConnectorNonNative.t.sol b/v2/test/ZetaConnectorNonNative.t.sol index 11dc3a31..b09fabac 100644 --- a/v2/test/ZetaConnectorNonNative.t.sol +++ b/v2/test/ZetaConnectorNonNative.t.sol @@ -18,7 +18,7 @@ import "src/evm/ZetaConnectorNonNative.sol"; import "./utils/IReceiverEVM.sol"; import "./utils/Zeta.non-eth.sol"; -import "src/evm/interfaces/IGatewayEVM.sol"; +import { IGatewayEVMErrors, IGatewayEVMEvents } from "src/evm/interfaces/IGatewayEVM.sol"; import "src/evm/interfaces/IZetaConnector.sol"; contract ZetaConnectorNonNativeTest is diff --git a/v2/test/utils/SenderZEVM.sol b/v2/test/utils/SenderZEVM.sol index cd1f2703..6c6a1bec 100644 --- a/v2/test/utils/SenderZEVM.sol +++ b/v2/test/utils/SenderZEVM.sol @@ -2,7 +2,8 @@ pragma solidity 0.8.26; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "src/zevm/interfaces/IGatewayZEVM.sol"; +import { IGatewayZEVM } from "src/zevm/interfaces/IGatewayZEVM.sol"; +import { RevertOptions } from "src/zevm/interfaces/IGatewayZEVM.sol"; import "src/zevm/interfaces/IZRC20.sol"; /// @title SenderZEVM @@ -30,8 +31,11 @@ contract SenderZEVM { // Encode the function call to the receiver's receivePayable method bytes memory message = abi.encodeWithSignature("receivePayable(string,uint256,bool)", str, num, flag); + RevertOptions memory revertOptions = + RevertOptions({ revertAddress: address(0x321), callOnRevert: true, abortAddress: address(0x321) }); + // Pass encoded call to gateway - IGatewayZEVM(gateway).call(receiver, chainId, message); + IGatewayZEVM(gateway).call(receiver, chainId, message, revertOptions); } /// @notice Withdraw and call a receiver on EVM. @@ -58,7 +62,10 @@ contract SenderZEVM { // Approve gateway to withdraw if (!IZRC20(zrc20).approve(gateway, amount)) revert ApprovalFailed(); + RevertOptions memory revertOptions = + RevertOptions({ revertAddress: address(0x321), callOnRevert: true, abortAddress: address(0x321) }); + // Pass encoded call to gateway - IGatewayZEVM(gateway).withdrawAndCall(receiver, amount, zrc20, message); + IGatewayZEVM(gateway).withdrawAndCall(receiver, amount, zrc20, message, revertOptions); } }