diff --git a/contracts/src/v0.8/l2ep/test/mocks/MockAggregatorV2V3.sol b/contracts/src/v0.8/l2ep/test/mocks/MockAggregatorV2V3.sol new file mode 100644 index 00000000000..c4e2f710300 --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/mocks/MockAggregatorV2V3.sol @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.9; + +import {AggregatorV2V3Interface} from "../../../shared/interfaces/AggregatorV2V3Interface.sol"; + +contract MockAggregatorV2V3 is AggregatorV2V3Interface { + function latestAnswer() external pure returns (int256) { + return 0; + } + + function latestTimestamp() external pure returns (uint256) { + return 0; + } + + function latestRound() external pure returns (uint256) { + return 0; + } + + function getAnswer(uint256) external pure returns (int256) { + return 0; + } + + function getTimestamp(uint256 roundId) external pure returns (uint256) { + return roundId; + } + + function decimals() external pure returns (uint8) { + return 0; + } + + function description() external pure returns (string memory) { + return ""; + } + + function version() external pure returns (uint256) { + return 0; + } + + function getRoundData( + uint80 + ) + external + pure + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (0, 0, 0, 0, 0); + } + + function latestRoundData() + external + pure + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (73786976294838220258, 96800000000, 163826896, 1638268960, 73786976294838220258); + } +} diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/.gitkeep b/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumValidator.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumValidator.t.sol new file mode 100644 index 00000000000..abc78892a3a --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumValidator.t.sol @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {AccessControllerInterface} from "../../../../shared/interfaces/AccessControllerInterface.sol"; +import {SimpleWriteAccessController} from "../../../../shared/access/SimpleWriteAccessController.sol"; +import {ArbitrumSequencerUptimeFeed} from "../../../dev/arbitrum/ArbitrumSequencerUptimeFeed.sol"; +import {MockArbitrumInbox} from "../../../../../v0.8/tests/MockArbitrumInbox.sol"; +import {ArbitrumValidator} from "../../../dev/arbitrum/ArbitrumValidator.sol"; +import {MockAggregatorV2V3} from "../../mocks/MockAggregatorV2V3.sol"; +import {L2EPTest} from "../L2EPTest.sol"; + +// Use this command from the /contracts directory to run this test file: +// +// FOUNDRY_PROFILE=l2ep forge test -vvv --match-path ./src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumValidator.t.sol +// +contract ArbitrumValidatorTest is L2EPTest { + /// Helper constants + address internal constant L2_SEQ_STATUS_RECORDER_ADDRESS = 0x491B1dDA0A8fa069bbC1125133A975BF4e85a91b; + uint256 internal constant GAS_PRICE_BID = 1000000; + uint256 internal constant BASE_FEE = 14000000000; + uint256 internal constant MAX_GAS = 1000000; + + /// Helper variables + address internal s_eoaValidator = vm.addr(0x2); + + /// L2EP contracts + AccessControllerInterface internal s_accessController; + MockArbitrumInbox internal s_mockArbitrumInbox; + ArbitrumValidator internal s_arbitrumValidator; + MockAggregatorV2V3 internal s_l1GasFeed; + + /// Events + event RetryableTicketNoRefundAliasRewriteCreated( + address destAddr, + uint256 arbTxCallValue, + uint256 maxSubmissionCost, + address submissionRefundAddress, + address valueRefundAddress, + uint256 maxGas, + uint256 gasPriceBid, + bytes data + ); + + /// Setup + function setUp() public { + s_accessController = new SimpleWriteAccessController(); + s_mockArbitrumInbox = new MockArbitrumInbox(); + s_l1GasFeed = new MockAggregatorV2V3(); + s_arbitrumValidator = new ArbitrumValidator( + address(s_mockArbitrumInbox), + L2_SEQ_STATUS_RECORDER_ADDRESS, + address(s_accessController), + MAX_GAS, + GAS_PRICE_BID, + BASE_FEE, + address(s_l1GasFeed), + ArbitrumValidator.PaymentStrategy.L1 + ); + } +} + +contract Validate is ArbitrumValidatorTest { + /// @notice it post sequencer offline + function test_PostSequencerOffline() public { + // Gives access to the s_eoaValidator + s_arbitrumValidator.addAccess(s_eoaValidator); + + // Gets the ArbitrumValidator L2 address + address arbitrumValidatorL2Addr = address( + uint160(address(s_arbitrumValidator)) + uint160(0x1111000000000000000000000000000000001111) + ); + + // Sets block.timestamp to a later date, funds the ArbitrumValidator contract, and sets msg.sender and tx.origin + uint256 futureTimestampInSeconds = block.timestamp + 5000; + vm.warp(futureTimestampInSeconds); + vm.deal(address(s_arbitrumValidator), 1 ether); + vm.startPrank(s_eoaValidator, s_eoaValidator); + + // Sets up the expected event data + vm.expectEmit(false, false, false, true); + emit RetryableTicketNoRefundAliasRewriteCreated( + L2_SEQ_STATUS_RECORDER_ADDRESS, // destAddr + 0, // arbTxCallValue + 25312000000000, // maxSubmissionCost + arbitrumValidatorL2Addr, // submissionRefundAddress + arbitrumValidatorL2Addr, // valueRefundAddress + MAX_GAS, // maxGas + GAS_PRICE_BID, // gasPriceBid + abi.encodeWithSelector(ArbitrumSequencerUptimeFeed.updateStatus.selector, true, futureTimestampInSeconds) // data + ); + + // Runs the function (which produces the event to test) + s_arbitrumValidator.validate(0, 0, 1, 1); + vm.stopPrank(); + } +} diff --git a/contracts/src/v0.8/tests/MockArbitrumInbox.sol b/contracts/src/v0.8/tests/MockArbitrumInbox.sol index cd85ed4d6ea..445a361b309 100644 --- a/contracts/src/v0.8/tests/MockArbitrumInbox.sol +++ b/contracts/src/v0.8/tests/MockArbitrumInbox.sol @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.9; + import {IInbox} from "../vendor/arb-bridge-eth/v0.8.0-custom/contracts/bridge/interfaces/IInbox.sol"; import {IBridge} from "../vendor/arb-bridge-eth/v0.8.0-custom/contracts/bridge/interfaces/IBridge.sol"; @@ -13,46 +16,46 @@ contract MockArbitrumInbox is IInbox { bytes data ); - function sendL2Message(bytes calldata messageData) external override returns (uint256) { + function sendL2Message(bytes calldata /* messageData */) external pure override returns (uint256) { return 0; } function sendUnsignedTransaction( - uint256 maxGas, - uint256 gasPriceBid, - uint256 nonce, - address destAddr, - uint256 amount, - bytes calldata data - ) external override returns (uint256) { + uint256 /* maxGas */, + uint256 /* gasPriceBid */, + uint256 /* nonce */, + address /* destAddr */, + uint256 /* amount */, + bytes calldata /* data */ + ) external pure override returns (uint256) { return 0; } function sendContractTransaction( - uint256 maxGas, - uint256 gasPriceBid, - address destAddr, - uint256 amount, - bytes calldata data - ) external override returns (uint256) { + uint256 /* maxGas */, + uint256 /* gasPriceBid */, + address /* destAddr */, + uint256 /* amount */, + bytes calldata /* data */ + ) external pure override returns (uint256) { return 0; } function sendL1FundedUnsignedTransaction( - uint256 maxGas, - uint256 gasPriceBid, - uint256 nonce, - address destAddr, - bytes calldata data + uint256 /* maxGas */, + uint256 /* gasPriceBid */, + uint256 /* nonce */, + address /* destAddr */, + bytes calldata /* data */ ) external payable override returns (uint256) { return 0; } function sendL1FundedContractTransaction( - uint256 maxGas, - uint256 gasPriceBid, - address destAddr, - bytes calldata data + uint256 /* maxGas */, + uint256 /* gasPriceBid */, + address /* destAddr */, + bytes calldata /* data */ ) external payable override returns (uint256) { return 0; } @@ -81,32 +84,32 @@ contract MockArbitrumInbox is IInbox { } function createRetryableTicket( - address destAddr, - uint256 arbTxCallValue, - uint256 maxSubmissionCost, - address submissionRefundAddress, - address valueRefundAddress, - uint256 maxGas, - uint256 gasPriceBid, - bytes calldata data + address /* destAddr */, + uint256 /* arbTxCallValue */, + uint256 /* maxSubmissionCost */, + address /* submissionRefundAddress */, + address /* valueRefundAddress */, + uint256 /* maxGas */, + uint256 /* gasPriceBid */, + bytes calldata /* data */ ) external payable override returns (uint256) { return 0; } - function depositEth(address destAddr) external payable override returns (uint256) { + function depositEth(address /* destAddr */) external payable override returns (uint256) { return 0; } function depositEthRetryable( - address destAddr, - uint256 maxSubmissionCost, - uint256 maxGas, - uint256 maxGasPrice + address /* destAddr */, + uint256 /* maxSubmissionCost */, + uint256 /* maxGas */, + uint256 /* maxGasPrice */ ) external payable override returns (uint256) { return 0; } - function bridge() external view override returns (IBridge) { + function bridge() external pure override returns (IBridge) { return IBridge(address(0)); }