diff --git a/contracts/src/v0.8/automation/dev/test/AutomationRegistry2_3.t.sol b/contracts/src/v0.8/automation/dev/test/AutomationRegistry2_3.t.sol index 7a33b9b9746..8d0fdbe522d 100644 --- a/contracts/src/v0.8/automation/dev/test/AutomationRegistry2_3.t.sol +++ b/contracts/src/v0.8/automation/dev/test/AutomationRegistry2_3.t.sol @@ -723,7 +723,6 @@ contract SetConfig is SetUp { } } -// allow NOPs to withdraw balances made before disableOffchainNOPsOffchain is called contract NOPsSettlement is SetUp { event NOPsSettledOffchain(address[] payees, uint256[] payments); event FundsWithdrawn(uint256 indexed id, uint256 amount, address to); @@ -1000,38 +999,6 @@ contract NOPsSettlement is SetUp { registry.withdrawFunds(id, UPKEEP_ADMIN); } - function _transmit(uint256 id, Registry registry) internal { - uint256[] memory upkeepIds = new uint256[](1); - uint256[] memory gasLimits = new uint256[](1); - bytes[] memory performDatas = new bytes[](1); - bytes[] memory triggers = new bytes[](1); - upkeepIds[0] = id; - gasLimits[0] = 1000000; - triggers[0] = _encodeConditionalTrigger( - AutoBase.ConditionalTrigger(uint32(block.number - 1), blockhash(block.number - 1)) - ); - AutoBase.Report memory report = AutoBase.Report( - uint256(1000000000), - uint256(2000000000), - upkeepIds, - gasLimits, - triggers, - performDatas - ); - - bytes memory reportBytes = _encodeReport(report); - (, , bytes32 configDigest) = registry.latestConfigDetails(); - bytes32[3] memory reportContext = [configDigest, configDigest, configDigest]; - uint256[] memory signerPKs = new uint256[](2); - signerPKs[0] = SIGNING_KEY0; - signerPKs[1] = SIGNING_KEY1; - (bytes32[] memory rs, bytes32[] memory ss, bytes32 vs) = _signReport(reportBytes, reportContext, signerPKs); - - vm.startPrank(TRANSMITTERS[0]); - registry.transmit(reportContext, reportBytes, rs, ss, vs); - vm.stopPrank(); - } - function _configureWithNewTransmitters(Registry registry, Registrar registrar) internal { IERC20[] memory billingTokens = new IERC20[](1); billingTokens[0] = IERC20(address(usdToken)); @@ -1345,3 +1312,47 @@ contract BillingOverrides is SetUp { assertGt(maxPayment2, maxPayment1); } } + +contract Transmit is SetUp { + function test_handlesMixedBatchOfBillingTokens() external { + uint256[] memory prevUpkeepBalances = new uint256[](3); + prevUpkeepBalances[0] = registry.getBalance(linkUpkeepID); + prevUpkeepBalances[1] = registry.getBalance(usdUpkeepID); + prevUpkeepBalances[2] = registry.getBalance(nativeUpkeepID); + uint256[] memory prevTokenBalances = new uint256[](3); + prevTokenBalances[0] = linkToken.balanceOf(address(registry)); + prevTokenBalances[1] = usdToken.balanceOf(address(registry)); + prevTokenBalances[2] = weth.balanceOf(address(registry)); + uint256[] memory prevReserveBalances = new uint256[](3); + prevReserveBalances[0] = registry.getReserveAmount(address(linkToken)); + prevReserveBalances[1] = registry.getReserveAmount(address(usdToken)); + prevReserveBalances[2] = registry.getReserveAmount(address(weth)); + uint256[] memory upkeepIDs = new uint256[](3); + upkeepIDs[0] = linkUpkeepID; + upkeepIDs[1] = usdUpkeepID; + upkeepIDs[2] = nativeUpkeepID; + // do the thing + _transmit(upkeepIDs, registry); + // assert upkeep balances have decreased + require(prevUpkeepBalances[0] > registry.getBalance(linkUpkeepID), "link upkeep balance should have decreased"); + require(prevUpkeepBalances[1] > registry.getBalance(usdUpkeepID), "usd upkeep balance should have decreased"); + require(prevUpkeepBalances[2] > registry.getBalance(nativeUpkeepID), "native upkeep balance should have decreased"); + // assert token balances have not changed + assertEq(prevTokenBalances[0], linkToken.balanceOf(address(registry))); + assertEq(prevTokenBalances[1], usdToken.balanceOf(address(registry))); + assertEq(prevTokenBalances[2], weth.balanceOf(address(registry))); + // assert reserve amounts have adjusted accordingly + require( + prevReserveBalances[0] < registry.getReserveAmount(address(linkToken)), + "usd reserve amount should have increased" + ); // link reserve amount increases in value equal to the decrease of the other reserve amounts + require( + prevReserveBalances[1] > registry.getReserveAmount(address(usdToken)), + "usd reserve amount should have decreased" + ); + require( + prevReserveBalances[2] > registry.getReserveAmount(address(weth)), + "native reserve amount should have decreased" + ); + } +} diff --git a/contracts/src/v0.8/automation/dev/test/BaseTest.t.sol b/contracts/src/v0.8/automation/dev/test/BaseTest.t.sol index 1706ac049a3..49a47396456 100644 --- a/contracts/src/v0.8/automation/dev/test/BaseTest.t.sol +++ b/contracts/src/v0.8/automation/dev/test/BaseTest.t.sol @@ -12,7 +12,7 @@ import {AutomationRegistryBase2_3 as AutoBase} from "../v2_3/AutomationRegistryB import {AutomationRegistryLogicA2_3} from "../v2_3/AutomationRegistryLogicA2_3.sol"; import {AutomationRegistryLogicB2_3} from "../v2_3/AutomationRegistryLogicB2_3.sol"; import {AutomationRegistryLogicC2_3} from "../v2_3/AutomationRegistryLogicC2_3.sol"; -import {IAutomationRegistryMaster2_3, AutomationRegistryBase2_3} from "../interfaces/v2_3/IAutomationRegistryMaster2_3.sol"; +import {IAutomationRegistryMaster2_3 as Registry, AutomationRegistryBase2_3} from "../interfaces/v2_3/IAutomationRegistryMaster2_3.sol"; import {AutomationRegistrar2_3} from "../v2_3/AutomationRegistrar2_3.sol"; import {ChainModuleBase} from "../../chains/ChainModuleBase.sol"; import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; @@ -127,7 +127,7 @@ contract BaseTest is Test { } /// @notice deploys the component parts of a registry, but nothing more - function deployRegistry(AutoBase.PayoutMode payoutMode) internal returns (IAutomationRegistryMaster2_3) { + function deployRegistry(AutoBase.PayoutMode payoutMode) internal returns (Registry) { AutomationForwarderLogic forwarderLogic = new AutomationForwarderLogic(); AutomationRegistryLogicC2_3 logicC2_3 = new AutomationRegistryLogicC2_3( address(linkToken), @@ -141,14 +141,14 @@ contract BaseTest is Test { ); AutomationRegistryLogicB2_3 logicB2_3 = new AutomationRegistryLogicB2_3(logicC2_3); AutomationRegistryLogicA2_3 logicA2_3 = new AutomationRegistryLogicA2_3(logicB2_3); - return IAutomationRegistryMaster2_3(payable(address(new AutomationRegistry2_3(logicA2_3)))); + return Registry(payable(address(new AutomationRegistry2_3(logicA2_3)))); } /// @notice deploys and configures a registry, registrar, and everything needed for most tests function deployAndConfigureRegistryAndRegistrar( AutoBase.PayoutMode payoutMode - ) internal returns (IAutomationRegistryMaster2_3, AutomationRegistrar2_3) { - IAutomationRegistryMaster2_3 registry = deployRegistry(payoutMode); + ) internal returns (Registry, AutomationRegistrar2_3) { + Registry registry = deployRegistry(payoutMode); IERC20[] memory billingTokens = new IERC20[](3); billingTokens[0] = IERC20(address(usdToken)); @@ -258,7 +258,7 @@ contract BaseTest is Test { /// @notice this function updates the billing config for the provided token on the provided registry, /// and throws an error if the token is not found function _updateBillingTokenConfig( - IAutomationRegistryMaster2_3 registry, + Registry registry, address billingToken, AutomationRegistryBase2_3.BillingConfig memory newConfig ) internal { @@ -291,6 +291,52 @@ contract BaseTest is Test { ); } + function _transmit(uint256 id, Registry registry) internal { + uint256[] memory ids = new uint256[](1); + ids[0] = id; + _transmit(ids, registry); + } + + function _transmit(uint256[] memory ids, Registry registry) internal { + uint256[] memory upkeepIds = new uint256[](ids.length); + uint256[] memory gasLimits = new uint256[](ids.length); + bytes[] memory performDatas = new bytes[](ids.length); + bytes[] memory triggers = new bytes[](ids.length); + for (uint256 i = 0; i < ids.length; i++) { + upkeepIds[i] = ids[i]; + gasLimits[i] = registry.getUpkeep(ids[i]).performGas; + performDatas[i] = new bytes(0); + uint8 triggerType = registry.getTriggerType(ids[i]); + if (triggerType == 0) { + triggers[i] = _encodeConditionalTrigger( + AutoBase.ConditionalTrigger(uint32(block.number - 1), blockhash(block.number - 1)) + ); + } else { + revert("not implemented"); + } + } + AutoBase.Report memory report = AutoBase.Report( + uint256(1000000000), + uint256(2000000000), + upkeepIds, + gasLimits, + triggers, + performDatas + ); + + bytes memory reportBytes = _encodeReport(report); + (, , bytes32 configDigest) = registry.latestConfigDetails(); + bytes32[3] memory reportContext = [configDigest, configDigest, configDigest]; + uint256[] memory signerPKs = new uint256[](2); + signerPKs[0] = SIGNING_KEY0; + signerPKs[1] = SIGNING_KEY1; + (bytes32[] memory rs, bytes32[] memory ss, bytes32 vs) = _signReport(reportBytes, reportContext, signerPKs); + + vm.startPrank(TRANSMITTERS[0]); + registry.transmit(reportContext, reportBytes, rs, ss, vs); + vm.stopPrank(); + } + /// @notice Gather signatures on report data /// @param report - Report bytes generated from `_buildReport` /// @param reportContext - Report context bytes32 generated from `_buildReport`