From 223fa6ca55753243da0abee0f463d857a7a8b267 Mon Sep 17 00:00:00 2001 From: Mikael <26343374+0xmikko@users.noreply.github.com> Date: Fri, 28 Feb 2025 18:43:20 +0100 Subject: [PATCH 1/4] fix: restoring signature in event + better parameter names --- contracts/global/BytecodeRepository.sol | 2 +- contracts/interfaces/IBytecodeRepository.sol | 52 +++++++++++--------- wagmi.config.js | 4 -- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/contracts/global/BytecodeRepository.sol b/contracts/global/BytecodeRepository.sol index 876ebd6..5f1e114 100644 --- a/contracts/global/BytecodeRepository.sol +++ b/contracts/global/BytecodeRepository.sol @@ -299,7 +299,7 @@ contract BytecodeRepository is ImmutableOwnableTrait, SanityCheckTrait, IBytecod } } reports.push(auditReport); - emit AuditBytecode(bytecodeHash, auditor, auditReport.reportUrl); + emit AuditBytecode(bytecodeHash, auditor, auditReport.reportUrl, auditReport.signature); } // ----------------- // diff --git a/contracts/interfaces/IBytecodeRepository.sol b/contracts/interfaces/IBytecodeRepository.sol index 8081b27..0ce2026 100644 --- a/contracts/interfaces/IBytecodeRepository.sol +++ b/contracts/interfaces/IBytecodeRepository.sol @@ -16,19 +16,23 @@ interface IBytecodeRepository is IVersion, IImmutableOwnableTrait { event AddAuditor(address indexed auditor, string name); event AddPublicDomain(bytes32 indexed domain); event AddSystemDomain(bytes32 indexed domain); - event AllowContract(bytes32 indexed bytecodeHash, bytes32 indexed cType, uint256 indexed ver); - event AuditBytecode(bytes32 indexed bytecodeHash, address indexed auditor, string reportUrl); + event AllowContract(bytes32 indexed bytecodeHash, bytes32 indexed contractType, uint256 indexed version); + event AuditBytecode(bytes32 indexed bytecodeHash, address indexed auditor, string reportUrl, bytes signature); event DeployContract( - bytes32 indexed bytecodeHash, bytes32 indexed cType, uint256 indexed ver, address contractAddress + bytes32 indexed bytecodeHash, bytes32 indexed contractType, uint256 indexed version, address contractAddress ); - event ForbidContract(bytes32 indexed bytecodeHash, bytes32 indexed cType, uint256 indexed ver); + event ForbidContract(bytes32 indexed bytecodeHash, bytes32 indexed contractType, uint256 indexed version); event ForbidInitCode(bytes32 indexed initCodeHash); event RemoveAuditor(address indexed auditor); - event RemoveContractTypeOwner(bytes32 indexed cType); - event SetContractTypeOwner(bytes32 indexed cType, address indexed owner); + event RemoveContractTypeOwner(bytes32 indexed contractType); + event SetContractTypeOwner(bytes32 indexed contractType, address indexed owner); event SetTokenSpecificPostfix(address indexed token, bytes32 indexed postfix); event UploadBytecode( - bytes32 indexed bytecodeHash, bytes32 indexed cType, uint256 indexed ver, address author, string source + bytes32 indexed bytecodeHash, + bytes32 indexed contractType, + uint256 indexed version, + address author, + string source ); // ------ // @@ -36,25 +40,25 @@ interface IBytecodeRepository is IVersion, IImmutableOwnableTrait { // ------ // error AuditorIsNotApprovedException(address auditor); - error AuthorIsNotContractTypeOwnerException(bytes32 cType, address author); - error BytecodeIsAlreadyAllowedException(bytes32 cType, uint256 ver); + error AuthorIsNotContractTypeOwnerException(bytes32 contractType, address author); + error BytecodeIsAlreadyAllowedException(bytes32 contractType, uint256 version); error BytecodeIsAlreadySignedByAuditorException(bytes32 bytecodeHash, address auditor); - error BytecodeIsNotAllowedException(bytes32 cType, uint256 ver); + error BytecodeIsNotAllowedException(bytes32 contractType, uint256 version); error BytecodeIsNotAuditedException(bytes32 bytecodeHash); error BytecodeIsNotUploadedException(bytes32 bytecodeHash); error CallerIsNotBytecodeAuthorException(address caller); error ContractIsAlreadyDeployedException(address deployedContract); - error ContractTypeIsNotInPublicDomainException(bytes32 cType); + error ContractTypeIsNotInPublicDomainException(bytes32 contractType); error DomainIsAlreadyMarketAsPublicException(bytes32 domain); error DomainIsAlreadyMarketAsSystemException(bytes32 domain); error InitCodeIsForbiddenException(bytes32 initCodeHash); error InvalidAuditorSignatureException(address auditor); error InvalidAuthorSignatureException(address author); error InvalidBytecodeException(bytes32 bytecodeHash); - error InvalidContractTypeException(bytes32 cType); + error InvalidContractTypeException(bytes32 contractType); error InvalidDomainException(bytes32 domain); - error InvalidVersionException(bytes32 cType, uint256 ver); - error VersionNotFoundException(bytes32 cType); + error InvalidVersionException(bytes32 contractType, uint256 version); + error VersionNotFoundException(bytes32 contractType); // --------------- // // EIP-712 GETTERS // @@ -76,13 +80,13 @@ interface IBytecodeRepository is IVersion, IImmutableOwnableTrait { function isDeployedFromRepository(address deployedContract) external view returns (bool); function getDeployedContractBytecodeHash(address deployedContract) external view returns (bytes32); function computeAddress( - bytes32 cType, - uint256 ver, + bytes32 contractType, + uint256 version, bytes calldata constructorParams, bytes32 salt, address deployer ) external view returns (address); - function deploy(bytes32 cType, uint256 ver, bytes calldata constructorParams, bytes32 salt) + function deploy(bytes32 contractType, uint256 version, bytes calldata constructorParams, bytes32 salt) external returns (address); @@ -108,11 +112,11 @@ interface IBytecodeRepository is IVersion, IImmutableOwnableTrait { // ALLOWING BYTECODE // // ----------------- // - function getAllowedBytecodeHash(bytes32 cType, uint256 ver) external view returns (bytes32); - function getContractTypeOwner(bytes32 cType) external view returns (address); + function getAllowedBytecodeHash(bytes32 contractType, uint256 version) external view returns (bytes32); + function getContractTypeOwner(bytes32 contractType) external view returns (address); function allowSystemContract(bytes32 bytecodeHash) external; function allowPublicContract(bytes32 bytecodeHash) external; - function removePublicContractType(bytes32 cType) external; + function removePublicContractType(bytes32 contractType) external; // ------------------ // // DOMAINS MANAGEMENT // @@ -152,8 +156,8 @@ interface IBytecodeRepository is IVersion, IImmutableOwnableTrait { // VERSION CONTROL // // --------------- // - function getVersions(bytes32 cType) external view returns (uint256[] memory); - function getLatestVersion(bytes32 cType) external view returns (uint256); - function getLatestMinorVersion(bytes32 cType, uint256 majorVersion) external view returns (uint256); - function getLatestPatchVersion(bytes32 cType, uint256 minorVersion) external view returns (uint256); + function getVersions(bytes32 contractType) external view returns (uint256[] memory); + function getLatestVersion(bytes32 contractType) external view returns (uint256); + function getLatestMinorVersion(bytes32 contractType, uint256 majorVersion) external view returns (uint256); + function getLatestPatchVersion(bytes32 contractType, uint256 minorVersion) external view returns (uint256); } diff --git a/wagmi.config.js b/wagmi.config.js index 42f9edd..69b65e5 100644 --- a/wagmi.config.js +++ b/wagmi.config.js @@ -17,10 +17,6 @@ export default defineConfig({ "IPoolConfigureActions.sol/**.json", "IPriceOracleConfigureActions.sol/**.json", "ICreditConfigureActions.sol/**.json", - "ITumblerV3.sol/**.json", - "IGaugeV3.sol/**.json", - "IAliasedLossPolicyV3.sol/**.json", - "DefaultLossPolicy.sol/**.json", ], }), ], From e0ed3d09629adddf40f4a58ea21c5e990f48b66d Mon Sep 17 00:00:00 2001 From: Dima Lekhovitsky Date: Sat, 1 Mar 2025 16:37:17 +0200 Subject: [PATCH 2/4] fix: small fixes + proper tests setup --- contracts/global/BytecodeRepository.sol | 9 +- contracts/instance/InstanceManager.sol | 18 ++- contracts/instance/PriceFeedStore.sol | 10 +- contracts/interfaces/IBytecodeRepository.sol | 3 +- contracts/market/MarketConfigurator.sol | 2 +- .../legacy/MarketConfiguratorLegacy.sol | 5 +- contracts/test/helpers/GlobalSetup.sol | 132 +++++++++++------- .../test/helpers/InstanceManagerHelper.sol | 21 +++ lib/@gearbox-protocol/core-v3 | 2 +- 9 files changed, 128 insertions(+), 74 deletions(-) diff --git a/contracts/global/BytecodeRepository.sol b/contracts/global/BytecodeRepository.sol index 5f1e114..dee7d20 100644 --- a/contracts/global/BytecodeRepository.sol +++ b/contracts/global/BytecodeRepository.sol @@ -248,7 +248,14 @@ contract BytecodeRepository is ImmutableOwnableTrait, SanityCheckTrait, IBytecod source: bytecode.source, authorSignature: bytecode.authorSignature }); - emit UploadBytecode(bytecodeHash, bytecode.contractType, bytecode.version, bytecode.author, bytecode.source); + emit UploadBytecode( + bytecodeHash, + bytecode.contractType, + bytecode.version, + bytecode.author, + bytecode.source, + bytecode.authorSignature + ); } // ----------------- // diff --git a/contracts/instance/InstanceManager.sol b/contracts/instance/InstanceManager.sol index e2d9295..170aaf9 100644 --- a/contracts/instance/InstanceManager.sol +++ b/contracts/instance/InstanceManager.sol @@ -137,7 +137,7 @@ contract InstanceManager is Ownable, IInstanceManager { ? _getLegacyGearStakingAddress() : _deploySystemContract(contractType_, version_); - if (newSystemContract != address(0)) _setAddress(contractType_, newSystemContract, saveVersion); + _setAddress(contractType_, newSystemContract, saveVersion); } /// @notice Allows cross-chain governance to set a global address in the address provider @@ -203,15 +203,12 @@ contract InstanceManager is Ownable, IInstanceManager { } /// @dev Deploys a system contract and returns its address - function _deploySystemContract(bytes32 _contractType, uint256 _version) internal returns (address) { - try ProxyCall(crossChainGovernanceProxy).proxyCall( + function _deploySystemContract(bytes32 contractType_, uint256 version_) internal returns (address) { + bytes memory result = ProxyCall(crossChainGovernanceProxy).proxyCall( address(bytecodeRepository), - abi.encodeCall(BytecodeRepository.deploy, (_contractType, _version, abi.encode(addressProvider), 0)) - ) returns (bytes memory result) { - return abi.decode(result, (address)); - } catch { - return address(0); - } + abi.encodeCall(BytecodeRepository.deploy, (contractType_, version_, abi.encode(addressProvider), 0)) + ); + return abi.decode(result, (address)); } /// @dev Whether there is a legacy instance on this chain @@ -229,7 +226,8 @@ contract InstanceManager is Ownable, IInstanceManager { return 0xe88846b6C85AA67688e453c7eaeeeb40F51e1F0a; } else if (block.chainid == 42161) { return 0xf3599BEfe8E79169Afd5f0b7eb0A1aA322F193D9; + } else { + revert(); } - return address(0); } } diff --git a/contracts/instance/PriceFeedStore.sol b/contracts/instance/PriceFeedStore.sol index 2ee31d8..44c28b3 100644 --- a/contracts/instance/PriceFeedStore.sol +++ b/contracts/instance/PriceFeedStore.sol @@ -236,13 +236,13 @@ contract PriceFeedStore is /// @notice Executes price feed configuration `calls` with owner privileges /// @dev Reverts if caller is not owner /// @dev Reverts if any of call targets is not a known price feed - /// @dev Reverts if any of calls transfers or renounces ownership over price feed + /// @dev Reverts if any of calls renounces ownership over price feed function configurePriceFeeds(Call[] calldata calls) external override onlyOwner { uint256 numCalls = calls.length; for (uint256 i; i < numCalls; ++i) { if (!_knownPriceFeeds.contains(calls[i].target)) revert PriceFeedIsNotKnownException(calls[i].target); bytes4 selector = bytes4(calls[i].callData); - if (selector == Ownable.transferOwnership.selector || selector == Ownable.renounceOwnership.selector) { + if (selector == Ownable.renounceOwnership.selector) { revert ForbiddenConfigurationMethodException(selector); } calls[i].target.functionCall(calls[i].callData); @@ -292,14 +292,12 @@ contract PriceFeedStore is /// @dev Returns whether `priceFeed` is deployed externally or via BCR. /// For latter case, also ensures that price feed is owned by the store. - function _validatePriceFeedDeployment(address priceFeed) internal view returns (bool) { + function _validatePriceFeedDeployment(address priceFeed) internal returns (bool) { if (!IBytecodeRepository(bytecodeRepository).isDeployedFromRepository(priceFeed)) return true; + try Ownable2Step(priceFeed).acceptOwnership() {} catch {} try Ownable(priceFeed).owner() returns (address owner_) { if (owner_ != address(this)) revert PriceFeedIsNotOwnedByStore(priceFeed); - try Ownable2Step(priceFeed).pendingOwner() returns (address pendingOwner_) { - if (pendingOwner_ != address(0)) revert PriceFeedIsNotOwnedByStore(priceFeed); - } catch {} } catch {} return false; diff --git a/contracts/interfaces/IBytecodeRepository.sol b/contracts/interfaces/IBytecodeRepository.sol index 0ce2026..261c583 100644 --- a/contracts/interfaces/IBytecodeRepository.sol +++ b/contracts/interfaces/IBytecodeRepository.sol @@ -32,7 +32,8 @@ interface IBytecodeRepository is IVersion, IImmutableOwnableTrait { bytes32 indexed contractType, uint256 indexed version, address author, - string source + string source, + bytes signature ); // ------ // diff --git a/contracts/market/MarketConfigurator.sol b/contracts/market/MarketConfigurator.sol index 3c01094..a887127 100644 --- a/contracts/market/MarketConfigurator.sol +++ b/contracts/market/MarketConfigurator.sol @@ -991,7 +991,7 @@ contract MarketConfigurator is DeployerTrait, IMarketConfigurator { } } - /// @dev Returns latest patch in the address provider for given contract type and minor version + /// @dev Returns latest patch in the address provider for given contract type with matching minor version function _getLatestPatch(bytes32 key, uint256 minorVersion) internal view returns (address) { return _getAddressOrRevert(key, IAddressProvider(addressProvider).getLatestPatchVersion(key, minorVersion)); } diff --git a/contracts/market/legacy/MarketConfiguratorLegacy.sol b/contracts/market/legacy/MarketConfiguratorLegacy.sol index 4e493c8..91cf628 100644 --- a/contracts/market/legacy/MarketConfiguratorLegacy.sol +++ b/contracts/market/legacy/MarketConfiguratorLegacy.sol @@ -206,11 +206,10 @@ contract MarketConfiguratorLegacy is MarketConfigurator { address rateKeeper = _rateKeeper(quotaKeeper); address lossPolicy = IContractsRegister(contractsRegister).getLossPolicy(pool); - // NOTE: authorize factories for contracts that might be used after the migration; - // legacy price oracle is left unauthorized since it's not gonna be used after the migration + // NOTE: authorize factories for contracts that might still be used after the migration; legacy price oracle + // is left unauthorized since it's not gonna be used, IRM is unauthorized since it's not configurable _authorizeFactory(factories.poolFactory, pool, pool); _authorizeFactory(factories.poolFactory, pool, quotaKeeper); - _authorizeFactory(factories.interestRateModelFactory, pool, interestRateModel); _authorizeFactory(factories.rateKeeperFactory, pool, rateKeeper); _authorizeFactory(factories.lossPolicyFactory, pool, lossPolicy); diff --git a/contracts/test/helpers/GlobalSetup.sol b/contracts/test/helpers/GlobalSetup.sol index a0ab2d2..11148e1 100644 --- a/contracts/test/helpers/GlobalSetup.sol +++ b/contracts/test/helpers/GlobalSetup.sol @@ -10,6 +10,7 @@ import {PriceFeedStore} from "../../instance/PriceFeedStore.sol"; import {IBytecodeRepository} from "../../interfaces/IBytecodeRepository.sol"; import {IAddressProvider} from "../../interfaces/IAddressProvider.sol"; import {IInstanceManager} from "../../interfaces/IInstanceManager.sol"; +import {Domain} from "../../libraries/Domain.sol"; import {IWETH} from "@gearbox-protocol/core-v3/contracts/interfaces/external/IWETH.sol"; import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol"; @@ -40,7 +41,15 @@ import { AP_LOSS_POLICY_DEFAULT, AP_CREDIT_MANAGER, AP_CREDIT_FACADE, - AP_CREDIT_CONFIGURATOR + AP_CREDIT_CONFIGURATOR, + DOMAIN_ADAPTER, + DOMAIN_BOT, + DOMAIN_DEGEN_NFT, + DOMAIN_IRM, + DOMAIN_LOSS_POLICY, + DOMAIN_PRICE_FEED, + DOMAIN_RATE_KEEPER, + DOMAIN_ZAPPER } from "../../libraries/ContractLiterals.sol"; import {SignedBatch, Bytecode} from "../../interfaces/Types.sol"; @@ -121,8 +130,6 @@ import {CurveCryptoLPPriceFeed} from "@gearbox-protocol/oracles-v3/contracts/ora import {CurveStableLPPriceFeed} from "@gearbox-protocol/oracles-v3/contracts/oracles/curve/CurveStableLPPriceFeed.sol"; import {ERC4626PriceFeed} from "@gearbox-protocol/oracles-v3/contracts/oracles/erc4626/ERC4626PriceFeed.sol"; -import {console} from "forge-std/console.sol"; - struct UploadableContract { bytes initCode; bytes32 contractType; @@ -142,7 +149,10 @@ contract GlobalSetup is Test, InstanceManagerHelper { constructor() { _setCoreContracts(); _setAdapters(); + _setInterestRateModels(); + _setLossPolicies(); _setPriceFeeds(); + _setRateKeepers(); } function _setUpGlobalContracts() internal { @@ -150,21 +160,40 @@ contract GlobalSetup is Test, InstanceManagerHelper { CrossChainCall[] memory calls = new CrossChainCall[](1); calls[0] = _generateAddAuditorCall(auditor, "Initial Auditor"); - - _submitBatchAndSign("Add Auditor", calls); + _submitBatchAndSign("Add auditor", calls); + + bytes32[8] memory publicDomains = [ + DOMAIN_ADAPTER, + DOMAIN_BOT, + DOMAIN_DEGEN_NFT, + DOMAIN_IRM, + DOMAIN_LOSS_POLICY, + DOMAIN_PRICE_FEED, + DOMAIN_RATE_KEEPER, + DOMAIN_ZAPPER + ]; + calls = new CrossChainCall[](publicDomains.length); + for (uint256 i = 0; i < publicDomains.length; ++i) { + calls[i] = _generateAddPublicDomainCall(publicDomains[i]); + } + _submitBatchAndSign("Add public domains", calls); uint256 len = contractsToUpload.length; - calls = new CrossChainCall[](len); - for (uint256 i = 0; i < len; ++i) { bytes32 bytecodeHash = _uploadByteCodeAndSign( contractsToUpload[i].initCode, contractsToUpload[i].contractType, contractsToUpload[i].version ); - calls[i] = _generateAllowSystemContractCall(bytecodeHash); - } - _submitBatchAndSign("Allow system contracts", calls); + bool isPublicContract = IBytecodeRepository(bytecodeRepository).isPublicDomain( + Domain.extractDomain(contractsToUpload[i].contractType) + ); + // NOTE: allowing public contracts doesn't require CCG permissions but it's convenient to execute in batch + calls[i] = isPublicContract + ? _generateAllowPublicContractCall(bytecodeHash) + : _generateAllowSystemContractCall(bytecodeHash); + } + _submitBatchAndSign("Allow contracts", calls); DeploySystemContractCall[10] memory deployCalls = [ DeploySystemContractCall({contractType: AP_BOT_LIST, version: 3_10, saveVersion: false}), @@ -178,17 +207,14 @@ contract GlobalSetup is Test, InstanceManagerHelper { DeploySystemContractCall({contractType: AP_RATE_KEEPER_FACTORY, version: 3_10, saveVersion: true}), DeploySystemContractCall({contractType: AP_LOSS_POLICY_FACTORY, version: 3_10, saveVersion: true}) ]; - len = deployCalls.length; - calls = new CrossChainCall[](len); for (uint256 i = 0; i < len; ++i) { calls[i] = _generateDeploySystemContractCall( deployCalls[i].contractType, deployCalls[i].version, deployCalls[i].saveVersion ); } - - _submitBatchAndSign("System contracts", calls); + _submitBatchAndSign("Deploy system contracts", calls); } function _attachGlobalContracts() internal { @@ -289,26 +315,6 @@ contract GlobalSetup is Test, InstanceManagerHelper { }) ); - contractsToUpload.push( - UploadableContract({ - initCode: type(LinearInterestRateModelV3).creationCode, - contractType: AP_INTEREST_RATE_MODEL_LINEAR, - version: 3_10 - }) - ); - - contractsToUpload.push( - UploadableContract({ - initCode: type(TumblerV3).creationCode, - contractType: AP_RATE_KEEPER_TUMBLER, - version: 3_10 - }) - ); - - contractsToUpload.push( - UploadableContract({initCode: type(GaugeV3).creationCode, contractType: AP_RATE_KEEPER_GAUGE, version: 3_10}) - ); - contractsToUpload.push( UploadableContract({initCode: type(BotListV3).creationCode, contractType: AP_BOT_LIST, version: 3_10}) ); @@ -337,14 +343,6 @@ contract GlobalSetup is Test, InstanceManagerHelper { }) ); - contractsToUpload.push( - UploadableContract({ - initCode: type(AliasedLossPolicyV3).creationCode, - contractType: AP_LOSS_POLICY_ALIASED, - version: 3_10 - }) - ); - contractsToUpload.push( UploadableContract({ initCode: type(MarketConfigurator).creationCode, @@ -399,7 +397,6 @@ contract GlobalSetup is Test, InstanceManagerHelper { } function _setAdapters() internal { - // TODO: set adapters contractsToUpload.push( UploadableContract({ initCode: type(EqualizerRouterAdapter).creationCode, @@ -593,15 +590,34 @@ contract GlobalSetup is Test, InstanceManagerHelper { ); } + function _setInterestRateModels() internal { + contractsToUpload.push( + UploadableContract({ + initCode: type(LinearInterestRateModelV3).creationCode, + contractType: "INTEREST_RATE_MODEL::LINEAR", + version: 3_10 + }) + ); + } + + function _setLossPolicies() internal { + contractsToUpload.push( + UploadableContract({ + initCode: type(AliasedLossPolicyV3).creationCode, + contractType: "LOSS_POLICY::ALIASED", + version: 3_10 + }) + ); + } + function _setPriceFeeds() internal { - // TODO: set price feeds - // contractsToUpload.push( - // UploadableContract({ - // initCode: type(BPTWeightedPriceFeed).creationCode, - // contractType: "PRICE_FEED::BALANCER_WEIGHTED", - // version: 3_10 - // }) - // ); + contractsToUpload.push( + UploadableContract({ + initCode: type(BPTWeightedPriceFeed).creationCode, + contractType: "PRICE_FEED::BALANCER_WEIGHTED", + version: 3_10 + }) + ); contractsToUpload.push( UploadableContract({ @@ -716,6 +732,20 @@ contract GlobalSetup is Test, InstanceManagerHelper { ); } + function _setRateKeepers() internal { + contractsToUpload.push( + UploadableContract({initCode: type(GaugeV3).creationCode, contractType: "RATE_KEEPER::GAUGE", version: 3_10}) + ); + + contractsToUpload.push( + UploadableContract({ + initCode: type(TumblerV3).creationCode, + contractType: "RATE_KEEPER::TUMBLER", + version: 3_10 + }) + ); + } + // function _setupPriceFeedStore() internal { // // _addPriceFeed(CHAINLINK_ETH_USD, 1 days); // // _addPriceFeed(CHAINLINK_USDC_USD, 1 days); diff --git a/contracts/test/helpers/InstanceManagerHelper.sol b/contracts/test/helpers/InstanceManagerHelper.sol index 2796500..3c32c94 100644 --- a/contracts/test/helpers/InstanceManagerHelper.sol +++ b/contracts/test/helpers/InstanceManagerHelper.sol @@ -91,6 +91,12 @@ contract InstanceManagerHelper is BCRHelpers, CCGHelper { ); } + function _generateAllowPublicContractCall(bytes32 _bytecodeHash) internal view returns (CrossChainCall memory) { + return _buildCrossChainCallDAO( + bytecodeRepository, abi.encodeCall(IBytecodeRepository.allowPublicContract, (_bytecodeHash)) + ); + } + function _generateDeploySystemContractCall(bytes32 _contractName, uint256 _version, bool _saveVersion) internal view @@ -103,6 +109,21 @@ contract InstanceManagerHelper is BCRHelpers, CCGHelper { }); } + function _generateAddPublicDomainCall(bytes32 domain) internal view returns (CrossChainCall memory) { + return + _buildCrossChainCallDAO(bytecodeRepository, abi.encodeCall(IBytecodeRepository.addPublicDomain, (domain))); + } + + function _generateSetTokenSpecificPostfixCall(address token, bytes32 postfix) + internal + view + returns (CrossChainCall memory) + { + return _buildCrossChainCallDAO( + bytecodeRepository, abi.encodeCall(IBytecodeRepository.setTokenSpecificPostfix, (token, postfix)) + ); + } + function _generateActivateCall( uint256 _chainId, address _instanceOwner, diff --git a/lib/@gearbox-protocol/core-v3 b/lib/@gearbox-protocol/core-v3 index f9894cb..a94cb84 160000 --- a/lib/@gearbox-protocol/core-v3 +++ b/lib/@gearbox-protocol/core-v3 @@ -1 +1 @@ -Subproject commit f9894cb5ce8c0f6fd3dd4b233e8d72f953d2fb05 +Subproject commit a94cb842d221594fff4fac92253d316c24bcad7e From 7417ac335e9e139e49a608f7deac2d9c4970c1d0 Mon Sep 17 00:00:00 2001 From: Dima Lekhovitsky Date: Sat, 1 Mar 2025 16:48:29 +0200 Subject: [PATCH 3/4] fix: remove unnecessary call from IM helper --- contracts/test/helpers/InstanceManagerHelper.sol | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/contracts/test/helpers/InstanceManagerHelper.sol b/contracts/test/helpers/InstanceManagerHelper.sol index 3c32c94..27b5950 100644 --- a/contracts/test/helpers/InstanceManagerHelper.sol +++ b/contracts/test/helpers/InstanceManagerHelper.sol @@ -114,16 +114,6 @@ contract InstanceManagerHelper is BCRHelpers, CCGHelper { _buildCrossChainCallDAO(bytecodeRepository, abi.encodeCall(IBytecodeRepository.addPublicDomain, (domain))); } - function _generateSetTokenSpecificPostfixCall(address token, bytes32 postfix) - internal - view - returns (CrossChainCall memory) - { - return _buildCrossChainCallDAO( - bytecodeRepository, abi.encodeCall(IBytecodeRepository.setTokenSpecificPostfix, (token, postfix)) - ); - } - function _generateActivateCall( uint256 _chainId, address _instanceOwner, From 75ae179f5b9992539aa918ad10f86d6f7bf9b18f Mon Sep 17 00:00:00 2001 From: Dima Lekhovitsky Date: Sun, 2 Mar 2025 12:58:38 +0200 Subject: [PATCH 4/4] test: tests and setup fixes --- .../configuration/ConfigurationTestHelper.sol | 4 +- .../InterestRateModelConfiguration.unit.t.sol | 4 +- .../test/global/InstanceManager.unit.t.sol | 3 +- .../test/global/PriceFeedStore.unit.t.sol | 40 ++----------------- contracts/test/helpers/GlobalSetup.sol | 2 +- contracts/test/suite/NewChainDeploySuite.sol | 4 +- 6 files changed, 12 insertions(+), 45 deletions(-) diff --git a/contracts/test/configuration/ConfigurationTestHelper.sol b/contracts/test/configuration/ConfigurationTestHelper.sol index fe4c41f..a2b68fb 100644 --- a/contracts/test/configuration/ConfigurationTestHelper.sol +++ b/contracts/test/configuration/ConfigurationTestHelper.sol @@ -146,9 +146,9 @@ contract ConfigurationTestHelper is Test, GlobalSetup { bytes32 bytecodeHash = _uploadByteCodeAndSign(type(MockLossPolicy).creationCode, "LOSS_POLICY::MOCK", 3_10); - calls[0] = _generateAllowSystemContractCall(bytecodeHash); + calls[0] = _generateAllowPublicContractCall(bytecodeHash); - _submitBatchAndSign("Allow system contracts", calls); + _submitBatchAndSign("Allow public contracts", calls); } function _deployTestPool() internal returns (address) { diff --git a/contracts/test/configuration/InterestRateModelConfiguration.unit.t.sol b/contracts/test/configuration/InterestRateModelConfiguration.unit.t.sol index b98a28c..1f49127 100644 --- a/contracts/test/configuration/InterestRateModelConfiguration.unit.t.sol +++ b/contracts/test/configuration/InterestRateModelConfiguration.unit.t.sol @@ -20,8 +20,8 @@ contract InterestRateModelConfigurationUnitTest is ConfigurationTestHelper { function test_IRM_01_configure() public { CrossChainCall[] memory calls = new CrossChainCall[](1); bytes32 bytecodeHash = _uploadByteCodeAndSign(type(MockIRM).creationCode, "IRM::MOCK", 3_10); - calls[0] = _generateAllowSystemContractCall(bytecodeHash); - _submitBatchAndSign("Allow system contracts", calls); + calls[0] = _generateAllowPublicContractCall(bytecodeHash); + _submitBatchAndSign("Allow public contracts", calls); vm.prank(admin); address newIRM = marketConfigurator.updateInterestRateModel( diff --git a/contracts/test/global/InstanceManager.unit.t.sol b/contracts/test/global/InstanceManager.unit.t.sol index 1e1a8b8..352450f 100644 --- a/contracts/test/global/InstanceManager.unit.t.sol +++ b/contracts/test/global/InstanceManager.unit.t.sol @@ -294,10 +294,9 @@ contract InstanceManagerTest is Test { "DEPLOYMENT_FAILED" ); + vm.expectRevert("DEPLOYMENT_FAILED"); vm.prank(crossChainGovernance); manager.deploySystemContract(contractType, version, false); - // Should not update address if deployment failed - assertEq(addressProvider.getAddressOrRevert(contractType, NO_VERSION_CONTROL), newContract); } /// @notice Test legacy GEAR staking deployment diff --git a/contracts/test/global/PriceFeedStore.unit.t.sol b/contracts/test/global/PriceFeedStore.unit.t.sol index 650be35..af00ac3 100644 --- a/contracts/test/global/PriceFeedStore.unit.t.sol +++ b/contracts/test/global/PriceFeedStore.unit.t.sol @@ -488,6 +488,7 @@ contract PriceFeedStoreTest is Test { abi.encodeWithSignature("isDeployedFromRepository(address)", address(ownableFeed)), abi.encode(true) ); + vm.mockCall(address(ownableFeed), abi.encodeWithSignature("acceptOwnership()"), ""); vm.mockCall(address(ownableFeed), abi.encodeWithSignature("owner()"), abi.encode(address(store))); // Test Ownable feed owned by other (should fail) @@ -497,20 +498,9 @@ contract PriceFeedStoreTest is Test { abi.encodeWithSignature("isDeployedFromRepository(address)", address(wrongOwnerFeed)), abi.encode(true) ); + vm.mockCall(address(wrongOwnerFeed), abi.encodeWithSignature("acceptOwnership()"), ""); vm.mockCall(address(wrongOwnerFeed), abi.encodeWithSignature("owner()"), abi.encode(makeAddr("other"))); - // Test Ownable2Step feed with pending transfer (should fail) - MockPriceFeed ownable2StepFeed = new MockPriceFeed(); - vm.mockCall( - address(bytecodeRepository), - abi.encodeWithSignature("isDeployedFromRepository(address)", address(ownable2StepFeed)), - abi.encode(true) - ); - vm.mockCall(address(ownable2StepFeed), abi.encodeWithSignature("owner()"), abi.encode(address(store))); - vm.mockCall( - address(ownable2StepFeed), abi.encodeWithSignature("pendingOwner()"), abi.encode(makeAddr("pending")) - ); - vm.startPrank(owner); // Non-ownable should pass @@ -525,12 +515,6 @@ contract PriceFeedStoreTest is Test { ); store.addPriceFeed(address(wrongOwnerFeed), 3600, "Wrong Owner Feed"); - // Pending transfer should fail - vm.expectRevert( - abi.encodeWithSelector(IPriceFeedStore.PriceFeedIsNotOwnedByStore.selector, address(ownable2StepFeed)) - ); - store.addPriceFeed(address(ownable2StepFeed), 3600, "Ownable2Step Feed"); - vm.stopPrank(); } @@ -574,36 +558,20 @@ contract PriceFeedStoreTest is Test { store.configurePriceFeeds(calls); } - function test_PFS_24_configurePriceFeeds_reverts_on_ownership_transfer() public { + function test_PFS_24_configurePriceFeeds_reverts_on_renounceOwnership() public { vm.prank(owner); store.addPriceFeed(address(priceFeed), 3600, "ETH/USD"); - Call[] memory transferCall = new Call[](1); - transferCall[0] = - Call(address(priceFeed), abi.encodeWithSignature("transferOwnership(address)", makeAddr("newOwner"))); - Call[] memory renounceCall = new Call[](1); renounceCall[0] = Call(address(priceFeed), abi.encodeWithSignature("renounceOwnership()")); - vm.startPrank(owner); - - // Test transferOwnership - vm.expectRevert( - abi.encodeWithSelector( - IPriceFeedStore.ForbiddenConfigurationMethodException.selector, bytes4(transferCall[0].callData) - ) - ); - store.configurePriceFeeds(transferCall); - - // Test renounceOwnership vm.expectRevert( abi.encodeWithSelector( IPriceFeedStore.ForbiddenConfigurationMethodException.selector, bytes4(renounceCall[0].callData) ) ); + vm.prank(owner); store.configurePriceFeeds(renounceCall); - - vm.stopPrank(); } function test_PFS_25_removePriceFeed_works() public { diff --git a/contracts/test/helpers/GlobalSetup.sol b/contracts/test/helpers/GlobalSetup.sol index 11148e1..37813fb 100644 --- a/contracts/test/helpers/GlobalSetup.sol +++ b/contracts/test/helpers/GlobalSetup.sol @@ -594,7 +594,7 @@ contract GlobalSetup is Test, InstanceManagerHelper { contractsToUpload.push( UploadableContract({ initCode: type(LinearInterestRateModelV3).creationCode, - contractType: "INTEREST_RATE_MODEL::LINEAR", + contractType: "IRM::LINEAR", version: 3_10 }) ); diff --git a/contracts/test/suite/NewChainDeploySuite.sol b/contracts/test/suite/NewChainDeploySuite.sol index 1bf55d1..3ca3e9e 100644 --- a/contracts/test/suite/NewChainDeploySuite.sol +++ b/contracts/test/suite/NewChainDeploySuite.sol @@ -109,9 +109,9 @@ contract NewChainDeploySuite is Test, GlobalSetup { bytes32 bytecodeHash = _uploadByteCodeAndSign(type(MockLossPolicy).creationCode, "LOSS_POLICY::MOCK", 3_10); - calls[0] = _generateAllowSystemContractCall(bytecodeHash); + calls[0] = _generateAllowPublicContractCall(bytecodeHash); - _submitBatchAndSign("Allow system contracts", calls); + _submitBatchAndSign("Allow public contracts", calls); } function _setupPriceFeedStore() internal {