diff --git a/overridden_contracts/src/Gateway.sol b/overridden_contracts/src/Gateway.sol index 002f9e9..42e5743 100644 --- a/overridden_contracts/src/Gateway.sol +++ b/overridden_contracts/src/Gateway.sol @@ -509,9 +509,14 @@ contract Gateway is IOGateway, IInitializable, IUpgradable { revert MiddlewareNotSet(); } + // Probably need to send me the token to be minted? (uint256 epoch, uint256 eraIndex, uint256 totalPointsToken, uint256 totalTokensInflated, bytes32 rewardsRoot) = abi.decode(data, (uint256, uint256, uint256, uint256, bytes32)); + // ! We need a foreignTokenID to mint the token. I don't want to save it in the Assets storage otherwise it's another change to be made. Can we send directly the address of the token everytime? + // bytes32 foreignTokenID = bytes32(0); + // Assets.mintForeignToken(foreignTokenID, middlewareAddress, totalTokensInflated); + try IMiddlewareBasic(middlewareAddress).distributeRewards( epoch, eraIndex, totalPointsToken, totalTokensInflated, rewardsRoot ) {} catch Error(string memory err) { diff --git a/overridden_contracts/test/Gateway.t.sol b/overridden_contracts/test/Gateway.t.sol index abc36c5..f6aa41f 100644 --- a/overridden_contracts/test/Gateway.t.sol +++ b/overridden_contracts/test/Gateway.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.25; -import {Test, Vm} from "forge-std/Test.sol"; +import {Test} from "forge-std/Test.sol"; import {Strings} from "openzeppelin/utils/Strings.sol"; import {console} from "forge-std/console.sol"; @@ -11,7 +11,6 @@ import {IGateway} from "../src/interfaces/IGateway.sol"; import {IOGateway} from "../src/interfaces/IOGateway.sol"; import {IInitializable} from "../src/interfaces/IInitializable.sol"; import {IUpgradable} from "../src/interfaces/IUpgradable.sol"; -import {IMiddlewareBasic} from "../src/interfaces/IMiddlewareBasic.sol"; import {Gateway} from "../src/Gateway.sol"; import {MockGateway} from "./mocks/MockGateway.sol"; @@ -163,23 +162,6 @@ contract GatewayTest is Test { return (Command.CreateAgent, abi.encode((keccak256("6666")))); } - function _makeReportSlashesCommand() public pure returns (Command, bytes memory) { - IOGateway.Slash[] memory slashes = new IOGateway.Slash[](1); - slashes[0] = IOGateway.Slash({operatorKey: bytes32(uint256(1)), slashFraction: 500_000, timestamp: 1}); - uint256 eraIndex = 1; - return (Command.ReportSlashes, abi.encode(IOGateway.SlashParams({eraIndex: eraIndex, slashes: slashes}))); - } - - function _makeReportRewardsCommand() public pure returns (Command, bytes memory) { - uint256 epoch = 0; - uint256 eraIndex = 1; - uint256 totalPointsToken = 1 ether; - uint256 tokensInflatedToken = 1 ether; - bytes32 rewardsRoot = bytes32(uint256(1)); - - return (Command.ReportRewards, abi.encode(epoch, eraIndex, totalPointsToken, tokensInflatedToken, rewardsRoot)); - } - function makeMockProof() public pure returns (Verification.Proof memory) { return Verification.Proof({ leafPartial: Verification.MMRLeafPartial({ @@ -1027,256 +1009,4 @@ contract GatewayTest is Test { bytes memory encodedParams = abi.encode(params); MockGateway(address(gateway)).agentExecutePublic(encodedParams); } - - // middleware not set, should not be able to process slash - function testSubmitSlashesWithoutMiddleware() public { - deal(assetHubAgent, 50 ether); - - (Command command, bytes memory params) = _makeReportSlashesCommand(); - - vm.expectEmit(true, true, true, true); - emit IOGateway.UnableToProcessSlashMessageB(abi.encodeWithSelector(Gateway.MiddlewareNotSet.selector)); - // Expect the gateway to emit `InboundMessageDispatched` - vm.expectEmit(true, true, true, true); - emit IGateway.InboundMessageDispatched(assetHubParaID.into(), 1, messageID, false); - - hoax(relayer, 1 ether); - IGateway(address(gateway)).submitV1( - InboundMessage(assetHubParaID.into(), 1, command, params, maxDispatchGas, maxRefund, reward, messageID), - proof, - makeMockProof() - ); - } - - // middleware set, but not complying with the interface, should not process slash - function testSubmitSlashesWithMiddlewareNotComplyingInterface() public { - deal(assetHubAgent, 50 ether); - - (Command command, bytes memory params) = _makeReportSlashesCommand(); - - IOGateway(address(gateway)).setMiddleware(0x0123456789012345678901234567890123456789); - - bytes memory empty; - // Expect the gateway to emit `InboundMessageDispatched` - // For some reason when you are loading an address not complying an interface, you get an empty message - // It still serves us to know that this is the reason - vm.expectEmit(true, true, true, true); - emit IOGateway.UnableToProcessSlashMessageB(empty); - vm.expectEmit(true, true, true, true); - emit IGateway.InboundMessageDispatched(assetHubParaID.into(), 1, messageID, false); - - hoax(relayer, 1 ether); - IGateway(address(gateway)).submitV1( - InboundMessage(assetHubParaID.into(), 1, command, params, maxDispatchGas, maxRefund, reward, messageID), - proof, - makeMockProof() - ); - } - - // middleware set, complying interface but slash reverts - function testSubmitSlashesWithMiddlewareComplyingInterfaceAndSlashRevert() public { - deal(assetHubAgent, 50 ether); - - (Command command, bytes memory params) = _makeReportSlashesCommand(); - - bytes memory expectedError = bytes("no process slash"); - - // We mock the call so that it reverts - vm.mockCallRevert(address(1), abi.encodeWithSelector(IMiddlewareBasic.slash.selector), "no process slash"); - - // We mock the call so that it does not revert, but it will revert in the previous one - vm.mockCall(address(1), abi.encodeWithSelector(IMiddlewareBasic.getEpochAtTs.selector), abi.encode(10)); - - IOGateway(address(gateway)).setMiddleware(address(1)); - - IOGateway.Slash memory expectedSlash = - IOGateway.Slash({operatorKey: bytes32(uint256(1)), slashFraction: 500_000, timestamp: 1}); - - vm.expectEmit(true, true, true, true); - emit IOGateway.UnableToProcessIndividualSlashB( - expectedSlash.operatorKey, expectedSlash.slashFraction, expectedSlash.timestamp, expectedError - ); - vm.expectEmit(true, true, true, true); - emit IGateway.InboundMessageDispatched(assetHubParaID.into(), 1, messageID, true); - - hoax(relayer, 1 ether); - IGateway(address(gateway)).submitV1( - InboundMessage(assetHubParaID.into(), 1, command, params, maxDispatchGas, maxRefund, reward, messageID), - proof, - makeMockProof() - ); - } - - // middleware set, complying interface and slash processed - function testSubmitSlashesWithMiddlewareComplyingInterfaceAndSlashProcessed() public { - deal(assetHubAgent, 50 ether); - - (Command command, bytes memory params) = _makeReportSlashesCommand(); - - // We mock the call so that it does not revert - vm.mockCall(address(1), abi.encodeWithSelector(IMiddlewareBasic.slash.selector), abi.encode(10)); - - // We mock the call so that it does not revert - vm.mockCall(address(1), abi.encodeWithSelector(IMiddlewareBasic.getEpochAtTs.selector), abi.encode(10)); - - IOGateway(address(gateway)).setMiddleware(address(1)); - - // Since we are asserting all fields, the last one is a true, therefore meaning - // that the dispatch went through correctly - - vm.expectEmit(true, true, true, true); - emit IGateway.InboundMessageDispatched(assetHubParaID.into(), 1, messageID, true); - - hoax(relayer, 1 ether); - vm.recordLogs(); - IGateway(address(gateway)).submitV1( - InboundMessage(assetHubParaID.into(), 1, command, params, maxDispatchGas, maxRefund, reward, messageID), - proof, - makeMockProof() - ); - - Vm.Log[] memory entries = vm.getRecordedLogs(); - // We assert none of the slash error events has been emitted - for (uint256 i = 0; i < entries.length; i++) { - assertNotEq(entries[i].topics[0], IOGateway.UnableToProcessIndividualSlashB.selector); - assertNotEq(entries[i].topics[0], IOGateway.UnableToProcessIndividualSlashS.selector); - } - } - - function testSubmitRewards() public { - deal(assetHubAgent, 50 ether); - - (Command command, bytes memory params) = _makeReportRewardsCommand(); - - // We mock the call so that it does not revert - vm.mockCall(address(1), abi.encodeWithSelector(IMiddlewareBasic.distributeRewards.selector), abi.encode(true)); - - IOGateway(address(gateway)).setMiddleware(address(1)); - - // Expect the gateway to emit `InboundMessageDispatched` - vm.expectEmit(true, true, true, true); - emit IGateway.InboundMessageDispatched(assetHubParaID.into(), 1, messageID, true); - - hoax(relayer, 1 ether); - IGateway(address(gateway)).submitV1( - InboundMessage(assetHubParaID.into(), 1, command, params, maxDispatchGas, maxRefund, reward, messageID), - proof, - makeMockProof() - ); - } - - function testSubmitRewardsWithoutMiddleware() public { - deal(assetHubAgent, 50 ether); - - (Command command, bytes memory params) = _makeReportRewardsCommand(); - - vm.expectEmit(true, true, true, true); - emit IOGateway.UnableToProcessRewardsMessageB(abi.encodeWithSelector(Gateway.MiddlewareNotSet.selector)); - // Expect the gateway to emit `InboundMessageDispatched` - vm.expectEmit(true, true, true, true); - emit IGateway.InboundMessageDispatched(assetHubParaID.into(), 1, messageID, false); - - hoax(relayer, 1 ether); - IGateway(address(gateway)).submitV1( - InboundMessage(assetHubParaID.into(), 1, command, params, maxDispatchGas, maxRefund, reward, messageID), - proof, - makeMockProof() - ); - } - - // middleware set, but not complying with the interface, should not process rewards - function testSubmitRewardsWithMiddlewareNotComplyingInterface() public { - deal(assetHubAgent, 50 ether); - - (Command command, bytes memory params) = _makeReportRewardsCommand(); - - IOGateway(address(gateway)).setMiddleware(0x0123456789012345678901234567890123456789); - - bytes memory empty; - // Expect the gateway to emit `InboundMessageDispatched` - // For some reason when you are loading an address not complying an interface, you get an empty message - // It still serves us to know that this is the reason - vm.expectEmit(true, true, true, true); - emit IOGateway.UnableToProcessRewardsMessageB(empty); - vm.expectEmit(true, true, true, true); - emit IGateway.InboundMessageDispatched(assetHubParaID.into(), 1, messageID, false); - - hoax(relayer, 1 ether); - IGateway(address(gateway)).submitV1( - InboundMessage(assetHubParaID.into(), 1, command, params, maxDispatchGas, maxRefund, reward, messageID), - proof, - makeMockProof() - ); - } - - // middleware set, complying interface but rewards reverts - function testSubmitRewardsWithMiddlewareComplyingInterfaceAndRewardsRevert() public { - deal(assetHubAgent, 50 ether); - - (Command command, bytes memory params) = _makeReportRewardsCommand(); - - bytes memory expectedError = bytes("can't process rewards"); //This should actually come from IODefaultOperatorRewards - - // We mock the call so that it reverts - vm.mockCallRevert( - address(1), abi.encodeWithSelector(IMiddlewareBasic.distributeRewards.selector), "can't process rewards" - ); - - IOGateway(address(gateway)).setMiddleware(address(1)); - - uint256 expectedEpoch = 0; - uint256 expectedEraIndex = 1; - uint256 expectedTotalPointsToken = 1 ether; - uint256 expectedTotalTokensInflated = 1 ether; - bytes32 expectedRewardsRoot = bytes32(uint256(1)); - - vm.expectEmit(true, true, true, true); - emit IOGateway.UnableToProcessRewardsB( - expectedEpoch, - expectedEraIndex, - expectedTotalPointsToken, - expectedTotalTokensInflated, - expectedRewardsRoot, - expectedError - ); - vm.expectEmit(true, true, true, true); - emit IGateway.InboundMessageDispatched(assetHubParaID.into(), 1, messageID, true); - - hoax(relayer, 1 ether); - IGateway(address(gateway)).submitV1( - InboundMessage(assetHubParaID.into(), 1, command, params, maxDispatchGas, maxRefund, reward, messageID), - proof, - makeMockProof() - ); - } - - // middleware set, complying interface and rewards processed - function testSubmitRewardsWithMiddlewareComplyingInterfaceAndRewardsProcessed() public { - deal(assetHubAgent, 50 ether); - - (Command command, bytes memory params) = _makeReportRewardsCommand(); - - // We mock the call so that it does not revert - vm.mockCall(address(1), abi.encodeWithSelector(IMiddlewareBasic.distributeRewards.selector), abi.encode(true)); - - IOGateway(address(gateway)).setMiddleware(address(1)); - - vm.expectEmit(true, true, true, true); - emit IGateway.InboundMessageDispatched(assetHubParaID.into(), 1, messageID, true); - - hoax(relayer, 1 ether); - vm.recordLogs(); - IGateway(address(gateway)).submitV1( - InboundMessage(assetHubParaID.into(), 1, command, params, maxDispatchGas, maxRefund, reward, messageID), - proof, - makeMockProof() - ); - - Vm.Log[] memory entries = vm.getRecordedLogs(); - // We assert none of the rewards error events has been emitted - for (uint256 i = 0; i < entries.length; i++) { - assertNotEq(entries[i].topics[0], IOGateway.UnableToProcessRewardsMessageB.selector); - assertNotEq(entries[i].topics[0], IOGateway.UnableToProcessRewardsMessageS.selector); - } - } } diff --git a/overridden_contracts/test/override_test/Gateway.t.sol b/overridden_contracts/test/override_test/Gateway.t.sol index 9fb889e..64fbab5 100644 --- a/overridden_contracts/test/override_test/Gateway.t.sol +++ b/overridden_contracts/test/override_test/Gateway.t.sol @@ -14,7 +14,7 @@ // along with Tanssi. If not, see pragma solidity 0.8.25; -import {Test, console2} from "forge-std/Test.sol"; +import {Test, console2, Vm} from "forge-std/Test.sol"; import { AgentExecuteCommand, InboundMessage, @@ -26,6 +26,7 @@ import { multiAddressFromBytes20 } from "../../src/Types.sol"; import {IGateway} from "../../src/interfaces/IGateway.sol"; +import {IMiddlewareBasic} from "../../src/interfaces/IMiddlewareBasic.sol"; import {MockGateway} from "../mocks/MockGateway.sol"; import {CreateAgentParams, CreateChannelParams} from "../../src/Params.sol"; import {OperatingMode, ParaID, Command} from "../../src/Types.sol"; @@ -33,6 +34,7 @@ import {GatewayProxy} from "../../src/GatewayProxy.sol"; import {MultiAddress} from "../../src/MultiAddress.sol"; import {AgentExecutor} from "../../src/AgentExecutor.sol"; import {SetOperatingModeParams} from "../../src/Params.sol"; +import {Verification} from "../../src/Verification.sol"; import {Strings} from "openzeppelin/utils/Strings.sol"; @@ -147,7 +149,6 @@ contract GatewayTest is Test { account1 = makeAddr("account1"); account2 = makeAddr("account2"); - middleware = makeAddr("middleware"); // create tokens for account 1 hoax(account1); @@ -160,9 +161,39 @@ contract GatewayTest is Test { recipientAddress20 = multiAddressFromBytes20(bytes20(keccak256("recipient"))); dotTokenID = bytes32(uint256(1)); + } + + function _makeReportSlashesCommand() public pure returns (Command, bytes memory) { + IOGateway.Slash[] memory slashes = new IOGateway.Slash[](1); + slashes[0] = IOGateway.Slash({operatorKey: bytes32(uint256(1)), slashFraction: 500_000, timestamp: 1}); + uint256 eraIndex = 1; + return (Command.ReportSlashes, abi.encode(IOGateway.SlashParams({eraIndex: eraIndex, slashes: slashes}))); + } - // set middleware - IOGateway(address(gateway)).setMiddleware(middleware); + function _makeReportRewardsCommand() public pure returns (Command, bytes memory) { + uint256 epoch = 0; + uint256 eraIndex = 1; + uint256 totalPointsToken = 1 ether; + uint256 tokensInflatedToken = 1 ether; + bytes32 rewardsRoot = bytes32(uint256(1)); + + return (Command.ReportRewards, abi.encode(epoch, eraIndex, totalPointsToken, tokensInflatedToken, rewardsRoot)); + } + + function makeMockProof() public pure returns (Verification.Proof memory) { + return Verification.Proof({ + leafPartial: Verification.MMRLeafPartial({ + version: 0, + parentNumber: 0, + parentHash: bytes32(0), + nextAuthoritySetID: 0, + nextAuthoritySetLen: 0, + nextAuthoritySetRoot: 0 + }), + leafProof: new bytes32[](0), + leafProofOrder: 0, + parachainHeadsRoot: bytes32(0) + }); } function createLongOperatorsData() public view returns (bytes32[] memory) { @@ -296,4 +327,256 @@ contract GatewayTest is Test { assertEq(abi.encode(IOGateway.SlashParams({eraIndex: eraIndex, slashes: slashes})), TEST_VECTOR_SLASH_DATA); } + + // middleware not set, should not be able to process slash + function testSubmitSlashesWithoutMiddleware() public { + deal(assetHubAgent, 50 ether); + + (Command command, bytes memory params) = _makeReportSlashesCommand(); + + vm.expectEmit(true, true, true, true); + emit IOGateway.UnableToProcessSlashMessageB(abi.encodeWithSelector(Gateway.MiddlewareNotSet.selector)); + // Expect the gateway to emit `InboundMessageDispatched` + vm.expectEmit(true, true, true, true); + emit IGateway.InboundMessageDispatched(assetHubParaID.into(), 1, messageID, false); + + hoax(relayer, 1 ether); + IGateway(address(gateway)).submitV1( + InboundMessage(assetHubParaID.into(), 1, command, params, maxDispatchGas, maxRefund, reward, messageID), + proof, + makeMockProof() + ); + } + + // middleware set, but not complying with the interface, should not process slash + function testSubmitSlashesWithMiddlewareNotComplyingInterface() public { + deal(assetHubAgent, 50 ether); + + (Command command, bytes memory params) = _makeReportSlashesCommand(); + + IOGateway(address(gateway)).setMiddleware(0x0123456789012345678901234567890123456789); + + bytes memory empty; + // Expect the gateway to emit `InboundMessageDispatched` + // For some reason when you are loading an address not complying an interface, you get an empty message + // It still serves us to know that this is the reason + vm.expectEmit(true, true, true, true); + emit IOGateway.UnableToProcessSlashMessageB(empty); + vm.expectEmit(true, true, true, true); + emit IGateway.InboundMessageDispatched(assetHubParaID.into(), 1, messageID, false); + + hoax(relayer, 1 ether); + IGateway(address(gateway)).submitV1( + InboundMessage(assetHubParaID.into(), 1, command, params, maxDispatchGas, maxRefund, reward, messageID), + proof, + makeMockProof() + ); + } + + // middleware set, complying interface but slash reverts + function testSubmitSlashesWithMiddlewareComplyingInterfaceAndSlashRevert() public { + deal(assetHubAgent, 50 ether); + + (Command command, bytes memory params) = _makeReportSlashesCommand(); + + bytes memory expectedError = bytes("no process slash"); + + // We mock the call so that it reverts + vm.mockCallRevert(address(1), abi.encodeWithSelector(IMiddlewareBasic.slash.selector), "no process slash"); + + // We mock the call so that it does not revert, but it will revert in the previous one + vm.mockCall(address(1), abi.encodeWithSelector(IMiddlewareBasic.getEpochAtTs.selector), abi.encode(10)); + + IOGateway(address(gateway)).setMiddleware(address(1)); + + IOGateway.Slash memory expectedSlash = + IOGateway.Slash({operatorKey: bytes32(uint256(1)), slashFraction: 500_000, timestamp: 1}); + + vm.expectEmit(true, true, true, true); + emit IOGateway.UnableToProcessIndividualSlashB( + expectedSlash.operatorKey, expectedSlash.slashFraction, expectedSlash.timestamp, expectedError + ); + vm.expectEmit(true, true, true, true); + emit IGateway.InboundMessageDispatched(assetHubParaID.into(), 1, messageID, true); + + hoax(relayer, 1 ether); + IGateway(address(gateway)).submitV1( + InboundMessage(assetHubParaID.into(), 1, command, params, maxDispatchGas, maxRefund, reward, messageID), + proof, + makeMockProof() + ); + } + + // middleware set, complying interface and slash processed + function testSubmitSlashesWithMiddlewareComplyingInterfaceAndSlashProcessed() public { + deal(assetHubAgent, 50 ether); + + (Command command, bytes memory params) = _makeReportSlashesCommand(); + + // We mock the call so that it does not revert + vm.mockCall(address(1), abi.encodeWithSelector(IMiddlewareBasic.slash.selector), abi.encode(10)); + + // We mock the call so that it does not revert + vm.mockCall(address(1), abi.encodeWithSelector(IMiddlewareBasic.getEpochAtTs.selector), abi.encode(10)); + + IOGateway(address(gateway)).setMiddleware(address(1)); + + // Since we are asserting all fields, the last one is a true, therefore meaning + // that the dispatch went through correctly + + vm.expectEmit(true, true, true, true); + emit IGateway.InboundMessageDispatched(assetHubParaID.into(), 1, messageID, true); + + hoax(relayer, 1 ether); + vm.recordLogs(); + IGateway(address(gateway)).submitV1( + InboundMessage(assetHubParaID.into(), 1, command, params, maxDispatchGas, maxRefund, reward, messageID), + proof, + makeMockProof() + ); + + Vm.Log[] memory entries = vm.getRecordedLogs(); + // We assert none of the slash error events has been emitted + for (uint256 i = 0; i < entries.length; i++) { + assertNotEq(entries[i].topics[0], IOGateway.UnableToProcessIndividualSlashB.selector); + assertNotEq(entries[i].topics[0], IOGateway.UnableToProcessIndividualSlashS.selector); + } + } + + function testSubmitRewards() public { + deal(assetHubAgent, 50 ether); + + (Command command, bytes memory params) = _makeReportRewardsCommand(); + + // We mock the call so that it does not revert + vm.mockCall(address(1), abi.encodeWithSelector(IMiddlewareBasic.distributeRewards.selector), abi.encode(true)); + + IOGateway(address(gateway)).setMiddleware(address(1)); + + // Expect the gateway to emit `InboundMessageDispatched` + vm.expectEmit(true, true, true, true); + emit IGateway.InboundMessageDispatched(assetHubParaID.into(), 1, messageID, true); + + hoax(relayer, 1 ether); + IGateway(address(gateway)).submitV1( + InboundMessage(assetHubParaID.into(), 1, command, params, maxDispatchGas, maxRefund, reward, messageID), + proof, + makeMockProof() + ); + } + + function testSubmitRewardsWithoutMiddleware() public { + deal(assetHubAgent, 50 ether); + + (Command command, bytes memory params) = _makeReportRewardsCommand(); + + vm.expectEmit(true, true, true, true); + emit IOGateway.UnableToProcessRewardsMessageB(abi.encodeWithSelector(Gateway.MiddlewareNotSet.selector)); + // Expect the gateway to emit `InboundMessageDispatched` + vm.expectEmit(true, true, true, true); + emit IGateway.InboundMessageDispatched(assetHubParaID.into(), 1, messageID, false); + + hoax(relayer, 1 ether); + IGateway(address(gateway)).submitV1( + InboundMessage(assetHubParaID.into(), 1, command, params, maxDispatchGas, maxRefund, reward, messageID), + proof, + makeMockProof() + ); + } + + // middleware set, but not complying with the interface, should not process rewards + function testSubmitRewardsWithMiddlewareNotComplyingInterface() public { + deal(assetHubAgent, 50 ether); + + (Command command, bytes memory params) = _makeReportRewardsCommand(); + + IOGateway(address(gateway)).setMiddleware(0x0123456789012345678901234567890123456789); + + bytes memory empty; + // Expect the gateway to emit `InboundMessageDispatched` + // For some reason when you are loading an address not complying an interface, you get an empty message + // It still serves us to know that this is the reason + vm.expectEmit(true, true, true, true); + emit IOGateway.UnableToProcessRewardsMessageB(empty); + vm.expectEmit(true, true, true, true); + emit IGateway.InboundMessageDispatched(assetHubParaID.into(), 1, messageID, false); + + hoax(relayer, 1 ether); + IGateway(address(gateway)).submitV1( + InboundMessage(assetHubParaID.into(), 1, command, params, maxDispatchGas, maxRefund, reward, messageID), + proof, + makeMockProof() + ); + } + + // middleware set, complying interface but rewards reverts + function testSubmitRewardsWithMiddlewareComplyingInterfaceAndRewardsRevert() public { + deal(assetHubAgent, 50 ether); + + (Command command, bytes memory params) = _makeReportRewardsCommand(); + + bytes memory expectedError = bytes("can't process rewards"); //This should actually come from IODefaultOperatorRewards + + // We mock the call so that it reverts + vm.mockCallRevert( + address(1), abi.encodeWithSelector(IMiddlewareBasic.distributeRewards.selector), "can't process rewards" + ); + + IOGateway(address(gateway)).setMiddleware(address(1)); + + uint256 expectedEpoch = 0; + uint256 expectedEraIndex = 1; + uint256 expectedTotalPointsToken = 1 ether; + uint256 expectedTotalTokensInflated = 1 ether; + bytes32 expectedRewardsRoot = bytes32(uint256(1)); + + vm.expectEmit(true, true, true, true); + emit IOGateway.UnableToProcessRewardsB( + expectedEpoch, + expectedEraIndex, + expectedTotalPointsToken, + expectedTotalTokensInflated, + expectedRewardsRoot, + expectedError + ); + vm.expectEmit(true, true, true, true); + emit IGateway.InboundMessageDispatched(assetHubParaID.into(), 1, messageID, true); + + hoax(relayer, 1 ether); + IGateway(address(gateway)).submitV1( + InboundMessage(assetHubParaID.into(), 1, command, params, maxDispatchGas, maxRefund, reward, messageID), + proof, + makeMockProof() + ); + } + + // middleware set, complying interface and rewards processed + function testSubmitRewardsWithMiddlewareComplyingInterfaceAndRewardsProcessed() public { + deal(assetHubAgent, 50 ether); + + (Command command, bytes memory params) = _makeReportRewardsCommand(); + + // We mock the call so that it does not revert + vm.mockCall(address(1), abi.encodeWithSelector(IMiddlewareBasic.distributeRewards.selector), abi.encode(true)); + + IOGateway(address(gateway)).setMiddleware(address(1)); + + vm.expectEmit(true, true, true, true); + emit IGateway.InboundMessageDispatched(assetHubParaID.into(), 1, messageID, true); + + hoax(relayer, 1 ether); + vm.recordLogs(); + IGateway(address(gateway)).submitV1( + InboundMessage(assetHubParaID.into(), 1, command, params, maxDispatchGas, maxRefund, reward, messageID), + proof, + makeMockProof() + ); + + Vm.Log[] memory entries = vm.getRecordedLogs(); + // We assert none of the rewards error events has been emitted + for (uint256 i = 0; i < entries.length; i++) { + assertNotEq(entries[i].topics[0], IOGateway.UnableToProcessRewardsMessageB.selector); + assertNotEq(entries[i].topics[0], IOGateway.UnableToProcessRewardsMessageS.selector); + } + } }