diff --git a/.github/workflows/solidity-foundry.yml b/.github/workflows/solidity-foundry.yml index 582503b0341..4b2d7b9b96f 100644 --- a/.github/workflows/solidity-foundry.yml +++ b/.github/workflows/solidity-foundry.yml @@ -31,7 +31,7 @@ jobs: { "name": "ccip", "setup": { "run-coverage": true, "min-coverage": 97.6, "run-gas-snapshot": true, "run-forge-fmt": true }}, { "name": "functions", "setup": { "run-coverage": false, "min-coverage": 98.5, "run-gas-snapshot": true, "run-forge-fmt": false }}, { "name": "keystone", "setup": { "run-coverage": true, "min-coverage": 72.8, "run-gas-snapshot": false, "run-forge-fmt": false }}, - { "name": "l2ep", "setup": { "run-coverage": true, "min-coverage": 63.4, "run-gas-snapshot": true, "run-forge-fmt": false }}, + { "name": "l2ep", "setup": { "run-coverage": true, "min-coverage": 61.0, "run-gas-snapshot": true, "run-forge-fmt": false }}, { "name": "liquiditymanager", "setup": { "run-coverage": true, "min-coverage": 46.3, "run-gas-snapshot": true, "run-forge-fmt": false }}, { "name": "llo-feeds", "setup": { "run-coverage": true, "min-coverage": 49.3, "run-gas-snapshot": true, "run-forge-fmt": false }}, { "name": "operatorforwarder", "setup": { "run-coverage": true, "min-coverage": 55.7, "run-gas-snapshot": true, "run-forge-fmt": false }}, diff --git a/contracts/.changeset/heavy-balloons-cheat.md b/contracts/.changeset/heavy-balloons-cheat.md new file mode 100644 index 00000000000..c0aedb266ec --- /dev/null +++ b/contracts/.changeset/heavy-balloons-cheat.md @@ -0,0 +1,9 @@ +--- +"chainlink": patch +--- + +#added Add ZKSync L2EP SequencerUptimeFeed contract +#added Add ZKSync L2EP Validator contract + + +SHIP-3004 \ No newline at end of file diff --git a/contracts/.gas-snapshot b/contracts/.gas-snapshot index 3a0354d539c..e793f8ce549 100644 --- a/contracts/.gas-snapshot +++ b/contracts/.gas-snapshot @@ -1,112 +1,142 @@ -CapabilitiesRegistry_AddCapabilitiesTest:test_AddCapability_NoConfigurationContract() (gas: 154832) -CapabilitiesRegistry_AddCapabilitiesTest:test_AddCapability_WithConfiguration() (gas: 178813) -CapabilitiesRegistry_AddCapabilitiesTest:test_RevertWhen_CalledByNonAdmin() (gas: 24723) -CapabilitiesRegistry_AddCapabilitiesTest:test_RevertWhen_CapabilityExists() (gas: 145703) -CapabilitiesRegistry_AddCapabilitiesTest:test_RevertWhen_ConfigurationContractDoesNotMatchInterface() (gas: 94606) -CapabilitiesRegistry_AddCapabilitiesTest:test_RevertWhen_ConfigurationContractNotDeployed() (gas: 92961) -CapabilitiesRegistry_AddDONTest:test_AddDON() (gas: 372302) -CapabilitiesRegistry_AddDONTest:test_RevertWhen_CalledByNonAdmin() (gas: 19273) -CapabilitiesRegistry_AddDONTest:test_RevertWhen_CapabilityDoesNotExist() (gas: 169752) -CapabilitiesRegistry_AddDONTest:test_RevertWhen_DeprecatedCapabilityAdded() (gas: 239789) -CapabilitiesRegistry_AddDONTest:test_RevertWhen_DuplicateCapabilityAdded() (gas: 249596) -CapabilitiesRegistry_AddDONTest:test_RevertWhen_DuplicateNodeAdded() (gas: 116890) -CapabilitiesRegistry_AddDONTest:test_RevertWhen_FaultToleranceIsZero() (gas: 43358) -CapabilitiesRegistry_AddDONTest:test_RevertWhen_NodeAlreadyBelongsToWorkflowDON() (gas: 343924) -CapabilitiesRegistry_AddDONTest:test_RevertWhen_NodeDoesNotSupportCapability() (gas: 180150) -CapabilitiesRegistry_AddNodeOperatorsTest:test_AddNodeOperators() (gas: 184135) -CapabilitiesRegistry_AddNodeOperatorsTest:test_RevertWhen_CalledByNonAdmin() (gas: 17602) -CapabilitiesRegistry_AddNodeOperatorsTest:test_RevertWhen_NodeOperatorAdminAddressZero() (gas: 18498) -CapabilitiesRegistry_AddNodesTest:test_AddsNodeParams() (gas: 358448) -CapabilitiesRegistry_AddNodesTest:test_OwnerCanAddNodes() (gas: 358414) -CapabilitiesRegistry_AddNodesTest:test_RevertWhen_AddingDuplicateP2PId() (gas: 301229) -CapabilitiesRegistry_AddNodesTest:test_RevertWhen_AddingNodeWithInvalidCapability() (gas: 55174) -CapabilitiesRegistry_AddNodesTest:test_RevertWhen_AddingNodeWithInvalidNodeOperator() (gas: 24895) -CapabilitiesRegistry_AddNodesTest:test_RevertWhen_AddingNodeWithoutCapabilities() (gas: 27669) -CapabilitiesRegistry_AddNodesTest:test_RevertWhen_CalledByNonNodeOperatorAdminAndNonOwner() (gas: 25108) -CapabilitiesRegistry_AddNodesTest:test_RevertWhen_P2PIDEmpty() (gas: 27408) -CapabilitiesRegistry_AddNodesTest:test_RevertWhen_SignerAddressEmpty() (gas: 27047) -CapabilitiesRegistry_AddNodesTest:test_RevertWhen_SignerAddressNotUnique() (gas: 309679) -CapabilitiesRegistry_DeprecateCapabilitiesTest:test_DeprecatesCapability() (gas: 89807) -CapabilitiesRegistry_DeprecateCapabilitiesTest:test_EmitsEvent() (gas: 89935) -CapabilitiesRegistry_DeprecateCapabilitiesTest:test_RevertWhen_CalledByNonAdmin() (gas: 22944) -CapabilitiesRegistry_DeprecateCapabilitiesTest:test_RevertWhen_CapabilityDoesNotExist() (gas: 16231) -CapabilitiesRegistry_DeprecateCapabilitiesTest:test_RevertWhen_CapabilityIsDeprecated() (gas: 91264) -CapabilitiesRegistry_GetCapabilitiesTest:test_ReturnsCapabilities() (gas: 135553) -CapabilitiesRegistry_GetDONsTest:test_CorrectlyFetchesDONs() (gas: 65468) -CapabilitiesRegistry_GetDONsTest:test_DoesNotIncludeRemovedDONs() (gas: 64924) -CapabilitiesRegistry_GetHashedCapabilityTest:test_CorrectlyGeneratesHashedCapabilityId() (gas: 11428) -CapabilitiesRegistry_GetHashedCapabilityTest:test_DoesNotCauseIncorrectClashes() (gas: 13087) -CapabilitiesRegistry_GetNodeOperatorsTest:test_CorrectlyFetchesNodeOperators() (gas: 36407) -CapabilitiesRegistry_GetNodeOperatorsTest:test_DoesNotIncludeRemovedNodeOperators() (gas: 38692) -CapabilitiesRegistry_GetNodesTest:test_CorrectlyFetchesNodes() (gas: 65288) -CapabilitiesRegistry_GetNodesTest:test_DoesNotIncludeRemovedNodes() (gas: 73533) -CapabilitiesRegistry_RemoveDONsTest:test_RemovesDON() (gas: 54761) -CapabilitiesRegistry_RemoveDONsTest:test_RevertWhen_CalledByNonAdmin() (gas: 15647) -CapabilitiesRegistry_RemoveDONsTest:test_RevertWhen_DONDoesNotExist() (gas: 16550) -CapabilitiesRegistry_RemoveNodeOperatorsTest:test_RemovesNodeOperator() (gas: 36122) -CapabilitiesRegistry_RemoveNodeOperatorsTest:test_RevertWhen_CalledByNonOwner() (gas: 15816) -CapabilitiesRegistry_RemoveNodesTest:test_CanAddNodeWithSameSignerAddressAfterRemoving() (gas: 115151) -CapabilitiesRegistry_RemoveNodesTest:test_CanRemoveWhenDONDeleted() (gas: 287716) -CapabilitiesRegistry_RemoveNodesTest:test_CanRemoveWhenNodeNoLongerPartOfDON() (gas: 561023) -CapabilitiesRegistry_RemoveNodesTest:test_OwnerCanRemoveNodes() (gas: 73376) -CapabilitiesRegistry_RemoveNodesTest:test_RemovesNode() (gas: 75211) -CapabilitiesRegistry_RemoveNodesTest:test_RevertWhen_CalledByNonNodeOperatorAdminAndNonOwner() (gas: 25053) -CapabilitiesRegistry_RemoveNodesTest:test_RevertWhen_NodeDoesNotExist() (gas: 18418) -CapabilitiesRegistry_RemoveNodesTest:test_RevertWhen_NodePartOfCapabilitiesDON() (gas: 385369) -CapabilitiesRegistry_RemoveNodesTest:test_RevertWhen_P2PIDEmpty() (gas: 18408) -CapabilitiesRegistry_TypeAndVersionTest:test_TypeAndVersion() (gas: 9796) -CapabilitiesRegistry_UpdateDONTest:test_RevertWhen_CalledByNonAdmin() (gas: 19415) -CapabilitiesRegistry_UpdateDONTest:test_RevertWhen_CapabilityDoesNotExist() (gas: 152914) -CapabilitiesRegistry_UpdateDONTest:test_RevertWhen_DONDoesNotExist() (gas: 17835) -CapabilitiesRegistry_UpdateDONTest:test_RevertWhen_DeprecatedCapabilityAdded() (gas: 222996) -CapabilitiesRegistry_UpdateDONTest:test_RevertWhen_DuplicateCapabilityAdded() (gas: 232804) -CapabilitiesRegistry_UpdateDONTest:test_RevertWhen_DuplicateNodeAdded() (gas: 107643) -CapabilitiesRegistry_UpdateDONTest:test_RevertWhen_NodeDoesNotSupportCapability() (gas: 163357) -CapabilitiesRegistry_UpdateDONTest:test_UpdatesDON() (gas: 371909) -CapabilitiesRegistry_UpdateNodeOperatorTest:test_RevertWhen_CalledByNonAdminAndNonOwner() (gas: 20728) -CapabilitiesRegistry_UpdateNodeOperatorTest:test_RevertWhen_NodeOperatorAdminIsZeroAddress() (gas: 20052) -CapabilitiesRegistry_UpdateNodeOperatorTest:test_RevertWhen_NodeOperatorDoesNotExist() (gas: 19790) -CapabilitiesRegistry_UpdateNodeOperatorTest:test_RevertWhen_NodeOperatorIdAndParamLengthsMismatch() (gas: 15430) -CapabilitiesRegistry_UpdateNodeOperatorTest:test_UpdatesNodeOperator() (gas: 37034) -CapabilitiesRegistry_UpdateNodesTest:test_CanUpdateParamsIfNodeSignerAddressNoLongerUsed() (gas: 256371) -CapabilitiesRegistry_UpdateNodesTest:test_OwnerCanUpdateNodes() (gas: 162166) -CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_AddingNodeWithInvalidCapability() (gas: 35873) -CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_CalledByAnotherNodeOperatorAdmin() (gas: 29200) -CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_CalledByNonNodeOperatorAdminAndNonOwner() (gas: 29377) -CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_NodeDoesNotExist() (gas: 29199) -CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_NodeSignerAlreadyAssignedToAnotherNode() (gas: 31326) -CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_P2PIDEmpty() (gas: 29165) -CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_RemovingCapabilityRequiredByCapabilityDON() (gas: 470910) -CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_RemovingCapabilityRequiredByWorkflowDON() (gas: 341191) -CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_SignerAddressEmpty() (gas: 29058) -CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_UpdatingNodeWithoutCapabilities() (gas: 27587) -CapabilitiesRegistry_UpdateNodesTest:test_UpdatesNodeParams() (gas: 162220) -KeystoneForwarder_ReportTest:test_Report_ConfigVersion() (gas: 2002057) -KeystoneForwarder_ReportTest:test_Report_FailedDeliveryWhenReceiverInterfaceNotSupported() (gas: 128934) -KeystoneForwarder_ReportTest:test_Report_FailedDeliveryWhenReceiverNotContract() (gas: 130621) -KeystoneForwarder_ReportTest:test_Report_SuccessfulDelivery() (gas: 359123) -KeystoneForwarder_ReportTest:test_Report_SuccessfulRetryWithMoreGas() (gas: 423982) -KeystoneForwarder_ReportTest:test_RevertWhen_AnySignatureIsInvalid() (gas: 86348) -KeystoneForwarder_ReportTest:test_RevertWhen_AnySignerIsInvalid() (gas: 118486) -KeystoneForwarder_ReportTest:test_RevertWhen_ReportHasDuplicateSignatures() (gas: 94516) -KeystoneForwarder_ReportTest:test_RevertWhen_ReportHasIncorrectDON() (gas: 75930) -KeystoneForwarder_ReportTest:test_RevertWhen_ReportHasInexistentConfigVersion() (gas: 76320) -KeystoneForwarder_ReportTest:test_RevertWhen_ReportIsMalformed() (gas: 45585) -KeystoneForwarder_ReportTest:test_RevertWhen_RetryingInvalidContractTransmission() (gas: 143354) -KeystoneForwarder_ReportTest:test_RevertWhen_RetryingSuccessfulTransmission() (gas: 353272) -KeystoneForwarder_ReportTest:test_RevertWhen_TooFewSignatures() (gas: 55292) -KeystoneForwarder_ReportTest:test_RevertWhen_TooManySignatures() (gas: 56050) -KeystoneForwarder_SetConfigTest:test_RevertWhen_ExcessSigners() (gas: 20184) -KeystoneForwarder_SetConfigTest:test_RevertWhen_FaultToleranceIsZero() (gas: 88057) -KeystoneForwarder_SetConfigTest:test_RevertWhen_InsufficientSigners() (gas: 14533) -KeystoneForwarder_SetConfigTest:test_RevertWhen_NotOwner() (gas: 88766) -KeystoneForwarder_SetConfigTest:test_RevertWhen_ProvidingDuplicateSigners() (gas: 114570) -KeystoneForwarder_SetConfigTest:test_RevertWhen_ProvidingZeroAddressSigner() (gas: 114225) -KeystoneForwarder_SetConfigTest:test_SetConfig_FirstTime() (gas: 1540541) -KeystoneForwarder_SetConfigTest:test_SetConfig_WhenSignersAreRemoved() (gas: 1535211) -KeystoneForwarder_TypeAndVersionTest:test_TypeAndVersion() (gas: 9641) -KeystoneRouter_SetConfigTest:test_AddForwarder_RevertWhen_NotOwner() (gas: 10978) -KeystoneRouter_SetConfigTest:test_RemoveForwarder_RevertWhen_NotOwner() (gas: 10923) -KeystoneRouter_SetConfigTest:test_RemoveForwarder_Success() (gas: 17599) -KeystoneRouter_SetConfigTest:test_Route_RevertWhen_UnauthorizedForwarder() (gas: 18552) -KeystoneRouter_SetConfigTest:test_Route_Success() (gas: 76407) \ No newline at end of file +ArbitrumCrossDomainForwarder_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 37568) +ArbitrumCrossDomainForwarder_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 12963) +ArbitrumCrossDomainForwarder_Constructor:test_InitialState() (gas: 22163) +ArbitrumCrossDomainForwarder_Forward:test_Forward() (gas: 47867) +ArbitrumCrossDomainForwarder_Forward:test_ForwardRevert() (gas: 22181) +ArbitrumCrossDomainForwarder_Forward:test_NotCallableByUnknownAddress() (gas: 16056) +ArbitrumCrossDomainForwarder_TransferL1Ownership:test_CallableByL1Owner() (gas: 41453) +ArbitrumCrossDomainForwarder_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 19290) +ArbitrumCrossDomainForwarder_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 18637) +ArbitrumCrossDomainForwarder_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 13242) +ArbitrumCrossDomainGovernor_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 37568) +ArbitrumCrossDomainGovernor_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 12963) +ArbitrumCrossDomainGovernor_Constructor:test_InitialState() (gas: 22186) +ArbitrumCrossDomainGovernor_Forward:test_CallableByL2Owner() (gas: 50003) +ArbitrumCrossDomainGovernor_Forward:test_Forward() (gas: 47896) +ArbitrumCrossDomainGovernor_Forward:test_ForwardRevert() (gas: 24326) +ArbitrumCrossDomainGovernor_Forward:test_NotCallableByUnknownAddress() (gas: 18233) +ArbitrumCrossDomainGovernor_ForwardDelegate:test_BubbleUpRevert() (gas: 19386) +ArbitrumCrossDomainGovernor_ForwardDelegate:test_CallableByCrossDomainMessengerAddressOrL1Owner() (gas: 60874) +ArbitrumCrossDomainGovernor_ForwardDelegate:test_CallableByL2Owner() (gas: 63003) +ArbitrumCrossDomainGovernor_ForwardDelegate:test_NotCallableByUnknownAddress() (gas: 18245) +ArbitrumCrossDomainGovernor_ForwardDelegate:test_RevertsBatchWhenOneCallFails() (gas: 64368) +ArbitrumCrossDomainGovernor_TransferL1Ownership:test_CallableByL1Owner() (gas: 41453) +ArbitrumCrossDomainGovernor_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 19290) +ArbitrumCrossDomainGovernor_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 18637) +ArbitrumCrossDomainGovernor_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 13242) +ArbitrumSequencerUptimeFeed_AggregatorV3Interface:test_AggregatorV3Interface() (gas: 104862) +ArbitrumSequencerUptimeFeed_AggregatorV3Interface:test_Return0WhenRoundDoesNotExistYet() (gas: 19967) +ArbitrumSequencerUptimeFeed_Constants:test_InitialState() (gas: 8518) +ArbitrumSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceAllowReadsIfConsumingContractIsWhitelisted() (gas: 604370) +ArbitrumSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceDisallowReadsIfConsumingContractIsNotWhitelisted() (gas: 574432) +ArbitrumSequencerUptimeFeed_UpdateStatus:test_IgnoreOutOfOrderUpdates() (gas: 99629) +ArbitrumSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddr() (gas: 15447) +ArbitrumSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndNoTimeChange() (gas: 114625) +ArbitrumSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndTimeChange() (gas: 114708) +ArbitrumValidator_Validate:test_PostSequencerOffline() (gas: 69086) +OptimismCrossDomainForwarder_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 47160) +OptimismCrossDomainForwarder_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 22160) +OptimismCrossDomainForwarder_Constructor:test_InitialState() (gas: 21998) +OptimismCrossDomainForwarder_Forward:test_Forward() (gas: 58281) +OptimismCrossDomainForwarder_Forward:test_ForwardRevert() (gas: 32560) +OptimismCrossDomainForwarder_Forward:test_NotCallableByUnknownAddress() (gas: 13867) +OptimismCrossDomainForwarder_TransferL1Ownership:test_CallableByL1Owner() (gas: 48933) +OptimismCrossDomainForwarder_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 28753) +OptimismCrossDomainForwarder_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 16448) +OptimismCrossDomainForwarder_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 11053) +OptimismCrossDomainGovernor_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 47160) +OptimismCrossDomainGovernor_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 22160) +OptimismCrossDomainGovernor_Constructor:test_InitialState() (gas: 22021) +OptimismCrossDomainGovernor_Forward:test_CallableByL2Owner() (gas: 47846) +OptimismCrossDomainGovernor_Forward:test_Forward() (gas: 58330) +OptimismCrossDomainGovernor_Forward:test_ForwardRevert() (gas: 32619) +OptimismCrossDomainGovernor_Forward:test_NotCallableByUnknownAddress() (gas: 16047) +OptimismCrossDomainGovernor_ForwardDelegate:test_BubbleUpRevert() (gas: 29189) +OptimismCrossDomainGovernor_ForwardDelegate:test_CallableByCrossDomainMessengerAddressOrL1Owner() (gas: 72942) +OptimismCrossDomainGovernor_ForwardDelegate:test_CallableByL2Owner() (gas: 72947) +OptimismCrossDomainGovernor_ForwardDelegate:test_NotCallableByUnknownAddress() (gas: 16059) +OptimismCrossDomainGovernor_ForwardDelegate:test_RevertsBatchWhenOneCallFails() (gas: 76156) +OptimismCrossDomainGovernor_TransferL1Ownership:test_CallableByL1Owner() (gas: 48933) +OptimismCrossDomainGovernor_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 28753) +OptimismCrossDomainGovernor_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 16448) +OptimismCrossDomainGovernor_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 11053) +OptimismSequencerUptimeFeed_AggregatorV3Interface:test_AggregatorV3Interface() (gas: 72400) +OptimismSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetAnswerWhenRoundDoesNotExistYet() (gas: 17653) +OptimismSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetRoundDataWhenRoundDoesNotExistYet() (gas: 17893) +OptimismSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetTimestampWhenRoundDoesNotExistYet() (gas: 17642) +OptimismSequencerUptimeFeed_Constructor:test_InitialState() (gas: 22050) +OptimismSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceAllowReadsIfConsumingContractIsWhitelisted() (gas: 601594) +OptimismSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceDisallowReadsIfConsumingContractIsNotWhitelisted() (gas: 574437) +OptimismSequencerUptimeFeed_UpdateStatus:test_IgnoreOutOfOrderUpdates() (gas: 67873) +OptimismSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddr() (gas: 13079) +OptimismSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddrAndNotL1SenderAddr() (gas: 23542) +OptimismSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenNoChange() (gas: 77322) +OptimismSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndNoTimeChange() (gas: 96182) +OptimismSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndTimeChange() (gas: 96265) +OptimismValidator_SetGasLimit:test_CorrectlyUpdatesTheGasLimit() (gas: 18671) +OptimismValidator_Validate:test_PostSequencerOffline() (gas: 74790) +OptimismValidator_Validate:test_PostSequencerStatusWhenThereIsNotStatusChange() (gas: 74869) +OptimismValidator_Validate:test_RevertsIfCalledByAnAccountWithNoAccess() (gas: 15571) +ScrollCrossDomainForwarder_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 47255) +ScrollCrossDomainForwarder_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 22212) +ScrollCrossDomainForwarder_Constructor:test_InitialState() (gas: 21674) +ScrollCrossDomainForwarder_Forward:test_Forward() (gas: 58348) +ScrollCrossDomainForwarder_Forward:test_ForwardRevert() (gas: 32618) +ScrollCrossDomainForwarder_Forward:test_NotCallableByUnknownAddress() (gas: 13867) +ScrollCrossDomainForwarder_TransferL1Ownership:test_CallableByL1Owner() (gas: 48999) +ScrollCrossDomainForwarder_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 28819) +ScrollCrossDomainForwarder_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 16448) +ScrollCrossDomainForwarder_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 11053) +ScrollCrossDomainGovernor_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 47255) +ScrollCrossDomainGovernor_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 22212) +ScrollCrossDomainGovernor_Constructor:test_InitialState() (gas: 21697) +ScrollCrossDomainGovernor_Forward:test_CallableByL2Owner() (gas: 47841) +ScrollCrossDomainGovernor_Forward:test_Forward() (gas: 58392) +ScrollCrossDomainGovernor_Forward:test_ForwardRevert() (gas: 32674) +ScrollCrossDomainGovernor_Forward:test_NotCallableByUnknownAddress() (gas: 16044) +ScrollCrossDomainGovernor_ForwardDelegate:test_BubbleUpRevert() (gas: 29250) +ScrollCrossDomainGovernor_ForwardDelegate:test_CallableByCrossDomainMessengerAddressOrL1Owner() (gas: 73009) +ScrollCrossDomainGovernor_ForwardDelegate:test_CallableByL2Owner() (gas: 73014) +ScrollCrossDomainGovernor_ForwardDelegate:test_NotCallableByUnknownAddress() (gas: 16056) +ScrollCrossDomainGovernor_ForwardDelegate:test_RevertsBatchWhenOneCallFails() (gas: 76224) +ScrollCrossDomainGovernor_TransferL1Ownership:test_CallableByL1Owner() (gas: 48999) +ScrollCrossDomainGovernor_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 28819) +ScrollCrossDomainGovernor_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 16448) +ScrollCrossDomainGovernor_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 11053) +ScrollSequencerUptimeFeed_AggregatorV3Interface:test_AggregatorV3Interface() (gas: 72423) +ScrollSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetAnswerWhenRoundDoesNotExistYet() (gas: 17653) +ScrollSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetRoundDataWhenRoundDoesNotExistYet() (gas: 17893) +ScrollSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetTimestampWhenRoundDoesNotExistYet() (gas: 17642) +ScrollSequencerUptimeFeed_Constructor:test_InitialState() (gas: 173935) +ScrollSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceAllowReadsIfConsumingContractIsWhitelisted() (gas: 601594) +ScrollSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceDisallowReadsIfConsumingContractIsNotWhitelisted() (gas: 574437) +ScrollSequencerUptimeFeed_UpdateStatus:test_IgnoreOutOfOrderUpdates() (gas: 67919) +ScrollSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddr() (gas: 13079) +ScrollSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddrAndNotL1SenderAddr() (gas: 23542) +ScrollSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenNoChange() (gas: 77368) +ScrollSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndNoTimeChange() (gas: 96228) +ScrollSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndTimeChange() (gas: 96311) +ScrollValidator_SetGasLimit:test_CorrectlyUpdatesTheGasLimit() (gas: 18805) +ScrollValidator_Validate:test_PostSequencerOffline() (gas: 78326) +ScrollValidator_Validate:test_PostSequencerStatusWhenThereIsNotStatusChange() (gas: 78411) +ScrollValidator_Validate:test_RevertsIfCalledByAnAccountWithNoAccess() (gas: 15571) +ZKSyncSequencerUptimeFeed_AggregatorV3Interface:test_AggregatorV3Interface() (gas: 67166) +ZKSyncSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetAnswerWhenRoundDoesNotExistYet() (gas: 17653) +ZKSyncSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetRoundDataWhenRoundDoesNotExistYet() (gas: 17893) +ZKSyncSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetTimestampWhenRoundDoesNotExistYet() (gas: 17642) +ZKSyncSequencerUptimeFeed_Constructor:test_InitialState() (gas: 22054) +ZKSyncSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceAllowReadsIfConsumingContractIsWhitelisted() (gas: 601614) +ZKSyncSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceDisallowReadsIfConsumingContractIsNotWhitelisted() (gas: 574443) +ZKSyncSequencerUptimeFeed_UpdateStatus:test_IgnoreOutOfOrderUpdates() (gas: 61924) +ZKSyncSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddr() (gas: 13035) +ZKSyncSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenNoChange() (gas: 71379) +ZKSyncSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndNoTimeChange() (gas: 90241) +ZKSyncSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndTimeChange() (gas: 90324) +ZKSyncValidator_Constructor:test_ConstructingRevertedWithInvalidChainId() (gas: 103725) +ZKSyncValidator_Constructor:test_ConstructingRevertedWithZeroL1BridgeAddress() (gas: 81440) +ZKSyncValidator_Constructor:test_ConstructingRevertedWithZeroL2UpdateFeedAddress() (gas: 81497) +ZKSyncValidator_GetChainId:test_CorrectlyGetsTheChainId() (gas: 8350) +ZKSyncValidator_GetSetL2GasPerPubdataByteLimit:test_CorrectlyGetsAndUpdatesTheGasPerPubdataByteLimit() (gas: 18915) +ZKSyncValidator_Validate:test_PostSequencerOffline() (gas: 52255) +ZKSyncValidator_Validate:test_PostSequencerStatusWhenThereIsNotStatusChange() (gas: 52355) +ZKSyncValidator_Validate:test_RevertsIfCalledByAnAccountWithNoAccess() (gas: 15644) \ No newline at end of file diff --git a/contracts/foundry.toml b/contracts/foundry.toml index c755ba6437b..cab8b05ba92 100644 --- a/contracts/foundry.toml +++ b/contracts/foundry.toml @@ -54,10 +54,10 @@ src = 'src/v0.8/automation' test = 'src/v0.8/automation/test' [profile.l2ep] +solc_version = '0.8.24' optimizer_runs = 1_000_000 src = 'src/v0.8/l2ep' test = 'src/v0.8/l2ep/test' -solc_version = '0.8.19' [profile.llo-feeds] optimizer_runs = 1_000_000 diff --git a/contracts/gas-snapshots/l2ep.gas-snapshot b/contracts/gas-snapshots/l2ep.gas-snapshot index 42a9aa0b35a..e793f8ce549 100644 --- a/contracts/gas-snapshots/l2ep.gas-snapshot +++ b/contracts/gas-snapshots/l2ep.gas-snapshot @@ -1,122 +1,142 @@ -ArbitrumCrossDomainForwarder_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 37613) +ArbitrumCrossDomainForwarder_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 37568) ArbitrumCrossDomainForwarder_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 12963) -ArbitrumCrossDomainForwarder_Constructor:test_InitialState() (gas: 22196) +ArbitrumCrossDomainForwarder_Constructor:test_InitialState() (gas: 22163) ArbitrumCrossDomainForwarder_Forward:test_Forward() (gas: 47867) ArbitrumCrossDomainForwarder_Forward:test_ForwardRevert() (gas: 22181) ArbitrumCrossDomainForwarder_Forward:test_NotCallableByUnknownAddress() (gas: 16056) -ArbitrumCrossDomainForwarder_TransferL1Ownership:test_CallableByL1Owner() (gas: 41430) -ArbitrumCrossDomainForwarder_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 19312) -ArbitrumCrossDomainForwarder_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 18671) -ArbitrumCrossDomainForwarder_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 13219) -ArbitrumCrossDomainGovernor_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 37613) +ArbitrumCrossDomainForwarder_TransferL1Ownership:test_CallableByL1Owner() (gas: 41453) +ArbitrumCrossDomainForwarder_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 19290) +ArbitrumCrossDomainForwarder_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 18637) +ArbitrumCrossDomainForwarder_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 13242) +ArbitrumCrossDomainGovernor_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 37568) ArbitrumCrossDomainGovernor_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 12963) -ArbitrumCrossDomainGovernor_Constructor:test_InitialState() (gas: 22219) -ArbitrumCrossDomainGovernor_Forward:test_CallableByL2Owner() (gas: 49980) -ArbitrumCrossDomainGovernor_Forward:test_Forward() (gas: 47918) -ArbitrumCrossDomainGovernor_Forward:test_ForwardRevert() (gas: 24348) -ArbitrumCrossDomainGovernor_Forward:test_NotCallableByUnknownAddress() (gas: 18255) +ArbitrumCrossDomainGovernor_Constructor:test_InitialState() (gas: 22186) +ArbitrumCrossDomainGovernor_Forward:test_CallableByL2Owner() (gas: 50003) +ArbitrumCrossDomainGovernor_Forward:test_Forward() (gas: 47896) +ArbitrumCrossDomainGovernor_Forward:test_ForwardRevert() (gas: 24326) +ArbitrumCrossDomainGovernor_Forward:test_NotCallableByUnknownAddress() (gas: 18233) ArbitrumCrossDomainGovernor_ForwardDelegate:test_BubbleUpRevert() (gas: 19386) ArbitrumCrossDomainGovernor_ForwardDelegate:test_CallableByCrossDomainMessengerAddressOrL1Owner() (gas: 60874) -ArbitrumCrossDomainGovernor_ForwardDelegate:test_CallableByL2Owner() (gas: 62980) +ArbitrumCrossDomainGovernor_ForwardDelegate:test_CallableByL2Owner() (gas: 63003) ArbitrumCrossDomainGovernor_ForwardDelegate:test_NotCallableByUnknownAddress() (gas: 18245) -ArbitrumCrossDomainGovernor_ForwardDelegate:test_RevertsBatchWhenOneCallFails() (gas: 64379) -ArbitrumCrossDomainGovernor_TransferL1Ownership:test_CallableByL1Owner() (gas: 41430) -ArbitrumCrossDomainGovernor_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 19312) -ArbitrumCrossDomainGovernor_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 18671) -ArbitrumCrossDomainGovernor_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 13219) -ArbitrumSequencerUptimeFeed_AggregatorV3Interface:test_AggregatorV3Interface() (gas: 104994) -ArbitrumSequencerUptimeFeed_AggregatorV3Interface:test_Return0WhenRoundDoesNotExistYet() (gas: 20033) -ArbitrumSequencerUptimeFeed_Constants:test_InitialState() (gas: 8530) -ArbitrumSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceAllowReadsIfConsumingContractIsWhitelisted() (gas: 604414) -ArbitrumSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceDisallowReadsIfConsumingContractIsNotWhitelisted() (gas: 574476) -ArbitrumSequencerUptimeFeed_UpdateStatus:test_IgnoreOutOfOrderUpdates() (gas: 99662) -ArbitrumSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddr() (gas: 15424) -ArbitrumSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndNoTimeChange() (gas: 114647) -ArbitrumSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndTimeChange() (gas: 114707) +ArbitrumCrossDomainGovernor_ForwardDelegate:test_RevertsBatchWhenOneCallFails() (gas: 64368) +ArbitrumCrossDomainGovernor_TransferL1Ownership:test_CallableByL1Owner() (gas: 41453) +ArbitrumCrossDomainGovernor_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 19290) +ArbitrumCrossDomainGovernor_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 18637) +ArbitrumCrossDomainGovernor_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 13242) +ArbitrumSequencerUptimeFeed_AggregatorV3Interface:test_AggregatorV3Interface() (gas: 104862) +ArbitrumSequencerUptimeFeed_AggregatorV3Interface:test_Return0WhenRoundDoesNotExistYet() (gas: 19967) +ArbitrumSequencerUptimeFeed_Constants:test_InitialState() (gas: 8518) +ArbitrumSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceAllowReadsIfConsumingContractIsWhitelisted() (gas: 604370) +ArbitrumSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceDisallowReadsIfConsumingContractIsNotWhitelisted() (gas: 574432) +ArbitrumSequencerUptimeFeed_UpdateStatus:test_IgnoreOutOfOrderUpdates() (gas: 99629) +ArbitrumSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddr() (gas: 15447) +ArbitrumSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndNoTimeChange() (gas: 114625) +ArbitrumSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndTimeChange() (gas: 114708) ArbitrumValidator_Validate:test_PostSequencerOffline() (gas: 69086) -OptimismCrossDomainForwarder_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 47206) +OptimismCrossDomainForwarder_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 47160) OptimismCrossDomainForwarder_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 22160) -OptimismCrossDomainForwarder_Constructor:test_InitialState() (gas: 22031) +OptimismCrossDomainForwarder_Constructor:test_InitialState() (gas: 21998) OptimismCrossDomainForwarder_Forward:test_Forward() (gas: 58281) OptimismCrossDomainForwarder_Forward:test_ForwardRevert() (gas: 32560) OptimismCrossDomainForwarder_Forward:test_NotCallableByUnknownAddress() (gas: 13867) -OptimismCrossDomainForwarder_TransferL1Ownership:test_CallableByL1Owner() (gas: 48910) -OptimismCrossDomainForwarder_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 28775) -OptimismCrossDomainForwarder_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 16482) -OptimismCrossDomainForwarder_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 11030) -OptimismCrossDomainGovernor_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 47206) +OptimismCrossDomainForwarder_TransferL1Ownership:test_CallableByL1Owner() (gas: 48933) +OptimismCrossDomainForwarder_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 28753) +OptimismCrossDomainForwarder_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 16448) +OptimismCrossDomainForwarder_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 11053) +OptimismCrossDomainGovernor_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 47160) OptimismCrossDomainGovernor_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 22160) -OptimismCrossDomainGovernor_Constructor:test_InitialState() (gas: 22054) -OptimismCrossDomainGovernor_Forward:test_CallableByL2Owner() (gas: 47823) -OptimismCrossDomainGovernor_Forward:test_Forward() (gas: 58352) -OptimismCrossDomainGovernor_Forward:test_ForwardRevert() (gas: 32641) -OptimismCrossDomainGovernor_Forward:test_NotCallableByUnknownAddress() (gas: 16069) +OptimismCrossDomainGovernor_Constructor:test_InitialState() (gas: 22021) +OptimismCrossDomainGovernor_Forward:test_CallableByL2Owner() (gas: 47846) +OptimismCrossDomainGovernor_Forward:test_Forward() (gas: 58330) +OptimismCrossDomainGovernor_Forward:test_ForwardRevert() (gas: 32619) +OptimismCrossDomainGovernor_Forward:test_NotCallableByUnknownAddress() (gas: 16047) OptimismCrossDomainGovernor_ForwardDelegate:test_BubbleUpRevert() (gas: 29189) OptimismCrossDomainGovernor_ForwardDelegate:test_CallableByCrossDomainMessengerAddressOrL1Owner() (gas: 72942) -OptimismCrossDomainGovernor_ForwardDelegate:test_CallableByL2Owner() (gas: 72924) +OptimismCrossDomainGovernor_ForwardDelegate:test_CallableByL2Owner() (gas: 72947) OptimismCrossDomainGovernor_ForwardDelegate:test_NotCallableByUnknownAddress() (gas: 16059) -OptimismCrossDomainGovernor_ForwardDelegate:test_RevertsBatchWhenOneCallFails() (gas: 76167) -OptimismCrossDomainGovernor_TransferL1Ownership:test_CallableByL1Owner() (gas: 48910) -OptimismCrossDomainGovernor_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 28775) -OptimismCrossDomainGovernor_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 16482) -OptimismCrossDomainGovernor_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 11030) -OptimismSequencerUptimeFeed_AggregatorV3Interface:test_AggregatorV3Interface() (gas: 74304) -OptimismSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetAnswerWhenRoundDoesNotExistYet() (gas: 17679) -OptimismSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetRoundDataWhenRoundDoesNotExistYet() (gas: 17897) -OptimismSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetTimestampWhenRoundDoesNotExistYet() (gas: 17603) -OptimismSequencerUptimeFeed_Constructor:test_InitialState() (gas: 22110) -OptimismSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceAllowReadsIfConsumingContractIsWhitelisted() (gas: 601843) -OptimismSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceDisallowReadsIfConsumingContractIsNotWhitelisted() (gas: 574481) -OptimismSequencerUptimeFeed_UpdateStatus:test_IgnoreOutOfOrderUpdates() (gas: 69730) -OptimismSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddr() (gas: 13214) -OptimismSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddrAndNotL1SenderAddr() (gas: 23632) -OptimismSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenNoChange() (gas: 79637) -OptimismSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndNoTimeChange() (gas: 100045) -OptimismSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndTimeChange() (gas: 100105) -OptimismValidator_SetGasLimit:test_CorrectlyUpdatesTheGasLimit() (gas: 18695) -OptimismValidator_Validate:test_PostSequencerOffline() (gas: 74813) +OptimismCrossDomainGovernor_ForwardDelegate:test_RevertsBatchWhenOneCallFails() (gas: 76156) +OptimismCrossDomainGovernor_TransferL1Ownership:test_CallableByL1Owner() (gas: 48933) +OptimismCrossDomainGovernor_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 28753) +OptimismCrossDomainGovernor_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 16448) +OptimismCrossDomainGovernor_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 11053) +OptimismSequencerUptimeFeed_AggregatorV3Interface:test_AggregatorV3Interface() (gas: 72400) +OptimismSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetAnswerWhenRoundDoesNotExistYet() (gas: 17653) +OptimismSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetRoundDataWhenRoundDoesNotExistYet() (gas: 17893) +OptimismSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetTimestampWhenRoundDoesNotExistYet() (gas: 17642) +OptimismSequencerUptimeFeed_Constructor:test_InitialState() (gas: 22050) +OptimismSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceAllowReadsIfConsumingContractIsWhitelisted() (gas: 601594) +OptimismSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceDisallowReadsIfConsumingContractIsNotWhitelisted() (gas: 574437) +OptimismSequencerUptimeFeed_UpdateStatus:test_IgnoreOutOfOrderUpdates() (gas: 67873) +OptimismSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddr() (gas: 13079) +OptimismSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddrAndNotL1SenderAddr() (gas: 23542) +OptimismSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenNoChange() (gas: 77322) +OptimismSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndNoTimeChange() (gas: 96182) +OptimismSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndTimeChange() (gas: 96265) +OptimismValidator_SetGasLimit:test_CorrectlyUpdatesTheGasLimit() (gas: 18671) +OptimismValidator_Validate:test_PostSequencerOffline() (gas: 74790) OptimismValidator_Validate:test_PostSequencerStatusWhenThereIsNotStatusChange() (gas: 74869) OptimismValidator_Validate:test_RevertsIfCalledByAnAccountWithNoAccess() (gas: 15571) -ScrollCrossDomainForwarder_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 47300) +ScrollCrossDomainForwarder_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 47255) ScrollCrossDomainForwarder_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 22212) -ScrollCrossDomainForwarder_Constructor:test_InitialState() (gas: 21707) +ScrollCrossDomainForwarder_Constructor:test_InitialState() (gas: 21674) ScrollCrossDomainForwarder_Forward:test_Forward() (gas: 58348) ScrollCrossDomainForwarder_Forward:test_ForwardRevert() (gas: 32618) ScrollCrossDomainForwarder_Forward:test_NotCallableByUnknownAddress() (gas: 13867) -ScrollCrossDomainForwarder_TransferL1Ownership:test_CallableByL1Owner() (gas: 48976) -ScrollCrossDomainForwarder_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 28841) -ScrollCrossDomainForwarder_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 16482) -ScrollCrossDomainForwarder_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 11030) -ScrollCrossDomainGovernor_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 47300) +ScrollCrossDomainForwarder_TransferL1Ownership:test_CallableByL1Owner() (gas: 48999) +ScrollCrossDomainForwarder_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 28819) +ScrollCrossDomainForwarder_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 16448) +ScrollCrossDomainForwarder_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 11053) +ScrollCrossDomainGovernor_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 47255) ScrollCrossDomainGovernor_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 22212) -ScrollCrossDomainGovernor_Constructor:test_InitialState() (gas: 21730) -ScrollCrossDomainGovernor_Forward:test_CallableByL2Owner() (gas: 47818) -ScrollCrossDomainGovernor_Forward:test_Forward() (gas: 58414) -ScrollCrossDomainGovernor_Forward:test_ForwardRevert() (gas: 32696) -ScrollCrossDomainGovernor_Forward:test_NotCallableByUnknownAddress() (gas: 16066) +ScrollCrossDomainGovernor_Constructor:test_InitialState() (gas: 21697) +ScrollCrossDomainGovernor_Forward:test_CallableByL2Owner() (gas: 47841) +ScrollCrossDomainGovernor_Forward:test_Forward() (gas: 58392) +ScrollCrossDomainGovernor_Forward:test_ForwardRevert() (gas: 32674) +ScrollCrossDomainGovernor_Forward:test_NotCallableByUnknownAddress() (gas: 16044) ScrollCrossDomainGovernor_ForwardDelegate:test_BubbleUpRevert() (gas: 29250) ScrollCrossDomainGovernor_ForwardDelegate:test_CallableByCrossDomainMessengerAddressOrL1Owner() (gas: 73009) -ScrollCrossDomainGovernor_ForwardDelegate:test_CallableByL2Owner() (gas: 72991) +ScrollCrossDomainGovernor_ForwardDelegate:test_CallableByL2Owner() (gas: 73014) ScrollCrossDomainGovernor_ForwardDelegate:test_NotCallableByUnknownAddress() (gas: 16056) -ScrollCrossDomainGovernor_ForwardDelegate:test_RevertsBatchWhenOneCallFails() (gas: 76235) -ScrollCrossDomainGovernor_TransferL1Ownership:test_CallableByL1Owner() (gas: 48976) -ScrollCrossDomainGovernor_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 28841) -ScrollCrossDomainGovernor_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 16482) -ScrollCrossDomainGovernor_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 11030) -ScrollSequencerUptimeFeed_AggregatorV3Interface:test_AggregatorV3Interface() (gas: 72590) -ScrollSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetAnswerWhenRoundDoesNotExistYet() (gas: 17675) +ScrollCrossDomainGovernor_ForwardDelegate:test_RevertsBatchWhenOneCallFails() (gas: 76224) +ScrollCrossDomainGovernor_TransferL1Ownership:test_CallableByL1Owner() (gas: 48999) +ScrollCrossDomainGovernor_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 28819) +ScrollCrossDomainGovernor_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 16448) +ScrollCrossDomainGovernor_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 11053) +ScrollSequencerUptimeFeed_AggregatorV3Interface:test_AggregatorV3Interface() (gas: 72423) +ScrollSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetAnswerWhenRoundDoesNotExistYet() (gas: 17653) ScrollSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetRoundDataWhenRoundDoesNotExistYet() (gas: 17893) -ScrollSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetTimestampWhenRoundDoesNotExistYet() (gas: 17599) -ScrollSequencerUptimeFeed_Constructor:test_InitialState() (gas: 103508) -ScrollSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceAllowReadsIfConsumingContractIsWhitelisted() (gas: 601694) -ScrollSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceDisallowReadsIfConsumingContractIsNotWhitelisted() (gas: 574481) -ScrollSequencerUptimeFeed_UpdateStatus:test_IgnoreOutOfOrderUpdates() (gas: 67615) -ScrollSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddr() (gas: 13214) -ScrollSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddrAndNotL1SenderAddr() (gas: 23632) -ScrollSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenNoChange() (gas: 77220) -ScrollSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndNoTimeChange() (gas: 95908) -ScrollSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndTimeChange() (gas: 95968) -ScrollValidator_SetGasLimit:test_CorrectlyUpdatesTheGasLimit() (gas: 18829) -ScrollValidator_Validate:test_PostSequencerOffline() (gas: 78349) +ScrollSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetTimestampWhenRoundDoesNotExistYet() (gas: 17642) +ScrollSequencerUptimeFeed_Constructor:test_InitialState() (gas: 173935) +ScrollSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceAllowReadsIfConsumingContractIsWhitelisted() (gas: 601594) +ScrollSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceDisallowReadsIfConsumingContractIsNotWhitelisted() (gas: 574437) +ScrollSequencerUptimeFeed_UpdateStatus:test_IgnoreOutOfOrderUpdates() (gas: 67919) +ScrollSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddr() (gas: 13079) +ScrollSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddrAndNotL1SenderAddr() (gas: 23542) +ScrollSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenNoChange() (gas: 77368) +ScrollSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndNoTimeChange() (gas: 96228) +ScrollSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndTimeChange() (gas: 96311) +ScrollValidator_SetGasLimit:test_CorrectlyUpdatesTheGasLimit() (gas: 18805) +ScrollValidator_Validate:test_PostSequencerOffline() (gas: 78326) ScrollValidator_Validate:test_PostSequencerStatusWhenThereIsNotStatusChange() (gas: 78411) -ScrollValidator_Validate:test_RevertsIfCalledByAnAccountWithNoAccess() (gas: 15571) \ No newline at end of file +ScrollValidator_Validate:test_RevertsIfCalledByAnAccountWithNoAccess() (gas: 15571) +ZKSyncSequencerUptimeFeed_AggregatorV3Interface:test_AggregatorV3Interface() (gas: 67166) +ZKSyncSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetAnswerWhenRoundDoesNotExistYet() (gas: 17653) +ZKSyncSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetRoundDataWhenRoundDoesNotExistYet() (gas: 17893) +ZKSyncSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetTimestampWhenRoundDoesNotExistYet() (gas: 17642) +ZKSyncSequencerUptimeFeed_Constructor:test_InitialState() (gas: 22054) +ZKSyncSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceAllowReadsIfConsumingContractIsWhitelisted() (gas: 601614) +ZKSyncSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceDisallowReadsIfConsumingContractIsNotWhitelisted() (gas: 574443) +ZKSyncSequencerUptimeFeed_UpdateStatus:test_IgnoreOutOfOrderUpdates() (gas: 61924) +ZKSyncSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddr() (gas: 13035) +ZKSyncSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenNoChange() (gas: 71379) +ZKSyncSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndNoTimeChange() (gas: 90241) +ZKSyncSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndTimeChange() (gas: 90324) +ZKSyncValidator_Constructor:test_ConstructingRevertedWithInvalidChainId() (gas: 103725) +ZKSyncValidator_Constructor:test_ConstructingRevertedWithZeroL1BridgeAddress() (gas: 81440) +ZKSyncValidator_Constructor:test_ConstructingRevertedWithZeroL2UpdateFeedAddress() (gas: 81497) +ZKSyncValidator_GetChainId:test_CorrectlyGetsTheChainId() (gas: 8350) +ZKSyncValidator_GetSetL2GasPerPubdataByteLimit:test_CorrectlyGetsAndUpdatesTheGasPerPubdataByteLimit() (gas: 18915) +ZKSyncValidator_Validate:test_PostSequencerOffline() (gas: 52255) +ZKSyncValidator_Validate:test_PostSequencerStatusWhenThereIsNotStatusChange() (gas: 52355) +ZKSyncValidator_Validate:test_RevertsIfCalledByAnAccountWithNoAccess() (gas: 15644) \ No newline at end of file diff --git a/contracts/package.json b/contracts/package.json index 26fbd885705..ea700c87d49 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -86,6 +86,7 @@ "@openzeppelin/contracts": "4.9.3", "@openzeppelin/contracts-upgradeable": "4.9.3", "@scroll-tech/contracts": "0.1.0", + "@zksync/contracts": "git+https://github.com/matter-labs/era-contracts.git#446d391d34bdb48255d5f8fef8a8248925fc98b9", "semver": "^7.6.3" } } diff --git a/contracts/pnpm-lock.yaml b/contracts/pnpm-lock.yaml index 5c45da8ab0a..237b334fc4b 100644 --- a/contracts/pnpm-lock.yaml +++ b/contracts/pnpm-lock.yaml @@ -35,6 +35,9 @@ importers: '@scroll-tech/contracts': specifier: 0.1.0 version: 0.1.0 + '@zksync/contracts': + specifier: git+https://github.com/matter-labs/era-contracts.git#446d391d34bdb48255d5f8fef8a8248925fc98b9 + version: era-contracts@https://codeload.github.com/matter-labs/era-contracts/tar.gz/446d391d34bdb48255d5f8fef8a8248925fc98b9 semver: specifier: ^7.6.3 version: 7.6.3 @@ -1380,6 +1383,10 @@ packages: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} + era-contracts@https://codeload.github.com/matter-labs/era-contracts/tar.gz/446d391d34bdb48255d5f8fef8a8248925fc98b9: + resolution: {tarball: https://codeload.github.com/matter-labs/era-contracts/tar.gz/446d391d34bdb48255d5f8fef8a8248925fc98b9} + version: 0.1.0 + error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} @@ -4961,6 +4968,8 @@ snapshots: env-paths@2.2.1: {} + era-contracts@https://codeload.github.com/matter-labs/era-contracts/tar.gz/446d391d34bdb48255d5f8fef8a8248925fc98b9: {} + error-ex@1.3.2: dependencies: is-arrayish: 0.2.1 diff --git a/contracts/remappings.txt b/contracts/remappings.txt index ec64b1b2118..4ed0fcfd9a2 100644 --- a/contracts/remappings.txt +++ b/contracts/remappings.txt @@ -5,3 +5,4 @@ forge-std/=src/v0.8/vendor/forge-std/src/ hardhat/=node_modules/hardhat/ @eth-optimism/=node_modules/@eth-optimism/ @scroll-tech/=node_modules/@scroll-tech/ +@zksync/=node_modules/@zksync/ diff --git a/contracts/scripts/native_solc_compile_all_l2ep b/contracts/scripts/native_solc_compile_all_l2ep index 1b9f5fb611d..1f671158068 100755 --- a/contracts/scripts/native_solc_compile_all_l2ep +++ b/contracts/scripts/native_solc_compile_all_l2ep @@ -1,59 +1,38 @@ #!/usr/bin/env bash -########### -# Logging # -########### - set -e echo " ┌──────────────────────────────────────────────┐" echo " │ Compiling L2EP contracts... │" echo " └──────────────────────────────────────────────┘" -###################### -# Helper Variable(s) # -###################### - -export SOLC_VERSION="0.8.19" +SOLC_VERSION="0.8.24" +OPTIMIZE_RUNS=1000000 -SCRIPTPATH="$( - cd "$(dirname "$0")" >/dev/null 2>&1 - pwd -P -)" +SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" +python3 -m pip install --require-hashes -r $SCRIPTPATH/requirements.txt +solc-select install $SOLC_VERSION +solc-select use $SOLC_VERSION ROOT="$( cd "$(dirname "$0")" >/dev/null 2>&1 cd ../ && pwd -P )" -###################### -# Helper Function(s) # -###################### - compileContract() { - local optimize_runs=1000000 local version="$1" local srcpath="$2" solc \ @openzeppelin/=$ROOT/node_modules/@openzeppelin/ \ @eth-optimism/=$ROOT/node_modules/@eth-optimism/ \ @scroll-tech/=$ROOT/node_modules/@scroll-tech/ \ - --overwrite --optimize --optimize-runs $optimize_runs --metadata-hash none \ + --overwrite --optimize --optimize-runs $OPTIMIZE_RUNS --metadata-hash none \ -o $ROOT/solc/v$SOLC_VERSION/l2ep/"$version" \ - --abi --bin \ - --allow-paths $ROOT/src/v0.8,$ROOT/node_modules \ + --abi --bin --allow-paths $ROOT/src/v0.8,$ROOT/node_modules \ + --evm-version paris \ $ROOT/src/v0.8/l2ep/"$srcpath" } -################# -# Version 1.0.0 # -################# - -python3 -m pip install --require-hashes -r $SCRIPTPATH/requirements.txt - -solc-select install $SOLC_VERSION -solc-select use $SOLC_VERSION - compileContract v1_0_0 dev/arbitrum/ArbitrumValidator.sol compileContract v1_0_0 dev/arbitrum/ArbitrumSequencerUptimeFeed.sol compileContract v1_0_0 dev/arbitrum/ArbitrumCrossDomainForwarder.sol diff --git a/contracts/src/v0.8/l2ep/dev/CrossDomainDelegateForwarder.sol b/contracts/src/v0.8/l2ep/dev/CrossDomainDelegateForwarder.sol index 5dc73619afc..859c6f0e7f3 100644 --- a/contracts/src/v0.8/l2ep/dev/CrossDomainDelegateForwarder.sol +++ b/contracts/src/v0.8/l2ep/dev/CrossDomainDelegateForwarder.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; import {CrossDomainOwnable} from "./CrossDomainOwnable.sol"; -import {DelegateForwarderInterface} from "./interfaces/DelegateForwarderInterface.sol"; +import {IDelegateForwarder} from "./interfaces/IDelegateForwarder.sol"; /** * @title CrossDomainDelegateForwarder - L1 xDomain account representation (with delegatecall support) @@ -10,4 +10,4 @@ import {DelegateForwarderInterface} from "./interfaces/DelegateForwarderInterfac * @dev Any other L2 contract which uses this contract's address as a privileged position, * can consider that position to be held by the `l1Owner` */ -abstract contract CrossDomainDelegateForwarder is DelegateForwarderInterface, CrossDomainOwnable {} +abstract contract CrossDomainDelegateForwarder is IDelegateForwarder, CrossDomainOwnable {} diff --git a/contracts/src/v0.8/l2ep/dev/CrossDomainForwarder.sol b/contracts/src/v0.8/l2ep/dev/CrossDomainForwarder.sol index 8f218f66b80..c097057f8a7 100644 --- a/contracts/src/v0.8/l2ep/dev/CrossDomainForwarder.sol +++ b/contracts/src/v0.8/l2ep/dev/CrossDomainForwarder.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; import {CrossDomainOwnable} from "./CrossDomainOwnable.sol"; -import {ForwarderInterface} from "./interfaces/ForwarderInterface.sol"; +import {IForwarder} from "./interfaces/IForwarder.sol"; /** * @title CrossDomainForwarder - L1 xDomain account representation @@ -10,4 +10,4 @@ import {ForwarderInterface} from "./interfaces/ForwarderInterface.sol"; * @dev Any other L2 contract which uses this contract's address as a privileged position, * can consider that position to be held by the `l1Owner` */ -abstract contract CrossDomainForwarder is ForwarderInterface, CrossDomainOwnable {} +abstract contract CrossDomainForwarder is IForwarder, CrossDomainOwnable {} diff --git a/contracts/src/v0.8/l2ep/dev/CrossDomainOwnable.sol b/contracts/src/v0.8/l2ep/dev/CrossDomainOwnable.sol index f861da32a7c..c85762b6fca 100644 --- a/contracts/src/v0.8/l2ep/dev/CrossDomainOwnable.sol +++ b/contracts/src/v0.8/l2ep/dev/CrossDomainOwnable.sol @@ -2,13 +2,13 @@ pragma solidity ^0.8.0; import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; -import {CrossDomainOwnableInterface} from "./interfaces/CrossDomainOwnableInterface.sol"; +import {ICrossDomainOwnable} from "./interfaces/ICrossDomainOwnable.sol"; /** * @title The CrossDomainOwnable contract * @notice A contract with helpers for cross-domain contract ownership. */ -contract CrossDomainOwnable is CrossDomainOwnableInterface, ConfirmedOwner { +contract CrossDomainOwnable is ICrossDomainOwnable, ConfirmedOwner { address internal s_l1Owner; address internal s_l1PendingOwner; diff --git a/contracts/src/v0.8/l2ep/dev/Flags.sol b/contracts/src/v0.8/l2ep/dev/Flags.sol index 0fcd095ac8e..2dc030d7d59 100644 --- a/contracts/src/v0.8/l2ep/dev/Flags.sol +++ b/contracts/src/v0.8/l2ep/dev/Flags.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; +pragma solidity ^0.8.24; import {SimpleReadAccessController} from "../../shared/access/SimpleReadAccessController.sol"; import {AccessControllerInterface} from "../../shared/interfaces/AccessControllerInterface.sol"; import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol"; /* dev dependencies - to be re/moved after audit */ -import {FlagsInterface} from "./interfaces/FlagsInterface.sol"; +import {IFlags} from "./interfaces/IFlags.sol"; /** * @title The Flags contract @@ -18,7 +18,7 @@ import {FlagsInterface} from "./interfaces/FlagsInterface.sol"; * FlagOn events you should filter for addresses you care about. */ // solhint-disable gas-custom-errors -contract Flags is ITypeAndVersion, FlagsInterface, SimpleReadAccessController { +contract Flags is ITypeAndVersion, IFlags, SimpleReadAccessController { AccessControllerInterface public raisingAccessController; AccessControllerInterface public loweringAccessController; diff --git a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumCrossDomainForwarder.sol b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumCrossDomainForwarder.sol index 158ffcc3042..0db657ee71c 100644 --- a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumCrossDomainForwarder.sol +++ b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumCrossDomainForwarder.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity ^0.8.24; -import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; +import {ITypeAndVersion} from "../../../shared/interfaces/ITypeAndVersion.sol"; // solhint-disable-next-line no-unused-import -import {ForwarderInterface} from "../interfaces/ForwarderInterface.sol"; +import {IForwarder} from "../interfaces/IForwarder.sol"; import {CrossDomainForwarder} from "../CrossDomainForwarder.sol"; import {CrossDomainOwnable} from "../CrossDomainOwnable.sol"; @@ -17,7 +17,7 @@ import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/ut * @dev Any other L2 contract which uses this contract's address as a privileged position, * can be considered to be owned by the `l1Owner` */ -contract ArbitrumCrossDomainForwarder is TypeAndVersionInterface, CrossDomainForwarder { +contract ArbitrumCrossDomainForwarder is ITypeAndVersion, CrossDomainForwarder { /** * @notice creates a new Arbitrum xDomain Forwarder contract * @param l1OwnerAddr the L1 owner address that will be allowed to call the forward fn @@ -31,7 +31,7 @@ contract ArbitrumCrossDomainForwarder is TypeAndVersionInterface, CrossDomainFor * - ArbitrumCrossDomainForwarder 0.1.0: initial release * - ArbitrumCrossDomainForwarder 1.0.0: Use OZ Address, CrossDomainOwnable * - * @inheritdoc TypeAndVersionInterface + * @inheritdoc ITypeAndVersion */ function typeAndVersion() external pure virtual override returns (string memory) { return "ArbitrumCrossDomainForwarder 1.0.0"; @@ -46,7 +46,7 @@ contract ArbitrumCrossDomainForwarder is TypeAndVersionInterface, CrossDomainFor /** * @dev forwarded only if L2 Messenger calls with `xDomainMessageSender` being the L1 owner address - * @inheritdoc ForwarderInterface + * @inheritdoc IForwarder */ function forward(address target, bytes memory data) external virtual override onlyL1Owner { Address.functionCall(target, data, "Forwarder call reverted"); diff --git a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumCrossDomainGovernor.sol b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumCrossDomainGovernor.sol index ebf579b8494..60d9cc52666 100644 --- a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumCrossDomainGovernor.sol +++ b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumCrossDomainGovernor.sol @@ -2,10 +2,10 @@ pragma solidity ^0.8.0; // solhint-disable-next-line no-unused-import -import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; +import {ITypeAndVersion} from "../../../shared/interfaces/ITypeAndVersion.sol"; // solhint-disable-next-line no-unused-import -import {ForwarderInterface} from "../interfaces/ForwarderInterface.sol"; -import {DelegateForwarderInterface} from "../interfaces/DelegateForwarderInterface.sol"; +import {IForwarder} from "../interfaces/IForwarder.sol"; +import {IDelegateForwarder} from "../interfaces/IDelegateForwarder.sol"; import {ArbitrumCrossDomainForwarder} from "./ArbitrumCrossDomainForwarder.sol"; @@ -17,7 +17,7 @@ import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/ut * @dev Any other L2 contract which uses this contract's address as a privileged position, * can be considered to be simultaneously owned by the `l1Owner` and L2 `owner` */ -contract ArbitrumCrossDomainGovernor is DelegateForwarderInterface, ArbitrumCrossDomainForwarder { +contract ArbitrumCrossDomainGovernor is IDelegateForwarder, ArbitrumCrossDomainForwarder { /** * @notice creates a new Arbitrum xDomain Forwarder contract * @param l1OwnerAddr the L1 owner address that will be allowed to call the forward fn @@ -30,7 +30,7 @@ contract ArbitrumCrossDomainGovernor is DelegateForwarderInterface, ArbitrumCros * * - ArbitrumCrossDomainGovernor 1.0.0: initial release * - * @inheritdoc TypeAndVersionInterface + * @inheritdoc ITypeAndVersion */ function typeAndVersion() external pure virtual override returns (string memory) { return "ArbitrumCrossDomainGovernor 1.0.0"; @@ -38,7 +38,7 @@ contract ArbitrumCrossDomainGovernor is DelegateForwarderInterface, ArbitrumCros /** * @dev forwarded only if L2 Messenger calls with `msg.sender` being the L1 owner address, or called by the L2 owner - * @inheritdoc ForwarderInterface + * @inheritdoc IForwarder */ function forward(address target, bytes memory data) external override onlyLocalOrCrossDomainOwner { Address.functionCall(target, data, "Governor call reverted"); @@ -46,7 +46,7 @@ contract ArbitrumCrossDomainGovernor is DelegateForwarderInterface, ArbitrumCros /** * @dev forwarded only if L2 Messenger calls with `msg.sender` being the L1 owner address, or called by the L2 owner - * @inheritdoc DelegateForwarderInterface + * @inheritdoc IDelegateForwarder */ function forwardDelegate(address target, bytes memory data) external override onlyLocalOrCrossDomainOwner { Address.functionDelegateCall(target, data, "Governor delegatecall reverted"); diff --git a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumSequencerUptimeFeed.sol b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumSequencerUptimeFeed.sol index 63952ab7ba6..678bef3a853 100644 --- a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumSequencerUptimeFeed.sol +++ b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumSequencerUptimeFeed.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.4; +pragma solidity ^0.8.24; import {AddressAliasHelper} from "../../../vendor/arb-bridge-eth/v0.8.0-custom/contracts/libraries/AddressAliasHelper.sol"; import {AggregatorInterface} from "../../../shared/interfaces/AggregatorInterface.sol"; import {AggregatorV3Interface} from "../../../shared/interfaces/AggregatorV3Interface.sol"; import {AggregatorV2V3Interface} from "../../../shared/interfaces/AggregatorV2V3Interface.sol"; -import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; -import {FlagsInterface} from "../interfaces/FlagsInterface.sol"; -import {ArbitrumSequencerUptimeFeedInterface} from "../interfaces/ArbitrumSequencerUptimeFeedInterface.sol"; +import {ITypeAndVersion} from "../../../shared/interfaces/ITypeAndVersion.sol"; +import {IFlags} from "../interfaces/IFlags.sol"; +import {ISequencerUptimeFeed} from "../interfaces/ISequencerUptimeFeed.sol"; import {SimpleReadAccessController} from "../../../shared/access/SimpleReadAccessController.sol"; /** @@ -18,8 +18,8 @@ import {SimpleReadAccessController} from "../../../shared/access/SimpleReadAcces */ contract ArbitrumSequencerUptimeFeed is AggregatorV2V3Interface, - ArbitrumSequencerUptimeFeedInterface, - TypeAndVersionInterface, + ISequencerUptimeFeed, + ITypeAndVersion, SimpleReadAccessController { /// @dev Round info (for uptime history) @@ -62,7 +62,7 @@ contract ArbitrumSequencerUptimeFeed is /// @dev Flags contract to raise/lower flags on, during status transitions // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i - FlagsInterface public immutable FLAGS; + IFlags public immutable FLAGS; /// @dev L1 address address private s_l1Sender; /// @dev s_latestRoundId == 0 means this contract is uninitialized. @@ -76,7 +76,7 @@ contract ArbitrumSequencerUptimeFeed is constructor(address flagsAddress, address l1SenderAddress) { _setL1Sender(l1SenderAddress); - FLAGS = FlagsInterface(flagsAddress); + FLAGS = IFlags(flagsAddress); } /** @@ -120,7 +120,7 @@ contract ArbitrumSequencerUptimeFeed is * * - ArbitrumSequencerUptimeFeed 1.0.0: initial release * - * @inheritdoc TypeAndVersionInterface + * @inheritdoc ITypeAndVersion */ function typeAndVersion() external pure virtual override returns (string memory) { return "ArbitrumSequencerUptimeFeed 1.0.0"; diff --git a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumValidator.sol b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumValidator.sol index edcb62cae90..05f9349eb62 100644 --- a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumValidator.sol +++ b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumValidator.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity ^0.8.24; import {AggregatorValidatorInterface} from "../../../shared/interfaces/AggregatorValidatorInterface.sol"; -import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; +import {ITypeAndVersion} from "../../../shared/interfaces/ITypeAndVersion.sol"; import {AccessControllerInterface} from "../../../shared/interfaces/AccessControllerInterface.sol"; import {SimpleWriteAccessController} from "../../../shared/access/SimpleWriteAccessController.sol"; /* ./dev dependencies - to be moved from ./dev after audit */ -import {ArbitrumSequencerUptimeFeedInterface} from "../interfaces/ArbitrumSequencerUptimeFeedInterface.sol"; +import {ISequencerUptimeFeed} from "../interfaces/ISequencerUptimeFeed.sol"; import {IArbitrumDelayedInbox} from "../interfaces/IArbitrumDelayedInbox.sol"; import {AddressAliasHelper} from "../../../vendor/arb-bridge-eth/v0.8.0-custom/contracts/libraries/AddressAliasHelper.sol"; import {ArbSys} from "../../../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol"; @@ -20,7 +20,7 @@ import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/ut * - Gas configuration is controlled by a configurable external SimpleWriteAccessController * - Funds on the contract are managed by the owner */ -contract ArbitrumValidator is TypeAndVersionInterface, AggregatorValidatorInterface, SimpleWriteAccessController { +contract ArbitrumValidator is ITypeAndVersion, AggregatorValidatorInterface, SimpleWriteAccessController { enum PaymentStrategy { L1, L2 @@ -124,7 +124,7 @@ contract ArbitrumValidator is TypeAndVersionInterface, AggregatorValidatorInterf * - ArbitrumValidator 2.0.0: change how maxSubmissionCost is calculated when sending cross chain messages * - now calls `calculateRetryableSubmissionFee` instead of inlining equation to estimate * the maxSubmissionCost required to send the message to L2 - * @inheritdoc TypeAndVersionInterface + * @inheritdoc ITypeAndVersion */ function typeAndVersion() external pure virtual override returns (string memory) { return "ArbitrumValidator 2.0.0"; @@ -264,7 +264,7 @@ contract ArbitrumValidator is TypeAndVersionInterface, AggregatorValidatorInterf // Excess gas on L2 will be sent to the L2 xDomain alias address of this contract address refundAddr = L2_ALIAS; // Encode the ArbitrumSequencerUptimeFeed call - bytes4 selector = ArbitrumSequencerUptimeFeedInterface.updateStatus.selector; + bytes4 selector = ISequencerUptimeFeed.updateStatus.selector; bool status = currentAnswer == ANSWER_SEQ_OFFLINE; uint64 timestamp = uint64(block.timestamp); // Encode `status` and `timestamp` diff --git a/contracts/src/v0.8/l2ep/dev/interfaces/DelegateForwarderInterface.sol b/contracts/src/v0.8/l2ep/dev/interfaces/DelegateForwarderInterface.sol deleted file mode 100644 index 498dee586c8..00000000000 --- a/contracts/src/v0.8/l2ep/dev/interfaces/DelegateForwarderInterface.sol +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -/// @title DelegateForwarderInterface - forwards a delegatecall to a target, under some conditions -// solhint-disable-next-line interface-starts-with-i -interface DelegateForwarderInterface { - /** - * @notice forward delegatecalls the `target` with `data` - * @param target contract address to be delegatecalled - * @param data to send to target contract - */ - function forwardDelegate(address target, bytes memory data) external; -} diff --git a/contracts/src/v0.8/l2ep/dev/interfaces/ForwarderInterface.sol b/contracts/src/v0.8/l2ep/dev/interfaces/ForwarderInterface.sol deleted file mode 100644 index a6db32b9231..00000000000 --- a/contracts/src/v0.8/l2ep/dev/interfaces/ForwarderInterface.sol +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -/// @title ForwarderInterface - forwards a call to a target, under some conditions -// solhint-disable-next-line interface-starts-with-i -interface ForwarderInterface { - /** - * @notice forward calls the `target` with `data` - * @param target contract address to be called - * @param data to send to target contract - */ - function forward(address target, bytes memory data) external; -} diff --git a/contracts/src/v0.8/l2ep/dev/interfaces/CrossDomainOwnableInterface.sol b/contracts/src/v0.8/l2ep/dev/interfaces/ICrossDomainOwnable.sol similarity index 65% rename from contracts/src/v0.8/l2ep/dev/interfaces/CrossDomainOwnableInterface.sol rename to contracts/src/v0.8/l2ep/dev/interfaces/ICrossDomainOwnable.sol index ddcfded9ca2..d5a01386e3c 100644 --- a/contracts/src/v0.8/l2ep/dev/interfaces/CrossDomainOwnableInterface.sol +++ b/contracts/src/v0.8/l2ep/dev/interfaces/ICrossDomainOwnable.sol @@ -1,9 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -/// @title CrossDomainOwnableInterface - A contract with helpers for cross-domain contract ownership -// solhint-disable-next-line interface-starts-with-i -interface CrossDomainOwnableInterface { +/// @title A contract with helpers for cross-domain contract ownership +interface ICrossDomainOwnable { event L1OwnershipTransferRequested(address indexed from, address indexed to); event L1OwnershipTransferred(address indexed from, address indexed to); diff --git a/contracts/src/v0.8/l2ep/dev/interfaces/IDelegateForwarder.sol b/contracts/src/v0.8/l2ep/dev/interfaces/IDelegateForwarder.sol new file mode 100644 index 00000000000..3df532b94c5 --- /dev/null +++ b/contracts/src/v0.8/l2ep/dev/interfaces/IDelegateForwarder.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +/// @title Forwards a delegatecall to a target, under some conditions +interface IDelegateForwarder { + /// @notice forward delegatecalls the `target` with `data` + /// @param target contract address to be delegatecalled + /// @param data to send to target contract + function forwardDelegate(address target, bytes memory data) external; +} diff --git a/contracts/src/v0.8/l2ep/dev/interfaces/FlagsInterface.sol b/contracts/src/v0.8/l2ep/dev/interfaces/IFlags.sol similarity index 82% rename from contracts/src/v0.8/l2ep/dev/interfaces/FlagsInterface.sol rename to contracts/src/v0.8/l2ep/dev/interfaces/IFlags.sol index b6491a9d601..6ae5a3a3f38 100644 --- a/contracts/src/v0.8/l2ep/dev/interfaces/FlagsInterface.sol +++ b/contracts/src/v0.8/l2ep/dev/interfaces/IFlags.sol @@ -1,8 +1,7 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; +pragma solidity ^0.8.0; -// solhint-disable-next-line interface-starts-with-i -interface FlagsInterface { +interface IFlags { function getFlag(address) external view returns (bool); function getFlags(address[] calldata) external view returns (bool[] memory); diff --git a/contracts/src/v0.8/l2ep/dev/interfaces/IForwarder.sol b/contracts/src/v0.8/l2ep/dev/interfaces/IForwarder.sol new file mode 100644 index 00000000000..374e3810647 --- /dev/null +++ b/contracts/src/v0.8/l2ep/dev/interfaces/IForwarder.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +/// @title Forwards a call to a target, under some conditions +interface IForwarder { + /// @notice forward calls the `target` with `data` + /// @param target contract address to be called + /// @param data to send to target contract + function forward(address target, bytes memory data) external; +} diff --git a/contracts/src/v0.8/l2ep/dev/interfaces/ArbitrumSequencerUptimeFeedInterface.sol b/contracts/src/v0.8/l2ep/dev/interfaces/ISequencerUptimeFeed.sol similarity index 54% rename from contracts/src/v0.8/l2ep/dev/interfaces/ArbitrumSequencerUptimeFeedInterface.sol rename to contracts/src/v0.8/l2ep/dev/interfaces/ISequencerUptimeFeed.sol index 57b507bae8d..879dc06d37e 100644 --- a/contracts/src/v0.8/l2ep/dev/interfaces/ArbitrumSequencerUptimeFeedInterface.sol +++ b/contracts/src/v0.8/l2ep/dev/interfaces/ISequencerUptimeFeed.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -// solhint-disable-next-line interface-starts-with-i -interface ArbitrumSequencerUptimeFeedInterface { +interface ISequencerUptimeFeed { function updateStatus(bool status, uint64 timestamp) external; } diff --git a/contracts/src/v0.8/l2ep/dev/interfaces/OptimismSequencerUptimeFeedInterface.sol b/contracts/src/v0.8/l2ep/dev/interfaces/OptimismSequencerUptimeFeedInterface.sol deleted file mode 100644 index a08a1b26204..00000000000 --- a/contracts/src/v0.8/l2ep/dev/interfaces/OptimismSequencerUptimeFeedInterface.sol +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -// solhint-disable-next-line interface-starts-with-i -interface OptimismSequencerUptimeFeedInterface { - function updateStatus(bool status, uint64 timestamp) external; -} diff --git a/contracts/src/v0.8/l2ep/dev/interfaces/ScrollSequencerUptimeFeedInterface.sol b/contracts/src/v0.8/l2ep/dev/interfaces/ScrollSequencerUptimeFeedInterface.sol deleted file mode 100644 index 89327fbc3a1..00000000000 --- a/contracts/src/v0.8/l2ep/dev/interfaces/ScrollSequencerUptimeFeedInterface.sol +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.19; - -// solhint-disable-next-line interface-starts-with-i -interface ScrollSequencerUptimeFeedInterface { - function updateStatus(bool status, uint64 timestamp) external; -} diff --git a/contracts/src/v0.8/l2ep/dev/optimism/OptimismCrossDomainForwarder.sol b/contracts/src/v0.8/l2ep/dev/optimism/OptimismCrossDomainForwarder.sol index 37d9260b47b..1d037886960 100644 --- a/contracts/src/v0.8/l2ep/dev/optimism/OptimismCrossDomainForwarder.sol +++ b/contracts/src/v0.8/l2ep/dev/optimism/OptimismCrossDomainForwarder.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity ^0.8.24; -import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; +import {ITypeAndVersion} from "../../../shared/interfaces/ITypeAndVersion.sol"; // solhint-disable-next-line no-unused-import -import {ForwarderInterface} from "../interfaces/ForwarderInterface.sol"; +import {IForwarder} from "../interfaces/IForwarder.sol"; /* ./dev dependencies - to be moved from ./dev after audit */ import {CrossDomainForwarder} from "../CrossDomainForwarder.sol"; @@ -18,7 +18,7 @@ import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/ut * @dev Any other L2 contract which uses this contract's address as a privileged position, * can be considered to be owned by the `l1Owner` */ -contract OptimismCrossDomainForwarder is TypeAndVersionInterface, CrossDomainForwarder { +contract OptimismCrossDomainForwarder is ITypeAndVersion, CrossDomainForwarder { // OVM_L2CrossDomainMessenger is a precompile usually deployed to 0x4200000000000000000000000000000000000007 // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i iOVM_CrossDomainMessenger private immutable OVM_CROSS_DOMAIN_MESSENGER; @@ -40,7 +40,7 @@ contract OptimismCrossDomainForwarder is TypeAndVersionInterface, CrossDomainFor * - OptimismCrossDomainForwarder 0.1.0: initial release * - OptimismCrossDomainForwarder 1.0.0: Use OZ Address, CrossDomainOwnable * - * @inheritdoc TypeAndVersionInterface + * @inheritdoc ITypeAndVersion */ function typeAndVersion() external pure virtual override returns (string memory) { return "OptimismCrossDomainForwarder 1.0.0"; @@ -48,7 +48,7 @@ contract OptimismCrossDomainForwarder is TypeAndVersionInterface, CrossDomainFor /** * @dev forwarded only if L2 Messenger calls with `xDomainMessageSender` being the L1 owner address - * @inheritdoc ForwarderInterface + * @inheritdoc IForwarder */ function forward(address target, bytes memory data) external virtual override onlyL1Owner { Address.functionCall(target, data, "Forwarder call reverted"); diff --git a/contracts/src/v0.8/l2ep/dev/optimism/OptimismCrossDomainGovernor.sol b/contracts/src/v0.8/l2ep/dev/optimism/OptimismCrossDomainGovernor.sol index ad780946911..6a41bd98f03 100644 --- a/contracts/src/v0.8/l2ep/dev/optimism/OptimismCrossDomainGovernor.sol +++ b/contracts/src/v0.8/l2ep/dev/optimism/OptimismCrossDomainGovernor.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity ^0.8.24; -import {DelegateForwarderInterface} from "../interfaces/DelegateForwarderInterface.sol"; +import {IDelegateForwarder} from "../interfaces/IDelegateForwarder.sol"; // solhint-disable-next-line no-unused-import -import {ForwarderInterface} from "../interfaces/ForwarderInterface.sol"; +import {IForwarder} from "../interfaces/IForwarder.sol"; import {OptimismCrossDomainForwarder} from "./OptimismCrossDomainForwarder.sol"; @@ -16,7 +16,7 @@ import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/ut * @dev Any other L2 contract which uses this contract's address as a privileged position, * can be considered to be simultaneously owned by the `l1Owner` and L2 `owner` */ -contract OptimismCrossDomainGovernor is DelegateForwarderInterface, OptimismCrossDomainForwarder { +contract OptimismCrossDomainGovernor is IDelegateForwarder, OptimismCrossDomainForwarder { /** * @notice creates a new Optimism xDomain Forwarder contract * @param crossDomainMessengerAddr the xDomain bridge messenger (Optimism bridge L2) contract address @@ -39,7 +39,7 @@ contract OptimismCrossDomainGovernor is DelegateForwarderInterface, OptimismCros /** * @dev forwarded only if L2 Messenger calls with `msg.sender` being the L1 owner address, or called by the L2 owner - * @inheritdoc ForwarderInterface + * @inheritdoc IForwarder */ function forward(address target, bytes memory data) external override onlyLocalOrCrossDomainOwner { Address.functionCall(target, data, "Governor call reverted"); @@ -47,7 +47,7 @@ contract OptimismCrossDomainGovernor is DelegateForwarderInterface, OptimismCros /** * @dev forwarded only if L2 Messenger calls with `msg.sender` being the L1 owner address, or called by the L2 owner - * @inheritdoc DelegateForwarderInterface + * @inheritdoc IDelegateForwarder */ function forwardDelegate(address target, bytes memory data) external override onlyLocalOrCrossDomainOwner { Address.functionDelegateCall(target, data, "Governor delegatecall reverted"); diff --git a/contracts/src/v0.8/l2ep/dev/optimism/OptimismSequencerUptimeFeed.sol b/contracts/src/v0.8/l2ep/dev/optimism/OptimismSequencerUptimeFeed.sol index 947b1b0bf5d..0e6f9c52f22 100644 --- a/contracts/src/v0.8/l2ep/dev/optimism/OptimismSequencerUptimeFeed.sol +++ b/contracts/src/v0.8/l2ep/dev/optimism/OptimismSequencerUptimeFeed.sol @@ -1,12 +1,8 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.4; +pragma solidity ^0.8.19; + +import {BaseSequencerUptimeFeed} from "../shared/BaseSequencerUptimeFeed.sol"; -import {AggregatorInterface} from "../../../shared/interfaces/AggregatorInterface.sol"; -import {AggregatorV3Interface} from "../../../shared/interfaces/AggregatorV3Interface.sol"; -import {AggregatorV2V3Interface} from "../../../shared/interfaces/AggregatorV2V3Interface.sol"; -import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; -import {OptimismSequencerUptimeFeedInterface} from "./../interfaces/OptimismSequencerUptimeFeedInterface.sol"; -import {SimpleReadAccessController} from "../../../shared/access/SimpleReadAccessController.sol"; import {IL2CrossDomainMessenger} from "@eth-optimism/contracts/L2/messaging/IL2CrossDomainMessenger.sol"; /** @@ -14,50 +10,8 @@ import {IL2CrossDomainMessenger} from "@eth-optimism/contracts/L2/messaging/IL2C * @notice L2 contract that receives status updates from a specific L1 address, * records a new answer if the status changed */ -contract OptimismSequencerUptimeFeed is - AggregatorV2V3Interface, - OptimismSequencerUptimeFeedInterface, - TypeAndVersionInterface, - SimpleReadAccessController -{ - /// @dev Round info (for uptime history) - struct Round { - bool status; - uint64 startedAt; - uint64 updatedAt; - } - - /// @dev Packed state struct to save sloads - struct FeedState { - uint80 latestRoundId; - bool latestStatus; - uint64 startedAt; - uint64 updatedAt; - } - - /// @notice Sender is not the L2 messenger - error InvalidSender(); - /// @notice Replacement for AggregatorV3Interface "No data present" - error NoDataPresent(); - - event L1SenderTransferred(address indexed from, address indexed to); - /// @dev Emitted when an `updateStatus` call is ignored due to unchanged status or stale timestamp - event UpdateIgnored(bool latestStatus, uint64 latestTimestamp, bool incomingStatus, uint64 incomingTimestamp); - /// @dev Emitted when a updateStatus is called without the status changing - event RoundUpdated(int256 status, uint64 updatedAt); - - // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables - uint8 public constant override decimals = 0; - // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables - string public constant override description = "L2 Sequencer Uptime Status Feed"; - // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables - uint256 public constant override version = 1; - - /// @dev L1 address - address private s_l1Sender; - /// @dev s_latestRoundId == 0 means this contract is uninitialized. - FeedState private s_feedState = FeedState({latestRoundId: 0, latestStatus: false, startedAt: 0, updatedAt: 0}); - mapping(uint80 => Round) private s_rounds; +contract OptimismSequencerUptimeFeed is BaseSequencerUptimeFeed { + string public constant override typeAndVersion = "OptimismSequencerUptimeFeed 1.1.0-dev"; // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i IL2CrossDomainMessenger private immutable s_l2CrossDomainMessenger; @@ -67,202 +21,19 @@ contract OptimismSequencerUptimeFeed is * @param l2CrossDomainMessengerAddr Address of the L2CrossDomainMessenger contract * @param initialStatus The initial status of the feed */ - constructor(address l1SenderAddress, address l2CrossDomainMessengerAddr, bool initialStatus) { - _setL1Sender(l1SenderAddress); + constructor( + address l1SenderAddress, + address l2CrossDomainMessengerAddr, + bool initialStatus + ) BaseSequencerUptimeFeed(l1SenderAddress, initialStatus) { s_l2CrossDomainMessenger = IL2CrossDomainMessenger(l2CrossDomainMessengerAddr); - uint64 timestamp = uint64(block.timestamp); - - // Initialise roundId == 1 as the first round - _recordRound(1, initialStatus, timestamp); - } - - /** - * @notice Check if a roundId is valid in this current contract state - * @dev Mainly used for AggregatorV2V3Interface functions - * @param roundId Round ID to check - */ - function _isValidRound(uint256 roundId) private view returns (bool) { - return roundId > 0 && roundId <= type(uint80).max && s_feedState.latestRoundId >= roundId; - } - - /** - * @notice versions: - * - * - OptimismSequencerUptimeFeed 1.0.0: initial release - * - * @inheritdoc TypeAndVersionInterface - */ - function typeAndVersion() external pure virtual override returns (string memory) { - return "OptimismSequencerUptimeFeed 1.0.0"; - } - - /// @return L1 sender address - function l1Sender() public view virtual returns (address) { - return s_l1Sender; - } - - /** - * @notice Set the allowed L1 sender for this contract to a new L1 sender - * @dev Can be disabled by setting the L1 sender as `address(0)`. Accessible only by owner. - * @param to new L1 sender that will be allowed to call `updateStatus` on this contract - */ - function transferL1Sender(address to) external virtual onlyOwner { - _setL1Sender(to); - } - - /// @notice internal method that stores the L1 sender - function _setL1Sender(address to) private { - address from = s_l1Sender; - if (from != to) { - s_l1Sender = to; - emit L1SenderTransferred(from, to); - } - } - - /** - * @dev Returns an AggregatorV2V3Interface compatible answer from status flag - * - * @param status The status flag to convert to an aggregator-compatible answer - */ - function _getStatusAnswer(bool status) private pure returns (int256) { - return status ? int256(1) : int256(0); - } - - /** - * @notice Helper function to record a round and set the latest feed state. - * - * @param roundId The round ID to record - * @param status Sequencer status - * @param timestamp The L1 block timestamp of status update - */ - function _recordRound(uint80 roundId, bool status, uint64 timestamp) private { - uint64 updatedAt = uint64(block.timestamp); - Round memory nextRound = Round(status, timestamp, updatedAt); - FeedState memory feedState = FeedState(roundId, status, timestamp, updatedAt); - - s_rounds[roundId] = nextRound; - s_feedState = feedState; - - emit NewRound(roundId, msg.sender, timestamp); - emit AnswerUpdated(_getStatusAnswer(status), roundId, timestamp); } - /** - * @notice Helper function to update when a round was last updated - * - * @param roundId The round ID to update - * @param status Sequencer status - */ - function _updateRound(uint80 roundId, bool status) private { - uint64 updatedAt = uint64(block.timestamp); - s_rounds[roundId].updatedAt = updatedAt; - s_feedState.updatedAt = updatedAt; - emit RoundUpdated(_getStatusAnswer(status), updatedAt); - } - - /** - * @notice Record a new status and timestamp if it has changed since the last round. - * @dev This function will revert if not called from `l1Sender` via the L1->L2 messenger. - * - * @param status Sequencer status - * @param timestamp Block timestamp of status update - */ - function updateStatus(bool status, uint64 timestamp) external override { - FeedState memory feedState = s_feedState; + function _validateSender(address l1Sender) internal view override { if ( - msg.sender != address(s_l2CrossDomainMessenger) || s_l2CrossDomainMessenger.xDomainMessageSender() != s_l1Sender + msg.sender != address(s_l2CrossDomainMessenger) || s_l2CrossDomainMessenger.xDomainMessageSender() != l1Sender ) { revert InvalidSender(); } - - // Ignore if latest recorded timestamp is newer - if (feedState.startedAt > timestamp) { - emit UpdateIgnored(feedState.latestStatus, feedState.startedAt, status, timestamp); - return; - } - - if (feedState.latestStatus == status) { - _updateRound(feedState.latestRoundId, status); - } else { - feedState.latestRoundId += 1; - _recordRound(feedState.latestRoundId, status, timestamp); - } - } - - /// @inheritdoc AggregatorInterface - function latestAnswer() external view override checkAccess returns (int256) { - FeedState memory feedState = s_feedState; - return _getStatusAnswer(feedState.latestStatus); - } - - /// @inheritdoc AggregatorInterface - function latestTimestamp() external view override checkAccess returns (uint256) { - FeedState memory feedState = s_feedState; - return feedState.startedAt; - } - - /// @inheritdoc AggregatorInterface - function latestRound() external view override checkAccess returns (uint256) { - FeedState memory feedState = s_feedState; - return feedState.latestRoundId; - } - - /// @inheritdoc AggregatorInterface - function getAnswer(uint256 roundId) external view override checkAccess returns (int256) { - if (_isValidRound(roundId)) { - return _getStatusAnswer(s_rounds[uint80(roundId)].status); - } - - revert NoDataPresent(); - } - - /// @inheritdoc AggregatorInterface - function getTimestamp(uint256 roundId) external view override checkAccess returns (uint256) { - if (_isValidRound(roundId)) { - return s_rounds[uint80(roundId)].startedAt; - } - - revert NoDataPresent(); - } - - /// @inheritdoc AggregatorV3Interface - function getRoundData( - uint80 _roundId - ) - public - view - override - checkAccess - returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) - { - if (_isValidRound(_roundId)) { - Round memory round = s_rounds[_roundId]; - answer = _getStatusAnswer(round.status); - startedAt = uint256(round.startedAt); - roundId = _roundId; - updatedAt = uint256(round.updatedAt); - answeredInRound = roundId; - } else { - revert NoDataPresent(); - } - return (roundId, answer, startedAt, updatedAt, answeredInRound); - } - - /// @inheritdoc AggregatorV3Interface - function latestRoundData() - external - view - override - checkAccess - returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) - { - FeedState memory feedState = s_feedState; - - roundId = feedState.latestRoundId; - answer = _getStatusAnswer(feedState.latestStatus); - startedAt = feedState.startedAt; - updatedAt = feedState.updatedAt; - answeredInRound = roundId; - return (roundId, answer, startedAt, updatedAt, answeredInRound); } } diff --git a/contracts/src/v0.8/l2ep/dev/optimism/OptimismValidator.sol b/contracts/src/v0.8/l2ep/dev/optimism/OptimismValidator.sol index a54a56ee604..cf5222f017e 100644 --- a/contracts/src/v0.8/l2ep/dev/optimism/OptimismValidator.sol +++ b/contracts/src/v0.8/l2ep/dev/optimism/OptimismValidator.sol @@ -1,82 +1,28 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity ^0.8.19; -import {AggregatorValidatorInterface} from "../../../shared/interfaces/AggregatorValidatorInterface.sol"; -import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; -import {OptimismSequencerUptimeFeedInterface} from "./../interfaces/OptimismSequencerUptimeFeedInterface.sol"; +import {ISequencerUptimeFeed} from "./../interfaces/ISequencerUptimeFeed.sol"; -import {SimpleWriteAccessController} from "../../../shared/access/SimpleWriteAccessController.sol"; +import {BaseValidator} from "../shared/BaseValidator.sol"; import {IL1CrossDomainMessenger} from "@eth-optimism/contracts/L1/messaging/IL1CrossDomainMessenger.sol"; -/** - * @title OptimismValidator - makes cross chain call to update the Sequencer Uptime Feed on L2 - */ -contract OptimismValidator is TypeAndVersionInterface, AggregatorValidatorInterface, SimpleWriteAccessController { - int256 private constant ANSWER_SEQ_OFFLINE = 1; - uint32 private s_gasLimit; - - // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i - address public immutable L1_CROSS_DOMAIN_MESSENGER_ADDRESS; - // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i - address public immutable L2_UPTIME_FEED_ADDR; - - /** - * @notice emitted when gas cost to spend on L2 is updated - * @param gasLimit updated gas cost - */ - event GasLimitUpdated(uint32 gasLimit); - - /** - * @param l1CrossDomainMessengerAddress address the L1CrossDomainMessenger contract address - * @param l2UptimeFeedAddr the address of the OptimismSequencerUptimeFeed contract address - * @param gasLimit the gasLimit to use for sending a message from L1 to L2 - */ - constructor(address l1CrossDomainMessengerAddress, address l2UptimeFeedAddr, uint32 gasLimit) { - // solhint-disable-next-line gas-custom-errors - require(l1CrossDomainMessengerAddress != address(0), "Invalid xDomain Messenger address"); - // solhint-disable-next-line gas-custom-errors - require(l2UptimeFeedAddr != address(0), "Invalid OptimismSequencerUptimeFeed contract address"); - L1_CROSS_DOMAIN_MESSENGER_ADDRESS = l1CrossDomainMessengerAddress; - L2_UPTIME_FEED_ADDR = l2UptimeFeedAddr; - s_gasLimit = gasLimit; - } - - /** - * @notice versions: - * - * - OptimismValidator 0.1.0: initial release - * - OptimismValidator 1.0.0: change target of L2 sequencer status update - * - now calls `updateStatus` on an L2 OptimismSequencerUptimeFeed contract instead of - * directly calling the Flags contract - * - * @inheritdoc TypeAndVersionInterface - */ - function typeAndVersion() external pure virtual override returns (string memory) { - return "OptimismValidator 1.0.0"; - } - - /** - * @notice sets the new gas cost to spend when sending cross chain message - * @param gasLimit the updated gas cost - */ - function setGasLimit(uint32 gasLimit) external onlyOwner { - s_gasLimit = gasLimit; - emit GasLimitUpdated(gasLimit); - } - - /** - * @notice fetches the gas cost of sending a cross chain message - */ - function getGasLimit() external view returns (uint32) { - return s_gasLimit; - } - - /** - * @notice validate method sends an xDomain L2 tx to update Uptime Feed contract on L2. - * @dev A message is sent using the L1CrossDomainMessenger. This method is accessed controlled. - * @param currentAnswer new aggregator answer - value of 1 considers the sequencer offline. - */ +/// @title OptimismValidator - makes cross chain call to update the Sequencer Uptime Feed on L2 +contract OptimismValidator is BaseValidator { + string public constant override typeAndVersion = "OptimismValidator 1.1.0-dev"; + + /// @param l1CrossDomainMessengerAddress address the L1CrossDomainMessenger contract address + /// @param l2UptimeFeedAddr the address of the OptimismSequencerUptimeFeed contract address + /// @param gasLimit the gasLimit to use for sending a message from L1 to L2 + constructor( + address l1CrossDomainMessengerAddress, + address l2UptimeFeedAddr, + uint32 gasLimit + ) BaseValidator(l1CrossDomainMessengerAddress, l2UptimeFeedAddr, gasLimit) {} + + /// @notice validate method sends an xDomain L2 tx to update Uptime Feed contract on L2. + /// @dev A message is sent using the L1CrossDomainMessenger. This method is accessed controlled. + /// @param currentAnswer new aggregator answer - value of 1 considers the sequencer offline. function validate( uint256 /* previousRoundId */, int256 /* previousAnswer */, @@ -84,7 +30,7 @@ contract OptimismValidator is TypeAndVersionInterface, AggregatorValidatorInterf int256 currentAnswer ) external override checkAccess returns (bool) { // Encode the OptimismSequencerUptimeFeed call - bytes4 selector = OptimismSequencerUptimeFeedInterface.updateStatus.selector; + bytes4 selector = ISequencerUptimeFeed.updateStatus.selector; bool status = currentAnswer == ANSWER_SEQ_OFFLINE; uint64 timestamp = uint64(block.timestamp); // Encode `status` and `timestamp` diff --git a/contracts/src/v0.8/l2ep/dev/scroll/ScrollCrossDomainForwarder.sol b/contracts/src/v0.8/l2ep/dev/scroll/ScrollCrossDomainForwarder.sol index 4ec51fc6938..c70bc794afb 100644 --- a/contracts/src/v0.8/l2ep/dev/scroll/ScrollCrossDomainForwarder.sol +++ b/contracts/src/v0.8/l2ep/dev/scroll/ScrollCrossDomainForwarder.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.19; +pragma solidity 0.8.24; -import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; -import {ForwarderInterface} from "../interfaces/ForwarderInterface.sol"; +import {ITypeAndVersion} from "../../../shared/interfaces/ITypeAndVersion.sol"; +import {IForwarder} from "../interfaces/IForwarder.sol"; import {CrossDomainForwarder} from "../CrossDomainForwarder.sol"; import {CrossDomainOwnable} from "../CrossDomainOwnable.sol"; @@ -14,7 +14,7 @@ import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/ut /// @notice L2 Contract which receives messages from a specific L1 address and transparently forwards them to the destination. /// @dev Any other L2 contract which uses this contract's address as a privileged position, /// can be considered to be owned by the `l1Owner` -contract ScrollCrossDomainForwarder is TypeAndVersionInterface, CrossDomainForwarder { +contract ScrollCrossDomainForwarder is ITypeAndVersion, CrossDomainForwarder { string public constant override typeAndVersion = "ScrollCrossDomainForwarder 1.0.0"; address internal immutable i_scrollCrossDomainMessenger; @@ -28,7 +28,7 @@ contract ScrollCrossDomainForwarder is TypeAndVersionInterface, CrossDomainForwa } /// @dev forwarded only if L2 Messenger calls with `xDomainMessageSender` being the L1 owner address - /// @inheritdoc ForwarderInterface + /// @inheritdoc IForwarder function forward(address target, bytes memory data) external override onlyL1Owner { Address.functionCall(target, data, "Forwarder call reverted"); } diff --git a/contracts/src/v0.8/l2ep/dev/scroll/ScrollCrossDomainGovernor.sol b/contracts/src/v0.8/l2ep/dev/scroll/ScrollCrossDomainGovernor.sol index f7d13059fe7..dae621e9b08 100644 --- a/contracts/src/v0.8/l2ep/dev/scroll/ScrollCrossDomainGovernor.sol +++ b/contracts/src/v0.8/l2ep/dev/scroll/ScrollCrossDomainGovernor.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.19; +pragma solidity 0.8.24; -import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; -import {DelegateForwarderInterface} from "../interfaces/DelegateForwarderInterface.sol"; +import {ITypeAndVersion} from "../../../shared/interfaces/ITypeAndVersion.sol"; +import {IDelegateForwarder} from "../interfaces/IDelegateForwarder.sol"; // solhint-disable-next-line no-unused-import -import {ForwarderInterface} from "../interfaces/ForwarderInterface.sol"; +import {IForwarder} from "../interfaces/IForwarder.sol"; import {CrossDomainForwarder} from "../CrossDomainForwarder.sol"; import {CrossDomainOwnable} from "../CrossDomainOwnable.sol"; @@ -16,7 +16,7 @@ import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/ut /// @notice L2 Contract which receives messages from a specific L1 address and transparently forwards them to the destination. /// @dev Any other L2 contract which uses this contract's address as a privileged position, /// can be considered to be simultaneously owned by the `l1Owner` and L2 `owner` -contract ScrollCrossDomainGovernor is DelegateForwarderInterface, TypeAndVersionInterface, CrossDomainForwarder { +contract ScrollCrossDomainGovernor is IDelegateForwarder, ITypeAndVersion, CrossDomainForwarder { string public constant override typeAndVersion = "ScrollCrossDomainGovernor 1.0.0"; address internal immutable i_scrollCrossDomainMessenger; @@ -29,13 +29,13 @@ contract ScrollCrossDomainGovernor is DelegateForwarderInterface, TypeAndVersion i_scrollCrossDomainMessenger = address(crossDomainMessengerAddr); } - /// @inheritdoc ForwarderInterface + /// @inheritdoc IForwarder /// @dev forwarded only if L2 Messenger calls with `msg.sender` being the L1 owner address, or called by the L2 owner function forward(address target, bytes memory data) external override onlyLocalOrCrossDomainOwner { Address.functionCall(target, data, "Governor call reverted"); } - /// @inheritdoc DelegateForwarderInterface + /// @inheritdoc IDelegateForwarder /// @dev forwarded only if L2 Messenger calls with `msg.sender` being the L1 owner address, or called by the L2 owner function forwardDelegate(address target, bytes memory data) external override onlyLocalOrCrossDomainOwner { Address.functionDelegateCall(target, data, "Governor delegatecall reverted"); diff --git a/contracts/src/v0.8/l2ep/dev/scroll/ScrollSequencerUptimeFeed.sol b/contracts/src/v0.8/l2ep/dev/scroll/ScrollSequencerUptimeFeed.sol index e60e8703b77..40f2941aa69 100644 --- a/contracts/src/v0.8/l2ep/dev/scroll/ScrollSequencerUptimeFeed.sol +++ b/contracts/src/v0.8/l2ep/dev/scroll/ScrollSequencerUptimeFeed.sol @@ -1,66 +1,16 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.19; +pragma solidity 0.8.24; -import {ScrollSequencerUptimeFeedInterface} from "../interfaces/ScrollSequencerUptimeFeedInterface.sol"; -import {AggregatorInterface} from "../../../shared/interfaces/AggregatorInterface.sol"; -import {AggregatorV3Interface} from "../../../shared/interfaces/AggregatorV3Interface.sol"; -import {AggregatorV2V3Interface} from "../../../shared/interfaces/AggregatorV2V3Interface.sol"; -import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; - -import {SimpleReadAccessController} from "../../../shared/access/SimpleReadAccessController.sol"; +import {BaseSequencerUptimeFeed} from "../shared/BaseSequencerUptimeFeed.sol"; import {IL2ScrollMessenger} from "@scroll-tech/contracts/L2/IL2ScrollMessenger.sol"; /// @title ScrollSequencerUptimeFeed - L2 sequencer uptime status aggregator /// @notice L2 contract that receives status updates, and records a new answer if the status changed -contract ScrollSequencerUptimeFeed is - AggregatorV2V3Interface, - ScrollSequencerUptimeFeedInterface, - TypeAndVersionInterface, - SimpleReadAccessController -{ - string public constant override typeAndVersion = "ScrollSequencerUptimeFeed 1.0.0"; - - /// @dev Round info (for uptime history) - struct Round { - bool status; - uint64 startedAt; - uint64 updatedAt; - } - - /// @dev Packed state struct to save sloads - struct FeedState { - uint80 latestRoundId; - bool latestStatus; - uint64 startedAt; - uint64 updatedAt; - } - - /// @notice Sender is not the L2 messenger - error InvalidSender(); - /// @notice Replacement for AggregatorV3Interface "No data present" - error NoDataPresent(); - /// @notice Address must not be the zero address +contract ScrollSequencerUptimeFeed is BaseSequencerUptimeFeed { error ZeroAddress(); - event L1SenderTransferred(address indexed from, address indexed to); - /// @dev Emitted when an `updateStatus` call is ignored due to unchanged status or stale timestamp - event UpdateIgnored(bool latestStatus, uint64 latestTimestamp, bool incomingStatus, uint64 incomingTimestamp); - /// @dev Emitted when a updateStatus is called without the status changing - event RoundUpdated(int256 status, uint64 updatedAt); - - // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables - uint8 public constant override decimals = 0; - // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables - string public constant override description = "L2 Sequencer Uptime Status Feed"; - // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables - uint256 public constant override version = 1; - - /// @dev L1 address - address private s_l1Sender; - /// @dev s_latestRoundId == 0 means this contract is uninitialized. - FeedState private s_feedState = FeedState({latestRoundId: 0, latestStatus: false, startedAt: 0, updatedAt: 0}); - mapping(uint80 roundId => Round round) private s_rounds; + string public constant override typeAndVersion = "ScrollSequencerUptimeFeed 1.1.0-dev"; // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i IL2ScrollMessenger private immutable s_l2CrossDomainMessenger; @@ -68,169 +18,23 @@ contract ScrollSequencerUptimeFeed is /// @param l1SenderAddress Address of the L1 contract that is permissioned to call this contract /// @param l2CrossDomainMessengerAddr Address of the L2CrossDomainMessenger contract /// @param initialStatus The initial status of the feed - constructor(address l1SenderAddress, address l2CrossDomainMessengerAddr, bool initialStatus) { + constructor( + address l1SenderAddress, + address l2CrossDomainMessengerAddr, + bool initialStatus + ) BaseSequencerUptimeFeed(l1SenderAddress, initialStatus) { if (l2CrossDomainMessengerAddr == address(0)) { revert ZeroAddress(); } - _setL1Sender(l1SenderAddress); s_l2CrossDomainMessenger = IL2ScrollMessenger(l2CrossDomainMessengerAddr); - - // Initialise roundId == 1 as the first round - _recordRound(1, initialStatus, uint64(block.timestamp)); - } - - /// @notice Check if a roundId is valid in this current contract state - /// @dev Mainly used for AggregatorV2V3Interface functions - /// @param roundId Round ID to check - function _isValidRound(uint256 roundId) private view returns (bool) { - return roundId > 0 && roundId <= type(uint80).max && s_feedState.latestRoundId >= roundId; - } - - /// @return L1 sender address - function l1Sender() public view virtual returns (address) { - return s_l1Sender; } - /// @notice Set the allowed L1 sender for this contract to a new L1 sender - /// @dev Can be disabled by setting the L1 sender as `address(0)`. Accessible only by owner. - /// @param to new L1 sender that will be allowed to call `updateStatus` on this contract - function transferL1Sender(address to) external virtual onlyOwner { - _setL1Sender(to); - } - - /// @notice internal method that stores the L1 sender - function _setL1Sender(address to) private { - address from = s_l1Sender; - if (from != to) { - s_l1Sender = to; - emit L1SenderTransferred(from, to); - } - } - - /// @dev Returns an AggregatorV2V3Interface compatible answer from status flag - /// @param status The status flag to convert to an aggregator-compatible answer - function _getStatusAnswer(bool status) private pure returns (int256) { - return status ? int256(1) : int256(0); - } - - /// @notice Helper function to record a round and set the latest feed state. - /// @param roundId The round ID to record - /// @param status Sequencer status - /// @param timestamp The L1 block timestamp of status update - function _recordRound(uint80 roundId, bool status, uint64 timestamp) private { - s_feedState = FeedState(roundId, status, timestamp, uint64(block.timestamp)); - s_rounds[roundId] = Round(status, timestamp, uint64(block.timestamp)); - - emit NewRound(roundId, msg.sender, timestamp); - emit AnswerUpdated(_getStatusAnswer(status), roundId, timestamp); - } - - /// @notice Helper function to update when a round was last updated - /// @param roundId The round ID to update - /// @param status Sequencer status - function _updateRound(uint80 roundId, bool status) private { - s_feedState.updatedAt = uint64(block.timestamp); - s_rounds[roundId].updatedAt = uint64(block.timestamp); - emit RoundUpdated(_getStatusAnswer(status), uint64(block.timestamp)); - } - - /// @notice Record a new status and timestamp if it has changed since the last round. - /// @dev This function will revert if not called from `l1Sender` via the L1->L2 messenger. - /// - /// @param status Sequencer status - /// @param timestamp Block timestamp of status update - function updateStatus(bool status, uint64 timestamp) external override { - FeedState memory feedState = s_feedState; - + function _validateSender(address l1Sender) internal view override { if ( - msg.sender != address(s_l2CrossDomainMessenger) || s_l2CrossDomainMessenger.xDomainMessageSender() != s_l1Sender + msg.sender != address(s_l2CrossDomainMessenger) || s_l2CrossDomainMessenger.xDomainMessageSender() != l1Sender ) { revert InvalidSender(); } - - // Ignore if latest recorded timestamp is newer - if (feedState.startedAt > timestamp) { - emit UpdateIgnored(feedState.latestStatus, feedState.startedAt, status, timestamp); - return; - } - - if (feedState.latestStatus == status) { - _updateRound(feedState.latestRoundId, status); - } else { - feedState.latestRoundId += 1; - _recordRound(feedState.latestRoundId, status, timestamp); - } - } - - /// @inheritdoc AggregatorInterface - function latestAnswer() external view override checkAccess returns (int256) { - return _getStatusAnswer(s_feedState.latestStatus); - } - - /// @inheritdoc AggregatorInterface - function latestTimestamp() external view override checkAccess returns (uint256) { - return s_feedState.startedAt; - } - - /// @inheritdoc AggregatorInterface - function latestRound() external view override checkAccess returns (uint256) { - return s_feedState.latestRoundId; - } - - /// @inheritdoc AggregatorInterface - function getAnswer(uint256 roundId) external view override checkAccess returns (int256) { - if (!_isValidRound(roundId)) { - revert NoDataPresent(); - } - - return _getStatusAnswer(s_rounds[uint80(roundId)].status); - } - - /// @inheritdoc AggregatorInterface - function getTimestamp(uint256 roundId) external view override checkAccess returns (uint256) { - if (!_isValidRound(roundId)) { - revert NoDataPresent(); - } - - return s_rounds[uint80(roundId)].startedAt; - } - - /// @inheritdoc AggregatorV3Interface - function getRoundData( - uint80 _roundId - ) - public - view - override - checkAccess - returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) - { - if (!_isValidRound(_roundId)) { - revert NoDataPresent(); - } - - Round memory round = s_rounds[_roundId]; - - return (_roundId, _getStatusAnswer(round.status), uint256(round.startedAt), uint256(round.updatedAt), _roundId); - } - - /// @inheritdoc AggregatorV3Interface - function latestRoundData() - external - view - override - checkAccess - returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) - { - FeedState memory feedState = s_feedState; - - return ( - feedState.latestRoundId, - _getStatusAnswer(feedState.latestStatus), - feedState.startedAt, - feedState.updatedAt, - feedState.latestRoundId - ); } } diff --git a/contracts/src/v0.8/l2ep/dev/scroll/ScrollValidator.sol b/contracts/src/v0.8/l2ep/dev/scroll/ScrollValidator.sol index 9df4a12ac6e..b009c80fdfd 100644 --- a/contracts/src/v0.8/l2ep/dev/scroll/ScrollValidator.sol +++ b/contracts/src/v0.8/l2ep/dev/scroll/ScrollValidator.sol @@ -1,71 +1,31 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.19; +pragma solidity 0.8.24; -import {AggregatorValidatorInterface} from "../../../shared/interfaces/AggregatorValidatorInterface.sol"; -import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; -import {ScrollSequencerUptimeFeedInterface} from "../interfaces/ScrollSequencerUptimeFeedInterface.sol"; +import {ISequencerUptimeFeed} from "../interfaces/ISequencerUptimeFeed.sol"; -import {SimpleWriteAccessController} from "../../../shared/access/SimpleWriteAccessController.sol"; +import {BaseValidator} from "../shared/BaseValidator.sol"; import {IL1MessageQueue} from "@scroll-tech/contracts/L1/rollup/IL1MessageQueue.sol"; import {IL1ScrollMessenger} from "@scroll-tech/contracts/L1/IL1ScrollMessenger.sol"; /// @title ScrollValidator - makes cross chain call to update the Sequencer Uptime Feed on L2 -contract ScrollValidator is TypeAndVersionInterface, AggregatorValidatorInterface, SimpleWriteAccessController { - // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i - address public immutable L1_CROSS_DOMAIN_MESSENGER_ADDRESS; - // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i - address public immutable L2_UPTIME_FEED_ADDR; +contract ScrollValidator is BaseValidator { + string public constant override typeAndVersion = "ScrollValidator 1.1.0-dev"; + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i address public immutable L1_MSG_QUEUE_ADDR; - string public constant override typeAndVersion = "ScrollValidator 1.0.0"; - int256 private constant ANSWER_SEQ_OFFLINE = 1; - uint32 private s_gasLimit; - - /// @notice emitted when gas cost to spend on L2 is updated - /// @param gasLimit updated gas cost - event GasLimitUpdated(uint32 gasLimit); - - /// @param l1CrossDomainMessengerAddress address the L1CrossDomainMessenger contract address - /// @param l2UptimeFeedAddr the address of the ScrollSequencerUptimeFeed contract address - /// @param gasLimit the gasLimit to use for sending a message from L1 to L2 constructor( address l1CrossDomainMessengerAddress, address l2UptimeFeedAddr, address l1MessageQueueAddr, uint32 gasLimit - ) { - // solhint-disable-next-line gas-custom-errors - require(l1CrossDomainMessengerAddress != address(0), "Invalid xDomain Messenger address"); + ) BaseValidator(l1CrossDomainMessengerAddress, l2UptimeFeedAddr, gasLimit) { // solhint-disable-next-line gas-custom-errors require(l1MessageQueueAddr != address(0), "Invalid L1 message queue address"); - // solhint-disable-next-line gas-custom-errors - require(l2UptimeFeedAddr != address(0), "Invalid ScrollSequencerUptimeFeed contract address"); - L1_CROSS_DOMAIN_MESSENGER_ADDRESS = l1CrossDomainMessengerAddress; - L2_UPTIME_FEED_ADDR = l2UptimeFeedAddr; L1_MSG_QUEUE_ADDR = l1MessageQueueAddr; - s_gasLimit = gasLimit; - } - - /// @notice sets the new gas cost to spend when sending cross chain message - /// @param gasLimit the updated gas cost - function setGasLimit(uint32 gasLimit) external onlyOwner { - s_gasLimit = gasLimit; - emit GasLimitUpdated(gasLimit); } - /// @notice fetches the gas cost of sending a cross chain message - function getGasLimit() external view returns (uint32) { - return s_gasLimit; - } - - /// @notice makes this contract payable - /// @dev receives funds: - /// - to use them (if configured) to pay for L2 execution on L1 - /// - when withdrawing funds from L2 xDomain alias address (pay for L2 execution on L2) - receive() external payable {} - /// @notice validate method sends an xDomain L2 tx to update Uptime Feed contract on L2. /// @dev A message is sent using the L1CrossDomainMessenger. This method is accessed controlled. /// @param currentAnswer new aggregator answer - value of 1 considers the sequencer offline. @@ -82,7 +42,7 @@ contract ScrollValidator is TypeAndVersionInterface, AggregatorValidatorInterfac L2_UPTIME_FEED_ADDR, 0, abi.encodeWithSelector( - ScrollSequencerUptimeFeedInterface.updateStatus.selector, + ISequencerUptimeFeed.updateStatus.selector, currentAnswer == ANSWER_SEQ_OFFLINE, uint64(block.timestamp) ), diff --git a/contracts/src/v0.8/l2ep/dev/shared/BaseSequencerUptimeFeed.sol b/contracts/src/v0.8/l2ep/dev/shared/BaseSequencerUptimeFeed.sol new file mode 100644 index 00000000000..15c20504569 --- /dev/null +++ b/contracts/src/v0.8/l2ep/dev/shared/BaseSequencerUptimeFeed.sol @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {ITypeAndVersion} from "../../../shared/interfaces/ITypeAndVersion.sol"; +import {AggregatorInterface} from "../../../shared/interfaces/AggregatorInterface.sol"; +import {AggregatorV3Interface} from "../../../shared/interfaces/AggregatorV3Interface.sol"; +import {AggregatorV2V3Interface} from "../../../shared/interfaces/AggregatorV2V3Interface.sol"; +import {ISequencerUptimeFeed} from "./../interfaces/ISequencerUptimeFeed.sol"; + +import {SimpleReadAccessController} from "../../../shared/access/SimpleReadAccessController.sol"; + +/// @title L2 sequencer uptime status aggregator +/// @notice L2 contract that receives status updates from a specific L1 address, +/// records a new answer if the status changed +abstract contract BaseSequencerUptimeFeed is + ITypeAndVersion, + AggregatorV2V3Interface, + ISequencerUptimeFeed, + SimpleReadAccessController +{ + /// @dev Round info for uptime history + struct Round { + uint64 startedAt; // ─╮ The timestamp at which the round started + uint64 updatedAt; // │ The timestamp at which the round was updated + bool status; // ──────╯ The sequencer status for the round + } + + struct FeedState { + uint80 latestRoundId; // ─╮ The ID of the latest round + uint64 startedAt; // │ The date at which the latest round started + uint64 updatedAt; // │ The date at which the latest round was updated + bool latestStatus; // ────╯ The status of the latest round + } + + /// @notice Sender is not the L2 messenger + error InvalidSender(); + /// @notice Replacement for AggregatorV3Interface "No data present" + error NoDataPresent(); + + event L1SenderTransferred(address indexed from, address indexed to); + /// @dev Emitted when an `updateStatus` call is ignored due to unchanged status or stale timestamp + event UpdateIgnored(bool latestStatus, uint64 latestTimestamp, bool incomingStatus, uint64 incomingTimestamp); + /// @dev Emitted when a updateStatus is called without the status changing + event RoundUpdated(int256 status, uint64 updatedAt); + + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables + uint8 public constant override decimals = 0; + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables + string public constant override description = "L2 Sequencer Uptime Status Feed"; + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables + uint256 public constant override version = 1; + + /// @dev L1 address + address private s_l1Sender; + /// @dev s_latestRoundId == 0 means this contract is uninitialized. + FeedState private s_feedState = FeedState({latestRoundId: 0, latestStatus: false, startedAt: 0, updatedAt: 0}); + mapping(uint80 roundId => Round round) private s_rounds; + + /// @param l1SenderAddress Address of the L1 contract that is permissioned to call this contract + /// @param initialStatus The initial status of the feed + constructor(address l1SenderAddress, bool initialStatus) { + // We neet to allow l1SenderAddress to be zero because this contract is deployed first + // After deploying the validator contract, this contract will be updated with the correct L1 sender address + _setL1Sender(l1SenderAddress); + + // Initialise roundId == 1 as the first round + _recordRound(1, initialStatus, uint64(block.timestamp)); + } + + /// @notice Check if a roundId is valid in this current contract state + /// @dev Mainly used for AggregatorV2V3Interface functions + /// @param roundId Round ID to check + function _isValidRound(uint256 roundId) private view returns (bool) { + return roundId > 0 && roundId <= type(uint80).max && s_feedState.latestRoundId >= roundId; + } + + /// @return L1 sender address + function l1Sender() public view virtual returns (address) { + return s_l1Sender; + } + + /// @notice Set the allowed L1 sender for this contract to a new L1 sender + /// @dev Can be disabled by setting the L1 sender as `address(0)`. Accessible only by owner. + /// @param to new L1 sender that will be allowed to call `updateStatus` on this contract + function transferL1Sender(address to) external virtual onlyOwner { + _setL1Sender(to); + } + + /// @notice internal method that stores the L1 sender + function _setL1Sender(address newSender) internal { + address oldSender = s_l1Sender; + if (oldSender != newSender) { + s_l1Sender = newSender; + emit L1SenderTransferred(oldSender, newSender); + } + } + + /// @dev Returns an AggregatorV2V3Interface compatible answer from status flag + /// @param status The status flag to convert to an aggregator-compatible answer + function _getStatusAnswer(bool status) internal pure returns (int256) { + return status ? int256(1) : int256(0); + } + + /// @notice Helper function to record a round and set the latest feed state. + /// @param roundId The round ID to record + /// @param status Sequencer status + /// @param timestamp The L1 block timestamp of status update + function _recordRound(uint80 roundId, bool status, uint64 timestamp) internal { + s_rounds[roundId] = Round({status: status, startedAt: timestamp, updatedAt: uint64(block.timestamp)}); + s_feedState = FeedState({ + latestRoundId: roundId, + latestStatus: status, + startedAt: timestamp, + updatedAt: uint64(block.timestamp) + }); + + emit NewRound(roundId, msg.sender, timestamp); + emit AnswerUpdated(_getStatusAnswer(status), roundId, timestamp); + } + + /// @notice Helper function to update when a round was last updated + /// @param roundId The round ID to update + /// @param status Sequencer status + function _updateRound(uint80 roundId, bool status) internal { + s_rounds[roundId].updatedAt = uint64(block.timestamp); + s_feedState.updatedAt = uint64(block.timestamp); + emit RoundUpdated(_getStatusAnswer(status), uint64(block.timestamp)); + } + + function _getFeedState() internal view returns (FeedState memory) { + return s_feedState; + } + + /// @inheritdoc AggregatorInterface + function latestAnswer() external view override checkAccess returns (int256) { + return _getStatusAnswer(s_feedState.latestStatus); + } + + /// @inheritdoc AggregatorInterface + function latestTimestamp() external view override checkAccess returns (uint256) { + return s_feedState.startedAt; + } + + /// @inheritdoc AggregatorInterface + function latestRound() external view override checkAccess returns (uint256) { + return s_feedState.latestRoundId; + } + + /// @inheritdoc AggregatorInterface + function getAnswer(uint256 roundId) external view override checkAccess returns (int256) { + if (!_isValidRound(roundId)) { + revert NoDataPresent(); + } + + return _getStatusAnswer(s_rounds[uint80(roundId)].status); + } + + /// @inheritdoc AggregatorInterface + function getTimestamp(uint256 roundId) external view override checkAccess returns (uint256) { + if (!_isValidRound(roundId)) { + revert NoDataPresent(); + } + + return s_rounds[uint80(roundId)].startedAt; + } + + /** + * @notice Record a new status and timestamp if it has changed since the last round. + * @dev This function will revert if not called from `l1Sender` via the L1->L2 messenger. + * + * @param status Sequencer status + * @param timestamp Block timestamp of status update + */ + function updateStatus(bool status, uint64 timestamp) external override { + _validateSender(s_l1Sender); + + FeedState memory feedState = _getFeedState(); + // Ignore if latest recorded timestamp is newer + if (feedState.startedAt > timestamp) { + emit UpdateIgnored(feedState.latestStatus, feedState.startedAt, status, timestamp); + return; + } + + if (feedState.latestStatus == status) { + _updateRound(feedState.latestRoundId, status); + } else { + feedState.latestRoundId += 1; + _recordRound(feedState.latestRoundId, status, timestamp); + } + } + + function _validateSender(address l1Sender) internal virtual; + + /// @inheritdoc AggregatorV3Interface + function getRoundData( + uint80 _roundId + ) + public + view + override + checkAccess + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + if (!_isValidRound(_roundId)) { + revert NoDataPresent(); + } + + Round storage round = s_rounds[_roundId]; + + return (_roundId, _getStatusAnswer(round.status), uint256(round.startedAt), uint256(round.updatedAt), _roundId); + } + + /// @inheritdoc AggregatorV3Interface + function latestRoundData() + external + view + override + checkAccess + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + FeedState storage feedState = s_feedState; + + return ( + feedState.latestRoundId, + _getStatusAnswer(feedState.latestStatus), + feedState.startedAt, + feedState.updatedAt, + feedState.latestRoundId + ); + } +} diff --git a/contracts/src/v0.8/l2ep/dev/shared/BaseValidator.sol b/contracts/src/v0.8/l2ep/dev/shared/BaseValidator.sol new file mode 100644 index 00000000000..9b05b88e98b --- /dev/null +++ b/contracts/src/v0.8/l2ep/dev/shared/BaseValidator.sol @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {AggregatorValidatorInterface} from "../../../shared/interfaces/AggregatorValidatorInterface.sol"; +import {ITypeAndVersion} from "../../../shared/interfaces/ITypeAndVersion.sol"; + +import {SimpleWriteAccessController} from "../../../shared/access/SimpleWriteAccessController.sol"; + +abstract contract BaseValidator is SimpleWriteAccessController, AggregatorValidatorInterface, ITypeAndVersion { + /// @notice emitted when gas cost to spend on L2 is updated + /// @param gasLimit updated gas cost + event GasLimitUpdated(uint32 gasLimit); + + error L1CrossDomainMessengerAddressZero(); + error L2UptimeFeedAddrZero(); + + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i + address public immutable L1_CROSS_DOMAIN_MESSENGER_ADDRESS; + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i + address public immutable L2_UPTIME_FEED_ADDR; + + int256 internal constant ANSWER_SEQ_OFFLINE = 1; + + uint32 internal s_gasLimit; + + /// @param l1CrossDomainMessengerAddress address the L1CrossDomainMessenger contract address + /// @param l2UptimeFeedAddr the address of the ScrollSequencerUptimeFeed contract address + /// @param gasLimit the gasLimit to use for sending a message from L1 to L2 + constructor(address l1CrossDomainMessengerAddress, address l2UptimeFeedAddr, uint32 gasLimit) { + if (l1CrossDomainMessengerAddress == address(0)) { + revert L1CrossDomainMessengerAddressZero(); + } + if (l2UptimeFeedAddr == address(0)) { + revert L2UptimeFeedAddrZero(); + } + + L1_CROSS_DOMAIN_MESSENGER_ADDRESS = l1CrossDomainMessengerAddress; + L2_UPTIME_FEED_ADDR = l2UptimeFeedAddr; + s_gasLimit = gasLimit; + } + + /// @notice fetches the gas cost of sending a cross chain message + function getGasLimit() external view returns (uint32) { + return s_gasLimit; + } + + /// @notice sets the new gas cost to spend when sending cross chain message + /// @param gasLimit the updated gas cost + function setGasLimit(uint32 gasLimit) external onlyOwner { + s_gasLimit = gasLimit; + emit GasLimitUpdated(gasLimit); + } + + /// @notice makes this contract payable + /// @dev receives funds: + /// - to use them (if configured) to pay for L2 execution on L1 + /// - when withdrawing funds from L2 xDomain alias address (pay for L2 execution on L2) + receive() external payable {} +} diff --git a/contracts/src/v0.8/l2ep/dev/zksync/ZKSyncSequencerUptimeFeed.sol b/contracts/src/v0.8/l2ep/dev/zksync/ZKSyncSequencerUptimeFeed.sol new file mode 100644 index 00000000000..0074a0277d1 --- /dev/null +++ b/contracts/src/v0.8/l2ep/dev/zksync/ZKSyncSequencerUptimeFeed.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {BaseSequencerUptimeFeed} from "../shared/BaseSequencerUptimeFeed.sol"; + +import {AddressAliasHelper} from "../../../vendor/arb-bridge-eth/v0.8.0-custom/contracts/libraries/AddressAliasHelper.sol"; + +/// @title ZKSyncSequencerUptimeFeed - L2 sequencer uptime status aggregator +/// @notice L2 contract that receives status updates from a specific L1 address, +/// records a new answer if the status changed +contract ZKSyncSequencerUptimeFeed is BaseSequencerUptimeFeed { + string public constant override typeAndVersion = "ZKSyncSequencerUptimeFeed 1.1.0-dev"; + + /// @param l1SenderAddress Address of the L1 contract that is permissioned to call this contract + /// @param initialStatus The initial status of the feed + constructor(address l1SenderAddress, bool initialStatus) BaseSequencerUptimeFeed(l1SenderAddress, initialStatus) {} + + function _validateSender(address l1Sender) internal view override { + address aliasedL1Sender = AddressAliasHelper.applyL1ToL2Alias(l1Sender); + + if (msg.sender != aliasedL1Sender) { + revert InvalidSender(); + } + } +} diff --git a/contracts/src/v0.8/l2ep/dev/zksync/ZKSyncValidator.sol b/contracts/src/v0.8/l2ep/dev/zksync/ZKSyncValidator.sol new file mode 100644 index 00000000000..10f68ce286d --- /dev/null +++ b/contracts/src/v0.8/l2ep/dev/zksync/ZKSyncValidator.sol @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {ISequencerUptimeFeed} from "./../interfaces/ISequencerUptimeFeed.sol"; + +import {BaseValidator} from "../shared/BaseValidator.sol"; + +import {IBridgehub, L2TransactionRequestDirect} from "@zksync/contracts/l1-contracts/contracts/bridgehub/IBridgehub.sol"; + +/// @title ZKSyncValidator - makes cross chain call to update the Sequencer Uptime Feed on L2 +contract ZKSyncValidator is BaseValidator { + /// Contract state variables + string public constant override typeAndVersion = "ZKSyncValidator 1.1.0-dev"; + uint32 private constant ZKSYNC_TEST_NET_CHAIN_ID = 300; + uint32 private constant ZKSYNC_MAIN_NET_CHAIN_ID = 324; + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i + uint32 private immutable CHAIN_ID; + /// @dev how much l2 gas each byte of pubdata costs + uint32 private s_l2GasPerPubdataByteLimit; + + /// @notice emitted when the gas per pubdata byte limit is updated + /// @param l2GasPerPubdataByteLimit updated gas per pubdata byte limit + event GasPerPubdataByteLimitUpdated(uint32 l2GasPerPubdataByteLimit); + + /// @notice ChainID is not a valid value + error InvalidChainID(); + + /// @param l1CrossDomainMessengerAddress address the Bridgehub contract address + /// @param l2UptimeFeedAddr the address of the SequencerUptimeFeedInterface contract address + /// @param gasLimit the gasLimit to use for sending a message from L1 to L2 + constructor( + address l1CrossDomainMessengerAddress, + address l2UptimeFeedAddr, + uint32 gasLimit, + uint32 chainId, + uint32 l2GasPerPubdataByteLimit + ) BaseValidator(l1CrossDomainMessengerAddress, l2UptimeFeedAddr, gasLimit) { + if (chainId != ZKSYNC_TEST_NET_CHAIN_ID && chainId != ZKSYNC_MAIN_NET_CHAIN_ID) { + revert InvalidChainID(); + } + + s_l2GasPerPubdataByteLimit = l2GasPerPubdataByteLimit; + CHAIN_ID = chainId; + } + + /// @notice sets the l2GasPerPubdataByteLimit for the L2 transaction request + /// @param l2GasPerPubdataByteLimit the updated l2GasPerPubdataByteLimit + function setL2GasPerPubdataByteLimit(uint32 l2GasPerPubdataByteLimit) external onlyOwner { + if (s_l2GasPerPubdataByteLimit != l2GasPerPubdataByteLimit) { + s_l2GasPerPubdataByteLimit = l2GasPerPubdataByteLimit; + emit GasPerPubdataByteLimitUpdated(l2GasPerPubdataByteLimit); + } + } + + /// @notice fetches the l2GasPerPubdataByteLimit for the L2 transaction request + function getL2GasPerPubdataByteLimit() external view returns (uint32) { + return s_l2GasPerPubdataByteLimit; + } + + /// @notice fetches the chain id + function getChainId() external view returns (uint32) { + return CHAIN_ID; + } + + /// @notice validate method sends an xDomain L2 tx to update Uptime Feed contract on L2. + /// @dev A message is sent using the Bridgehub. This method is accessed controlled. + /// @param currentAnswer new aggregator answer - value of 1 considers the sequencer offline. + function validate( + uint256 /* previousRoundId */, + int256 /* previousAnswer */, + uint256 /* currentRoundId */, + int256 currentAnswer + ) external override checkAccess returns (bool) { + IBridgehub bridgeHub = IBridgehub(L1_CROSS_DOMAIN_MESSENGER_ADDRESS); + + uint256 transactionBaseCostEstimate = bridgeHub.l2TransactionBaseCost( + CHAIN_ID, + tx.gasprice, + s_gasLimit, + s_l2GasPerPubdataByteLimit + ); + + L2TransactionRequestDirect memory l2TransactionRequestDirect = L2TransactionRequestDirect({ + chainId: CHAIN_ID, + mintValue: transactionBaseCostEstimate, + l2Contract: L2_UPTIME_FEED_ADDR, + l2Value: 0, + l2Calldata: abi.encodeWithSelector( + ISequencerUptimeFeed.updateStatus.selector, + currentAnswer == ANSWER_SEQ_OFFLINE, + uint64(block.timestamp) + ), + l2GasLimit: s_gasLimit, + l2GasPerPubdataByteLimit: s_l2GasPerPubdataByteLimit, + factoryDeps: new bytes[](0), + refundRecipient: msg.sender + }); + + // Make the xDomain call + bridgeHub.requestL2TransactionDirect{value: transactionBaseCostEstimate}(l2TransactionRequestDirect); + + return true; + } +} diff --git a/contracts/src/v0.8/l2ep/test/mocks/MockAggregatorV2V3.sol b/contracts/src/v0.8/l2ep/test/mocks/MockAggregatorV2V3.sol index c4e2f710300..52019324f59 100644 --- a/contracts/src/v0.8/l2ep/test/mocks/MockAggregatorV2V3.sol +++ b/contracts/src/v0.8/l2ep/test/mocks/MockAggregatorV2V3.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.9; +pragma solidity ^0.8.24; import {AggregatorV2V3Interface} from "../../../shared/interfaces/AggregatorV2V3Interface.sol"; diff --git a/contracts/src/v0.8/l2ep/test/mocks/scroll/MockScrollL1CrossDomainMessenger.sol b/contracts/src/v0.8/l2ep/test/mocks/scroll/MockScrollL1CrossDomainMessenger.sol index e63847d6557..42147fbd91e 100644 --- a/contracts/src/v0.8/l2ep/test/mocks/scroll/MockScrollL1CrossDomainMessenger.sol +++ b/contracts/src/v0.8/l2ep/test/mocks/scroll/MockScrollL1CrossDomainMessenger.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.9; +pragma solidity ^0.8.24; import {IL1ScrollMessenger} from "@scroll-tech/contracts/L1/IL1ScrollMessenger.sol"; diff --git a/contracts/src/v0.8/l2ep/test/mocks/scroll/MockScrollL1MessageQueue.sol b/contracts/src/v0.8/l2ep/test/mocks/scroll/MockScrollL1MessageQueue.sol index 1700bcbe168..e43f1bf1366 100644 --- a/contracts/src/v0.8/l2ep/test/mocks/scroll/MockScrollL1MessageQueue.sol +++ b/contracts/src/v0.8/l2ep/test/mocks/scroll/MockScrollL1MessageQueue.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.19; +pragma solidity 0.8.24; import {IL1MessageQueue} from "@scroll-tech/contracts/L1/rollup/IL1MessageQueue.sol"; diff --git a/contracts/src/v0.8/l2ep/test/mocks/scroll/MockScrollL2CrossDomainMessenger.sol b/contracts/src/v0.8/l2ep/test/mocks/scroll/MockScrollL2CrossDomainMessenger.sol index 66400b7d305..af0e0b5ca59 100644 --- a/contracts/src/v0.8/l2ep/test/mocks/scroll/MockScrollL2CrossDomainMessenger.sol +++ b/contracts/src/v0.8/l2ep/test/mocks/scroll/MockScrollL2CrossDomainMessenger.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.9; +pragma solidity ^0.8.24; import {IL2ScrollMessenger} from "@scroll-tech/contracts/L2/IL2ScrollMessenger.sol"; diff --git a/contracts/src/v0.8/l2ep/test/mocks/zksync/MockZKSyncL1Bridge.sol b/contracts/src/v0.8/l2ep/test/mocks/zksync/MockZKSyncL1Bridge.sol new file mode 100644 index 00000000000..b46b9d9fdf0 --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/mocks/zksync/MockZKSyncL1Bridge.sol @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import {IBridgehub, L2TransactionRequestDirect, L2TransactionRequestTwoBridgesOuter} from "@zksync/contracts/l1-contracts/contracts/bridgehub/IBridgehub.sol"; +import {IL1SharedBridge} from "@zksync/contracts/l1-contracts/contracts/bridge/interfaces/IL1SharedBridge.sol"; +import {L2Message, L2Log, TxStatus} from "@zksync/contracts/l1-contracts/contracts/common/Messaging.sol"; + +contract MockBridgehub is IBridgehub { + address public pendingAdmin; + address public admin; + address public sharedBridgeAddr; + + mapping(address stateTransitionManager => bool stateTransitionManagerIsRegistered) + public registeredStateTransitionManagers; + mapping(uint256 chainId => address stateTransitionManagerAddress) public stateTransitionManagers; + mapping(address baseToken => bool tokenIsRegistered) public registeredTokens; + mapping(uint256 chainId => address baseToken) public baseTokens; + mapping(uint256 chainId => address hyperChain) public hyperchains; + + /// Generic error for unauthorized actions + error NotAuthorized(string msg); + + /// Fake event that will get emitted when `requestL2TransactionDirect` is called + event SentMessage(address indexed sender, bytes message); + + /// Admin functions + function setPendingAdmin(address _newPendingAdmin) external override { + emit NewPendingAdmin(pendingAdmin, _newPendingAdmin); + pendingAdmin = _newPendingAdmin; + } + + function acceptAdmin() external override { + if (msg.sender != pendingAdmin) { + revert NotAuthorized("Only pending admin can accept"); + } + + emit NewAdmin(admin, pendingAdmin); + admin = pendingAdmin; + pendingAdmin = address(0); + } + + /// Getters + function stateTransitionManagerIsRegistered(address _stateTransitionManager) external view override returns (bool) { + return registeredStateTransitionManagers[_stateTransitionManager]; + } + + function stateTransitionManager(uint256 _chainId) external view override returns (address) { + return stateTransitionManagers[_chainId]; + } + + function tokenIsRegistered(address _baseToken) external view override returns (bool) { + return registeredTokens[_baseToken]; + } + + function baseToken(uint256 _chainId) external view override returns (address) { + return baseTokens[_chainId]; + } + + function sharedBridge() external view override returns (IL1SharedBridge) { + return IL1SharedBridge(sharedBridgeAddr); + } + + function getHyperchain(uint256 _chainId) external view override returns (address) { + return hyperchains[_chainId]; + } + + /// Mailbox forwarder + function proveL2MessageInclusion( + uint256, + uint256, + uint256, + L2Message calldata, + bytes32[] calldata + ) external pure override returns (bool) { + return true; + } + + function proveL2LogInclusion( + uint256, + uint256, + uint256, + L2Log memory, + bytes32[] calldata + ) external pure override returns (bool) { + return true; + } + + function proveL1ToL2TransactionStatus( + uint256, + bytes32, + uint256, + uint256, + uint16, + bytes32[] calldata, + TxStatus + ) external pure override returns (bool) { + return true; + } + + function requestL2TransactionDirect( + L2TransactionRequestDirect calldata txRequest + ) external payable override returns (bytes32) { + emit SentMessage(msg.sender, txRequest.l2Calldata); + return keccak256(abi.encodePacked("L2TransactionDirect")); + } + + function requestL2TransactionTwoBridges( + L2TransactionRequestTwoBridgesOuter calldata + ) external payable override returns (bytes32) { + return keccak256(abi.encodePacked("L2TransactionTwoBridges")); + } + + function l2TransactionBaseCost(uint256, uint256, uint256, uint256) external pure override returns (uint256) { + return 0; + } + + /// Registry + function createNewChain( + uint256 _chainId, + address _stateTransitionManager, + address _baseToken, + uint256, + address, + bytes calldata + ) external override returns (uint256 chainId) { + hyperchains[_chainId] = _stateTransitionManager; + baseTokens[_chainId] = _baseToken; + emit NewChain(_chainId, _stateTransitionManager, address(this)); + return _chainId; + } + + function addStateTransitionManager(address _stateTransitionManager) external override { + registeredStateTransitionManagers[_stateTransitionManager] = true; + } + + function removeStateTransitionManager(address _stateTransitionManager) external override { + registeredStateTransitionManagers[_stateTransitionManager] = false; + } + + function addToken(address _token) external override { + registeredTokens[_token] = true; + } + + function setSharedBridge(address _sharedBridgeAddr) external override { + sharedBridgeAddr = _sharedBridgeAddr; + } +} diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/L2EPTest.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/L2EPTest.t.sol index 561e32be1a2..93640f4bcb4 100644 --- a/contracts/src/v0.8/l2ep/test/v1_0_0/L2EPTest.t.sol +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/L2EPTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.19; +pragma solidity ^0.8.24; import {Greeter} from "../../../tests/Greeter.sol"; @@ -13,21 +13,6 @@ contract L2EPTest is Test { address internal s_eoaValidator = vm.addr(0x3); address internal s_deployerAddr = vm.addr(0x4); - /// @param expectedGasUsage - the expected gas usage - /// @param startGasUsage - the gas usage before the code of interest is run - /// @param finalGasUsage - the gas usage after the code of interest is run - /// @param deviation - the amount of gas that the actual usage is allowed to deviate by (e.g. (expectedGas - deviation) <= actualGasUsage <= (expectedGas + deviation)) - function assertGasUsageIsCloseTo( - uint256 expectedGasUsage, - uint256 startGasUsage, - uint256 finalGasUsage, - uint256 deviation - ) public { - uint256 gasUsed = (startGasUsage - finalGasUsage) * tx.gasprice; - assertLe(gasUsed, expectedGasUsage + deviation); - assertGe(gasUsed, expectedGasUsage - deviation); - } - /// @param selector - the function selector /// @param greeterAddr - the address of the Greeter contract /// @param message - the new greeting message, which will be passed as an argument to Greeter#setGreeting diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumCrossDomainForwarder.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumCrossDomainForwarder.t.sol index be3851c5b5d..cff9b953e2e 100644 --- a/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumCrossDomainForwarder.t.sol +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumCrossDomainForwarder.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.19; +pragma solidity 0.8.24; import {ArbitrumCrossDomainForwarder} from "../../../dev/arbitrum/ArbitrumCrossDomainForwarder.sol"; import {Greeter} from "../../../../tests/Greeter.sol"; diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumCrossDomainGovernor.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumCrossDomainGovernor.t.sol index c5b8adaf7d2..610f49f16c4 100644 --- a/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumCrossDomainGovernor.t.sol +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumCrossDomainGovernor.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.19; +pragma solidity 0.8.24; import {ArbitrumCrossDomainGovernor} from "../../../dev/arbitrum/ArbitrumCrossDomainGovernor.sol"; import {Greeter} from "../../../../tests/Greeter.sol"; diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumSequencerUptimeFeed.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumSequencerUptimeFeed.t.sol index 5565409709b..e308ead3432 100644 --- a/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumSequencerUptimeFeed.t.sol +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumSequencerUptimeFeed.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.19; +pragma solidity 0.8.24; import {SimpleWriteAccessController} from "../../../../shared/access/SimpleWriteAccessController.sol"; import {ArbitrumSequencerUptimeFeed} from "../../../dev/arbitrum/ArbitrumSequencerUptimeFeed.sol"; 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 index 504635540ce..ab872991749 100644 --- 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 @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.19; +pragma solidity 0.8.24; import {AccessControllerInterface} from "../../../../shared/interfaces/AccessControllerInterface.sol"; diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismCrossDomainForwarder.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismCrossDomainForwarder.t.sol index d5c482dce98..c0e82ab8d5e 100644 --- a/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismCrossDomainForwarder.t.sol +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismCrossDomainForwarder.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.19; +pragma solidity 0.8.24; import {OptimismCrossDomainForwarder} from "../../../dev/optimism/OptimismCrossDomainForwarder.sol"; import {MockOVMCrossDomainMessenger} from "../../mocks/optimism/MockOVMCrossDomainMessenger.sol"; diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismCrossDomainGovernor.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismCrossDomainGovernor.t.sol index e1a5aef95a1..8f8fb9d7e7c 100644 --- a/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismCrossDomainGovernor.t.sol +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismCrossDomainGovernor.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.19; +pragma solidity 0.8.24; import {OptimismCrossDomainGovernor} from "../../../dev/optimism/OptimismCrossDomainGovernor.sol"; import {MockOVMCrossDomainMessenger} from "../../mocks/optimism/MockOVMCrossDomainMessenger.sol"; diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismSequencerUptimeFeed.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismSequencerUptimeFeed.t.sol index 071d6e5b42e..eec9657ac14 100644 --- a/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismSequencerUptimeFeed.t.sol +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismSequencerUptimeFeed.t.sol @@ -1,9 +1,10 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.19; +pragma solidity 0.8.24; import {MockOptimismL1CrossDomainMessenger} from "../../../../tests/MockOptimismL1CrossDomainMessenger.sol"; import {MockOptimismL2CrossDomainMessenger} from "../../../../tests/MockOptimismL2CrossDomainMessenger.sol"; import {OptimismSequencerUptimeFeed} from "../../../dev/optimism/OptimismSequencerUptimeFeed.sol"; +import {BaseSequencerUptimeFeed} from "../../../dev/shared/BaseSequencerUptimeFeed.sol"; import {FeedConsumer} from "../../../../tests/FeedConsumer.sol"; import {L2EPTest} from "../L2EPTest.t.sol"; @@ -61,7 +62,7 @@ contract OptimismSequencerUptimeFeed_UpdateStatus is OptimismSequencerUptimeFeed vm.startPrank(s_strangerAddr, s_strangerAddr); // Tries to update the status from an unauthorized account - vm.expectRevert(OptimismSequencerUptimeFeed.InvalidSender.selector); + vm.expectRevert(BaseSequencerUptimeFeed.InvalidSender.selector); s_optimismSequencerUptimeFeed.updateStatus(true, uint64(1)); } @@ -74,7 +75,7 @@ contract OptimismSequencerUptimeFeed_UpdateStatus is OptimismSequencerUptimeFeed s_mockOptimismL2CrossDomainMessenger.setSender(s_strangerAddr); // Tries to update the status from an unauthorized account - vm.expectRevert(OptimismSequencerUptimeFeed.InvalidSender.selector); + vm.expectRevert(BaseSequencerUptimeFeed.InvalidSender.selector); s_optimismSequencerUptimeFeed.updateStatus(true, uint64(1)); } @@ -257,7 +258,7 @@ contract OptimismSequencerUptimeFeed_AggregatorV3Interface is OptimismSequencerU vm.startPrank(s_l1OwnerAddr, s_l1OwnerAddr); // Gets data from a round that has not happened yet - vm.expectRevert(OptimismSequencerUptimeFeed.NoDataPresent.selector); + vm.expectRevert(BaseSequencerUptimeFeed.NoDataPresent.selector); s_optimismSequencerUptimeFeed.getRoundData(2); } @@ -267,7 +268,7 @@ contract OptimismSequencerUptimeFeed_AggregatorV3Interface is OptimismSequencerU vm.startPrank(s_l1OwnerAddr, s_l1OwnerAddr); // Gets data from a round that has not happened yet - vm.expectRevert(OptimismSequencerUptimeFeed.NoDataPresent.selector); + vm.expectRevert(BaseSequencerUptimeFeed.NoDataPresent.selector); s_optimismSequencerUptimeFeed.getAnswer(2); } @@ -277,7 +278,7 @@ contract OptimismSequencerUptimeFeed_AggregatorV3Interface is OptimismSequencerU vm.startPrank(s_l1OwnerAddr, s_l1OwnerAddr); // Gets data from a round that has not happened yet - vm.expectRevert(OptimismSequencerUptimeFeed.NoDataPresent.selector); + vm.expectRevert(BaseSequencerUptimeFeed.NoDataPresent.selector); s_optimismSequencerUptimeFeed.getTimestamp(2); } } diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismValidator.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismValidator.t.sol index 9364396817a..59395bf5d8b 100644 --- a/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismValidator.t.sol +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismValidator.t.sol @@ -1,5 +1,7 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.19; +pragma solidity 0.8.24; + +import {ISequencerUptimeFeed} from "../../../dev/interfaces/ISequencerUptimeFeed.sol"; import {MockOptimismL1CrossDomainMessenger} from "../../../../tests/MockOptimismL1CrossDomainMessenger.sol"; import {MockOptimismL2CrossDomainMessenger} from "../../../../tests/MockOptimismL2CrossDomainMessenger.sol"; @@ -73,7 +75,7 @@ contract OptimismValidator_Validate is OptimismValidatorTest { emit SentMessage( L2_SEQ_STATUS_RECORDER_ADDRESS, // target address(s_optimismValidator), // sender - abi.encodeWithSelector(OptimismSequencerUptimeFeed.updateStatus.selector, false, futureTimestampInSeconds), // message + abi.encodeWithSelector(ISequencerUptimeFeed.updateStatus.selector, false, futureTimestampInSeconds), // message 0, // nonce INIT_GAS_LIMIT // gas limit ); @@ -97,7 +99,7 @@ contract OptimismValidator_Validate is OptimismValidatorTest { emit SentMessage( L2_SEQ_STATUS_RECORDER_ADDRESS, // target address(s_optimismValidator), // sender - abi.encodeWithSelector(OptimismSequencerUptimeFeed.updateStatus.selector, true, futureTimestampInSeconds), // message + abi.encodeWithSelector(ISequencerUptimeFeed.updateStatus.selector, true, futureTimestampInSeconds), // message 0, // nonce INIT_GAS_LIMIT // gas limit ); diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollCrossDomainForwarder.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollCrossDomainForwarder.t.sol index f921fa9242e..e34e84f4006 100644 --- a/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollCrossDomainForwarder.t.sol +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollCrossDomainForwarder.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.19; +pragma solidity 0.8.24; import {MockScrollCrossDomainMessenger} from "../../mocks/scroll/MockScrollCrossDomainMessenger.sol"; import {ScrollCrossDomainForwarder} from "../../../dev/scroll/ScrollCrossDomainForwarder.sol"; diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollCrossDomainGovernor.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollCrossDomainGovernor.t.sol index 9c444604946..8c3d56d1560 100644 --- a/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollCrossDomainGovernor.t.sol +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollCrossDomainGovernor.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.19; +pragma solidity 0.8.24; import {MockScrollCrossDomainMessenger} from "../../mocks/scroll/MockScrollCrossDomainMessenger.sol"; import {ScrollCrossDomainGovernor} from "../../../dev/scroll/ScrollCrossDomainGovernor.sol"; diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollSequencerUptimeFeed.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollSequencerUptimeFeed.t.sol index 3aac50e7c1e..0968c69415f 100644 --- a/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollSequencerUptimeFeed.t.sol +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollSequencerUptimeFeed.t.sol @@ -1,9 +1,10 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.19; +pragma solidity 0.8.24; import {MockScrollL1CrossDomainMessenger} from "../../mocks/scroll/MockScrollL1CrossDomainMessenger.sol"; import {MockScrollL2CrossDomainMessenger} from "../../mocks/scroll/MockScrollL2CrossDomainMessenger.sol"; import {ScrollSequencerUptimeFeed} from "../../../dev/scroll/ScrollSequencerUptimeFeed.sol"; +import {BaseSequencerUptimeFeed} from "../../../dev/shared/BaseSequencerUptimeFeed.sol"; import {FeedConsumer} from "../../../../tests/FeedConsumer.sol"; import {L2EPTest} from "../L2EPTest.t.sol"; @@ -65,7 +66,7 @@ contract ScrollSequencerUptimeFeed_UpdateStatus is ScrollSequencerUptimeFeedTest vm.startPrank(s_strangerAddr, s_strangerAddr); // Tries to update the status from an unauthorized account - vm.expectRevert(ScrollSequencerUptimeFeed.InvalidSender.selector); + vm.expectRevert(BaseSequencerUptimeFeed.InvalidSender.selector); s_scrollSequencerUptimeFeed.updateStatus(true, uint64(1)); } @@ -78,7 +79,7 @@ contract ScrollSequencerUptimeFeed_UpdateStatus is ScrollSequencerUptimeFeedTest s_mockScrollL2CrossDomainMessenger.setSender(s_strangerAddr); // Tries to update the status from an unauthorized account - vm.expectRevert(ScrollSequencerUptimeFeed.InvalidSender.selector); + vm.expectRevert(BaseSequencerUptimeFeed.InvalidSender.selector); s_scrollSequencerUptimeFeed.updateStatus(true, uint64(1)); } @@ -261,7 +262,7 @@ contract ScrollSequencerUptimeFeed_AggregatorV3Interface is ScrollSequencerUptim vm.startPrank(s_l1OwnerAddr, s_l1OwnerAddr); // Gets data from a round that has not happened yet - vm.expectRevert(ScrollSequencerUptimeFeed.NoDataPresent.selector); + vm.expectRevert(BaseSequencerUptimeFeed.NoDataPresent.selector); s_scrollSequencerUptimeFeed.getRoundData(2); } @@ -271,7 +272,7 @@ contract ScrollSequencerUptimeFeed_AggregatorV3Interface is ScrollSequencerUptim vm.startPrank(s_l1OwnerAddr, s_l1OwnerAddr); // Gets data from a round that has not happened yet - vm.expectRevert(ScrollSequencerUptimeFeed.NoDataPresent.selector); + vm.expectRevert(BaseSequencerUptimeFeed.NoDataPresent.selector); s_scrollSequencerUptimeFeed.getAnswer(2); } @@ -281,7 +282,7 @@ contract ScrollSequencerUptimeFeed_AggregatorV3Interface is ScrollSequencerUptim vm.startPrank(s_l1OwnerAddr, s_l1OwnerAddr); // Gets data from a round that has not happened yet - vm.expectRevert(ScrollSequencerUptimeFeed.NoDataPresent.selector); + vm.expectRevert(BaseSequencerUptimeFeed.NoDataPresent.selector); s_scrollSequencerUptimeFeed.getTimestamp(2); } } diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollValidator.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollValidator.t.sol index f425ca1c6e5..3d5298d5184 100644 --- a/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollValidator.t.sol +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollValidator.t.sol @@ -1,5 +1,7 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.19; +pragma solidity 0.8.24; + +import {ISequencerUptimeFeed} from "../../../dev/interfaces/ISequencerUptimeFeed.sol"; import {MockScrollL1CrossDomainMessenger} from "../../mocks/scroll/MockScrollL1CrossDomainMessenger.sol"; import {MockScrollL2CrossDomainMessenger} from "../../mocks/scroll/MockScrollL2CrossDomainMessenger.sol"; @@ -87,7 +89,7 @@ contract ScrollValidator_Validate is ScrollValidatorTest { 0, // value 0, // nonce INIT_GAS_LIMIT, // gas limit - abi.encodeWithSelector(ScrollSequencerUptimeFeed.updateStatus.selector, false, futureTimestampInSeconds) // message + abi.encodeWithSelector(ISequencerUptimeFeed.updateStatus.selector, false, futureTimestampInSeconds) // message ); // Runs the function (which produces the event to test) @@ -112,7 +114,7 @@ contract ScrollValidator_Validate is ScrollValidatorTest { 0, // value 0, // nonce INIT_GAS_LIMIT, // gas limit - abi.encodeWithSelector(ScrollSequencerUptimeFeed.updateStatus.selector, true, futureTimestampInSeconds) // message + abi.encodeWithSelector(ISequencerUptimeFeed.updateStatus.selector, true, futureTimestampInSeconds) // message ); // Runs the function (which produces the event to test) diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/zksync/ZKSyncSequencerUptimeFeed.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/zksync/ZKSyncSequencerUptimeFeed.t.sol new file mode 100644 index 00000000000..6d90b3973e9 --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/zksync/ZKSyncSequencerUptimeFeed.t.sol @@ -0,0 +1,291 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import {AddressAliasHelper} from "../../../../vendor/arb-bridge-eth/v0.8.0-custom/contracts/libraries/AddressAliasHelper.sol"; +import {ZKSyncSequencerUptimeFeed} from "../../../dev/zksync/ZKSyncSequencerUptimeFeed.sol"; +import {BaseSequencerUptimeFeed} from "../../../dev/shared/BaseSequencerUptimeFeed.sol"; +import {FeedConsumer} from "../../../../tests/FeedConsumer.sol"; +import {L2EPTest} from "../L2EPTest.t.sol"; + +contract ZKSyncSequencerUptimeFeedTest is L2EPTest { + /// Helper Variables + address internal s_aliasedL1OwnerAddress = AddressAliasHelper.applyL1ToL2Alias(s_l1OwnerAddr); + + /// L2EP contracts + ZKSyncSequencerUptimeFeed internal s_zksyncSequencerUptimeFeed; + + /// Events + event UpdateIgnored(bool latestStatus, uint64 latestTimestamp, bool incomingStatus, uint64 incomingTimestamp); + event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 updatedAt); + event RoundUpdated(int256 status, uint64 updatedAt); + + /// Setup + function setUp() public { + // Deploys contracts + s_zksyncSequencerUptimeFeed = new ZKSyncSequencerUptimeFeed(s_l1OwnerAddr, false); + } +} + +contract ZKSyncSequencerUptimeFeed_Constructor is ZKSyncSequencerUptimeFeedTest { + /// @notice it should have been deployed with the correct initial state + function test_InitialState() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l1OwnerAddr, s_l1OwnerAddr); + + // Checks L1 sender + address actualL1Addr = s_zksyncSequencerUptimeFeed.l1Sender(); + assertEq(actualL1Addr, s_l1OwnerAddr); + + // Checks latest round data + (uint80 roundId, int256 answer, , , ) = s_zksyncSequencerUptimeFeed.latestRoundData(); + assertEq(roundId, 1); + assertEq(answer, 0); + } +} + +contract ZKSyncSequencerUptimeFeed_UpdateStatus is ZKSyncSequencerUptimeFeedTest { + /// @notice it should revert if called by an unauthorized account + function test_RevertIfNotL2CrossDomainMessengerAddr() public { + // Sets msg.sender and tx.origin to an unauthorized address + vm.startPrank(s_strangerAddr, s_strangerAddr); + + // Tries to update the status from an unauthorized account + vm.expectRevert(BaseSequencerUptimeFeed.InvalidSender.selector); + s_zksyncSequencerUptimeFeed.updateStatus(true, uint64(1)); + } + + /// @notice it should update status when status has not changed and incoming timestamp is the same as latest + function test_UpdateStatusWhenNoChange() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_aliasedL1OwnerAddress, s_aliasedL1OwnerAddress); + + // Fetches the latest timestamp + uint256 timestamp = s_zksyncSequencerUptimeFeed.latestTimestamp(); + + // Submits a status update + vm.expectEmit(); + emit AnswerUpdated(1, 2, timestamp); + s_zksyncSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + assertEq(s_zksyncSequencerUptimeFeed.latestAnswer(), 1); + assertEq(s_zksyncSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + + // Stores the current round data before updating it + ( + uint80 roundIdBeforeUpdate, + int256 answerBeforeUpdate, + uint256 startedAtBeforeUpdate, + , + uint80 answeredInRoundBeforeUpdate + ) = s_zksyncSequencerUptimeFeed.latestRoundData(); + + // Submit another status update with the same status + vm.expectEmit(); + emit RoundUpdated(1, uint64(block.timestamp)); + s_zksyncSequencerUptimeFeed.updateStatus(true, uint64(timestamp + 200)); + assertEq(s_zksyncSequencerUptimeFeed.latestAnswer(), 1); + assertEq(s_zksyncSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + + // Stores the current round data after updating it + ( + uint80 roundIdAfterUpdate, + int256 answerAfterUpdate, + uint256 startedAtAfterUpdate, + uint256 updatedAtAfterUpdate, + uint80 answeredInRoundAfterUpdate + ) = s_zksyncSequencerUptimeFeed.latestRoundData(); + + // Verifies the latest round data has been properly updated + assertEq(roundIdAfterUpdate, roundIdBeforeUpdate); + assertEq(answerAfterUpdate, answerBeforeUpdate); + assertEq(startedAtAfterUpdate, startedAtBeforeUpdate); + assertEq(answeredInRoundAfterUpdate, answeredInRoundBeforeUpdate); + assertEq(updatedAtAfterUpdate, block.timestamp); + } + + /// @notice it should update status when status has changed and incoming timestamp is newer than the latest + function test_UpdateStatusWhenStatusChangeAndTimeChange() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_aliasedL1OwnerAddress, s_aliasedL1OwnerAddress); + + // Submits a status update + uint256 timestamp = s_zksyncSequencerUptimeFeed.latestTimestamp(); + vm.expectEmit(); + emit AnswerUpdated(1, 2, timestamp); + s_zksyncSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + assertEq(s_zksyncSequencerUptimeFeed.latestAnswer(), 1); + assertEq(s_zksyncSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + + // Submit another status update, different status, newer timestamp should update + timestamp = timestamp + 200; + vm.expectEmit(); + emit AnswerUpdated(0, 3, timestamp); + s_zksyncSequencerUptimeFeed.updateStatus(false, uint64(timestamp)); + assertEq(s_zksyncSequencerUptimeFeed.latestAnswer(), 0); + assertEq(s_zksyncSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + } + + /// @notice it should update status when status has changed and incoming timestamp is the same as latest + function test_UpdateStatusWhenStatusChangeAndNoTimeChange() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_aliasedL1OwnerAddress, s_aliasedL1OwnerAddress); + + // Fetches the latest timestamp + uint256 timestamp = s_zksyncSequencerUptimeFeed.latestTimestamp(); + + // Submits a status update + vm.expectEmit(); + emit AnswerUpdated(1, 2, timestamp); + s_zksyncSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + assertEq(s_zksyncSequencerUptimeFeed.latestAnswer(), 1); + assertEq(s_zksyncSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + + // Submit another status update, different status, same timestamp should update + vm.expectEmit(); + emit AnswerUpdated(0, 3, timestamp); + s_zksyncSequencerUptimeFeed.updateStatus(false, uint64(timestamp)); + assertEq(s_zksyncSequencerUptimeFeed.latestAnswer(), 0); + assertEq(s_zksyncSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + } + + /// @notice it should ignore out-of-order updates + function test_IgnoreOutOfOrderUpdates() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_aliasedL1OwnerAddress, s_aliasedL1OwnerAddress); + + // Submits a status update + uint256 timestamp = s_zksyncSequencerUptimeFeed.latestTimestamp() + 10000; + vm.expectEmit(); + emit AnswerUpdated(1, 2, timestamp); + s_zksyncSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + assertEq(s_zksyncSequencerUptimeFeed.latestAnswer(), 1); + assertEq(s_zksyncSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + + // Update with different status, but stale timestamp, should be ignored + timestamp = timestamp - 1000; + vm.expectEmit(false, false, false, false); + emit UpdateIgnored(true, 0, true, 0); // arguments are dummy values + // TODO: how can we check that an AnswerUpdated event was NOT emitted + s_zksyncSequencerUptimeFeed.updateStatus(false, uint64(timestamp)); + } +} + +contract ZKSyncSequencerUptimeFeed_AggregatorV3Interface is ZKSyncSequencerUptimeFeedTest { + /// @notice it should return valid answer from getRoundData and latestRoundData + function test_AggregatorV3Interface() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_aliasedL1OwnerAddress, s_aliasedL1OwnerAddress); + + // Defines helper variables + uint80 roundId; + int256 answer; + uint256 startedAt; + uint256 updatedAt; + uint80 answeredInRound; + + // Checks initial state + (roundId, answer, startedAt, updatedAt, answeredInRound) = s_zksyncSequencerUptimeFeed.latestRoundData(); + assertEq(roundId, 1); + assertEq(answer, 0); + assertEq(answeredInRound, roundId); + assertEq(startedAt, updatedAt); + + // Submits status update with different status and newer timestamp, should update + uint256 timestamp = startedAt + 1000; + s_zksyncSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + (roundId, answer, startedAt, updatedAt, answeredInRound) = s_zksyncSequencerUptimeFeed.getRoundData(2); + assertEq(roundId, 2); + assertEq(answer, 1); + assertEq(answeredInRound, roundId); + assertEq(startedAt, timestamp); + assertLe(updatedAt, startedAt); + + // Saves round 2 data + uint80 roundId2 = roundId; + int256 answer2 = answer; + uint256 startedAt2 = startedAt; + uint256 updatedAt2 = updatedAt; + uint80 answeredInRound2 = answeredInRound; + + // Checks that last round is still returning the correct data + (roundId, answer, startedAt, updatedAt, answeredInRound) = s_zksyncSequencerUptimeFeed.getRoundData(1); + assertEq(roundId, 1); + assertEq(answer, 0); + assertEq(answeredInRound, roundId); + assertEq(startedAt, updatedAt); + + // Assert latestRoundData corresponds to latest round id + (roundId, answer, startedAt, updatedAt, answeredInRound) = s_zksyncSequencerUptimeFeed.latestRoundData(); + assertEq(roundId2, roundId); + assertEq(answer2, answer); + assertEq(startedAt2, startedAt); + assertEq(updatedAt2, updatedAt); + assertEq(answeredInRound2, answeredInRound); + } + + /// @notice it should revert from #getRoundData when round does not yet exist (future roundId) + function test_RevertGetRoundDataWhenRoundDoesNotExistYet() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l1OwnerAddr, s_l1OwnerAddr); + + // Gets data from a round that has not happened yet + vm.expectRevert(BaseSequencerUptimeFeed.NoDataPresent.selector); + s_zksyncSequencerUptimeFeed.getRoundData(2); + } + + /// @notice it should revert from #getAnswer when round does not yet exist (future roundId) + function test_RevertGetAnswerWhenRoundDoesNotExistYet() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l1OwnerAddr, s_l1OwnerAddr); + + // Gets data from a round that has not happened yet + vm.expectRevert(BaseSequencerUptimeFeed.NoDataPresent.selector); + s_zksyncSequencerUptimeFeed.getAnswer(2); + } + + /// @notice it should revert from #getTimestamp when round does not yet exist (future roundId) + function test_RevertGetTimestampWhenRoundDoesNotExistYet() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l1OwnerAddr, s_l1OwnerAddr); + + // Gets data from a round that has not happened yet + vm.expectRevert(BaseSequencerUptimeFeed.NoDataPresent.selector); + s_zksyncSequencerUptimeFeed.getTimestamp(2); + } +} + +contract ZKSyncSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions is ZKSyncSequencerUptimeFeedTest { + /// @notice it should disallow reads on AggregatorV2V3Interface functions when consuming contract is not whitelisted + function test_AggregatorV2V3InterfaceDisallowReadsIfConsumingContractIsNotWhitelisted() public { + // Deploys a FeedConsumer contract + FeedConsumer feedConsumer = new FeedConsumer(address(s_zksyncSequencerUptimeFeed)); + + // Sanity - consumer is not whitelisted + assertEq(s_zksyncSequencerUptimeFeed.checkEnabled(), true); + assertEq(s_zksyncSequencerUptimeFeed.hasAccess(address(feedConsumer), abi.encode("")), false); + + // Asserts reads are not possible from consuming contract + vm.expectRevert("No access"); + feedConsumer.latestAnswer(); + vm.expectRevert("No access"); + feedConsumer.latestRoundData(); + } + + /// @notice it should allow reads on AggregatorV2V3Interface functions when consuming contract is whitelisted + function test_AggregatorV2V3InterfaceAllowReadsIfConsumingContractIsWhitelisted() public { + // Deploys a FeedConsumer contract + FeedConsumer feedConsumer = new FeedConsumer(address(s_zksyncSequencerUptimeFeed)); + + // Whitelist consumer + s_zksyncSequencerUptimeFeed.addAccess(address(feedConsumer)); + + // Sanity - consumer is whitelisted + assertEq(s_zksyncSequencerUptimeFeed.checkEnabled(), true); + assertEq(s_zksyncSequencerUptimeFeed.hasAccess(address(feedConsumer), abi.encode("")), true); + + // Asserts reads are possible from consuming contract + (uint80 roundId, int256 answer, , , ) = feedConsumer.latestRoundData(); + assertEq(feedConsumer.latestAnswer(), 0); + assertEq(roundId, 1); + assertEq(answer, 0); + } +} diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/zksync/ZKSyncValidator.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/zksync/ZKSyncValidator.t.sol new file mode 100644 index 00000000000..0bea147c8cd --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/zksync/ZKSyncValidator.t.sol @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import {MockBridgehub} from "../../mocks/zksync/MockZKSyncL1Bridge.sol"; +import {ISequencerUptimeFeed} from "../../../dev/interfaces/ISequencerUptimeFeed.sol"; +import {ZKSyncValidator} from "../../../dev/zksync/ZKSyncValidator.sol"; +import {BaseValidator} from "../../../dev/shared/BaseValidator.sol"; +import {L2EPTest} from "../L2EPTest.t.sol"; + +contract ZKSyncValidatorTest is L2EPTest { + address internal constant L2_SEQ_STATUS_RECORDER_ADDRESS = address(0x491B1dDA0A8fa069bbC1125133A975BF4e85a91b); + address internal constant DUMMY_L1_XDOMAIN_MSNGR_ADDR = address(0xa04Fc18f012B1a5A8231c7Ee4b916Dd6dbd271b6); + address internal constant DUMMY_L2_UPTIME_FEED_ADDR = address(0xFe31891940A2e5f04B76eD8bD1038E44127d1512); + uint32 internal constant INIT_GAS_PER_PUBDATA_BYTE_LIMIT = 800; + uint32 internal constant INIT_GAS_LIMIT = 1900000; + uint32 internal constant MAIN_NET_CHAIN_ID = 300; + uint32 internal constant BAD_CHAIN_ID = 0; + + ISequencerUptimeFeed internal s_zksyncSequencerUptimeFeed; + MockBridgehub internal s_mockZKSyncL1Bridge; + ZKSyncValidator internal s_zksyncValidator; + + /// Fake event that will get emitted when `requestL2TransactionDirect` is called + /// Definition is taken from MockZKSyncL1Bridge + event SentMessage(address indexed sender, bytes message); + + /// Setup + function setUp() public { + s_mockZKSyncL1Bridge = new MockBridgehub(); + + s_zksyncValidator = new ZKSyncValidator( + address(s_mockZKSyncL1Bridge), + DUMMY_L2_UPTIME_FEED_ADDR, + INIT_GAS_LIMIT, + MAIN_NET_CHAIN_ID, + INIT_GAS_PER_PUBDATA_BYTE_LIMIT + ); + } +} + +contract ZKSyncValidator_Constructor is ZKSyncValidatorTest { + /// @notice it correctly validates that the chain id is valid + function test_ConstructingRevertedWithInvalidChainId() public { + vm.expectRevert(ZKSyncValidator.InvalidChainID.selector); + new ZKSyncValidator( + DUMMY_L1_XDOMAIN_MSNGR_ADDR, + DUMMY_L2_UPTIME_FEED_ADDR, + INIT_GAS_LIMIT, + BAD_CHAIN_ID, + INIT_GAS_PER_PUBDATA_BYTE_LIMIT + ); + } + + /// @notice it correctly validates that the L1 bridge address is not zero + function test_ConstructingRevertedWithZeroL1BridgeAddress() public { + vm.expectRevert(BaseValidator.L1CrossDomainMessengerAddressZero.selector); + new ZKSyncValidator( + address(0), + DUMMY_L2_UPTIME_FEED_ADDR, + INIT_GAS_LIMIT, + MAIN_NET_CHAIN_ID, + INIT_GAS_PER_PUBDATA_BYTE_LIMIT + ); + } + + /// @notice it correctly validates that the L2 Uptime feed address is not zero + function test_ConstructingRevertedWithZeroL2UpdateFeedAddress() public { + vm.expectRevert(BaseValidator.L2UptimeFeedAddrZero.selector); + new ZKSyncValidator( + DUMMY_L1_XDOMAIN_MSNGR_ADDR, + address(0), + INIT_GAS_LIMIT, + MAIN_NET_CHAIN_ID, + INIT_GAS_PER_PUBDATA_BYTE_LIMIT + ); + } +} + +contract ZKSyncValidator_GetSetL2GasPerPubdataByteLimit is ZKSyncValidatorTest { + /// @notice it correctly updates the gas limit per pubdata byte + function test_CorrectlyGetsAndUpdatesTheGasPerPubdataByteLimit() public { + assertEq(s_zksyncValidator.getL2GasPerPubdataByteLimit(), INIT_GAS_PER_PUBDATA_BYTE_LIMIT); + + uint32 newGasPerPubDataByteLimit = 2000000; + s_zksyncValidator.setL2GasPerPubdataByteLimit(newGasPerPubDataByteLimit); + assertEq(s_zksyncValidator.getL2GasPerPubdataByteLimit(), newGasPerPubDataByteLimit); + } +} + +contract ZKSyncValidator_GetChainId is ZKSyncValidatorTest { + /// @notice it correctly gets the chain id + function test_CorrectlyGetsTheChainId() public { + assertEq(s_zksyncValidator.getChainId(), MAIN_NET_CHAIN_ID); + } +} + +contract ZKSyncValidator_Validate is ZKSyncValidatorTest { + /// @notice it reverts if called by account with no access + function test_RevertsIfCalledByAnAccountWithNoAccess() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("No access"); + s_zksyncValidator.validate(0, 0, 1, 1); + } + + /// @notice it posts sequencer status when there is not status change + function test_PostSequencerStatusWhenThereIsNotStatusChange() public { + // Gives access to the s_eoaValidator + s_zksyncValidator.addAccess(s_eoaValidator); + + // Sets block.timestamp to a later date + uint256 futureTimestampInSeconds = block.timestamp + 5000; + vm.startPrank(s_eoaValidator); + vm.warp(futureTimestampInSeconds); + + // Sets up the expected event data + bytes memory message = abi.encodeWithSelector( + ISequencerUptimeFeed.updateStatus.selector, + false, + futureTimestampInSeconds + ); + + vm.expectEmit(false, false, false, true); + emit SentMessage(address(s_zksyncValidator), message); + + // Runs the function (which produces the event to test) + s_zksyncValidator.validate(0, 0, 0, 0); + } + + /// @notice it post sequencer offline + function test_PostSequencerOffline() public { + // Gives access to the s_eoaValidator + s_zksyncValidator.addAccess(s_eoaValidator); + + // Sets block.timestamp to a later date + uint256 futureTimestampInSeconds = block.timestamp + 10000; + vm.startPrank(s_eoaValidator); + vm.warp(futureTimestampInSeconds); + + // Sets up the expected event data + vm.expectEmit(false, false, false, true); + emit SentMessage( + address(s_zksyncValidator), + abi.encodeWithSelector(ISequencerUptimeFeed.updateStatus.selector, true, futureTimestampInSeconds) + ); + + // Runs the function (which produces the event to test) + s_zksyncValidator.validate(0, 0, 1, 1); + } +}