diff --git a/.gas-snapshot b/.gas-snapshot index f2854ac..63be8e1 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,31 +1,34 @@ -AcceptManagerTransfer:testFuzz_acceptManagerTransfer(address) (runs: 256, μ: 185205, ~: 185205) -AcceptManagerTransfer:test_RevertIf_NoPendingManager() (gas: 170816) +AcceptManagerTransfer:testFuzz_acceptManagerTransfer(address) (runs: 256, μ: 185139, ~: 185139) +AcceptManagerTransfer:test_RevertIf_NoPendingManager() (gas: 170772) AcceptManagerTransfer:test_isAdmin() (gas: 953761) -AddAdminVerifier:testFuzz_RevertIf_addAdminVerifierByUnauthorized(address) (runs: 256, μ: 270819, ~: 270819) -AddAdminVerifier:testFuzz_RevertIf_addAdminVerifierTwice(address) (runs: 256, μ: 47771, ~: 47771) -AddAdminVerifier:test_addAdminVerifier(address) (runs: 256, μ: 49506, ~: 49506) +AddAdminVerifier:testFuzz_RevertIf_addAdminVerifierByUnauthorized(address) (runs: 256, μ: 270817, ~: 270817) +AddAdminVerifier:testFuzz_RevertIf_addAdminVerifierTwice(address) (runs: 256, μ: 47899, ~: 47899) +AddAdminVerifier:test_addAdminVerifier(address) (runs: 256, μ: 49570, ~: 49570) AddAdminVerifier:test_isAdmin() (gas: 953695) -AddAssertion:testFuzz_RevertIf_addAssertionByUnauthorized(bytes32,address) (runs: 256, μ: 168554, ~: 168554) -AddAssertion:testFuzz_RevertIf_addAssertionNotRegistered(address,bytes32) (runs: 256, μ: 21802, ~: 21802) -AddAssertion:testFuzz_RevertIf_addDuplicateAssertion(bytes32) (runs: 256, μ: 240904, ~: 240904) -AddAssertion:testFuzz_addAssertion(bytes32) (runs: 256, μ: 234653, ~: 234653) -AddAssertion:testFuzz_addMultipleAssertions(bytes32,bytes32) (runs: 256, μ: 282925, ~: 282925) -AddAssertion:testFuzz_addTooManyAssertions(bytes32) (runs: 256, μ: 511735, ~: 511735) -AddAssertion:testFuzz_expectAssertionAdded(bytes32) (runs: 256, μ: 242023, ~: 242023) -AddAssertion:test_RevertIf_addAssertionWithUnregisteredDAVerifier() (gas: 168781) +AddAssertion:testFuzz_RevertIf_addAssertionByUnauthorized(bytes32,address) (runs: 256, μ: 168510, ~: 168510) +AddAssertion:testFuzz_RevertIf_addAssertionNotRegistered(address,bytes32) (runs: 256, μ: 21780, ~: 21780) +AddAssertion:testFuzz_RevertIf_addDuplicateAssertion(bytes32) (runs: 256, μ: 240838, ~: 240838) +AddAssertion:testFuzz_addAssertion(bytes32) (runs: 256, μ: 234609, ~: 234609) +AddAssertion:testFuzz_addMultipleAssertions(bytes32,bytes32) (runs: 256, μ: 282859, ~: 282859) +AddAssertion:testFuzz_addTooManyAssertions(bytes32) (runs: 256, μ: 511537, ~: 511537) +AddAssertion:testFuzz_expectAssertionAdded(bytes32) (runs: 256, μ: 241979, ~: 241979) +AddAssertion:test_RevertIf_addAssertionWithUnregisteredDAVerifier() (gas: 168737) AddAssertion:test_isAdmin() (gas: 953695) -AddAssertionWithWhitelist:testFuzz_RevertIf_addAssertionByNonWhitelistedManager(bytes32) (runs: 256, μ: 177531, ~: 177531) -AddAssertionWithWhitelist:test_addAssertionAfterAddingToWhitelist() (gas: 254234) -AddAssertionWithWhitelist:test_addAssertionWhenWhitelistDisabled() (gas: 233237) +AddAssertionWithWhitelist:testFuzz_RevertIf_addAssertionByNonWhitelistedManager(bytes32) (runs: 256, μ: 177443, ~: 177443) +AddAssertionWithWhitelist:test_addAssertionAfterAddingToWhitelist() (gas: 254197) +AddAssertionWithWhitelist:test_addAssertionWhenWhitelistDisabled() (gas: 233171) AddAssertionWithWhitelist:test_isAdmin() (gas: 953695) -AddDAVerifier:testFuzz_RevertIf_addDAVerifierByUnauthorized(address) (runs: 256, μ: 26949, ~: 26949) -AddDAVerifier:testFuzz_RevertIf_addDAVerifierTwice(address) (runs: 256, μ: 48425, ~: 48425) -AddDAVerifier:test_addDAVerifier(address) (runs: 256, μ: 52844, ~: 52844) +AddDAVerifier:testFuzz_RevertIf_addDAVerifierByUnauthorized(address) (runs: 256, μ: 26861, ~: 26861) +AddDAVerifier:testFuzz_RevertIf_addDAVerifierTwice(address) (runs: 256, μ: 48381, ~: 48381) +AddDAVerifier:test_addDAVerifier(address) (runs: 256, μ: 52778, ~: 52778) AddDAVerifier:test_isAdmin() (gas: 953695) -AddToWhitelist:testFuzz_RevertIf_addToWhitelistByUnauthorized(address) (runs: 256, μ: 30865, ~: 30865) -AddToWhitelist:test_RevertIf_addAlreadyWhitelistedAccount() (gas: 45839) -AddToWhitelist:test_addToWhitelist() (gas: 54605) +AddToWhitelist:testFuzz_RevertIf_addToWhitelistByUnauthorized(address) (runs: 256, μ: 30933, ~: 30933) +AddToWhitelist:test_RevertIf_addAlreadyWhitelistedAccount() (gas: 45842) +AddToWhitelist:test_addToWhitelist() (gas: 54590) AddToWhitelist:test_isAdmin() (gas: 953695) +AdminVerifierAlwaysApproveTest:test_verifyAdminReturnsTrueForAnyRequester() (gas: 10911) +AdminVerifierAlwaysApproveTest:test_verifyAdminReturnsTrueForZeroAddresses() (gas: 7049) +AdminVerifierAlwaysApproveTest:test_verifyAdminReturnsTrueWithData() (gas: 8290) AdminVerifierSuperAdminTest:test_verifyAdminReflectsOwnershipTransfer() (gas: 23022) AdminVerifierSuperAdminTest:test_verifyAdminReturnsFalseForOthers() (gas: 9984) AdminVerifierSuperAdminTest:test_verifyAdminReturnsTrueForOwner() (gas: 10026) @@ -49,19 +52,19 @@ AdminVerifierWhitelistTest:test_excludeRemovesWhitelistEntry() (gas: 56055) AdminVerifierWhitelistTest:test_releaseExclusionByReleaser() (gas: 32588) AdminVerifierWhitelistTest:test_removeFromWhitelist() (gas: 35882) AdminVerifierWhitelistTest:test_verifyAdmin() (gas: 57812) -Batch:testFuzz_batchResetStorage(bytes32) (runs: 256, μ: 171867, ~: 171867) -Batch:test_batch(bytes32,bytes32) (runs: 256, μ: 316333, ~: 316333) +Batch:testFuzz_batchResetStorage(bytes32) (runs: 256, μ: 171911, ~: 171911) +Batch:test_batch(bytes32,bytes32) (runs: 256, μ: 316223, ~: 316223) Batch:test_isAdmin() (gas: 953739) BatchTest:test_batchExecutesAllCalls() (gas: 34598) BatchTest:test_batchIsNotPayable() (gas: 16262) BatchTest:test_batchRevertsWhenInnerCallFails() (gas: 12304) -Constructor:test_assertionTimelockZero() (gas: 98568) +Constructor:test_assertionTimelockZero() (gas: 98888) Constructor:test_isAdmin() (gas: 953761) DAVerifierECDSATest:testFuzz_RevertIf_verifyDAWithWrongProver(bytes32,bytes,uint256) (runs: 256, μ: 18769, ~: 18765) -DAVerifierECDSATest:testFuzz_RevertIf_verifyDAwithInvalidSignature(bytes32,bytes,bytes) (runs: 256, μ: 11413, ~: 11410) +DAVerifierECDSATest:testFuzz_RevertIf_verifyDAwithInvalidSignature(bytes32,bytes,bytes) (runs: 256, μ: 11412, ~: 11410) DAVerifierECDSATest:testFuzz_verifyDA(bytes32,bytes) (runs: 256, μ: 17575, ~: 17571) -DAVerifierOnChainTest:testFuzz_verifyDA_invalidProof(bytes32,bytes,bytes) (runs: 256, μ: 11683, ~: 11673) -DAVerifierOnChainTest:testFuzz_verifyDA_metadataIgnored(bytes,bytes,bytes) (runs: 256, μ: 11626, ~: 11604) +DAVerifierOnChainTest:testFuzz_verifyDA_invalidProof(bytes32,bytes,bytes) (runs: 256, μ: 11683, ~: 11671) +DAVerifierOnChainTest:testFuzz_verifyDA_metadataIgnored(bytes,bytes,bytes) (runs: 256, μ: 11627, ~: 11604) DAVerifierOnChainTest:testFuzz_verifyDA_validProof(bytes,bytes) (runs: 256, μ: 8575, ~: 8563) DAVerifierOnChainTest:test_verifyDA_deterministicPure() (gas: 10415) DAVerifierOnChainTest:test_verifyDA_emptyProof() (gas: 7323) @@ -75,201 +78,208 @@ DAVerifierRegistryTest:test_isRegistered_returnsTrueAfterAdd() (gas: 34462) DAVerifierRegistryTest:test_remove() (gas: 26284) DAVerifierRegistryTest:test_remove_RevertIf_NotRegistered() (gas: 13624) DAVerifierRegistryTest:test_remove_emitsEvent() (gas: 28380) -DeployCoreWithStagingIntegrationTest:test_AddAssertionWithOnChainDAVerifierOnBothOracles() (gas: 393263) -DeployCoreWithStagingIntegrationTest:test_AddToWhitelistOnBothOracles() (gas: 91286) +DeployAdminVerifiersTest:test_RevertIf_coreDeployWhitelistVerifierWithoutAdmin() (gas: 10160657) +DeployAdminVerifiersTest:test_RevertIf_testingScriptAddsVerifiersWithoutStateOracle() (gas: 2225277) +DeployAdminVerifiersTest:test_RevertIf_testingScriptDeploysSuperAdminVerifierWithoutAdmin() (gas: 2084462) +DeployAdminVerifiersTest:test_coreDeployAdminVerifiersAddsOnlyProductionVerifiersToStateOracle() (gas: 17274071) +DeployAdminVerifiersTest:test_testingScriptDeploysAndAddsTestVerifiersToStateOracle() (gas: 8038679) +DeployCoreWithStagingIntegrationTest:test_AddAssertionWithOnChainDAVerifierOnBothOracles() (gas: 393189) +DeployCoreWithStagingIntegrationTest:test_AddToWhitelistOnBothOracles() (gas: 91300) DeployCoreWithStagingIntegrationTest:test_BothOraclesDeployed() (gas: 5105) DeployCoreWithStagingIntegrationTest:test_BothOraclesHaveBothDAVerifiers() (gas: 41415) -DeployCoreWithStagingIntegrationTest:test_BothOraclesShareSameAdminVerifier() (gas: 29848) +DeployCoreWithStagingIntegrationTest:test_BothOraclesShareSameAdminVerifier() (gas: 29804) DeployCoreWithStagingIntegrationTest:test_ECDSAVerifierIsSharedAcrossOracles() (gas: 29871) -DeployCoreWithStagingIntegrationTest:test_FullWorkflow_WhitelistAndRegisterOnBothOracles() (gas: 281775) +DeployCoreWithStagingIntegrationTest:test_FullWorkflow_WhitelistAndRegisterOnBothOracles() (gas: 281701) DeployCoreWithStagingIntegrationTest:test_OnChainVerifierIsSharedAcrossOracles() (gas: 29849) DeployCoreWithStagingIntegrationTest:test_OraclesHaveDifferentConfigs() (gas: 29364) DeployCoreWithStagingIntegrationTest:test_PersistentAccountsFunded() (gas: 8375) -DeployCoreWithStagingIntegrationTest:test_RegisterContractOnBothOracles() (gas: 268796) -DisableWhitelist:testFuzz_RevertIf_disableWhitelistByUnauthorized(address) (runs: 256, μ: 22700, ~: 22700) -DisableWhitelist:test_RevertIf_disableAlreadyDisabledWhitelist() (gas: 25195) -DisableWhitelist:test_disableWhitelist() (gas: 28255) +DeployCoreWithStagingIntegrationTest:test_RegisterContractOnBothOracles() (gas: 268766) +DisableWhitelist:testFuzz_RevertIf_disableWhitelistByUnauthorized(address) (runs: 256, μ: 22634, ~: 22634) +DisableWhitelist:test_RevertIf_disableAlreadyDisabledWhitelist() (gas: 25151) +DisableWhitelist:test_disableWhitelist() (gas: 28189) DisableWhitelist:test_isAdmin() (gas: 953761) -DisableWhitelist:test_nonWhitelistedUserWhenDisabled() (gas: 30133) -DisableWhitelist:test_whitelistedUserAfterReenabling() (gas: 60127) -DisableWhitelist:test_whitelistedUserWhenDisabled() (gas: 59811) -EnableWhitelist:testFuzz_RevertIf_enableWhitelistByUnauthorized(address) (runs: 256, μ: 22721, ~: 22721) -EnableWhitelist:test_RevertIf_enableAlreadyEnabledWhitelist() (gas: 25245) -EnableWhitelist:test_enableWhitelist() (gas: 28214) +DisableWhitelist:test_nonWhitelistedUserWhenDisabled() (gas: 30089) +DisableWhitelist:test_whitelistedUserAfterReenabling() (gas: 60090) +DisableWhitelist:test_whitelistedUserWhenDisabled() (gas: 59774) +EnableWhitelist:testFuzz_RevertIf_enableWhitelistByUnauthorized(address) (runs: 256, μ: 22655, ~: 22655) +EnableWhitelist:test_RevertIf_enableAlreadyEnabledWhitelist() (gas: 25201) +EnableWhitelist:test_enableWhitelist() (gas: 28148) EnableWhitelist:test_isAdmin() (gas: 953761) -GrantGuardianAdminRole:testFuzz_RevertIf_nonOwnerGrantsGuardianAdminRole(address) (runs: 256, μ: 18745, ~: 18745) +GrantGuardianAdminRole:testFuzz_RevertIf_nonOwnerGrantsGuardianAdminRole(address) (runs: 256, μ: 18723, ~: 18723) GrantGuardianAdminRole:test_isAdmin() (gas: 953695) -GrantGuardianAdminRole:test_ownerCanGrantGuardianAdminRole() (gas: 50860) -GrantGuardianRole:testFuzz_RevertIf_nonGuardianAdminGrantsGuardianRole(address) (runs: 256, μ: 20748, ~: 20748) -GrantGuardianRole:test_guardianAdminCanGrantGuardianRole() (gas: 51186) +GrantGuardianAdminRole:test_ownerCanGrantGuardianAdminRole() (gas: 50926) +GrantGuardianRole:testFuzz_RevertIf_nonGuardianAdminGrantsGuardianRole(address) (runs: 256, μ: 20814, ~: 20814) +GrantGuardianRole:test_guardianAdminCanGrantGuardianRole() (gas: 51142) GrantGuardianRole:test_isAdmin() (gas: 953761) -GrantOperatorAdminRole:testFuzz_RevertIf_nonOwnerGrantsOperatorAdminRole(address) (runs: 256, μ: 18720, ~: 18720) +GrantOperatorAdminRole:testFuzz_RevertIf_nonOwnerGrantsOperatorAdminRole(address) (runs: 256, μ: 18698, ~: 18698) GrantOperatorAdminRole:test_isAdmin() (gas: 953739) -GrantOperatorAdminRole:test_ownerCanGrantOperatorAdminRole() (gas: 50814) -GrantOperatorRole:testFuzz_RevertIf_nonOperatorAdminGrantsOperatorRole(address) (runs: 256, μ: 28131, ~: 28131) -GrantOperatorRole:testFuzz_RevertIf_nonOperatorAdminGrantsOperatorRoleUsingHelper(address) (runs: 256, μ: 24026, ~: 24026) +GrantOperatorAdminRole:test_ownerCanGrantOperatorAdminRole() (gas: 50882) +GrantOperatorRole:testFuzz_RevertIf_nonOperatorAdminGrantsOperatorRole(address) (runs: 256, μ: 28243, ~: 28243) +GrantOperatorRole:testFuzz_RevertIf_nonOperatorAdminGrantsOperatorRoleUsingHelper(address) (runs: 256, μ: 24071, ~: 24071) GrantOperatorRole:test_isAdmin() (gas: 953783) -GrantOperatorRole:test_ownerCanGrantOperatorRole() (gas: 56290) -GrantOperatorRole:test_ownerCanGrantOperatorRoleUsingHelper() (gas: 51069) -GrantOperatorRole:test_stateOracleAdminHasDefaultAdminRole() (gas: 16070) -GuardianAdminCanManageGuardians:testFuzz_RevertIf_nonGuardianAdminGrantsGuardianRole(address) (runs: 256, μ: 21640, ~: 21640) -GuardianAdminCanManageGuardians:testFuzz_RevertIf_nonGuardianAdminRevokesGuardianRole(address) (runs: 256, μ: 51968, ~: 51968) -GuardianAdminCanManageGuardians:test_guardianAdminCanGrantGuardianRole() (gas: 51908) -GuardianAdminCanManageGuardians:test_guardianAdminCanRevokeGuardianRole() (gas: 42415) +GrantOperatorRole:test_ownerCanGrantOperatorRole() (gas: 56447) +GrantOperatorRole:test_ownerCanGrantOperatorRoleUsingHelper() (gas: 51159) +GrantOperatorRole:test_stateOracleAdminHasDefaultAdminRole() (gas: 16114) +GuardianAdminCanManageGuardians:testFuzz_RevertIf_nonGuardianAdminGrantsGuardianRole(address) (runs: 256, μ: 21706, ~: 21706) +GuardianAdminCanManageGuardians:testFuzz_RevertIf_nonGuardianAdminRevokesGuardianRole(address) (runs: 256, μ: 52101, ~: 52101) +GuardianAdminCanManageGuardians:test_guardianAdminCanGrantGuardianRole() (gas: 51864) +GuardianAdminCanManageGuardians:test_guardianAdminCanRevokeGuardianRole() (gas: 42433) GuardianAdminCanManageGuardians:test_isAdmin() (gas: 953695) -GuardianEmergencyActions:test_guardianCanRemoveAssertion() (gas: 271169) -GuardianEmergencyActions:test_guardianCanRevokeManager() (gas: 181949) -GuardianEmergencyActions:test_guardianCannotAddAdminVerifier() (gas: 264624) -GuardianEmergencyActions:test_guardianCannotAddDAVerifier() (gas: 20692) -GuardianEmergencyActions:test_guardianCannotAddToWhitelist() (gas: 27789) -GuardianEmergencyActions:test_guardianCannotDisableWhitelist() (gas: 19939) -GuardianEmergencyActions:test_guardianCannotEnableWhitelist() (gas: 30615) -GuardianEmergencyActions:test_guardianCannotRemoveAdminVerifier() (gas: 22749) -GuardianEmergencyActions:test_guardianCannotRemoveDAVerifier() (gas: 22794) -GuardianEmergencyActions:test_guardianCannotRemoveFromWhitelist() (gas: 54997) -GuardianEmergencyActions:test_guardianCannotSetMaxAssertionsPerAA() (gas: 20420) +GuardianEmergencyActions:test_guardianCanRemoveAssertion() (gas: 271110) +GuardianEmergencyActions:test_guardianCanRevokeManager() (gas: 181934) +GuardianEmergencyActions:test_guardianCannotAddAdminVerifier() (gas: 264666) +GuardianEmergencyActions:test_guardianCannotAddDAVerifier() (gas: 20648) +GuardianEmergencyActions:test_guardianCannotAddToWhitelist() (gas: 27834) +GuardianEmergencyActions:test_guardianCannotDisableWhitelist() (gas: 19895) +GuardianEmergencyActions:test_guardianCannotEnableWhitelist() (gas: 30549) +GuardianEmergencyActions:test_guardianCannotRemoveAdminVerifier() (gas: 22705) +GuardianEmergencyActions:test_guardianCannotRemoveDAVerifier() (gas: 22750) +GuardianEmergencyActions:test_guardianCannotRemoveFromWhitelist() (gas: 55049) +GuardianEmergencyActions:test_guardianCannotSetMaxAssertionsPerAA() (gas: 20398) GuardianEmergencyActions:test_isAdmin() (gas: 953761) GuardianRoleBase:test_isAdmin() (gas: 953761) GuardianRoleBase:test_isAdmin() (gas: 953761) -Initialize:test_RevertIf_alreadyInitialized() (gas: 21222) -Initialize:test_RevertIf_initializeNonProxy() (gas: 4097793) -Initialize:test_isAdmin() (gas: 953761) -InitializeWhitelist:test_initialNonWhitelistedUser() (gas: 19126) -InitializeWhitelist:test_initialWhitelistState() (gas: 13110) +Initialize:test_RevertIf_alreadyInitialized() (gas: 21244) +Initialize:test_RevertIf_initializeNonProxy() (gas: 4293371) +Initialize:test_initializeWithWhitelistDisabled() (gas: 5459554) +Initialize:test_initializeWithWhitelistEnabledAndInitialAccount() (gas: 5496038) +Initialize:test_isAdmin() (gas: 953783) +InitializeWhitelist:test_initialNonWhitelistedUser() (gas: 19104) +InitializeWhitelist:test_initialWhitelistState() (gas: 13088) InitializeWhitelist:test_isAdmin() (gas: 953761) -OperatorAdminCanManageOperators:testFuzz_RevertIf_nonOperatorAdminGrantsOperatorRole(address) (runs: 256, μ: 24963, ~: 24963) -OperatorAdminCanManageOperators:testFuzz_RevertIf_nonOperatorAdminRevokesOperatorRole(address) (runs: 256, μ: 55290, ~: 55290) +OperatorAdminCanManageOperators:testFuzz_RevertIf_nonOperatorAdminGrantsOperatorRole(address) (runs: 256, μ: 25008, ~: 25008) +OperatorAdminCanManageOperators:testFuzz_RevertIf_nonOperatorAdminRevokesOperatorRole(address) (runs: 256, μ: 55313, ~: 55313) OperatorAdminCanManageOperators:test_isAdmin() (gas: 953739) -OperatorAdminCanManageOperators:test_operatorAdminCanGrantOperatorRole() (gas: 51812) -OperatorAdminCanManageOperators:test_operatorAdminCanRevokeOperatorRole() (gas: 42391) -OperatorAdminCanManageOperators:test_operatorAdminCannotManageWhitelist() (gas: 20800) -OperatorAdminCanManageOperators:test_operatorAdminCannotRemoveAssertionByOwner() (gas: 260112) -OperatorAdminCanManageOperators:test_operatorAdminCannotRevokeManager() (gas: 195238) -OperatorCanManageWhitelist:testFuzz_RevertIf_nonOperatorAddsToWhitelist(address) (runs: 256, μ: 31801, ~: 31801) -OperatorCanManageWhitelist:testFuzz_RevertIf_nonOperatorRemovesFromWhitelist(address) (runs: 256, μ: 60955, ~: 60955) +OperatorAdminCanManageOperators:test_operatorAdminCanGrantOperatorRole() (gas: 51902) +OperatorAdminCanManageOperators:test_operatorAdminCanRevokeOperatorRole() (gas: 42445) +OperatorAdminCanManageOperators:test_operatorAdminCannotManageWhitelist() (gas: 20845) +OperatorAdminCanManageOperators:test_operatorAdminCannotRemoveAssertionByOwner() (gas: 260053) +OperatorAdminCanManageOperators:test_operatorAdminCannotRevokeManager() (gas: 195223) +OperatorCanManageWhitelist:testFuzz_RevertIf_nonOperatorAddsToWhitelist(address) (runs: 256, μ: 31869, ~: 31869) +OperatorCanManageWhitelist:testFuzz_RevertIf_nonOperatorRemovesFromWhitelist(address) (runs: 256, μ: 61030, ~: 61030) OperatorCanManageWhitelist:test_isAdmin() (gas: 953783) -OperatorCanManageWhitelist:test_operatorCanAddToWhitelist() (gas: 51900) -OperatorCanManageWhitelist:test_operatorCanRemoveFromWhitelist() (gas: 41553) +OperatorCanManageWhitelist:test_operatorCanAddToWhitelist() (gas: 51885) +OperatorCanManageWhitelist:test_operatorCanRemoveFromWhitelist() (gas: 41524) OperatorRoleBase:test_isAdmin() (gas: 953761) OwnableTest:test_isAdmin() (gas: 953717) -OwnableTest:test_newOwnerCanGrantRolesAsOwner() (gas: 229628) -OwnableTest:test_ownerIsInitializerOnProxy() (gas: 13577) -OwnableTest:test_ownerIsZeroOnImplementation() (gas: 3833400) -OwnableTest:test_transferOwnership() (gas: 230046) +OwnableTest:test_newOwnerCanGrantRolesAsOwner() (gas: 229518) +OwnableTest:test_ownerIsInitializerOnProxy() (gas: 13555) +OwnableTest:test_ownerIsZeroOnImplementation() (gas: 4028956) +OwnableTest:test_transferOwnership() (gas: 230222) OwnerOnlyFunctionsRemainProtected:test_isAdmin() (gas: 953805) -OwnerOnlyFunctionsRemainProtected:test_operatorCannotAddAdminVerifier() (gas: 264602) -OwnerOnlyFunctionsRemainProtected:test_operatorCannotAddDAVerifier() (gas: 20650) -OwnerOnlyFunctionsRemainProtected:test_operatorCannotDisableWhitelist() (gas: 19961) -OwnerOnlyFunctionsRemainProtected:test_operatorCannotEnableWhitelist() (gas: 30658) -OwnerOnlyFunctionsRemainProtected:test_operatorCannotRemoveAdminVerifier() (gas: 22749) -OwnerOnlyFunctionsRemainProtected:test_operatorCannotRemoveAssertionByOwner() (gas: 260107) -OwnerOnlyFunctionsRemainProtected:test_operatorCannotRemoveDAVerifier() (gas: 22748) -OwnerOnlyFunctionsRemainProtected:test_operatorCannotRevokeManager() (gas: 195232) -OwnerOnlyFunctionsRemainProtected:test_operatorCannotSetMaxAssertionsPerAA() (gas: 20376) +OwnerOnlyFunctionsRemainProtected:test_operatorCannotAddAdminVerifier() (gas: 264644) +OwnerOnlyFunctionsRemainProtected:test_operatorCannotAddDAVerifier() (gas: 20606) +OwnerOnlyFunctionsRemainProtected:test_operatorCannotDisableWhitelist() (gas: 19917) +OwnerOnlyFunctionsRemainProtected:test_operatorCannotEnableWhitelist() (gas: 30592) +OwnerOnlyFunctionsRemainProtected:test_operatorCannotRemoveAdminVerifier() (gas: 22705) +OwnerOnlyFunctionsRemainProtected:test_operatorCannotRemoveAssertionByOwner() (gas: 260048) +OwnerOnlyFunctionsRemainProtected:test_operatorCannotRemoveDAVerifier() (gas: 22704) +OwnerOnlyFunctionsRemainProtected:test_operatorCannotRevokeManager() (gas: 195217) +OwnerOnlyFunctionsRemainProtected:test_operatorCannotSetMaxAssertionsPerAA() (gas: 20354) ProxyHelper:test_isAdmin() (gas: 953783) -Register:testFuzz_RevertIf_registerAssertionAdopterAdminVerifierNotAdded() (gas: 264776) -Register:testFuzz_RevertIf_registerByUnauthorized(address) (runs: 256, μ: 142245, ~: 142245) -Register:test_RevertIf_registerAssertionAdopterTwice() (gas: 167308) -Register:test_expectAssertionAdopterAdded() (gas: 162235) +Register:testFuzz_RevertIf_registerAssertionAdopterAdminVerifierNotAdded() (gas: 264754) +Register:testFuzz_RevertIf_registerByUnauthorized(address) (runs: 256, μ: 142213, ~: 142223) +Register:test_RevertIf_registerAssertionAdopterTwice() (gas: 167264) +Register:test_expectAssertionAdopterAdded() (gas: 162213) Register:test_isAdmin() (gas: 953695) -Register:test_registerByOwner() (gas: 159694) -RegisterAssertionAdopterWithWhitelist:testFuzz_RevertIf_registerByNonWhitelistedUser(address) (runs: 256, μ: 126516, ~: 126516) +Register:test_registerByOwner() (gas: 159672) +RegisterAssertionAdopterWithWhitelist:testFuzz_RevertIf_registerByNonWhitelistedUser(address) (runs: 256, μ: 126494, ~: 126494) RegisterAssertionAdopterWithWhitelist:test_isAdmin() (gas: 953761) -RegisterAssertionAdopterWithWhitelist:test_registerByNonWhitelistedUserWhenDisabled() (gas: 168714) -RegisterAssertionAdopterWithWhitelist:test_registerByWhitelistedUser() (gas: 189529) -RemoveAdminVerifier:testFuzz_RevertIf_removeAdminVerifierByUnauthorized(address) (runs: 256, μ: 303005, ~: 303005) -RemoveAdminVerifier:testFuzz_RevertIf_removeAdminVerifierNotRegistered(address) (runs: 256, μ: 22963, ~: 22963) +RegisterAssertionAdopterWithWhitelist:test_registerByNonWhitelistedUserWhenDisabled() (gas: 168670) +RegisterAssertionAdopterWithWhitelist:test_registerByWhitelistedUser() (gas: 189514) +RemoveAdminVerifier:testFuzz_RevertIf_removeAdminVerifierByUnauthorized(address) (runs: 256, μ: 302981, ~: 302981) +RemoveAdminVerifier:testFuzz_RevertIf_removeAdminVerifierNotRegistered(address) (runs: 256, μ: 22941, ~: 22941) RemoveAdminVerifier:test_isAdmin() (gas: 953695) -RemoveAdminVerifier:test_removeAdminVerifier() (gas: 275567) -RemoveAssertion:testFuzz_RevertIf_removeAssertionAlreadyRemoved(bytes32) (runs: 256, μ: 254138, ~: 254138) -RemoveAssertion:testFuzz_RevertIf_removeAssertionByUnauthorized(bytes32,address) (runs: 256, μ: 240379, ~: 240379) -RemoveAssertion:testFuzz_RevertIf_removeAssertionByUnauthorizedAdmin(bytes32,address) (runs: 256, μ: 252869, ~: 252869) -RemoveAssertion:testFuzz_RevertIf_removeNonExistentAssertion(bytes32) (runs: 256, μ: 164568, ~: 164568) -RemoveAssertion:testFuzz_removeAssertion(bytes32) (runs: 256, μ: 250783, ~: 250783) -RemoveAssertion:testFuzz_removeAssertionByAdmin(bytes32) (runs: 256, μ: 256811, ~: 256811) -RemoveAssertion:test_expectAssertionRemoved(bytes32) (runs: 256, μ: 247151, ~: 247151) +RemoveAdminVerifier:test_removeAdminVerifier() (gas: 275609) +RemoveAssertion:testFuzz_RevertIf_removeAssertionAlreadyRemoved(bytes32) (runs: 256, μ: 254251, ~: 254251) +RemoveAssertion:testFuzz_RevertIf_removeAssertionByUnauthorized(bytes32,address) (runs: 256, μ: 240313, ~: 240313) +RemoveAssertion:testFuzz_RevertIf_removeAssertionByUnauthorizedAdmin(bytes32,address) (runs: 256, μ: 252759, ~: 252759) +RemoveAssertion:testFuzz_RevertIf_removeNonExistentAssertion(bytes32) (runs: 256, μ: 164524, ~: 164524) +RemoveAssertion:testFuzz_removeAssertion(bytes32) (runs: 256, μ: 250717, ~: 250717) +RemoveAssertion:testFuzz_removeAssertionByAdmin(bytes32) (runs: 256, μ: 256723, ~: 256723) +RemoveAssertion:test_expectAssertionRemoved(bytes32) (runs: 256, μ: 247085, ~: 247085) RemoveAssertion:test_isAdmin() (gas: 953761) RemoveAssertionWithWhitelist:test_isAdmin() (gas: 953695) -RemoveAssertionWithWhitelist:test_removeAssertionByNonWhitelistedManager() (gas: 250085) -RemoveDAVerifier:testFuzz_RevertIf_removeDAVerifierByUnauthorized(address) (runs: 256, μ: 59097, ~: 59097) -RemoveDAVerifier:testFuzz_RevertIf_removeDAVerifierNotRegistered(address) (runs: 256, μ: 23005, ~: 23005) +RemoveAssertionWithWhitelist:test_removeAssertionByNonWhitelistedManager() (gas: 250004) +RemoveDAVerifier:testFuzz_RevertIf_removeDAVerifierByUnauthorized(address) (runs: 256, μ: 58965, ~: 58965) +RemoveDAVerifier:testFuzz_RevertIf_removeDAVerifierNotRegistered(address) (runs: 256, μ: 22983, ~: 22983) RemoveDAVerifier:test_isAdmin() (gas: 953695) -RemoveDAVerifier:test_removeDAVerifier() (gas: 39256) -RemoveFromWhitelist:testFuzz_RevertIf_removeFromWhitelistByUnauthorized(address) (runs: 256, μ: 60107, ~: 60107) -RemoveFromWhitelist:test_RevertIf_removeNonWhitelistedAccount() (gas: 21207) +RemoveDAVerifier:test_removeDAVerifier() (gas: 39186) +RemoveFromWhitelist:testFuzz_RevertIf_removeFromWhitelistByUnauthorized(address) (runs: 256, μ: 60182, ~: 60182) +RemoveFromWhitelist:test_RevertIf_removeNonWhitelistedAccount() (gas: 21185) RemoveFromWhitelist:test_isAdmin() (gas: 953761) -RemoveFromWhitelist:test_removeFromWhitelist() (gas: 43248) +RemoveFromWhitelist:test_removeFromWhitelist() (gas: 43219) RenounceOwnershipTest:test_isAdmin() (gas: 953695) -RenounceOwnershipTest:test_renounceOwnershipMaintainsInvariant() (gas: 107828) -ResetStorage:testFuzz_RevertIf_resetStorageByUnauthorized(bytes32,address) (runs: 256, μ: 164399, ~: 164399) -ResetStorage:testFuzz_RevertIf_resetStorageForUnregisteredAdopter(address,bytes32,address) (runs: 256, μ: 16873, ~: 16873) -ResetStorage:testFuzz_resetStorage(bytes32) (runs: 256, μ: 175835, ~: 175835) +RenounceOwnershipTest:test_renounceOwnershipMaintainsInvariant() (gas: 107935) +ResetStorage:testFuzz_RevertIf_resetStorageByUnauthorized(bytes32,address) (runs: 256, μ: 164443, ~: 164443) +ResetStorage:testFuzz_RevertIf_resetStorageForUnregisteredAdopter(address,bytes32,address) (runs: 256, μ: 16939, ~: 16939) +ResetStorage:testFuzz_resetStorage(bytes32) (runs: 256, μ: 175946, ~: 175946) ResetStorage:test_isAdmin() (gas: 953783) -ResetStorage:test_resetStorageAllowsZeroStorageKey() (gas: 168440) -RevokeGuardianAdminRole:testFuzz_RevertIf_nonOwnerRevokesGuardianAdminRole(address) (runs: 256, μ: 18701, ~: 18701) +ResetStorage:test_resetStorageAllowsZeroStorageKey() (gas: 168484) +RevokeGuardianAdminRole:testFuzz_RevertIf_nonOwnerRevokesGuardianAdminRole(address) (runs: 256, μ: 18766, ~: 18766) RevokeGuardianAdminRole:test_isAdmin() (gas: 953739) -RevokeGuardianAdminRole:test_ownerCanRevokeGuardianAdminRole() (gas: 29640) -RevokeGuardianRole:testFuzz_RevertIf_nonGuardianAdminRevokesGuardianRole(address) (runs: 256, μ: 20720, ~: 20720) -RevokeGuardianRole:test_guardianAdminCanRevokeGuardianRole() (gas: 29892) +RevokeGuardianAdminRole:test_ownerCanRevokeGuardianAdminRole() (gas: 29793) +RevokeGuardianRole:testFuzz_RevertIf_nonGuardianAdminRevokesGuardianRole(address) (runs: 256, μ: 20853, ~: 20853) +RevokeGuardianRole:test_guardianAdminCanRevokeGuardianRole() (gas: 29915) RevokeGuardianRole:test_isAdmin() (gas: 953695) -RevokeManager:testFuzz_RevertIf_revokeManagerByUnauthorized(address) (runs: 256, μ: 176360, ~: 176360) -RevokeManager:testFuzz_revokeManager(address) (runs: 256, μ: 171606, ~: 171606) -RevokeManager:test_RevertIf_revokeManagerOfNonExistentAdopter() (gas: 129205) +RevokeManager:testFuzz_RevertIf_revokeManagerByUnauthorized(address) (runs: 256, μ: 176294, ~: 176294) +RevokeManager:testFuzz_revokeManager(address) (runs: 256, μ: 171540, ~: 171540) +RevokeManager:test_RevertIf_revokeManagerOfNonExistentAdopter() (gas: 129183) RevokeManager:test_isAdmin() (gas: 953695) -RevokeOperatorAdminRole:testFuzz_RevertIf_nonOwnerRevokesOperatorAdminRole(address) (runs: 256, μ: 18678, ~: 18678) +RevokeOperatorAdminRole:testFuzz_RevertIf_nonOwnerRevokesOperatorAdminRole(address) (runs: 256, μ: 18745, ~: 18745) RevokeOperatorAdminRole:test_isAdmin() (gas: 953739) -RevokeOperatorAdminRole:test_ownerCanRevokeOperatorAdminRole() (gas: 29662) -RevokeOperatorRole:testFuzz_RevertIf_nonOperatorAdminRevokesOperatorRole(address) (runs: 256, μ: 28131, ~: 28131) -RevokeOperatorRole:testFuzz_RevertIf_nonOperatorAdminRevokesOperatorRoleUsingHelper(address) (runs: 256, μ: 23977, ~: 23977) +RevokeOperatorAdminRole:test_ownerCanRevokeOperatorAdminRole() (gas: 29819) +RevokeOperatorRole:testFuzz_RevertIf_nonOperatorAdminRevokesOperatorRole(address) (runs: 256, μ: 28221, ~: 28221) +RevokeOperatorRole:testFuzz_RevertIf_nonOperatorAdminRevokesOperatorRoleUsingHelper(address) (runs: 256, μ: 24000, ~: 24000) RevokeOperatorRole:test_isAdmin() (gas: 953783) -RevokeOperatorRole:test_ownerCanRevokeOperatorRole() (gas: 35064) -RevokeOperatorRole:test_ownerCanRevokeOperatorRoleUsingHelper() (gas: 29907) +RevokeOperatorRole:test_ownerCanRevokeOperatorRole() (gas: 35199) +RevokeOperatorRole:test_ownerCanRevokeOperatorRoleUsingHelper() (gas: 29975) RevokeOperatorRoleBase:test_isAdmin() (gas: 953761) -SetMaxAssertionsPerAA:testFuzz_RevertIf_setMaxAssertionsPerAAByUnauthorized(uint16,address) (runs: 256, μ: 26703, ~: 26703) -SetMaxAssertionsPerAA:test_AddAssertionsThenLowerMaxAndRevertOnAdd() (gas: 312177) +SetMaxAssertionsPerAA:testFuzz_RevertIf_setMaxAssertionsPerAAByUnauthorized(uint16,address) (runs: 256, μ: 26637, ~: 26637) +SetMaxAssertionsPerAA:test_AddAssertionsThenLowerMaxAndRevertOnAdd() (gas: 312089) SetMaxAssertionsPerAA:test_isAdmin() (gas: 953761) -SetMaxAssertionsPerAA:test_setMaxAssertionsPerAA(uint16) (runs: 256, μ: 23728, ~: 24230) +SetMaxAssertionsPerAA:test_setMaxAssertionsPerAA(uint16) (runs: 256, μ: 23690, ~: 24230) StateOracleAccessControlBase:test_isAdmin() (gas: 953761) StateOracleBase:test_isAdmin() (gas: 953761) -StateOracleOwnerECDSATest:testFuzz_addAssertionWithValidProof(bytes32) (runs: 256, μ: 93774, ~: 93774) -StateOracleOwnerECDSATest:test_RevertIf_addAssertionWithInvalidProof() (gas: 42527) -StateOracleOwnerECDSATest:test_addAndRemoveAssertion() (gas: 113950) -StateOracleOwnerECDSATest:test_addAssertionWithValidProof() (gas: 100965) -StateOracleOwnerECDSATest:test_addMultipleAssertions() (gas: 141263) -StateOracleOwnerECDSATest:test_assertionAddedEventEmitted() (gas: 98593) +StateOracleOwnerECDSATest:testFuzz_addAssertionWithValidProof(bytes32) (runs: 256, μ: 93752, ~: 93752) +StateOracleOwnerECDSATest:test_RevertIf_addAssertionWithInvalidProof() (gas: 42505) +StateOracleOwnerECDSATest:test_addAndRemoveAssertion() (gas: 113906) +StateOracleOwnerECDSATest:test_addAssertionWithValidProof() (gas: 100943) +StateOracleOwnerECDSATest:test_addMultipleAssertions() (gas: 141286) +StateOracleOwnerECDSATest:test_assertionAddedEventEmitted() (gas: 98571) StateOracleOwnerECDSATest:test_isAdmin() (gas: 953695) -StateOracleOwnerOnChainTest:testFuzz_addAssertionWithValidProof(bytes32) (runs: 256, μ: 88319, ~: 88319) -StateOracleOwnerOnChainTest:test_RevertIf_addAssertionWithInvalidProof() (gas: 39504) -StateOracleOwnerOnChainTest:test_addAndRemoveAssertion() (gas: 108495) -StateOracleOwnerOnChainTest:test_addAssertionWithValidProof() (gas: 95510) -StateOracleOwnerOnChainTest:test_addMultipleAssertions() (gas: 130356) -StateOracleOwnerOnChainTest:test_assertionAddedEventEmitted() (gas: 92620) +StateOracleOwnerOnChainTest:testFuzz_addAssertionWithValidProof(bytes32) (runs: 256, μ: 88297, ~: 88297) +StateOracleOwnerOnChainTest:test_RevertIf_addAssertionWithInvalidProof() (gas: 39482) +StateOracleOwnerOnChainTest:test_addAndRemoveAssertion() (gas: 108451) +StateOracleOwnerOnChainTest:test_addAssertionWithValidProof() (gas: 95488) +StateOracleOwnerOnChainTest:test_addMultipleAssertions() (gas: 130379) +StateOracleOwnerOnChainTest:test_assertionAddedEventEmitted() (gas: 92598) StateOracleOwnerOnChainTest:test_isAdmin() (gas: 953695) -StateOracleWhitelistECDSATest:testFuzz_addAssertionWithValidProof(bytes32) (runs: 256, μ: 93774, ~: 93774) -StateOracleWhitelistECDSATest:test_RevertIf_addAssertionWithInvalidProof() (gas: 42527) -StateOracleWhitelistECDSATest:test_addAndRemoveAssertion() (gas: 113950) -StateOracleWhitelistECDSATest:test_addAssertionWithValidProof() (gas: 100965) -StateOracleWhitelistECDSATest:test_addMultipleAssertions() (gas: 141263) -StateOracleWhitelistECDSATest:test_assertionAddedEventEmitted() (gas: 98593) +StateOracleWhitelistECDSATest:testFuzz_addAssertionWithValidProof(bytes32) (runs: 256, μ: 93752, ~: 93752) +StateOracleWhitelistECDSATest:test_RevertIf_addAssertionWithInvalidProof() (gas: 42505) +StateOracleWhitelistECDSATest:test_addAndRemoveAssertion() (gas: 113906) +StateOracleWhitelistECDSATest:test_addAssertionWithValidProof() (gas: 100943) +StateOracleWhitelistECDSATest:test_addMultipleAssertions() (gas: 141286) +StateOracleWhitelistECDSATest:test_assertionAddedEventEmitted() (gas: 98571) StateOracleWhitelistECDSATest:test_isAdmin() (gas: 953695) -StateOracleWhitelistOnChainTest:testFuzz_addAssertionWithValidProof(bytes32) (runs: 256, μ: 88319, ~: 88319) -StateOracleWhitelistOnChainTest:test_RevertIf_addAssertionWithInvalidProof() (gas: 39504) -StateOracleWhitelistOnChainTest:test_addAndRemoveAssertion() (gas: 108495) -StateOracleWhitelistOnChainTest:test_addAssertionWithValidProof() (gas: 95510) -StateOracleWhitelistOnChainTest:test_addMultipleAssertions() (gas: 130356) -StateOracleWhitelistOnChainTest:test_assertionAddedEventEmitted() (gas: 92620) +StateOracleWhitelistOnChainTest:testFuzz_addAssertionWithValidProof(bytes32) (runs: 256, μ: 88297, ~: 88297) +StateOracleWhitelistOnChainTest:test_RevertIf_addAssertionWithInvalidProof() (gas: 39482) +StateOracleWhitelistOnChainTest:test_addAndRemoveAssertion() (gas: 108451) +StateOracleWhitelistOnChainTest:test_addAssertionWithValidProof() (gas: 95488) +StateOracleWhitelistOnChainTest:test_addMultipleAssertions() (gas: 130379) +StateOracleWhitelistOnChainTest:test_assertionAddedEventEmitted() (gas: 92598) StateOracleWhitelistOnChainTest:test_isAdmin() (gas: 953695) -StateOracleWithDAVerifierECDSATest:testFuzz_RevertIf_addAssertionWithWrongProver(bytes32,bytes,uint256) (runs: 256, μ: 42675, ~: 42632) -StateOracleWithDAVerifierECDSATest:testFuzz_addAssertionWithECDSAProof(bytes32,bytes) (runs: 256, μ: 91496, ~: 91306) +StateOracleWithDAVerifierECDSATest:testFuzz_RevertIf_addAssertionWithWrongProver(bytes32,bytes,uint256) (runs: 256, μ: 42653, ~: 42610) +StateOracleWithDAVerifierECDSATest:testFuzz_addAssertionWithECDSAProof(bytes32,bytes) (runs: 256, μ: 91471, ~: 91284) StateOracleWithDAVerifierECDSATest:test_isAdmin() (gas: 953739) StorageIntegrity:test_isAdmin() (gas: 953695) -StorageIntegrity:test_storageIntegrity() (gas: 27097) -StorageIntegrity:test_storageIntegrityAfterDAVerifierRemoval() (gas: 269424) -StorageIntegrity:test_storageIntegrityAfterOperations() (gas: 279138) +StorageIntegrity:test_storageIntegrity() (gas: 27075) +StorageIntegrity:test_storageIntegrityAfterDAVerifierRemoval() (gas: 269292) +StorageIntegrity:test_storageIntegrityAfterOperations() (gas: 279028) TransferManagementBase:test_isAdmin() (gas: 953761) -TransferManager:testFuzz_RevertIf_transferManagerByUnauthorized(address,address) (runs: 256, μ: 203561, ~: 203561) -TransferManager:testFuzz_changePendingManager(address,address) (runs: 256, μ: 199181, ~: 199181) -TransferManager:testFuzz_transferManager(address) (runs: 256, μ: 194926, ~: 194926) -TransferManager:test_RevertIf_transferManagerToZeroAddress() (gas: 169304) +TransferManager:testFuzz_RevertIf_transferManagerByUnauthorized(address,address) (runs: 256, μ: 203407, ~: 203407) +TransferManager:testFuzz_changePendingManager(address,address) (runs: 256, μ: 199071, ~: 199071) +TransferManager:testFuzz_transferManager(address) (runs: 256, μ: 194882, ~: 194882) +TransferManager:test_RevertIf_transferManagerToZeroAddress() (gas: 169260) TransferManager:test_isAdmin() (gas: 953783) WhitelistBase:test_isAdmin() (gas: 953761) \ No newline at end of file diff --git a/.storage-layout b/.storage-layout index b185919..f8162ce 100644 --- a/.storage-layout +++ b/.storage-layout @@ -25,7 +25,7 @@ "type": "t_mapping(t_bytes32,t_struct(RoleData)22_storage)" }, { - "astId": 1058, + "astId": 1067, "contract": "src/StateOracle.sol:StateOracle", "label": "assertionAdopters", "offset": 0, @@ -33,23 +33,23 @@ "type": "t_mapping(t_address,t_struct(AssertionAdopter)979_storage)" }, { - "astId": 1064, + "astId": 1073, "contract": "src/StateOracle.sol:StateOracle", "label": "adminVerifiers", "offset": 0, "slot": "4", - "type": "t_mapping(t_contract(IAdminVerifier)2524,t_bool)" + "type": "t_mapping(t_contract(IAdminVerifier)2650,t_bool)" }, { - "astId": 1070, + "astId": 1079, "contract": "src/StateOracle.sol:StateOracle", "label": "daVerifiers", "offset": 0, "slot": "5", - "type": "t_mapping(t_contract(IDAVerifier)2553,t_bool)" + "type": "t_mapping(t_contract(IDAVerifier)2679,t_bool)" }, { - "astId": 1075, + "astId": 1084, "contract": "src/StateOracle.sol:StateOracle", "label": "whitelist", "offset": 0, @@ -57,7 +57,7 @@ "type": "t_mapping(t_address,t_bool)" }, { - "astId": 1078, + "astId": 1087, "contract": "src/StateOracle.sol:StateOracle", "label": "whitelistEnabled", "offset": 0, @@ -65,7 +65,7 @@ "type": "t_bool" }, { - "astId": 1081, + "astId": 1090, "contract": "src/StateOracle.sol:StateOracle", "label": "maxAssertionsPerAA", "offset": 1, @@ -89,12 +89,12 @@ "label": "bytes32", "numberOfBytes": "32" }, - "t_contract(IAdminVerifier)2524": { + "t_contract(IAdminVerifier)2650": { "encoding": "inplace", "label": "contract IAdminVerifier", "numberOfBytes": "20" }, - "t_contract(IDAVerifier)2553": { + "t_contract(IDAVerifier)2679": { "encoding": "inplace", "label": "contract IDAVerifier", "numberOfBytes": "20" @@ -127,16 +127,16 @@ "numberOfBytes": "32", "value": "t_struct(RoleData)22_storage" }, - "t_mapping(t_contract(IAdminVerifier)2524,t_bool)": { + "t_mapping(t_contract(IAdminVerifier)2650,t_bool)": { "encoding": "mapping", - "key": "t_contract(IAdminVerifier)2524", + "key": "t_contract(IAdminVerifier)2650", "label": "mapping(contract IAdminVerifier => bool)", "numberOfBytes": "32", "value": "t_bool" }, - "t_mapping(t_contract(IDAVerifier)2553,t_bool)": { + "t_mapping(t_contract(IDAVerifier)2679,t_bool)": { "encoding": "mapping", - "key": "t_contract(IDAVerifier)2553", + "key": "t_contract(IDAVerifier)2679", "label": "mapping(contract IDAVerifier => bool)", "numberOfBytes": "32", "value": "t_bool" diff --git a/Makefile b/Makefile index 172db1c..2d5000c 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: check-storage-layout update-storage-layout +.PHONY: check-storage-layout deploy update-storage-layout check-storage-layout: @bash shell/check_storage_layout.sh @@ -6,3 +6,6 @@ check-storage-layout: update-storage-layout: forge inspect StateOracle storage-layout --json > .storage-layout @echo "Storage layout snapshot updated." + +deploy: + ./shell/deploy_wizard.sh diff --git a/README.md b/README.md index aab0155..9f49f89 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,33 @@ State Oracle Implementation deployed at
State Oracle Proxy deployed at
``` +### Interactive deployment wizard + +Run the terminal wizard from the repository root: + +```sh +make deploy +``` + +The wizard uses `DeployCore` as its deployment backend and guides you through: + +- production or testing mode, plus an optional staging State Oracle; +- admin verifier selection and assignment to the production and/or staging oracle; +- ECDSA and/or on-chain DA verification, independently assigned to each State Oracle; +- initial State Oracle whitelist state and addresses; +- optional explorer verification using `ETHERSCAN_API_KEY`; +- all State Oracle limits, timelocks, admins, and verifier-specific addresses; and +- a Foundry keystore account selected from `cast wallet list`. + +The wallet password and explorer API key are read without echoing. The password is checked before +deployment and stored only in a temporary mode-`600` file that is removed when the wizard exits. +Before broadcasting, the wizard prints a redacted Forge command and a complete configuration +summary. After broadcasting, it reads Foundry's receipt file and prints every deployment address, +block number, transaction hash, and proxy admin address. + +Testing mode also exposes the `Super Admin` and `Always Approve` admin verifiers. These options are +rejected by the Solidity deployment backend unless testing mode is explicitly enabled. + ## Installation 1. Clone the repository: diff --git a/package.json b/package.json index 294b558..68300a7 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,9 @@ "scripts": { "prepare": "./shell/create_artifacts.sh", "test": "forge test", + "test:deploy-wizard": "python3 test/shell/test_deploy_wizard.py", "build": "forge build", + "deploy:wizard": "./shell/deploy_wizard.sh", "format": "forge fmt", "clean": "forge clean" }, diff --git a/script/DeployCore.s.sol b/script/DeployCore.s.sol index 27caf5e..cb85d60 100644 --- a/script/DeployCore.s.sol +++ b/script/DeployCore.s.sol @@ -166,6 +166,7 @@ contract DeployCore is Script { } function _deployWhitelistAdminVerifier() internal virtual returns (address verifier) { + require(whitelistAdmin != address(0), "Invalid whitelist admin"); verifier = address(new AdminVerifierWhitelist(whitelistAdmin)); console2.log("Admin Verifier (Whitelist) deployed at", verifier); return verifier; diff --git a/script/DeployTestingAdminVerifiers.s.sol b/script/DeployTestingAdminVerifiers.s.sol new file mode 100644 index 0000000..5360272 --- /dev/null +++ b/script/DeployTestingAdminVerifiers.s.sol @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: CC0-1.0 +pragma solidity ^0.8.28; + +import {StateOracle} from "../src/StateOracle.sol"; +import {IAdminVerifier} from "../src/interfaces/IAdminVerifier.sol"; +import {AdminVerifierAlwaysApprove} from "../src/verification/admin/AdminVerifierAlwaysApprove.sol"; +import {AdminVerifierSuperAdmin} from "../src/verification/admin/AdminVerifierSuperAdmin.sol"; +import {console2} from "forge-std/console2.sol"; +import {Script} from "forge-std/Script.sol"; + +contract DeployTestingAdminVerifiers is Script { + address stateOracle; + address superAdmin; + bool deploySuperAdminVerifierEnabled; + bool deployAlwaysApproveVerifierEnabled; + bool addToStateOracle; + + function setUp() public virtual { + stateOracle = vm.envOr("TEST_STATE_ORACLE_ADDRESS", address(0)); + superAdmin = vm.envOr("TEST_ADMIN_VERIFIER_SUPER_ADMIN_ADDRESS", address(0)); + deploySuperAdminVerifierEnabled = vm.envOr("DEPLOY_TEST_ADMIN_VERIFIER_SUPER_ADMIN", false); + deployAlwaysApproveVerifierEnabled = vm.envOr("DEPLOY_TEST_ADMIN_VERIFIER_ALWAYS_APPROVE", false); + addToStateOracle = vm.envOr("ADD_TEST_ADMIN_VERIFIERS_TO_STATE_ORACLE", false); + } + + modifier broadcast() { + vm.startBroadcast(); + _; + vm.stopBroadcast(); + } + + function run() public broadcast { + _run(); + } + + function deploySuperAdminVerifier(address _superAdmin) public broadcast returns (address) { + return _deploySuperAdminVerifier(_superAdmin); + } + + function deployAlwaysApproveAdminVerifier() public broadcast returns (address) { + return _deployAlwaysApproveAdminVerifier(); + } + + function deployAndAddSuperAdminVerifier(address _stateOracle, address _superAdmin) + public + broadcast + returns (address verifier) + { + verifier = _deploySuperAdminVerifier(_superAdmin); + _addAdminVerifier(_stateOracle, verifier); + } + + function deployAndAddAlwaysApproveAdminVerifier(address _stateOracle) public broadcast returns (address verifier) { + verifier = _deployAlwaysApproveAdminVerifier(); + _addAdminVerifier(_stateOracle, verifier); + } + + function addAdminVerifier(address _stateOracle, address verifier) public broadcast { + _addAdminVerifier(_stateOracle, verifier); + } + + function _run() internal returns (address[] memory deployments) { + deployments = _deployEnabledAdminVerifiers(); + if (addToStateOracle) { + _addAdminVerifiers(stateOracle, deployments); + } + } + + function _deployEnabledAdminVerifiers() internal returns (address[] memory deployments) { + uint256 count; + if (deploySuperAdminVerifierEnabled) count++; + if (deployAlwaysApproveVerifierEnabled) count++; + require(count > 0, "No test verifiers enabled"); + + deployments = new address[](count); + uint256 index; + if (deploySuperAdminVerifierEnabled) { + deployments[index++] = _deploySuperAdminVerifier(superAdmin); + } + if (deployAlwaysApproveVerifierEnabled) { + deployments[index++] = _deployAlwaysApproveAdminVerifier(); + } + } + + function _deploySuperAdminVerifier(address _superAdmin) internal virtual returns (address verifier) { + require(_superAdmin != address(0), "Invalid super admin"); + verifier = address(new AdminVerifierSuperAdmin(_superAdmin)); + console2.log("Testing Admin Verifier (Super Admin) deployed at", verifier); + } + + function _deployAlwaysApproveAdminVerifier() internal virtual returns (address verifier) { + verifier = address(new AdminVerifierAlwaysApprove()); + console2.log("Testing Admin Verifier (Always Approve) deployed at", verifier); + } + + function _addAdminVerifiers(address _stateOracle, address[] memory verifiers) internal { + require(_stateOracle != address(0), "Invalid state oracle"); + for (uint256 i = 0; i < verifiers.length; i++) { + _addAdminVerifier(_stateOracle, verifiers[i]); + } + } + + function _addAdminVerifier(address _stateOracle, address verifier) internal { + require(_stateOracle != address(0), "Invalid state oracle"); + require(verifier != address(0), "Invalid admin verifier"); + StateOracle(_stateOracle).addAdminVerifier(IAdminVerifier(verifier)); + console2.log("Testing admin verifier added to StateOracle", verifier); + } +} diff --git a/script/DeployWizard.s.sol b/script/DeployWizard.s.sol new file mode 100644 index 0000000..48bb9de --- /dev/null +++ b/script/DeployWizard.s.sol @@ -0,0 +1,261 @@ +// SPDX-License-Identifier: CC0-1.0 +pragma solidity ^0.8.28; + +import {DeployCore} from "./DeployCore.s.sol"; +import {StateOracle} from "../src/StateOracle.sol"; +import {IAdminVerifier} from "../src/interfaces/IAdminVerifier.sol"; +import {IDAVerifier} from "../src/interfaces/IDAVerifier.sol"; +import {AdminVerifierAlwaysApprove} from "../src/verification/admin/AdminVerifierAlwaysApprove.sol"; +import {AdminVerifierSuperAdmin} from "../src/verification/admin/AdminVerifierSuperAdmin.sol"; +import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {console2} from "forge-std/console2.sol"; + +/// @notice Deployment backend for shell/deploy_wizard.sh. +/// @dev DeployCore remains the source of the production deployment primitives. This +/// script only adds per-oracle verifier selection and initial whitelist configuration. +contract DeployWizard is DeployCore { + struct VerifierDeployments { + address daECDSA; + address daOnChain; + address adminOwner; + address adminWhitelist; + address adminSuperAdmin; + address adminAlwaysApprove; + } + + bool internal deploymentIsTesting; + bool internal deployStaging; + bool internal whitelistEnabled; + + bool internal daECDSAProduction; + bool internal daECDSAStaging; + bool internal daOnChainProduction; + bool internal daOnChainStaging; + + bool internal adminOwnerProduction; + bool internal adminOwnerStaging; + bool internal adminWhitelistProduction; + bool internal adminWhitelistStaging; + bool internal adminSuperAdminProduction; + bool internal adminSuperAdminStaging; + bool internal adminAlwaysApproveProduction; + bool internal adminAlwaysApproveStaging; + + uint256 internal stagingAssertionTimelockBlocks; + uint16 internal stagingMaxAssertionsPerAA; + address internal testSuperAdmin; + address[] internal initialWhitelist; + + function setUp() public override { + deploymentIsTesting = vm.envOr("DEPLOYMENT_IS_TESTING", false); + deployStaging = vm.envOr("DEPLOY_STAGING_STATE_ORACLE", false); + whitelistEnabled = vm.envOr("STATE_ORACLE_WHITELIST_ENABLED", true); + + admin = vm.envAddress("STATE_ORACLE_ADMIN_ADDRESS"); + require(admin != address(0), "Invalid State Oracle admin"); + + uint256 rawMaxAssertions = vm.envUint("STATE_ORACLE_MAX_ASSERTIONS_PER_AA"); + require(rawMaxAssertions > 0 && rawMaxAssertions <= type(uint16).max, "Invalid max assertions"); + // The bounds check above makes this narrowing conversion safe. + // forge-lint: disable-next-line(unsafe-typecast) + maxAssertionsPerAA = uint16(rawMaxAssertions); + + uint256 rawTimelock = vm.envUint("STATE_ORACLE_ASSERTION_TIMELOCK_BLOCKS"); + require(rawTimelock > 0, "Invalid assertion timelock"); + assertionTimelockBlocks = rawTimelock; + + if (deployStaging) { + uint256 rawStagingMaxAssertions = vm.envUint("STAGING_STATE_ORACLE_MAX_ASSERTIONS_PER_AA"); + require( + rawStagingMaxAssertions > 0 && rawStagingMaxAssertions <= type(uint16).max, + "Invalid staging max assertions" + ); + // The bounds check above makes this narrowing conversion safe. + // forge-lint: disable-next-line(unsafe-typecast) + stagingMaxAssertionsPerAA = uint16(rawStagingMaxAssertions); + + uint256 rawStagingTimelock = vm.envUint("STAGING_STATE_ORACLE_ASSERTION_TIMELOCK_BLOCKS"); + require(rawStagingTimelock > 0, "Invalid staging assertion timelock"); + stagingAssertionTimelockBlocks = rawStagingTimelock; + } + + _loadVerifierConfiguration(); + + initialWhitelist = vm.envOr("STATE_ORACLE_INITIAL_WHITELIST", ",", new address[](0)); + } + + function run() public override broadcast { + _fundPersistentAccounts(); + + VerifierDeployments memory deployed = _deploySelectedVerifiers(); + + _deployConfiguredOracle( + "Production", + _selectedAdminVerifiers(true, deployed), + _selectedDAVerifiers(true, deployed), + assertionTimelockBlocks, + maxAssertionsPerAA + ); + + if (deployStaging) { + _deployConfiguredOracle( + "Staging", + _selectedAdminVerifiers(false, deployed), + _selectedDAVerifiers(false, deployed), + stagingAssertionTimelockBlocks, + stagingMaxAssertionsPerAA + ); + } + } + + function _loadVerifierConfiguration() internal { + daECDSAProduction = vm.envOr("DA_VERIFIER_ECDSA_PRODUCTION", false); + daECDSAStaging = vm.envOr("DA_VERIFIER_ECDSA_STAGING", false); + daOnChainProduction = vm.envOr("DA_VERIFIER_ONCHAIN_PRODUCTION", false); + daOnChainStaging = vm.envOr("DA_VERIFIER_ONCHAIN_STAGING", false); + + require(_selectedDAVerifierCount(true) > 0, "Production requires a DA verifier"); + require(!deployStaging || _selectedDAVerifierCount(false) > 0, "Staging requires a DA verifier"); + require(deployStaging || !(daECDSAStaging || daOnChainStaging), "Staging DA verifier selected without staging"); + + if (daECDSAProduction || daECDSAStaging) { + daProver = vm.envAddress("DA_PROVER_ADDRESS"); + require(daProver != address(0), "Invalid DA prover"); + } + + adminOwnerProduction = vm.envOr("ADMIN_VERIFIER_OWNER_PRODUCTION", false); + adminOwnerStaging = vm.envOr("ADMIN_VERIFIER_OWNER_STAGING", false); + adminWhitelistProduction = vm.envOr("ADMIN_VERIFIER_WHITELIST_PRODUCTION", false); + adminWhitelistStaging = vm.envOr("ADMIN_VERIFIER_WHITELIST_STAGING", false); + adminSuperAdminProduction = vm.envOr("ADMIN_VERIFIER_SUPER_ADMIN_PRODUCTION", false); + adminSuperAdminStaging = vm.envOr("ADMIN_VERIFIER_SUPER_ADMIN_STAGING", false); + adminAlwaysApproveProduction = vm.envOr("ADMIN_VERIFIER_ALWAYS_APPROVE_PRODUCTION", false); + adminAlwaysApproveStaging = vm.envOr("ADMIN_VERIFIER_ALWAYS_APPROVE_STAGING", false); + + require(_selectedAdminVerifierCount(true) > 0, "Production requires an admin verifier"); + require(!deployStaging || _selectedAdminVerifierCount(false) > 0, "Staging requires an admin verifier"); + require( + deployStaging + || !(adminOwnerStaging || adminWhitelistStaging || adminSuperAdminStaging || adminAlwaysApproveStaging), + "Staging admin verifier selected without staging" + ); + + if (adminWhitelistProduction || adminWhitelistStaging) { + whitelistAdmin = vm.envAddress("ADMIN_VERIFIER_WHITELIST_ADMIN_ADDRESS"); + require(whitelistAdmin != address(0), "Invalid admin verifier whitelist owner"); + } + + if (adminSuperAdminProduction || adminSuperAdminStaging) { + require(deploymentIsTesting, "Super Admin verifier is test-only"); + testSuperAdmin = vm.envAddress("TEST_ADMIN_VERIFIER_SUPER_ADMIN_ADDRESS"); + require(testSuperAdmin != address(0), "Invalid test super admin"); + } + require( + deploymentIsTesting || !(adminAlwaysApproveProduction || adminAlwaysApproveStaging), + "Always Approve verifier is test-only" + ); + } + + function _deploySelectedVerifiers() internal returns (VerifierDeployments memory deployed) { + if (daECDSAProduction || daECDSAStaging) { + deployed.daECDSA = _deployDAVerifierECDSA(); + _logDeployment("DA Verifier (ECDSA)", deployed.daECDSA); + } + if (daOnChainProduction || daOnChainStaging) { + deployed.daOnChain = _deployDAVerifierOnChain(); + _logDeployment("DA Verifier (On-chain)", deployed.daOnChain); + } + if (adminOwnerProduction || adminOwnerStaging) { + deployed.adminOwner = _deployOwnerAdminVerifier(); + _logDeployment("Admin Verifier (Owner)", deployed.adminOwner); + } + if (adminWhitelistProduction || adminWhitelistStaging) { + deployed.adminWhitelist = _deployWhitelistAdminVerifier(); + _logDeployment("Admin Verifier (Whitelist)", deployed.adminWhitelist); + } + if (adminSuperAdminProduction || adminSuperAdminStaging) { + deployed.adminSuperAdmin = address(new AdminVerifierSuperAdmin(testSuperAdmin)); + console2.log("Testing Admin Verifier (Super Admin) deployed at", deployed.adminSuperAdmin); + _logDeployment("Testing Admin Verifier (Super Admin)", deployed.adminSuperAdmin); + } + if (adminAlwaysApproveProduction || adminAlwaysApproveStaging) { + deployed.adminAlwaysApprove = address(new AdminVerifierAlwaysApprove()); + console2.log("Testing Admin Verifier (Always Approve) deployed at", deployed.adminAlwaysApprove); + _logDeployment("Testing Admin Verifier (Always Approve)", deployed.adminAlwaysApprove); + } + } + + function _selectedDAVerifiers(bool production, VerifierDeployments memory deployed) + internal + view + returns (address[] memory verifiers) + { + verifiers = new address[](_selectedDAVerifierCount(production)); + uint256 index; + if (production ? daECDSAProduction : daECDSAStaging) verifiers[index++] = deployed.daECDSA; + if (production ? daOnChainProduction : daOnChainStaging) verifiers[index] = deployed.daOnChain; + } + + function _selectedDAVerifierCount(bool production) internal view returns (uint256 count) { + if (production ? daECDSAProduction : daECDSAStaging) count++; + if (production ? daOnChainProduction : daOnChainStaging) count++; + } + + function _selectedAdminVerifiers(bool production, VerifierDeployments memory deployed) + internal + view + returns (address[] memory verifiers) + { + verifiers = new address[](_selectedAdminVerifierCount(production)); + uint256 index; + if (production ? adminOwnerProduction : adminOwnerStaging) verifiers[index++] = deployed.adminOwner; + if (production ? adminWhitelistProduction : adminWhitelistStaging) { + verifiers[index++] = deployed.adminWhitelist; + } + if (production ? adminSuperAdminProduction : adminSuperAdminStaging) { + verifiers[index++] = deployed.adminSuperAdmin; + } + if (production ? adminAlwaysApproveProduction : adminAlwaysApproveStaging) { + verifiers[index] = deployed.adminAlwaysApprove; + } + } + + function _selectedAdminVerifierCount(bool production) internal view returns (uint256 count) { + if (production ? adminOwnerProduction : adminOwnerStaging) count++; + if (production ? adminWhitelistProduction : adminWhitelistStaging) count++; + if (production ? adminSuperAdminProduction : adminSuperAdminStaging) count++; + if (production ? adminAlwaysApproveProduction : adminAlwaysApproveStaging) count++; + } + + function _deployConfiguredOracle( + string memory environment, + address[] memory adminVerifierDeployments, + address[] memory daVerifierDeployments, + uint256 timelockBlocks, + uint16 maxAssertions + ) internal returns (address proxyAddress) { + address implementation = _deployStateOracle(timelockBlocks, string.concat(environment, " State Oracle")); + _logDeployment(string.concat(environment, " State Oracle Implementation"), implementation); + + IAdminVerifier[] memory adminVerifiers = new IAdminVerifier[](adminVerifierDeployments.length); + for (uint256 i = 0; i < adminVerifierDeployments.length; i++) { + adminVerifiers[i] = IAdminVerifier(adminVerifierDeployments[i]); + } + IDAVerifier[] memory daVerifiers = new IDAVerifier[](daVerifierDeployments.length); + for (uint256 i = 0; i < daVerifierDeployments.length; i++) { + daVerifiers[i] = IDAVerifier(daVerifierDeployments[i]); + } + + bytes memory initCallData = abi.encodeCall( + StateOracle.initializeWithWhitelist, + (admin, adminVerifiers, daVerifiers, maxAssertions, whitelistEnabled, initialWhitelist) + ); + proxyAddress = address(new TransparentUpgradeableProxy(implementation, admin, initCallData)); + console2.log(string.concat(environment, " State Oracle Proxy deployed at"), proxyAddress); + _logDeployment(string.concat(environment, " State Oracle Proxy"), proxyAddress); + } + + function _logDeployment(string memory name, address deployedAddress) internal pure { + console2.log(string.concat("WIZARD_DEPLOYMENT|", name, "|"), deployedAddress); + } +} diff --git a/shell/deploy_wizard.sh b/shell/deploy_wizard.sh new file mode 100755 index 0000000..13affaa --- /dev/null +++ b/shell/deploy_wizard.sh @@ -0,0 +1,841 @@ +#!/usr/bin/env bash + +set -Eeuo pipefail + +ROOT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) +PASSWORD_FILE="" +FORGE_OUTPUT_FILE="" +CURSOR_HIDDEN=false +COLOR_RESET="" +COLOR_BOLD="" +COLOR_DIM="" +COLOR_RED="" +COLOR_GREEN="" +COLOR_YELLOW="" +COLOR_BLUE="" +COLOR_MAGENTA="" +COLOR_CYAN="" + +cleanup() { + if [[ "$CURSOR_HIDDEN" == "true" ]]; then + { printf '\033[?25h' >/dev/tty; } 2>/dev/null || true + fi + if [[ -n "$PASSWORD_FILE" && -f "$PASSWORD_FILE" ]]; then + rm -f "$PASSWORD_FILE" + fi + if [[ -n "$FORGE_OUTPUT_FILE" && -f "$FORGE_OUTPUT_FILE" ]]; then + rm -f "$FORGE_OUTPUT_FILE" + fi +} +trap cleanup EXIT +trap 'exit 130' INT TERM + +usage() { + cat <<'EOF' +Usage: ./shell/deploy_wizard.sh + +Interactively configures and deploys the Credible Layer contracts. Use the +arrow keys to move, Space to toggle multi-select entries, and Enter to accept. + +The wizard reads existing values from these variables as prompt defaults: + RPC_URL or ETH_RPC_URL + ETHERSCAN_API_KEY + STATE_ORACLE_MAX_ASSERTIONS_PER_AA + STATE_ORACLE_ASSERTION_TIMELOCK_BLOCKS + STATE_ORACLE_ADMIN_ADDRESS + STAGING_STATE_ORACLE_MAX_ASSERTIONS_PER_AA + STAGING_STATE_ORACLE_ASSERTION_TIMELOCK_BLOCKS + DA_PROVER_ADDRESS + ADMIN_VERIFIER_WHITELIST_ADMIN_ADDRESS + TEST_ADMIN_VERIFIER_SUPER_ADMIN_ADDRESS +EOF +} + +die() { + printf '%sError:%s %s\n' "${COLOR_BOLD}${COLOR_RED}" "$COLOR_RESET" "$*" >&2 + exit 1 +} + +init_colors() { + if [[ -v NO_COLOR || ${TERM:-} == "dumb" ]]; then + return + fi + + COLOR_RESET=$'\033[0m' + COLOR_BOLD=$'\033[1m' + COLOR_DIM=$'\033[2m' + COLOR_RED=$'\033[31m' + COLOR_GREEN=$'\033[32m' + COLOR_YELLOW=$'\033[33m' + COLOR_BLUE=$'\033[34m' + COLOR_MAGENTA=$'\033[35m' + COLOR_CYAN=$'\033[36m' +} + +tty_print() { + printf '%s' "$*" >/dev/tty +} + +tty_println() { + printf '%s\n' "$*" >/dev/tty +} + +tty_heading() { + tty_println "${COLOR_BOLD}${COLOR_CYAN}$*${COLOR_RESET}" +} + +tty_section() { + tty_println "${COLOR_BOLD}${COLOR_MAGENTA}$*${COLOR_RESET}" +} + +tty_hint() { + tty_println "${COLOR_DIM}$*${COLOR_RESET}" +} + +tty_warn() { + tty_println "${COLOR_BOLD}${COLOR_YELLOW}Warning:${COLOR_RESET} $*" +} + +tty_success() { + tty_println "${COLOR_BOLD}${COLOR_GREEN}$*${COLOR_RESET}" +} + +tty_field() { + local label=$1 + shift + printf ' %s%-21s%s %s%s%s\n' \ + "$COLOR_CYAN" "${label}:" "$COLOR_RESET" "$COLOR_GREEN" "$*" "$COLOR_RESET" >/dev/tty +} + +require_command() { + command -v "$1" >/dev/null 2>&1 || die "Required command not found: $1" +} + +read_key() { + local key suffix + IFS= read -rsn1 key /dev/tty + CURSOR_HIDDEN=true + + while true; do + if [[ $rendered -eq 1 ]]; then + printf '\033[%dA' "$count" >/dev/tty + fi + for ((i = 0; i < count; i++)); do + prefix=" " + if [[ $i -eq $selected ]]; then + prefix="${COLOR_BOLD}${COLOR_BLUE}› " + printf '\r\033[2K%s%s%s\n' "$prefix" "${items[$i]}" "$COLOR_RESET" >/dev/tty + else + printf '\r\033[2K%s%s\n' "$prefix" "${items[$i]}" >/dev/tty + fi + done + rendered=1 + + read_key + case "$KEY_RESULT" in + $'\033[A') + selected=$(((selected - 1 + count) % count)) + ;; + $'\033[B') + selected=$(((selected + 1) % count)) + ;; + "") + break + ;; + esac + done + + printf '\033[?25h' >/dev/tty + CURSOR_HIDDEN=false + MENU_INDEX=$selected + MENU_VALUE=${items[$selected]} +} + +menu_select_many() { + local question=$1 + shift + local items=("$@") + local cursor=0 + local rendered=0 + local count=${#items[@]} + local selected_count i marker prefix + + MULTI_SELECTED=() + for ((i = 0; i < count; i++)); do + MULTI_SELECTED[$i]=0 + done + + tty_println "" + tty_heading "$question" + tty_hint " ↑/↓ move · Space toggle · Enter continue" + printf '\033[?25l' >/dev/tty + CURSOR_HIDDEN=true + + while true; do + if [[ $rendered -eq 1 ]]; then + printf '\033[%dA' "$count" >/dev/tty + fi + for ((i = 0; i < count; i++)); do + marker="[ ]" + prefix=" " + if [[ ${MULTI_SELECTED[$i]} -eq 1 ]]; then + marker="${COLOR_BOLD}${COLOR_GREEN}[x]${COLOR_RESET}" + fi + if [[ $i -eq $cursor ]]; then + prefix="${COLOR_BOLD}${COLOR_BLUE}› ${COLOR_RESET}" + fi + printf '\r\033[2K%s%s %s\n' "$prefix" "$marker" "${items[$i]}" >/dev/tty + done + rendered=1 + + read_key + case "$KEY_RESULT" in + $'\033[A') + cursor=$(((cursor - 1 + count) % count)) + ;; + $'\033[B') + cursor=$(((cursor + 1) % count)) + ;; + " ") + if [[ ${MULTI_SELECTED[$cursor]} -eq 1 ]]; then + MULTI_SELECTED[$cursor]=0 + else + MULTI_SELECTED[$cursor]=1 + fi + ;; + "") + selected_count=0 + for ((i = 0; i < count; i++)); do + selected_count=$((selected_count + MULTI_SELECTED[i])) + done + if [[ $selected_count -gt 0 ]]; then + break + fi + printf '\a' >/dev/tty + ;; + esac + done + + printf '\033[?25h' >/dev/tty + CURSOR_HIDDEN=false +} + +prompt_value() { + local label=$1 + local default_value=${2:-} + local value + + while true; do + if [[ -n "$default_value" ]]; then + printf '%s%s%s %s[%s]%s: ' \ + "$COLOR_BOLD" "$label" "$COLOR_RESET" "$COLOR_DIM" "$default_value" "$COLOR_RESET" >/dev/tty + else + printf '%s%s%s: ' "$COLOR_BOLD" "$label" "$COLOR_RESET" >/dev/tty + fi + IFS= read -r value /dev/tty + IFS= read -rs value /dev/null); then + lower=$(printf '%s' "$checksum" | tr '[:upper:]' '[:lower:]') + if [[ "$lower" != "0x0000000000000000000000000000000000000000" ]]; then + PROMPT_RESULT=$checksum + return + fi + fi + tty_warn "Enter a non-zero Ethereum address." + done +} + +decimal_le() { + local value=$1 + local maximum=$2 + + value=$(printf '%s' "$value" | sed 's/^0*//') + [[ -n "$value" ]] || value=0 + if [[ ${#value} -lt ${#maximum} ]]; then + return 0 + fi + if [[ ${#value} -gt ${#maximum} ]]; then + return 1 + fi + [[ "$value" == "$maximum" || "$value" < "$maximum" ]] +} + +prompt_uint() { + local label=$1 + local default_value=$2 + local maximum=$3 + + while true; do + prompt_value "$label" "$default_value" + if [[ "$PROMPT_RESULT" =~ ^[0-9]+$ ]] && [[ "$PROMPT_RESULT" != "0" ]] \ + && decimal_le "$PROMPT_RESULT" "$maximum"; then + PROMPT_RESULT=$(printf '%s' "$PROMPT_RESULT" | sed 's/^0*//') + [[ -n "$PROMPT_RESULT" ]] || PROMPT_RESULT=0 + return + fi + tty_warn "Enter an integer from 1 through $maximum." + done +} + +bool_for_selection() { + if [[ $1 -eq 1 ]]; then + printf 'true' + else + printf 'false' + fi +} + +join_by_comma() { + local joined="" + local value + for value in "$@"; do + if [[ -n "$joined" ]]; then + joined="${joined},${value}" + else + joined=$value + fi + done + printf '%s' "$joined" +} + +print_redacted_command() { + local item redact_next=false + tty_println "" + tty_section "Wallet password validation command" + printf ' cast wallet address --account %q --password-file \n' "$wallet_account" >/dev/tty + tty_println "" + tty_section "Forge deployment command" + tty_println " env \\" + for item in "${env_args[@]}"; do + case "$item" in + ETH_RPC_URL=*) item='ETH_RPC_URL=' ;; + ETHERSCAN_API_KEY=*) item='ETHERSCAN_API_KEY=' ;; + esac + printf ' %q \\\n' "$item" >/dev/tty + done + tty_print " forge" + for item in "${forge_args[@]}"; do + if [[ "$redact_next" == "true" ]]; then + item='' + redact_next=false + elif [[ "$item" == "--rpc-url" ]]; then + redact_next=true + elif [[ "$item" == "$PASSWORD_FILE" ]]; then + item='' + fi + printf ' %q' "$item" >/dev/tty + done + tty_println "" +} + +lookup_transaction() { + local broadcast_file=$1 + local address=$2 + jq -r --arg address "$address" ' + [.transactions[] + | select(((.contractAddress // "") | ascii_downcase) == ($address | ascii_downcase))] + | last + | .hash // empty + ' "$broadcast_file" +} + +lookup_block_hex() { + local broadcast_file=$1 + local transaction_hash=$2 + jq -r --arg hash "$transaction_hash" ' + [.receipts[] | select((.transactionHash // "") == $hash)] + | last + | .blockNumber // empty + ' "$broadcast_file" +} + +print_deployment_summary() { + local broadcast_file=$1 + local deployments label address transaction_hash block_hex block_number proxy_admin + + deployments=$(sed -nE \ + 's/^.*WIZARD_DEPLOYMENT\|([^|]+)\|[[:space:]]*(0x[[:xdigit:]]{40}).*$/\1|\2/p' \ + "$FORGE_OUTPUT_FILE" | awk -F'|' '!seen[$1 "|" tolower($2)]++') + + tty_println "" + tty_success "Deployment complete" + tty_field "Chain ID" "$chain_id" + tty_field "Deployer" "$wallet_address ($wallet_account)" + tty_field "Broadcast data" "$broadcast_file" + tty_println "" + + if [[ -z "$deployments" ]]; then + tty_warn "Foundry completed, but no deployment markers were found in its output." + return + fi + + while IFS='|' read -r label address; do + transaction_hash=$(lookup_transaction "$broadcast_file" "$address") + block_hex="" + block_number="unknown" + if [[ -n "$transaction_hash" ]]; then + block_hex=$(lookup_block_hex "$broadcast_file" "$transaction_hash") + if [[ -n "$block_hex" ]]; then + block_number=$(printf '%d' "$block_hex") + fi + else + transaction_hash="unknown" + fi + + tty_section "$label" + tty_field "Address" "$address" + tty_field "Block" "$block_number" + tty_field "Transaction" "$transaction_hash" + + case "$label" in + *"State Oracle Proxy") + proxy_admin=$(jq -r --arg hash "$transaction_hash" ' + .transactions[] + | select((.hash // "") == $hash) + | .additionalContracts[]? + | select(.contractName == "ProxyAdmin") + | .address + ' "$broadcast_file" | tail -n 1) + if [[ -n "$proxy_admin" ]]; then + tty_field "Proxy admin" "$proxy_admin (same block and transaction)" + fi + ;; + esac + tty_println "" + done </dev/null || ! { : >/dev/tty; } 2>/dev/null; then + die "This wizard requires an interactive terminal" +fi + +init_colors +require_command forge +require_command cast +require_command jq + +cd "$ROOT_DIR" + +tty_heading "Credible Layer deployment wizard" +tty_hint "================================" + +menu_select_one "What kind of deployment is this?" "Production" "Testing" +deployment_kind=$MENU_VALUE +deployment_is_testing=false +if [[ "$deployment_kind" == "Testing" ]]; then + deployment_is_testing=true +fi + +menu_select_one "Deploy a staging State Oracle as well?" "No" "Yes" +deploy_staging=false +if [[ "$MENU_VALUE" == "Yes" ]]; then + deploy_staging=true +fi + +admin_options=("Owner" "Whitelist") +if [[ "$deployment_is_testing" == "true" ]]; then + admin_options[2]="Super Admin (test-only)" + admin_options[3]="Always Approve (test-only, unsafe)" +fi +menu_select_many "Which admin verifiers should be deployed?" "${admin_options[@]}" +admin_selected=("${MULTI_SELECTED[@]}") + +admin_production=(0 0 0 0) +admin_staging=(0 0 0 0) +while true; do + admin_production=(0 0 0 0) + admin_staging=(0 0 0 0) + for ((i = 0; i < ${#admin_options[@]}; i++)); do + [[ ${admin_selected[$i]} -eq 1 ]] || continue + if [[ "$deploy_staging" == "true" ]]; then + menu_select_many "Add ${admin_options[$i]} to which State Oracle(s)?" "Production" "Staging" + admin_production[$i]=${MULTI_SELECTED[0]} + admin_staging[$i]=${MULTI_SELECTED[1]} + else + menu_select_many "Add ${admin_options[$i]} to which State Oracle(s)?" "Production" + admin_production[$i]=${MULTI_SELECTED[0]} + fi + done + + production_count=0 + staging_count=0 + for ((i = 0; i < ${#admin_options[@]}; i++)); do + production_count=$((production_count + admin_production[i])) + staging_count=$((staging_count + admin_staging[i])) + done + if [[ $production_count -gt 0 ]] && { [[ "$deploy_staging" == "false" ]] || [[ $staging_count -gt 0 ]]; }; then + break + fi + tty_warn "Each State Oracle needs at least one admin verifier. Please assign them again." +done + +da_options=("ECDSA signatures" "On-chain bytecode") +menu_select_many "Which DA verifiers should be deployed?" "${da_options[@]}" +da_selected=("${MULTI_SELECTED[@]}") + +da_production=(0 0) +da_staging=(0 0) +while true; do + da_production=(0 0) + da_staging=(0 0) + for ((i = 0; i < ${#da_options[@]}; i++)); do + [[ ${da_selected[$i]} -eq 1 ]] || continue + if [[ "$deploy_staging" == "true" ]]; then + menu_select_many "Add ${da_options[$i]} to which State Oracle(s)?" "Production" "Staging" + da_production[$i]=${MULTI_SELECTED[0]} + da_staging[$i]=${MULTI_SELECTED[1]} + else + menu_select_many "Add ${da_options[$i]} to which State Oracle(s)?" "Production" + da_production[$i]=${MULTI_SELECTED[0]} + fi + done + + production_count=$((da_production[0] + da_production[1])) + staging_count=$((da_staging[0] + da_staging[1])) + if [[ $production_count -gt 0 ]] && { [[ "$deploy_staging" == "false" ]] || [[ $staging_count -gt 0 ]]; }; then + break + fi + tty_warn "Each State Oracle needs at least one DA verifier. Please assign them again." +done + +menu_select_one "Should the State Oracle whitelist be enabled?" "Enabled" "Disabled" +whitelist_enabled=true +if [[ "$MENU_VALUE" == "Disabled" ]]; then + whitelist_enabled=false +fi + +whitelist_addresses=() +if [[ "$whitelist_enabled" == "true" ]]; then + menu_select_one "Add addresses to the initial whitelist?" "No" "Yes" + if [[ "$MENU_VALUE" == "Yes" ]]; then + while true; do + prompt_address "Address to whitelist" "" + candidate=$PROMPT_RESULT + duplicate=false + for existing in "${whitelist_addresses[@]-}"; do + if [[ "$(printf '%s' "$existing" | tr '[:upper:]' '[:lower:]')" \ + == "$(printf '%s' "$candidate" | tr '[:upper:]' '[:lower:]')" ]]; then + duplicate=true + fi + done + if [[ "$duplicate" == "true" ]]; then + tty_warn "That address is already in the initial whitelist." + else + whitelist_addresses[${#whitelist_addresses[@]}]=$candidate + fi + + menu_select_one "Initial whitelist now contains ${#whitelist_addresses[@]} address(es)." \ + "Add another address" "Done" + [[ "$MENU_VALUE" == "Add another address" ]] || break + done + fi +fi + +menu_select_one "Verify deployed contracts on the block explorer?" "Yes" "No" +verify_contracts=false +etherscan_api_key="" +if [[ "$MENU_VALUE" == "Yes" ]]; then + verify_contracts=true + etherscan_api_key=${ETHERSCAN_API_KEY:-} + if [[ -z "$etherscan_api_key" ]]; then + while ! prompt_secret "ETHERSCAN_API_KEY"; do + tty_warn "An API key is required when verification is enabled." + done + etherscan_api_key=$PROMPT_RESULT + PROMPT_RESULT="" + else + tty_success "Using the non-empty ETHERSCAN_API_KEY from the environment." + fi +fi + +default_rpc=${RPC_URL:-${ETH_RPC_URL:-}} +while true; do + prompt_value "RPC URL" "$default_rpc" + rpc_url=$PROMPT_RESULT + if chain_id=$(cast chain-id --rpc-url "$rpc_url" 2>/dev/null); then + break + fi + tty_warn "Could not connect to that RPC URL." +done +tty_success "Connected to chain ID $chain_id." + +prompt_uint "Maximum assertions per adopter" "${STATE_ORACLE_MAX_ASSERTIONS_PER_AA:-}" "65535" +max_assertions=$PROMPT_RESULT +prompt_uint "Assertion timelock in blocks" "${STATE_ORACLE_ASSERTION_TIMELOCK_BLOCKS:-}" \ + "115792089237316195423570985008687907853269984665640564039457584007913129639935" +assertion_timelock=$PROMPT_RESULT +prompt_address "State Oracle admin" "${STATE_ORACLE_ADMIN_ADDRESS:-}" +state_oracle_admin=$PROMPT_RESULT + +staging_max_assertions="" +staging_assertion_timelock="" +if [[ "$deploy_staging" == "true" ]]; then + prompt_uint "Staging maximum assertions per adopter" \ + "${STAGING_STATE_ORACLE_MAX_ASSERTIONS_PER_AA:-}" "65535" + staging_max_assertions=$PROMPT_RESULT + prompt_uint "Staging assertion timelock in blocks" \ + "${STAGING_STATE_ORACLE_ASSERTION_TIMELOCK_BLOCKS:-}" \ + "115792089237316195423570985008687907853269984665640564039457584007913129639935" + staging_assertion_timelock=$PROMPT_RESULT +fi + +da_prover="" +if [[ ${da_selected[0]} -eq 1 ]]; then + prompt_address "DA prover address" "${DA_PROVER_ADDRESS:-}" + da_prover=$PROMPT_RESULT +fi + +admin_verifier_whitelist_admin="" +if [[ ${admin_selected[1]} -eq 1 ]]; then + prompt_address "Admin Verifier Whitelist owner" "${ADMIN_VERIFIER_WHITELIST_ADMIN_ADDRESS:-}" + admin_verifier_whitelist_admin=$PROMPT_RESULT +fi + +test_super_admin="" +if [[ ${admin_selected[2]:-0} -eq 1 ]]; then + prompt_address "Testing Super Admin address" "${TEST_ADMIN_VERIFIER_SUPER_ADMIN_ADDRESS:-}" + test_super_admin=$PROMPT_RESULT +fi + +wallet_output=$(cast wallet list 2>/dev/null) || die "Unable to list Foundry keystore accounts" +wallet_names=() +wallet_labels=() +while IFS= read -r wallet_line; do + [[ -n "$wallet_line" ]] || continue + wallet_labels[${#wallet_labels[@]}]=$wallet_line + wallet_names[${#wallet_names[@]}]=${wallet_line%% (*} +done <"$PASSWORD_FILE" + wallet_password="" + + if wallet_address=$(cast wallet address --account "$wallet_account" --password-file "$PASSWORD_FILE" 2>/dev/null); then + break + fi + + rm -f "$PASSWORD_FILE" + PASSWORD_FILE="" + tty_warn "That password did not unlock $wallet_account. Try again." +done + +if ! wallet_balance_wei=$(cast balance "$wallet_address" --rpc-url "$rpc_url" 2>/dev/null); then + die "Unable to read the balance for $wallet_address on chain $chain_id" +fi +if [[ ! "$wallet_balance_wei" =~ ^[0-9]+$ ]]; then + die "Received an invalid balance for $wallet_address on chain $chain_id" +fi +if [[ "$wallet_balance_wei" =~ ^0+$ ]]; then + die "Selected wallet $wallet_address has no funds on chain $chain_id. Fund it before deploying." +fi + +wallet_balance=$(cast balance --ether "$wallet_address" --rpc-url "$rpc_url" 2>/dev/null || printf 'unknown') +wallet_nonce=$(cast nonce "$wallet_address" --rpc-url "$rpc_url" 2>/dev/null || printf 'unknown') +tty_success "Wallet unlocked successfully: $wallet_address" + +env_args=( + "ETH_RPC_URL=$rpc_url" + "DEPLOYMENT_IS_TESTING=$deployment_is_testing" + "DEPLOY_STAGING_STATE_ORACLE=$deploy_staging" + "STATE_ORACLE_WHITELIST_ENABLED=$whitelist_enabled" + "STATE_ORACLE_MAX_ASSERTIONS_PER_AA=$max_assertions" + "STATE_ORACLE_ASSERTION_TIMELOCK_BLOCKS=$assertion_timelock" + "STATE_ORACLE_ADMIN_ADDRESS=$state_oracle_admin" + "DA_VERIFIER_ECDSA_PRODUCTION=$(bool_for_selection "${da_production[0]}")" + "DA_VERIFIER_ECDSA_STAGING=$(bool_for_selection "${da_staging[0]}")" + "DA_VERIFIER_ONCHAIN_PRODUCTION=$(bool_for_selection "${da_production[1]}")" + "DA_VERIFIER_ONCHAIN_STAGING=$(bool_for_selection "${da_staging[1]}")" + "ADMIN_VERIFIER_OWNER_PRODUCTION=$(bool_for_selection "${admin_production[0]}")" + "ADMIN_VERIFIER_OWNER_STAGING=$(bool_for_selection "${admin_staging[0]}")" + "ADMIN_VERIFIER_WHITELIST_PRODUCTION=$(bool_for_selection "${admin_production[1]}")" + "ADMIN_VERIFIER_WHITELIST_STAGING=$(bool_for_selection "${admin_staging[1]}")" + "ADMIN_VERIFIER_SUPER_ADMIN_PRODUCTION=$(bool_for_selection "${admin_production[2]}")" + "ADMIN_VERIFIER_SUPER_ADMIN_STAGING=$(bool_for_selection "${admin_staging[2]}")" + "ADMIN_VERIFIER_ALWAYS_APPROVE_PRODUCTION=$(bool_for_selection "${admin_production[3]}")" + "ADMIN_VERIFIER_ALWAYS_APPROVE_STAGING=$(bool_for_selection "${admin_staging[3]}")" +) + +if [[ "$deploy_staging" == "true" ]]; then + env_args[${#env_args[@]}]="STAGING_STATE_ORACLE_MAX_ASSERTIONS_PER_AA=$staging_max_assertions" + env_args[${#env_args[@]}]="STAGING_STATE_ORACLE_ASSERTION_TIMELOCK_BLOCKS=$staging_assertion_timelock" +fi +if [[ -n "$da_prover" ]]; then + env_args[${#env_args[@]}]="DA_PROVER_ADDRESS=$da_prover" +fi +if [[ -n "$admin_verifier_whitelist_admin" ]]; then + env_args[${#env_args[@]}]="ADMIN_VERIFIER_WHITELIST_ADMIN_ADDRESS=$admin_verifier_whitelist_admin" +fi +if [[ -n "$test_super_admin" ]]; then + env_args[${#env_args[@]}]="TEST_ADMIN_VERIFIER_SUPER_ADMIN_ADDRESS=$test_super_admin" +fi +if [[ ${#whitelist_addresses[@]} -gt 0 ]]; then + whitelist_csv=$(join_by_comma "${whitelist_addresses[@]}") + env_args[${#env_args[@]}]="STATE_ORACLE_INITIAL_WHITELIST=$whitelist_csv" +fi +if [[ "$verify_contracts" == "true" ]]; then + env_args[${#env_args[@]}]="ETHERSCAN_API_KEY=$etherscan_api_key" +fi + +forge_args=( + script + "script/DeployWizard.s.sol:DeployWizard" + --rpc-url "$rpc_url" + --account "$wallet_account" + --sender "$wallet_address" + --password-file "$PASSWORD_FILE" + --broadcast +) +if [[ "$verify_contracts" == "true" ]]; then + forge_args[${#forge_args[@]}]=--verify +fi + +production_admin_summary="" +staging_admin_summary="" +for ((i = 0; i < ${#admin_options[@]}; i++)); do + if [[ ${admin_production[$i]} -eq 1 ]]; then + production_admin_summary="${production_admin_summary}${production_admin_summary:+, }${admin_options[$i]}" + fi + if [[ ${admin_staging[$i]} -eq 1 ]]; then + staging_admin_summary="${staging_admin_summary}${staging_admin_summary:+, }${admin_options[$i]}" + fi +done +production_da_summary="" +staging_da_summary="" +for ((i = 0; i < ${#da_options[@]}; i++)); do + if [[ ${da_production[$i]} -eq 1 ]]; then + production_da_summary="${production_da_summary}${production_da_summary:+, }${da_options[$i]}" + fi + if [[ ${da_staging[$i]} -eq 1 ]]; then + staging_da_summary="${staging_da_summary}${staging_da_summary:+, }${da_options[$i]}" + fi +done + +tty_println "" +tty_section "Deployment summary" +tty_field "Kind" "$deployment_kind" +tty_field "Chain ID" "$chain_id" +tty_field "Wallet" "$wallet_account ($wallet_address)" +tty_field "Wallet balance" "$wallet_balance ETH" +tty_field "Wallet nonce" "$wallet_nonce" +tty_field "State Oracle admin" "$state_oracle_admin" +tty_field "Staging oracle" "$deploy_staging" +tty_field "Whitelist enabled" "$whitelist_enabled" +tty_field "Verify contracts" "$verify_contracts" +tty_field "Production limits" "$max_assertions assertions, $assertion_timelock blocks" +tty_field "Production admin" "$production_admin_summary" +tty_field "Production DA" "$production_da_summary" +if [[ "$deploy_staging" == "true" ]]; then + tty_field "Staging limits" "$staging_max_assertions assertions, $staging_assertion_timelock blocks" + tty_field "Staging admin" "$staging_admin_summary" + tty_field "Staging DA" "$staging_da_summary" +fi +if [[ -n "$da_prover" ]]; then + tty_field "DA prover" "$da_prover" +fi +if [[ -n "$admin_verifier_whitelist_admin" ]]; then + tty_field "Verifier WL owner" "$admin_verifier_whitelist_admin" +fi +if [[ -n "$test_super_admin" ]]; then + tty_field "Test super admin" "$test_super_admin" +fi +if [[ ${#whitelist_addresses[@]} -gt 0 ]]; then + tty_field "Initial whitelist" "$(join_by_comma "${whitelist_addresses[@]}")" +fi +if [[ "$deployment_kind" == "Production" ]]; then + tty_println "" + tty_warn "Production deployment selected. Confirm the chain, admin, and wallet carefully." +fi + +print_redacted_command + +menu_select_one "Ready to continue?" "Deploy now" "Print command only" "Cancel" +case "$MENU_VALUE" in + "Print command only") + tty_success "No transactions were sent." + exit 0 + ;; + "Cancel") + tty_warn "Deployment cancelled." + exit 0 + ;; +esac + +FORGE_OUTPUT_FILE=$(mktemp "${TMPDIR:-/tmp}/credible-layer-forge.XXXXXX") +set +e +env "${env_args[@]}" forge "${forge_args[@]}" 2>&1 | tee "$FORGE_OUTPUT_FILE" +forge_status=${PIPESTATUS[0]} +set -e +[[ $forge_status -eq 0 ]] || die "Forge deployment failed with status $forge_status" + +broadcast_file="$ROOT_DIR/broadcast/DeployWizard.s.sol/$chain_id/run-latest.json" +[[ -f "$broadcast_file" ]] || die "Deployment succeeded, but the broadcast receipt was not found at $broadcast_file" +print_deployment_summary "$broadcast_file" diff --git a/src/StateOracle.sol b/src/StateOracle.sol index 92e02b0..156bce0 100644 --- a/src/StateOracle.sol +++ b/src/StateOracle.sol @@ -201,15 +201,47 @@ contract StateOracle is Batch, Initializable, StateOracleAccessControl { IDAVerifier[] calldata _daVerifiers, uint16 _maxAssertionsPerAA ) external initializer { + _initialize(admin, _adminVerifiers, _daVerifiers, _maxAssertionsPerAA, true, new address[](0)); + } + + /// @notice Initializes the contract with an explicit whitelist configuration + /// @param admin The address to set as the admin + /// @param _adminVerifiers The admin verifiers to add + /// @param _daVerifiers The DA verifiers to add + /// @param _maxAssertionsPerAA Maximum number of assertions per assertion adopter + /// @param _whitelistEnabled Whether whitelist checks are enabled initially + /// @param _initialWhitelist Addresses to add to the initial whitelist + function initializeWithWhitelist( + address admin, + IAdminVerifier[] calldata _adminVerifiers, + IDAVerifier[] calldata _daVerifiers, + uint16 _maxAssertionsPerAA, + bool _whitelistEnabled, + address[] calldata _initialWhitelist + ) external initializer { + _initialize(admin, _adminVerifiers, _daVerifiers, _maxAssertionsPerAA, _whitelistEnabled, _initialWhitelist); + } + + function _initialize( + address admin, + IAdminVerifier[] memory _adminVerifiers, + IDAVerifier[] memory _daVerifiers, + uint16 _maxAssertionsPerAA, + bool _whitelistEnabled, + address[] memory _initialWhitelist + ) internal { _initializeRoles(admin); - whitelistEnabled = true; + whitelistEnabled = _whitelistEnabled; for (uint256 i = 0; i < _adminVerifiers.length; i++) { _addAdminVerifier(_adminVerifiers[i]); } for (uint256 i = 0; i < _daVerifiers.length; i++) { _addDAVerifier(_daVerifiers[i]); } + for (uint256 i = 0; i < _initialWhitelist.length; i++) { + _addToWhitelist(_initialWhitelist[i]); + } _setMaxAssertionsPerAA(_maxAssertionsPerAA); } @@ -292,6 +324,10 @@ contract StateOracle is Batch, Initializable, StateOracleAccessControl { /// @notice Adds an account to the whitelist /// @param account The address to add function addToWhitelist(address account) external onlyOperator { + _addToWhitelist(account); + } + + function _addToWhitelist(address account) internal { require(!whitelist[account], AlreadyWhitelisted(account)); whitelist[account] = true; emit AddedToWhitelist(account); diff --git a/src/verification/admin/AdminVerifierAlwaysApprove.sol b/src/verification/admin/AdminVerifierAlwaysApprove.sol new file mode 100644 index 0000000..c161ea8 --- /dev/null +++ b/src/verification/admin/AdminVerifierAlwaysApprove.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {IAdminVerifier} from "../../interfaces/IAdminVerifier.sol"; + +/// @title AdminVerifierAlwaysApprove +/// @notice Test-only admin verifier that accepts every requester for every assertion adopter. +/// @dev WARNING: This component is intended strictly for internal testing. Deploying this +/// contract in production would allow any address to register as manager for any adopter. +contract AdminVerifierAlwaysApprove is IAdminVerifier { + /// @inheritdoc IAdminVerifier + /// @notice Always returns true. + function verifyAdmin(address, address, bytes calldata) external pure returns (bool) { + return true; + } +} diff --git a/test/AdminVerifierAlwaysApprove.t.sol b/test/AdminVerifierAlwaysApprove.t.sol new file mode 100644 index 0000000..51f170f --- /dev/null +++ b/test/AdminVerifierAlwaysApprove.t.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: CC0-1.0 +pragma solidity ^0.8.28; + +import {Test} from "forge-std/Test.sol"; +import {AdminVerifierAlwaysApprove} from "../src/verification/admin/AdminVerifierAlwaysApprove.sol"; + +contract AdminVerifierAlwaysApproveTest is Test { + AdminVerifierAlwaysApprove verifier; + address constant REQUESTER = + address(uint160(uint256(keccak256(abi.encode("pcl.test.AdminVerifierAlwaysApprove.REQUESTER"))))); + address constant OTHER = + address(uint160(uint256(keccak256(abi.encode("pcl.test.AdminVerifierAlwaysApprove.OTHER"))))); + address constant ADOPTER = + address(uint160(uint256(keccak256(abi.encode("pcl.test.AdminVerifierAlwaysApprove.ADOPTER"))))); + + function setUp() public { + verifier = new AdminVerifierAlwaysApprove(); + } + + function test_verifyAdminReturnsTrueForAnyRequester() public view { + assertTrue(verifier.verifyAdmin(ADOPTER, REQUESTER, "")); + assertTrue(verifier.verifyAdmin(ADOPTER, OTHER, "")); + } + + function test_verifyAdminReturnsTrueForZeroAddresses() public view { + assertTrue(verifier.verifyAdmin(address(0), address(0), "")); + } + + function test_verifyAdminReturnsTrueWithData() public view { + assertTrue(verifier.verifyAdmin(ADOPTER, REQUESTER, abi.encode("ignored"))); + } +} diff --git a/test/DeployAdminVerifiers.t.sol b/test/DeployAdminVerifiers.t.sol new file mode 100644 index 0000000..6fdce40 --- /dev/null +++ b/test/DeployAdminVerifiers.t.sol @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: CC0-1.0 +pragma solidity ^0.8.28; + +import {Test} from "forge-std/Test.sol"; +import {DeployCore} from "../script/DeployCore.s.sol"; +import {DeployTestingAdminVerifiers} from "../script/DeployTestingAdminVerifiers.s.sol"; +import {IAdminVerifier} from "../src/interfaces/IAdminVerifier.sol"; +import {IDAVerifier} from "../src/interfaces/IDAVerifier.sol"; +import {StateOracle} from "../src/StateOracle.sol"; +import {AdminVerifierSuperAdmin} from "../src/verification/admin/AdminVerifierSuperAdmin.sol"; +import {AdminVerifierWhitelist} from "../src/verification/admin/AdminVerifierWhitelist.sol"; +import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {DAVerifierMock} from "./utils/DAVerifierMock.sol"; +import {OwnableAdopter} from "./utils/Adopter.sol"; + +contract DeployCoreHarness is DeployCore { + function configureAdminVerifiers( + address _admin, + bool _deployOwnerVerifier, + bool _deployWhitelistVerifier, + address _whitelistAdmin + ) external { + admin = _admin; + deployOwnerVerifier = _deployOwnerVerifier; + deployWhitelistVerifier = _deployWhitelistVerifier; + whitelistAdmin = _whitelistAdmin; + } + + function deployAdminVerifiersForTest() external returns (address[] memory) { + return _deployAdminVerifiers(); + } + + function deployStateOracleProxyForTest( + address stateOracle, + address[] memory adminVerifierDeployments, + address[] memory daVerifierAddresses, + uint16 maxAssertions + ) external returns (address) { + return _deployStateOracleProxy(stateOracle, adminVerifierDeployments, daVerifierAddresses, maxAssertions); + } +} + +contract DeployTestingAdminVerifiersHarness is DeployTestingAdminVerifiers { + function configureTestingAdminVerifiers( + address _stateOracle, + address _superAdmin, + bool _deploySuperAdminVerifier, + bool _deployAlwaysApproveVerifier, + bool _addToStateOracle + ) external { + stateOracle = _stateOracle; + superAdmin = _superAdmin; + deploySuperAdminVerifierEnabled = _deploySuperAdminVerifier; + deployAlwaysApproveVerifierEnabled = _deployAlwaysApproveVerifier; + addToStateOracle = _addToStateOracle; + } + + function runForTest() external returns (address[] memory) { + return _run(); + } +} + +contract DeployAdminVerifiersTest is Test { + address constant ADMIN = address(uint160(uint256(keccak256(abi.encode("pcl.test.DeployAdminVerifiers.ADMIN"))))); + address constant OWNER = address(uint160(uint256(keccak256(abi.encode("pcl.test.DeployAdminVerifiers.OWNER"))))); + address constant WHITELIST_ADMIN = + address(uint160(uint256(keccak256(abi.encode("pcl.test.DeployAdminVerifiers.WHITELIST_ADMIN"))))); + address constant SUPER_ADMIN = + address(uint160(uint256(keccak256(abi.encode("pcl.test.DeployAdminVerifiers.SUPER_ADMIN"))))); + address constant OTHER = address(uint160(uint256(keccak256(abi.encode("pcl.test.DeployAdminVerifiers.OTHER"))))); + uint16 constant MAX_ASSERTIONS_PER_AA = 5; + + function test_coreDeployAdminVerifiersAddsOnlyProductionVerifiersToStateOracle() public { + DeployCoreHarness deployer = new DeployCoreHarness(); + deployer.configureAdminVerifiers(ADMIN, true, true, WHITELIST_ADMIN); + + address[] memory verifiers = deployer.deployAdminVerifiersForTest(); + assertEq(verifiers.length, 2); + + OwnableAdopter adopter = new OwnableAdopter(OWNER); + assertTrue(IAdminVerifier(verifiers[0]).verifyAdmin(address(adopter), OWNER, "")); + assertTrue(AdminVerifierWhitelist(verifiers[1]).hasRole(bytes32(0), WHITELIST_ADMIN)); + assertTrue( + AdminVerifierWhitelist(verifiers[1]) + .hasRole(AdminVerifierWhitelist(verifiers[1]).WHITELIST_ADMIN_ROLE(), WHITELIST_ADMIN) + ); + + address[] memory daVerifiers = new address[](1); + daVerifiers[0] = address(new DAVerifierMock()); + StateOracle stateOracle = StateOracle( + deployer.deployStateOracleProxyForTest( + address(_deployStateOracleImplementation()), verifiers, daVerifiers, MAX_ASSERTIONS_PER_AA + ) + ); + + for (uint256 i = 0; i < verifiers.length; i++) { + assertTrue(stateOracle.isAdminVerifierRegistered(IAdminVerifier(verifiers[i]))); + } + } + + function test_RevertIf_coreDeployWhitelistVerifierWithoutAdmin() public { + DeployCoreHarness deployer = new DeployCoreHarness(); + deployer.configureAdminVerifiers(ADMIN, false, true, address(0)); + + vm.expectRevert(bytes("Invalid whitelist admin")); + deployer.deployAdminVerifiersForTest(); + } + + function test_testingScriptDeploysAndAddsTestVerifiersToStateOracle() public { + DeployTestingAdminVerifiersHarness deployer = new DeployTestingAdminVerifiersHarness(); + StateOracle stateOracle = _deployStateOracle(address(deployer), new IAdminVerifier[](0)); + deployer.configureTestingAdminVerifiers(address(stateOracle), SUPER_ADMIN, true, true, true); + + address[] memory verifiers = deployer.runForTest(); + assertEq(verifiers.length, 2); + + assertTrue(AdminVerifierSuperAdmin(verifiers[0]).verifyAdmin(address(1), SUPER_ADMIN, "")); + assertTrue(IAdminVerifier(verifiers[1]).verifyAdmin(address(1), OTHER, "")); + assertTrue(stateOracle.isAdminVerifierRegistered(IAdminVerifier(verifiers[0]))); + assertTrue(stateOracle.isAdminVerifierRegistered(IAdminVerifier(verifiers[1]))); + } + + function test_RevertIf_testingScriptDeploysSuperAdminVerifierWithoutAdmin() public { + DeployTestingAdminVerifiersHarness deployer = new DeployTestingAdminVerifiersHarness(); + deployer.configureTestingAdminVerifiers(address(1), address(0), true, false, false); + + vm.expectRevert(bytes("Invalid super admin")); + deployer.runForTest(); + } + + function test_RevertIf_testingScriptAddsVerifiersWithoutStateOracle() public { + DeployTestingAdminVerifiersHarness deployer = new DeployTestingAdminVerifiersHarness(); + deployer.configureTestingAdminVerifiers(address(0), SUPER_ADMIN, false, true, true); + + vm.expectRevert(bytes("Invalid state oracle")); + deployer.runForTest(); + } + + function _deployStateOracle(address oracleAdmin, IAdminVerifier[] memory adminVerifiers) + internal + returns (StateOracle) + { + StateOracle implementation = _deployStateOracleImplementation(); + IDAVerifier[] memory daVerifiers = new IDAVerifier[](1); + daVerifiers[0] = IDAVerifier(address(new DAVerifierMock())); + bytes memory initCallData = abi.encodeWithSelector( + StateOracle.initialize.selector, oracleAdmin, adminVerifiers, daVerifiers, MAX_ASSERTIONS_PER_AA + ); + return + StateOracle(address(new TransparentUpgradeableProxy(address(implementation), address(this), initCallData))); + } + + function _deployStateOracleImplementation() internal returns (StateOracle) { + return new StateOracle(10); + } +} diff --git a/test/StateOracle.t.sol b/test/StateOracle.t.sol index 7d7574e..c0fdd5a 100644 --- a/test/StateOracle.t.sol +++ b/test/StateOracle.t.sol @@ -86,6 +86,9 @@ contract Constructor is StateOracleBase { } contract Initialize is StateOracleBase { + address constant INITIAL_WHITELIST_ACCOUNT = address(0xBEEF); + IDAVerifier additionalDAVerifier; + function test_RevertIf_alreadyInitialized() public { vm.expectRevert(Initializable.InvalidInitialization.selector); stateOracle.initialize(OWNER, new IAdminVerifier[](0), new IDAVerifier[](0), MAX_ASSERTIONS_PER_AA); @@ -102,6 +105,45 @@ contract Initialize is StateOracleBase { vm.expectRevert(Initializable.InvalidInitialization.selector); stateOracle.initialize(STATE_ORACLE_ADMIN, verifiers, daVerifiers, MAX_ASSERTIONS_PER_AA); } + + function test_initializeWithWhitelistEnabledAndInitialAccount() public { + address[] memory initialWhitelist = new address[](1); + initialWhitelist[0] = INITIAL_WHITELIST_ACCOUNT; + + StateOracle configuredOracle = _deployWithWhitelist(true, initialWhitelist); + + assertTrue(configuredOracle.whitelistEnabled()); + assertTrue(configuredOracle.whitelist(INITIAL_WHITELIST_ACCOUNT)); + assertTrue(configuredOracle.isWhitelisted(INITIAL_WHITELIST_ACCOUNT)); + assertFalse(configuredOracle.isWhitelisted(address(0xCAFE))); + assertTrue(configuredOracle.isDAVerifierRegistered(daVerifierMock)); + assertTrue(configuredOracle.isDAVerifierRegistered(additionalDAVerifier)); + } + + function test_initializeWithWhitelistDisabled() public { + StateOracle configuredOracle = _deployWithWhitelist(false, new address[](0)); + + assertFalse(configuredOracle.whitelistEnabled()); + assertTrue(configuredOracle.isWhitelisted(address(0xCAFE))); + } + + function _deployWithWhitelist(bool enabled, address[] memory initialWhitelist) + internal + returns (StateOracle configuredOracle) + { + StateOracle implementation = new StateOracle(TIMEOUT); + IAdminVerifier[] memory verifiers = new IAdminVerifier[](1); + verifiers[0] = adminVerifier; + additionalDAVerifier = IDAVerifier(address(new DAVerifierMock())); + IDAVerifier[] memory daVerifiers = new IDAVerifier[](2); + daVerifiers[0] = daVerifierMock; + daVerifiers[1] = additionalDAVerifier; + bytes memory data = abi.encodeCall( + StateOracle.initializeWithWhitelist, + (STATE_ORACLE_ADMIN, verifiers, daVerifiers, MAX_ASSERTIONS_PER_AA, enabled, initialWhitelist) + ); + configuredOracle = StateOracle(deployProxy(address(implementation), data)); + } } contract Register is StateOracleBase { diff --git a/test/shell/test_deploy_wizard.py b/test/shell/test_deploy_wizard.py new file mode 100644 index 0000000..e12c1ea --- /dev/null +++ b/test/shell/test_deploy_wizard.py @@ -0,0 +1,255 @@ +#!/usr/bin/env python3 + +import errno +import os +import pty +import selectors +import signal +import tempfile +import time +import unittest +from pathlib import Path + + +ROOT_DIR = Path(__file__).resolve().parents[2] +WIZARD = ROOT_DIR / "shell" / "deploy_wizard.sh" + + +class WizardSession: + def __init__(self, no_color=True, balance_wei="0"): + self._temporary_directory = tempfile.TemporaryDirectory() + fake_bin = Path(self._temporary_directory.name) + self.forge_arguments = fake_bin / "forge-arguments" + forge = fake_bin / "forge" + forge.write_text( + '#!/bin/sh\nprintf \'%s\\n\' "$@" > "$FAKE_FORGE_ARGUMENTS"\n' + ) + forge.chmod(0o755) + jq = fake_bin / "jq" + jq.write_text("#!/bin/sh\nexit 0\n") + jq.chmod(0o755) + cast = fake_bin / "cast" + cast.write_text( + f"""#!/bin/sh +case "$1" in + chain-id) echo 31337 ;; + to-check-sum-address) echo "$2" ;; + balance) echo {balance_wei} ;; + nonce) echo 0 ;; + wallet) + case "$2" in + list) echo "deployer (Local)" ;; + address) echo 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 ;; + esac + ;; +esac +""" + ) + cast.chmod(0o755) + + self.pid, self.master_fd = pty.fork() + if self.pid == 0: + environment = os.environ.copy() + if no_color: + environment["NO_COLOR"] = "1" + else: + environment.pop("NO_COLOR", None) + environment["TERM"] = "xterm-256color" + environment["RPC_URL"] = "http://rpc.example" + environment["STATE_ORACLE_MAX_ASSERTIONS_PER_AA"] = "5" + environment["STATE_ORACLE_ASSERTION_TIMELOCK_BLOCKS"] = "10" + environment["STATE_ORACLE_ADMIN_ADDRESS"] = ( + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + ) + environment["FAKE_FORGE_ARGUMENTS"] = str(self.forge_arguments) + environment["PATH"] = f"{fake_bin}:{environment['PATH']}" + os.chdir(ROOT_DIR) + os.execvpe(str(WIZARD), [str(WIZARD)], environment) + + self.output = "" + self.transcript = "" + self.selector = selectors.DefaultSelector() + self.selector.register(self.master_fd, selectors.EVENT_READ) + + def expect_any(self, *needles, timeout=5): + deadline = time.monotonic() + timeout + while time.monotonic() < deadline: + for needle in needles: + if needle in self.output: + match_end = self.output.index(needle) + len(needle) + self.output = self.output[match_end:] + return needle + + if not self.selector.select(0.1): + continue + try: + chunk = os.read(self.master_fd, 4096) + except OSError as error: + if error.errno == errno.EIO: + break + raise + if not chunk: + break + decoded = chunk.decode(errors="replace") + self.output += decoded + self.transcript += decoded + + self.fail_with_output(f"Timed out waiting for one of: {needles}") + + def send(self, keys): + os.write(self.master_fd, keys) + + def fail_with_output(self, message): + raise AssertionError(f"{message}\nWizard output:\n{self.output}") + + def close(self): + try: + os.kill(self.pid, signal.SIGKILL) + except ProcessLookupError: + pass + self.selector.close() + try: + os.close(self.master_fd) + except OSError: + pass + try: + os.waitpid(self.pid, 0) + except ChildProcessError: + pass + self._temporary_directory.cleanup() + + +class DeployWizardTest(unittest.TestCase): + def test_interactive_output_uses_color(self): + wizard = WizardSession(no_color=False) + try: + wizard.expect_any("Credible Layer deployment wizard") + self.assertIn("\x1b[1m\x1b[36m", wizard.transcript) + finally: + wizard.close() + + def test_assigning_multiple_da_verifiers_to_production_advances_to_whitelist(self): + wizard = WizardSession() + try: + wizard.expect_any("What kind of deployment is this?") + wizard.send(b"\r") + wizard.expect_any("Deploy a staging State Oracle as well?") + wizard.send(b"\r") + + wizard.expect_any("Which admin verifiers should be deployed?") + wizard.send(b" \r") + wizard.expect_any("Add Owner to which State Oracle(s)?") + wizard.send(b" \r") + + wizard.expect_any("Which DA verifiers should be deployed?") + wizard.send(b" \x1b[B \r") + wizard.expect_any("Add ECDSA signatures to which State Oracle(s)?") + wizard.send(b" \r") + wizard.expect_any("Add On-chain bytecode to which State Oracle(s)?") + wizard.send(b" \r") + wizard.expect_any("Should the State Oracle whitelist be enabled?") + finally: + wizard.close() + + def test_zero_balance_wallet_stops_before_forge(self): + wizard = WizardSession() + try: + wizard.expect_any("What kind of deployment is this?") + wizard.send(b"\r") + wizard.expect_any("Deploy a staging State Oracle as well?") + wizard.send(b"\r") + + wizard.expect_any("Which admin verifiers should be deployed?") + wizard.send(b" \r") + wizard.expect_any("Add Owner to which State Oracle(s)?") + wizard.send(b" \r") + + wizard.expect_any("Which DA verifiers should be deployed?") + wizard.send(b"\x1b[B \r") + wizard.expect_any("Add On-chain bytecode to which State Oracle(s)?") + wizard.send(b" \r") + + wizard.expect_any("Should the State Oracle whitelist be enabled?") + wizard.send(b"\x1b[B\r") + wizard.expect_any("Verify deployed contracts on the block explorer?") + wizard.send(b"\x1b[B\r") + + wizard.expect_any("RPC URL") + wizard.send(b"\r") + wizard.expect_any("Maximum assertions per adopter") + wizard.send(b"\r") + wizard.expect_any("Assertion timelock in blocks") + wizard.send(b"\r") + wizard.expect_any("State Oracle admin") + wizard.send(b"\r") + + wizard.expect_any("Which Foundry wallet should deploy the contracts?") + wizard.send(b"\r") + wizard.expect_any("Password for deployer") + wizard.send(b"password\r") + + result = wizard.expect_any( + "has no funds on chain 31337", + "Deployment summary", + ) + if result == "Deployment summary": + self.fail("zero-balance wallet reached the deployment confirmation") + finally: + wizard.close() + + def test_funded_account_sets_forge_rpc_and_sender(self): + wizard = WizardSession(balance_wei="1000000000000000000") + try: + wizard.expect_any("What kind of deployment is this?") + wizard.send(b"\r") + wizard.expect_any("Deploy a staging State Oracle as well?") + wizard.send(b"\r") + + wizard.expect_any("Which admin verifiers should be deployed?") + wizard.send(b" \r") + wizard.expect_any("Add Owner to which State Oracle(s)?") + wizard.send(b" \r") + + wizard.expect_any("Which DA verifiers should be deployed?") + wizard.send(b"\x1b[B \r") + wizard.expect_any("Add On-chain bytecode to which State Oracle(s)?") + wizard.send(b" \r") + + wizard.expect_any("Should the State Oracle whitelist be enabled?") + wizard.send(b"\x1b[B\r") + wizard.expect_any("Verify deployed contracts on the block explorer?") + wizard.send(b"\x1b[B\r") + + wizard.expect_any("RPC URL") + wizard.send(b"\r") + wizard.expect_any("Maximum assertions per adopter") + wizard.send(b"\r") + wizard.expect_any("Assertion timelock in blocks") + wizard.send(b"\r") + wizard.expect_any("State Oracle admin") + wizard.send(b"\r") + + wizard.expect_any("Which Foundry wallet should deploy the contracts?") + wizard.send(b"\r") + wizard.expect_any("Password for deployer") + wizard.send(b"password\r") + + wizard.expect_any("Ready to continue?") + self.assertIn("--rpc-url \\", wizard.transcript) + wizard.send(b"\r") + wizard.expect_any("Deployment complete", "broadcast receipt was not found") + + forge_arguments = wizard.forge_arguments.read_text().splitlines() + rpc_index = forge_arguments.index("--rpc-url") + self.assertEqual(forge_arguments[rpc_index + 1], "http://rpc.example") + sender_index = forge_arguments.index("--sender") + self.assertEqual( + forge_arguments[sender_index + 1], + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + ) + finally: + wizard.close() + + +if __name__ == "__main__": + unittest.main()