diff --git a/contracts/accounting/AccountingService.sol b/contracts/accounting/AccountingService.sol index dac69b498..ab31c803e 100644 --- a/contracts/accounting/AccountingService.sol +++ b/contracts/accounting/AccountingService.sol @@ -26,14 +26,13 @@ contract AccountingService is ) internal virtual override - initializer() + onlyInitializing() { ( - address authority, - address registry - ) = abi.decode(data, (address, address)); + address authority + ) = abi.decode(data, (address)); - __Service_init(authority, registry, owner); + __Service_init(authority, owner); _registerInterface(type(IAccountingService).interfaceId); } @@ -256,7 +255,7 @@ contract AccountingService is internal virtual { - emit LogComponentServiceUpdateFee( + emit LogAccountingServiceUpdateFee( productNftId, name, feeBefore.fractionalFee, diff --git a/contracts/accounting/AccountingServiceManager.sol b/contracts/accounting/AccountingServiceManager.sol index b8cb608a6..d00197847 100644 --- a/contracts/accounting/AccountingServiceManager.sol +++ b/contracts/accounting/AccountingServiceManager.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.20; import {AccountingService} from "./AccountingService.sol"; -import {IVersionable} from "../upgradeability/IVersionable.sol"; +import {IUpgradeable} from "../upgradeability/IUpgradeable.sol"; import {ProxyManager} from "../upgradeability/ProxyManager.sol"; contract AccountingServiceManager is ProxyManager { @@ -12,19 +12,17 @@ contract AccountingServiceManager is ProxyManager { /// @dev initializes proxy manager with service implementation constructor( address authority, - address registry, bytes32 salt ) { AccountingService svc = new AccountingService(); - bytes memory data = abi.encode(authority, registry); - IVersionable versionable = initialize( - registry, + bytes memory data = abi.encode(authority); + IUpgradeable upgradeable = initialize( address(svc), data, salt); - _accountingService = AccountingService(address(versionable)); + _accountingService = AccountingService(address(upgradeable)); } //--- view functions ----------------------------------------------------// diff --git a/contracts/accounting/IAccountingService.sol b/contracts/accounting/IAccountingService.sol index 69963286b..e0c8f5f66 100644 --- a/contracts/accounting/IAccountingService.sol +++ b/contracts/accounting/IAccountingService.sol @@ -13,7 +13,7 @@ import {UFixed} from "../type/UFixed.sol"; interface IAccountingService is IService { - event LogComponentServiceUpdateFee( + event LogAccountingServiceUpdateFee( NftId nftId, string feeName, UFixed previousFractionalFee, diff --git a/contracts/authorization/AccessAdmin.sol b/contracts/authorization/AccessAdmin.sol index 42cab602b..431dbe358 100644 --- a/contracts/authorization/AccessAdmin.sol +++ b/contracts/authorization/AccessAdmin.sol @@ -7,20 +7,20 @@ import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet import {IAccess} from "./IAccess.sol"; import {IAccessAdmin} from "./IAccessAdmin.sol"; import {IAuthorization} from "./IAuthorization.sol"; -import {IRegistry} from "../registry/IRegistry.sol"; import {IServiceAuthorization} from "./IServiceAuthorization.sol"; import {AccessAdminLib} from "./AccessAdminLib.sol"; import {AccessManagerCloneable} from "./AccessManagerCloneable.sol"; import {Blocknumber, BlocknumberLib} from "../type/Blocknumber.sol"; import {ContractLib} from "../shared/ContractLib.sol"; -import {NftId, NftIdLib} from "../type/NftId.sol"; +import {NftId} from "../type/NftId.sol"; import {ObjectType} from "../type/ObjectType.sol"; import {RoleId, RoleIdLib, ADMIN_ROLE, PUBLIC_ROLE} from "../type/RoleId.sol"; +import {RegistryLinked} from "../shared/RegistryLinked.sol"; import {Selector, SelectorSetLib} from "../type/Selector.sol"; import {Str, StrLib} from "../type/String.sol"; import {TimestampLib} from "../type/Timestamp.sol"; -import {VersionPart} from "../type/Version.sol"; +import {VersionPartLib, VersionPart} from "../type/Version.sol"; /** @@ -30,6 +30,7 @@ import {VersionPart} from "../type/Version.sol"; */ contract AccessAdmin is AccessManagedUpgradeable, + RegistryLinked, IAccessAdmin { using EnumerableSet for EnumerableSet.AddressSet; @@ -91,12 +92,16 @@ contract AccessAdmin is /// Internally initializes access manager with this admin and creates basic role setup. function initialize( address authority, - string memory adminName + string memory adminName, + VersionPart release ) public - initializer() { - __AccessAdmin_init(authority, adminName); + if(_getInitializedVersion() != 0) { + revert InvalidInitialization(); + } + + __AccessAdmin_init(authority, adminName, release); } @@ -106,14 +111,16 @@ contract AccessAdmin is /// - this function as well as any completeSetup functions MUST be called in the same tx. function __AccessAdmin_init( address authority, - string memory adminName + string memory adminName, + VersionPart release ) internal - onlyInitializing() + reinitializer(release.toInt()) { AccessAdminLib.checkInitParameters(authority, adminName); + _authority = AccessManagerCloneable(authority); - _authority.initialize(address(this)); + _authority.initialize(address(this), release); // delayed additional check for authority after its initialization if (!ContractLib.isAuthority(authority)) { @@ -121,7 +128,7 @@ contract AccessAdmin is } // effects - // set and initialize this access manager contract as + // set and initialize this contract as // the admin (ADMIN_ROLE) of the provided authority __AccessManaged_init(authority); @@ -129,7 +136,7 @@ contract AccessAdmin is _adminName = adminName; // set initial linked NFT ID to zero - _linkedNftId = NftIdLib.zero(); + //_linkedNftId = NftIdLib.zero(); // setup admin role _createRoleUnchecked( @@ -149,12 +156,7 @@ contract AccessAdmin is //--- view functions for access admin ---------------------------------------// function getRelease() public view virtual returns (VersionPart release) { - return _authority.getRelease(); - } - - - function getRegistry() public view returns (IRegistry registry) { - return _authority.getRegistry(); + return VersionPartLib.toVersionPart(uint8(_getInitializedVersion())); } @@ -298,11 +300,12 @@ contract AccessAdmin is //--- internal/private functions -------------------------------------------------// function _linkToNftOwnable(address registerable) internal { - if (!getRegistry().isRegistered(registerable)) { + NftId nftId = _getRegistry().getNftIdForAddress(registerable); + if (nftId.eqz()) { revert ErrorAccessAdminNotRegistered(registerable); } - _linkedNftId = getRegistry().getNftIdForAddress(registerable); + _linkedNftId = nftId; } diff --git a/contracts/authorization/AccessAdminLib.sol b/contracts/authorization/AccessAdminLib.sol index 24aa5daa6..619b72c42 100644 --- a/contracts/authorization/AccessAdminLib.sol +++ b/contracts/authorization/AccessAdminLib.sol @@ -336,9 +336,9 @@ library AccessAdminLib { // ACCESS_ADMIN_LIB view returns (IAuthorization componentAuthorization) { - checkIsRegistered(address(accessAdmin.getRegistry()), componentAddress, expectedType); - VersionPart expecteRelease = accessAdmin.getRelease(); + checkIsRegistered(componentAddress, expectedType, expecteRelease); + IAuthorizedComponent component = IAuthorizedComponent(componentAddress); componentAuthorization = component.getAuthorization(); @@ -436,22 +436,25 @@ library AccessAdminLib { // ACCESS_ADMIN_LIB function checkIsRegistered( - address registry, address target, - ObjectType expectedType + ObjectType expectedType, + VersionPart expectedRelease ) public view { - checkRegistry(registry); + IRegistry.ObjectInfo memory info = ContractLib.getRegistry().getObjectInfo(target); - ObjectType tagetType = IRegistry(registry).getObjectInfo(target).objectType; - if (tagetType.eqz()) { + if (info.objectType.eqz()) { revert IAccessAdmin.ErrorAccessAdminNotRegistered(target); } - if (tagetType != expectedType) { - revert IAccessAdmin.ErrorAccessAdminTargetTypeMismatch(target, expectedType, tagetType); + if (info.objectType != expectedType) { + revert IAccessAdmin.ErrorAccessAdminTargetTypeMismatch(target, expectedType, info.objectType); + } + + if (info.release != expectedRelease) { + revert IAccessAdmin.ErrorAccessAdminTargetReleaseMismatch(target, expectedRelease, info.release); } } diff --git a/contracts/authorization/AccessManagerCloneable.sol b/contracts/authorization/AccessManagerCloneable.sol index 64ea901c8..e8b60b36b 100644 --- a/contracts/authorization/AccessManagerCloneable.sol +++ b/contracts/authorization/AccessManagerCloneable.sol @@ -4,9 +4,9 @@ pragma solidity ^0.8.20; import {AccessManagerUpgradeable} from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagerUpgradeable.sol"; import {IAccessManager} from "@openzeppelin/contracts/access/manager/IAccessManager.sol"; +import {IAccessAdmin} from "./IAccessAdmin.sol"; import {InitializableERC165} from "../shared/InitializableERC165.sol"; -import {RegistryLinked} from "../shared/RegistryLinked.sol"; -import {VersionPart} from "../type/Version.sol"; +import {VersionPartLib, VersionPart} from "../type/Version.sol"; /// @dev An AccessManager based on OpenZeppelin that is cloneable and has a central lock property. @@ -14,8 +14,7 @@ import {VersionPart} from "../type/Version.sol"; /// Cloned by upon release preparation and instance cloning. contract AccessManagerCloneable is AccessManagerUpgradeable, - InitializableERC165, - RegistryLinked + InitializableERC165 { error ErrorAccessManagerCallerNotAdmin(address caller); error ErrorAccessManagerRegistryAlreadySet(address registry); @@ -24,7 +23,6 @@ contract AccessManagerCloneable is error ErrorAccessManagerTargetAdminLocked(address target); error ErrorAccessManagerCallerAdminLocked(address caller); - VersionPart private _release; bool private _isLocked; @@ -36,34 +34,36 @@ contract AccessManagerCloneable is _; } - - function initialize(address admin) + function initialize(address adminAddress, VersionPart release) public - initializer() + { - __ERC165_init(); - __AccessManager_init(admin); + if(_getInitializedVersion() != 0) { + revert InvalidInitialization(); + } - _registerInterface(type(IAccessManager).interfaceId); + AccessManagerCloneable_init(adminAddress, release); } - - /// @dev Completes the setup of the access manager. - /// Links the access manager to the registry and sets the release version. - function completeSetup( - address registry, + function AccessManagerCloneable_init( + address admin, VersionPart release ) - external - onlyAdminRole - reinitializer(uint64(release.toInt())) + internal + reinitializer(release.toInt()) { - _checkAndSetRegistry(registry); - _checkAndSetRelease(release); + if (!release.isValidRelease()) { + revert ErrorAccessManagerInvalidRelease(release); + } + + __ERC165_init(); + __AccessManager_init(admin); + + _registerInterface(type(IAccessManager).interfaceId); } /// @dev Returns true if the caller is authorized to call the target with the given selector and the manager lock is not set to locked. - /// Feturn values as in OpenZeppelin AccessManager. + /// Return values as in OpenZeppelin AccessManager. /// For a locked manager the function reverts with ErrorAccessManagerTargetAdminLocked. function canCall( address caller, @@ -101,10 +101,10 @@ contract AccessManagerCloneable is /// For the registry admin release 3 is returned. /// For the release admin and the instance admin the actual release version is returned. function getRelease() external view returns (VersionPart release) { - return _release; + return VersionPartLib.toVersionPart( + uint8(_getInitializedVersion())); } - /// @dev Returns true iff all contracts of this access manager are locked. function isLocked() public @@ -113,28 +113,4 @@ contract AccessManagerCloneable is { return _isLocked; } - - - function _checkAndSetRelease(VersionPart release) - internal - { - if (!release.isValidRelease()) { - revert ErrorAccessManagerInvalidRelease(release); - } - - _release = release; - } - - - function _checkAndSetRegistry(address registry) - internal - { - // checks - if(address(getRegistry()) != address(0)) { - revert ErrorAccessManagerRegistryAlreadySet(address(getRegistry()) ); - } - - // effects - __RegistryLinked_init(registry); - } } \ No newline at end of file diff --git a/contracts/authorization/Authorization.sol b/contracts/authorization/Authorization.sol index 79189a97f..84d309b41 100644 --- a/contracts/authorization/Authorization.sol +++ b/contracts/authorization/Authorization.sol @@ -9,7 +9,7 @@ import {ObjectType} from "../type/ObjectType.sol"; import {RoleId, RoleIdLib} from "../type/RoleId.sol"; import {ServiceAuthorization} from "../authorization/ServiceAuthorization.sol"; import {Str, StrLib} from "../type/String.sol"; - +import {VersionPart} from "../type/Version.sol"; contract Authorization is ServiceAuthorization, @@ -30,7 +30,7 @@ contract Authorization is constructor( string memory mainTargetName, ObjectType domain, - uint8 release, + VersionPart release, string memory commitHash, IAccess.TargetType targetType, bool includeTokenHandler diff --git a/contracts/authorization/IAccessAdmin.sol b/contracts/authorization/IAccessAdmin.sol index d6a58ef43..9fff54da9 100644 --- a/contracts/authorization/IAccessAdmin.sol +++ b/contracts/authorization/IAccessAdmin.sol @@ -6,7 +6,6 @@ import {IAccessManaged} from "@openzeppelin/contracts/access/manager/IAccessMana import {IAccess} from "./IAccess.sol"; import {IAuthorization} from "./IAuthorization.sol"; import {IRegistryLinked} from "../shared/IRegistryLinked.sol"; -import {IRelease} from "../registry/IRelease.sol"; import {Blocknumber} from "../type/Blocknumber.sol"; import {NftId} from "../type/NftId.sol"; @@ -19,8 +18,7 @@ import {VersionPart} from "../type/Version.sol"; interface IAccessAdmin is IAccessManaged, IAccess, - IRegistryLinked, - IRelease + IRegistryLinked { // roles, targets and functions @@ -59,6 +57,7 @@ interface IAccessAdmin is error ErrorAccessAdminTargetNotCreated(address target); error ErrorAccessAdminTargetNotRegistered(address target); error ErrorAccessAdminTargetTypeMismatch(address target, ObjectType expectedType, ObjectType actualType); + error ErrorAccessAdminTargetReleaseMismatch(address target, VersionPart expectedRelease, VersionPart actualRelease); // check authorization error ErrorAccessAdminAlreadyInitialized(address authorization); @@ -139,4 +138,5 @@ interface IAccessAdmin is function authorizedFunctions(address target) external view returns (uint256 numberOfFunctions); function getAuthorizedFunction(address target, uint256 idx) external view returns (FunctionInfo memory func, RoleId roleId); + function getRelease() external view returns (VersionPart); } \ No newline at end of file diff --git a/contracts/authorization/IServiceAuthorization.sol b/contracts/authorization/IServiceAuthorization.sol index 5549fa508..c2f34acac 100644 --- a/contracts/authorization/IServiceAuthorization.sol +++ b/contracts/authorization/IServiceAuthorization.sol @@ -16,7 +16,7 @@ interface IServiceAuthorization is error ErrorAuthorizationMainTargetNameEmpty(); error ErrorAuthorizationTargetDomainZero(); - error ErrorAuthorizationReleaseInvalid(uint8 release); + error ErrorAuthorizationReleaseInvalid(VersionPart release); error ErrorAuthorizationCommitHashInvalid(string commitHash); /// @dev Returns the main domain of the authorization. diff --git a/contracts/authorization/ServiceAuthorization.sol b/contracts/authorization/ServiceAuthorization.sol index 312d631ad..2048146c4 100644 --- a/contracts/authorization/ServiceAuthorization.sol +++ b/contracts/authorization/ServiceAuthorization.sol @@ -30,7 +30,7 @@ contract ServiceAuthorization is string public constant ROLE_NAME_SUFFIX = "_Role"; ObjectType public immutable DOMAIN; - uint256 internal immutable _release; + VersionPart internal immutable _release; string internal _commitHash; string internal _mainTargetName; @@ -55,7 +55,7 @@ contract ServiceAuthorization is constructor( string memory mainTargetName, ObjectType domain, - uint8 release, + VersionPart release, string memory commitHash ) { @@ -68,7 +68,7 @@ contract ServiceAuthorization is revert ErrorAuthorizationTargetDomainZero(); } - if (release < VersionPartLib.releaseMin().toInt() || release >= VersionPartLib.releaseMax().toInt()) { + if (!VersionPartLib.isValidRelease(release)) { revert ErrorAuthorizationReleaseInvalid(release); } @@ -103,7 +103,7 @@ contract ServiceAuthorization is /// @inheritdoc IServiceAuthorization function getRelease() public view returns(VersionPart release) { - return VersionPartLib.toVersionPart(_release); + return _release; } /// @inheritdoc IServiceAuthorization diff --git a/contracts/distribution/BasicDistribution.sol b/contracts/distribution/BasicDistribution.sol index ad218633e..26c6ae907 100644 --- a/contracts/distribution/BasicDistribution.sol +++ b/contracts/distribution/BasicDistribution.sol @@ -119,7 +119,6 @@ contract BasicDistribution is } function _initializeBasicDistribution( - address registry, NftId instanceNftId, IAuthorization authorization, address initialOwner, @@ -130,7 +129,6 @@ contract BasicDistribution is onlyInitializing() { __Distribution_init( - registry, instanceNftId, authorization, false, diff --git a/contracts/distribution/BasicDistributionAuthorization.sol b/contracts/distribution/BasicDistributionAuthorization.sol index e534dcff0..0433057be 100644 --- a/contracts/distribution/BasicDistributionAuthorization.sol +++ b/contracts/distribution/BasicDistributionAuthorization.sol @@ -2,15 +2,16 @@ pragma solidity ^0.8.20; import {IAccess} from "../authorization/IAccess.sol"; -import {IInstanceLinkedComponent} from "../shared/IInstanceLinkedComponent.sol"; +import {IComponent} from "../shared/IComponent.sol"; import {Authorization} from "../authorization/Authorization.sol"; import {BasicDistribution} from "./BasicDistribution.sol"; import {Distribution} from "./Distribution.sol"; import {COMPONENT, DISTRIBUTION} from "../type/ObjectType.sol"; import {PUBLIC_ROLE} from "../type/RoleId.sol"; +import {GIF_INITIAL_RELEASE} from "../registry/Registry.sol"; import {TokenHandler} from "../shared/TokenHandler.sol"; - +import {VersionPartLib} from "../type/Version.sol"; contract BasicDistributionAuthorization is Authorization @@ -20,7 +21,7 @@ contract BasicDistributionAuthorization Authorization( distributionName, DISTRIBUTION(), - 3, + GIF_INITIAL_RELEASE(), COMMIT_HASH, TargetType.Component, true) @@ -60,7 +61,7 @@ contract BasicDistributionAuthorization _authorize(functions, BasicDistribution.changeDistributorType.selector, "changeDistributorType"); _authorize(functions, BasicDistribution.createReferral.selector, "createReferral"); - _authorize(functions, IInstanceLinkedComponent.withdrawFees.selector, "withdrawFees"); + _authorize(functions, IComponent.withdrawFees.selector, "withdrawFees"); _authorize(functions, Distribution.withdrawCommission.selector, "withdrawCommission"); } } diff --git a/contracts/distribution/Distribution.sol b/contracts/distribution/Distribution.sol index bab899424..2bb8a2c69 100644 --- a/contracts/distribution/Distribution.sol +++ b/contracts/distribution/Distribution.sol @@ -104,7 +104,6 @@ abstract contract Distribution is function __Distribution_init( - address registry, NftId productNftId, IAuthorization authorization, bool isInterceptor, @@ -116,7 +115,6 @@ abstract contract Distribution is onlyInitializing() { __InstanceLinkedComponent_init( - registry, productNftId, name, DISTRIBUTION(), diff --git a/contracts/distribution/DistributionService.sol b/contracts/distribution/DistributionService.sol index 68cd39315..9c1df3f21 100644 --- a/contracts/distribution/DistributionService.sol +++ b/contracts/distribution/DistributionService.sol @@ -20,8 +20,6 @@ import {KEEP_STATE} from "../type/StateId.sol"; import {ObjectType, ACCOUNTING, COMPONENT, DISTRIBUTION, INSTANCE, DISTRIBUTION, DISTRIBUTOR, REGISTRY} from "../type/ObjectType.sol"; import {InstanceReader} from "../instance/InstanceReader.sol"; import {InstanceStore} from "../instance/InstanceStore.sol"; -// TODO PoolLib feels wrong, should likely go in a component type independent lib -import {PoolLib} from "../pool/PoolLib.sol"; import {ReferralId, ReferralStatus, ReferralLib, REFERRAL_OK, REFERRAL_ERROR_UNKNOWN, REFERRAL_ERROR_EXPIRED, REFERRAL_ERROR_EXHAUSTED} from "../type/Referral.sol"; import {Seconds} from "../type/Seconds.sol"; import {Service} from "../shared/Service.sol"; @@ -44,14 +42,13 @@ contract DistributionService is ) internal virtual override - initializer() + onlyInitializing() { ( - address authority, - address registry - ) = abi.decode(data, (address, address)); + address authority + ) = abi.decode(data, (address)); - __Service_init(authority, registry, owner); + __Service_init(authority, owner); _accountingService = IAccountingService(_getServiceAddress(ACCOUNTING())); _componentService = IComponentService(_getServiceAddress(COMPONENT())); @@ -81,7 +78,7 @@ contract DistributionService is (NftId distributionNftId, IInstance instance) = _getAndVerifyActiveDistribution(); { - NftId productNftId = getRegistry().getParentNftId(distributionNftId); + NftId productNftId = _getRegistry().getParentNftId(distributionNftId); IComponents.FeeInfo memory feeInfo = instance.getInstanceReader().getFeeInfo(productNftId); UFixed variableDistributionFees = feeInfo.distributionFee.fractionalFee; @@ -134,11 +131,12 @@ contract DistributionService is NftIdLib.zero(), distributionNftId, DISTRIBUTOR(), + getRelease(), true, // intercepting property for bundles is defined on pool - address(0), - distributor, - "" - )); + address(0)), + distributor, + "" + ); IDistribution.DistributorInfo memory info = IDistribution.DistributorInfo({ distributorType: distributorType, @@ -197,9 +195,11 @@ contract DistributionService is revert ErrorDistributionServiceExpirationInvalid(expiryAt); } - NftId distributorDistributionNftId = getRegistry().getParentNftId(distributorNftId); - if (distributorDistributionNftId != distributionNftId) { - revert ErrorDistributionServiceDistributorDistributionMismatch(distributorNftId, distributorDistributionNftId, distributionNftId); + { + NftId distributorDistributionNftId = _getRegistry().getParentNftId(distributorNftId); + if (distributorDistributionNftId != distributionNftId) { + revert ErrorDistributionServiceDistributorDistributionMismatch(distributorNftId, distributorDistributionNftId, distributionNftId); + } } { @@ -251,7 +251,7 @@ contract DistributionService is onlyNftOfType(distributionNftId, DISTRIBUTION()) { if (referralIsValid(distributionNftId, referralId)) { - IInstance instance = IInstance(ContractLib.getInstanceForComponent(getRegistry(), distributionNftId)); + IInstance instance = IInstance(ContractLib.getInstanceForComponent(distributionNftId)); // update book keeping for referral info IDistribution.ReferralInfo memory referralInfo = instance.getInstanceReader().getReferralInfo(referralId); @@ -272,7 +272,7 @@ contract DistributionService is restricted() onlyNftOfType(distributionNftId, DISTRIBUTION()) { - IInstance instance = IInstance(ContractLib.getInstanceForComponent(getRegistry(), distributionNftId)); + IInstance instance = IInstance(ContractLib.getInstanceForComponent(distributionNftId)); InstanceReader reader = instance.getInstanceReader(); InstanceStore store = instance.getInstanceStore(); @@ -340,7 +340,7 @@ contract DistributionService is // transfer amount to distributor { - address distributor = getRegistry().ownerOf(distributorNftId); + address distributor = _getRegistry().ownerOf(distributorNftId); emit LogDistributionServiceCommissionWithdrawn(distributorNftId, distributor, address(distributionInfo.tokenHandler.TOKEN()), withdrawnAmount); distributionInfo.tokenHandler.pushToken(distributor, withdrawnAmount); } @@ -357,7 +357,7 @@ contract DistributionService is return false; } - IInstance instance = IInstance(ContractLib.getInstanceForComponent(getRegistry(), distributionNftId)); + IInstance instance = IInstance(ContractLib.getInstanceForComponent(distributionNftId)); IDistribution.ReferralInfo memory info = instance.getInstanceReader().getReferralInfo(referralId); if (info.distributorNftId.eqz()) { @@ -438,7 +438,11 @@ contract DistributionService is IInstance instance ) { - return PoolLib.getAndVerifyActiveComponent(getRegistry(), msg.sender, DISTRIBUTION()); + (poolNftId, instance) = ContractLib.getAndVerifyComponent( + msg.sender, + DISTRIBUTION(), + getRelease(), + true); } diff --git a/contracts/distribution/DistributionServiceManager.sol b/contracts/distribution/DistributionServiceManager.sol index 6bde2c98f..55a7bbf37 100644 --- a/contracts/distribution/DistributionServiceManager.sol +++ b/contracts/distribution/DistributionServiceManager.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; -import {IVersionable} from "../upgradeability/IVersionable.sol"; +import {IUpgradeable} from "../upgradeability/IUpgradeable.sol"; import {ProxyManager} from "../upgradeability/ProxyManager.sol"; import {DistributionService} from "./DistributionService.sol"; @@ -12,19 +12,17 @@ contract DistributionServiceManager is ProxyManager { /// @dev initializes proxy manager with distribution service implementation and deploys instance constructor( address authority, - address registry, bytes32 salt ) { DistributionService svc = new DistributionService{salt: salt}(); - bytes memory data = abi.encode(authority, registry); - IVersionable versionable = initialize( - registry, + bytes memory data = abi.encode(authority); + IUpgradeable upgradeable = initialize( address(svc), data, salt); - _distributionService = DistributionService(address(versionable)); + _distributionService = DistributionService(address(upgradeable)); } //--- view functions ----------------------------------------------------// diff --git a/contracts/examples/fire/FirePool.sol b/contracts/examples/fire/FirePool.sol index 239c39748..8bd494e60 100644 --- a/contracts/examples/fire/FirePool.sol +++ b/contracts/examples/fire/FirePool.sol @@ -16,7 +16,6 @@ contract FirePool is BasicPool { constructor( - address registry, NftId fireProductNftId, string memory componentName, IAuthorization authorization @@ -24,7 +23,6 @@ contract FirePool is { address initialOwner = msg.sender; _intialize( - registry, fireProductNftId, componentName, IComponents.PoolInfo({ @@ -41,7 +39,6 @@ contract FirePool is } function _intialize( - address registry, NftId fireProductNftId, string memory componentName, IComponents.PoolInfo memory poolInfo, @@ -52,7 +49,6 @@ contract FirePool is initializer { _initializeBasicPool( - registry, fireProductNftId, componentName, poolInfo, diff --git a/contracts/examples/fire/FireProduct.sol b/contracts/examples/fire/FireProduct.sol index 3e7c09458..48f11044c 100644 --- a/contracts/examples/fire/FireProduct.sol +++ b/contracts/examples/fire/FireProduct.sol @@ -65,7 +65,6 @@ contract FireProduct is mapping(uint256 fireId => mapping (NftId policyId => bool claimed)) private _claimed; constructor( - address registry, NftId instanceNftid, string memory componentName, IAuthorization authorization @@ -74,7 +73,6 @@ contract FireProduct is address initialOwner = msg.sender; _initialize( - registry, instanceNftid, componentName, authorization, @@ -82,7 +80,6 @@ contract FireProduct is } function _initialize( - address registry, NftId instanceNftId, string memory componentName, IAuthorization authorization, @@ -92,7 +89,6 @@ contract FireProduct is initializer { _initializeBasicProduct( - registry, instanceNftId, componentName, IComponents.ProductInfo({ diff --git a/contracts/examples/flight/FlightOracle.sol b/contracts/examples/flight/FlightOracle.sol index 959c14e57..5b281a9d6 100644 --- a/contracts/examples/flight/FlightOracle.sol +++ b/contracts/examples/flight/FlightOracle.sol @@ -38,7 +38,6 @@ contract FlightOracle is constructor( - address registry, NftId productNftId, string memory componentName, IAuthorization authorization @@ -46,7 +45,6 @@ contract FlightOracle is { address initialOwner = msg.sender; initialize( - registry, productNftId, authorization, initialOwner, @@ -56,7 +54,6 @@ contract FlightOracle is function initialize( - address registry, NftId productNftId, IAuthorization authorization, address initialOwner, @@ -67,7 +64,6 @@ contract FlightOracle is initializer() { _initializeBasicOracle( - registry, productNftId, authorization, initialOwner, diff --git a/contracts/examples/flight/FlightPool.sol b/contracts/examples/flight/FlightPool.sol index 6ef6bbc7c..da6ef8321 100644 --- a/contracts/examples/flight/FlightPool.sol +++ b/contracts/examples/flight/FlightPool.sol @@ -20,7 +20,6 @@ contract FlightPool is BasicPool { constructor( - address registry, NftId productNftId, string memory componentName, IAuthorization authorization @@ -28,7 +27,6 @@ contract FlightPool is { address initialOwner = msg.sender; _intialize( - registry, productNftId, componentName, IComponents.PoolInfo({ @@ -45,7 +43,6 @@ contract FlightPool is } function _intialize( - address registry, NftId productNftId, string memory componentName, IComponents.PoolInfo memory poolInfo, @@ -56,7 +53,6 @@ contract FlightPool is initializer { _initializeBasicPool( - registry, productNftId, componentName, poolInfo, diff --git a/contracts/examples/flight/FlightProduct.sol b/contracts/examples/flight/FlightProduct.sol index 0a600ae3a..cb5dcb520 100644 --- a/contracts/examples/flight/FlightProduct.sol +++ b/contracts/examples/flight/FlightProduct.sol @@ -134,7 +134,6 @@ contract FlightProduct is constructor( - address registry, NftId instanceNftid, string memory componentName, IAuthorization authorization @@ -143,7 +142,6 @@ contract FlightProduct is address initialOwner = msg.sender; _initialize( - registry, instanceNftid, componentName, authorization, @@ -647,7 +645,6 @@ contract FlightProduct is function _initialize( - address registry, NftId instanceNftId, string memory componentName, IAuthorization authorization, @@ -657,7 +654,6 @@ contract FlightProduct is initializer { __Product_init( - registry, instanceNftId, componentName, IComponents.ProductInfo({ diff --git a/contracts/examples/unpermissioned/SimpleDistribution.sol b/contracts/examples/unpermissioned/SimpleDistribution.sol index 127a9f7ec..d241287ce 100644 --- a/contracts/examples/unpermissioned/SimpleDistribution.sol +++ b/contracts/examples/unpermissioned/SimpleDistribution.sol @@ -17,14 +17,12 @@ contract SimpleDistribution is { constructor( - address registry, NftId productNftId, IAuthorization authorization, address initialOwner ) { initialize( - registry, productNftId, authorization, initialOwner, @@ -32,7 +30,6 @@ contract SimpleDistribution is } function initialize( - address registry, NftId productNftId, IAuthorization authorization, address initialOwner, @@ -43,7 +40,6 @@ contract SimpleDistribution is initializer() { _initializeBasicDistribution( - registry, productNftId, authorization, initialOwner, diff --git a/contracts/examples/unpermissioned/SimpleOracle.sol b/contracts/examples/unpermissioned/SimpleOracle.sol index a7bc9ba9c..8616b0de0 100644 --- a/contracts/examples/unpermissioned/SimpleOracle.sol +++ b/contracts/examples/unpermissioned/SimpleOracle.sol @@ -31,14 +31,12 @@ contract SimpleOracle is event LogSimpleOracleSyncResponseSent(RequestId requestId, string responseText); constructor( - address registry, NftId productNftId, IAuthorization authorization, address initialOwner ) { initialize( - registry, productNftId, authorization, initialOwner, @@ -47,7 +45,6 @@ contract SimpleOracle is } function initialize( - address registry, NftId productNftId, IAuthorization authorization, address initialOwner, @@ -58,7 +55,6 @@ contract SimpleOracle is initializer() { _initializeBasicOracle( - registry, productNftId, authorization, initialOwner, diff --git a/contracts/examples/unpermissioned/SimplePool.sol b/contracts/examples/unpermissioned/SimplePool.sol index b1f578cbc..1fd3f4b07 100644 --- a/contracts/examples/unpermissioned/SimplePool.sol +++ b/contracts/examples/unpermissioned/SimplePool.sol @@ -17,7 +17,6 @@ contract SimplePool is { constructor( - address registry, NftId productNftId, IComponents.PoolInfo memory poolInfo, IAuthorization authorization, @@ -25,7 +24,6 @@ contract SimplePool is ) { initialize( - registry, productNftId, poolInfo, authorization, @@ -35,7 +33,6 @@ contract SimplePool is function initialize( - address registry, NftId productNftId, IComponents.PoolInfo memory poolInfo, IAuthorization authorization, @@ -46,7 +43,6 @@ contract SimplePool is initializer() { _initializeBasicPool( - registry, productNftId, "SimplePool", poolInfo, diff --git a/contracts/examples/unpermissioned/SimpleProduct.sol b/contracts/examples/unpermissioned/SimpleProduct.sol index cf62e20cd..d747a9a13 100644 --- a/contracts/examples/unpermissioned/SimpleProduct.sol +++ b/contracts/examples/unpermissioned/SimpleProduct.sol @@ -34,7 +34,6 @@ contract SimpleProduct is IOracleService private _oracleService; constructor( - address registry, NftId instanceNftId, string memory name, IComponents.ProductInfo memory productInfo, @@ -44,7 +43,6 @@ contract SimpleProduct is ) { initialize( - registry, instanceNftId, name, productInfo, @@ -55,7 +53,6 @@ contract SimpleProduct is function initialize( - address registry, NftId instanceNftid, string memory name, IComponents.ProductInfo memory productInfo, @@ -68,7 +65,6 @@ contract SimpleProduct is initializer() { _initializeBasicProduct( - registry, instanceNftid, name, productInfo, diff --git a/contracts/instance/Instance.sol b/contracts/instance/Instance.sol index dc56e220c..e363980f9 100644 --- a/contracts/instance/Instance.sol +++ b/contracts/instance/Instance.sol @@ -26,8 +26,6 @@ contract Instance is IInstance, Registerable { - bool private _initialized; - IComponentService internal _componentService; IInstanceService internal _instanceService; @@ -59,8 +57,6 @@ contract Instance is function initialize( InstanceContracts memory instanceContracts, - IRegistry registry, - VersionPart release, address initialOwner, bool tokenRegistryDisabled // only disable for testing ) @@ -74,9 +70,9 @@ contract Instance is _instanceAdmin = instanceContracts.instanceAdmin; // setup instance object info + IRegistry registry = _getRegistry(); __Registerable_init({ authority: instanceContracts.instanceAdmin.authority(), - registry: address(registry), parentNftId: registry.getNftId(), objectType: INSTANCE(), isInterceptor: false, @@ -93,19 +89,19 @@ contract Instance is // initialize instance supporting contracts _instanceStore.initialize(); _productStore.initialize(); - _bundleSet.initialize(instanceContracts.instanceAdmin.authority(), address(registry)); - _riskSet.initialize(instanceContracts.instanceAdmin.authority(), address(registry)); + _bundleSet.initialize(instanceContracts.instanceAdmin.authority()); + _riskSet.initialize(instanceContracts.instanceAdmin.authority()); _instanceReader.initialize(); _componentService = IComponentService( - getRegistry().getServiceAddress( + registry.getServiceAddress( COMPONENT(), - release)); + getRelease())); _instanceService = IInstanceService( - getRegistry().getServiceAddress( + registry.getServiceAddress( INSTANCE(), - release)); + getRelease())); _tokenRegistryDisabled = tokenRegistryDisabled; diff --git a/contracts/instance/InstanceAdmin.sol b/contracts/instance/InstanceAdmin.sol index f5f316c83..3894dc016 100644 --- a/contracts/instance/InstanceAdmin.sol +++ b/contracts/instance/InstanceAdmin.sol @@ -11,9 +11,10 @@ import {AccessAdminLib} from "../authorization/AccessAdminLib.sol"; import {AccessManagerCloneable} from "../authorization/AccessManagerCloneable.sol"; import {ObjectType, INSTANCE} from "../type/ObjectType.sol"; import {RoleId, ADMIN_ROLE} from "../type/RoleId.sol"; +import {GIF_INITIAL_RELEASE} from "../registry/Registry.sol"; import {Str} from "../type/String.sol"; -import {VersionPart} from "../type/Version.sol"; import {INSTANCE_TARGET_NAME, INSTANCE_ADMIN_TARGET_NAME, INSTANCE_STORE_TARGET_NAME, PRODUCT_STORE_TARGET_NAME, BUNDLE_SET_TARGET_NAME, RISK_SET_TARGET_NAME} from "./TargetNames.sol"; +import {VersionPart} from "../type/Version.sol"; contract InstanceAdmin is @@ -26,13 +27,12 @@ contract InstanceAdmin is error ErrorInstanceAdminNotComponentOrCustomTarget(address target); IInstance internal _instance; - IRegistry internal _registry; uint64 internal _customRoleIdNext; modifier onlyInstanceService() { - if (msg.sender != _registry.getServiceAddress(INSTANCE(), getRelease())) { + if (msg.sender != _getRegistry().getServiceAddress(INSTANCE(), getRelease())) { revert ErrorInstanceAdminNotInstanceService(msg.sender); } _; @@ -43,7 +43,8 @@ contract InstanceAdmin is constructor(address accessManager) { initialize( accessManager, - "MasterInstanceAdmin"); + "MasterInstanceAdmin", + GIF_INITIAL_RELEASE()); } @@ -51,32 +52,23 @@ contract InstanceAdmin is /// Important: Initialization of instance admin is only complete after calling this function. /// Important: The instance MUST be registered and all instance supporting contracts must be wired to this instance. function completeSetup( - address registry, address authorization, - VersionPart release, address instance ) external - reinitializer(uint64(release.toInt())) { // checks - AccessAdminLib.checkIsRegistered(registry, instance, INSTANCE()); + AccessAdminLib.checkIsRegistered(instance, INSTANCE(), getRelease()); // effects - AccessManagerCloneable( - authority()).completeSetup( - registry, - release); - AccessAdminLib.checkAuthorization( address(_authorization), authorization, INSTANCE(), // expectedDomain - release, // expectedRelease + getRelease(), // expectedRelease false, // expectServiceAuthorization true); // checkAlreadyInitialized - _registry = IRegistry(registry); _instance = IInstance(instance); _authorization = IAuthorization(authorization); _customRoleIdNext = 0; @@ -105,7 +97,7 @@ contract InstanceAdmin is for(uint256 i = 0; i < serviceDomains.length; i++) { ObjectType serviceDomain = serviceDomains[i]; RoleId serviceRoleId = authorization.getServiceRole(serviceDomain); - address service = _registry.getServiceAddress(serviceDomain, getRelease()); + address service = _getRegistry().getServiceAddress(serviceDomain, getRelease()); _grantRoleToAccount( serviceRoleId, @@ -134,7 +126,8 @@ contract InstanceAdmin is /// Important: The component MUST be registered. function initializeComponentAuthorization( address componentAddress, - ObjectType expectedType + ObjectType expectedType, + VersionPart expectedRelease ) external restricted() diff --git a/contracts/instance/InstanceAuthorizationV3.sol b/contracts/instance/InstanceAuthorizationV3.sol index 3174aa17f..545c78ce1 100644 --- a/contracts/instance/InstanceAuthorizationV3.sol +++ b/contracts/instance/InstanceAuthorizationV3.sol @@ -13,7 +13,9 @@ import {InstanceStore} from "../instance/InstanceStore.sol"; import {INSTANCE_TARGET_NAME, INSTANCE_ADMIN_TARGET_NAME, INSTANCE_STORE_TARGET_NAME, PRODUCT_STORE_TARGET_NAME, BUNDLE_SET_TARGET_NAME, RISK_SET_TARGET_NAME} from "./TargetNames.sol"; import {ProductStore} from "../instance/ProductStore.sol"; import {ADMIN_ROLE, INSTANCE_OWNER_ROLE, PUBLIC_ROLE} from "../type/RoleId.sol"; -import {RiskSet} from "../instance/RiskSet.sol"; +import {GIF_INITIAL_RELEASE} from "../registry/Registry.sol"; +import {RiskSet} from "../instance/RiskSet.sol"; +import {VersionPartLib} from "../type/Version.sol"; contract InstanceAuthorizationV3 @@ -27,7 +29,7 @@ contract InstanceAuthorizationV3 Authorization( INSTANCE_TARGET_NAME, INSTANCE(), - 3, + GIF_INITIAL_RELEASE(), COMMIT_HASH, TargetType.Instance, false) diff --git a/contracts/instance/InstanceReader.sol b/contracts/instance/InstanceReader.sol index 22c027062..2a39df503 100644 --- a/contracts/instance/InstanceReader.sol +++ b/contracts/instance/InstanceReader.sol @@ -28,6 +28,7 @@ import {NftId} from "../type/NftId.sol"; import {PayoutId, PayoutIdLib} from "../type/PayoutId.sol"; import {PolicyServiceLib} from "../product/PolicyServiceLib.sol"; import {ProductStore} from "./ProductStore.sol"; +import {RegistryLinked} from "../shared/RegistryLinked.sol"; import {ReferralId, ReferralStatus, ReferralLib} from "../type/Referral.sol"; import {RequestId} from "../type/RequestId.sol"; import {RiskId} from "../type/RiskId.sol"; @@ -40,14 +41,19 @@ import {UFixed, UFixedLib} from "../type/UFixed.sol"; /// @dev Central reader contract for a specific instance. /// Provides reading functions for all instance data and related component data. -contract InstanceReader { +contract InstanceReader is + RegistryLinked +{ error ErrorInstanceReaderAlreadyInitialized(); error ErrorInstanceReaderInstanceAddressZero(); - + // TODO make state immutable: + // 1. instance receives reader through setInstanceReader() + // 2. this way instance initialization is not depends on reader + // 3. and reader is simple contract with constructor + // 4. no _initialized in storage, the rest is immutable bool private _initialized = false; - IRegistry internal _registry; IInstance internal _instance; InstanceAdmin internal _instanceAdmin; @@ -78,27 +84,24 @@ contract InstanceReader { _initialized = true; _instance = IInstance(instanceAddress); _instanceAdmin = _instance.getInstanceAdmin(); - _registry = _instance.getRegistry(); _store = _instance.getInstanceStore(); _productStore = _instance.getProductStore(); _bundleSet = _instance.getBundleSet(); _riskSet = _instance.getRiskSet(); - _distributionService = IDistributionService(_registry.getServiceAddress(DISTRIBUTION(), _instance.getRelease())); + + _distributionService = IDistributionService( + _getRegistry().getServiceAddress(DISTRIBUTION(), _instance.getRelease())); } //--- instance functions ---------------------------------------------------------// - /// @dev Returns the registry this instance is registered in. - function getRegistry() public view returns (IRegistry registry) { - return _registry; - } /// @dev Returns the instance NFT ID. function getInstanceNftId() public view returns (NftId instanceNftid) { - return _registry.getNftIdForAddress(address(_instance)); + return _getRegistry().getNftIdForAddress(address(_instance)); } @@ -435,7 +438,7 @@ contract InstanceReader { return _store.getReferralInfo(referralId); } - + // TODO reader dependce on service os wrong? function getDiscountPercentage(ReferralId referralId) public view @@ -444,10 +447,7 @@ contract InstanceReader { ReferralStatus status ) { - return IDistributionService( - _registry.getServiceAddress( - DISTRIBUTION(), - _instance.getRelease())).getDiscountPercentage( + return _distributionService.getDiscountPercentage( this, // instance reader referralId); } diff --git a/contracts/instance/InstanceService.sol b/contracts/instance/InstanceService.sol index e10a641f6..3c01d40c8 100644 --- a/contracts/instance/InstanceService.sol +++ b/contracts/instance/InstanceService.sol @@ -175,7 +175,7 @@ contract InstanceService is IInstance(instanceAddress).getInstanceAdmin().setInstanceLocked(locked); emit LogInstanceServiceInstanceLocked( - getRegistry().getNftIdForAddress(instanceAddress), + _getRegistry().getNftIdForAddress(instanceAddress), locked); } @@ -204,13 +204,11 @@ contract InstanceService is // MUST be set after instance is set up and registered IAuthorization instanceAuthorization = InstanceAdmin(_masterInstanceAdmin).getInstanceAuthorization(); instanceAdmin.completeSetup( - address(getRegistry()), address(instanceAuthorization), - getRelease(), address(instance)); // hard checks for newly cloned instance - assert(address(instance.getRegistry()) == address(getRegistry())); + //assert(address(instance._getRegistry()) == address(_getRegistry()));// consider deleting this assert(instance.getRelease() == getRelease()); // register cloned instance as staking target @@ -231,7 +229,7 @@ contract InstanceService is restricted() onlyInstance() { - NftId instanceNftId = getRegistry().getNftIdForAddress(msg.sender); + NftId instanceNftId = _getRegistry().getNftIdForAddress(msg.sender); _stakingService.setInstanceLockingPeriod( instanceNftId, stakeLockingPeriod); @@ -244,7 +242,7 @@ contract InstanceService is restricted() onlyInstance() { - NftId instanceNftId = getRegistry().getNftIdForAddress(msg.sender); + NftId instanceNftId = _getRegistry().getNftIdForAddress(msg.sender); _stakingService.setInstanceRewardRate( instanceNftId, rewardRate); @@ -256,7 +254,7 @@ contract InstanceService is restricted() onlyInstance() { - NftId instanceNftId = getRegistry().getNftIdForAddress(msg.sender); + NftId instanceNftId = _getRegistry().getNftIdForAddress(msg.sender); _stakingService.setInstanceMaxStakedAmount( instanceNftId, maxStakedAmount); @@ -270,7 +268,7 @@ contract InstanceService is onlyInstance() returns (Amount newBalance) { - NftId instanceNftId = getRegistry().getNftIdForAddress(msg.sender); + NftId instanceNftId = _getRegistry().getNftIdForAddress(msg.sender); newBalance = _stakingService.refillInstanceRewardReserves( instanceNftId, rewardProvider, @@ -285,7 +283,7 @@ contract InstanceService is onlyInstance() returns (Amount newBalance) { - NftId instanceNftId = getRegistry().getNftIdForAddress(msg.sender); + NftId instanceNftId = _getRegistry().getNftIdForAddress(msg.sender); newBalance = _stakingService.withdrawInstanceRewardReserves( instanceNftId, dipAmount); @@ -308,7 +306,7 @@ contract InstanceService is instance.setInstanceReader(upgradedInstanceReaderClone); emit LogInstanceServiceInstanceReaderUpgraded( - getRegistry().getNftIdForAddress(instanceAddress), + _getRegistry().getNftIdForAddress(instanceAddress), address(upgradedInstanceReaderClone)); } @@ -349,6 +347,7 @@ contract InstanceService is if(instanceStoreAddress == address(0)) { revert ErrorInstanceServiceInstanceStoreZero(); } if(productStoreAddress == address(0)) { revert ErrorInstanceServiceProductStoreZero(); } // TODO: rename exception + // TODO check instance cluster release if(instance.authority() != instanceAdmin.authority()) { revert ErrorInstanceServiceInstanceAuthorityMismatch(); } if(bundleSet.authority() != instanceAdmin.authority()) { revert ErrorInstanceServiceBundleSetAuthorityMismatch(); } if(riskSet.authority() != instanceAdmin.authority()) { revert ErrorInstanceServiceRiskSetAuthorityMismatch(); } @@ -391,7 +390,7 @@ contract InstanceService is _masterInstanceReader = instanceReaderAddress; emit LogInstanceServiceMasterInstanceReaderUpgraded( - getRegistry().getNftIdForAddress(_masterInstance), + _getRegistry().getNftIdForAddress(_masterInstance), instanceReaderAddress); } @@ -419,7 +418,8 @@ contract InstanceService is clonedAdmin.initialize( address(clonedAccessManager), - "InstanceAdmin"); + "InstanceAdmin", + getRelease()); } @@ -445,8 +445,6 @@ contract InstanceService is riskSet: RiskSet(Clones.clone(_masterInstanceRiskSet)), instanceReader: InstanceReader(Clones.clone(address(_masterInstanceReader))) }), - getRegistry(), - getRelease(), instanceOwner, allowAnyToken); @@ -461,14 +459,13 @@ contract InstanceService is ) internal virtual override - initializer() + onlyInitializing() { ( - address authority, - address registry - ) = abi.decode(data, (address, address)); + address authority + ) = abi.decode(data, (address)); - __Service_init(authority, registry, owner); + __Service_init(authority, owner); _registryService = IRegistryService(_getServiceAddress(REGISTRY())); _stakingService = IStakingService(_getServiceAddress(STAKING())); @@ -486,7 +483,8 @@ contract InstanceService is virtual view { - IRegistry registry = getRegistry(); + // TODO use ContractLib to verify registration, type and release + IRegistry registry = _getRegistry(); NftId instanceNftId = registry.getNftIdForAddress(instanceAddress); if (instanceNftId.eqz()) { diff --git a/contracts/instance/InstanceServiceManager.sol b/contracts/instance/InstanceServiceManager.sol index 7ab1dbf77..4a954ed12 100644 --- a/contracts/instance/InstanceServiceManager.sol +++ b/contracts/instance/InstanceServiceManager.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; -import {IVersionable} from "../upgradeability/IVersionable.sol"; +import {IUpgradeable} from "../upgradeability/IUpgradeable.sol"; import {ProxyManager} from "../upgradeability/ProxyManager.sol"; import {InstanceService} from "./InstanceService.sol"; @@ -12,19 +12,17 @@ contract InstanceServiceManager is ProxyManager { /// @dev initializes proxy manager with instance service implementation constructor( address authority, - address registry, bytes32 salt ) { InstanceService svc = new InstanceService{salt: salt}(); - bytes memory data = abi.encode(authority, registry); - IVersionable versionable = initialize( - registry, + bytes memory data = abi.encode(authority); + IUpgradeable upgradeable = initialize( address(svc), data, salt); - _instanceService = InstanceService(address(versionable)); + _instanceService = InstanceService(address(upgradeable)); } //--- view functions ----------------------------------------------------// diff --git a/contracts/instance/base/Cloneable.sol b/contracts/instance/base/Cloneable.sol index baf51a8c4..8c3421558 100644 --- a/contracts/instance/base/Cloneable.sol +++ b/contracts/instance/base/Cloneable.sol @@ -4,25 +4,19 @@ pragma solidity ^0.8.20; import {AccessManagedUpgradeable} from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol"; import {IRegistry} from "../../registry/IRegistry.sol"; +import {RegistryLinked} from "../../shared/RegistryLinked.sol"; abstract contract Cloneable is - AccessManagedUpgradeable + AccessManagedUpgradeable, + RegistryLinked { - IRegistry internal _registry; - /// @dev call to initialize MUST be made in the same transaction as cloning of the contract function __Cloneable_init( - address authority, - address registry + address authority ) internal onlyInitializing { __AccessManaged_init(authority); - _registry = IRegistry(registry); - } - - function getRegistry() external view returns (IRegistry) { - return _registry; } } diff --git a/contracts/instance/base/ObjectSet.sol b/contracts/instance/base/ObjectSet.sol index f70129a12..f71d19cf8 100644 --- a/contracts/instance/base/ObjectSet.sol +++ b/contracts/instance/base/ObjectSet.sol @@ -21,12 +21,12 @@ contract ObjectSet is address internal _instanceAddress; /// @dev This initializer needs to be called from the instance itself. - function initialize(address authority, address registry) + function initialize(address authority) external initializer() { _instanceAddress = msg.sender; - __Cloneable_init(authority, registry); + __Cloneable_init(authority); emit LogObjectSetInitialized(address(_instanceAddress)); } diff --git a/contracts/oracle/BasicOracle.sol b/contracts/oracle/BasicOracle.sol index 5a215a898..49b349760 100644 --- a/contracts/oracle/BasicOracle.sol +++ b/contracts/oracle/BasicOracle.sol @@ -23,7 +23,6 @@ contract BasicOracle is } function _initializeBasicOracle( - address registry, NftId instanceNftId, IAuthorization authorization, address initialOwner, @@ -35,7 +34,6 @@ contract BasicOracle is { __Oracle_init( - registry, instanceNftId, authorization, initialOwner, diff --git a/contracts/oracle/BasicOracleAuthorization.sol b/contracts/oracle/BasicOracleAuthorization.sol index d0f6609de..b504435d8 100644 --- a/contracts/oracle/BasicOracleAuthorization.sol +++ b/contracts/oracle/BasicOracleAuthorization.sol @@ -8,6 +8,8 @@ import {IAccess} from "../authorization/IAccess.sol"; import {IOracle} from "./IOracle.sol"; import {PUBLIC_ROLE} from "../../contracts/type/RoleId.sol"; import {RoleId} from "../type/RoleId.sol"; +import {GIF_INITIAL_RELEASE} from "../registry/Registry.sol"; +import {VersionPartLib} from "../type/Version.sol"; contract BasicOracleAuthorization @@ -21,7 +23,7 @@ contract BasicOracleAuthorization Authorization( componentName, ORACLE(), - 3, + GIF_INITIAL_RELEASE(), commitHash, TargetType.Component, false) diff --git a/contracts/oracle/IOracleService.sol b/contracts/oracle/IOracleService.sol index 96f04c28b..7155c294a 100644 --- a/contracts/oracle/IOracleService.sol +++ b/contracts/oracle/IOracleService.sol @@ -18,13 +18,9 @@ interface IOracleService is IService { event LogOracleServiceRequestCancelled(RequestId requestId, NftId requesterNftId); // create request - error ErrorOracleServiceProductMismatch(ObjectType callerObjectType, NftId productNft, NftId oracleParentNftId); error ErrorOracleServiceExpiryInThePast(Timestamp blockTimestamp, Timestamp expiryAt); error ErrorOracleServiceCallbackMethodNameEmpty(); - // respond - error ErrorOracleServiceNotResponsibleOracle(RequestId requestId, NftId expectedOracleNftId, NftId oracleNftId); - // get request info error ErrorOracleServiceRequestStateNotActive(RequestId requestId, StateId state); error ErrorOracleServiceCallerNotResponsibleOracle(RequestId requestId, NftId oracleNftId, NftId callerNftId); diff --git a/contracts/oracle/Oracle.sol b/contracts/oracle/Oracle.sol index 45d5afaa0..f48ac82fa 100644 --- a/contracts/oracle/Oracle.sol +++ b/contracts/oracle/Oracle.sol @@ -5,10 +5,11 @@ import {Amount} from "../type/Amount.sol"; import {COMPONENT, PRODUCT, ORACLE} from "../type/ObjectType.sol"; import {IAuthorization} from "../authorization/IAuthorization.sol"; import {IComponentService} from "../shared/IComponentService.sol"; -import {IInstanceLinkedComponent} from "../shared/IInstanceLinkedComponent.sol"; +import {IComponent} from "../shared/IComponent.sol"; import {IOracleComponent} from "./IOracleComponent.sol"; import {IOracleService} from "./IOracleService.sol"; import {NftId} from "../type/NftId.sol"; +import {Component} from "../shared/Component.sol"; import {InstanceLinkedComponent} from "../shared/InstanceLinkedComponent.sol"; import {RequestId} from "../type/RequestId.sol"; import {Timestamp} from "../type/Timestamp.sol"; @@ -66,7 +67,7 @@ abstract contract Oracle is function withdrawFees(Amount amount) external virtual - override(IInstanceLinkedComponent, InstanceLinkedComponent) + override(IComponent, Component) onlyOwner() restricted() returns (Amount) @@ -76,7 +77,6 @@ abstract contract Oracle is function __Oracle_init( - address registry, NftId productNftId, IAuthorization authorization, address initialOwner, @@ -87,7 +87,6 @@ abstract contract Oracle is onlyInitializing() { __InstanceLinkedComponent_init( - registry, productNftId, name, ORACLE(), diff --git a/contracts/oracle/OracleService.sol b/contracts/oracle/OracleService.sol index 111f50312..1f26557eb 100644 --- a/contracts/oracle/OracleService.sol +++ b/contracts/oracle/OracleService.sol @@ -29,14 +29,13 @@ contract OracleService is ) internal virtual override - initializer() + onlyInitializing() { ( - address authority, - address registry - ) = abi.decode(data, (address, address)); + address authority + ) = abi.decode(data, (address)); - __Service_init(authority, registry, owner); + __Service_init(authority, owner); _registerInterface(type(IOracleService).interfaceId); } @@ -49,25 +48,24 @@ contract OracleService is external virtual restricted() - onlyNftOfType(oracleNftId, ORACLE()) returns (RequestId requestId) { // checks - // get and check active caller - ( - IRegistry.ObjectInfo memory requesterInfo, - address instance - ) = ContractLib.getAndVerifyAnyComponent( - getRegistry(), msg.sender, true); - - ( - NftId requesterNftId, - IOracleComponent oracle - ) = _checkRequestParams( - getRegistry(), oracleNftId, requesterInfo, expiryAt, callbackMethodName); + NftId requesterNftId; // component + IOracleComponent oracle; - // effects { + IInstance instance; + ( + requesterNftId, + oracle, + instance + ) = ContractLib.getAndVerifyComponentAndOracle( + oracleNftId, getRelease()); + + _checkRequestParams(expiryAt, callbackMethodName); + + // effects // create request info IOracle.RequestInfo memory request = IOracle.RequestInfo({ requesterNftId: requesterNftId, @@ -81,7 +79,7 @@ contract OracleService is }); // store request with instance - requestId = IInstance(instance).getInstanceStore().createRequest(request); + requestId = instance.getInstanceStore().createRequest(request); } emit LogOracleServiceRequestCreated(requestId, requesterNftId, oracleNftId, expiryAt); @@ -108,13 +106,11 @@ contract OracleService is returns (bool success) { ( - IRegistry.ObjectInfo memory info, - address instanceAddress + NftId oracleNftId, + IInstance instance ) = ContractLib.getAndVerifyComponent( - getRegistry(), msg.sender, ORACLE(), true); + msg.sender, ORACLE(), getRelease(), true); - NftId oracleNftId = info.nftId; - IInstance instance = IInstance(instanceAddress); bool callerIsOracle = true; IOracle.RequestInfo memory request = _checkAndGetRequestInfo(instance, requestId, oracleNftId, callerIsOracle); request.responseData = responseData; @@ -123,7 +119,7 @@ contract OracleService is instance.getInstanceStore().updateRequest( requestId, request, KEEP_STATE()); - IRegistry.ObjectInfo memory requesterInfo = getRegistry().getObjectInfo( + IRegistry.ObjectInfo memory requesterInfo = _getRegistry().getObjectInfo( request.requesterNftId); string memory functionSignature = string( @@ -156,24 +152,25 @@ contract OracleService is restricted() { ( - IRegistry.ObjectInfo memory info, - address instanceAddress - ) = ContractLib.getAndVerifyAnyComponent( - getRegistry(), msg.sender, true); + // !!! TODO requesterNftId is in request.requesterNftId + // here is responder nft id? + NftId requesterNftId, // component + IInstance instance + ) = ContractLib.getAndVerifyComponent( + msg.sender, COMPONENT(), getRelease(), true); - NftId requesterNftId = info.nftId; - IInstance instance = IInstance(instanceAddress); bool callerIsOracle = false; IOracle.RequestInfo memory request = _checkAndGetRequestInfo(instance, requestId, requesterNftId, callerIsOracle); // attempt to deliver response to requester + address requester = msg.sender; string memory functionSignature = string( abi.encodePacked( request.callbackMethodName, "(uint64,bytes)" )); - (bool success, bytes memory returnData) = info.objectAddress.call( + (bool success, bytes memory returnData) = requester.call( abi.encodeWithSignature( functionSignature, requestId, @@ -184,7 +181,8 @@ contract OracleService is instance.getInstanceStore().updateRequestState(requestId, FULFILLED()); emit LogOracleServiceResponseResent(requestId, requesterNftId); } else { - emit LogOracleServiceDeliveryFailed(requestId, info.objectAddress, functionSignature); + // TODO why requester address instead of nftId? + emit LogOracleServiceDeliveryFailed(requestId, requester, functionSignature); } } @@ -195,13 +193,11 @@ contract OracleService is restricted() { ( - IRegistry.ObjectInfo memory info, - address instanceAddress - ) = ContractLib.getAndVerifyAnyComponent( - getRegistry(), msg.sender, true); + NftId requesterNftId, // component + IInstance instance + ) = ContractLib.getAndVerifyComponent( + msg.sender, COMPONENT(), getRelease(), true); - NftId requesterNftId = info.nftId; - IInstance instance = IInstance(instanceAddress); bool callerIsOracle = false; // TODO property isCancelled and state update to CANCELLED are redundant, get rid of isCancelled IOracle.RequestInfo memory request = _checkAndGetRequestInfo(instance, requestId, requesterNftId, callerIsOracle); @@ -211,7 +207,7 @@ contract OracleService is // call oracle component // TODO add check that oracle is active? - address oracleAddress = getRegistry().getObjectAddress(request.oracleNftId); + address oracleAddress = _getRegistry().getObjectAddress(request.oracleNftId); IOracleComponent(oracleAddress).cancel(requestId); emit LogOracleServiceRequestCancelled(requestId, requesterNftId); @@ -219,39 +215,13 @@ contract OracleService is function _checkRequestParams( - IRegistry registry, - NftId oracleNftId, - IRegistry.ObjectInfo memory requesterInfo, Timestamp expiryAt, string memory callbackMethodName ) internal virtual view - returns ( - NftId requesterNftId, - IOracleComponent oracle - ) { - // get oracle info - (IRegistry.ObjectInfo memory oracleInfo,) = ContractLib.getInfoAndInstance( - registry, oracleNftId, true); - - // obtain return values - requesterNftId = requesterInfo.nftId; - oracle = IOracleComponent(oracleInfo.objectAddress); - - // check that requester and oracle share same product cluster - if (requesterInfo.objectType == PRODUCT()) { - if (oracleInfo.parentNftId != requesterNftId) { - revert ErrorOracleServiceProductMismatch(requesterInfo.objectType, requesterNftId, oracleInfo.parentNftId); - } - } else { - if (oracleInfo.parentNftId != requesterInfo.parentNftId) { - revert ErrorOracleServiceProductMismatch(requesterInfo.objectType, requesterInfo.parentNftId, oracleInfo.parentNftId); - } - } - // check expiriyAt >= now if (expiryAt < TimestampLib.current()) { revert ErrorOracleServiceExpiryInThePast(TimestampLib.current(), expiryAt); diff --git a/contracts/oracle/OracleServiceManager.sol b/contracts/oracle/OracleServiceManager.sol index 108c4f06a..e633e7202 100644 --- a/contracts/oracle/OracleServiceManager.sol +++ b/contracts/oracle/OracleServiceManager.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; -import {IVersionable} from "../upgradeability/IVersionable.sol"; +import {IUpgradeable} from "../upgradeability/IUpgradeable.sol"; import {ProxyManager} from "../upgradeability/ProxyManager.sol"; import {OracleService} from "./OracleService.sol"; @@ -12,19 +12,17 @@ contract OracleServiceManager is ProxyManager { /// @dev initializes proxy manager with service implementation and deploys instance constructor( address authority, - address registry, bytes32 salt ) { OracleService svc = new OracleService{salt: salt}(); - bytes memory data = abi.encode(authority, registry); - IVersionable versionable = initialize( - registry, + bytes memory data = abi.encode(authority); + IUpgradeable upgradeable = initialize( address(svc), data, salt); - _oracleService = OracleService(address(versionable)); + _oracleService = OracleService(address(upgradeable)); } //--- view functions ----------------------------------------------------// diff --git a/contracts/pool/BasicPool.sol b/contracts/pool/BasicPool.sol index cbc74ffc0..83fcf47f5 100644 --- a/contracts/pool/BasicPool.sol +++ b/contracts/pool/BasicPool.sol @@ -18,7 +18,6 @@ abstract contract BasicPool is { function _initializeBasicPool( - address registry, NftId productNftId, string memory name, IComponents.PoolInfo memory poolInfo, @@ -30,7 +29,6 @@ abstract contract BasicPool is onlyInitializing() { __Pool_init( - registry, productNftId, name, poolInfo, @@ -45,8 +43,8 @@ abstract contract BasicPool is public virtual restricted() - onlyBundleOwner(bundleNftId) - onlyNftOfType(bundleNftId, BUNDLE()) + onlyBundleOwner(bundleNftId) // TODO single modifier to check everything about given arbitrary nftId + onlyNftOfType(bundleNftId, BUNDLE()) // TODO service will check this { _stake(bundleNftId, amount); } diff --git a/contracts/pool/BasicPoolAuthorization.sol b/contracts/pool/BasicPoolAuthorization.sol index 8417fa897..a8727dfc3 100644 --- a/contracts/pool/BasicPoolAuthorization.sol +++ b/contracts/pool/BasicPoolAuthorization.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.20; import {IAccess} from "../authorization/IAccess.sol"; -import {IInstanceLinkedComponent} from "../shared/IInstanceLinkedComponent.sol"; +import {IComponent} from "../shared/IComponent.sol"; import {IPoolComponent} from "./IPoolComponent.sol"; import {Authorization} from "../authorization/Authorization.sol"; @@ -10,8 +10,9 @@ import {BasicPool} from "./BasicPool.sol"; import {COMPONENT, POOL} from "../type/ObjectType.sol"; import {PUBLIC_ROLE} from "../../contracts/type/RoleId.sol"; import {RoleId} from "../type/RoleId.sol"; +import {GIF_INITIAL_RELEASE} from "../registry/Registry.sol"; import {TokenHandler} from "../shared/TokenHandler.sol"; - +import {VersionPartLib} from "../type/Version.sol"; contract BasicPoolAuthorization is Authorization @@ -21,7 +22,7 @@ contract BasicPoolAuthorization Authorization( poolName, POOL(), - 3, + GIF_INITIAL_RELEASE(), COMMIT_HASH, TargetType.Component, true) @@ -70,7 +71,7 @@ contract BasicPoolAuthorization _authorize(functions, BasicPool.unstake.selector, "unstake"); _authorize(functions, BasicPool.extend.selector, "extend"); - _authorize(functions, IInstanceLinkedComponent.withdrawFees.selector, "withdrawFees"); + _authorize(functions, IComponent.withdrawFees.selector, "withdrawFees"); _authorize(functions, BasicPool.withdrawBundleFees.selector, "withdrawBundleFees"); // authorize pool service diff --git a/contracts/pool/BundleService.sol b/contracts/pool/BundleService.sol index 6f78e04be..6b61f6f2d 100644 --- a/contracts/pool/BundleService.sol +++ b/contracts/pool/BundleService.sol @@ -12,11 +12,11 @@ import {InstanceStore} from "../instance/InstanceStore.sol"; import {Amount, AmountLib} from "../type/Amount.sol"; import {BundleSet} from "../instance/BundleSet.sol"; +import {ContractLib} from "../shared/ContractLib.sol"; import {Fee} from "../type/Fee.sol"; import {InstanceReader} from "../instance/InstanceReader.sol"; import {NftId, NftIdLib} from "../type/NftId.sol"; import {ObjectType, ACCOUNTING, COMPONENT, POOL, BUNDLE, POLICY, REGISTRY} from "../type/ObjectType.sol"; -import {PoolLib} from "./PoolLib.sol"; import {Seconds} from "../type/Seconds.sol"; import {Service} from "../shared/Service.sol"; import {StateId, ACTIVE, PAUSED, CLOSED, KEEP_STATE} from "../type/StateId.sol"; @@ -41,14 +41,13 @@ contract BundleService is ) internal virtual override - initializer() + onlyInitializing() { ( - address authority, - address registry - ) = abi.decode(data, (address, address)); + address authority + ) = abi.decode(data, (address)); - __Service_init(authority, registry, owner); + __Service_init(authority, owner); _registryService = IRegistryService(_getServiceAddress(REGISTRY())); _accountingService = IAccountingService(_getServiceAddress(ACCOUNTING())); @@ -66,9 +65,12 @@ contract BundleService is virtual restricted() { - _checkNftType(bundleNftId, BUNDLE()); + ( + NftId poolNftId, + IInstance instance + ) = ContractLib.getAndVerifyPoolForBundle( + bundleNftId, getRelease()); - (NftId poolNftId, IInstance instance) = PoolLib.getAndVerifyActivePool(getRegistry(), msg.sender); InstanceReader instanceReader = instance.getInstanceReader(); IBundle.BundleInfo memory bundleInfo = instanceReader.getBundleInfo(bundleNftId); if(bundleInfo.poolNftId.eqz()) { @@ -97,7 +99,10 @@ contract BundleService is restricted() returns(NftId bundleNftId) { - (NftId poolNftId, IInstance instance) = PoolLib.getAndVerifyActivePool(getRegistry(), msg.sender); + ( + NftId poolNftId, + IInstance instance + ) = ContractLib.getAndVerifyPool(getRelease()); // register bundle with registry bundleNftId = _registryService.registerBundle( @@ -105,11 +110,11 @@ contract BundleService is NftIdLib.zero(), poolNftId, BUNDLE(), + getRelease(), false, // intercepting property for bundles is defined on pool - address(0), - owner, - "" // bundle data to be stored in registry - ) + address(0)), + owner, + "" // bundle data to be stored in registry ); // create bundle info in instance @@ -191,9 +196,8 @@ contract BundleService is restricted() { // checks - _checkNftType(bundleNftId, BUNDLE()); - - (, IInstance instance) = PoolLib.getAndVerifyActivePool(getRegistry(), msg.sender); + (, IInstance instance) = ContractLib.getAndVerifyPoolForBundle( + bundleNftId, getRelease()); // effects // update set of active bundles @@ -331,9 +335,12 @@ contract BundleService is returns (Timestamp extendedExpiredAt) { // checks - _checkNftType(bundleNftId, BUNDLE()); + ( + NftId poolNftId, + IInstance instance + ) = ContractLib.getAndVerifyPoolForBundle( + bundleNftId, getRelease()); - (NftId poolNftId, IInstance instance) = PoolLib.getAndVerifyActivePool(getRegistry(), msg.sender); IBundle.BundleInfo memory bundleInfo = instance.getInstanceReader().getBundleInfo(bundleNftId); StateId bundleState = instance.getInstanceReader().getBundleState(bundleNftId); @@ -379,7 +386,6 @@ contract BundleService is emit LogBundleServiceCollateralReleased(bundleNftId, policyNftId, collateralAmount); } - function _getDomain() internal pure override returns(ObjectType) { return BUNDLE(); } diff --git a/contracts/pool/BundleServiceManager.sol b/contracts/pool/BundleServiceManager.sol index c581632ce..12570d4db 100644 --- a/contracts/pool/BundleServiceManager.sol +++ b/contracts/pool/BundleServiceManager.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; -import {IVersionable} from "../upgradeability/IVersionable.sol"; +import {IUpgradeable} from "../upgradeability/IUpgradeable.sol"; import {ProxyManager} from "../upgradeability/ProxyManager.sol"; import {BundleService} from "./BundleService.sol"; @@ -11,20 +11,18 @@ contract BundleServiceManager is ProxyManager { /// @dev initializes proxy manager with pool service implementation constructor( - address authority, - address registry, + address authority, bytes32 salt ) { BundleService svc = new BundleService{salt: salt}(); - bytes memory data = abi.encode(authority, registry); - IVersionable versionable = initialize( - registry, + bytes memory data = abi.encode(authority); + IUpgradeable upgradeable = initialize( address(svc), data, salt); - _bundleService = BundleService(address(versionable)); + _bundleService = BundleService(address(upgradeable)); } //--- view functions ----------------------------------------------------// diff --git a/contracts/pool/IPoolService.sol b/contracts/pool/IPoolService.sol index 4fcd4fb26..7fba6b02e 100644 --- a/contracts/pool/IPoolService.sol +++ b/contracts/pool/IPoolService.sol @@ -18,15 +18,14 @@ interface IPoolService is IService { event LogPoolServiceWalletFunded(NftId poolNftId, address poolOwner, Amount amount); event LogPoolServiceWalletDefunded(NftId poolNftId, address poolOwner, Amount amount); - event LogPoolServiceBundleCreated(NftId instanceNftId, NftId poolNftId, NftId bundleNftId); - event LogPoolServiceBundleClosed(NftId instanceNftId, NftId poolNftId, NftId bundleNftId); + event LogPoolServiceBundleClosed(NftId poolNftId, NftId bundleNftId); - event LogPoolServiceBundleStaked(NftId instanceNftId, NftId poolNftId, NftId bundleNftId, Amount amount, Amount netAmount); - event LogPoolServiceBundleUnstaked(NftId instanceNftId, NftId poolNftId, NftId bundleNftId, Amount amount, Amount netAmount); + event LogPoolServiceBundleStaked(NftId poolNftId, NftId bundleNftId, Amount amount, Amount netAmount); + event LogPoolServiceBundleUnstaked(NftId poolNftId, NftId bundleNftId, Amount amount, Amount netAmount); - event LogPoolServiceFeesWithdrawn(NftId bundleNftId, address recipient, address tokenAddress, Amount amount); + event LogPoolServiceFeesWithdrawn(NftId poolNftId, NftId bundleNftId, address recipient, address tokenAddress, Amount amount); - event LogPoolServiceProcessFundedClaim(NftId policyNftId, ClaimId claimId, Amount availableAmount); + event LogPoolServiceProcessFundedClaim(NftId poolNftId, NftId policyNftId, ClaimId claimId, Amount availableAmount); event LogPoolServiceApplicationVerified(NftId poolNftId, NftId bundleNftId, NftId applicationNftId, Amount totalCollateralAmount); event LogPoolServiceCollateralLocked(NftId poolNftId, NftId bundleNftId, NftId applicationNftId, Amount totalCollateralAmount, Amount lockedCollateralAmount); diff --git a/contracts/pool/Pool.sol b/contracts/pool/Pool.sol index 9624ce216..a3bca4dc0 100644 --- a/contracts/pool/Pool.sol +++ b/contracts/pool/Pool.sol @@ -35,7 +35,7 @@ abstract contract Pool is modifier onlyBundleOwner(NftId bundleNftId) { - if(msg.sender != getRegistry().ownerOf(bundleNftId)) { + if(msg.sender != _getRegistry().ownerOf(bundleNftId)) { revert ErrorPoolNotBundleOwner(bundleNftId, msg.sender); } _; @@ -124,7 +124,6 @@ abstract contract Pool is // Internals function __Pool_init( - address registry, NftId productNftId, string memory name, IComponents.PoolInfo memory poolInfo, @@ -136,7 +135,6 @@ abstract contract Pool is onlyInitializing() { __InstanceLinkedComponent_init( - registry, productNftId, name, POOL(), diff --git a/contracts/pool/PoolLib.sol b/contracts/pool/PoolLib.sol index 09c5583cc..d2b1779b9 100644 --- a/contracts/pool/PoolLib.sol +++ b/contracts/pool/PoolLib.sol @@ -18,6 +18,7 @@ import {ObjectType, BUNDLE, POOL} from "../type/ObjectType.sol"; import {PayoutId} from "../type/PayoutId.sol"; import {TokenHandler} from "../shared/TokenHandler.sol"; import {UFixed} from "../type/UFixed.sol"; +import {VersionPart} from "../type/Version.sol"; library PoolLib { @@ -76,7 +77,6 @@ library PoolLib { function calculateStakingAmounts( - IRegistry registry, InstanceReader instanceReader, NftId poolNftId, Amount stakingAmount @@ -88,7 +88,7 @@ library PoolLib { Amount netStakingAmount ) { - NftId productNftId = registry.getParentNftId(poolNftId); + NftId productNftId = ContractLib.getRegistry().getParentNftId(poolNftId); Fee memory stakingFee = instanceReader.getFeeInfo(productNftId).stakingFee; ( feeAmount, @@ -100,7 +100,6 @@ library PoolLib { function calculatePayoutAmounts( - IRegistry registry, InstanceReader instanceReader, NftId productNftId, NftId policyNftId, @@ -121,7 +120,7 @@ library PoolLib { netPayoutAmount = payoutAmount; if (payoutBeneficiary == address(0)) { - beneficiary = registry.ownerOf(policyNftId); + beneficiary = ContractLib.getRegistry().ownerOf(policyNftId); } else { beneficiary = payoutBeneficiary; } @@ -136,14 +135,13 @@ library PoolLib { function getPolicyHolder( - IRegistry registry, NftId policyNftId ) internal view returns (IPolicyHolder policyHolder) { - address policyHolderAddress = registry.ownerOf(policyNftId); + address policyHolderAddress = ContractLib.getRegistry().ownerOf(policyNftId); policyHolder = IPolicyHolder(policyHolderAddress); if (!ContractLib.isPolicyHolder(policyHolderAddress)) { @@ -151,99 +149,7 @@ library PoolLib { } } - - function checkAndGetPoolInfo( - IRegistry registry, - address sender, - NftId bundleNftId - ) - public - view - returns ( - InstanceReader instanceReader, - InstanceStore instanceStore, - NftId instanceNftId, - NftId poolNftId, - IComponents.PoolInfo memory poolInfo - ) - { - checkNftType(registry, bundleNftId, BUNDLE()); - - IInstance instance; - (poolNftId, instance) = getAndVerifyActivePool(registry, sender); - instanceReader = instance.getInstanceReader(); - instanceStore = instance.getInstanceStore(); - instanceNftId = instance.getNftId(); - poolInfo = instanceReader.getPoolInfo(poolNftId); - - if (registry.getParentNftId(bundleNftId) != poolNftId) { - revert IPoolService.ErrorPoolServiceBundlePoolMismatch(bundleNftId, poolNftId); - } - } - - - function getAndVerifyActivePool( - IRegistry registry, - address sender - ) - public - view - returns ( - NftId poolNftId, - IInstance instance - ) - { - ( - IRegistry.ObjectInfo memory info, - address instanceAddress - ) = ContractLib.getAndVerifyComponent( - registry, - sender, - POOL(), - true); // only active pools - - poolNftId = info.nftId; - instance = IInstance(instanceAddress); - } - - - function getAndVerifyActiveComponent( - IRegistry registry, - address sender, - ObjectType expectedComponentType - ) - public - view - returns ( - NftId componentNftId, - IInstance instance - ) - { - ( - IRegistry.ObjectInfo memory info, - address instanceAddress - ) = ContractLib.getAndVerifyComponent( - registry, - sender, - expectedComponentType, - true); // only active components - - componentNftId = info.nftId; - instance = IInstance(instanceAddress); - } - - function checkNftType( - IRegistry registry, - NftId nftId, - ObjectType expectedObjectType - ) internal view { - if(!registry.isObjectType(nftId, expectedObjectType)) { - revert INftOwnable.ErrorNftOwnableInvalidType(nftId, expectedObjectType); - } - } - function transferTokenAndNotifyPolicyHolder( - IRegistry registry, InstanceReader instanceReader, TokenHandler poolTokenHandler, NftId productNftId, @@ -265,7 +171,6 @@ library PoolLib { processingFeeAmount, beneficiary ) = calculatePayoutAmounts( - registry, instanceReader, productNftId, policyNftId, @@ -287,7 +192,6 @@ library PoolLib { // callback to policy holder if applicable policyHolderPayoutExecuted( - registry, policyNftId, payoutId, beneficiary, @@ -295,7 +199,6 @@ library PoolLib { } function policyHolderPayoutExecuted( - IRegistry registry, NftId policyNftId, PayoutId payoutId, address beneficiary, @@ -303,7 +206,7 @@ library PoolLib { ) private { - IPolicyHolder policyHolder = getPolicyHolder(registry, policyNftId); + IPolicyHolder policyHolder = getPolicyHolder(policyNftId); if(address(policyHolder) != address(0)) { policyHolder.payoutExecuted(policyNftId, payoutId, payoutAmount, beneficiary); } diff --git a/contracts/pool/PoolService.sol b/contracts/pool/PoolService.sol index c3c46a1a6..037d83cfb 100644 --- a/contracts/pool/PoolService.sol +++ b/contracts/pool/PoolService.sol @@ -42,19 +42,18 @@ contract PoolService is ) internal virtual override - initializer() + onlyInitializing() { ( - address authority, - address registry - ) = abi.decode(data, (address, address)); + address authority + ) = abi.decode(data, (address)); - __Service_init(authority, registry, owner); + __Service_init(authority, owner); _accountingService = IAccountingService(_getServiceAddress(ACCOUNTING())); _bundleService = IBundleService(_getServiceAddress(BUNDLE())); _componentService = IComponentService(_getServiceAddress(COMPONENT())); - _staking = IStaking(getRegistry().getStakingAddress()); + _staking = IStaking(_getRegistry().getStakingAddress()); _registerInterface(type(IPoolService).interfaceId); } @@ -66,7 +65,11 @@ contract PoolService is virtual restricted() { - (NftId poolNftId, IInstance instance) = _getAndVerifyActivePool(); + ( + NftId poolNftId, + IInstance instance + ) = ContractLib.getAndVerifyPool(getRelease()); + InstanceReader instanceReader = instance.getInstanceReader(); IComponents.PoolInfo memory poolInfo = instanceReader.getPoolInfo(poolNftId); @@ -78,15 +81,20 @@ contract PoolService is } + // TODO closing bundle here but creating in bundle service function closeBundle(NftId bundleNftId) external restricted() virtual { - _checkNftType(bundleNftId, BUNDLE()); - - (NftId poolNftId, IInstance instance) = _getAndVerifyActivePool(); + // checks + ( + NftId poolNftId, + IInstance instance + ) = ContractLib.getAndVerifyPoolForBundle( + bundleNftId, getRelease()); + // effects // TODO get performance fee for pool (#477) // releasing collateral in bundle @@ -95,15 +103,15 @@ contract PoolService is _accountingService.decreasePoolBalance( instance.getInstanceStore(), poolNftId, - unstakedAmount + feeAmount, + unstakedAmount + feeAmount, AmountLib.zero()); - emit LogPoolServiceBundleClosed(instance.getNftId(), poolNftId, bundleNftId); + emit LogPoolServiceBundleClosed(poolNftId, bundleNftId); - if ((unstakedAmount + feeAmount).gtz()){ - IComponents.ComponentInfo memory poolComponentInfo = instance.getInstanceReader().getComponentInfo(poolNftId); - poolComponentInfo.tokenHandler.pushToken( - getRegistry().ownerOf(bundleNftId), + if ((unstakedAmount + feeAmount).gtz()) { + TokenHandler tokenHandler = instance.getInstanceReader().getTokenHandler(poolNftId); + tokenHandler.pushToken( + _getRegistry().ownerOf(bundleNftId), unstakedAmount + feeAmount); } } @@ -119,56 +127,25 @@ contract PoolService is restricted() virtual { - _checkNftType(policyNftId, POLICY()); + ( + NftId poolNftId, + IInstance instance + ) = ContractLib.getAndVerifyPoolForPolicy( + policyNftId, getRelease()); - (NftId poolNftId, IInstance instance) = _getAndVerifyActivePool(); InstanceReader instanceReader = instance.getInstanceReader(); - NftId productNftId = getRegistry().getParentNftId(poolNftId); - - // check policy matches with calling pool - IPolicy.PolicyInfo memory policyInfo = instanceReader.getPolicyInfo(policyNftId); - if(policyInfo.productNftId != productNftId) { - revert ErrorPoolServicePolicyPoolMismatch( - policyNftId, - policyInfo.productNftId, - productNftId); - } + NftId productNftId = _getRegistry().getParentNftId(poolNftId); - emit LogPoolServiceProcessFundedClaim(policyNftId, claimId, availableAmount); + emit LogPoolServiceProcessFundedClaim(poolNftId, policyNftId, claimId, availableAmount); + // TODO reading the whole struct for just 1 check // callback to product component if applicable if (instanceReader.getProductInfo(productNftId).isProcessingFundedClaims) { - address productAddress = getRegistry().getObjectAddress(productNftId); + address productAddress = _getRegistry().getObjectAddress(productNftId); IProductComponent(productAddress).processFundedClaim(policyNftId, claimId, availableAmount); } } - - // function _checkAndGetPoolInfo(NftId bundleNftId) - // internal - // view - // returns ( - // InstanceReader instanceReader, - // InstanceStore instanceStore, - // NftId instanceNftId, - // NftId poolNftId, - // IComponents.PoolInfo memory poolInfo - // ) - // { - // _checkNftType(bundleNftId, BUNDLE()); - - // (NftId poolNftId, IInstance instance) = _getAndVerifyActivePool(); - // instanceReader = instance.getInstanceReader(); - // instanceStore = instance.getInstanceStore(); - // instanceNftId = instance.getNftId(); - // poolInfo = instanceReader.getPoolInfo(poolNftId); - - // if (getRegistry().getParentNftId(bundleNftId) != poolNftId) { - // revert ErrorPoolServiceBundlePoolMismatch(bundleNftId, poolNftId); - // } - // } - - /// @inheritdoc IPoolService function stake(NftId bundleNftId, Amount amount) external @@ -179,12 +156,14 @@ contract PoolService is ) { ( - InstanceReader instanceReader, - InstanceStore instanceStore, - NftId instanceNftId, - NftId poolNftId, - IComponents.PoolInfo memory poolInfo - ) = PoolLib.checkAndGetPoolInfo(getRegistry(), msg.sender, bundleNftId); + NftId poolNftId, + IInstance instance + ) = ContractLib.getAndVerifyPoolForBundle( + bundleNftId, getRelease()); + + InstanceReader instanceReader = instance.getInstanceReader(); + InstanceStore instanceStore = instance.getInstanceStore(); + IComponents.PoolInfo memory poolInfo = instanceReader.getPoolInfo(poolNftId); { Amount currentPoolBalance = instanceReader.getBalanceAmount(poolNftId); @@ -199,7 +178,6 @@ contract PoolService is feeAmount, netAmount ) = PoolLib.calculateStakingAmounts( - getRegistry(), instanceReader, poolNftId, amount); @@ -213,13 +191,13 @@ contract PoolService is _bundleService.stake(instanceReader, instanceStore, bundleNftId, netAmount); - emit LogPoolServiceBundleStaked(instanceNftId, poolNftId, bundleNftId, amount, netAmount); + emit LogPoolServiceBundleStaked(poolNftId, bundleNftId, amount, netAmount); // only collect staking amount when pool is not externally managed if (!poolInfo.isExternallyManaged) { // collect tokens from bundle owner - address bundleOwner = getRegistry().ownerOf(bundleNftId); + address bundleOwner = _getRegistry().ownerOf(bundleNftId); PoolLib.pullStakingAmount( instanceReader, poolNftId, @@ -237,11 +215,13 @@ contract PoolService is returns(Amount netAmount) { ( - InstanceReader instanceReader, - InstanceStore instanceStore, - NftId instanceNftId, - NftId poolNftId, - ) = PoolLib.checkAndGetPoolInfo(getRegistry(), msg.sender, bundleNftId); + NftId poolNftId, + IInstance instance + ) = ContractLib.getAndVerifyPoolForBundle( + bundleNftId, getRelease()); + + InstanceReader instanceReader = instance.getInstanceReader(); + InstanceStore instanceStore = instance.getInstanceStore(); // call bundle service for bookkeeping and additional checks Amount unstakedAmount = _bundleService.unstake(instanceStore, bundleNftId, amount); @@ -260,13 +240,13 @@ contract PoolService is AmountLib.zero()); - emit LogPoolServiceBundleUnstaked(instanceNftId, poolNftId, bundleNftId, unstakedAmount, netAmount); + emit LogPoolServiceBundleUnstaked(poolNftId, bundleNftId, unstakedAmount, netAmount); // only distribute staking amount when pool is not externally managed if (!instanceReader.getPoolInfo(poolNftId).isExternallyManaged) { // transfer amount to bundle owner - address bundleOwner = getRegistry().ownerOf(bundleNftId); + address bundleOwner = _getRegistry().ownerOf(bundleNftId); PoolLib.pushUnstakingAmount( instanceReader, poolNftId, @@ -284,7 +264,7 @@ contract PoolService is ( NftId poolNftId, IInstance instance - ) = _getAndVerifyActivePool(); + ) = ContractLib.getAndVerifyPool(getRelease()); // check that pool is externally managed InstanceReader reader = instance.getInstanceReader(); @@ -292,7 +272,7 @@ contract PoolService is revert ErrorPoolServicePoolNotExternallyManaged(poolNftId); } - address poolOwner = getRegistry().ownerOf(poolNftId); + address poolOwner = _getRegistry().ownerOf(poolNftId); emit LogPoolServiceWalletFunded(poolNftId, poolOwner, amount); PoolLib.pullStakingAmount( @@ -311,7 +291,7 @@ contract PoolService is ( NftId poolNftId, IInstance instance - ) = _getAndVerifyActivePool(); + ) = ContractLib.getAndVerifyPool(getRelease()); // check that pool is externally managed InstanceReader reader = instance.getInstanceReader(); @@ -319,7 +299,7 @@ contract PoolService is revert ErrorPoolServicePoolNotExternallyManaged(poolNftId); } - address poolOwner = getRegistry().ownerOf(poolNftId); + address poolOwner = _getRegistry().ownerOf(poolNftId); emit LogPoolServiceWalletDefunded(poolNftId, poolOwner, amount); PoolLib.pushUnstakingAmount( @@ -340,10 +320,8 @@ contract PoolService is { _checkNftType(bundleNftId, BUNDLE()); - IRegistry registry = getRegistry(); - NftId poolNftId = registry.getParentNftId(bundleNftId); - (, address instanceAddress) = ContractLib.getInfoAndInstance(registry, poolNftId, true); - IInstance instance = IInstance(instanceAddress); + NftId poolNftId = _getRegistry().getParentNftId(bundleNftId); + (, IInstance instance) = ContractLib.getInfoAndInstance(poolNftId, getRelease(), true); Amount poolFeeAmount = premium.poolFeeFixAmount + premium.poolFeeVarAmount; Amount bundleFeeAmount = premium.bundleFeeFixAmount + premium.bundleFeeVarAmount; @@ -414,7 +392,7 @@ contract PoolService is // pool callback when required if (poolIsVerifyingApplications) { IPoolComponent pool = IPoolComponent( - getRegistry().getObjectAddress(poolNftId)); + _getRegistry().getObjectAddress(poolNftId)); pool.verifyApplication( applicationNftId, @@ -454,7 +432,7 @@ contract PoolService is _checkNftType(policyNftId, POLICY()); // effects - NftId poolNftId = getRegistry().getParentNftId(bundleNftId); + NftId poolNftId = _getRegistry().getParentNftId(bundleNftId); _accountingService.decreasePoolBalance( instanceStore, @@ -484,7 +462,6 @@ contract PoolService is // interactions (netPayoutAmount, processingFeeAmount) = PoolLib.transferTokenAndNotifyPolicyHolder( - getRegistry(), instanceReader, poolTokenHandler, productNftId, @@ -522,9 +499,12 @@ contract PoolService is returns (Amount withdrawnAmount) { // checks - _checkNftType(bundleNftId, BUNDLE()); + ( + NftId poolNftId, + IInstance instance + ) = ContractLib.getAndVerifyPoolForBundle( + bundleNftId, getRelease()); - (NftId poolNftId, IInstance instance) = _getAndVerifyActivePool(); InstanceReader reader = instance.getInstanceReader(); // determine withdrawn amount @@ -550,10 +530,10 @@ contract PoolService is // interactions // transfer amount to bundle owner { - address bundleOwner = getRegistry().ownerOf(bundleNftId); + address bundleOwner = _getRegistry().ownerOf(bundleNftId); TokenHandler tokenHandler = reader.getTokenHandler(poolNftId); address token = address(tokenHandler.TOKEN()); - emit LogPoolServiceFeesWithdrawn(bundleNftId, bundleOwner, token, withdrawnAmount); + emit LogPoolServiceFeesWithdrawn(poolNftId, bundleNftId, bundleOwner, token, withdrawnAmount); tokenHandler.pushToken(bundleOwner, withdrawnAmount); } @@ -594,20 +574,6 @@ contract PoolService is remainingCollateralAmount); } - - function _getAndVerifyActivePool() - internal - virtual - view - returns ( - NftId poolNftId, - IInstance instance - ) - { - return PoolLib.getAndVerifyActivePool(getRegistry(), msg.sender); - } - - function _getDomain() internal pure override returns(ObjectType) { return POOL(); } diff --git a/contracts/pool/PoolServiceManager.sol b/contracts/pool/PoolServiceManager.sol index ef4a316df..6c0a87a3e 100644 --- a/contracts/pool/PoolServiceManager.sol +++ b/contracts/pool/PoolServiceManager.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; -import {IVersionable} from "../upgradeability/IVersionable.sol"; +import {IUpgradeable} from "../upgradeability/IUpgradeable.sol"; import {ProxyManager} from "../upgradeability/ProxyManager.sol"; import {PoolService} from "./PoolService.sol"; @@ -12,19 +12,17 @@ contract PoolServiceManager is ProxyManager { /// @dev initializes proxy manager with pool service implementation constructor( address authority, - address registry, bytes32 salt ) { PoolService poolSrv = new PoolService{salt: salt}(); - bytes memory data = abi.encode(authority, registry); - IVersionable versionable = initialize( - registry, + bytes memory data = abi.encode(authority); + IUpgradeable upgradeable = initialize( address(poolSrv), data, salt); - _poolService = PoolService(address(versionable)); + _poolService = PoolService(address(upgradeable)); } //--- view functions ----------------------------------------------------// diff --git a/contracts/product/ApplicationService.sol b/contracts/product/ApplicationService.sol index 68e9e243f..f9154ac2b 100644 --- a/contracts/product/ApplicationService.sol +++ b/contracts/product/ApplicationService.sol @@ -38,14 +38,13 @@ contract ApplicationService is ) internal virtual override - initializer() + onlyInitializing() { ( - address authority, - address registry - ) = abi.decode(data, (address, address)); + address authority + ) = abi.decode(data, (address)); - __Service_init(authority, registry, owner); + __Service_init(authority, owner); _distributionService = IDistributionService(_getServiceAddress(DISTRIBUTION())); _pricingService = IPricingService(_getServiceAddress(PRICE())); @@ -54,7 +53,9 @@ contract ApplicationService is _registerInterface(type(IApplicationService).interfaceId); } - + // TODO product - bundle - risk - refferal - distribution + // checkBundle() is faster then checking with registry but first need to know poolNftId + // check pool, get its nftIdf and instance -> instacne.getBundleSet.checkBundle(bundsleNftId) ???? function _checkLinkedApplicationParameters( InstanceReader instanceReader, NftId productNftId, @@ -108,12 +109,11 @@ contract ApplicationService is NftIdLib.zero(), productNftId, POLICY(), + getRelease(), false, // intercepting property for policies is defined on product - address(0), - applicationOwner, - ""); + address(0)); - applicationNftId = _registryService.registerPolicy(objectInfo); + applicationNftId = _registryService.registerPolicy(objectInfo, applicationOwner, ""); } @@ -155,7 +155,7 @@ contract ApplicationService is { _checkNftType(bundleNftId, BUNDLE()); - (NftId productNftId, IInstance instance) = _getAndVerifyActiveProduct(); + (NftId productNftId, IInstance instance) = ContractLib.getAndVerifyProduct(getRelease()); // check if provided references are valid and linked to calling product contract InstanceReader instanceReader = instance.getInstanceReader(); @@ -290,36 +290,15 @@ contract ApplicationService is restricted() nonReentrant() { - _checkNftType(applicationNftId, POLICY()); + (, IInstance instance) = ContractLib.getAndVerifyProductForPolicy( + applicationNftId, getRelease()); - (, IInstance instance) = _getAndVerifyActiveProduct(); instance.getProductStore().updateApplicationState(applicationNftId, REVOKED()); emit LogApplicationServiceApplicationRevoked(applicationNftId); } // internal functions - function _getAndVerifyActiveProduct() - internal - view - returns ( - NftId productNftId, - IInstance instance - ) - { - ( - IRegistry.ObjectInfo memory info, - address instanceAddress - ) = ContractLib.getAndVerifyComponent( - getRegistry(), - msg.sender, - PRODUCT(), - true); // only active pools - - productNftId = info.nftId; - instance = IInstance(instanceAddress); - } - function _getDomain() internal pure override returns(ObjectType) { return APPLICATION(); diff --git a/contracts/product/ApplicationServiceManager.sol b/contracts/product/ApplicationServiceManager.sol index fcaf7bbf5..62d762526 100644 --- a/contracts/product/ApplicationServiceManager.sol +++ b/contracts/product/ApplicationServiceManager.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; -import {IVersionable} from "../upgradeability/IVersionable.sol"; +import {IUpgradeable} from "../upgradeability/IUpgradeable.sol"; import {ProxyManager} from "../upgradeability/ProxyManager.sol"; import {ApplicationService} from "./ApplicationService.sol"; @@ -12,19 +12,17 @@ contract ApplicationServiceManager is ProxyManager { /// @dev initializes proxy manager with service implementation constructor( address authority, - address registry, bytes32 salt ) { ApplicationService svc = new ApplicationService{salt: salt}(); - bytes memory data = abi.encode(authority, registry); - IVersionable versionable = initialize( - registry, + bytes memory data = abi.encode(authority); + IUpgradeable upgradeable = initialize( address(svc), data, salt); - _applicationService = ApplicationService(address(versionable)); + _applicationService = ApplicationService(address(upgradeable)); } //--- view functions ----------------------------------------------------// diff --git a/contracts/product/BasicProduct.sol b/contracts/product/BasicProduct.sol index 11c826cdd..394c6046f 100644 --- a/contracts/product/BasicProduct.sol +++ b/contracts/product/BasicProduct.sol @@ -24,7 +24,6 @@ abstract contract BasicProduct is } function _initializeBasicProduct( - address registry, NftId instanceNftId, string memory name, IComponents.ProductInfo memory productInfo, @@ -37,7 +36,6 @@ abstract contract BasicProduct is onlyInitializing() { __Product_init( - registry, instanceNftId, name, productInfo, diff --git a/contracts/product/BasicProductAuthorization.sol b/contracts/product/BasicProductAuthorization.sol index 016d2fa64..71e5d559c 100644 --- a/contracts/product/BasicProductAuthorization.sol +++ b/contracts/product/BasicProductAuthorization.sol @@ -2,15 +2,16 @@ pragma solidity ^0.8.20; import {IAccess} from "../authorization/IAccess.sol"; -import {IInstanceLinkedComponent} from "../shared/IInstanceLinkedComponent.sol"; +import {IComponent} from "../shared/IComponent.sol"; import {IProductComponent} from "./IProductComponent.sol"; import {Authorization} from "../authorization/Authorization.sol"; import {BasicProduct} from "./BasicProduct.sol"; import {COMPONENT, ORACLE, PRODUCT, POLICY} from "../type/ObjectType.sol"; import {RoleId, PUBLIC_ROLE} from "../type/RoleId.sol"; +import {GIF_INITIAL_RELEASE} from "../registry/Registry.sol"; import {TokenHandler} from "../shared/TokenHandler.sol"; - +import {VersionPartLib} from "../type/Version.sol"; contract BasicProductAuthorization is Authorization @@ -19,7 +20,7 @@ contract BasicProductAuthorization Authorization( componentName, PRODUCT(), - 3, + GIF_INITIAL_RELEASE(), COMMIT_HASH, TargetType.Component, true) @@ -58,7 +59,7 @@ contract BasicProductAuthorization functions = _authorizeForTarget(getMainTargetName(), PUBLIC_ROLE()); _authorize(functions, BasicProduct.setFees.selector, "setFees"); _authorize(functions, IProductComponent.registerComponent.selector, "registerComponent"); - _authorize(functions, IInstanceLinkedComponent.withdrawFees.selector, "withdrawFees"); + _authorize(functions, IComponent.withdrawFees.selector, "withdrawFees"); } } diff --git a/contracts/product/ClaimService.sol b/contracts/product/ClaimService.sol index 7cfa40f8f..ee189a0f7 100644 --- a/contracts/product/ClaimService.sol +++ b/contracts/product/ClaimService.sol @@ -39,17 +39,16 @@ contract ClaimService is ) internal virtual override - initializer() + onlyInitializing() { ( - address authority, - address registry - ) = abi.decode(data, (address, address)); + address authority + ) = abi.decode(data, (address)); - __Service_init(authority, registry, owner); + __Service_init(authority, owner); - _policyService = IPolicyService(getRegistry().getServiceAddress(POLICY(), getVersion().toMajorPart())); - _poolService = IPoolService(getRegistry().getServiceAddress(POOL(), getVersion().toMajorPart())); + _policyService = IPolicyService(_getRegistry().getServiceAddress(POLICY(), getVersion().toMajorPart())); + _poolService = IPoolService(_getRegistry().getServiceAddress(POOL(), getVersion().toMajorPart())); _registerInterface(type(IClaimService).interfaceId); } @@ -478,7 +477,7 @@ contract ClaimService is uint24 payoutNo = claimInfo.payoutsCount + 1; payoutId = PayoutIdLib.toPayoutId(claimId, payoutNo); if (beneficiary == address(0)) { - beneficiary = getRegistry().ownerOf(policyNftId); + beneficiary = _getRegistry().ownerOf(policyNftId); } instanceContracts.productStore.createPayout( @@ -515,7 +514,7 @@ contract ClaimService is IPolicy.PolicyInfo memory policyInfo ) { - (productNftId, instance) = _getAndVerifyActiveProduct(); + (productNftId, instance) = ContractLib.getAndVerifyProduct(getRelease()); instanceContracts.instanceReader = InstanceReader(instance.getInstanceReader()); instanceContracts.instanceStore = InstanceStore(instance.getInstanceStore()); instanceContracts.productStore = ProductStore(instance.getProductStore()); @@ -529,29 +528,6 @@ contract ClaimService is } } - - function _getAndVerifyActiveProduct() - internal - view - returns ( - NftId productNftId, - IInstance instance - ) - { - ( - IRegistry.ObjectInfo memory info, - address instanceAddress - ) = ContractLib.getAndVerifyComponent( - getRegistry(), - msg.sender, // caller - PRODUCT(), - true); // isActive - - // get component nft id and instance - productNftId = info.nftId; - instance = IInstance(instanceAddress); - } - function _verifyClaim( InstanceReader instanceReader, NftId policyNftId, @@ -586,7 +562,7 @@ contract ClaimService is { NftId poolNftId = instanceReader.getProductInfo(productNftId).poolNftId; if (instanceReader.getPoolInfo(poolNftId).isProcessingConfirmedClaims) { - address poolAddress = getRegistry().getObjectAddress(poolNftId); + address poolAddress = _getRegistry().getObjectAddress(poolNftId); IPoolComponent(poolAddress).processConfirmedClaim(policyNftId, claimId, amount); } } @@ -611,7 +587,7 @@ contract ClaimService is view returns (IPolicyHolder policyHolder) { - address policyHolderAddress = getRegistry().ownerOf(policyNftId); + address policyHolderAddress = _getRegistry().ownerOf(policyNftId); policyHolder = IPolicyHolder(policyHolderAddress); if (!ContractLib.isPolicyHolder(policyHolderAddress)) { diff --git a/contracts/product/ClaimServiceManager.sol b/contracts/product/ClaimServiceManager.sol index b54f69a46..b06bc7a3a 100644 --- a/contracts/product/ClaimServiceManager.sol +++ b/contracts/product/ClaimServiceManager.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; -import {IVersionable} from "../upgradeability/IVersionable.sol"; +import {IUpgradeable} from "../upgradeability/IUpgradeable.sol"; import {ProxyManager} from "../upgradeability/ProxyManager.sol"; import {ClaimService} from "./ClaimService.sol"; @@ -11,20 +11,18 @@ contract ClaimServiceManager is ProxyManager { /// @dev initializes proxy manager with service implementation constructor( - address authority, - address registry, + address authority, bytes32 salt ) { ClaimService svc = new ClaimService{salt: salt}(); - bytes memory data = abi.encode(authority, registry); - IVersionable versionable = initialize( - registry, + bytes memory data = abi.encode(authority); + IUpgradeable upgradeable = initialize( address(svc), data, salt); - _claimService = ClaimService(address(versionable)); + _claimService = ClaimService(address(upgradeable)); } //--- view functions ----------------------------------------------------// diff --git a/contracts/product/IPolicyService.sol b/contracts/product/IPolicyService.sol index 1ecddab7f..ca0fb16ac 100644 --- a/contracts/product/IPolicyService.sol +++ b/contracts/product/IPolicyService.sol @@ -20,7 +20,6 @@ interface IPolicyService is IService { event LogPolicyServicePolicyClosed(NftId policyNftId); error LogPolicyServiceMaxPremiumAmountExceeded(NftId policyNftId, Amount maxPremiumAmount, Amount premiumAmount); - error ErrorPolicyServicePolicyProductMismatch(NftId applicationNftId, NftId expectedProductNftId, NftId actualProductNftId); error ErrorPolicyServicePolicyStateNotApplied(NftId applicationNftId); error ErrorPolicyServicePolicyStateNotCollateralized(NftId applicationNftId); error ErrorPolicyServicePolicyAlreadyActivated(NftId policyNftId); diff --git a/contracts/product/PolicyService.sol b/contracts/product/PolicyService.sol index d3db85340..0452b09dd 100644 --- a/contracts/product/PolicyService.sol +++ b/contracts/product/PolicyService.sol @@ -45,21 +45,20 @@ contract PolicyService is ) internal virtual override - initializer + onlyInitializing() { ( - address authority, - address registry - ) = abi.decode(data, (address, address)); + address authority + ) = abi.decode(data, (address)); - __Service_init(authority, registry, owner); + __Service_init(authority, owner); VersionPart majorVersion = getVersion().toMajorPart(); - _accountingService = IAccountingService(getRegistry().getServiceAddress(ACCOUNTING(), majorVersion)); - _componentService = IComponentService(getRegistry().getServiceAddress(COMPONENT(), majorVersion)); - _poolService = IPoolService(getRegistry().getServiceAddress(POOL(), majorVersion)); - _distributionService = IDistributionService(getRegistry().getServiceAddress(DISTRIBUTION(), majorVersion)); - _pricingService = IPricingService(getRegistry().getServiceAddress(PRICE(), majorVersion)); + _accountingService = IAccountingService(_getRegistry().getServiceAddress(ACCOUNTING(), majorVersion)); + _componentService = IComponentService(_getRegistry().getServiceAddress(COMPONENT(), majorVersion)); + _poolService = IPoolService(_getRegistry().getServiceAddress(POOL(), majorVersion)); + _distributionService = IDistributionService(_getRegistry().getServiceAddress(DISTRIBUTION(), majorVersion)); + _pricingService = IPricingService(_getRegistry().getServiceAddress(PRICE(), majorVersion)); _registerInterface(type(IPolicyService).interfaceId); } @@ -74,7 +73,8 @@ contract PolicyService is nonReentrant() { // checks - (IInstance instance,,) = _getAndVerifyCallerForPolicy(applicationNftId); + (, IInstance instance) = ContractLib.getAndVerifyProductForPolicy( + applicationNftId, getRelease()); // check policy is in state applied if (instance.getInstanceReader().getPolicyState(applicationNftId) != APPLIED()) { @@ -105,10 +105,10 @@ contract PolicyService is { // checks ( - IInstance instance, NftId productNftId, - IPolicy.PolicyInfo memory applicationInfo - ) = _getAndVerifyCallerForPolicy(applicationNftId); + IPolicy.PolicyInfo memory applicationInfo, + IInstance instance + ) = _getAndVerifyCallerAndInfoForPolicy(applicationNftId); // check policy is in state applied InstanceReader instanceReader = instance.getInstanceReader(); @@ -173,7 +173,7 @@ contract PolicyService is } // link policy to risk and bundle - NftId poolNftId = getRegistry().getParentNftId(bundleNftId); + NftId poolNftId = _getRegistry().getParentNftId(bundleNftId); instance.getRiskSet().linkPolicy(productNftId, riskId, applicationNftId); instance.getBundleSet().linkPolicy(poolNftId, bundleNftId, applicationNftId); @@ -198,10 +198,10 @@ contract PolicyService is { // checks ( - IInstance instance, NftId productNftId, - IPolicy.PolicyInfo memory policyInfo - ) = _getAndVerifyCallerForPolicy(policyNftId); + IPolicy.PolicyInfo memory policyInfo, + IInstance instance + ) = _getAndVerifyCallerAndInfoForPolicy(policyNftId); // check policy is in state collateralized InstanceReader instanceReader = instance.getInstanceReader(); @@ -218,7 +218,7 @@ contract PolicyService is IPolicy.PremiumInfo memory premium = instanceReader.getPremiumInfo(policyNftId); instanceReader.getTokenHandler( productNftId).checkBalanceAndAllowance( - getRegistry().ownerOf(policyNftId), + _getRegistry().ownerOf(policyNftId), premium.premiumAmount, false); @@ -226,7 +226,7 @@ contract PolicyService is // _checkPremiumBalanceAndAllowance( // tokenHandler.TOKEN(), // address(tokenHandler), - // getRegistry().ownerOf(policyNftId), + // _getRegistry().ownerOf(policyNftId), // premium.premiumAmount); // effects @@ -263,9 +263,10 @@ contract PolicyService is { // checks ( - IInstance instance,, - IPolicy.PolicyInfo memory policyInfo - ) = _getAndVerifyCallerForPolicy(policyNftId); + , // NftId productNftId, + IPolicy.PolicyInfo memory policyInfo, + IInstance instance + ) = _getAndVerifyCallerAndInfoForPolicy(policyNftId); // effects policyInfo = PolicyServiceLib.activate(policyNftId, policyInfo, activateAt); @@ -291,9 +292,10 @@ contract PolicyService is { // checks ( - IInstance instance,, - IPolicy.PolicyInfo memory policyInfo - ) = _getAndVerifyCallerForPolicy(policyNftId); + , // NftId productNftId, + IPolicy.PolicyInfo memory policyInfo, + IInstance instance + ) = _getAndVerifyCallerAndInfoForPolicy(policyNftId); if (policyInfo.activatedAt.eqz()) { revert ErrorPolicyServicePolicyNotActivated(policyNftId); @@ -333,9 +335,10 @@ contract PolicyService is { // checks ( - IInstance instance,, - IPolicy.PolicyInfo memory policyInfo - ) = _getAndVerifyCallerForPolicy(policyNftId); + , // NftId productNftId, + IPolicy.PolicyInfo memory policyInfo, + IInstance instance + ) = _getAndVerifyCallerAndInfoForPolicy(policyNftId); // more checks, effects + interactions return _expire( @@ -385,10 +388,10 @@ contract PolicyService is { // checks ( - IInstance instance, NftId productNftId, - IPolicy.PolicyInfo memory policyInfo - ) = _getAndVerifyCallerForPolicy(policyNftId); + IPolicy.PolicyInfo memory policyInfo, + IInstance instance + ) = _getAndVerifyCallerAndInfoForPolicy(policyNftId); InstanceReader instanceReader = instance.getInstanceReader(); // check policy is in a closeable state @@ -418,7 +421,7 @@ contract PolicyService is instance.getProductStore().updatePolicy(policyNftId, policyInfo, CLOSED()); // unlink policy from risk and bundle - NftId poolNftId = getRegistry().getParentNftId(bundleNftId); + NftId poolNftId = _getRegistry().getParentNftId(bundleNftId); instance.getRiskSet().unlinkPolicy(productNftId, riskId, policyNftId); instance.getBundleSet().unlinkPolicy(poolNftId, bundleNftId, policyNftId); @@ -500,7 +503,7 @@ contract PolicyService is internal virtual { - address policyHolder = getRegistry().ownerOf(policyNftId); + address policyHolder = _getRegistry().ownerOf(policyNftId); ( , @@ -574,7 +577,7 @@ contract PolicyService is view returns (IPolicyHolder policyHolder) { - address policyHolderAddress = getRegistry().ownerOf(policyNftId); + address policyHolderAddress = _getRegistry().ownerOf(policyNftId); policyHolder = IPolicyHolder(policyHolderAddress); if (!ContractLib.isPolicyHolder(policyHolderAddress)) { @@ -606,36 +609,20 @@ contract PolicyService is } } - - function _getAndVerifyCallerForPolicy(NftId policyNftId) + function _getAndVerifyCallerAndInfoForPolicy(NftId policyNftId) internal virtual view returns ( - IInstance instance, NftId productNftId, - IPolicy.PolicyInfo memory policyInfo + IPolicy.PolicyInfo memory policyInfo, + IInstance instance ) { - ( - IRegistry.ObjectInfo memory productInfo, - address instanceAddress - ) = ContractLib.getAndVerifyComponent( - getRegistry(), - msg.sender, // caller contract - PRODUCT(), // caller must be product - true); // only active caller - - productNftId = productInfo.nftId; // calling product nft id - instance = IInstance(instanceAddress); - policyInfo = instance.getInstanceReader().getPolicyInfo(policyNftId); + (productNftId, instance) = ContractLib.getAndVerifyProductForPolicy( + policyNftId, getRelease()); - if (policyInfo.productNftId != productNftId) { - revert ErrorPolicyServicePolicyProductMismatch( - policyNftId, - productNftId, - policyInfo.productNftId); - } + policyInfo = instance.getInstanceReader().getPolicyInfo(policyNftId); } diff --git a/contracts/product/PolicyServiceManager.sol b/contracts/product/PolicyServiceManager.sol index 93693b1de..5531d7919 100644 --- a/contracts/product/PolicyServiceManager.sol +++ b/contracts/product/PolicyServiceManager.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; -import {IVersionable} from "../upgradeability/IVersionable.sol"; +import {IUpgradeable} from "../upgradeability/IUpgradeable.sol"; import {ProxyManager} from "../upgradeability/ProxyManager.sol"; import {PolicyService} from "./PolicyService.sol"; @@ -12,19 +12,17 @@ contract PolicyServiceManager is ProxyManager { /// @dev initializes proxy manager with product service implementation constructor( address authority, - address registry, bytes32 salt ) { PolicyService svc = new PolicyService{salt: salt}(); - bytes memory data = abi.encode(authority, registry); - IVersionable versionable = initialize( - registry, + bytes memory data = abi.encode(authority); + IUpgradeable upgradeable = initialize( address(svc), data, salt); - _policyService = PolicyService(address(versionable)); + _policyService = PolicyService(address(upgradeable)); } //--- view functions ----------------------------------------------------// diff --git a/contracts/product/PricingService.sol b/contracts/product/PricingService.sol index fc0f7dfd4..7146e942f 100644 --- a/contracts/product/PricingService.sol +++ b/contracts/product/PricingService.sol @@ -36,14 +36,13 @@ contract PricingService is ) internal virtual override - initializer() + onlyInitializing() { ( - address authority, - address registry - ) = abi.decode(data, (address, address)); + address authority + ) = abi.decode(data, (address)); - __Service_init(authority, registry, owner); + __Service_init(authority, owner); _distributionService = IDistributionService(_getServiceAddress(DISTRIBUTION())); @@ -78,11 +77,11 @@ contract PricingService is // verify product ( IRegistry.ObjectInfo memory registryInfo, - address instanceAddress - ) = ContractLib.getInfoAndInstance(getRegistry(), productNftId, false); + IInstance instance + ) = ContractLib.getInfoAndInstance(productNftId, getRelease(), false); // get instance reader from local instance variable - reader = IInstance(instanceAddress).getInstanceReader(); + reader = instance.getInstanceReader(); NftId riskProductNftId = reader.getRiskInfo(riskId).productNftId; if (productNftId != riskProductNftId) { diff --git a/contracts/product/PricingServiceManager.sol b/contracts/product/PricingServiceManager.sol index c5ab63ec1..60f1644b9 100644 --- a/contracts/product/PricingServiceManager.sol +++ b/contracts/product/PricingServiceManager.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; -import {IVersionable} from "../upgradeability/IVersionable.sol"; +import {IUpgradeable} from "../upgradeability/IUpgradeable.sol"; import {ProxyManager} from "../upgradeability/ProxyManager.sol"; import {PricingService} from "./PricingService.sol"; @@ -12,19 +12,17 @@ contract PricingServiceManager is ProxyManager { /// @dev initializes proxy manager with pricing service implementation and deploys instance constructor( address authority, - address registry, bytes32 salt ) { PricingService pricingSrv = new PricingService{salt: salt}(); - bytes memory data = abi.encode(authority, registry); - IVersionable versionable = initialize( - registry, + bytes memory data = abi.encode(authority); + IUpgradeable upgradeable = initialize( address(pricingSrv), data, salt); - _pricingService = PricingService(address(versionable)); + _pricingService = PricingService(address(upgradeable)); } //--- view functions ----------------------------------------------------// diff --git a/contracts/product/Product.sol b/contracts/product/Product.sol index 4a7382e07..333fe89dc 100644 --- a/contracts/product/Product.sol +++ b/contracts/product/Product.sol @@ -134,7 +134,6 @@ abstract contract Product is function __Product_init( - address registry, NftId instanceNftId, string memory name, IComponents.ProductInfo memory productInfo, @@ -147,7 +146,6 @@ abstract contract Product is onlyInitializing() { __InstanceLinkedComponent_init( - registry, instanceNftId, name, PRODUCT(), diff --git a/contracts/product/RiskService.sol b/contracts/product/RiskService.sol index fb8bb65e4..e56350084 100644 --- a/contracts/product/RiskService.sol +++ b/contracts/product/RiskService.sol @@ -26,15 +26,14 @@ contract RiskService is bytes memory data ) internal - initializer virtual override + onlyInitializing() { ( - address authority, - address registry - ) = abi.decode(data, (address, address)); + address authority + ) = abi.decode(data, (address)); - __Service_init(authority, registry, owner); + __Service_init(authority, owner); _registerInterface(type(IRiskService).interfaceId); } @@ -49,7 +48,7 @@ contract RiskService is returns (RiskId riskId) { // checks - (NftId productNftId, IInstance instance) = _getAndVerifyActiveComponent(PRODUCT()); + (NftId productNftId, IInstance instance) = ContractLib.getAndVerifyProduct(getRelease()); // effects riskId = RiskIdLib.toRiskId(productNftId, id); @@ -80,7 +79,7 @@ contract RiskService is restricted() { // checks - (NftId productNftId, IInstance instance) = _getAndVerifyActiveComponent(PRODUCT()); + (NftId productNftId, IInstance instance) = ContractLib.getAndVerifyProduct(getRelease()); // effects InstanceReader instanceReader = instance.getInstanceReader(); @@ -107,7 +106,7 @@ contract RiskService is restricted() { // checks - (NftId productNftId, IInstance instance) = _getAndVerifyActiveComponent(PRODUCT()); + (NftId productNftId, IInstance instance) = ContractLib.getAndVerifyProduct(getRelease()); if (!instance.getRiskSet().hasRisk(productNftId, riskId)) { revert ErrorRiskServiceUnknownRisk(productNftId, riskId); @@ -135,7 +134,7 @@ contract RiskService is restricted() { // checks - (NftId productNftId, IInstance instance) = _getAndVerifyActiveComponent(PRODUCT()); + (NftId productNftId, IInstance instance) = ContractLib.getAndVerifyProduct(getRelease()); (bool exists, bool active) = instance.getRiskSet().checkRisk(productNftId, riskId); if (!exists) { @@ -152,37 +151,6 @@ contract RiskService is emit LogRiskServiceRiskClosed(productNftId, riskId); } - function _getAndVerifyActiveComponent(ObjectType expectedType) - internal - view - returns ( - NftId componentNftId, - IInstance instance - ) - { - IRegistry.ObjectInfo memory info; - address instanceAddress; - bool isActive = true; - - if (expectedType != COMPONENT()) { - (info, instanceAddress) = ContractLib.getAndVerifyComponent( - getRegistry(), - msg.sender, // caller - expectedType, - isActive); - } else { - (info, instanceAddress) = ContractLib.getAndVerifyAnyComponent( - getRegistry(), - msg.sender, - isActive); - } - - // get component nft id and instance - componentNftId = info.nftId; - instance = IInstance(instanceAddress); - } - - function _getDomain() internal pure override returns(ObjectType) { return RISK(); } diff --git a/contracts/product/RiskServiceManager.sol b/contracts/product/RiskServiceManager.sol index d3485b6ba..e0130b063 100644 --- a/contracts/product/RiskServiceManager.sol +++ b/contracts/product/RiskServiceManager.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; -import {IVersionable} from "../upgradeability/IVersionable.sol"; +import {IUpgradeable} from "../upgradeability/IUpgradeable.sol"; import {ProxyManager} from "../upgradeability/ProxyManager.sol"; import {RiskService} from "./RiskService.sol"; @@ -12,19 +12,17 @@ contract RiskServiceManager is ProxyManager { /// @dev initializes proxy manager with product service implementation constructor( address authority, - address registry, bytes32 salt ) { RiskService svc = new RiskService{salt: salt}(); - bytes memory data = abi.encode(authority, registry); - IVersionable versionable = initialize( - registry, + bytes memory data = abi.encode(authority); + IUpgradeable upgradeable = initialize( address(svc), data, salt); - _riskService = RiskService(address(versionable)); + _riskService = RiskService(address(upgradeable)); } //--- view functions ----------------------------------------------------// diff --git a/contracts/registry/IRegistry.sol b/contracts/registry/IRegistry.sol index 5e0d629e6..f04b7847e 100644 --- a/contracts/registry/IRegistry.sol +++ b/contracts/registry/IRegistry.sol @@ -19,8 +19,8 @@ interface IRegistry is IERC165 { - event LogRegistryObjectRegistered(NftId nftId, NftId parentNftId, ObjectType objectType, bool isInterceptor, address objectAddress, address initialOwner); - event LogRegistryServiceRegistered(VersionPart majorVersion, ObjectType domain); + event LogRegistryObjectRegistered(NftId nftId, NftId parentNftId, ObjectType objectType, VersionPart objectVersion, bool isInterceptor, address objectAddress, address initialOwner); + event LogRegistryServiceRegistered(VersionPart release, ObjectType domain); event LogRegistryChainRegistryRegistered(NftId nftId, uint256 chainId, address chainRegistryAddress); // initialize @@ -49,6 +49,7 @@ interface IRegistry is error ErrorRegistryCoreTypeRegistration(); // _register() + error ErrorRegistryReleaseMismatch(VersionPart objectrelease, VersionPart parentRelease, VersionPart senderRelease); error ErrorRegistryGlobalRegistryAsParent(address objectAddress, ObjectType objectType); error ErrorRegistryTypeCombinationInvalid(address objectAddress, ObjectType objectType, ObjectType parentType); error ErrorRegistryContractAlreadyRegistered(address objectAddress); @@ -58,13 +59,10 @@ interface IRegistry is NftId nftId; NftId parentNftId; ObjectType objectType; + VersionPart release; bool isInterceptor; // slot 1 address objectAddress; - // slot 2 - address initialOwner; - // slot 3 - bytes data; } /// @dev Registers a registry contract for a specified chain. @@ -72,28 +70,30 @@ interface IRegistry is function registerRegistry( NftId nftId, uint256 chainId, - address chainRegistryAddress + address chainRegistryAddress, + VersionPart release ) external; /// @dev Register a service with using the provided domain and version. /// The function returns a newly minted service NFT ID. /// May only be used to register services. function registerService( - ObjectInfo memory serviceInfo, - VersionPart serviceVersion, - ObjectType serviceDomain + ObjectInfo memory info, + address initialOwner, + ObjectType domain, + bytes memory data ) external returns(NftId nftId); /// @dev Register an object with a known core type. /// The function returns a newly minted object NFT ID. /// May not be used to register services. - function register(ObjectInfo memory info) external returns (NftId nftId); + function register(ObjectInfo memory info, address initialOwner, bytes memory data) external returns (NftId nftId); /// @dev Register an object with a custom type. /// The function returns a newly minted object NFT ID. /// This function is reserved for GIF releases > 3. /// May not be used to register known core types. - function registerWithCustomType(ObjectInfo memory info) external returns (NftId nftId); + function registerWithCustomType(ObjectInfo memory info, address initialOwner, bytes memory data) external returns (NftId nftId); function getInitialRelease() external view returns (VersionPart); @@ -126,9 +126,15 @@ interface IRegistry is function getParentNftId(NftId nftId) external view returns (NftId parentNftId); - function isObjectType(NftId nftId, ObjectType expectedObjectType) external view returns (bool); + function getObjectData(NftId nftId) external view returns (bytes memory data); - function isObjectType(address contractAddress, ObjectType expectedObjectType) external view returns (bool); + function getObjectData(address objectAddress) external view returns (bytes memory data); + + function isObjectType(NftId nftId, ObjectType expectedObjectType, VersionPart expectedRelease) external view returns (bool); + + function isObjectType(address contractAddress, ObjectType expectedObjectType, VersionPart expectedRelease) external view returns (bool); + + function getObjectRelease(NftId nftId) external view returns (VersionPart release); function getObjectAddress(NftId nftId) external view returns (address objectAddress); diff --git a/contracts/registry/IRegistryService.sol b/contracts/registry/IRegistryService.sol index 2f2b029b7..92cae312e 100644 --- a/contracts/registry/IRegistryService.sol +++ b/contracts/registry/IRegistryService.sol @@ -19,13 +19,12 @@ interface IRegistryService is { error ErrorRegistryServiceNotRegistryOwner(); - error ErrorRegistryServiceNotService(address notService); - error ErrorRegistryServiceNotInstance(address notInstance); - error ErrorRegistryServiceNotProduct(address notProduct); - error ErrorRegistryServiceNotComponent(address notComponent); - error ErrorRegistryServiceNotProductLinkedComponent(address notProductLinkedComponent); + // _checkInterface() + error ErrorRegistryServiceNotContract(address notContract); + error ErrorRegistryServiceInterfaceNotSupported(address registerable, bytes4 interfaceId); error ErrorRegistryServiceRegisterableAddressInvalid(IRegisterable registerable, address found); + error ErrorRegistryServiceRegisterableParentInvalid(IRegisterable registerable, NftId expected, NftId found); error ErrorRegistryServiceRegisterableTypeInvalid(IRegisterable registerable, ObjectType expected, ObjectType found); error ErrorRegistryServiceRegisterableOwnerInvalid(IRegisterable registerable, address expected, address found); error ErrorRegistryServiceRegisterableOwnerZero(IRegisterable registerable); @@ -40,23 +39,20 @@ interface IRegistryService is error ErrorRegistryServiceInvalidInitialOwner(address initialOwner); error ErrorRegistryServiceInvalidAddress(address registerableAddress); - function registerStake(IRegistry.ObjectInfo memory info) + function registerStake(IRegistry.ObjectInfo memory info, address initialOwner, bytes memory data) external returns(NftId nftId); - function registerInstance(IRegisterable instance, address owner) + function registerInstance(IRegisterable instance, address initialOwner) external returns(IRegistry.ObjectInfo memory info); - function registerProduct(IComponent product, address owner) + function registerComponent(IRegisterable component, NftId parenNftId, ObjectType componentType, address initialOwner) external returns(IRegistry.ObjectInfo memory info); - function registerProductLinkedComponent(IComponent component, ObjectType objectType, address owner) - external returns(IRegistry.ObjectInfo memory info); - - function registerDistributor(IRegistry.ObjectInfo memory info) external returns(NftId nftId); + function registerDistributor(IRegistry.ObjectInfo memory info, address initialOwner, bytes memory data) external returns(NftId nftId); - function registerPolicy(IRegistry.ObjectInfo memory info) external returns(NftId nftId); + function registerPolicy(IRegistry.ObjectInfo memory info, address initialOwner, bytes memory data) external returns(NftId nftId); - function registerBundle(IRegistry.ObjectInfo memory info) external returns(NftId nftId); + function registerBundle(IRegistry.ObjectInfo memory info, address initialOwner, bytes memory data) external returns(NftId nftId); } diff --git a/contracts/registry/IRelease.sol b/contracts/registry/IRelease.sol index 371f90a23..d6777511a 100644 --- a/contracts/registry/IRelease.sol +++ b/contracts/registry/IRelease.sol @@ -23,7 +23,4 @@ interface IRelease { bytes32 salt; } - /// @dev Registers a registry contract for a specified chain. - /// Only one chain registry may be registered per chain - function getRelease() external view returns (VersionPart release); } \ No newline at end of file diff --git a/contracts/registry/Registry.sol b/contracts/registry/Registry.sol index d50f860de..e63a37440 100644 --- a/contracts/registry/Registry.sol +++ b/contracts/registry/Registry.sol @@ -18,6 +18,8 @@ import {IStaking} from "../staking/IStaking.sol"; import {ReleaseRegistry} from "./ReleaseRegistry.sol"; import {TokenRegistry} from "./TokenRegistry.sol"; import {RegistryAdmin} from "./RegistryAdmin.sol"; +import {Versionable} from "../shared/Versionable.sol"; +import {VersionLib, Version} from "../type/Version.sol"; /// @dev IMPORTANT // Each NFT minted by registry is accosiated with: @@ -31,20 +33,27 @@ import {RegistryAdmin} from "./RegistryAdmin.sol"; // 5) registerRegistry() -> registers IRegistry address (from different chain) by GifAdmin. Works ONLY on mainnet. // Note: getters by address MUST not be used with this address (will return 0 or data related to different object or even revert) + +function GIF_INITIAL_RELEASE() pure returns (VersionPart) { + return VersionPartLib.toVersionPart(3); +} + + /// @dev Chain Registry contract implementing IRegistry. /// IRegistry for method details. contract Registry is Initializable, AccessManaged, + Versionable, IRegistry { /// @dev Protocol NFT ID NftId public immutable PROTOCOL_NFT_ID; - /// @dev Gobal registry NFT ID + /// @dev Global registry NFT ID NftId public immutable GLOBAL_REGISTRY_NFT_ID; - /// @dev Gobal registry address on mainnet. + /// @dev Global registry address on mainnet. address public immutable GLOBAL_REGISTRY_ADDRESS; /// @dev Registry NFT ID @@ -68,8 +77,9 @@ contract Registry is mapping(uint256 chainId => NftId registryNftId) private _registryNftIdByChainId; uint256[] private _chainId; - /// @dev keep track of object info and address reverse lookup + /// @dev keep track of object info, data and address reverse lookup mapping(NftId nftId => ObjectInfo info) private _info; + mapping(NftId nftId => bytes data) private _data; mapping(address object => NftId nftId) private _nftIdByAddress; /// @dev keep track of service addresses by version and domain @@ -146,7 +156,8 @@ contract Registry is function registerRegistry( NftId nftId, uint256 chainId, - address registryAddress + address registryAddress, + VersionPart release ) external restricted() @@ -180,20 +191,19 @@ contract Registry is nftId: nftId, parentNftId: REGISTRY_NFT_ID, objectType: REGISTRY(), + release: release, isInterceptor: false, - objectAddress: registryAddress, - initialOwner: NFT_LOCK_ADDRESS, - data: "" - }), + objectAddress: registryAddress}), false); // do not update address lookup for objects on a different chain } // TODO limit service owner to registry admin? /// @inheritdoc IRegistry function registerService( - ObjectInfo memory info, - VersionPart version, - ObjectType domain + ObjectInfo memory info, + address initialOwner, + ObjectType domain, + bytes memory data ) external restricted() @@ -206,12 +216,13 @@ contract Registry is } // version is defined - if(version.eqz()) { + VersionPart release = info.release; + if(release.eqz()) { revert ErrorRegistryServiceVersionZero(service); } // service domain is defined if(domain.eqz()) { - revert ErrorRegistryServiceDomainZero(service, version); + revert ErrorRegistryServiceDomainZero(service, release); } // service has proper type @@ -221,30 +232,31 @@ contract Registry is // service parent has registry type if(info.parentNftId != REGISTRY_NFT_ID) { - revert ErrorRegistryServiceParentNotRegistry(service, version, info.parentNftId); + revert ErrorRegistryServiceParentNotRegistry(service, release, info.parentNftId); } // service has not already been registered - if(_service[version][domain] != address(0)) { - revert ErrorRegistryServiceDomainAlreadyRegistered(service, version, domain); + if(_service[release][domain] != address(0)) { + revert ErrorRegistryServiceDomainAlreadyRegistered(service, release, domain); } - _service[version][domain] = service; + _service[release][domain] = service; - emit LogRegistryServiceRegistered(version, domain); + emit LogRegistryServiceRegistered(release, domain); - nftId = _register(info); + nftId = _register(info, initialOwner, data); } /// @inheritdoc IRegistry - function register(ObjectInfo memory info) + function register(ObjectInfo memory info, address initialOwner, bytes memory data) external restricted() returns(NftId nftId) { address objectAddress = info.objectAddress; ObjectType objectType = info.objectType; + VersionPart parentRelease = _info[info.parentNftId].release; // specialized functions have to be used to register registries and services if(objectType == REGISTRY() || objectType == STAKING() || objectType == SERVICE()) { @@ -268,18 +280,21 @@ contract Registry is } } - nftId = _register(info); + _checkRelease(info.release, parentRelease, parentType); + + nftId = _register(info, initialOwner, data); } /// @inheritdoc IRegistry - function registerWithCustomType(ObjectInfo memory info) + function registerWithCustomType(ObjectInfo memory info, address initialOwner, bytes memory data) external restricted() returns(NftId nftId) { ObjectType objectType = info.objectType; ObjectType parentType = _info[info.parentNftId].objectType; + VersionPart parentRelease = _info[info.parentNftId].release; if(_coreTypes[objectType]) { revert ErrorRegistryCoreTypeRegistration(); @@ -295,13 +310,36 @@ contract Registry is revert ErrorRegistryTypeCombinationInvalid(info.objectAddress, objectType, parentType); } - nftId = _register(info); + _checkRelease(info.release, parentRelease, parentType); + + nftId = _register(info, initialOwner, data); } + function _checkRelease( + VersionPart objectRelease, + VersionPart parentRelease, + ObjectType parentType + ) internal view + { + VersionPart senderRelease = _info[_nftIdByAddress[msg.sender]].release; + + // assume: + // 1) only address with role can reach this function -> caller is registered registry service + // 2) locked registry service can not call registry -> no "caller is locked" check is needed + if(parentType == PROTOCOL()) { + // STAKING for PROTOCOL, parent release is 0 + if(senderRelease != objectRelease) { + revert ErrorRegistryReleaseMismatch(objectRelease, parentRelease, senderRelease); + } + } + else if(senderRelease != objectRelease || senderRelease != parentRelease) { + revert ErrorRegistryReleaseMismatch(objectRelease, parentRelease, senderRelease); + } + } /// @dev earliest GIF major version function getInitialRelease() external view returns (VersionPart) { - return VersionPartLib.toVersionPart(_releaseRegistry.INITIAL_GIF_VERSION()); + return GIF_INITIAL_RELEASE(); } /// @dev next GIF release version to be released @@ -366,13 +404,20 @@ contract Registry is return _info[nftId].parentNftId; } - function isObjectType(address contractAddress, ObjectType expectedObjectType) external view returns (bool) { + function isObjectType(address contractAddress, ObjectType expectedObjectType, VersionPart release) external view returns (bool) { NftId nftId = _nftIdByAddress[contractAddress]; - return isObjectType(nftId, expectedObjectType); + return isObjectType(nftId, expectedObjectType, release); } - function isObjectType(NftId nftId, ObjectType expectedObjectType) public view returns (bool) { - return _info[nftId].objectType == expectedObjectType; + function isObjectType(NftId nftId, ObjectType expectedObjectType, VersionPart release) public view returns (bool) { + return ( + _info[nftId].objectType == expectedObjectType && + _info[nftId].release == release + ); + } + + function getObjectRelease(NftId nftId) external view returns (VersionPart release) { + return _info[nftId].release; } function getObjectAddress(NftId nftId) external view returns (address) { @@ -383,6 +428,14 @@ contract Registry is return _info[_nftIdByAddress[object]]; } + function getObjectData(NftId nftId) external view returns (bytes memory data) { + return _data[nftId]; + } + + function getObjectData(address objectAddress) external view returns (bytes memory data) { + return _data[_nftIdByAddress[objectAddress]]; + } + function isRegistered(NftId nftId) public view returns (bool) { return _info[nftId].objectType.gtz(); } @@ -441,6 +494,12 @@ contract Registry is return ownerOf(address(this)); } + // Versionable + + function getVersion() public pure override returns (Version) { + return VersionLib.toVersion(GIF_INITIAL_RELEASE().toInt(), 0 , 0); + } + // IERC165 function supportsInterface(bytes4 interfaceId) external pure returns (bool) { @@ -454,62 +513,49 @@ contract Registry is // Internals /// @dev registry protects only against tampering existing records, registering with invalid types pairs and 0 parent address - function _register(ObjectInfo memory info) + function _register(ObjectInfo memory info, address initialOwner, bytes memory data) internal returns(NftId nftId) { - ObjectType objectType = info.objectType; // do not care here, never PROTOCOL(), REGISTRY() - bool isInterceptor = info.isInterceptor; - address objectAddress = info.objectAddress; // do not care here, can be 0 - address owner = info.initialOwner; // do not care here, can be 0, can be equal info.objectAddress - NftId parentNftId = info.parentNftId; // do not care here, can not be 0 ObjectInfo memory parentInfo = _info[parentNftId]; - address parentAddress = parentInfo.objectAddress; // can be 0 - - // parent is contract -> need to check? -> check before minting - // special case: staking: to protocol possible as well - // NO LONGER TRUE: special case: global registry nft as parent when not on mainnet -> global registry address is 0 - // special case: when parentNftId == CHAIN_NFT.mint(), check for zero parent address before mint - // special case: when parentNftId == CHAIN_NFT.mint() && objectAddress == initialOwner - // Parent can have 0 address in case of STAKE for PROTOCOL / CUSTOM_TYPE for POLICY - // But it MUST be registered -> parentType != 0 && parentNftId != 0 - /*if(objectType != STAKE()) { - if(parentAddress == address(0)) { - revert ErrorRegistryParentAddressZero(); - } - }*/ // global registry is never parent when not on mainnet if(block.chainid != 1) { if(parentNftId == GLOBAL_REGISTRY_NFT_ID) { - revert ErrorRegistryGlobalRegistryAsParent(objectAddress, objectType); + revert ErrorRegistryGlobalRegistryAsParent(info.objectAddress, info.objectType); } } address interceptorAddress = _getInterceptor( - isInterceptor, - objectType, - objectAddress, + info.isInterceptor, + info.objectType, + info.objectAddress, parentInfo.isInterceptor, - parentAddress); + parentInfo.objectAddress); + + uint256 tokenId = CHAIN_NFT.mint( + initialOwner, + interceptorAddress, + EMPTY_URI); - uint256 tokenId = CHAIN_NFT.getNextTokenId(); nftId = NftIdLib.toNftId(tokenId); info.nftId = nftId; _info[nftId] = info; - _setAddressForNftId(nftId, objectAddress); - - emit LogRegistryObjectRegistered(nftId, parentNftId, objectType, isInterceptor, objectAddress, owner); - - // calls nft receiver(1) and interceptor(2) - uint256 mintedTokenId = CHAIN_NFT.mint( - owner, - interceptorAddress, - EMPTY_URI); + if(data.length > 0) { + _data[nftId] = data; + } + _setAddressForNftId(nftId, info.objectAddress); - assert(mintedTokenId == tokenId); + emit LogRegistryObjectRegistered( + nftId, + parentNftId, + info.objectType, + info.release, + info.isInterceptor, + info.objectAddress, + initialOwner); } /// @dev obtain interceptor address for this nft if applicable, address(0) otherwise @@ -561,10 +607,10 @@ contract Registry is nftId: protocolNftId, parentNftId: NftIdLib.zero(), objectType: PROTOCOL(), + release: VersionPartLib.toVersionPart(0), isInterceptor: false, - objectAddress: address(0), - initialOwner: NFT_LOCK_ADDRESS, - data: ""}), + objectAddress: address(0)}), + NFT_LOCK_ADDRESS, // initial owner of protocol true); } @@ -584,10 +630,9 @@ contract Registry is nftId: GLOBAL_REGISTRY_NFT_ID, parentNftId: PROTOCOL_NFT_ID, objectType: REGISTRY(), + release: getRelease(), isInterceptor: false, - objectAddress: GLOBAL_REGISTRY_ADDRESS, - initialOwner: NFT_LOCK_ADDRESS, - data: ""}), + objectAddress: GLOBAL_REGISTRY_ADDRESS}), block.chainid == 1);// update address lookup for global registry only on mainnet // if not on mainnet: register this registry with global registry as parent @@ -603,10 +648,9 @@ contract Registry is nftId: registryNftId, parentNftId: GLOBAL_REGISTRY_NFT_ID, objectType: REGISTRY(), + release: getRelease(), isInterceptor: false, - objectAddress: address(this), - initialOwner: NFT_LOCK_ADDRESS, - data: ""}), + objectAddress: address(this)}), true); } } @@ -630,6 +674,7 @@ contract Registry is // register the registry info _registerForNft( info, + NFT_LOCK_ADDRESS, // initial owner of any registry updateAddressLookup); } @@ -647,10 +692,10 @@ contract Registry is nftId: stakingNftId, parentNftId: REGISTRY_NFT_ID, objectType: STAKING(), + release: VersionPartLib.toVersionPart(3), isInterceptor: false, - objectAddress: _stakingAddress, - initialOwner: stakingOwner, - data: ""}), + objectAddress: _stakingAddress}), + stakingOwner, true); IStaking(_stakingAddress).initializeTokenHandler(); @@ -658,7 +703,8 @@ contract Registry is /// @dev Register the provided object info for the specified NFT ID. function _registerForNft( - ObjectInfo memory info, + ObjectInfo memory info, + address initialOwner, bool updateAddressLookup ) internal @@ -670,7 +716,7 @@ contract Registry is } // calls nft receiver - CHAIN_NFT.mint(info.initialOwner, info.nftId.toInt()); + CHAIN_NFT.mint(initialOwner, info.nftId.toInt()); } function _setAddressForNftId(NftId nftId, address objectAddress) diff --git a/contracts/registry/RegistryAdmin.sol b/contracts/registry/RegistryAdmin.sol index 499c5ed8d..41589161c 100644 --- a/contracts/registry/RegistryAdmin.sol +++ b/contracts/registry/RegistryAdmin.sol @@ -11,8 +11,8 @@ import {AccessAdminLib} from "../authorization/AccessAdminLib.sol"; import {AccessManagerCloneable} from "../authorization/AccessManagerCloneable.sol"; import {ObjectType, REGISTRY} from "../type/ObjectType.sol"; import {RoleId, RoleIdLib, GIF_MANAGER_ROLE, GIF_ADMIN_ROLE} from "../type/RoleId.sol"; +import {GIF_INITIAL_RELEASE} from "../registry/Registry.sol"; import {Str} from "../type/String.sol"; -import {VersionPart} from "../type/Version.sol"; /* 1) GIF_MANAGER_ROLE @@ -52,7 +52,6 @@ contract RegistryAdmin is // completeSetup error ErrorRegistryAdminNotRegistry(address registry); - address internal _registry; address private _releaseRegistry; address private _tokenRegistry; address private _staking; @@ -62,49 +61,40 @@ contract RegistryAdmin is constructor() { initialize( address(new AccessManagerCloneable()), - "RegistryAdmin"); + "RegistryAdmin", + GIF_INITIAL_RELEASE()); } function completeSetup( - address registry, address authorization, - VersionPart release, address gifAdmin, address gifManager ) public virtual - reinitializer(type(uint8).max) { // checks - AccessAdminLib.checkRegistry(registry); - - AccessManagerCloneable( - authority()).completeSetup( - registry, - release); - AccessAdminLib.checkAuthorization( address(_authorization), authorization, REGISTRY(), - release, + getRelease(), false, // expectServiceAuthorization false); // checkAlreadyInitialized); - - _registry = registry; + + // effects _authorization = IAuthorization(authorization); - IRegistry registryContract = IRegistry(registry); - _releaseRegistry = registryContract.getReleaseRegistryAddress(); - _tokenRegistry = registryContract.getTokenRegistryAddress(); - _staking = registryContract.getStakingAddress(); + IRegistry registry = _getRegistry(); + _releaseRegistry = registry.getReleaseRegistryAddress(); + _tokenRegistry = registry.getTokenRegistryAddress(); + _staking = registry.getStakingAddress(); _stakingTargetHandler = address(IStaking(_staking).getTargetHandler()); _stakingStore = address(IStaking(_staking).getStakingStore()); // link nft ownability to registry - _linkToNftOwnable(_registry); + _linkToNftOwnable(address(_getRegistry())); _createRoles(_authorization); @@ -149,7 +139,7 @@ contract RegistryAdmin is internal { // create unchecked registry targets - _createTarget(_registry, registryTargetName, TargetType.Core, false); + _createTarget(address(_getRegistry()), registryTargetName, TargetType.Core, false); _createTarget(address(this), REGISTRY_ADMIN_TARGET_NAME, TargetType.Core, false); _createTarget(_releaseRegistry, RELEASE_REGISTRY_TARGET_NAME, TargetType.Core, false); _createTarget(_tokenRegistry, TOKEN_REGISTRY_TARGET_NAME, TargetType.Core, false); diff --git a/contracts/registry/RegistryAuthorization.sol b/contracts/registry/RegistryAuthorization.sol index d8c4c9945..33d5aa575 100644 --- a/contracts/registry/RegistryAuthorization.sol +++ b/contracts/registry/RegistryAuthorization.sol @@ -12,6 +12,7 @@ import {PUBLIC_ROLE} from "../type/RoleId.sol"; import {ReleaseRegistry} from "./ReleaseRegistry.sol"; import {RegistryAdmin} from "./RegistryAdmin.sol"; import {RoleIdLib, ADMIN_ROLE, GIF_ADMIN_ROLE, GIF_MANAGER_ROLE} from "../type/RoleId.sol"; +import {GIF_INITIAL_RELEASE} from "../registry/Registry.sol"; import {StakingStore} from "../staking/StakingStore.sol"; import {TargetHandler} from "../staking/TargetHandler.sol"; import {TokenHandler} from "../shared/TokenHandler.sol"; @@ -49,7 +50,7 @@ contract RegistryAuthorization Authorization( REGISTRY_TARGET_NAME, REGISTRY(), - 3, + GIF_INITIAL_RELEASE(), commitHash, TargetType.Core, false) // includeTokenHandler @@ -100,7 +101,7 @@ contract RegistryAuthorization AccessAdminLib.roleInfo( ADMIN_ROLE(), TargetType.Custom, // custom is only type that allows role removal - 2, // TODO decide on max member count + 1, // TODO decide on max member count GIF_ADMIN_ROLE_NAME)); // gif manager role @@ -109,7 +110,7 @@ contract RegistryAuthorization AccessAdminLib.roleInfo( ADMIN_ROLE(), TargetType.Custom, // custom is only type that allows role removal - 1, // TODO decide on max member count + 2, // TODO decide on max member count GIF_MANAGER_ROLE_NAME)); } diff --git a/contracts/registry/RegistryService.sol b/contracts/registry/RegistryService.sol index 07115fa0e..4952e6a8a 100644 --- a/contracts/registry/RegistryService.sol +++ b/contracts/registry/RegistryService.sol @@ -1,16 +1,18 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; -import {IComponent} from "../../contracts/shared/IComponent.sol"; import {IDistributionComponent} from "../../contracts/distribution/IDistributionComponent.sol"; import {IInstance} from "../instance/IInstance.sol"; +import {IInstanceLinkedComponent} from "../../contracts/shared/IInstanceLinkedComponent.sol"; import {IPoolComponent} from "../../contracts/pool/IPoolComponent.sol"; import {IProductComponent} from "../../contracts/product/IProductComponent.sol"; import {IRegisterable} from "../../contracts/shared/IRegisterable.sol"; import {IRegistry} from "./IRegistry.sol"; import {IRegistryService} from "./IRegistryService.sol"; +import {IStaking} from "../../contracts/staking/IStaking.sol"; -import {ObjectType, REGISTRY, SERVICE, PRODUCT, ORACLE, POOL, INSTANCE, COMPONENT, DISTRIBUTION, DISTRIBUTOR, APPLICATION, POLICY, CLAIM, BUNDLE, STAKE, STAKING, PRICE} from "../../contracts/type/ObjectType.sol"; +import {ContractLib} from "../shared/ContractLib.sol"; +import {ObjectType, REGISTRY, SERVICE, PRODUCT, ORACLE, POOL, INSTANCE, COMPONENT, DISTRIBUTION, DISTRIBUTOR, POLICY, BUNDLE, STAKE, STAKING} from "../../contracts/type/ObjectType.sol"; import {NftId, NftIdLib} from "../../contracts/type/NftId.sol"; import {Service} from "../shared/Service.sol"; @@ -21,8 +23,6 @@ contract RegistryService is // TODO update to real hash when registry is stable bytes32 public constant REGISTRY_CREATION_CODE_HASH = bytes32(0); - // from Versionable - /// @dev top level initializer function _initialize( address owner, @@ -33,16 +33,15 @@ contract RegistryService is onlyInitializing { ( - address authority, - address registry - ) = abi.decode(data, (address, address)); + address authority + ) = abi.decode(data, (address)); - __Service_init(authority, registry, owner); + __Service_init(authority, owner); _registerInterface(type(IRegistryService).interfaceId); } - - function registerStaking(IRegisterable staking, address owner) + // TODO register have no combos with STAKING; decide on parentNftId arg + function registerStaking(IRegisterable staking, address expectedOwner) external virtual restricted() @@ -50,12 +49,16 @@ contract RegistryService is IRegistry.ObjectInfo memory info ) { - info = _getAndVerifyContractInfo(staking, STAKING(), owner); - info.nftId = getRegistry().register(info); + _checkInterface(staking, type(IStaking).interfaceId); + + address owner; + bytes memory data; + (info, owner, data) = _getAndVerifyContractInfo(staking, NftIdLib.zero(), STAKING(), expectedOwner); + info.nftId = _getRegistry().register(info, owner, data); } - function registerInstance(IRegisterable instance, address owner) + function registerInstance(IRegisterable instance, address expectedOwner) external virtual restricted() @@ -63,19 +66,21 @@ contract RegistryService is IRegistry.ObjectInfo memory info ) { - if(!instance.supportsInterface(type(IInstance).interfaceId)) { - revert ErrorRegistryServiceNotInstance(address(instance)); - } + _checkInterface(instance, type(IInstance).interfaceId); - info = _getAndVerifyContractInfo(instance, INSTANCE(), owner); - info.nftId = getRegistry().register(info); + address owner; + bytes memory data; + (info, owner, data) = _getAndVerifyContractInfo(instance, _getRegistry().getNftId(), INSTANCE(), expectedOwner); + info.nftId = _getRegistry().register(info, owner, data); instance.linkToRegisteredNftId(); // asume safe } - function registerProduct( - IComponent product, - address initialOwner + function registerComponent( + IRegisterable component, + NftId expectedParentNftId, + ObjectType expectedType, + address expectedOwner ) external virtual @@ -84,83 +89,75 @@ contract RegistryService is IRegistry.ObjectInfo memory info ) { - if(!product.supportsInterface(type(IProductComponent).interfaceId)) { - revert ErrorRegistryServiceNotProduct(address(product)); - } - - info = _getAndVerifyContractInfo(product, PRODUCT(), initialOwner); - info.nftId = getRegistry().register(info); + _checkInterface( + component, + type(IInstanceLinkedComponent).interfaceId); + + address owner; + bytes memory data; + (info, owner, data) = _getAndVerifyContractInfo(component, expectedParentNftId, expectedType, expectedOwner); + info.nftId = _getRegistry().register(info, owner, data); } - function registerProductLinkedComponent( - IComponent component, - ObjectType objectType, - address initialOwner - ) - external - virtual - restricted() - returns( - IRegistry.ObjectInfo memory info - ) - { - // CAN revert if no ERC165 support -> will revert with empty message - if(!component.supportsInterface(type(IComponent).interfaceId)) { - revert ErrorRegistryServiceNotComponent(address(component)); - } - - if (!(objectType == DISTRIBUTION() || objectType == ORACLE() || objectType == POOL())) { - revert ErrorRegistryServiceNotProductLinkedComponent(address(component)); - } - - info = _getAndVerifyContractInfo(component, objectType, initialOwner); - info.nftId = getRegistry().register(info); - } - - function registerDistributor(IRegistry.ObjectInfo memory info) + function registerDistributor(IRegistry.ObjectInfo memory info, address owner, bytes memory data) external virtual restricted() returns(NftId nftId) { - _verifyObjectInfo(info, DISTRIBUTOR()); - nftId = getRegistry().register(info); + _verifyObjectInfo(info, owner, DISTRIBUTOR()); + nftId = _getRegistry().register(info, owner, data); } - function registerPolicy(IRegistry.ObjectInfo memory info) + function registerPolicy(IRegistry.ObjectInfo memory info, address owner, bytes memory data) external virtual restricted() returns(NftId nftId) { - _verifyObjectInfo(info, POLICY()); - nftId = getRegistry().register(info); + _verifyObjectInfo(info, owner, POLICY()); + nftId = _getRegistry().register(info, owner, data); } - function registerBundle(IRegistry.ObjectInfo memory info) + function registerBundle(IRegistry.ObjectInfo memory info, address owner, bytes memory data) external virtual restricted() returns(NftId nftId) { - _verifyObjectInfo(info, BUNDLE()); - nftId = getRegistry().register(info); + _verifyObjectInfo(info, owner, BUNDLE()); + nftId = _getRegistry().register(info, owner, data); } - function registerStake(IRegistry.ObjectInfo memory info) + function registerStake(IRegistry.ObjectInfo memory info, address owner, bytes memory data) external virtual restricted() returns(NftId nftId) { - _verifyObjectInfo(info, STAKE()); - nftId = getRegistry().register(info); + _verifyObjectInfo(info, owner, STAKE()); + nftId = _getRegistry().register(info, owner, data); } // Internal + function _checkInterface(IRegisterable registerable, bytes4 interfaceId) internal view + { + if(!ContractLib.supportsInterface(address(registerable), interfaceId)) { + revert ErrorRegistryServiceInterfaceNotSupported(address(registerable), interfaceId); + } + } + + /// @dev Based on the provided component address, parent, type and owner this function reverts iff: + /// - the component address does not match with address stored in component's initial info + /// - the component type does not match with the required type + /// - the component parent does not match with the required parent (when required parent is not zero) + /// - the component initialOwner does not match with the required owner (when required owner is not zero) + /// - the component initialOwner is zero (redundant, consider deleting) + /// - the component initialOwner is already registered function _getAndVerifyContractInfo( IRegisterable registerable, + NftId expectedParent, ObjectType expectedType, // assume can be valid only address expectedOwner // assume can be 0 when given by other service ) @@ -168,40 +165,62 @@ contract RegistryService is virtual view returns( - IRegistry.ObjectInfo memory info + IRegistry.ObjectInfo memory info, + address initialOwner, + bytes memory data ) { info = registerable.getInitialInfo(); + data = registerable.getInitialData(); + initialOwner = registerable.getOwner(); if(info.objectAddress != address(registerable)) { revert ErrorRegistryServiceRegisterableAddressInvalid(registerable, info.objectAddress); } - if(info.objectType != expectedType) {// type is checked in registry anyway...but service logic may depend on expected value - revert ErrorRegistryServiceRegisterableTypeInvalid(registerable, expectedType, info.objectType); + if(expectedType != COMPONENT()) { + // exact match + if(info.objectType != expectedType) {// type is checked in registry anyway...but service logic may depend on expected value + revert ErrorRegistryServiceRegisterableTypeInvalid(registerable, expectedType, info.objectType); + } + } else { + // match any component except product + if(!(info.objectType == DISTRIBUTION() || info.objectType == ORACLE() || info.objectType == POOL())) { + revert ErrorRegistryServiceRegisterableTypeInvalid(registerable, expectedType, info.objectType); + } } - address owner = info.initialOwner; + if(expectedParent.gtz()) { + // exact parent is important + if(info.parentNftId != expectedParent) { + revert ErrorRegistryServiceRegisterableParentInvalid(registerable, expectedParent, info.parentNftId); + } + } - if(owner != expectedOwner) { // registerable owner protection - revert ErrorRegistryServiceRegisterableOwnerInvalid(registerable, expectedOwner, owner); + if(expectedOwner > address(0)) { + // exact owner is important + if(initialOwner != expectedOwner) { // registerable owner protection + revert ErrorRegistryServiceRegisterableOwnerInvalid(registerable, expectedOwner, initialOwner); + } } - if(owner == address(registerable)) { + if(initialOwner == address(registerable)) { revert ErrorRegistryServiceRegisterableSelfRegistration(registerable); } - if(owner == address(0)) { + // redundant, checked by chainNft + if(initialOwner == address(0)) { revert ErrorRegistryServiceRegisterableOwnerZero(registerable); } - if(getRegistry().isRegistered(owner)) { - revert ErrorRegistryServiceRegisterableOwnerRegistered(registerable, owner); + if(_getRegistry().isRegistered(initialOwner)) { + revert ErrorRegistryServiceRegisterableOwnerRegistered(registerable, initialOwner); } } function _verifyObjectInfo( IRegistry.ObjectInfo memory info, + address initialOwner, ObjectType expectedType ) internal @@ -216,20 +235,18 @@ contract RegistryService is revert ErrorRegistryServiceObjectTypeInvalid(expectedType, info.objectType); } - address owner = info.initialOwner; - - if(owner == address(0)) { + if(initialOwner == address(0)) { revert ErrorRegistryServiceObjectOwnerZero(info.objectType); } - if(owner == msg.sender) { - revert ErrorRegistryServiceInvalidInitialOwner(owner); + if(initialOwner == msg.sender) { + revert ErrorRegistryServiceInvalidInitialOwner(initialOwner); } - if(getRegistry().isRegistered(owner)) { - ObjectType ownerType = getRegistry().getObjectInfo(owner).objectType; + if(_getRegistry().isRegistered(initialOwner)) { + ObjectType ownerType = _getRegistry().getObjectInfo(initialOwner).objectType; if(ownerType == REGISTRY() || ownerType == STAKING() || ownerType == SERVICE() || ownerType == INSTANCE()) { - revert ErrorRegistryServiceObjectOwnerRegistered(info.objectType, owner); + revert ErrorRegistryServiceObjectOwnerRegistered(info.objectType, initialOwner); } } } diff --git a/contracts/registry/RegistryServiceManager.sol b/contracts/registry/RegistryServiceManager.sol index d971993fe..44d096517 100644 --- a/contracts/registry/RegistryServiceManager.sol +++ b/contracts/registry/RegistryServiceManager.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; -import {IVersionable} from "../upgradeability/IVersionable.sol"; +import {IUpgradeable} from "../upgradeability/IUpgradeable.sol"; import {ProxyManager} from "../upgradeability/ProxyManager.sol"; import {RegistryService} from "./RegistryService.sol"; @@ -9,7 +9,6 @@ contract RegistryServiceManager is ProxyManager { error ErrorRegistryAccessManagerAuthorityZero(); - error ErrorRegistryAccessManagerRegistryZero(); bytes32 constant public ACCESS_MANAGER_CREATION_CODE_HASH = 0x0; @@ -18,27 +17,21 @@ contract RegistryServiceManager is /// @dev initializes proxy manager with registry service implementation and deploys registry constructor( address authority, // used by implementation - address registry, // used by implementation bytes32 salt ) { if(authority == address(0)) { revert ErrorRegistryAccessManagerAuthorityZero(); } - - if(registry == address(0)) { - revert ErrorRegistryAccessManagerRegistryZero(); - } RegistryService srv = new RegistryService{ salt: salt }(); - bytes memory data = abi.encode(authority, registry); - IVersionable versionable = initialize( - registry, + bytes memory data = abi.encode(authority); + IUpgradeable upgradeable = initialize( address(srv), data, salt); - _registryService = RegistryService(address(versionable)); + _registryService = RegistryService(address(upgradeable)); } //--- view functions ----------------------------------------------------// diff --git a/contracts/registry/ReleaseAdmin.sol b/contracts/registry/ReleaseAdmin.sol index 6dd4d934a..29bbf6e8a 100644 --- a/contracts/registry/ReleaseAdmin.sol +++ b/contracts/registry/ReleaseAdmin.sol @@ -10,6 +10,7 @@ import {AccessAdmin} from "../authorization/AccessAdmin.sol"; import {AccessAdminLib} from "../authorization/AccessAdminLib.sol"; import {AccessManagerCloneable} from "../authorization/AccessManagerCloneable.sol"; import {ObjectType, ObjectTypeLib, RELEASE} from "../type/ObjectType.sol"; +import {GIF_INITIAL_RELEASE} from "../registry/Registry.sol"; import {RoleId, ADMIN_ROLE, RELEASE_REGISTRY_ROLE} from "../type/RoleId.sol"; import {Str} from "../type/String.sol"; import {VersionPart} from "../type/Version.sol"; @@ -46,44 +47,37 @@ contract ReleaseAdmin is } - // @dev Only used for master release admin + /// @dev Only used for master release admin constructor(address accessManager) { initialize( accessManager, - "MasterReleaseAdmin"); + "MasterReleaseAdmin", + GIF_INITIAL_RELEASE()); } function completeSetup( - address registry, address authorization, - VersionPart release, address releaseRegistry ) external - reinitializer(uint64(release.toInt())) + //onlyDeployer() { - // checks - AccessAdminLib.checkRegistry(registry); - - AccessManagerCloneable( - authority()).completeSetup( - registry, - release); + // effects IServiceAuthorization serviceAuthorization = IServiceAuthorization(authorization); AccessAdminLib.checkAuthorization( address(_authorization), address(serviceAuthorization), RELEASE(), - release, + getRelease(), true, // expectServiceAuthorization true); // checkAlreadyInitialized); _serviceAuthorization = serviceAuthorization; // link nft ownability to registry - _linkToNftOwnable(registry); + _linkToNftOwnable(address(_getRegistry())); _createRoles(_serviceAuthorization); @@ -180,8 +174,7 @@ contract ReleaseAdmin is //--- private initialization functions -------------------------------------------// function _setupReleaseRegistry(address releaseRegistry) - private - onlyInitializing() + private { _createRole( diff --git a/contracts/registry/ReleaseRegistry.sol b/contracts/registry/ReleaseRegistry.sol index 94bd50ab5..50d4c14ac 100644 --- a/contracts/registry/ReleaseRegistry.sol +++ b/contracts/registry/ReleaseRegistry.sol @@ -5,10 +5,9 @@ import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol"; import {AccessManaged} from "@openzeppelin/contracts/access/manager/AccessManaged.sol"; import {IAccessAdmin} from "../authorization/IAccessAdmin.sol"; -import {AccessManagerCloneable} from "../authorization/AccessManagerCloneable.sol"; import {IRegistry} from "./IRegistry.sol"; import {IRelease} from "./IRelease.sol"; -import {IRegistryLinked} from "../shared/IRegistryLinked.sol"; +import {RegistryLinked} from "../shared/RegistryLinked.sol"; import {IService} from "../shared/IService.sol"; import {IServiceAuthorization} from "../authorization/IServiceAuthorization.sol"; @@ -16,7 +15,7 @@ import {ContractLib} from "../shared/ContractLib.sol"; import {NftId} from "../type/NftId.sol"; import {ObjectType, ObjectTypeLib, COMPONENT, POOL, RELEASE, REGISTRY, SERVICE, STAKING} from "../type/ObjectType.sol"; import {RegistryAdmin} from "./RegistryAdmin.sol"; -import {Registry} from "./Registry.sol"; +import {Registry, GIF_INITIAL_RELEASE} from "./Registry.sol"; import {ReleaseAdmin} from "./ReleaseAdmin.sol"; import {ReleaseLifecycle} from "./ReleaseLifecycle.sol"; import {Seconds} from "../type/Seconds.sol"; @@ -34,18 +33,13 @@ import {VersionPart, VersionPartLib} from "../type/Version.sol"; contract ReleaseRegistry is AccessManaged, ReleaseLifecycle, - IRegistryLinked + RegistryLinked { - uint256 public constant INITIAL_GIF_VERSION = 3;// first active release version - event LogReleaseCreation(IAccessAdmin admin, VersionPart release, bytes32 salt); event LogReleaseActivation(VersionPart release); event LogReleaseDisabled(VersionPart release); event LogReleaseEnabled(VersionPart release); - // constructor - error ErrorReleaseRegistryNotRegistry(Registry registry); - // _verifyServiceAuthorization error ErrorReleaseRegistryNotServiceAuth(address notAuth); error ErrorReleaseRegistryServiceAuthVersionMismatch(IServiceAuthorization auth, VersionPart expected, VersionPart actual); @@ -59,20 +53,19 @@ contract ReleaseRegistry is // _verifyService error ErrorReleaseRegistryNotService(address notService); - error ErrorReleaseRegistryServiceAuthorityMismatch(IService service, address serviceAuthority, address releaseAuthority); - error ErrorReleaseRegistryServiceVersionMismatch(IService service, VersionPart serviceVersion, VersionPart releaseVersion); + error ErrorReleaseRegistryServiceAuthorityMismatch(IService service, address expectedAuthority, address actualAuthority); error ErrorReleaseRegistryServiceDomainMismatch(IService service, ObjectType expectedDomain, ObjectType actualDomain); - // _verifyServiceInfo + // _getAndVerifyServiceInfo error ErrorReleaseRegistryServiceInfoAddressInvalid(IService service, address expected); error ErrorReleaseRegistryServiceInfoInterceptorInvalid(IService service, bool isInterceptor); error ErrorReleaseRegistryServiceInfoTypeInvalid(IService service, ObjectType expected, ObjectType found); + error ErrorReleaseRegistryServiceInfoReleaseMismatch(IService service, VersionPart expected, VersionPart actual); error ErrorReleaseRegistryServiceInfoOwnerInvalid(IService service, address expected, address found); error ErrorReleaseRegistryServiceSelfRegistration(IService service); error ErrorReleaseRegistryServiceOwnerRegistered(IService service, address owner); RegistryAdmin public immutable _registryAdmin; - Registry public immutable _registry; mapping(VersionPart release => IRelease.ReleaseInfo info) internal _releaseInfo; VersionPart [] internal _release; // array of all created releases @@ -86,21 +79,18 @@ contract ReleaseRegistry is uint256 internal _servicesToRegister = 0; // TODO move master relase admin outside constructor (same construction as for registry admin) - constructor(Registry registry) + constructor() AccessManaged(msg.sender) { - if (!ContractLib.isRegistry(address(registry))) { - revert ErrorReleaseRegistryNotRegistry(registry); - } + IRegistry registry = _getRegistry(); setAuthority(registry.getAuthority()); - _registry = registry; - _registryAdmin = RegistryAdmin(_registry.getRegistryAdminAddress()); + _registryAdmin = RegistryAdmin(registry.getRegistryAdminAddress()); _masterReleaseAdmin = new ReleaseAdmin( _cloneNewAccessManager()); - _next = VersionPartLib.toVersionPart(INITIAL_GIF_VERSION - 1); + _next = VersionPartLib.toVersionPart(GIF_INITIAL_RELEASE().toInt() - 1); } /// @dev Initiates the creation of a new GIF release by the GIF admin. @@ -118,7 +108,7 @@ contract ReleaseRegistry is } release = VersionPartLib.toVersionPart(release.toInt() + 1); - _release.push(release); + _release.push(release); // TODO push only activated releases, _next keeps total release count _next = release; _releaseInfo[release].version = release; @@ -184,24 +174,21 @@ contract ReleaseRegistry is address releaseAuthority = ReleaseAdmin(_releaseInfo[releaseVersion].releaseAdmin).authority(); IServiceAuthorization releaseAuthz = _releaseInfo[releaseVersion].auth; ObjectType expectedDomain = releaseAuthz.getServiceDomain(_registeredServices); + address expectedOwner = msg.sender; // service can work with release registry and release version ( IRegistry.ObjectInfo memory info, - ObjectType serviceDomain, - VersionPart serviceVersion - //,string memory serviceName + bytes memory data, + ObjectType serviceDomain ) = _verifyService( service, + expectedOwner, releaseAuthority, releaseVersion, expectedDomain ); - //_releaseInfo[releaseVersion].addresses.push(address(service)); // TODO get this info from auth contract? - //_releaseInfo[releaseVersion].domains.push(serviceDomain); - //_releaseInfo[releaseVersion].names.push(serviceName); // TODO if needed read in _verifyService() - _registeredServices++; // TODO use releaseInfo.someArray.length instead of _registeredServices // release fully deployed @@ -222,7 +209,7 @@ contract ReleaseRegistry is releaseAdmin.setReleaseLocked(true); // register service with registry - nftId = _registry.registerService(info, serviceVersion, serviceDomain); + nftId = _getRegistry().registerService(info, expectedOwner, serviceDomain, data); service.linkToRegisteredNftId(); } @@ -245,25 +232,27 @@ contract ReleaseRegistry is // grant special roles for registry/staking/pool services // this will enable access to core contracts functions + IRegistry registry = _getRegistry(); + // registry service MUST be registered for each release - address service = _registry.getServiceAddress(REGISTRY(), release); + address service = registry.getServiceAddress(REGISTRY(), release); if(service == address(0)) { revert ErrorReleaseRegistryRegistryServiceMissing(release); } _registryAdmin.grantServiceRoleForAllVersions(IService(service), REGISTRY()); - service = _registry.getServiceAddress(STAKING(), release); + service = registry.getServiceAddress(STAKING(), release); if(service != address(0)) { _registryAdmin.grantServiceRoleForAllVersions(IService(service), STAKING()); } - service = _registry.getServiceAddress(COMPONENT(), release); + service = registry.getServiceAddress(COMPONENT(), release); if(service != address(0)) { _registryAdmin.grantServiceRoleForAllVersions(IService(service), COMPONENT()); } - service = _registry.getServiceAddress(POOL(), release); + service = registry.getServiceAddress(POOL(), release); if(service != address(0)) { _registryAdmin.grantServiceRoleForAllVersions(IService(service), POOL()); } @@ -356,12 +345,6 @@ contract ReleaseRegistry is return address(_registryAdmin); } - //--- IRegistryLinked ------------------------------------------------------// - - function getRegistry() external view returns (IRegistry) { - return _registry; - } - //--- private functions ----------------------------------------------------// function _setReleaseLocked(VersionPart release, bool locked) @@ -389,12 +372,11 @@ contract ReleaseRegistry is clonedAdmin.initialize( address(_cloneNewAccessManager()), - releaseAdminName); + releaseAdminName, + release); clonedAdmin.completeSetup( - address(_registry), address(serviceAuthorization), - release, address(this)); // release registry (this contract) // lock release (remains locked until activation) @@ -439,62 +421,65 @@ contract ReleaseRegistry is // TODO get service names function _verifyService( - IService service, + IService service, + address expectedOwner, address expectedAuthority, - VersionPart expectedVersion, + VersionPart expectedRelease, ObjectType expectedDomain ) internal view returns( - IRegistry.ObjectInfo memory serviceInfo, - ObjectType serviceDomain, - VersionPart serviceVersion + IRegistry.ObjectInfo memory info, + bytes memory data, + ObjectType domain ) { if(!service.supportsInterface(type(IService).interfaceId)) { revert ErrorReleaseRegistryNotService(address(service)); } - address owner = msg.sender; - address serviceAuthority = service.authority(); - serviceVersion = service.getVersion().toMajorPart(); - serviceDomain = service.getDomain();// checked in registry - serviceInfo = service.getInitialInfo(); + address authority = service.authority(); + domain = service.getDomain();// checked in registry - _verifyServiceInfo(service, serviceInfo, owner); + (info,, data) = _getAndVerifyServiceInfo( + service, + expectedOwner, + expectedRelease); - if(serviceAuthority != expectedAuthority) { + if(authority != expectedAuthority) { revert ErrorReleaseRegistryServiceAuthorityMismatch( service, - serviceAuthority, - expectedAuthority); + expectedAuthority, + authority); } - if(serviceVersion != expectedVersion) { - revert ErrorReleaseRegistryServiceVersionMismatch( - service, - serviceVersion, - expectedVersion); - } - - if(serviceDomain != expectedDomain) { + if(domain != expectedDomain) { revert ErrorReleaseRegistryServiceDomainMismatch( service, expectedDomain, - serviceDomain); + domain); } } - function _verifyServiceInfo( + function _getAndVerifyServiceInfo( IService service, - IRegistry.ObjectInfo memory info, - address expectedOwner // assume always valid, can not be 0 + address expectedOwner, // assume always valid, can not be 0 + VersionPart expectedRelease ) internal view + returns ( + IRegistry.ObjectInfo memory info, + address initialOwner, + bytes memory data + ) { + info = service.getInitialInfo(); + initialOwner = service.getOwner(); + data = service.getInitialData(); + if(info.objectAddress != address(service)) { revert ErrorReleaseRegistryServiceInfoAddressInvalid(service, info.objectAddress); } @@ -507,18 +492,23 @@ contract ReleaseRegistry is revert ErrorReleaseRegistryServiceInfoTypeInvalid(service, SERVICE(), info.objectType); } - address owner = info.initialOwner; + if(info.release != expectedRelease) { + revert ErrorReleaseRegistryServiceInfoReleaseMismatch( + service, + expectedRelease, + info.release); + } - if(owner != expectedOwner) { // registerable owner protection - revert ErrorReleaseRegistryServiceInfoOwnerInvalid(service, expectedOwner, owner); + if(initialOwner != expectedOwner) { // registerable owner protection + revert ErrorReleaseRegistryServiceInfoOwnerInvalid(service, expectedOwner, initialOwner); } - if(owner == address(service)) { + if(initialOwner == address(service)) { revert ErrorReleaseRegistryServiceSelfRegistration(service); } - if(_registry.isRegistered(owner)) { - revert ErrorReleaseRegistryServiceOwnerRegistered(service, owner); + if(_getRegistry().isRegistered(initialOwner)) { + revert ErrorReleaseRegistryServiceOwnerRegistered(service, initialOwner); } } } diff --git a/contracts/registry/ServiceAuthorizationV3.sol b/contracts/registry/ServiceAuthorizationV3.sol index 896fa1fdb..f12ea1610 100644 --- a/contracts/registry/ServiceAuthorizationV3.sol +++ b/contracts/registry/ServiceAuthorizationV3.sol @@ -21,6 +21,8 @@ import {IRegistryService} from "./IRegistryService.sol"; import {IRiskService} from "../product/IRiskService.sol"; import {ServiceAuthorization} from "../authorization/ServiceAuthorization.sol"; +import {VersionPartLib} from "../../contracts/type/Version.sol"; +import {GIF_INITIAL_RELEASE} from "../registry/Registry.sol"; contract ServiceAuthorizationV3 @@ -31,7 +33,7 @@ contract ServiceAuthorizationV3 ServiceAuthorization( "ReleaseAdmin", RELEASE(), - 3, + GIF_INITIAL_RELEASE(), commitHash) {} @@ -90,8 +92,7 @@ contract ServiceAuthorizationV3 _authorize(functions, IRegistryService.registerBundle.selector, "registerBundle"); functions = _authorizeForService(REGISTRY(), COMPONENT()); - _authorize(functions, IRegistryService.registerProduct.selector, "registerProduct"); - _authorize(functions, IRegistryService.registerProductLinkedComponent.selector, "registerProductLinkedComponent"); + _authorize(functions, IRegistryService.registerComponent.selector, "registerComponent"); functions = _authorizeForService(REGISTRY(), DISTRIBUTION()); _authorize(functions, IRegistryService.registerDistributor.selector, "registerDistributor"); diff --git a/contracts/registry/TokenRegistry.sol b/contracts/registry/TokenRegistry.sol index 258e5a6b6..8ff856a56 100644 --- a/contracts/registry/TokenRegistry.sol +++ b/contracts/registry/TokenRegistry.sol @@ -5,7 +5,7 @@ import {AccessManaged} from "@openzeppelin/contracts/access/manager/AccessManage import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {IRegistry} from "./IRegistry.sol"; -import {IRegistryLinked} from "../shared/IRegistryLinked.sol"; +import {RegistryLinked} from "../shared/RegistryLinked.sol"; import {IStaking} from "../staking/IStaking.sol"; import {ChainId, ChainIdLib} from "../type/ChainId.sol"; @@ -16,7 +16,7 @@ import {VersionPart} from "../type/Version.sol"; /// Only whitelisted tokens can be used as default tokens for products, distribution and pools components. contract TokenRegistry is AccessManaged, - IRegistryLinked + RegistryLinked { event LogTokenRegistryTokenRegistered(ChainId chainId, address token, uint256 decimals, string symbol); event LogTokenRegistryTokenGlobalStateSet(ChainId chainId, address token, bool active); @@ -47,7 +47,6 @@ contract TokenRegistry is mapping(ChainId chainId => mapping(address token => mapping(VersionPart release => bool isActive))) internal _active; TokenInfo [] internal _token; - IRegistry internal _registry; ChainId internal _chainId = ChainIdLib.current(); IERC20Metadata internal _dipToken; @@ -59,14 +58,13 @@ contract TokenRegistry is _; } - constructor(IRegistry registry, IERC20Metadata dipToken) + constructor(IERC20Metadata dipToken) AccessManaged(msg.sender) { // set authority - address authority = RegistryAdmin(registry.getRegistryAdminAddress()).authority(); + address authority = RegistryAdmin( + _getRegistry().getRegistryAdminAddress()).authority(); setAuthority(authority); - - _registry = registry; // TODO deal with chains without a dip token _dipToken = _verifyOnchainToken(address(dipToken)); @@ -180,7 +178,7 @@ contract TokenRegistry is // verify valid major version if(enforceVersionCheck) { uint256 version = release.toInt(); - if (!getRegistry().isActiveRelease(release)) { + if (!_getRegistry().isActiveRelease(release)) { revert ErrorTokenRegistryMajorVersionInvalid(release); } } @@ -228,13 +226,6 @@ contract TokenRegistry is return address(_dipToken); } - //--- IRegistryLinked --------------------------------------------------// - - /// @dev returns the dip token for this chain - function getRegistry() public view returns (IRegistry) { - return _registry; - } - //--- internal functions ------------------------------------------------// diff --git a/contracts/shared/Component.sol b/contracts/shared/Component.sol index 6d65024c6..0840ff8a0 100644 --- a/contracts/shared/Component.sol +++ b/contracts/shared/Component.sol @@ -12,7 +12,7 @@ import {NftId} from "../type/NftId.sol"; import {ObjectType, COMPONENT} from "../type/ObjectType.sol"; import {Registerable} from "../shared/Registerable.sol"; import {TokenHandler} from "../shared/TokenHandler.sol"; -import {Version, VersionLib} from "../type/Version.sol"; +import {Version, VersionPart, VersionLib} from "../type/Version.sol"; abstract contract Component is @@ -23,14 +23,17 @@ abstract contract Component is bytes32 public constant COMPONENT_LOCATION_V1 = 0xffe8d4462baed26a47154f4b8f6db497d2f772496965791d25bd456e342b7f00; struct ComponentStorage { - string _name; // unique (per instance) component name - bool _isInterceptor; + // slot 0 IComponentService _componentService; + // slot 1 + string _name; // unique (per instance) component name -> make pure to save gas? + // slot 2 + bytes _data; } modifier onlyChainNft() { - if(msg.sender != getRegistry().getChainNftAddress()) { + if(msg.sender != _getRegistry().getChainNftAddress()) { revert ErrorComponentNotChainNft(msg.sender); } _; @@ -44,10 +47,9 @@ abstract contract Component is } } - + /// @dev requires component parent to be registered function __Component_init( address authority, - address registry, NftId parentNftId, string memory name, ObjectType componentType, @@ -65,7 +67,6 @@ abstract contract Component is __Registerable_init( authority, - registry, parentNftId, componentType, isInterceptor, @@ -75,7 +76,6 @@ abstract contract Component is // set component state ComponentStorage storage $ = _getComponentStorage(); $._name = name; - $._isInterceptor = isInterceptor; $._componentService = IComponentService(_getServiceAddress(COMPONENT())); _registerInterface(type(IAccessManaged).interfaceId); @@ -93,6 +93,17 @@ abstract contract Component is _nftTransferFrom(from, to, tokenId, operator); } + /// @inheritdoc IComponent + function withdrawFees(Amount amount) + external + virtual + restricted() + onlyOwner() + returns (Amount withdrawnAmount) + { + return _withdrawFees(amount); + } + function getWallet() public view virtual returns (address walletAddress) { return getTokenHandler().getWallet(); @@ -110,10 +121,6 @@ abstract contract Component is return getComponentInfo().name; } - function getVersion() public view virtual returns (Version version) { - return VersionLib.toVersion(1, 0, 0); - } - function getComponentInfo() public virtual view returns (IComponents.ComponentInfo memory info) { if (isRegistered()) { return _getComponentInfo(); @@ -129,17 +136,9 @@ abstract contract Component is } - function isNftInterceptor() public virtual view returns(bool isInterceptor) { - if (isRegistered()) { - return getRegistry().getObjectInfo(address(this)).isInterceptor; - } else { - return _getComponentStorage()._isInterceptor; - } - } - function isRegistered() public virtual view returns (bool) { - return getRegistry().getNftIdForAddress(address(this)).gtz(); + return _getRegistry().getNftIdForAddress(address(this)).gtz(); } @@ -170,6 +169,12 @@ abstract contract Component is // empty default implementation } + function _withdrawFees(Amount amount) + internal + returns (Amount withdrawnAmount) + { + return _getComponentStorage()._componentService.withdrawFees(amount); + } /// @dev Sets the components wallet to the specified address. /// Depending on the source of the component information this function needs to be overwritten. @@ -205,6 +210,6 @@ abstract contract Component is /// @dev returns the service address for the specified domain /// gets address via lookup from registry using the major version form the linked instance function _getServiceAddress(ObjectType domain) internal view returns (address) { - return getRegistry().getServiceAddress(domain, getRelease()); + return _getRegistry().getServiceAddress(domain, getRelease()); } } \ No newline at end of file diff --git a/contracts/shared/ComponentService.sol b/contracts/shared/ComponentService.sol index 5329dc9ae..aaac17f5f 100644 --- a/contracts/shared/ComponentService.sol +++ b/contracts/shared/ComponentService.sol @@ -49,14 +49,13 @@ contract ComponentService is ) internal virtual override - initializer() + onlyInitializing() { ( - address authority, - address registry - ) = abi.decode(data, (address, address)); + address authority + ) = abi.decode(data, (address)); - __Service_init(authority, registry, owner); + __Service_init(authority, owner); _accountingService = IAccountingService(_getServiceAddress(ACCOUNTING())); _registryService = IRegistryService(_getServiceAddress(REGISTRY())); @@ -74,26 +73,21 @@ contract ComponentService is restricted() returns (NftId componentNftId) { - // checks // check sender is registered product - IRegistry registry = getRegistry(); - if (!registry.isObjectType(msg.sender, PRODUCT())) { + IRegistry registry = _getRegistry(); + if (!registry.isObjectType(msg.sender, PRODUCT(), getRelease())) { revert ErrorComponentServiceCallerNotProduct(msg.sender); } - // check provided address is product contract - if (!_isInstanceLinkedComponent(componentAddress)) { - revert ErrorComponentServiceNotComponent(componentAddress); - } - NftId productNftId = registry.getNftIdForAddress(msg.sender); IInstance instance = IInstance( registry.getObjectAddress( registry.getParentNftId(productNftId))); - componentNftId = _verifyAndRegister( + componentNftId = _register( instance, - componentAddress, + componentAddress, + COMPONENT(), productNftId, // product is parent of component to be registered address(0)); // token will be inhereited from product } @@ -184,7 +178,7 @@ contract ComponentService is withdrawnAmount); // transfer amount to component owner - address componentOwner = getRegistry().ownerOf(componentNftId); + address componentOwner = _getRegistry().ownerOf(componentNftId); TokenHandler tokenHandler = instanceReader.getTokenHandler(componentNftId); emit LogComponentServiceComponentFeesWithdrawn( componentNftId, @@ -210,23 +204,18 @@ contract ComponentService is nonReentrant() returns (NftId productNftId) { - // checks // check sender is registered instance - IRegistry registry = getRegistry(); - if (!registry.isObjectType(msg.sender, INSTANCE())) { + IRegistry registry = _getRegistry(); + if (!registry.isObjectType(msg.sender, INSTANCE(), getRelease())) { revert ErrorComponentServiceCallerNotInstance(msg.sender); } - // check provided address is product contract - if (!_isProduct(productAddress)) { - revert ErrorComponentServiceNotProduct(productAddress); - } - IInstance instance = IInstance(msg.sender); NftId instanceNftId = registry.getNftIdForAddress(msg.sender); - productNftId = _verifyAndRegister( + productNftId = _register( instance, productAddress, + PRODUCT(), instanceNftId, // instance is parent of product to be registered token); @@ -236,25 +225,6 @@ contract ComponentService is token); } - - function _isProduct(address target) internal view virtual returns (bool) { - if (!_isInstanceLinkedComponent(target)) { - return false; - } - - return IInstanceLinkedComponent(target).getInitialInfo().objectType == PRODUCT(); - } - - - function _isInstanceLinkedComponent(address target) internal view virtual returns (bool) { - if (!ContractLib.isContract(target)) { - return false; - } - - return ContractLib.supportsInterface(target, type(IInstanceLinkedComponent).interfaceId); - } - - /// @inheritdoc IComponentService function setProductFees( Fee memory productFee, // product fee on net premium @@ -478,9 +448,10 @@ contract ComponentService is /// @dev Registers the component represented by the provided address. /// The caller must ensure componentAddress is IInstanceLinkedComponent. - function _verifyAndRegister( + function _register( IInstance instance, address componentAddress, + ObjectType componentType, NftId parentNftId, address token ) @@ -488,36 +459,29 @@ contract ComponentService is virtual returns (NftId componentNftId) { - ( - IInstanceLinkedComponent component, - IRegistry.ObjectInfo memory objectInfo // initial component info - ) = _getAndVerifyRegisterableComponent( - componentAddress, - parentNftId); + IInstanceLinkedComponent component = IInstanceLinkedComponent(componentAddress); + // TODO consider adding release arg to _registryService.registerComponent() and similar + // in order to be 100% sure that services have same release? + IRegistry.ObjectInfo memory info = _registryService.registerComponent( + component, + parentNftId, + componentType, + address(0)); // component owner have no importance here + + componentType = info.objectType; + componentNftId = info.nftId; InstanceStore instanceStore = instance.getInstanceStore(); - ObjectType componentType = objectInfo.objectType; + InstanceReader instanceReader = instance.getInstanceReader(); if(componentType == PRODUCT()) { - // register product with registry - componentNftId = _registryService.registerProduct( - component, - objectInfo.initialOwner).nftId; - // create product info in instance store _createProduct(instance.getProductStore(), componentNftId, componentAddress); } else { - // register non product component with registry - componentNftId = _registryService.registerProductLinkedComponent( - component, - objectInfo.objectType, - objectInfo.initialOwner).nftId; - - InstanceReader instanceReader = instance.getInstanceReader(); - // create non product component info in instance store - NftId productNftId = parentNftId; + NftId productNftId = info.parentNftId; IComponents.ProductInfo memory productInfo = instanceReader.getProductInfo(productNftId); + if(componentType == POOL()) { _createPool(instanceStore, instance.getProductStore(), productNftId, componentNftId, componentAddress, productInfo); } else if(componentType == DISTRIBUTION()) { @@ -529,7 +493,7 @@ contract ComponentService is } // get product's token - token = address(instanceReader.getTokenHandler(productNftId).TOKEN()); + token = address(instanceReader.getToken(productNftId)); } _checkToken(instance, token); @@ -537,10 +501,11 @@ contract ComponentService is InstanceAdmin instanceAdmin = instance.getInstanceAdmin(); // deploy and wire token handler + IRegistry registry = _getRegistry(); IComponents.ComponentInfo memory componentInfo = component.getInitialComponentInfo(); componentInfo.tokenHandler = TokenHandlerDeployerLib.deployTokenHandler( - address(getRegistry()), - address(component), // initially, component is its own wallet + address(registry), + componentAddress, // initially, component is its own wallet token, instanceAdmin.authority()); @@ -553,15 +518,15 @@ contract ComponentService is component.linkToRegisteredNftId(); // authorize - instanceAdmin.initializeComponentAuthorization(componentAddress, componentType); + instanceAdmin.initializeComponentAuthorization(componentAddress, componentType, getRelease()); emit LogComponentServiceRegistered( instance.getNftId(), componentNftId, componentType, - address(component), + componentAddress, token, - objectInfo.initialOwner); + registry.ownerOf(componentNftId)); } @@ -570,9 +535,10 @@ contract ComponentService is view { if (! instance.isTokenRegistryDisabled()) { + // TODO call token registry directlly? // check if provided token is whitelisted and active if (!ContractLib.isActiveToken( - getRegistry().getTokenRegistryAddress(), + _getRegistry().getTokenRegistryAddress(), ChainIdLib.current(), token, AccessManagerCloneable(authority()).getRelease()) @@ -609,47 +575,10 @@ contract ComponentService is IComponents.FeeInfo memory info ) { - productNftId = getRegistry().getParentNftId(componentNftId); + productNftId = _getRegistry().getParentNftId(componentNftId); info = instanceReader.getFeeInfo(productNftId); } - - /// @dev Based on the provided component address required type the component - /// and related instance contract this function reverts iff: - /// - the component parent does not match with the required parent - /// - the component release does not match with the service release - /// - the component has already been registered - function _getAndVerifyRegisterableComponent( - address componentAddress, - NftId requiredParent - ) - internal - view - returns ( - IInstanceLinkedComponent component, - IRegistry.ObjectInfo memory info - ) - { - component = IInstanceLinkedComponent(componentAddress); - info = component.getInitialInfo(); - - // check component parent - if(info.parentNftId != requiredParent) { - revert ErrorComponentServiceComponentParentInvalid(componentAddress, requiredParent, info.parentNftId); - } - - // check component release (must match with service release) - if(component.getRelease() != getRelease()) { - revert ErrorComponentServiceComponentReleaseMismatch(componentAddress, getRelease(), component.getRelease()); - } - - // check component has not already been registered - if (getRegistry().getNftIdForAddress(componentAddress).gtz()) { - revert ErrorComponentServiceComponentAlreadyRegistered(componentAddress); - } - } - - function _setLocked(InstanceAdmin instanceAdmin, address componentAddress, bool locked) internal { instanceAdmin.setTargetLocked(componentAddress, locked); } @@ -663,25 +592,11 @@ contract ComponentService is IInstance instance ) { - IRegistry.ObjectInfo memory info; - address instanceAddress; - - if (expectedType != COMPONENT()) { - (info, instanceAddress) = ContractLib.getAndVerifyComponent( - getRegistry(), - msg.sender, // caller - expectedType, - isActive); - } else { - (info, instanceAddress) = ContractLib.getAndVerifyAnyComponent( - getRegistry(), - msg.sender, - isActive); - } - - // get component nft id and instance - componentNftId = info.nftId; - instance = IInstance(instanceAddress); + (componentNftId, instance) = ContractLib.getAndVerifyComponent( + msg.sender, // caller + expectedType, + getRelease(), + isActive); } diff --git a/contracts/shared/ComponentServiceManager.sol b/contracts/shared/ComponentServiceManager.sol index a85da0ca4..9a666e08a 100644 --- a/contracts/shared/ComponentServiceManager.sol +++ b/contracts/shared/ComponentServiceManager.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.20; import {ComponentService} from "./ComponentService.sol"; -import {IVersionable} from "../upgradeability/IVersionable.sol"; +import {IUpgradeable} from "../upgradeability/IUpgradeable.sol"; import {ProxyManager} from "../upgradeability/ProxyManager.sol"; contract ComponentServiceManager is ProxyManager { @@ -11,20 +11,18 @@ contract ComponentServiceManager is ProxyManager { /// @dev initializes proxy manager with service implementation constructor( - address authority, - address registry, + address authority, bytes32 salt ) { ComponentService svc = new ComponentService(); - bytes memory data = abi.encode(authority, registry); - IVersionable versionable = initialize( - registry, + bytes memory data = abi.encode(authority); + IUpgradeable upgradeable = initialize( address(svc), data, salt); - _componentService = ComponentService(address(versionable)); + _componentService = ComponentService(address(upgradeable)); } //--- view functions ----------------------------------------------------// diff --git a/contracts/shared/ContractLib.sol b/contracts/shared/ContractLib.sol index 2e2fc0d6e..bec7f7c12 100644 --- a/contracts/shared/ContractLib.sol +++ b/contracts/shared/ContractLib.sol @@ -5,114 +5,376 @@ import {ERC165Checker} from "@openzeppelin/contracts/utils/introspection/ERC165C import {IAccessManager} from "@openzeppelin/contracts/access/manager/IAccessManager.sol"; import {IAccessManaged} from "@openzeppelin/contracts/access/manager/IAccessManaged.sol"; +import {IInstance} from "../instance/IInstance.sol"; +import {IOracleComponent} from "../oracle/IOracleComponent.sol"; import {IPolicyHolder} from "../shared/IPolicyHolder.sol"; import {IRegistry} from "../registry/IRegistry.sol"; import {IService} from "../shared/IService.sol"; import {ChainId} from "../type/ChainId.sol"; import {NftId} from "../type/NftId.sol"; -import {ObjectType, INSTANCE, PRODUCT, DISTRIBUTION, ORACLE, POOL} from "../type/ObjectType.sol"; +import {ObjectType, INSTANCE, COMPONENT, PRODUCT, DISTRIBUTION, ORACLE, POOL, POLICY, BUNDLE} from "../type/ObjectType.sol"; +import {TokenRegistry} from "../registry/TokenRegistry.sol"; import {VersionPart} from "../type/Version.sol"; interface ITargetHelper { function isTargetLocked(address target) external view returns (bool); } -interface IInstanceAdminHelper { - function getInstanceAdmin() external view returns (ITargetHelper); -} +library ContractLib { -interface ITokenRegistryHelper { - function isActive(ChainId chainId, address token, VersionPart release) external view returns (bool); -} + error ErrorContractLibCallerNotRegistered(address caller); + error ErrorContractLibCallerNotComponent(/*address caller, */NftId callerNftId, ObjectType callerType); + error ErrorContractLibParentNotInstance(/*address component, */NftId componentNftId, NftId parentNftId/*, ObjectType parentType*/); + error ErrorContractLibParentNotProduct(/*address component, */NftId componentNftId, NftId parentNftId/*, ObjectType parentType*/); + error ErrorContractLibComponentTypeMismatch(/*address component, */NftId componentNftId, ObjectType expectedType, ObjectType actualType); + error ErrorContractLibComponentReleaseMismatch(/*address component, */NftId componentNftId, VersionPart expectedRelease, VersionPart actualRelease); + error ErrorContractLibComponentInactive(/*address component, */NftId componentNftId); -library ContractLib { + error ErrorContractLibObjectNotRegistered(NftId objectNftId); + error ErrorContractLibObjectTypeMismatch(NftId objectNftId, ObjectType expectedType, ObjectType actualType); + error ErrorContractLibObjectReleaseMismatch(NftId objectNftId, VersionPart expectedRelease, VersionPart actualRelease); + error ErrorContractLibObjectParentMismatch(NftId objectNftId, NftId expectedParentNftId, NftId actualParentNftId); + + error ErrorContractLibParentsMismatch(NftId componentNftId, NftId componentParentNftId, NftId objectNftId, NftId objectParentNftId); - error ErrorContractLibCallerNotRegistered(address target); - error ErrorContractLibCallerNotComponent(NftId componentNftId, ObjectType objectType); - error ErrorContractLibParentNotInstance(NftId componentNftId, NftId parentNftId); - error ErrorContractLibParentNotProduct(NftId componentNftId, NftId parentNftId); - error ErrorContractLibComponentTypeMismatch(NftId componentNftId, ObjectType expectedType, ObjectType actualType); - error ErrorContractLibComponentInactive(NftId componentNftId); + + + // update registry address whenever it changes + address public constant REGISTRY_ADDRESS = address(0x345cA3e014Aaf5dcA488057592ee47305D9B3e10); + + function getRegistry() internal pure returns (IRegistry) { + return IRegistry(REGISTRY_ADDRESS); + } + + function getAndVerifyProduct(VersionPart expectedRelease) + external + view + returns ( + NftId, // productNftId + IInstance // instance, + ) + { + return getAndVerifyComponent( + msg.sender, + PRODUCT(), + expectedRelease, + true); // only active product + } + + function getAndVerifyPool(VersionPart expectedRelease) + external + view + returns ( + NftId, // poolNftId + IInstance // instance, + ) + { + return getAndVerifyComponent( + msg.sender, + POOL(), + expectedRelease, + true); // only active pool + } + + function getAndVerifyProductForPolicy(NftId policyNftId, VersionPart expectedRelease) + external + view + returns ( + NftId, // productNftId + IInstance // instance, + ) + { + return getAndVerifyComponentWithChild( + msg.sender, // product + true, // only active product + policyNftId, // child nft id + POLICY(), // child must be policy + expectedRelease); + } + + function getAndVerifyPoolForBundle(NftId bundleNftId, VersionPart expectedRelease) + external + view + returns ( + NftId, // poolNftId + IInstance // instance, + ) + { + return getAndVerifyComponentWithChild({ + component: msg.sender, // pool + onlyActive: true, // only active pool + childNftId: bundleNftId, // child nft id + expectedChildType: BUNDLE(), // child must be bundle + expectedRelease: expectedRelease}); + } + + function getAndVerifyPoolForPolicy(NftId policyNftId, VersionPart expectedRelease) + external + view + returns ( + NftId poolNftId, + IInstance instance + ) + { + (poolNftId,, instance) = getAndVerifyComponentAndObject({ + component: msg.sender, // pool + expectedComponentType: POOL(), + onlyActive: true, + objectNftId: policyNftId, + expectedObjectType: POLICY(), + expectedRelease: expectedRelease + }); + } + + function getAndVerifyComponentAndOracle( + NftId oracleNftId, + VersionPart expectedRelease + ) + external + view + returns ( + NftId requesterNftId, + IOracleComponent oracle, + IInstance instance + ) + { + address oracleAddress; + (requesterNftId, oracleAddress, instance) = getAndVerifyComponentAndObject({ + component: msg.sender, + expectedComponentType: COMPONENT(), + onlyActive: true, + objectNftId: oracleNftId, + expectedObjectType: ORACLE(), + expectedRelease: expectedRelease + }); + + oracle = IOracleComponent(oracleAddress); + } function getInfoAndInstance( - IRegistry registry, NftId componentNftId, + VersionPart release, bool onlyActive ) - external + public view returns ( IRegistry.ObjectInfo memory info, - address instance + IInstance instance ) { + IRegistry registry = getRegistry(); info = registry.getObjectInfo(componentNftId); - return _getAndVerifyComponentAndInstance(registry, info, info.objectType, onlyActive); + (, instance) = _getAndVerifyComponentAndInstance(info, info.objectType, release, onlyActive); } - function getAndVerifyAnyComponent( - IRegistry registry, + function getAndVerifyComponent( address caller, + ObjectType expectedType, + VersionPart expectedRelease, bool onlyActive ) - external + public view returns ( - IRegistry.ObjectInfo memory callerInfo, - address instance + NftId componentNftId, + IInstance instance ) { - // check caller is component - callerInfo = _getAndVerifyObjectInfo(registry, caller); - if(!(callerInfo.objectType == PRODUCT() - || callerInfo.objectType == POOL() - || callerInfo.objectType == DISTRIBUTION() - || callerInfo.objectType == ORACLE()) - ) { - revert ErrorContractLibCallerNotComponent( - callerInfo.nftId, - callerInfo.objectType); + // check caller is registered + IRegistry.ObjectInfo memory info = _getAndVerifyObjectInfo(caller); + // check caller info + return _getAndVerifyComponentAndInstance(info, expectedType, expectedRelease, onlyActive); + } + + function getAndVerifyComponentWithChild( + address component, + bool onlyActive, + NftId childNftId, + ObjectType expectedChildType, // assume valid component type + VersionPart expectedRelease + ) + public + view + returns ( + //IRegistry.ObjectInfo memory info, // component info + NftId componentNftId, + IInstance instance) + { + IRegistry registry = getRegistry(); + IRegistry.ObjectInfo memory info = registry.getObjectInfo(childNftId); + + // check child registration + if(info.nftId.eqz()) { + revert ErrorContractLibObjectNotRegistered(childNftId); } - return _getAndVerifyComponentAndInstance(registry, callerInfo, callerInfo.objectType, onlyActive); - } + // check child type + if(info.objectType != expectedChildType) { + revert ErrorContractLibObjectTypeMismatch( + childNftId, + expectedChildType, + info.objectType); + } + // check child release + if(info.release != expectedRelease) { + revert ErrorContractLibObjectReleaseMismatch( + childNftId, + expectedRelease, + info.release); + } - function getAndVerifyComponent( - IRegistry registry, - address caller, - ObjectType expectedType, - bool onlyActive + info = registry.getObjectInfo(info.parentNftId); + componentNftId = info.nftId; + + // check parent is component + if(info.objectAddress != component) { + revert ErrorContractLibObjectParentMismatch( + childNftId, + registry.getNftIdForAddress(component), + info.nftId); + } + + // get instance + instance = getAndVerifyInstance(info);// _getAndVerifyInstance(info); + + // check component is active + _checkComponentActive( + instance, + component, + componentNftId, + onlyActive); + } + + /// @dev + // component is contract of type COMPONENT + // objectNftId is either contract of type COMPONENT or object of type POLICY, BUNDLE, etc. + // is either child of component or have same parent as component + function getAndVerifyComponentAndObject( + address component, + ObjectType expectedComponentType, + bool onlyActive, + NftId objectNftId, + ObjectType expectedObjectType, + VersionPart expectedRelease ) - external + public view returns ( - IRegistry.ObjectInfo memory info, - address instance - ) + NftId componentNftId, + address objectAddress, // 0 for non contracts objects + IInstance instance) { - info = _getAndVerifyObjectInfo(registry, caller); - return _getAndVerifyComponentAndInstance(registry, info, expectedType, onlyActive); + IRegistry registry = getRegistry(); + + IRegistry.ObjectInfo memory componentInfo = registry.getObjectInfo(component); + componentNftId = componentInfo.nftId; + + // check component registered + + // check component type + if(expectedComponentType != COMPONENT()) { + if(componentInfo.objectType != expectedComponentType) { + revert ErrorContractLibComponentTypeMismatch( + //component, + componentInfo.nftId, + expectedComponentType, + componentInfo.objectType); + } + } else if( + !( + componentInfo.objectType == PRODUCT() || + componentInfo.objectType == POOL() || + componentInfo.objectType == DISTRIBUTION() || + componentInfo.objectType == ORACLE() + ) + ) { + revert ErrorContractLibCallerNotComponent( + //component, + componentInfo.nftId, + componentInfo.objectType); + } + + // check component release + if(componentInfo.release != expectedRelease) { + revert ErrorContractLibComponentReleaseMismatch( + //component, + componentInfo.nftId, + expectedRelease, + componentInfo.release); + } + + IRegistry.ObjectInfo memory objectInfo = registry.getObjectInfo(objectNftId); + objectAddress = objectInfo.objectAddress; + + // check object type + if(objectInfo.objectType != expectedObjectType) { + revert ErrorContractLibObjectTypeMismatch( + objectNftId, + expectedObjectType, + objectInfo.objectType); + } + + if(componentInfo.objectType == PRODUCT()) { + // check object parent is product + if(componentInfo.nftId != objectInfo.parentNftId) { + revert ErrorContractLibObjectParentMismatch( + objectNftId, + objectInfo.parentNftId, + componentInfo.nftId); + } + } else { + // check component parent is product + + // check object parent is same product + if(componentInfo.parentNftId != objectInfo.parentNftId) { + revert ErrorContractLibParentsMismatch( + componentInfo.nftId, + componentInfo.parentNftId, + objectNftId, + objectInfo.parentNftId); + } + } + + // get instance + instance = getAndVerifyInstance(componentInfo); + + // check component is active + _checkComponentActive( + instance, + component, + componentNftId, + onlyActive); } function getInstanceForComponent( - IRegistry registry, NftId componentNftId ) public view returns (address instance) { + IRegistry registry = getRegistry(); NftId productNftId = registry.getParentNftId(componentNftId); NftId instanceNftId = registry.getParentNftId(productNftId); return registry.getObjectInfo(instanceNftId).objectAddress; } + // TODO check array of nfts and array of types + // need to call: checkNftType({nftId: {nftId1, nftId2, nftId3}, expectedObjectType: {.., .., ..}}) + /*function checkNftType(NftId nftId, ObjectType expectedObjectType) external view { + VersionPart expectedRelease = getRelease(); + if(expectedObjectType.eqz() || !_getRegistry().isObjectType(nftId, expectedObjectType, expectedRelease)) { + revert ErrorNftOwnableInvalidType(nftId, expectedObjectType, expectedRelease); + } + }*/ + // TODO hardcoded token registry address? function isActiveToken( address tokenRegistryAddress, ChainId chainId, @@ -123,7 +385,7 @@ library ContractLib { view returns (bool) { - return ITokenRegistryHelper( + return TokenRegistry( tokenRegistryAddress).isActive( chainId, token, release); } @@ -160,16 +422,6 @@ library ContractLib { } - function isRegistered(address registry, address caller, ObjectType expectedType) public view returns (bool) { - NftId nftId = IRegistry(registry).getNftIdForAddress(caller); - if (nftId.eqz()) { - return false; - } - - return IRegistry(registry).getObjectInfo(nftId).objectType == expectedType; - } - - function isService(address service) public view returns (bool) { if (!isContract(service)) { return false; @@ -179,12 +431,8 @@ library ContractLib { } - function isRegistry(address registry) public view returns (bool) { - if (!isContract(registry)) { - return false; - } - - return supportsInterface(registry, type(IRegistry).interfaceId); + function isRegistry(address registry) public pure returns (bool) { + return registry == REGISTRY_ADDRESS; } @@ -206,39 +454,59 @@ library ContractLib { function _getAndVerifyComponentAndInstance( - IRegistry registry, IRegistry.ObjectInfo memory info, ObjectType expectedType, + VersionPart expectedRelease, bool onlyActive ) internal view returns ( - IRegistry.ObjectInfo memory, - address instance + NftId componentNftId, + IInstance instance ) { - if(info.objectType != expectedType) { - revert ErrorContractLibComponentTypeMismatch( + if(expectedType != COMPONENT()) { + if(info.objectType != expectedType) { + revert ErrorContractLibComponentTypeMismatch( + //info.objectAddress, + info.nftId, + expectedType, + info.objectType); + } + } else if( + !( + info.objectType == PRODUCT() || + info.objectType == POOL() || + info.objectType == DISTRIBUTION() || + info.objectType == ORACLE() + ) + ) { + revert ErrorContractLibCallerNotComponent( + //info.objectAddress, info.nftId, - expectedType, info.objectType); } + if(info.release != expectedRelease) { + revert ErrorContractLibComponentReleaseMismatch( + //info.objectAddress, + info.nftId, + expectedRelease, + info.release); + } + + componentNftId = info.nftId; + // get instance and check component is active - instance = getAndVerifyInstance(registry, info); + instance = getAndVerifyInstance(info); _checkComponentActive(instance, info.objectAddress, info.nftId, onlyActive); - - return ( - info, - instance - ); } function _checkComponentActive( - address instance, - address target, + IInstance instance, + address component, NftId componentNftId, bool onlyActive ) @@ -246,11 +514,8 @@ library ContractLib { view { if (onlyActive) { - if (IInstanceAdminHelper( - instance).getInstanceAdmin().isTargetLocked( - target) - ) { - revert ErrorContractLibComponentInactive(componentNftId); + if (instance.getInstanceAdmin().isTargetLocked(component)) { + revert ErrorContractLibComponentInactive(/*component, */componentNftId); } } } @@ -260,13 +525,14 @@ library ContractLib { /// The info may represent a product or any other component. /// If the parent of the provided info is not registered with the correct type, the function reverts. function getAndVerifyInstance( - IRegistry registry, IRegistry.ObjectInfo memory info ) public view - returns (address instance) + returns (IInstance instance) { + IRegistry registry = getRegistry(); + // get instance for product case if (info.objectType == PRODUCT()) { // verify that parent of product is registered instance @@ -278,7 +544,7 @@ library ContractLib { } // we have verified that parent object is a registerd instance -> we return the instance address - return instanceInfo.objectAddress; + return IInstance(instanceInfo.objectAddress); } // not product: verify parent is registered product @@ -290,23 +556,23 @@ library ContractLib { } // we have verified that parent is registerd product -> we can rely on registry that its parent is an instance - return registry.getObjectAddress(info.parentNftId); + return IInstance(registry.getObjectAddress(info.parentNftId)); } - + // check registration and return info function _getAndVerifyObjectInfo( - IRegistry registry, address caller ) internal view returns (IRegistry.ObjectInfo memory info) { - NftId componentNftId = registry.getNftIdForAddress(caller); - if (componentNftId.eqz()) { + IRegistry registry = getRegistry(); + + info = registry.getObjectInfo(caller); + + if (info.nftId.eqz()) { revert ErrorContractLibCallerNotRegistered(caller); } - - info = registry.getObjectInfo(componentNftId); } } \ No newline at end of file diff --git a/contracts/shared/IComponent.sol b/contracts/shared/IComponent.sol index 3e319e5dd..16982005e 100644 --- a/contracts/shared/IComponent.sol +++ b/contracts/shared/IComponent.sol @@ -29,6 +29,11 @@ interface IComponent is event LogComponentWalletTokensTransferred(address from, address to, uint256 amount); event LogComponentTokenHandlerApproved(address tokenHandler, address token, Amount limit, bool isMaxAmount); + /// @dev Withdraw fees from the distribution component. Only component owner is allowed to withdraw fees. + /// @param amount the amount to withdraw + /// @return withdrawnAmount the amount that was actually withdrawn + function withdrawFees(Amount amount) external returns (Amount withdrawnAmount); + /// @dev returns the name of this component /// to successfully register the component with an instance the name MUST be unique in the linked instance function getName() external view returns (string memory name); @@ -43,9 +48,6 @@ interface IComponent is /// the default address is the token handler address function getWallet() external view returns (address walletAddress); - /// @dev returns true iff this compoent intercepts nft minting and transfers for objects registered by this component - function isNftInterceptor() external view returns(bool isInterceptor); - /// @dev returns true iff this component is registered with the registry function isRegistered() external view returns (bool); diff --git a/contracts/shared/IComponentService.sol b/contracts/shared/IComponentService.sol index 13da9707a..070531d49 100644 --- a/contracts/shared/IComponentService.sol +++ b/contracts/shared/IComponentService.sol @@ -18,18 +18,11 @@ interface IComponentService is { // registerProduct error ErrorComponentServiceCallerNotInstance(address caller); - error ErrorComponentServiceNotProduct(address product); error ErrorComponentServiceTokenInvalid(address token); // registerComponent error ErrorComponentServiceCallerNotProduct(address caller); - error ErrorComponentServiceNotComponent(address component); - - error ErrorComponentServiceNotInstanceLinkedComponent(address component); error ErrorComponentServiceComponentTypeNotSupported(address component, ObjectType invalid); - error ErrorComponentServiceComponentParentInvalid(address component, NftId required, NftId actual); - error ErrorComponentServiceComponentReleaseMismatch(address component, VersionPart serviceRelease, VersionPart componentRelease); - error ErrorComponentServiceComponentAlreadyRegistered(address component); error ErrorProductServiceNoDistributionExpected(NftId productNftId); error ErrorProductServiceDistributionAlreadyRegistered(NftId productNftId, NftId distributionNftId); @@ -37,18 +30,11 @@ interface IComponentService is error ErrorProductServiceOraclesAlreadyRegistered(NftId productNftId, uint8 expectedOracles); error ErrorProductServicePoolAlreadyRegistered(NftId productNftId, NftId poolNftId); - error ErrorComponentServiceNewWalletAddressZero(); - error ErrorComponentServiceWalletAddressZero(); - error ErrorComponentServiceWalletAddressIsSameAsCurrent(); - error ErrorComponentServiceWithdrawAmountIsZero(); error ErrorComponentServiceWithdrawAmountExceedsLimit(Amount withdrawnAmount, Amount withdrawLimit); - error ErrorComponentServiceWalletAllowanceTooSmall(address wallet, address spender, uint256 allowance, uint256 amount); event LogComponentServiceComponentLocked(address component, bool locked); event LogComponentServiceRegistered(NftId instanceNftId, NftId componentNftId, ObjectType componentType, address component, address token, address initialOwner); - event LogComponentServiceWalletAddressChanged(NftId componentNftId, address currentWallet, address newWallet); - event LogComponentServiceWalletTokensTransferred(NftId componentNftId, address currentWallet, address newWallet, uint256 currentBalance); event LogComponentServiceComponentFeesWithdrawn(NftId componentNftId, address recipient, address token, Amount withdrawnAmount); event LogComponentServiceProductFeesUpdated(NftId productNftId); event LogComponentServiceDistributionFeesUpdated(NftId distributionNftId); diff --git a/contracts/shared/IInstanceLinkedComponent.sol b/contracts/shared/IInstanceLinkedComponent.sol index f1b362ddd..39b0db825 100644 --- a/contracts/shared/IInstanceLinkedComponent.sol +++ b/contracts/shared/IInstanceLinkedComponent.sol @@ -7,19 +7,15 @@ import {IAuthorization} from "../authorization/IAuthorization.sol"; import {IInstance} from "../instance/IInstance.sol"; import {NftId} from "../type/NftId.sol"; import {ObjectType} from "../type/ObjectType.sol"; +import {VersionPart} from "../type/Version.sol"; /// @dev component base class /// component examples are product, distribution, pool and oracle interface IInstanceLinkedComponent is IAuthorizedComponent { - error ErrorInstanceLinkedComponentTypeMismatch(ObjectType requiredType, ObjectType objectType); - error ErrorInstanceLinkedComponentNotProduct(NftId nftId, ObjectType objectType); - - /// @dev Withdraw fees from the distribution component. Only component owner is allowed to withdraw fees. - /// @param amount the amount to withdraw - /// @return withdrawnAmount the amount that was actually withdrawn - function withdrawFees(Amount amount) external returns (Amount withdrawnAmount); + error ErrorInstanceLinkedComponentInstanceInvalid(); + error ErrorInstanceLinkedComponentInstanceMismatch(VersionPart instanceRelease, VersionPart componentRelease); /// @dev defines the instance to which this component is linked to function getInstance() external view returns (IInstance instance); diff --git a/contracts/shared/INftOwnable.sol b/contracts/shared/INftOwnable.sol index bf21377b2..554779a30 100644 --- a/contracts/shared/INftOwnable.sol +++ b/contracts/shared/INftOwnable.sol @@ -5,7 +5,6 @@ import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import {IRegistryLinked} from "./IRegistryLinked.sol"; import {NftId} from "../type/NftId.sol"; -import {ObjectType} from "../type/ObjectType.sol"; interface INftOwnable is IERC165, @@ -15,7 +14,6 @@ interface INftOwnable is error ErrorNftOwnableInitialOwnerZero(); error ErrorNftOwnableNotOwner(address account); - error ErrorNftOwnableInvalidType(NftId nftId, ObjectType expectedObjectType); error ErrorNftOwnableAlreadyLinked(NftId nftId); error ErrorNftOwnableContractNotRegistered(address contractAddress); diff --git a/contracts/shared/IRegisterable.sol b/contracts/shared/IRegisterable.sol index 071408a33..c1b1a4680 100644 --- a/contracts/shared/IRegisterable.sol +++ b/contracts/shared/IRegisterable.sol @@ -4,8 +4,11 @@ pragma solidity ^0.8.20; import {IAccessManaged} from "@openzeppelin/contracts/access/manager/IAccessManaged.sol"; import {INftOwnable} from "./INftOwnable.sol"; -import {IRelease} from "../registry/IRelease.sol"; import {IRegistry} from "../registry/IRegistry.sol"; +import {IVersionable} from "./IVersionable.sol"; +import {ObjectType} from "../type/ObjectType.sol"; +import {NftId} from "../type/NftId.sol"; +import {VersionPart} from "../type/Version.sol"; /// @title IRegisterable /// @dev Marks contracts that are intended to be registered in the registry. @@ -13,7 +16,7 @@ import {IRegistry} from "../registry/IRegistry.sol"; interface IRegisterable is IAccessManaged, INftOwnable, - IRelease + IVersionable { // __Registerable_init error ErrorAuthorityInvalid(address authority); @@ -21,6 +24,9 @@ interface IRegisterable is // onlyActive() error ErrorRegisterableNotActive(); + //_checkNftType() + error ErrorRegisterableInvalidType(NftId nftId, ObjectType expectedType, VersionPart expectedRelease); + /// @dev Returns true iff this contract managed by its authority is active. /// Queries the IAccessManaged.authority(). function isActive() external view returns (bool active); @@ -32,5 +38,10 @@ interface IRegisterable is function getInitialInfo() external view - returns (IRegistry.ObjectInfo memory); + returns (IRegistry.ObjectInfo memory info); + + function getInitialData() + external + view + returns (bytes memory data); } \ No newline at end of file diff --git a/contracts/shared/IRegistryLinked.sol b/contracts/shared/IRegistryLinked.sol index 0785c806b..ae65bd3d5 100644 --- a/contracts/shared/IRegistryLinked.sol +++ b/contracts/shared/IRegistryLinked.sol @@ -5,7 +5,5 @@ import {IRegistry} from "../registry/IRegistry.sol"; interface IRegistryLinked { - error ErrorNotRegistry(address registryAddress); - - function getRegistry() external view returns (IRegistry); + function getRegistry() external pure returns (IRegistry); } \ No newline at end of file diff --git a/contracts/shared/IService.sol b/contracts/shared/IService.sol index ab6d485b9..0298f095c 100644 --- a/contracts/shared/IService.sol +++ b/contracts/shared/IService.sol @@ -4,14 +4,14 @@ pragma solidity ^0.8.20; import {IAccessManaged} from "@openzeppelin/contracts/access/manager/IAccessManaged.sol"; import {IRegisterable} from "./IRegisterable.sol"; -import {IVersionable} from "../upgradeability/IVersionable.sol"; +import {IUpgradeable} from "../upgradeability/IUpgradeable.sol"; import {ObjectType} from "../type/ObjectType.sol"; import {RoleId} from "../type/RoleId.sol"; interface IService is IAccessManaged, IRegisterable, - IVersionable + IUpgradeable { /// @dev returns the domain for this service. /// In any GIF release only one service for any given domain may be deployed. diff --git a/contracts/shared/IVersionable.sol b/contracts/shared/IVersionable.sol new file mode 100644 index 000000000..509a31d31 --- /dev/null +++ b/contracts/shared/IVersionable.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.20; + +import {Version, VersionPart} from "../type/Version.sol"; + +interface IVersionable { + + error ErrorVersionableReleaseInvalid(address target, VersionPart invalidRelease); + error ErrorVersionableReleaseMismatch(address target, VersionPart expected, VersionPart actual); + + /** + * @dev returns version of this contract + * implementation MUST define version in this function + * version number MUST increase + */ + function getVersion() external pure returns(Version); + + function getRelease() external pure returns(VersionPart); +} diff --git a/contracts/shared/InstanceLinkedComponent.sol b/contracts/shared/InstanceLinkedComponent.sol index e2213105d..128822924 100644 --- a/contracts/shared/InstanceLinkedComponent.sol +++ b/contracts/shared/InstanceLinkedComponent.sol @@ -33,7 +33,6 @@ abstract contract InstanceLinkedComponent is struct InstanceLinkedComponentStorage { IInstance _instance; // instance for this component - InstanceReader _instanceReader; // instance reader for this component IAuthorization _initialAuthorization; IComponentService _componentService; IOracleService _oracleService; @@ -53,16 +52,7 @@ abstract contract InstanceLinkedComponent is } - /// @inheritdoc IInstanceLinkedComponent - function withdrawFees(Amount amount) - external - virtual - restricted() - onlyOwner() - returns (Amount withdrawnAmount) - { - return _withdrawFees(amount); - } + //function setInstanceReader(address readerAddress); //--- internal functions ------------------------------------------------// @@ -84,6 +74,7 @@ abstract contract InstanceLinkedComponent is } + function _cancelRequest(RequestId requestId) internal virtual @@ -108,7 +99,6 @@ abstract contract InstanceLinkedComponent is function __InstanceLinkedComponent_init( - address registry, NftId parentNftId, string memory name, ObjectType componentType, @@ -116,34 +106,25 @@ abstract contract InstanceLinkedComponent is bool isInterceptor, address initialOwner ) - internal + internal virtual onlyInitializing() { - // validate registry, nft ids and get parent nft id - NftId instanceNftId = _checkAndGetInstanceNftId( - registry, - parentNftId, - componentType); - - // set and check linked instance - InstanceLinkedComponentStorage storage $ = _getInstanceLinkedComponentStorage(); - $._instance = IInstance( - IRegistry(registry).getObjectAddress(instanceNftId)); + IInstance instance = _checkAndGetInstance(parentNftId, componentType); // set component specific parameters __Component_init( - $._instance.authority(), // instance linked components need to point to instance admin - registry, + instance.authority(), parentNftId, name, - componentType, + componentType, isInterceptor, initialOwner, ""); // registry data // set instance linked specific parameters - $._instanceReader = $._instance.getInstanceReader(); + InstanceLinkedComponentStorage storage $ = _getInstanceLinkedComponentStorage(); + $._instance = instance; $._initialAuthorization = authorization; $._componentService = IComponentService(_getServiceAddress(COMPONENT())); $._oracleService = IOracleService(_getServiceAddress(ORACLE())); @@ -152,44 +133,35 @@ abstract contract InstanceLinkedComponent is _registerInterface(type(IInstanceLinkedComponent).interfaceId); } - - function _checkAndGetInstanceNftId( - address registryAddress, + function _checkAndGetInstance( NftId parentNftId, ObjectType componentType ) - internal + private view - returns (NftId instanceNftId) + returns (IInstance instance) { - // if product, then parent is already instance - if (componentType == PRODUCT()) { - _checkAndGetRegistry(registryAddress, parentNftId, INSTANCE()); - return parentNftId; + NftId instanceNftId; + IRegistry registry = _getRegistry(); + + if(componentType == PRODUCT()) { + instanceNftId = parentNftId; + } else { + NftId productNftId = parentNftId; + instanceNftId = registry.getParentNftId(productNftId); } - // if not product parent is product, and parent of product is instance - IRegistry registry = _checkAndGetRegistry(registryAddress, parentNftId, PRODUCT()); - return registry.getParentNftId(parentNftId); - } + IRegistry.ObjectInfo memory info = registry.getObjectInfo(instanceNftId); - /// @dev checks the and gets registry. - /// validates registry using a provided nft id and expected object type. - function _checkAndGetRegistry( - address registryAddress, - NftId objectNftId, - ObjectType requiredType - ) - internal - view - returns (IRegistry registry) - { - registry = IRegistry(registryAddress); - IRegistry.ObjectInfo memory info = registry.getObjectInfo(objectNftId); + if (info.objectType != INSTANCE()) { + revert ErrorInstanceLinkedComponentInstanceInvalid(); + } - if (info.objectType != requiredType) { - revert ErrorInstanceLinkedComponentTypeMismatch(requiredType, info.objectType); + if(info.release != getRelease()) { + revert ErrorInstanceLinkedComponentInstanceMismatch(info.release, getRelease()); } + + instance = IInstance(info.objectAddress); } @@ -201,7 +173,7 @@ abstract contract InstanceLinkedComponent is function _getComponentInfo() internal virtual override view returns (IComponents.ComponentInfo memory info) { - NftId componentNftId = getRegistry().getNftIdForAddress(address(this)); + NftId componentNftId = _getRegistry().getNftIdForAddress(address(this)); // if registered, attempt to return component info via instance reader if (componentNftId.gtz()) { @@ -221,13 +193,6 @@ abstract contract InstanceLinkedComponent is /// @dev returns reader for linked instance function _getInstanceReader() internal view returns (InstanceReader reader) { - return _getInstanceLinkedComponentStorage()._instanceReader; - } - - function _withdrawFees(Amount amount) - internal - returns (Amount withdrawnAmount) - { - return _getInstanceLinkedComponentStorage()._componentService.withdrawFees(amount); + return _getInstanceLinkedComponentStorage()._instance.getInstanceReader(); } } \ No newline at end of file diff --git a/contracts/shared/NftOwnable.sol b/contracts/shared/NftOwnable.sol index 0caf8dc05..2b9b26e9d 100644 --- a/contracts/shared/NftOwnable.sol +++ b/contracts/shared/NftOwnable.sol @@ -4,7 +4,6 @@ pragma solidity ^0.8.20; import {InitializableERC165} from "./InitializableERC165.sol"; import {INftOwnable} from "./INftOwnable.sol"; import {NftId} from "../type/NftId.sol"; -import {ObjectType} from "../type/ObjectType.sol"; import {RegistryLinked} from "./RegistryLinked.sol"; contract NftOwnable is @@ -29,28 +28,15 @@ contract NftOwnable is } modifier onlyNftOwner(NftId nftId) { - if(!getRegistry().isOwnerOf(nftId, msg.sender)) { + if(!_getRegistry().isOwnerOf(nftId, msg.sender)) { revert ErrorNftOwnableNotOwner(msg.sender); } _; } - modifier onlyNftOfType(NftId nftId, ObjectType expectedObjectType) { - _checkNftType(nftId, expectedObjectType); - _; - } - - function _checkNftType(NftId nftId, ObjectType expectedObjectType) internal view { - if(expectedObjectType.eqz() || !getRegistry().isObjectType(nftId, expectedObjectType)) { - revert ErrorNftOwnableInvalidType(nftId, expectedObjectType); - } - } - - /// @dev Initialization for upgradable contracts. - // used in __Registerable_init, ProxyManager._preDeployChecksAndSetup + // used in __Registerable_init, ProxyManager.initialize function __NftOwnable_init( - address registry, address initialOwner ) internal @@ -58,7 +44,6 @@ contract NftOwnable is onlyInitializing() { __ERC165_init(); - __RegistryLinked_init(registry); if(initialOwner == address(0)) { revert ErrorNftOwnableInitialOwnerZero(); @@ -88,7 +73,7 @@ contract NftOwnable is NftOwnableStorage storage $ = _getNftOwnableStorage(); if ($._nftId.gtz()) { - return getRegistry().ownerOf($._nftId); + return _getRegistry().ownerOf($._nftId); } return $._initialOwner; @@ -108,15 +93,17 @@ contract NftOwnable is revert ErrorNftOwnableAlreadyLinked($._nftId); } - if (!getRegistry().isRegistered(nftOwnableAddress)) { + NftId nftId = _getRegistry().getNftIdForAddress(nftOwnableAddress); + + if (nftId.eqz()) { revert ErrorNftOwnableContractNotRegistered(nftOwnableAddress); } - $._nftId = getRegistry().getNftIdForAddress(nftOwnableAddress); + $._nftId = nftId; - emit LogNftOwnableNftLinkedToAddress($._nftId, getOwner()); + emit LogNftOwnableNftLinkedToAddress(nftId, getOwner()); - return $._nftId; + return nftId; } diff --git a/contracts/shared/PolicyHolder.sol b/contracts/shared/PolicyHolder.sol index 47f1c475a..e0a2a3914 100644 --- a/contracts/shared/PolicyHolder.sol +++ b/contracts/shared/PolicyHolder.sol @@ -23,14 +23,12 @@ contract PolicyHolder is // callbacks must only be allowed from the policy and claim services // will need a release parameter to fetch the right service addresses for the modifiers - function _initializePolicyHolder( - address registryAddress + function __PolicyHolder_init( ) internal virtual onlyInitializing() { - __RegistryLinked_init(registryAddress); _initializeERC165(); _registerInterface(type(IPolicyHolder).interfaceId); } @@ -47,7 +45,7 @@ contract PolicyHolder is /// @dev empty default implementation function payoutExecuted(NftId policyNftId, PayoutId payoutId, Amount amount, address beneficiary) external virtual {} - //--- IERC165 functions ---------------// + //--- IERC721 functions ---------------// function onERC721Received( address, // operator address, // from diff --git a/contracts/shared/Registerable.sol b/contracts/shared/Registerable.sol index 870c00471..5b9033fa7 100644 --- a/contracts/shared/Registerable.sol +++ b/contracts/shared/Registerable.sol @@ -9,15 +9,16 @@ import {ContractLib} from "../shared/ContractLib.sol"; import {NftId, NftIdLib} from "../type/NftId.sol"; import {NftOwnable} from "../shared/NftOwnable.sol"; import {ObjectType} from "../type/ObjectType.sol"; +import {Versionable} from "../shared/Versionable.sol"; import {VersionPart, VersionPartLib} from "../type/Version.sol"; import {IRegistry} from "../registry/IRegistry.sol"; import {IRegisterable} from "./IRegisterable.sol"; -import {IRelease} from "../registry/IRelease.sol"; abstract contract Registerable is AccessManagedUpgradeable, NftOwnable, + Versionable, IRegisterable { // keccak256(abi.encode(uint256(keccak256("gif-next.contracts.shared.Registerable.sol")) - 1)) & ~bytes32(uint256(0xff)); @@ -37,14 +38,27 @@ abstract contract Registerable is _; } + modifier onlyNftOfType(NftId nftId, ObjectType expectedObjectType) { + _checkNftType(nftId, expectedObjectType); + _; + } + + // TODO move to registerables verification library + // TODO and check the owner here? + function _checkNftType(NftId nftId, ObjectType expectedObjectType) internal view { + VersionPart expectedRelease = getRelease(); + if(expectedObjectType.eqz() || !_getRegistry().isObjectType(nftId, expectedObjectType, expectedRelease)) { + revert ErrorRegisterableInvalidType(nftId, expectedObjectType, expectedRelease); + } + } + function __Registerable_init( address authority, - address registry, NftId parentNftId, ObjectType objectType, bool isInterceptor, address initialOwner, - bytes memory data // writeonly data that will saved in the object info record of the registry + bytes memory data ) internal virtual @@ -54,14 +68,19 @@ abstract contract Registerable is revert ErrorAuthorityInvalid(authority); } + VersionPart release = AccessManagerCloneable(authority).getRelease(); + __AccessManaged_init(authority); - __NftOwnable_init(registry, initialOwner); + __NftOwnable_init(initialOwner); + __Versionable_init(release); RegisterableStorage storage $ = _getRegisterableStorage(); $._parentNftId = parentNftId; $._objectType = objectType; $._isInterceptor = isInterceptor; - $._data = data; + if(data.length > 0) { + $._data = data; + } _registerInterface(type(IAccessManaged).interfaceId); } @@ -72,13 +91,6 @@ abstract contract Registerable is return !AccessManagerCloneable(authority()).isTargetClosed(address(this)); } - - /// @inheritdoc IRelease - function getRelease() public virtual view returns (VersionPart release) { - return AccessManagerCloneable(authority()).getRelease(); - } - - /// @inheritdoc IRegisterable function getInitialInfo() public @@ -87,14 +99,19 @@ abstract contract Registerable is returns (IRegistry.ObjectInfo memory info) { RegisterableStorage storage $ = _getRegisterableStorage(); - return IRegistry.ObjectInfo( - NftIdLib.zero(), - $._parentNftId, - $._objectType, - $._isInterceptor, - address(this), - getOwner(), - $._data); + return ( + IRegistry.ObjectInfo( + NftIdLib.zero(), + $._parentNftId, + $._objectType, + getRelease(), + $._isInterceptor, + address(this)) + ); + } + + function getInitialData() public view virtual returns (bytes memory data) { + return _getRegisterableStorage()._data; } diff --git a/contracts/shared/RegistryLinked.sol b/contracts/shared/RegistryLinked.sol index c19916461..3eba07a61 100644 --- a/contracts/shared/RegistryLinked.sol +++ b/contracts/shared/RegistryLinked.sol @@ -1,38 +1,19 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; -import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import {ContractLib} from "../shared/ContractLib.sol"; import {IRegistry} from "../registry/IRegistry.sol"; import {IRegistryLinked} from "./IRegistryLinked.sol"; contract RegistryLinked is - Initializable, IRegistryLinked { - - // priorize simplicity and size over using standard upgradeability structs - IRegistry private _registry; - - /// @dev initialization for upgradable contracts - // used in _initializeRegisterable - function __RegistryLinked_init( - address registry - ) - internal - virtual - onlyInitializing() - { - if (!ContractLib.isRegistry(registry)) { - revert ErrorNotRegistry(registry); - } - - _registry = IRegistry(registry); + function getRegistry() external pure returns (IRegistry) { + return ContractLib.getRegistry(); } - - function getRegistry() public view returns (IRegistry) { - return _registry; + function _getRegistry() internal pure returns (IRegistry) { + return ContractLib.getRegistry(); } } \ No newline at end of file diff --git a/contracts/shared/Service.sol b/contracts/shared/Service.sol index f937f85c1..00d1f4584 100644 --- a/contracts/shared/Service.sol +++ b/contracts/shared/Service.sol @@ -5,25 +5,25 @@ import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/ut import {IRegistry} from "../registry/IRegistry.sol"; import {IService} from "./IService.sol"; -import {IVersionable} from "../upgradeability/IVersionable.sol"; +import {IVersionable} from "../shared/IVersionable.sol"; import {ObjectType, SERVICE} from "../type/ObjectType.sol"; import {Registerable} from "./Registerable.sol"; import {RoleId, RoleIdLib} from "../type/RoleId.sol"; -import {Version, VersionLib} from "../type/Version.sol"; -import {Versionable} from "../upgradeability/Versionable.sol"; +import {Version, VersionLib, VersionPartLib} from "../type/Version.sol"; +import {Versionable} from "../shared/Versionable.sol"; +import {Upgradeable} from "../upgradeability/Upgradeable.sol"; /// @dev service base contract abstract contract Service is - Registerable, - Versionable, + Registerable, + Upgradeable, ReentrancyGuardUpgradeable, IService { function __Service_init( address authority, // real authority for registry service adress(0) for other services - address registry, address initialOwner ) internal @@ -34,8 +34,7 @@ abstract contract Service is __Registerable_init( authority, - registry, - IRegistry(registry).getNftId(), + _getRegistry().getNftId(), SERVICE(), false, // is interceptor initialOwner, @@ -62,6 +61,6 @@ abstract contract Service is function _getServiceAddress(ObjectType domain) internal view returns (address) { - return getRegistry().getServiceAddress(domain, getRelease()); + return _getRegistry().getServiceAddress(domain, getRelease()); } } \ No newline at end of file diff --git a/contracts/shared/TokenHandler.sol b/contracts/shared/TokenHandler.sol index e4944c48c..62f9c051e 100644 --- a/contracts/shared/TokenHandler.sol +++ b/contracts/shared/TokenHandler.sol @@ -10,6 +10,7 @@ import {ContractLib} from "../shared/ContractLib.sol"; import {IRegistry} from "../registry/IRegistry.sol"; import {NftId} from "../type/NftId.sol"; import {SERVICE} from "../type/ObjectType.sol"; +import {VersionPart} from "../type/Version.sol"; /// @dev Token specific transfer helper base contract. @@ -49,6 +50,7 @@ contract TokenHandlerBase { IERC20Metadata public immutable TOKEN; address public immutable COMPONENT; NftId public immutable NFT_ID; + VersionPart public immutable RELEASE; address internal _wallet; @@ -69,6 +71,7 @@ contract TokenHandlerBase { REGISTRY = IRegistry(registry); COMPONENT = component; NFT_ID = REGISTRY.getNftIdForAddress(component); + RELEASE = REGISTRY.getObjectRelease(NFT_ID); if (NFT_ID.eqz()) { revert ErrorTokenHandlerComponentNotRegistered(component); @@ -254,7 +257,7 @@ contract TokenHandler is error ErrorTokenHandlerNotService(address service); modifier onlyService() { - if (!REGISTRY.isObjectType(msg.sender, SERVICE())) { + if (!REGISTRY.isObjectType(msg.sender, SERVICE(), RELEASE)) { revert ErrorTokenHandlerNotService(msg.sender); } _; diff --git a/contracts/shared/Versionable.sol b/contracts/shared/Versionable.sol new file mode 100644 index 000000000..29f6612d7 --- /dev/null +++ b/contracts/shared/Versionable.sol @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.20; + +import {IVersionable} from "./IVersionable.sol"; +import {GIF_INITIAL_RELEASE} from "../registry/Registry.sol"; +import {Version, VersionPart, VersionLib, VersionPartLib} from "../type/Version.sol"; + + +abstract contract Versionable is + IVersionable +{ + // TODO use arg of type Version + function __Versionable_init( + VersionPart release // wants to initialize to this release version + ) + internal + view + virtual + { + VersionPart currentRelease = getRelease(); + if (!currentRelease.isValidRelease()) { + revert ErrorVersionableReleaseInvalid(address(this), currentRelease); + } + + //Version initializedVersion = VersionLib.toVersion(_getInitializedVersion()); + //if(initializedVersion != getVersion()) {} + + _checkRelease(release); + } + + function getVersion() public pure virtual returns(Version) + { + return VersionLib.toVersion(GIF_INITIAL_RELEASE().toInt(), 0, 0); + } + + function getRelease() public pure returns(VersionPart) + { + return getVersion().toMajorPart(); + } + + function _checkRelease(VersionPart release) internal view { + VersionPart currentRelease = getRelease(); + if(currentRelease != release) { + revert ErrorVersionableReleaseMismatch(address(this), release, currentRelease); + } + } +} \ No newline at end of file diff --git a/contracts/staking/IStaking.sol b/contracts/staking/IStaking.sol index 1963db6a1..4d7071706 100644 --- a/contracts/staking/IStaking.sol +++ b/contracts/staking/IStaking.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.20; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {IComponent} from "../shared/IComponent.sol"; -import {IVersionable} from "../upgradeability/IVersionable.sol"; +import {IUpgradeable} from "../upgradeability/IUpgradeable.sol"; import {Amount} from "../type/Amount.sol"; import {Blocknumber} from "../type/Blocknumber.sol"; @@ -22,7 +22,7 @@ import {VersionPart} from "../type/Version.sol"; interface IStaking is IComponent, - IVersionable + IUpgradeable { // owner functions diff --git a/contracts/staking/Staking.sol b/contracts/staking/Staking.sol index ea4c91c9f..297cd835f 100644 --- a/contracts/staking/Staking.sol +++ b/contracts/staking/Staking.sol @@ -4,11 +4,10 @@ pragma solidity ^0.8.20; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {IRegistry} from "../registry/IRegistry.sol"; -import {IRelease} from "../registry/IRelease.sol"; import {IStaking} from "./IStaking.sol"; import {IStakingService} from "./IStakingService.sol"; import {ITargetLimitHandler} from "./ITargetLimitHandler.sol"; -import {IVersionable} from "../upgradeability/IVersionable.sol"; +import {IVersionable} from "../shared/IVersionable.sol"; import {Amount, AmountLib} from "../type/Amount.sol"; import {Blocknumber} from "../type/Blocknumber.sol"; @@ -16,7 +15,7 @@ import {ChainId, ChainIdLib} from "../type/ChainId.sol"; import {Component} from "../shared/Component.sol"; import {IComponent} from "../shared/IComponent.sol"; import {NftId} from "../type/NftId.sol"; -import {ObjectType, PROTOCOL, INSTANCE, STAKE, STAKING, TARGET} from "../type/ObjectType.sol"; +import {ObjectType, PROTOCOL, STAKE, STAKING, TARGET} from "../type/ObjectType.sol"; import {Seconds, SecondsLib} from "../type/Seconds.sol"; import {Registerable} from "../shared/Registerable.sol"; import {StakingLib} from "./StakingLib.sol"; @@ -28,12 +27,13 @@ import {TokenHandlerDeployerLib} from "../shared/TokenHandlerDeployerLib.sol"; import {TokenRegistry} from "../registry/TokenRegistry.sol"; import {UFixed, UFixedLib} from "../type/UFixed.sol"; import {Version, VersionLib, VersionPart, VersionPartLib} from "../type/Version.sol"; -import {Versionable} from "../upgradeability/Versionable.sol"; +import {Versionable} from "../shared/Versionable.sol"; +import {Upgradeable} from "../upgradeability/Upgradeable.sol"; contract Staking is Component, - Versionable, + Upgradeable, IStaking { string public constant CONTRACT_NAME = "Staking"; @@ -75,17 +75,18 @@ contract Staking is external virtual { - if (msg.sender != address(getRegistry())) { + IRegistry registry = _getRegistry(); + if (msg.sender != address(registry)) { revert ErrorStakingNotRegistry(msg.sender); } StakingStorage storage $ = _getStakingStorage(); address dipToken = _getStakingStorage()._tokenRegistry.getDipTokenAddress(); $._tokenHandler = TokenHandlerDeployerLib.deployTokenHandler( - address(getRegistry()), + address(registry), address(this), dipToken, - getRegistry().getAuthority()); + registry.getAuthority()); } @@ -190,7 +191,7 @@ contract Staking is // effects StakingStorage storage $ = _getStakingStorage(); address oldStakingService = address($._stakingService); - $._stakingService = StakingLib.checkAndGetStakingService(getRegistry(), release); + $._stakingService = StakingLib.checkAndGetStakingService(release); emit LogStakingStakingServiceSet(address($._stakingService), release, oldStakingService); } @@ -277,9 +278,10 @@ contract Staking is returns (Amount newBalance) { address transferTo; + IRegistry registry = _getRegistry(); // case 1: protocol target: staking owner is recipient - if (targetNftId == getRegistry().getProtocolNftId()) { + if (targetNftId == registry.getProtocolNftId()) { // verify that the caller is the staking owner transferTo = getOwner(); if (msg.sender != transferTo) { @@ -289,7 +291,7 @@ contract Staking is // case 2: same chain target: target owner is recipient } else if (ChainIdLib.isCurrentChain(targetNftId)) { // verify that the caller is the target owner - transferTo = getRegistry().ownerOf(targetNftId); + transferTo = registry.ownerOf(targetNftId); if (msg.sender != transferTo) { revert ErrorStakingNotNftOwner(targetNftId); } @@ -323,13 +325,15 @@ contract Staking is onlyTarget(targetNftId) returns (Amount newBalance) { + IRegistry registry = _getRegistry(); + // check that service does not withdraw from protocol target - if (targetNftId == getRegistry().getProtocolNftId()) { + if (targetNftId == registry.getProtocolNftId()) { revert ErrorStakingTargetTypeNotSupported(targetNftId, PROTOCOL()); } // default: on-chain target owner is recipient - address targetOwner = getRegistry().ownerOf(targetNftId); + address targetOwner = registry.ownerOf(targetNftId); return _withdrawRewardReserves(targetNftId, dipAmount, targetOwner); } @@ -431,7 +435,9 @@ contract Staking is virtual restricted() // only pool service { + // !!! TODO amount can be 0 StakingStorage storage $ = _getStakingStorage(); + // why not StakingBalanceStore instead of StakingStore? $._store.increaseTotalValueLocked(targetNftId, token, amount); } @@ -528,7 +534,7 @@ contract Staking is // collect staked DIP token via staking service if (stakeAmount.gtz()) { - address stakeOwner = getRegistry().ownerOf(stakeNftId); + address stakeOwner = _getRegistry().ownerOf(stakeNftId); $._stakingService.pullDipToken(stakeAmount, stakeOwner); } } @@ -551,7 +557,7 @@ contract Staking is // transfer unstaked DIP token via staking service if (unstakedAmount.gtz()) { - address stakeOwner = getRegistry().ownerOf(stakeNftId); + address stakeOwner = _getRegistry().ownerOf(stakeNftId); $._stakingService.pushDipToken(unstakedAmount, stakeOwner); } } @@ -582,7 +588,7 @@ contract Staking is AmountLib.max()); // unstake up to this amount // step 2: create new stake with full unstaked amount - address stakeOwner = getRegistry().ownerOf(stakeNftId); + address stakeOwner = _getRegistry().ownerOf(stakeNftId); newStakeNftId = $._stakingService.createStakeObject(newTargetNftId, stakeOwner); $._store.createStake(newStakeNftId, newTargetNftId, stakeOwner, newStakedAmount); @@ -621,7 +627,7 @@ contract Staking is // collect staked DIP token by staking service if (claimedAmount.gtz()) { // interactions - address stakeOwner = getRegistry().ownerOf(stakeNftId); + address stakeOwner = _getRegistry().ownerOf(stakeNftId); $._stakingService.pushDipToken(claimedAmount, stakeOwner); } } @@ -649,21 +655,11 @@ contract Staking is return _getStakingStorage()._tokenHandler; } - // from IRegisterable - function getRelease() - public - pure - virtual override (IRelease, Registerable) - returns(VersionPart) - { - return VersionPartLib.toVersionPart(3); - } - // from IVersionable function getVersion() public pure - virtual override (Component, IVersionable, Versionable) + virtual override (IVersionable, Versionable) returns(Version) { return VersionLib.toVersion(3,0,0); @@ -728,14 +724,13 @@ contract Staking is onlyInitializing() { ( - address registryAddress, address targetHandlerAddress, address stakingStoreAddress, address tokenRegistryAddress - ) = abi.decode(data, (address, address, address, address)); + ) = abi.decode(data, (address, address, address)); // wiring to external contracts - IRegistry registry = IRegistry(registryAddress); + IRegistry registry = _getRegistry(); StakingStorage storage $ = _getStakingStorage(); $._protocolNftId = registry.getProtocolNftId(); $._targetHandler = TargetHandler(targetHandlerAddress); @@ -745,9 +740,9 @@ contract Staking is // staking service has to be set via setStakingService after deploying the first GIF release // initialize component + // TODO Will read 0 component service address from registry __Component_init( registry.getAuthority(), - address(registry), registry.getNftId(), // parent nft id CONTRACT_NAME, STAKING(), @@ -781,7 +776,7 @@ contract Staking is } if (checkOwner) { - address nftOwner = getRegistry().ownerOf(nftId); + address nftOwner = _getRegistry().ownerOf(nftId); if (msg.sender != nftOwner) { revert ErrorStakingNotOwner(nftId, nftOwner, msg.sender); } diff --git a/contracts/staking/StakingLib.sol b/contracts/staking/StakingLib.sol index fbe6b67da..4d146dc46 100644 --- a/contracts/staking/StakingLib.sol +++ b/contracts/staking/StakingLib.sol @@ -6,6 +6,7 @@ import {IStaking} from "./IStaking.sol"; import {IStakingService} from "./IStakingService.sol"; import {Amount} from "../type/Amount.sol"; +import {ContractLib} from "../shared/ContractLib.sol"; import {NftId} from "../type/NftId.sol"; import {ReleaseRegistry} from "../registry/ReleaseRegistry.sol"; import {Seconds, SecondsLib} from "../type/Seconds.sol"; @@ -111,13 +112,14 @@ library StakingLib { function checkAndGetStakingService( - IRegistry registry, VersionPart release ) public view returns (IStakingService stakingService) { + IRegistry registry = ContractLib.getRegistry(); + if (!ReleaseRegistry(registry.getReleaseRegistryAddress()).isActiveRelease(release)) { revert IStaking.ErrorStakingReleaseNotActive(release); } diff --git a/contracts/staking/StakingManager.sol b/contracts/staking/StakingManager.sol index e2cda2a38..a47459158 100644 --- a/contracts/staking/StakingManager.sol +++ b/contracts/staking/StakingManager.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; -import {IVersionable} from "../upgradeability/IVersionable.sol"; +import {IUpgradeable} from "../upgradeability/IUpgradeable.sol"; import {ProxyManager} from "../upgradeability/ProxyManager.sol"; import {Staking} from "./Staking.sol"; @@ -15,7 +15,6 @@ contract StakingManager is /// @dev initializes proxy manager with service implementation constructor( - address registry, address targetHandler, address stakingStore, address tokenRegistry, @@ -27,18 +26,16 @@ contract StakingManager is _initialImplementation = address(stakingImplementation); _initializationData = abi.encode( - registry, targetHandler, stakingStore, tokenRegistry); - IVersionable versionable = initialize( - registry, + IUpgradeable upgradeable = initialize( _initialImplementation, _initializationData, salt); - _staking = Staking(address(versionable)); + _staking = Staking(address(upgradeable)); } //--- view functions ----------------------------------------------------// diff --git a/contracts/staking/StakingReader.sol b/contracts/staking/StakingReader.sol index 53402a748..ed52ae6db 100644 --- a/contracts/staking/StakingReader.sol +++ b/contracts/staking/StakingReader.sol @@ -4,36 +4,32 @@ pragma solidity ^0.8.20; import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import {IRegistry} from "../registry/IRegistry.sol"; -import {IRegistryLinked} from "../shared/IRegistryLinked.sol"; +import {RegistryLinked} from "../shared/RegistryLinked.sol"; import {IStaking} from "../staking/IStaking.sol"; -import {Amount, AmountLib} from "../type/Amount.sol"; -import {Blocknumber} from "../type/Blocknumber.sol"; +import {Amount} from "../type/Amount.sol"; import {ChainId} from "../type/ChainId.sol"; import {NftId} from "../type/NftId.sol"; import {ObjectType} from "../type/ObjectType.sol"; +import {RegistryLinked} from "../shared/RegistryLinked.sol"; import {Seconds} from "../type/Seconds.sol"; import {StakingStore} from "./StakingStore.sol"; -import {STAKE, TARGET} from "../type/ObjectType.sol"; -import {Timestamp} from "../type/Timestamp.sol"; import {UFixed} from "../type/UFixed.sol"; contract StakingReader is - IRegistryLinked, - Initializable + Initializable, + RegistryLinked { error ErrorStakingReaderUnauthorizedCaler(); address private _initializeOwner; - IRegistry private _registry; IStaking private _staking; StakingStore private _store; - constructor(IRegistry registry) { + constructor() { _initializeOwner = msg.sender; - _registry = registry; } function initialize( @@ -51,18 +47,14 @@ contract StakingReader is _store = StakingStore(stakingStoreAddress); } - // view and pure functions - - function getRegistry() external view returns (IRegistry registry) { - return _registry; - } + // view functions function getStaking() external view returns (IStaking staking) { return _staking; } function getProtocolNftId() external view returns (NftId protocolNftId) { - return _registry.getProtocolNftId(); + return _getRegistry().getProtocolNftId(); } @@ -82,7 +74,7 @@ contract StakingReader is function getTargetNftId(NftId stakeNftId) public view returns (NftId targetNftId) { - return _registry.getParentNftId(stakeNftId); + return _getRegistry().getParentNftId(stakeNftId); } diff --git a/contracts/staking/StakingService.sol b/contracts/staking/StakingService.sol index e16f4b3b3..2287d55c5 100644 --- a/contracts/staking/StakingService.sol +++ b/contracts/staking/StakingService.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.20; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; -import {IRegisterable} from "../shared/IRegisterable.sol"; import {IRegistry} from "../registry/IRegistry.sol"; import {IStaking} from "./IStaking.sol"; import {IStakingService} from "./IStakingService.sol"; @@ -114,7 +113,7 @@ contract StakingService is // update reward reserve book keeping StakingServiceStorage storage $ = _getStakingServiceStorage(); - address instanceOwner = getRegistry().ownerOf(instanceNftId); + address instanceOwner = _getRegistry().ownerOf(instanceNftId); newBalance = $._staking.refillRewardReservesByService(instanceNftId, dipAmount, instanceOwner); emit LogStakingServiceRewardReservesIncreased(instanceNftId, rewardProvider, dipAmount, newBalance); @@ -131,7 +130,7 @@ contract StakingService is _checkNftType(instanceNftId, INSTANCE()); // update reward reserve book keeping StakingServiceStorage storage $ = _getStakingServiceStorage(); - address instanceOwner = getRegistry().ownerOf(instanceNftId); + address instanceOwner = _getRegistry().ownerOf(instanceNftId); newBalance = $._staking.withdrawRewardReservesByService(instanceNftId, dipAmount, instanceOwner); emit LogStakingServiceRewardReservesDecreased(instanceNftId, instanceOwner, dipAmount, newBalance); @@ -158,11 +157,12 @@ contract StakingService is nftId: NftIdLib.zero(), parentNftId: targetNftId, objectType: STAKE(), + release: getRelease(), isInterceptor: false, - objectAddress: address(0), - initialOwner: stakeOwner, - data: "" - })); + objectAddress: address(0)}), + stakeOwner, // initialOwner + "" // data + ); emit LogStakingServiceStakeObjectCreated(stakeNftId, targetNftId, stakeOwner); } @@ -255,18 +255,18 @@ contract StakingService is ) internal virtual override - initializer() + onlyInitializing() { ( address authority, - address registry, address staking - ) = abi.decode(data, (address, address, address)); + ) = abi.decode(data, (address, address)); - __Service_init(authority, registry, owner); + __Service_init(authority, owner); StakingServiceStorage storage $ = _getStakingServiceStorage(); $._registryService = RegistryService(_getServiceAddress(REGISTRY())); + // TODO staking is registered in registry.initialize(), just check if address is registered staking $._staking = _registerStaking(staking); $._dip = $._staking.getToken(); $._tokenHandler = $._staking.getTokenHandler(); @@ -283,7 +283,7 @@ contract StakingService is { // check if provided staking contract is already registred // staking contract may have been already registered by a previous major relase - IRegistry.ObjectInfo memory stakingInfo = getRegistry().getObjectInfo(stakingAddress); + IRegistry.ObjectInfo memory stakingInfo = _getRegistry().getObjectInfo(stakingAddress); if (stakingInfo.nftId.gtz()) { // registered object but wrong type if (stakingInfo.objectType != STAKING()) { @@ -294,6 +294,9 @@ contract StakingService is return IStaking(stakingAddress); } + // TODO staking is registered in registry.initialize() + // consider deleting the rest of the function + // check that contract implements IStaking if(!IStaking(stakingAddress).supportsInterface(type(IStaking).interfaceId)) { revert ErrorStakingServiceNotSupportingIStaking(stakingAddress); @@ -301,7 +304,7 @@ contract StakingService is address owner = msg.sender; _getStakingServiceStorage()._registryService.registerStaking( - IRegisterable(stakingAddress), + IStaking(stakingAddress), owner); return IStaking(stakingAddress); diff --git a/contracts/staking/StakingServiceManager.sol b/contracts/staking/StakingServiceManager.sol index 549a31935..ec45b1978 100644 --- a/contracts/staking/StakingServiceManager.sol +++ b/contracts/staking/StakingServiceManager.sol @@ -2,8 +2,7 @@ pragma solidity ^0.8.20; import {IRegistry} from "../registry/IRegistry.sol"; -import {IVersionable} from "../upgradeability/IVersionable.sol"; - +import {IUpgradeable} from "../upgradeability/IUpgradeable.sol"; import {ProxyManager} from "../upgradeability/ProxyManager.sol"; import {StakingService} from "./StakingService.sol"; @@ -16,23 +15,20 @@ contract StakingServiceManager is /// @dev initializes proxy manager with service implementation constructor( address authority, - address registry, bytes32 salt ) { StakingService svc = new StakingService(); bytes memory data = abi.encode( authority, - registry, - IRegistry(registry).getStakingAddress()); + _getRegistry().getStakingAddress()); - IVersionable versionable = initialize( - registry, + IUpgradeable upgradeable = initialize( address(svc), data, salt); - _stakingService = StakingService(address(versionable)); + _stakingService = StakingService(address(upgradeable)); } //--- view functions ----------------------------------------------------// diff --git a/contracts/staking/StakingStore.sol b/contracts/staking/StakingStore.sol index 73daee594..9b34032e6 100644 --- a/contracts/staking/StakingStore.sol +++ b/contracts/staking/StakingStore.sol @@ -18,6 +18,7 @@ import {PROTOCOL, INSTANCE} from "../type/ObjectType.sol"; import {Seconds, SecondsLib} from "../type/Seconds.sol"; import {StakingLib} from "./StakingLib.sol"; import {StakingReader} from "./StakingReader.sol"; +import {RegistryLinked} from "../shared/RegistryLinked.sol"; import {TargetManagerLib} from "./TargetManagerLib.sol"; import {Timestamp, TimestampLib} from "../type/Timestamp.sol"; import {UFixed, UFixedLib} from "../type/UFixed.sol"; @@ -25,7 +26,8 @@ import {UFixed, UFixedLib} from "../type/UFixed.sol"; contract StakingStore is Initializable, - AccessManaged + AccessManaged, + RegistryLinked { // token @@ -53,7 +55,6 @@ contract StakingStore is error ErrorStakingStoreTvlBalanceAlreadyInitialized(NftId nftId, address token); error ErrorStakingStoreTvlBalanceNotInitialized(NftId nftId, address token); - IRegistry private _registry; ITargetLimitHandler private _targetLimitHandler; StakingReader private _reader; NftIdSet private _targetNftIdSet; @@ -75,16 +76,15 @@ contract StakingStore is constructor( - IRegistry registry, StakingReader reader ) AccessManaged(msg.sender) { + // set final authority - setAuthority(registry.getAuthority()); + setAuthority(_getRegistry().getAuthority()); // set internal variables - _registry = registry; _reader = reader; _targetNftIdSet = new NftIdSet(); @@ -495,7 +495,7 @@ contract StakingStore is emit IStaking.LogStakingRewardReservesRefilled( targetNftId, dipAmount, - _registry.ownerOf(targetNftId), + _getRegistry().ownerOf(targetNftId), newReserveBalance, lastUpdateIn); } @@ -520,7 +520,7 @@ contract StakingStore is emit IStaking.LogStakingRewardReservesWithdrawn( targetNftId, dipAmount, - _registry.ownerOf(targetNftId), + _getRegistry().ownerOf(targetNftId), newReserveBalance, lastUpdateIn); } @@ -929,7 +929,7 @@ contract StakingStore is // checks if (checkParameters) { TargetManagerLib.checkTargetParameters( - _registry, + _getRegistry(), _reader, targetNftId, objectType, diff --git a/contracts/staking/TargetHandler.sol b/contracts/staking/TargetHandler.sol index 70c1e887a..2058bd678 100644 --- a/contracts/staking/TargetHandler.sol +++ b/contracts/staking/TargetHandler.sol @@ -10,6 +10,7 @@ import {ITargetLimitHandler} from "./ITargetLimitHandler.sol"; import {Amount, AmountLib} from "../type/Amount.sol"; import {Blocknumber, BlocknumberLib} from "../type/Blocknumber.sol"; import {NftId} from "../type/NftId.sol"; +import {RegistryLinked} from "../shared/RegistryLinked.sol"; import {StakingStore} from "./StakingStore.sol"; import {UFixed, UFixedLib} from "../type/UFixed.sol"; @@ -17,12 +18,12 @@ import {UFixed, UFixedLib} from "../type/UFixed.sol"; contract TargetHandler is Initializable, AccessManaged, - ITargetLimitHandler + ITargetLimitHandler, + RegistryLinked { event LogTargetHandlerUpdateTriggersSet(uint16 tvlUpdatesTrigger, UFixed minTvlRatioTrigger, Blocknumber lastUpdateIn); - IRegistry private _registry; StakingStore private _store; /// @dev Update trigger value: Number of TVL updates below which limit updates are suppressed @@ -33,14 +34,12 @@ contract TargetHandler is constructor ( - IRegistry registry, StakingStore stakingStore ) AccessManaged(msg.sender) { // set final authority and registry - setAuthority(registry.getAuthority()); - _registry = registry; + setAuthority(_getRegistry().getAuthority()); _store = stakingStore; // set default trigger values diff --git a/contracts/type/Version.sol b/contracts/type/Version.sol index f6fef4901..be6075036 100644 --- a/contracts/type/Version.sol +++ b/contracts/type/Version.sol @@ -5,6 +5,9 @@ type VersionPart is uint8; using { versionPartGt as >, + versionPartGte as >=, + versionPartLt as <, + versionPartLte as <=, versionPartEq as ==, versionPartNe as !=, VersionPartLib.eqz, @@ -16,6 +19,9 @@ using { for VersionPart global; function versionPartGt(VersionPart a, VersionPart b) pure returns(bool isGreaterThan) { return VersionPart.unwrap(a) > VersionPart.unwrap(b); } +function versionPartGte(VersionPart a, VersionPart b) pure returns(bool isGreaterThan) { return VersionPart.unwrap(a) >= VersionPart.unwrap(b); } +function versionPartLt(VersionPart a, VersionPart b) pure returns(bool isLessThan) { return VersionPart.unwrap(a) < VersionPart.unwrap(b); } +function versionPartLte(VersionPart a, VersionPart b) pure returns(bool isLessThan) { return VersionPart.unwrap(a) <= VersionPart.unwrap(b); } function versionPartEq(VersionPart a, VersionPart b) pure returns(bool isSame) { return VersionPart.unwrap(a) == VersionPart.unwrap(b); } function versionPartNe(VersionPart a, VersionPart b) pure returns(bool isSame) { return VersionPart.unwrap(a) != VersionPart.unwrap(b); } @@ -27,8 +33,7 @@ library VersionPartLib { function releaseMax() public pure returns (VersionPart) { return toVersionPart(99); } function isValidRelease(VersionPart release) external pure returns(bool) { - uint256 releaseInt = VersionPart.unwrap(release); - return 3 <= releaseInt && releaseInt <= 99; + return releaseMin() <= release && release <= releaseMax(); } function toString(VersionPart a) external pure returns (string memory) { @@ -66,8 +71,9 @@ library VersionPartLib { function eqz(VersionPart a) external pure returns(bool) { return VersionPart.unwrap(a) == 0; } function gtz(VersionPart a) external pure returns(bool) { return VersionPart.unwrap(a) > 0; } - function toInt(VersionPart a) external pure returns(uint256) { return VersionPart.unwrap(a); } - function toVersionPart(uint256 a) public pure returns(VersionPart) { return VersionPart.wrap(uint8(a)); } + function toInt(VersionPart a) external pure returns(uint8) { return VersionPart.unwrap(a); } + function toVersionPart(uint8 a) public pure returns(VersionPart) { return VersionPart.wrap(uint8(a)); } + function zero() external pure returns(VersionPart) { return VersionPart.wrap(0); } } type Version is uint24; // contains major,minor,patch version parts @@ -87,7 +93,7 @@ function versionEq(Version a, Version b) pure returns(bool isSame) { return Vers library VersionLib { - function toInt(Version version) external pure returns(uint) { return Version.unwrap(version); } + function toInt(Version version) external pure returns(uint24) { return Version.unwrap(version); } function toUint64(Version version) external pure returns(uint64) { return Version.unwrap(version); } @@ -124,26 +130,19 @@ library VersionLib { ); } - // function toVersionPart(uint256 versionPart) public pure returns(VersionPart) { - // return VersionPart.wrap(uint8(versionPart)); - // } - function toVersion( - uint256 major, - uint256 minor, - uint256 patch + uint8 major, + uint8 minor, + uint8 patch ) external pure returns(Version) { - require( - major < 256 && minor < 256 && patch < 256, - "ERROR:VRS-010:VERSION_PART_TOO_BIG"); return Version.wrap( uint24( - (major << 16) + (minor << 8) + patch)); + (uint24(major) << 16) + (uint24(minor) << 8) + patch)); } // TODO check for overflow? diff --git a/contracts/upgradeability/IVersionable.sol b/contracts/upgradeability/IUpgradeable.sol similarity index 60% rename from contracts/upgradeability/IVersionable.sol rename to contracts/upgradeability/IUpgradeable.sol index 7d58fc47e..d98b3368b 100644 --- a/contracts/upgradeability/IVersionable.sol +++ b/contracts/upgradeability/IUpgradeable.sol @@ -1,21 +1,21 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; -import {Version} from "../type/Version.sol"; +import {IVersionable} from "../shared/IVersionable.sol"; /// IMPORTANT // Upgradeable contract MUST: -// 1) inherit from Versionable -// 2) implement version() function +// 1) inherit Upgradeable +// 2) implement getVersion() function // 3) implement internal _initialize() function with onlyInitializing modifier // 4) implement internal _upgrade() function with onlyInitializing modifier (1st version MUST revert) -// 5) have onlyInitialising modifier for each function callable inside _initialize()/_upgrade() (MUST use different functions for initialization/upgrade and normal operations) -// 6) use default empty constructor -> _disableInitializer() is called from Versionable contructor -// 7) use namespace storage (should this be needed) -// 8) since now inheritance is used for upgradability, contract MUST BE inherited ONLY by the next version +// 5) have onlyInitialising modifier for each function callable inside _initialize()/_upgrade() +// 6) use different functions for initialization, upgrade and normal operations +// 7) use default empty constructor -> _disableInitializer() is called from Upgradeable contructor +// 8) use namespace storage (should storage be needed) // Upgradeable contract SHOULD: // 9) define all non private methods as virtual (in order to be able to upgrade them latter) -// otherwise, it is still possible to upgrade contract, but everyone who is using it will have to switch to a new fucntions +// otherwise, it is still possible to upgrade contract, but everyone who is using it will have to switch to a new functions // in some cases this ok but not in the others... // // IMPORTANT @@ -26,31 +26,25 @@ import {Version} from "../type/Version.sol"; // 2) ALWAYS define private getter if accessing storage // - MUST use default implementation, CAN change ONLY return type -interface IVersionable { +interface IUpgradeable is IVersionable { error ErrorVersionableInitializeNotImplemented(); error ErrorVersionableUpgradeNotImplemented(); /** * @dev IMPORTANT + * top level initializer for each upgradeable * implementation MUST be guarded by initializer modifier * new version MUST inherit from previous version */ - function initializeVersionable(address activatedBy, bytes memory activationData) external; + function initialize(address activatedBy, bytes memory activationData) external; /** * @dev + * top level reinitializer for each upgradeable * implementation MUST be guarded by reinitializer(version().toUint64()) modifier * new version MUST inherit from previous version * the first verion MUST revert */ - function upgradeVersionable(bytes memory upgradeData) external; - - /** - * @dev returns version of this contract - * each new implementation MUST implement this function - * version number MUST increase - */ - function getVersion() external pure returns(Version); - + function upgrade(bytes memory upgradeData) external; } diff --git a/contracts/upgradeability/ProxyManager.sol b/contracts/upgradeability/ProxyManager.sol index 14db35272..3a0a5a3f6 100644 --- a/contracts/upgradeability/ProxyManager.sol +++ b/contracts/upgradeability/ProxyManager.sol @@ -5,14 +5,14 @@ import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.s import {ITransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import {Blocknumber, BlocknumberLib} from "../type/Blocknumber.sol"; -import {IVersionable} from "./IVersionable.sol"; +import {IUpgradeable} from "./IUpgradeable.sol"; import {NftId} from "../type/NftId.sol"; import {NftOwnable} from "../shared/NftOwnable.sol"; import {Timestamp, TimestampLib} from "../type/Timestamp.sol"; import {UpgradableProxyWithAdmin} from "./UpgradableProxyWithAdmin.sol"; -import {Version, VersionLib} from "../type/Version.sol"; +import {Version, VersionPart, VersionLib} from "../type/Version.sol"; -/// @dev manages proxy deployments for upgradable contracs of type IVersionable +/// @dev manages proxy deployments for upgradable contracs of type IUpgradeable contract ProxyManager is NftOwnable { @@ -27,14 +27,15 @@ contract ProxyManager is address activatedBy; } - event LogProxyManagerVersionableDeployed(address indexed proxy, address initialImplementation); - event LogProxyManagerVersionableUpgraded(address indexed proxy, address upgradedImplementation); + event LogProxyManagerProxyDeployed(address indexed proxy, address initialImplementation); + event LogProxyManagerProxyUpgraded(address indexed proxy, address upgradedImplementation); error ErrorProxyManagerAlreadyDeployed(); error ErrorProxyManagerNotYetDeployed(); error ErrorProxyManagerZeroVersion(); error ErrorProxyManagerNextVersionNotIncreasing(Version nextVersion); + error ErrorProxyManagerNextVersionReleaseInvalid(Version nextVersion); UpgradableProxyWithAdmin internal _proxy; @@ -44,17 +45,19 @@ contract ProxyManager is /// @dev convencience initializer function initialize( - address registry, address implementation, bytes memory data, bytes32 salt ) public initializer() - returns (IVersionable versionable) + returns (IUpgradeable upgradeable) { - versionable = deployDetermenistic( - registry, + address initialOwner = msg.sender; + + __NftOwnable_init(initialOwner); + + upgradeable = deployDetermenistic( implementation, data, salt); @@ -62,19 +65,20 @@ contract ProxyManager is /// @dev deploy initial contract function deploy( - address registry, address initialImplementation, bytes memory initializationData ) public virtual onlyInitializing() - returns (IVersionable versionable) + returns (IUpgradeable upgradeable) { - ( - address currentProxyOwner, - address initialProxyAdminOwner - ) = _preDeployChecksAndSetup(registry); + if (_versions.length > 0) { + revert ErrorProxyManagerAlreadyDeployed(); + } + + address currentProxyOwner = getOwner(); // used by implementation + address initialProxyAdminOwner = address(this); // used by proxy _proxy = new UpgradableProxyWithAdmin( initialImplementation, @@ -82,15 +86,14 @@ contract ProxyManager is getDeployData(currentProxyOwner, initializationData) ); - versionable = _updateVersionHistory( + upgradeable = _updateVersionHistory( initialImplementation, currentProxyOwner); - emit LogProxyManagerVersionableDeployed(address(versionable), initialImplementation); + emit LogProxyManagerProxyDeployed(address(upgradeable), initialImplementation); } function deployDetermenistic( - address registry, address initialImplementation, bytes memory initializationData, bytes32 salt @@ -98,12 +101,14 @@ contract ProxyManager is public virtual onlyInitializing() - returns (IVersionable versionable) + returns (IUpgradeable upgradeable) { - ( - address currentProxyOwner, - address initialProxyAdminOwner - ) = _preDeployChecksAndSetup(registry); + if (_versions.length > 0) { + revert ErrorProxyManagerAlreadyDeployed(); + } + + address currentProxyOwner = getOwner(); // used by implementation + address initialProxyAdminOwner = address(this); // used by proxy _proxy = new UpgradableProxyWithAdmin{salt: salt}( initialImplementation, @@ -111,11 +116,11 @@ contract ProxyManager is getDeployData(currentProxyOwner, initializationData) ); - versionable = _updateVersionHistory( + upgradeable = _updateVersionHistory( initialImplementation, currentProxyOwner); - emit LogProxyManagerVersionableDeployed(address(versionable), initialImplementation); + emit LogProxyManagerProxyDeployed(address(upgradeable), initialImplementation); } /// @dev upgrade existing contract. @@ -124,7 +129,7 @@ contract ProxyManager is public virtual onlyOwner() - returns (IVersionable versionable) + returns (IUpgradeable upgradeable) { bytes memory emptyUpgradeData; return upgrade(newImplementation, emptyUpgradeData); @@ -135,7 +140,7 @@ contract ProxyManager is public virtual onlyOwner() - returns (IVersionable versionable) + returns (IUpgradeable upgradeable) { if (_versions.length == 0) { revert ErrorProxyManagerNotYetDeployed(); @@ -150,11 +155,11 @@ contract ProxyManager is newImplementation, getUpgradeData(upgradeData)); - versionable = _updateVersionHistory( + upgradeable = _updateVersionHistory( newImplementation, currentProxyOwner); - emit LogProxyManagerVersionableUpgraded(address(versionable), newImplementation); + emit LogProxyManagerProxyUpgraded(address(upgradeable), newImplementation); } @@ -164,14 +169,14 @@ contract ProxyManager is function getDeployData(address proxyOwner, bytes memory deployData) public pure returns (bytes memory data) { return abi.encodeWithSelector( - IVersionable.initializeVersionable.selector, + IUpgradeable.initialize.selector, proxyOwner, deployData); } function getUpgradeData(bytes memory upgradeData) public pure returns (bytes memory data) { return abi.encodeWithSelector( - IVersionable.upgradeVersionable.selector, + IUpgradeable.upgrade.selector, upgradeData); } @@ -180,7 +185,7 @@ contract ProxyManager is } function getVersion() external view virtual returns(Version) { - return IVersionable(address(_proxy)).getVersion(); + return _versionHistory[_versions[_versions.length]].version; } function getVersionCount() external view returns(uint256) { @@ -195,42 +200,29 @@ contract ProxyManager is return _versionHistory[_version]; } - function _preDeployChecksAndSetup(address registry) - private - returns ( - address currentProxyOwner, - address initialProxyAdminOwner - ) - { - if (_versions.length > 0) { - revert ErrorProxyManagerAlreadyDeployed(); - } - - address initialOwner = msg.sender; - __NftOwnable_init(registry, initialOwner); - - currentProxyOwner = getOwner(); // used by implementation - initialProxyAdminOwner = address(this); // used by proxy - } - function _updateVersionHistory( address implementation, address activatedBy ) private - returns (IVersionable versionable) + returns (IUpgradeable upgradeable) { - versionable = IVersionable(address(_proxy)); - Version newVersion = versionable.getVersion(); + upgradeable = IUpgradeable(address(_proxy)); + Version newVersion = upgradeable.getVersion(); if(newVersion == VersionLib.zeroVersion()) { revert ErrorProxyManagerZeroVersion(); } if(_versions.length > 0) { - if(newVersion.toInt() <= _versions[_versions.length-1].toInt()) { + Version version = _versions[_versions.length-1]; + if(newVersion.toInt() <= version.toInt()) { revert ErrorProxyManagerNextVersionNotIncreasing(newVersion); } + + if(newVersion.toMajorPart() != version.toMajorPart()) { + revert ErrorProxyManagerNextVersionReleaseInvalid(newVersion); + } } // update version history diff --git a/contracts/upgradeability/Versionable.sol b/contracts/upgradeability/Upgradeable.sol similarity index 63% rename from contracts/upgradeability/Versionable.sol rename to contracts/upgradeability/Upgradeable.sol index c19f59470..9bac2bbd3 100644 --- a/contracts/upgradeability/Versionable.sol +++ b/contracts/upgradeability/Upgradeable.sol @@ -3,39 +3,40 @@ pragma solidity ^0.8.20; import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; -import {IVersionable} from "./IVersionable.sol"; -import {Version, VersionLib} from "../type/Version.sol"; +import {IUpgradeable} from "./IUpgradeable.sol"; +import {Version} from "../type/Version.sol"; +import {Versionable} from "../shared/Versionable.sol"; - -abstract contract Versionable is - Initializable, - IVersionable +abstract contract Upgradeable is + Initializable, + Versionable, + IUpgradeable { constructor() { _disableInitializers(); } - function initializeVersionable( + function initialize( address activatedBy, bytes memory data ) - public - initializer() + external { - _initialize(activatedBy, data); + if(_getInitializedVersion() != 0) { + revert InvalidInitialization(); + } + __Upgradeable_init(activatedBy, data); } - function upgradeVersionable( + function upgrade( bytes memory data ) external - reinitializer(VersionLib.toUint64(getVersion())) + reinitializer(getVersion().toInt()) { _upgrade(data); } - function getVersion() public pure virtual returns(Version); - // IMPORTANT each version must implement this function // each implementation MUST use onlyInitialising modifier // each implementation MUST call intializers of all base contracts... @@ -59,4 +60,14 @@ abstract contract Versionable is { revert ErrorVersionableUpgradeNotImplemented(); } + + function __Upgradeable_init( + address activatedBy, + bytes memory data + ) + private + reinitializer(getVersion().toInt()) + { + _initialize(activatedBy, data); + } } \ No newline at end of file diff --git a/foundry.toml b/foundry.toml index cc4c419a9..6ce33de25 100644 --- a/foundry.toml +++ b/foundry.toml @@ -20,7 +20,8 @@ gas_reports = [ "PricingService", "ProductStore", "RegistryService", - "RiskSet" + "RiskSet", + "ContractLib" ] diff --git a/hardhat.config.ts b/hardhat.config.ts index d756d24da..15e408eb9 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -17,11 +17,14 @@ const config: HardhatUserConfig = { enabled: true, runs: 200 } - } + }, }, docgen: require("./docs/config"), networks: { hardhat: { + accounts: { + mnemonic: process.env.WALLET_MNEMONIC || "candy maple cake sugar pudding cream honey rich smooth crumble sweet treat", + }, }, anvil: { chainId: 1337, diff --git a/scripts/deploy_all.ts b/scripts/deploy_all.ts index 512850cbc..498173b65 100644 --- a/scripts/deploy_all.ts +++ b/scripts/deploy_all.ts @@ -13,10 +13,10 @@ import { logger } from "./logger"; * - Deploys all contracts for flight delay */ async function main() { - const { protocolOwner, masterInstanceOwner, instanceOwner, productOwner: fireOwner, investor, customer } = await getNamedAccounts(); + const { protocolOwner, masterInstanceOwner, instanceOwner, productOwner: fireOwner, investor, customer, tokenIssuer, libraryDeployer } = await getNamedAccounts(); loadVerificationQueueState(); - const {services, libraries } = await deployGifContracts(protocolOwner, instanceOwner); + const {services, libraries } = await deployGifContracts(protocolOwner, instanceOwner, tokenIssuer, libraryDeployer); const { fireUsd, fireProduct, firePool } = await deployFireComponentContracts(libraries, services, fireOwner, protocolOwner); await createFireBundleAndPolicy(fireOwner, investor, customer, fireUsd, fireProduct, firePool); diff --git a/scripts/deploy_fire_components.ts b/scripts/deploy_fire_components.ts index 184b23c6c..f3d1ac608 100644 --- a/scripts/deploy_fire_components.ts +++ b/scripts/deploy_fire_components.ts @@ -146,7 +146,6 @@ export async function deployFireComponentContracts(libraries: LibraryAddresses, "FireProduct", fireOwner, [ - await instance.getRegistry(), instanceNftId, fireProductName, fireProductAuthAddress, @@ -163,6 +162,7 @@ export async function deployFireComponentContracts(libraries: LibraryAddresses, TimestampLib: timestampLibAddress, UFixedLib: ufixedLibAddress, VersionLib: versionLibAddress, + VersionPartLib: versionPartLibAddress, ObjectTypeLib: objectTypeLibAddress, } }); @@ -199,7 +199,6 @@ export async function deployFireComponentContracts(libraries: LibraryAddresses, "FirePool", fireOwner, [ - await instance.getRegistry(), fireProductNftId, firePoolName, firePoolAuthAddress, @@ -211,6 +210,7 @@ export async function deployFireComponentContracts(libraries: LibraryAddresses, NftIdLib: nftIdLibAddress, UFixedLib: ufixedLibAddress, VersionLib: versionLibAddress, + VersionPartLib: versionPartLibAddress, ObjectTypeLib: objectTypeLibAddress, } }); diff --git a/scripts/deploy_flightdelay_components.ts b/scripts/deploy_flightdelay_components.ts index 2c40c10ce..4f1aa7c56 100644 --- a/scripts/deploy_flightdelay_components.ts +++ b/scripts/deploy_flightdelay_components.ts @@ -181,7 +181,6 @@ export async function deployFlightDelayComponentContracts(libraries: LibraryAddr "FlightProduct", flightOwner, [ - await instance.getRegistry(), instanceNftId, productName, flightProductAuthAddress, @@ -198,6 +197,7 @@ export async function deployFlightDelayComponentContracts(libraries: LibraryAddr SecondsLib: secondsLibAddress, TimestampLib: timestampLibAddress, VersionLib: versionLibAddress, + VersionPartLib: versionPartLibAddress, } }); const flightProduct = flightProductBaseContract as FlightProduct; @@ -239,7 +239,6 @@ export async function deployFlightDelayComponentContracts(libraries: LibraryAddr "FlightPool", flightOwner, [ - await instance.getRegistry(), flightProductNftId, poolName, flightPoolAuthAddress, @@ -254,6 +253,7 @@ export async function deployFlightDelayComponentContracts(libraries: LibraryAddr SecondsLib: secondsLibAddress, UFixedLib: ufixedLibAddress, VersionLib: versionLibAddress, + VersionPartLib: versionPartLibAddress, } }); const flightPool = flightPoolBaseContract as FlightPool; @@ -295,7 +295,6 @@ export async function deployFlightDelayComponentContracts(libraries: LibraryAddr "FlightOracle", flightOwner, [ - await instance.getRegistry(), flightProductNftId, oracleName, flightOracleAuthAddress, @@ -306,6 +305,7 @@ export async function deployFlightDelayComponentContracts(libraries: LibraryAddr NftIdLib: nftIdLibAddress, LibRequestIdSet: libRequestIdSetAddress, VersionLib: versionLibAddress, + VersionPartLib: versionPartLibAddress, } }); const flightOracle = flightOracleBaseContract as FlightOracle; diff --git a/scripts/deploy_gif.ts b/scripts/deploy_gif.ts index 6facfedea..fcc7359f5 100644 --- a/scripts/deploy_gif.ts +++ b/scripts/deploy_gif.ts @@ -1,5 +1,5 @@ import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers"; -import { AddressLike, resolveAddress } from "ethers"; +import { AddressLike, resolveAddress, HDNodeWallet } from "ethers"; import fs from "fs"; import { ethers } from "hardhat"; import { ChainNft__factory, IRegistry__factory } from "../typechain-types"; @@ -7,7 +7,7 @@ import { getNamedAccounts, printBalance, validateNftOwnerhip } from "./libs/acco import { SKIP_INSTANCE_CREATION, WRITE_ADDRESSES_TO_FILE } from "./libs/constants"; import { InstanceAddresses, MASTER_INSTANCE_OWNER, cloneInstance, deployAndRegisterMasterInstance } from "./libs/instance"; import { LibraryAddresses, deployLibraries } from "./libs/libraries"; -import { RegistryAddresses, deployAndInitializeRegistry } from "./libs/registry"; +import { RegistryAddresses, deployDip, deployAndInitializeRegistry } from "./libs/registry"; import { ServiceAddresses, deployAndRegisterServices } from "./libs/services"; import { loadVerificationQueueState } from "./libs/verification_queue"; import { logger } from "./logger"; @@ -15,20 +15,21 @@ import { printBalances, printGasSpent, setBalanceAfter } from "./libs/gas_and_ba async function main() { - const { protocolOwner, instanceOwner } = await getNamedAccounts(); + const { protocolOwner, masterInstanceOwner, instanceOwner, tokenIssuer, libraryDeployer } = await getNamedAccounts(); loadVerificationQueueState(); - await deployGifContracts(protocolOwner, instanceOwner); + await deployGifContracts(protocolOwner, instanceOwner, tokenIssuer, libraryDeployer); } export async function deployGifContracts( - protocolOwner: HardhatEthersSigner, instanceOwner: HardhatEthersSigner + protocolOwner: HDNodeWallet, instanceOwner: HardhatEthersSigner, tokenIssuer: HardhatEthersSigner, libraryDeployer: HardhatEthersSigner ): Promise<{ services: ServiceAddresses, libraries: LibraryAddresses, registry: RegistryAddresses }> { logger.info("===== deploying GIF contracts"); // deploy protocol contracts - const libraries = await deployLibraries(protocolOwner); - const registry = await deployAndInitializeRegistry(protocolOwner, libraries); + const libraries = await deployLibraries(libraryDeployer); + const dip = await deployDip(tokenIssuer); + const registry = await deployAndInitializeRegistry(protocolOwner, dip, libraries); const services = await deployAndRegisterServices(protocolOwner, registry, libraries); // // deploy instance contracts @@ -162,6 +163,7 @@ function printAddresses( } addresses += `# --------\n`; + addresses += `REGISTRY_AUTHORIZATION_ADDRESS=${registry.registryAuthorizationAddress}\n`; addresses += `REGISTRY_ADMIN_ADDRESS=${registry.registryAdminAddress}\n`; addresses += `RELEASE_REGISTRY_ADDRESS=${registry.releaseRegistryAddress}\n`; addresses += `REGISTRY_ADDRESS=${registry.registryAddress}\n`; diff --git a/scripts/libs/accounts.ts b/scripts/libs/accounts.ts index c63eaaacc..2c9403fe3 100644 --- a/scripts/libs/accounts.ts +++ b/scripts/libs/accounts.ts @@ -1,6 +1,6 @@ import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers"; -import { AddressLike, formatEther, resolveAddress } from "ethers"; -import { ethers } from "hardhat"; +import { AddressLike, formatEther, resolveAddress, HDNodeWallet } from "ethers"; +import { ethers, network } from "hardhat"; import { ChainNft__factory } from "../../typechain-types"; import { logger } from "../logger"; import { resetBalances, setBalanceBefore } from "./gas_and_balance_tracker"; @@ -15,6 +15,8 @@ export async function getNamedAccounts(): Promise<{ instanceOwner: HardhatEthersSigner; customer: HardhatEthersSigner; investor: HardhatEthersSigner; + tokenIssuer: HardhatEthersSigner; + libraryDeployer: HardhatEthersSigner; }> { const signers = await ethers.getSigners(); const protocolOwner = signers[0]; @@ -25,7 +27,10 @@ export async function getNamedAccounts(): Promise<{ const instanceServiceOwner = signers[5]; const customer = signers[6]; const investor = signers[7]; + const tokenIssuer = signers[8]; + const libraryDeployer = signers[9]; const instanceOwner = signers[10]; + await printBalance( ["protocolOwner", protocolOwner] , // ["masterInstanceOwner", masterInstanceOwner] , @@ -33,14 +38,14 @@ export async function getNamedAccounts(): Promise<{ // ["poolOwner", poolOwner], // ["distributionOwner", distributionOwner], // ["instanceServiceOwner", instanceServiceOwner], - ["instanceOwner", instanceOwner], + ["instanceOwner", instanceOwner] ); resetBalances(); setBalanceBefore(await resolveAddress(protocolOwner), await ethers.provider.getBalance(protocolOwner)); setBalanceBefore(await resolveAddress(productOwner), await ethers.provider.getBalance(productOwner)); setBalanceBefore(await resolveAddress(instanceOwner), await ethers.provider.getBalance(instanceOwner)); - return { protocolOwner, masterInstanceOwner, productOwner, poolOwner, distributionOwner, instanceServiceOwner, instanceOwner, customer, investor }; + return { protocolOwner, masterInstanceOwner, productOwner, poolOwner, distributionOwner, instanceServiceOwner, instanceOwner, customer, investor, tokenIssuer, libraryDeployer }; } export async function printBalance(...signers: [string,HardhatEthersSigner][]) { diff --git a/scripts/libs/instance.ts b/scripts/libs/instance.ts index 093dadd7a..b6dfe46da 100644 --- a/scripts/libs/instance.ts +++ b/scripts/libs/instance.ts @@ -38,6 +38,8 @@ export async function deployAndRegisterMasterInstance( logger.info("======== Starting deployment of master instance ========"); + logger.info("-------- Starting deployment of InstanceAuthorizationV3 --------"); + const { address: masterInstanceAuthorizationV3Address } = await deployContract( "InstanceAuthorizationV3", owner, @@ -56,18 +58,21 @@ export async function deployAndRegisterMasterInstance( } ); + logger.info("-------- Starting deployment of master AccessManagerCloneable --------"); + const { address: masterAccessManagerAddress, contract: masterAccessManagerBaseContract } = await deployContract( "AccessManagerCloneable", owner, undefined, { libraries: { - ContractLib: libraries.contractLibAddress, VersionPartLib: libraries.versionPartLibAddress, } } ); + logger.info("-------- Starting deployment of master InstanceAdmin --------"); + const { address: masterInstanceAdminAddress, contract: masterInstanceAdminContract } = await deployContract( "InstanceAdmin", owner, @@ -79,8 +84,8 @@ export async function deployAndRegisterMasterInstance( AccessAdminLib: libraries.accessAdminLibAddress, BlocknumberLib: libraries.blockNumberLibAddress, ContractLib: libraries.contractLibAddress, - NftIdLib: libraries.nftIdLibAddress, RoleIdLib: libraries.roleIdLibAddress, + NftIdLib: libraries.nftIdLibAddress, SelectorSetLib: libraries.selectorSetLibAddress, StrLib: libraries.strLibAddress, TimestampLib: libraries.timestampLibAddress, @@ -90,6 +95,8 @@ export async function deployAndRegisterMasterInstance( ); const masterInstanceAdmin = masterInstanceAdminContract as InstanceAdmin; + logger.info("-------- Starting deployment of master InstanceStore --------"); + const { address: masterInstanceStoreAddress, contract: masterInstanceStoreContract } = await deployContract( "InstanceStore", owner, @@ -110,6 +117,8 @@ export async function deployAndRegisterMasterInstance( ); const masterInstanceStore = masterInstanceStoreContract as InstanceStore; + logger.info("-------- Starting deployment of master ProductStore --------"); + const { address: masterProductStoreAddress, contract: masterProductStoreContract } = await deployContract( "ProductStore", owner, @@ -129,6 +138,8 @@ export async function deployAndRegisterMasterInstance( ); const masterProductStore = masterProductStoreContract as InstanceStore; + logger.info("-------- Starting deployment of master BundleSet --------"); + const {address: masterInstanceBundleSetAddress, contract: masterBundleSetContrat} = await deployContract( "BundleSet", owner, @@ -145,6 +156,8 @@ export async function deployAndRegisterMasterInstance( ); const masterInstanceBundleSet = masterBundleSetContrat as BundleSet; + logger.info("-------- Starting deployment of master RiskSet --------"); + const {address: masterInstanceRiskSetAddress, contract: masterRiskSetContrat} = await deployContract( "RiskSet", owner, @@ -162,6 +175,8 @@ export async function deployAndRegisterMasterInstance( ); const masterInstanceRiskSet = masterRiskSetContrat as RiskSet; + logger.info("-------- Starting deployment of master InstanceReader --------"); + const { address: masterInstanceReaderAddress, contract: masterInstanceReaderContract } = await deployContract( "InstanceReader", owner, @@ -184,6 +199,8 @@ export async function deployAndRegisterMasterInstance( ); const masterInstanceReader = masterInstanceReaderContract as InstanceReader; + logger.info("-------- Starting deployment of master Instance --------"); + const { address: masterInstanceAddress, contract: masterInstanceBaseContract } = await deployContract( "Instance", owner, @@ -192,6 +209,8 @@ export async function deployAndRegisterMasterInstance( libraries: { ContractLib: libraries.contractLibAddress, NftIdLib: libraries.nftIdLibAddress, + VersionLib: libraries.versionLibAddress, + VersionPartLib: libraries.versionPartLibAddress, } } ); @@ -212,8 +231,6 @@ export async function deployAndRegisterMasterInstance( riskSet: masterInstanceRiskSetAddress, instanceReader: masterInstanceReaderAddress }, - registry.registryAddress, - 3, resolveAddress(owner), false, getTxOpts()), @@ -236,9 +253,7 @@ export async function deployAndRegisterMasterInstance( // wire instance admin to registry, instance and instance authorization await executeTx( () => masterInstanceAdmin.completeSetup( - registry.registryAddress, masterInstanceAuthorizationV3Address, - 3, masterInstanceAddress, getTxOpts()), "masterInstanceAdmin completeSetup", diff --git a/scripts/libs/libraries.ts b/scripts/libs/libraries.ts index 53f669206..779e9df88 100644 --- a/scripts/libs/libraries.ts +++ b/scripts/libs/libraries.ts @@ -267,7 +267,6 @@ export async function deployLibraries(owner: Signer): Promise AmountLib: amountLibAddress, ContractLib: contractLibAddress, FeeLib: feeLibAddress, - NftIdLib: nftIdLibAddress, UFixedLib: uFixedLibAddress, } }); diff --git a/scripts/libs/registry.ts b/scripts/libs/registry.ts index f2b32c7a3..7aa1d4268 100644 --- a/scripts/libs/registry.ts +++ b/scripts/libs/registry.ts @@ -14,13 +14,15 @@ import { TargetHandler, Staking__factory, TokenRegistry, - Dip__factory + Dip__factory, + ContractLib__factory } from "../../typechain-types"; import { logger } from "../logger"; import { deployContract, deployProxyManagerContract } from "./deployment"; import { LibraryAddresses } from "./libraries"; import { executeTx, getTxOpts } from "./transaction"; import { prepareVerificationData } from "./verification"; +import { exitOnError } from "winston"; export type RegistryAddresses = { @@ -68,12 +70,8 @@ export type RegistryAddresses = { } -export async function deployAndInitializeRegistry(owner: Signer, libraries: LibraryAddresses): Promise { - - logger.info("======== Starting deployment of registry ========"); - - - const COMMIT_HASH = "1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a"; +export async function deployDip(owner: Signer): Promise { + logger.info("======== Starting deployment of Dip ========"); const existingDipAddress = process.env.DIP_ADDRESS; let dipAddress: AddressLike; @@ -98,9 +96,22 @@ export async function deployAndInitializeRegistry(owner: Signer, libraries: Libr } const dip = dipBaseContract as Dip; - + + logger.info(`Dip deployed at ${dipAddress}`); + logger.info("======== Finished deployment of Dip ========"); + + // const dipMainnetAddress = "0xc719d010b63e5bbf2c0551872cd5316ed26acd83"; + return dip; +} + +export async function deployAndInitializeRegistry(owner: Signer, dip: Dip, libraries: LibraryAddresses): Promise { + + logger.info("======== Starting deployment of registry ========"); + logger.info("-------- Starting deployment RegistryAuthorization ----------------"); + const COMMIT_HASH = "1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a"; + const { address: registryAuthorizationAddress, contract: registryAuthorizationBaseContract } = await deployContract( "RegistryAuthorization", owner, @@ -133,8 +144,8 @@ export async function deployAndInitializeRegistry(owner: Signer, libraries: Libr AccessAdminLib: libraries.accessAdminLibAddress, BlocknumberLib: libraries.blockNumberLibAddress, ContractLib: libraries.contractLibAddress, - NftIdLib: libraries.nftIdLibAddress, RoleIdLib: libraries.roleIdLibAddress, + NftIdLib: libraries.nftIdLibAddress, SelectorSetLib: libraries.selectorSetLibAddress, StrLib: libraries.strLibAddress, TimestampLib: libraries.timestampLibAddress, @@ -155,10 +166,17 @@ export async function deployAndInitializeRegistry(owner: Signer, libraries: Libr libraries: { NftIdLib: libraries.nftIdLibAddress, ObjectTypeLib: libraries.objectTypeLibAddress, + VersionLib: libraries.versionLibAddress, VersionPartLib: libraries.versionPartLibAddress, } }); + const ContractLib = ContractLib__factory.connect(libraries.contractLibAddress.toString(), owner); + const hardcodedRegistryAddress = await ContractLib.REGISTRY_ADDRESS() as AddressLike; + if(registryAddress != hardcodedRegistryAddress) { + throw new Error(`Registry address does not match: ${registryAddress} != ${hardcodedRegistryAddress}`); + } + const registry = registryBaseContract as Registry; const registryNftId = await registry.getNftIdForAddress(registryAddress); @@ -170,7 +188,7 @@ export async function deployAndInitializeRegistry(owner: Signer, libraries: Libr const { address: releaseRegistryAddress, contract: releaseRegistryBaseContract } = await deployContract( "ReleaseRegistry", owner, - [registryAddress], + [], { libraries: { AccessAdminLib: libraries.accessAdminLibAddress, @@ -183,7 +201,6 @@ export async function deployAndInitializeRegistry(owner: Signer, libraries: Libr StateIdLib: libraries.stateIdLibAddress, StrLib: libraries.strLibAddress, TimestampLib: libraries.timestampLibAddress, - VersionLib: libraries.versionLibAddress, VersionPartLib: libraries.versionPartLibAddress, } }); @@ -192,13 +209,12 @@ export async function deployAndInitializeRegistry(owner: Signer, libraries: Libr logger.info("-------- Starting deployment TokenRegistry ----------------"); + const dipAddress = await resolveAddress(dip) as AddressLike; + const { address: tokenRegistryAddress, contract: tokenRegistryBaseContract } = await deployContract( "TokenRegistry", owner, - [ - registryAddress, - dipAddress//dipMainnetAddress - ], + [dipAddress],//dipMainnetAddress { libraries: { ChainIdLib: libraries.chainIdLibAddress, @@ -213,7 +229,7 @@ export async function deployAndInitializeRegistry(owner: Signer, libraries: Libr const { address: stakingReaderAddress, contract: stakingReaderBaseContract } = await deployContract( "StakingReader", owner, - [registryAddress], + [], { libraries: { } @@ -226,10 +242,7 @@ export async function deployAndInitializeRegistry(owner: Signer, libraries: Libr const { address: stakingStoreAddress, contract: stakingStoreBaseContract, } = await deployContract( "StakingStore", owner, - [ - registryAddress, - stakingReaderAddress - ], + [stakingReaderAddress], { libraries: { AmountLib: libraries.amountLibAddress, @@ -253,10 +266,7 @@ export async function deployAndInitializeRegistry(owner: Signer, libraries: Libr const { address: targetHandlerAddress, contract: targetHandlerBaseContract, } = await deployContract( "TargetHandler", owner, - [ - registryAddress, - stakingStoreAddress - ], + [stakingStoreAddress], { libraries: { AmountLib: libraries.amountLibAddress, @@ -289,7 +299,6 @@ export async function deployAndInitializeRegistry(owner: Signer, libraries: Libr "Staking", owner, [ - registryAddress, targetHandlerAddress, stakingStoreAddress, tokenRegistryAddress, @@ -314,7 +323,6 @@ export async function deployAndInitializeRegistry(owner: Signer, libraries: Libr const stakingManager = stakingManagerBaseContract as StakingManager; const staking = Staking__factory.connect(stakingAddress, owner); - const stakingNftId = await registry.getNftIdForAddress(stakingAddress); await executeTx( async () => await stakingReader.initialize(stakingAddress, stakingStoreAddress, getTxOpts()), @@ -328,11 +336,11 @@ export async function deployAndInitializeRegistry(owner: Signer, libraries: Libr [registry.interface] ); + const stakingNftId = await registry.getNftIdForAddress(stakingAddress); + await executeTx( async () => await registryAdmin.completeSetup( - registry, registryAuthorization, - 3, owner, owner, getTxOpts()), diff --git a/scripts/libs/services.ts b/scripts/libs/services.ts index 0f27e94ae..01f8c47da 100644 --- a/scripts/libs/services.ts +++ b/scripts/libs/services.ts @@ -120,17 +120,17 @@ export async function deployAndRegisterServices(owner: Signer, registry: Registr owner, [ authority, // address itself can be a salt like value - registry.registryAddress, release.salt ], { libraries: { - BlocknumberLib: libraries.blockNumberLibAddress, - ContractLib: libraries.contractLibAddress, - NftIdLib: libraries.nftIdLibAddress, - RoleIdLib: libraries.roleIdLibAddress, - TimestampLib: libraries.timestampLibAddress, - VersionLib: libraries.versionLibAddress, - }}); + BlocknumberLib: libraries.blockNumberLibAddress, + ContractLib: libraries.contractLibAddress, + NftIdLib: libraries.nftIdLibAddress, + RoleIdLib: libraries.roleIdLibAddress, + TimestampLib: libraries.timestampLibAddress, + VersionLib: libraries.versionLibAddress, + VersionPartLib: libraries.versionPartLibAddress, + }}); const registryService = RegistryService__factory.connect(registryServiceAddress, owner); @@ -153,7 +153,6 @@ export async function deployAndRegisterServices(owner: Signer, registry: Registr owner, [ authority, - registry.registryAddress, release.salt ], { libraries: { @@ -164,6 +163,7 @@ export async function deployAndRegisterServices(owner: Signer, registry: Registr RoleIdLib: libraries.roleIdLibAddress, TimestampLib: libraries.timestampLibAddress, VersionLib: libraries.versionLibAddress, + VersionPartLib: libraries.versionPartLibAddress, }}); const stakingServiceManager = stakingServiceManagerBaseContract as StakingServiceManager; @@ -179,7 +179,6 @@ export async function deployAndRegisterServices(owner: Signer, registry: Registr owner, [ authority, - registry.registryAddress, release.salt ], { libraries: { @@ -206,7 +205,6 @@ export async function deployAndRegisterServices(owner: Signer, registry: Registr owner, [ authority, - registry.registryAddress, release.salt ], { libraries: { @@ -218,6 +216,7 @@ export async function deployAndRegisterServices(owner: Signer, registry: Registr TimestampLib: libraries.timestampLibAddress, VersionLib: libraries.versionLibAddress, ObjectTypeLib: libraries.objectTypeLibAddress, + VersionPartLib: libraries.versionPartLibAddress, }}); const accountingServiceManager = accountingServiceManagerBaseContract as AccountingServiceManager; @@ -232,7 +231,6 @@ export async function deployAndRegisterServices(owner: Signer, registry: Registr owner, [ authority, - registry.registryAddress, release.salt ], { libraries: { @@ -246,6 +244,7 @@ export async function deployAndRegisterServices(owner: Signer, registry: Registr TimestampLib: libraries.timestampLibAddress, TokenHandlerDeployerLib: libraries.tokenHandlerDeployerLibAddress, VersionLib: libraries.versionLibAddress, + VersionPartLib: libraries.versionPartLibAddress, }}); const componentService = ComponentService__factory.connect(componentServiceAddress, owner); @@ -265,7 +264,6 @@ export async function deployAndRegisterServices(owner: Signer, registry: Registr owner, [ authority, - registry.registryAddress, release.salt ], { libraries: { @@ -274,7 +272,6 @@ export async function deployAndRegisterServices(owner: Signer, registry: Registr ContractLib: libraries.contractLibAddress, DistributorTypeLib: libraries.distributorTypeLibAddress, NftIdLib: libraries.nftIdLibAddress, - PoolLib: libraries.poolLibAddress, ReferralLib: libraries.referralLibAddress, RoleIdLib: libraries.roleIdLibAddress, SecondsLib: libraries.secondsLibAddress, @@ -282,6 +279,7 @@ export async function deployAndRegisterServices(owner: Signer, registry: Registr UFixedLib: libraries.uFixedLibAddress, VersionLib: libraries.versionLibAddress, ObjectTypeLib: libraries.objectTypeLibAddress, + VersionPartLib: libraries.versionPartLibAddress, }}); const distributionServiceManager = distributionServiceManagerBaseContract as DistributionServiceManager; @@ -296,7 +294,6 @@ export async function deployAndRegisterServices(owner: Signer, registry: Registr owner, [ authority, - registry.registryAddress, release.salt ], { libraries: { @@ -308,6 +305,7 @@ export async function deployAndRegisterServices(owner: Signer, registry: Registr TimestampLib: libraries.timestampLibAddress, VersionLib: libraries.versionLibAddress, ObjectTypeLib: libraries.objectTypeLibAddress, + VersionPartLib: libraries.versionPartLibAddress, }}); const pricingServiceManager = pricingServiceManagerBaseContract as PricingServiceManager; @@ -322,7 +320,6 @@ export async function deployAndRegisterServices(owner: Signer, registry: Registr owner, [ authority, - registry.registryAddress, release.salt ], { libraries: { @@ -330,12 +327,12 @@ export async function deployAndRegisterServices(owner: Signer, registry: Registr BlocknumberLib: libraries.blockNumberLibAddress, ContractLib: libraries.contractLibAddress, NftIdLib: libraries.nftIdLibAddress, - PoolLib: libraries.poolLibAddress, RoleIdLib: libraries.roleIdLibAddress, SecondsLib: libraries.secondsLibAddress, TimestampLib: libraries.timestampLibAddress, VersionLib: libraries.versionLibAddress, ObjectTypeLib: libraries.objectTypeLibAddress, + VersionPartLib: libraries.versionPartLibAddress, }}); const bundleServiceManager = bundleServiceManagerBaseContract as BundleServiceManager; @@ -350,7 +347,6 @@ export async function deployAndRegisterServices(owner: Signer, registry: Registr owner, [ authority, - registry.registryAddress, release.salt ], { libraries: { @@ -363,6 +359,7 @@ export async function deployAndRegisterServices(owner: Signer, registry: Registr TimestampLib: libraries.timestampLibAddress, VersionLib: libraries.versionLibAddress, ObjectTypeLib: libraries.objectTypeLibAddress, + VersionPartLib: libraries.versionPartLibAddress, }}); const poolServiceManager = poolServiceManagerBaseContract as PoolServiceManager; @@ -377,7 +374,6 @@ export async function deployAndRegisterServices(owner: Signer, registry: Registr owner, [ authority, - registry.registryAddress, release.salt ], { libraries: { @@ -388,7 +384,7 @@ export async function deployAndRegisterServices(owner: Signer, registry: Registr RoleIdLib: libraries.roleIdLibAddress, TimestampLib: libraries.timestampLibAddress, VersionLib: libraries.versionLibAddress, - ObjectTypeLib: libraries.objectTypeLibAddress, + VersionPartLib: libraries.versionPartLibAddress, }}); const oracleServiceManager = oracleServiceManagerBaseContract as OracleServiceManager; @@ -403,7 +399,6 @@ export async function deployAndRegisterServices(owner: Signer, registry: Registr owner, [ authority, - registry.registryAddress, release.salt ], { libraries: { @@ -414,6 +409,7 @@ export async function deployAndRegisterServices(owner: Signer, registry: Registr RoleIdLib: libraries.roleIdLibAddress, TimestampLib: libraries.timestampLibAddress, VersionLib: libraries.versionLibAddress, + VersionPartLib: libraries.versionPartLibAddress, }}); const riskServiceManager = riskServiceManagerBaseContract as RiskServiceManager; @@ -428,7 +424,6 @@ export async function deployAndRegisterServices(owner: Signer, registry: Registr owner, [ authority, - registry.registryAddress, release.salt ], { libraries: { @@ -441,6 +436,7 @@ export async function deployAndRegisterServices(owner: Signer, registry: Registr TimestampLib: libraries.timestampLibAddress, VersionLib: libraries.versionLibAddress, ObjectTypeLib: libraries.objectTypeLibAddress, + VersionPartLib: libraries.versionPartLibAddress, }}); const policyServiceManager = policyServiceManagerBaseContract as PolicyServiceManager; @@ -455,7 +451,6 @@ export async function deployAndRegisterServices(owner: Signer, registry: Registr owner, [ authority, - registry.registryAddress, release.salt ], { libraries: { @@ -469,6 +464,7 @@ export async function deployAndRegisterServices(owner: Signer, registry: Registr TimestampLib: libraries.timestampLibAddress, VersionLib: libraries.versionLibAddress, ObjectTypeLib: libraries.objectTypeLibAddress, + VersionPartLib: libraries.versionPartLibAddress, }}); const claimServiceManager = claimServiceManagerBaseContract as ClaimServiceManager; @@ -483,7 +479,6 @@ export async function deployAndRegisterServices(owner: Signer, registry: Registr owner, [ authority, - registry.registryAddress, release.salt ], { libraries: { @@ -496,6 +491,7 @@ export async function deployAndRegisterServices(owner: Signer, registry: Registr TimestampLib: libraries.timestampLibAddress, VersionLib: libraries.versionLibAddress, ObjectTypeLib: libraries.objectTypeLibAddress, + VersionPartLib: libraries.versionPartLibAddress, }}); const applicationServiceManager = applicationServiceManagerBaseContract as ApplicationServiceManager; diff --git a/test/Component.t.sol b/test/Component.t.sol index b906369c2..2f8f9a633 100644 --- a/test/Component.t.sol +++ b/test/Component.t.sol @@ -60,7 +60,7 @@ contract TestComponent is GifTest { address externallyOwnerWallet = makeAddr("externallyOwnerWallet"); - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(distribution.getWallet(), INITIAL_BALANCE); vm.stopPrank(); @@ -146,7 +146,7 @@ contract TestComponent is GifTest { address externallyOwnedWallet = makeAddr("externallyOwnedWallet"); // put some tokens in the distribution wallet - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(address(distribution.getTokenHandler()), INITIAL_BALANCE); vm.stopPrank(); @@ -173,7 +173,7 @@ contract TestComponent is GifTest { assertEq(distribution.getWallet(), externallyOwnedWallet, "wallet not externallyOwnedWallet"); // put some tokens in the externally owned wallet - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(address(externallyOwnedWallet), INITIAL_BALANCE); vm.stopPrank(); @@ -205,7 +205,7 @@ contract TestComponent is GifTest { assertEq(distribution.getWallet(), externallyOwnedWallet, "wallet not externallyOwnedWallet"); // put some tokens in the externally owned wallet - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(address(externallyOwnedWallet), INITIAL_BALANCE); vm.stopPrank(); @@ -232,7 +232,7 @@ contract TestComponent is GifTest { address externallyOwnedWallet2 = makeAddr("externallyOwnedWallet2"); // put some tokens in the externally owned wallet - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(address(externallyOwnedWallet), INITIAL_BALANCE); vm.stopPrank(); diff --git a/test/ProxyManager.t.sol b/test/ProxyManager.t.sol index 65cf3e312..e2ca98a1f 100644 --- a/test/ProxyManager.t.sol +++ b/test/ProxyManager.t.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.20; import {Test, Vm, console} from "../lib/forge-std/src/Test.sol"; -import {VersionLib} from "../contracts/type/Version.sol"; -import {IVersionable} from "../contracts/upgradeability/IVersionable.sol"; +import {VersionLib, VersionPartLib, VersionPart} from "../contracts/type/Version.sol"; +import {IUpgradeable} from "../contracts/upgradeability/IUpgradeable.sol"; import {ProxyManager} from "../contracts/upgradeability/ProxyManager.sol"; import {GifTest} from "./base/GifTest.sol"; @@ -20,23 +20,22 @@ contract ProxyManagerTest is GifTest { assertTrue(address(proxyManager) != address(0), "proxyManager address zero"); bytes memory initializationData = abi.encode(uint(42)); - IVersionable versionable = proxyManager.initialize( - address(registry), + IUpgradeable upgradeable = proxyManager.initialize( address(new ContractV01()), initializationData, bytes32("")); // solhint-disable-next-line - console.log("versionable[address]", address(versionable)); - assertTrue(address(versionable) != address(0), "versionable address zero"); + console.log("upgradeable[address]", address(upgradeable)); + assertTrue(address(upgradeable) != address(0), "upgradeable address zero"); // solhint-disable-next-line - console.log("version[int]", versionable.getVersion().toInt()); - assertTrue(versionable.getVersion() == VersionLib.toVersion(1,0,0), "version not (1,0,0)"); + console.log("version[int]", upgradeable.getVersion().toInt()); + assertTrue(upgradeable.getVersion() == VersionLib.toVersion(3,0,0), "version not (3,0,0)"); - ContractV01 productV1 = ContractV01(address(versionable)); + ContractV01 productV1 = ContractV01(address(upgradeable)); assertEq(productV1.getDataV01(), "hi from version 1", "unexpected message for getDataV01"); - ContractV02 productV2 = ContractV02(address(versionable)); + ContractV02 productV2 = ContractV02(address(upgradeable)); vm.expectRevert(); productV2.getDataV02(); } @@ -44,18 +43,18 @@ contract ProxyManagerTest is GifTest { function testProductV01DeployAndUpgrade() public { ProxyManager proxyManager = new ProxyManager(); + VersionPart release = VersionPartLib.toVersionPart(4); bytes memory initializationData = abi.encode(uint(0)); bytes memory upgradeData = abi.encode(uint(0)); - IVersionable versionable = proxyManager.initialize( - address(registry), - address(new ContractV01()), + IUpgradeable upgradeable = proxyManager.initialize( + address(new ContractV01()), initializationData, bytes32("")); proxyManager.upgrade(address(new ContractV02()), upgradeData); - assertTrue(versionable.getVersion() == VersionLib.toVersion(1,0,1), "version not (1,0,1)"); + assertTrue(upgradeable.getVersion() == VersionLib.toVersion(3,0,1), "version not (3,0,1)"); - ContractV02 productV2 = ContractV02(address(versionable)); + ContractV02 productV2 = ContractV02(address(upgradeable)); assertEq(productV2.getDataV01(), "hi from version 1", "unexpected message for getDataV01"); assertEq(productV2.getDataV02(), "hi from version 2", "unexpected message for getDataV02"); } @@ -68,8 +67,7 @@ contract ProxyManagerTest is GifTest { vm.recordLogs(); bytes memory initializationData = abi.encode(uint(0)); proxyManager.initialize( - address(registry), - address(new ContractV01()), + address(new ContractV01()), initializationData, bytes32("")); diff --git a/test/TestBundle.t.sol b/test/TestBundle.t.sol index f1ecfabb2..13be97cdd 100644 --- a/test/TestBundle.t.sol +++ b/test/TestBundle.t.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.20; import {console} from "../lib/forge-std/src/Test.sol"; -import {INftOwnable} from "../contracts/shared/INftOwnable.sol"; +import {IRegisterable} from "../contracts/shared/IRegisterable.sol"; import {Amount, AmountLib} from "../contracts/type/Amount.sol"; import {BasicPoolAuthorization} from "../contracts/pool/BasicPoolAuthorization.sol"; @@ -19,8 +19,10 @@ import {ObjectType, BUNDLE, PRODUCT} from "../contracts/type/ObjectType.sol"; import {Pool} from "../contracts/pool/Pool.sol"; import {IPoolService} from "../contracts/pool/IPoolService.sol"; import {PUBLIC_ROLE} from "../contracts/type/RoleId.sol"; +import {GIF_INITIAL_RELEASE} from "../contracts/registry/Registry.sol"; import {ReferralLib} from "../contracts/type/Referral.sol"; import {RiskId, RiskIdLib} from "../contracts/type/RiskId.sol"; +import {GIF_INITIAL_RELEASE} from "../contracts/registry/Registry.sol"; import {Seconds, SecondsLib} from "../contracts/type/Seconds.sol"; import {SimplePool} from "../contracts/examples/unpermissioned/SimplePool.sol"; import {StateId, ACTIVE, PAUSED, CLOSED} from "../contracts/type/StateId.sol"; @@ -70,7 +72,7 @@ contract TestBundle is GifTest { // THEN - expect log event vm.expectEmit(); - emit IPoolService.LogPoolServiceBundleStaked(instanceNftId, poolNftId, bundleNftId, stakeAmt, stakeNetAmt); + emit IPoolService.LogPoolServiceBundleStaked(poolNftId, bundleNftId, stakeAmt, stakeNetAmt); // WHEN - pool is staked with another 1000 tokens pool.stake(bundleNftId, stakeAmt); @@ -124,7 +126,7 @@ contract TestBundle is GifTest { // THEN - expect log event vm.expectEmit(); - emit IPoolService.LogPoolServiceBundleStaked(instanceNftId, poolNftId, bundleNftId, stakeAmt, stakeNetAmt); + emit IPoolService.LogPoolServiceBundleStaked(poolNftId, bundleNftId, stakeAmt, stakeNetAmt); // WHEN - pool is staked with another 1000 tokens pool.stake(bundleNftId, stakeAmt); @@ -345,9 +347,10 @@ contract TestBundle is GifTest { // THEN - revert vm.expectRevert(abi.encodeWithSelector( - INftOwnable.ErrorNftOwnableInvalidType.selector, + IRegisterable.ErrorRegisterableInvalidType.selector, productNftId, - BUNDLE() + BUNDLE(), + GIF_INITIAL_RELEASE() )); // WHEN - nft is not a bundle @@ -389,7 +392,7 @@ contract TestBundle is GifTest { // THEN - expect log event vm.expectEmit(); - emit IPoolService.LogPoolServiceBundleUnstaked(instanceNftId, poolNftId, bundleNftId, unstakeAmt, unstakeAmt); + emit IPoolService.LogPoolServiceBundleUnstaked(poolNftId, bundleNftId, unstakeAmt, unstakeAmt); // WHEN - 500 tokens are unstaked pool.unstake(bundleNftId, unstakeAmt); @@ -441,7 +444,7 @@ contract TestBundle is GifTest { // THEN - expect log event vm.expectEmit(); - emit IPoolService.LogPoolServiceBundleUnstaked(instanceNftId, poolNftId, bundleNftId, expectedUnstakeAmount, expectedUnstakeAmount); + emit IPoolService.LogPoolServiceBundleUnstaked(poolNftId, bundleNftId, expectedUnstakeAmount, expectedUnstakeAmount); // WHEN - max tokens are unstaked pool.unstake(bundleNftId, unstakeAmount); @@ -588,9 +591,10 @@ contract TestBundle is GifTest { // THEN - expect revert vm.expectRevert(abi.encodeWithSelector( - INftOwnable.ErrorNftOwnableInvalidType.selector, + IRegisterable.ErrorRegisterableInvalidType.selector, productNftId, - BUNDLE() + BUNDLE(), + GIF_INITIAL_RELEASE() )); // WHEN - unstaking with an invalid nft type is attempted @@ -1091,7 +1095,7 @@ contract TestBundle is GifTest { } function _fundInvestor(uint256 amount) internal { - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(investor, amount); vm.stopPrank(); } diff --git a/test/TestFees.t.sol b/test/TestFees.t.sol index 472cf6076..ea4d3f74c 100644 --- a/test/TestFees.t.sol +++ b/test/TestFees.t.sol @@ -476,6 +476,7 @@ contract TestFees is GifTest { // THEN - expect a log entry for the fee withdrawal vm.expectEmit(); emit IPoolService.LogPoolServiceFeesWithdrawn( + poolNftId, bundleNftId, investor, address(token), @@ -518,6 +519,7 @@ contract TestFees is GifTest { // THEN - expect a log entry for the fee withdrawal vm.expectEmit(); emit IPoolService.LogPoolServiceFeesWithdrawn( + poolNftId, bundleNftId, investor, address(token), @@ -574,6 +576,7 @@ contract TestFees is GifTest { // THEN - expect a log entry for the fee withdrawal vm.expectEmit(); emit IPoolService.LogPoolServiceFeesWithdrawn( + poolNftId, bundleNftId, investor, address(token), @@ -674,7 +677,7 @@ contract TestFees is GifTest { function _setupWithActivePolicy(bool purchaseWithReferral) internal returns (NftId policyNftId) { - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(customer, 1000); vm.stopPrank(); diff --git a/test/TestPool.t.sol b/test/TestPool.t.sol index 3e883501c..2d7f3285a 100644 --- a/test/TestPool.t.sol +++ b/test/TestPool.t.sol @@ -37,7 +37,6 @@ contract TestPool is GifTest { function test_poolContractLocations() public { newPool = new SimplePool( - address(registry), productNftId, _getDefaultSimplePoolInfo(), new BasicPoolAuthorization("NewSimplePool"), @@ -417,7 +416,7 @@ contract TestPool is GifTest { } function _fundInvestor(uint256 amount) internal { - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(investor, amount); vm.stopPrank(); diff --git a/test/authorization/AccessAdmin.t.sol b/test/authorization/AccessAdmin.t.sol index 26312d21b..702b1c49a 100644 --- a/test/authorization/AccessAdmin.t.sol +++ b/test/authorization/AccessAdmin.t.sol @@ -34,14 +34,14 @@ contract AccessAdminForTesting is AccessAdmin { RoleId internal _managerRoleId; // constructor as in registry admin - constructor() { + constructor(VersionPart release) { initialize( address(new AccessManagerCloneable()), - "TestAdmin"); + "TestAdmin", + release); } function completeSetup( - address registry, VersionPart release ) public @@ -51,11 +51,6 @@ contract AccessAdminForTesting is AccessAdmin { // this can be enforced when the contract is created and the setup is completed in a single tx. address deployer = msg.sender; - // link access manager to registry and release - AccessManagerCloneable(authority()).completeSetup( - registry, - release); - // create targets for testing _createTarget(address(this), "AccessAdmin", IAccess.TargetType.Core, false); @@ -275,17 +270,16 @@ contract AccessAdminBaseTest is Test { vm.startPrank(accessAdminDeployer); // create access admin for testing - accessAdmin = new AccessAdminForTesting(); + release = VersionPartLib.toVersionPart(3); + accessAdmin = new AccessAdminForTesting(release); // create registry and release version registryAdmin = new RegistryAdmin(); registry = new Registry(registryAdmin, globalRegistry); - release = VersionPartLib.toVersionPart(3); // complete setup (which links internal acccess manager to registry and release) // and grants manager role to deployer accessAdmin.completeSetup( - address(registry), release); vm.stopPrank(); diff --git a/test/authorization/AccessManagerCloneable.t.sol b/test/authorization/AccessManagerCloneable.t.sol index aa4b6e906..fbfce955d 100644 --- a/test/authorization/AccessManagerCloneable.t.sol +++ b/test/authorization/AccessManagerCloneable.t.sol @@ -1,32 +1,22 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; -import {IAccessManaged} from "../../lib/openzeppelin-contracts/contracts/access/manager/IAccessManaged.sol"; import {Test, console} from "../../lib/forge-std/src/Test.sol"; - import {AccessManagerCloneable} from "../../contracts/authorization/AccessManagerCloneable.sol"; -import {AccessManagedMock} from "../mock/AccessManagedMock.sol"; import {ContractLib} from "../../contracts/shared/ContractLib.sol"; -import {RegistryAdmin} from "../../contracts/registry/RegistryAdmin.sol"; -import {Registry} from "../../contracts/registry/Registry.sol"; import {VersionPart, VersionPartLib} from "../../contracts/type/Version.sol"; -contract AccessManagerCloneableTesting is AccessManagerCloneable { - function setRelase(VersionPart release) public { - _checkAndSetRelease(release); - } -} contract AccessManagerCloneableTest is Test { address public admin = makeAddr("accessManagerAdmin"); - AccessManagerCloneableTesting public accessManager; + AccessManagerCloneable public accessManager; function setUp() public virtual { - accessManager = new AccessManagerCloneableTesting(); - accessManager.initialize(admin); - accessManager.setRelase(VersionPartLib.toVersionPart(3)); + VersionPart release = VersionPartLib.toVersionPart(3); + accessManager = new AccessManagerCloneable(); + accessManager.initialize(admin, release); } diff --git a/test/authorization/AccessManagerCloneableEx.t.sol b/test/authorization/AccessManagerCloneableEx.t.sol index e1fb3bcb5..6703f5989 100644 --- a/test/authorization/AccessManagerCloneableEx.t.sol +++ b/test/authorization/AccessManagerCloneableEx.t.sol @@ -6,10 +6,7 @@ import {Test, console} from "../../lib/forge-std/src/Test.sol"; import {AccessManagerCloneable} from "../../contracts/authorization/AccessManagerCloneable.sol"; -import {AccessManagerCloneableTest} from "./AccessManagerCloneable.t.sol"; import {AccessManagedMock} from "../mock/AccessManagedMock.sol"; -import {RegistryAdmin} from "../../contracts/registry/RegistryAdmin.sol"; -import {Registry} from "../../contracts/registry/Registry.sol"; import {VersionPart, VersionPartLib} from "../../contracts/type/Version.sol"; @@ -22,20 +19,15 @@ contract AccessManagerCloneableExtendedTest is Test { address public admin = makeAddr("accessManagerAdmin"); AccessManagerCloneable public accessManager; - RegistryAdmin registryAdmin; - Registry registry; AccessManagedMock accessManaged; function setUp() public { + VersionPart release = VersionPartLib.toVersionPart(3); accessManager = new AccessManagerCloneable(); - accessManager.initialize(admin); + accessManager.initialize(admin, release); - registryAdmin = new RegistryAdmin(); - registry = new Registry(registryAdmin, globalRegistry); - - VersionPart version = VersionPartLib.toVersionPart(3); - vm.prank(admin); - accessManager.completeSetup(address(registry), version); + //vm.prank(admin); + //accessManager.completeSetup(address(registry)); accessManaged = new AccessManagedMock(address(accessManager)); diff --git a/test/authorization/RegistryAdminEx.sol b/test/authorization/RegistryAdminEx.sol index 7a4121bea..c0a0831f3 100644 --- a/test/authorization/RegistryAdminEx.sol +++ b/test/authorization/RegistryAdminEx.sol @@ -14,9 +14,7 @@ contract RegistryAdminEx is RegistryAdmin { AccessManagedMock public accessManagedMock; function completeSetup( - address registry, address authorization, - VersionPart release, address gifAdmin, address gifManager ) @@ -24,9 +22,7 @@ contract RegistryAdminEx is RegistryAdmin { virtual override { super.completeSetup( - registry, authorization, - release, gifAdmin, gifManager); diff --git a/test/base/GifClusterTest.sol b/test/base/GifClusterTest.sol index d0c2e6082..5f8db72ec 100644 --- a/test/base/GifClusterTest.sol +++ b/test/base/GifClusterTest.sol @@ -178,7 +178,6 @@ contract GifClusterTest is GifTest { IComponents.FeeInfo memory feeInfo = _getSimpleFeeInfo(); return new SimpleProduct( - address(registry), instanceNftId, name, productInfo, @@ -196,7 +195,6 @@ contract GifClusterTest is GifTest { returns(SimpleDistribution) { return new SimpleDistribution( - address(registry), productNftId, new BasicDistributionAuthorization(name), owner); @@ -211,7 +209,6 @@ contract GifClusterTest is GifTest { returns(SimpleOracle) { return new SimpleOracle( - address(registry), productNftId, new BasicOracleAuthorization(name, COMMIT_HASH), owner); @@ -226,7 +223,6 @@ contract GifClusterTest is GifTest { returns(SimplePool) { return new SimplePool( - address(registry), productNftId, _getDefaultSimplePoolInfo(), new BasicPoolAuthorization(name), @@ -259,7 +255,7 @@ contract GifClusterTest is GifTest { function _fundInstanceOwnerAndCreateApprovals() internal { - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(instanceOwner, INSTANCE_OWNER_FUNDING); vm.stopPrank(); diff --git a/test/base/GifDeployer.sol b/test/base/GifDeployer.sol index 52f3a4dfc..9f3746169 100644 --- a/test/base/GifDeployer.sol +++ b/test/base/GifDeployer.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; +import {Create2} from "@openzeppelin/contracts/utils/Create2.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {AccessManager} from "@openzeppelin/contracts/access/manager/AccessManager.sol"; import {Test, console} from "../../lib/forge-std/src/Test.sol"; @@ -15,12 +16,13 @@ import {IServiceAuthorization} from "../../contracts/authorization/IServiceAutho import {AmountLib} from "../../contracts/type/Amount.sol"; import {ObjectType, ObjectTypeLib} from "../../contracts/type/ObjectType.sol"; import {ChainNft} from "../../contracts/registry/ChainNft.sol"; +import {ContractLib} from "../../contracts/shared/ContractLib.sol"; import {NftId, NftIdLib} from "../../contracts/type/NftId.sol"; import {ProxyManager} from "../../contracts/upgradeability/ProxyManager.sol"; import {SCHEDULED, DEPLOYING} from "../../contracts/type/StateId.sol"; import {VersionPart, VersionPartLib} from "../../contracts/type/Version.sol"; import {RegistryAuthorization} from "../../contracts/registry/RegistryAuthorization.sol"; -import {RoleId} from "../../contracts/type/RoleId.sol"; +import {RoleId, GIF_ADMIN_ROLE, GIF_MANAGER_ROLE} from "../../contracts/type/RoleId.sol"; import {StateIdLib} from "../../contracts/type/StateId.sol"; import {TimestampLib} from "../../contracts/type/Timestamp.sol"; @@ -70,7 +72,6 @@ import {StakingServiceManager} from "../../contracts/staking/StakingServiceManag contract GifDeployer is Test { - uint8 public constant GIF_RELEASE = 3; string public constant COMMIT_HASH = "1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a"; struct DeployedServiceInfo { @@ -81,10 +82,10 @@ contract GifDeployer is Test { // global accounts address public globalRegistry = makeAddr("globalRegistry"); - address public registryOwner = makeAddr("registryOwner"); - address public stakingOwner = registryOwner; - address public gifAdmin = registryOwner; - address public gifManager = registryOwner; + address public stakingOwner = makeAddr("stakingOwner"); + address public gifAdmin = makeAddr("gifAdmin"); + address public gifManager;// must be different from gifAdmin + address public tokenIssuer = makeAddr("tokenIssuer"); // deploy core IERC20Metadata public dip; @@ -92,6 +93,7 @@ contract GifDeployer is Test { TokenRegistry public tokenRegistry; ReleaseRegistry public releaseRegistry; RegistryAdmin public registryAdmin; + RegistryAuthorization public registryAuthorization; StakingManager public stakingManager; Staking public staking; @@ -161,12 +163,7 @@ contract GifDeployer is Test { mapping(ObjectType domain => DeployedServiceInfo info) public serviceForDomain; - function deployCore( - address globalRegistry, - address gifAdmin, - address gifManager, - address stakingOwner - ) + function deployCore() public returns ( IERC20Metadata dip, @@ -178,12 +175,17 @@ contract GifDeployer is Test { Staking staking ) { - // solhint-disable - vm.startPrank(gifManager); + // derive gif manager address + string memory mnemonic = "candy maple cake sugar pudding cream honey rich smooth crumble sweet treat";//vm.envString("WALLET_MNEMONIC"); + (gifManager, ) = deriveRememberKey(mnemonic, 0); + // solhint-disable console.log("1) deploy dip token"); + vm.prank(tokenIssuer); dip = new Dip(); + vm.startPrank(gifManager); + console.log("2) deploy registry contracts"); ( registry, @@ -192,11 +194,17 @@ contract GifDeployer is Test { registryAdmin ) = _deployRegistry(dip); + vm.stopPrank(); + vm.startPrank(stakingOwner); + console.log("3) deploy staking contracts"); ( stakingManager, staking - ) = _deployStaking(registry, tokenRegistry); + ) = _deployStaking(tokenRegistry); + + vm.stopPrank(); + vm.startPrank(gifManager); console.log("4) complete setup for GIF core contracts"); @@ -211,9 +219,7 @@ contract GifDeployer is Test { console.log(" c) complete registry admin setup"); registryAdmin.completeSetup( - address(registry), - address(new RegistryAuthorization(COMMIT_HASH)), - VersionPartLib.toVersionPart(GIF_RELEASE), + address(registryAuthorization), gifAdmin, gifManager); @@ -223,7 +229,6 @@ contract GifDeployer is Test { // solhint-disable enable } - function _deployRegistry(IERC20Metadata dip) internal returns ( @@ -233,23 +238,27 @@ contract GifDeployer is Test { RegistryAdmin registryAdmin ) { + console.log(" a) deploy registry authorizaion"); + registryAuthorization = new RegistryAuthorization(COMMIT_HASH); - console.log(" a) deploy registry admin"); + console.log(" b) deploy registry admin"); registryAdmin = new RegistryAdmin(); - console.log(" b) deploy registry"); + console.log(" c) deploy registry"); registry = new Registry(registryAdmin, globalRegistry); - console.log(" c) deploy release registry"); - releaseRegistry = new ReleaseRegistry(registry); + console.log("registry deployed to ", address(registry)); + require(registry == ContractLib.getRegistry(), "deloyed registry address differs from hardcoded"); + + console.log(" d) deploy release registry"); + releaseRegistry = new ReleaseRegistry(); - console.log(" d) deploy token registry"); - tokenRegistry = new TokenRegistry(registry, dip); + console.log(" e) deploy token registry"); + tokenRegistry = new TokenRegistry(dip); } function _deployStaking( - Registry registry, TokenRegistry tokenRegistry ) internal @@ -259,21 +268,18 @@ contract GifDeployer is Test { ) { console.log(" a) deploy staking reader"); - StakingReader stakingReader = new StakingReader(registry); + StakingReader stakingReader = new StakingReader(); console.log(" b) deploy staking store"); StakingStore stakingStore = new StakingStore( - registry, stakingReader); console.log(" c) deploy target handler"); TargetHandler targetHandler = new TargetHandler( - registry, stakingStore); console.log(" d) deploy staking manager (including upgradeable staking)"); stakingManager = new StakingManager( - address(registry), address(targetHandler), address(stakingStore), address(tokenRegistry), @@ -295,23 +301,21 @@ contract GifDeployer is Test { function deployRelease( ReleaseRegistry releaseRegistry, - IServiceAuthorization serviceAuthorization, - address admin, - address manager + IServiceAuthorization serviceAuthorization ) public { - vm.startPrank(admin); + vm.startPrank(gifAdmin); releaseRegistry.createNextRelease(); vm.stopPrank(); - vm.startPrank(manager); + vm.startPrank(gifManager); _deployReleaseServices( releaseRegistry, serviceAuthorization); vm.stopPrank(); - vm.startPrank(admin); + vm.startPrank(gifAdmin); releaseRegistry.activateNextRelease(); vm.stopPrank(); } @@ -397,59 +401,59 @@ contract GifDeployer is Test { { address registryAddress = address(releaseRegistry.getRegistry()); - registryServiceManager = new RegistryServiceManager{salt: salt}(authority, registryAddress, salt); + registryServiceManager = new RegistryServiceManager{salt: salt}(authority, salt); registryService = registryServiceManager.getRegistryService(); registryServiceNftId = _registerService(releaseRegistry, registryServiceManager, registryService); - stakingServiceManager = new StakingServiceManager{salt: salt}(authority, registryAddress, salt); + stakingServiceManager = new StakingServiceManager{salt: salt}(authority, salt); stakingService = stakingServiceManager.getStakingService(); stakingServiceNftId = _registerService(releaseRegistry, stakingServiceManager, stakingService); - instanceServiceManager = new InstanceServiceManager{salt: salt}(authority, registryAddress, salt); + instanceServiceManager = new InstanceServiceManager{salt: salt}(authority, salt); instanceService = instanceServiceManager.getInstanceService(); instanceServiceNftId = _registerService(releaseRegistry, instanceServiceManager, instanceService); - accountingServiceManager = new AccountingServiceManager{salt: salt}(authority, registryAddress, salt); + accountingServiceManager = new AccountingServiceManager{salt: salt}(authority, salt); accountingService = accountingServiceManager.getAccountingService(); accountingServiceNftId = _registerService(releaseRegistry, accountingServiceManager, accountingService); - componentServiceManager = new ComponentServiceManager{salt: salt}(authority, registryAddress, salt); + componentServiceManager = new ComponentServiceManager{salt: salt}(authority, salt); componentService = componentServiceManager.getComponentService(); componentServiceNftId = _registerService(releaseRegistry, componentServiceManager, componentService); - distributionServiceManager = new DistributionServiceManager{salt: salt}(authority, registryAddress, salt); + distributionServiceManager = new DistributionServiceManager{salt: salt}(authority, salt); distributionService = distributionServiceManager.getDistributionService(); distributionServiceNftId = _registerService(releaseRegistry, distributionServiceManager, distributionService); - pricingServiceManager = new PricingServiceManager{salt: salt}(authority, registryAddress, salt); + pricingServiceManager = new PricingServiceManager{salt: salt}(authority, salt); pricingService = pricingServiceManager.getPricingService(); pricingServiceNftId = _registerService(releaseRegistry, pricingServiceManager, pricingService); - bundleServiceManager = new BundleServiceManager{salt: salt}(authority, registryAddress, salt); + bundleServiceManager = new BundleServiceManager{salt: salt}(authority, salt); bundleService = bundleServiceManager.getBundleService(); bundleServiceNftId = _registerService(releaseRegistry, bundleServiceManager, bundleService); - poolServiceManager = new PoolServiceManager{salt: salt}(authority, registryAddress, salt); + poolServiceManager = new PoolServiceManager{salt: salt}(authority, salt); poolService = poolServiceManager.getPoolService(); poolServiceNftId = _registerService(releaseRegistry, poolServiceManager, poolService); - oracleServiceManager = new OracleServiceManager{salt: salt}(authority, registryAddress, salt); + oracleServiceManager = new OracleServiceManager{salt: salt}(authority, salt); oracleService = oracleServiceManager.getOracleService(); oracleServiceNftId = _registerService(releaseRegistry, oracleServiceManager, oracleService); - riskServiceManager = new RiskServiceManager{salt: salt}(authority, registryAddress, salt); + riskServiceManager = new RiskServiceManager{salt: salt}(authority, salt); riskService = riskServiceManager.getRiskService(); riskServiceNftId = _registerService(releaseRegistry, riskServiceManager, riskService); - policyServiceManager = new PolicyServiceManager{salt: salt}(authority, registryAddress, salt); + policyServiceManager = new PolicyServiceManager{salt: salt}(authority, salt); policyService = policyServiceManager.getPolicyService(); policyServiceNftId = _registerService(releaseRegistry, policyServiceManager, policyService); - claimServiceManager = new ClaimServiceManager{salt: salt}(authority, registryAddress, salt); + claimServiceManager = new ClaimServiceManager{salt: salt}(authority, salt); claimService = claimServiceManager.getClaimService(); claimServiceNftId = _registerService(releaseRegistry, claimServiceManager, claimService); - applicationServiceManager = new ApplicationServiceManager{salt: salt}(authority, registryAddress, salt); + applicationServiceManager = new ApplicationServiceManager{salt: salt}(authority, salt); applicationService = applicationServiceManager.getApplicationService(); applicationServiceNftId = _registerService(releaseRegistry, applicationServiceManager, applicationService); @@ -494,19 +498,15 @@ contract GifDeployer is Test { assertEq(a.nftId.toInt(), b.nftId.toInt(), "getObjectInfo(address).nftId returned unexpected value"); assertEq(a.parentNftId.toInt(), b.parentNftId.toInt(), "getObjectInfo(address).parentNftId returned unexpected value"); assertEq(a.objectType.toInt(), b.objectType.toInt(), "getObjectInfo(address).objectType returned unexpected value"); + assertEq(a.release.toInt(), b.release.toInt(), "getObjectInfo(address).release returned unexpected value"); assertEq(a.objectAddress, b.objectAddress, "getObjectInfo(address).objectAddress returned unexpected value"); - assertEq(a.initialOwner, b.initialOwner, "getObjectInfo(address).initialOwner returned unexpected value"); - assertEq(a.data.length, b.data.length, "getObjectInfo(address).data.length returned unexpected value"); - assertEq(keccak256(a.data), keccak256(b.data), "getObjectInfo(address).data returned unexpected value"); return ( (a.nftId == b.nftId) && (a.parentNftId == b.parentNftId) && (a.objectType == b.objectType) && - (a.objectAddress == b.objectAddress) && - (a.initialOwner == b.initialOwner) && - (a.data.length == b.data.length) && - keccak256(a.data) == keccak256(b.data) + (a.release == b.release) && + (a.objectAddress == b.objectAddress) ); } @@ -516,10 +516,9 @@ contract GifDeployer is Test { NftIdLib.zero(), NftIdLib.zero(), ObjectTypeLib.zero(), + VersionPartLib.zero(), false, - address(0), - address(0), - bytes("") + address(0) ) ); } @@ -564,11 +563,15 @@ contract GifDeployer is Test { ); } + function eqBytes(bytes memory a, bytes memory b) public pure returns (bool isSame) { + return ( + a.length == b.length && + keccak256(a) == keccak256(b) + ); + } - function _deployCore( - address gifAdmin, - address gifManager - ) + + function _deployCore() internal { ( @@ -579,11 +582,7 @@ contract GifDeployer is Test { registryAdmin, stakingManager, staking - ) = deployCore( - globalRegistry, - gifAdmin, - gifManager, - stakingOwner); + ) = deployCore(); // obtain some references registryAddress = address(registry); @@ -597,13 +596,14 @@ contract GifDeployer is Test { function _printCoreSetup() internal view { // solhint-disable console.log("registry deployed at", address(registry)); - console.log("registry owner", registryOwner); - console.log("token registry deployed at", address(tokenRegistry)); console.log("release manager deployed at", address(releaseRegistry)); - console.log("registry access manager deployed:", address(registryAdmin)); - console.log("registry access manager authority", registryAdmin.authority()); + console.log("registry access admin deployed at", address(registryAdmin)); + console.log("registry access manager", registryAdmin.authority()); + console.log("registry authorization deployed at", address(registryAuthorization)); + console.log("gif admin", registryAdmin.getRoleMember(GIF_ADMIN_ROLE(), 0)); + console.log("gif manager", registryAdmin.getRoleMember(GIF_MANAGER_ROLE(), 0)); console.log("staking manager deployed at", address(stakingManager)); @@ -701,4 +701,21 @@ contract GifDeployer is Test { console.log(""); // solhint-enable } + + function _computeRegistryAddress(address deployer, address globalRegistry, bytes32 salt) internal pure returns (address) { + address accessAdmin = Create2.computeAddress( + salt, + keccak256(abi.encodePacked( + type(RegistryAdmin).creationCode)), // bytecodeHash + deployer); + + return Create2.computeAddress( + salt, + keccak256(abi.encodePacked( + type(Registry).creationCode, + abi.encode( + accessAdmin, + globalRegistry))), // bytecodeHash + deployer); + } } \ No newline at end of file diff --git a/test/base/GifDeployer.t.sol b/test/base/GifDeployer.t.sol index 10f0d9055..bbda3a94b 100644 --- a/test/base/GifDeployer.t.sol +++ b/test/base/GifDeployer.t.sol @@ -9,11 +9,12 @@ import {ChainId, ChainIdLib} from "../../contracts/type/ChainId.sol"; import {ChainNft} from "../../contracts/registry/ChainNft.sol"; import {Dip} from "../../contracts/mock/Dip.sol"; import {GifDeployer} from "./GifDeployer.sol"; -import {GIF_MANAGER_ROLE, GIF_ADMIN_ROLE} from "../../contracts/type/RoleId.sol"; +import {IAccess} from "../../contracts/authorization/IAccess.sol"; import {IRegistry} from "../../contracts/registry/IRegistry.sol"; import {IServiceAuthorization} from "../../contracts/authorization/IServiceAuthorization.sol"; import {NftId, NftIdLib} from "../../contracts/type/NftId.sol"; -import {Registry} from "../../contracts/registry/Registry.sol"; +import {ADMIN_ROLE, GIF_MANAGER_ROLE, GIF_ADMIN_ROLE} from "../../contracts/type/RoleId.sol"; +import {Registry, GIF_INITIAL_RELEASE} from "../../contracts/registry/Registry.sol"; import {RegistryAdmin} from "../../contracts/registry/RegistryAdmin.sol"; import {ReleaseAdmin} from "../../contracts/registry/ReleaseAdmin.sol"; import {ReleaseRegistry} from "../../contracts/registry/ReleaseRegistry.sol"; @@ -39,10 +40,9 @@ contract GifDeployerTest is GifDeployer { gifV3 = VersionPartLib.toVersionPart(3); serviceAuthorization = new ServiceAuthorizationV3(COMMIT_HASH); - _deployCore(gifAdmin, gifManager); + _deployCore(); } - function test_gifDeployerSetup() public { _printCoreSetup(); _printAuthz(registryAdmin, "registryAdmin"); @@ -124,29 +124,42 @@ contract GifDeployerTest is GifDeployer { // check linked contracts assertEq(address(releaseRegistry.getRegistry()), address(registry), "unexpected registry address"); - assertEq(releaseRegistry.INITIAL_GIF_VERSION(), gifV3.toInt(), "unexpected initial gif version"); + assertEq(GIF_INITIAL_RELEASE().toInt(), gifV3.toInt(), "unexpected initial gif version"); assertEq(address(releaseRegistry.getRegistryAdmin()), address(registryAdmin), "unexpected registry address"); // TODO amend once full gif setup is streamlined } - function test_gifDeployerCoreRegistryAccessManager() public { - assertTrue(address(registryAdmin) != address(0), "registry admin manager address zero"); - assertTrue(registryAdmin.authority() != address(0), "registry admin manager authority address zero"); + function test_gifDeployerCoreRegistryAdmin() public { + assertTrue(address(registryAdmin) != address(0), "registry admin address zero"); + assertTrue(registryAdmin.authority() != address(0), "registry admin authority address zero"); // check authority - assertEq(registryAdmin.authority(), registryAdmin.authority(), "unexpected release manager authority"); + //assertEq(registryAdmin.authority(), registryAdmin.authority(), "unexpected release manager authority"); ??? + + // check roles + assertTrue(registryAdmin.isRoleMember(GIF_ADMIN_ROLE(), gifAdmin), "gif admin is not GIF_ADMIN_ROLE member"); + assertEq(registryAdmin.roleMembers(GIF_ADMIN_ROLE()), 1, "GIF_ADMIN_ROLE have more than one member"); + + IAccess.RoleInfo memory gifAdminRoleInfo = registryAdmin.getRoleInfo(GIF_ADMIN_ROLE()); + assertEq(gifAdminRoleInfo.adminRoleId.toInt(), ADMIN_ROLE().toInt(), "unexpected admin role id for GIF_ADMIN_ROLE"); + assertTrue(gifAdminRoleInfo.targetType == IAccess.TargetType.Custom, "unexpected role type of GIF_ADMIN_ROLE"); + assertEq(gifAdminRoleInfo.maxMemberCount, 1, "unexpected max member count for GIF_ADMIN_ROLE"); + + assertTrue(registryAdmin.isRoleMember(GIF_MANAGER_ROLE(), gifManager), "gif manager is not GIF_MANAGER_ROLE member"); + assertEq(registryAdmin.roleMembers(GIF_MANAGER_ROLE()), 1, "GIF_MANAGER_ROLE have more than one member"); - // check initial roles assignments - assertTrue(registryAdmin.isRoleMember(GIF_ADMIN_ROLE(), gifAdmin), "registry owner not admin"); - assertTrue(registryAdmin.isRoleMember(GIF_MANAGER_ROLE(), gifManager), "registry owner not manager"); + IAccess.RoleInfo memory gifManagerRoleInfo = registryAdmin.getRoleInfo(GIF_MANAGER_ROLE()); + assertEq(gifManagerRoleInfo.adminRoleId.toInt(), ADMIN_ROLE().toInt(), "unexpected admin role id for GIF_MANAGER_ROLE"); + assertTrue(gifManagerRoleInfo.targetType == IAccess.TargetType.Custom, "unexpected role type of GIF_MANAGER_ROLE"); + assertEq(gifManagerRoleInfo.maxMemberCount, 2, "unexpected max member count for GIF_MANAGER_ROLE"); // check sample admin access IAccessManager authority = IAccessManager(registryAdmin.authority()); bool can; (can,) = authority.canCall(gifAdmin, address(registryAdmin), TokenRegistry.registerToken.selector); - assertFalse(can, "gif admin cannot call registerToken"); + assertFalse(can, "gif admin can call registerToken"); // check sample manager access (can,) = authority.canCall(gifManager, address(tokenRegistry), TokenRegistry.registerToken.selector); @@ -154,7 +167,6 @@ contract GifDeployerTest is GifDeployer { // check linked contracts assertEq(address(releaseRegistry.getRegistry()), address(registry), "unexpected registry address"); - assertEq(releaseRegistry.INITIAL_GIF_VERSION(), gifV3.toInt(), "unexpected initial gif version"); assertEq(address(releaseRegistry.getRegistryAdmin()), address(registryAdmin), "unexpected registry address"); // TODO amend once full gif setup is streamlined @@ -179,7 +191,6 @@ contract GifDeployerTest is GifDeployer { assertEq(stakingNftId.toInt(), registry.getNftIdForAddress(address(staking)).toInt(), "unexpected staking nft id"); // check ownership - assertEq(stakingOwner, registryOwner, "unexpected staking owner"); assertEq(staking.getOwner(), stakingOwner, "unexpected staking owner (via staking)"); assertEq(registry.ownerOf(address(staking)), stakingOwner, "unexpected staking owner (via registry)"); @@ -219,8 +230,6 @@ contract GifDeployerTest is GifDeployer { function _deployRelease() internal { deployRelease( releaseRegistry, - serviceAuthorization, - gifAdmin, - gifManager); + serviceAuthorization); } } diff --git a/test/base/GifTest.sol b/test/base/GifTest.sol index 8a1036472..6604ee1a2 100644 --- a/test/base/GifTest.sol +++ b/test/base/GifTest.sol @@ -148,38 +148,29 @@ contract GifTest is GifDeployer { internal virtual { - address gifAdmin = registryOwner; - address gifManager = registryOwner; - currentChainId = ChainIdLib.current(); // solhint-disable console.log("=== GifTest starting ======================================="); console.log("=== deploying core ========================================="); // solhint-enable - _deployCore(gifAdmin, gifManager); + _deployCore(); // solhint-disable-next-line console.log("=== deploying release ======================================"); - _deployAndRegisterServices(gifAdmin, gifManager); + _deployAndRegisterServices(); // solhint-disable-next-line console.log("=== register token ========================================="); - vm.startPrank(address(registryOwner)); _deployRegisterAndActivateToken(); - vm.stopPrank(); // solhint-disable-next-line console.log("=== deploying master instance =============================="); - vm.startPrank(registryOwner); _deployMasterInstance(); - vm.stopPrank(); // solhint-disable-next-line console.log("=== create instance ========================================"); - vm.startPrank(instanceOwner); _createInstance(); - vm.stopPrank(); // solhint-disable-next-line console.log("=== GifTest setup complete ================================="); @@ -230,30 +221,27 @@ contract GifTest is GifDeployer { } - function _deployAndRegisterServices( - address gifAdmin, - address gifManager - ) + function _deployAndRegisterServices() internal { IServiceAuthorization serviceAuthorization = new ServiceAuthorizationV3("85b428cbb5185aee615d101c2554b0a58fb64810"); deployRelease( releaseRegistry, - serviceAuthorization, - gifAdmin, - gifManager); + serviceAuthorization); VersionPart latestRelease = registry.getLatestRelease(); assertEq(releaseRegistry.getState(latestRelease).toInt(), ACTIVE().toInt(), "unexpected state for releaseRegistry after activateNextRelease"); // set staking service - vm.startPrank(stakingOwner); + vm.prank(stakingOwner); staking.setStakingService(latestRelease); } function _deployMasterInstance() internal { + vm.startPrank(gifManager); + // create instance supporting contracts masterAccessManager = new AccessManagerCloneable(); masterInstanceAdmin = new InstanceAdmin(address(masterAccessManager)); @@ -274,9 +262,7 @@ contract GifTest is GifDeployer { riskSet: masterRiskSet, instanceReader: masterInstanceReader }), - registry, - VersionPartLib.toVersionPart(3), - registryOwner, + gifManager, false); // sets master instance address in instance service @@ -286,9 +272,7 @@ contract GifTest is GifDeployer { // setup roles, targets and function grantings instanceAuthorizationV3 = new InstanceAuthorizationV3(); masterInstanceAdmin.completeSetup( - address(registry), address(instanceAuthorizationV3), - VersionPartLib.toVersionPart(3), address(masterInstance)); require(address(masterInstanceAdmin.getRegistry()) == address(registry), "unexpected master instance registry"); @@ -296,11 +280,14 @@ contract GifTest is GifDeployer { // MUST be set after instance is set up and registered // lock master instance nft - chainNft.transferFrom(registryOwner, NFT_LOCK_ADDRESS, masterInstanceNftId.toInt()); + chainNft.transferFrom(gifManager, NFT_LOCK_ADDRESS, masterInstanceNftId.toInt()); + + vm.stopPrank(); // solhint-disable console.log("master instance deployed at", address(masterInstance)); console.log("master instance nft id", masterInstanceNftId.toInt()); + console.log("master instance owner", masterInstance.getOwner()); console.log("master oz access manager deployed at", address(masterInstance.authority())); console.log("master instance access manager deployed at", address(masterInstanceAdmin)); console.log("master instance reader deployed at", address(masterInstanceReader)); @@ -312,6 +299,9 @@ contract GifTest is GifDeployer { function _createInstance() internal { + + vm.startPrank(instanceOwner); + ( instance, instanceNftId @@ -323,10 +313,13 @@ contract GifTest is GifDeployer { instanceBundleSet = instance.getBundleSet(); instanceRiskSet = instance.getRiskSet(); instanceStore = instance.getInstanceStore(); + + vm.stopPrank(); // solhint-disable console.log("cloned instance deployed at", address(instance)); console.log("cloned instance nft id", instanceNftId.toInt()); + console.log("cloned instance owner", instance.getOwner()); console.log("cloned oz access manager deployed at", instance.authority()); console.log("cloned instance reader deployed at", address(instanceReader)); console.log("cloned bundle set deployed at", address(instanceBundleSet)); @@ -336,6 +329,12 @@ contract GifTest is GifDeployer { } function _deployRegisterAndActivateToken() internal { + + vm.prank(tokenIssuer); + token = new Usdc(); + + vm.startPrank(gifManager); + VersionPart release = registry.getLatestRelease(); // dip @@ -343,12 +342,13 @@ contract GifTest is GifDeployer { currentChainId, address(dip), release, true); // usdc - token = new Usdc(); // TODO continue here : tokenRegistry need to call staktint to add registered tokens there tokenRegistry.registerToken(address(token)); tokenRegistry.setActiveForVersion( currentChainId, address(token), release, true); + vm.stopPrank(); + // solhint-disable console.log("token (usdc) deployed at", address(token)); console.log("token (dip) deployed at", address(dip)); @@ -405,7 +405,7 @@ contract GifTest is GifDeployer { FeeLib.zero()); vm.stopPrank(); - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(investor, DEFAULT_BUNDLE_CAPITALIZATION * 10**token.decimals()); token.transfer(customer, DEFAULT_CUSTOMER_FUNDS * 10**token.decimals()); vm.stopPrank(); @@ -442,7 +442,6 @@ contract GifTest is GifDeployer { // product owner deploys product vm.startPrank(productOwner); newProduct = new SimpleProduct( - address(registry), instanceNftId, "SimpleProduct", _getSimpleProductInfo(), @@ -508,7 +507,6 @@ contract GifTest is GifDeployer { vm.startPrank(poolOwner); pool = new SimplePool( - address(registry), productNftId, _getDefaultSimplePoolInfo(), new SimplePoolAuthorization("SimplePool"), @@ -536,7 +534,6 @@ contract GifTest is GifDeployer { vm.startPrank(distributionOwner); distribution = new SimpleDistribution( - address(registry), productNftId, new SimpleDistributionAuthorization("SimpleDistribution"), distributionOwner); @@ -553,7 +550,6 @@ contract GifTest is GifDeployer { vm.startPrank(oracleOwner); oracle = new SimpleOracle( - address(registry), productNftId, new BasicOracleAuthorization("SimpleOracle", COMMIT_HASH), oracleOwner); diff --git a/test/component/distribution/Referral.t.sol b/test/component/distribution/Referral.t.sol index dc2e84e8e..9fab6ffaf 100644 --- a/test/component/distribution/Referral.t.sol +++ b/test/component/distribution/Referral.t.sol @@ -79,7 +79,7 @@ contract ReferralTest is ReferralTestBase { assertEq(instanceReader.getFeeAmount(bundleNftId).toInt(), bundleFeeInitial.toInt(), "unexpected initial bundle balance"); // GIVEN - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(customer, 1000); vm.stopPrank(); @@ -180,7 +180,7 @@ contract ReferralTest is ReferralTestBase { // _setupBundle(bundleAmount); // GIVEN - two policies to collateralize - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(customer, 1000); token.transfer(customer2, 1000); vm.stopPrank(); @@ -450,7 +450,7 @@ contract ReferralTest is ReferralTestBase { function _setupBundle(uint256 bundleAmount) internal { - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(investor, bundleAmount); vm.stopPrank(); diff --git a/test/component/oracle/Oracle.t.sol b/test/component/oracle/Oracle.t.sol index 2d30c1cbe..e9b132ccd 100644 --- a/test/component/oracle/Oracle.t.sol +++ b/test/component/oracle/Oracle.t.sol @@ -7,6 +7,7 @@ import {GifTest} from "../../base/GifTest.sol"; import {Amount, AmountLib} from "../../../contracts/type/Amount.sol"; import {NftId, NftIdLib} from "../../../contracts/type/NftId.sol"; import {ClaimId} from "../../../contracts/type/ClaimId.sol"; +import {ContractLib} from "../../../contracts/shared/ContractLib.sol"; import {SimpleOracle} from "../../../contracts/examples/unpermissioned/SimpleOracle.sol"; import {IComponents} from "../../../contracts/instance/module/IComponents.sol"; import {ILifecycle} from "../../../contracts/shared/ILifecycle.sol"; @@ -20,14 +21,15 @@ import {Timestamp, TimestampLib, zeroTimestamp} from "../../../contracts/type/Ti import {IPolicyService} from "../../../contracts/product/IPolicyService.sol"; import {IRisk} from "../../../contracts/instance/module/IRisk.sol"; import {PayoutId, PayoutIdLib} from "../../../contracts/type/PayoutId.sol"; -import {POLICY, ORACLE} from "../../../contracts/type/ObjectType.sol"; +import {PRODUCT, POLICY, ORACLE} from "../../../contracts/type/ObjectType.sol"; +import {GIF_INITIAL_RELEASE} from "../../../contracts/registry/Registry.sol"; import {RiskId, RiskIdLib, eqRiskId} from "../../../contracts/type/RiskId.sol"; import {ReferralLib} from "../../../contracts/type/Referral.sol"; import {RequestId, RequestIdLib} from "../../../contracts/type/RequestId.sol"; import {SUBMITTED, ACTIVE, CANCELLED, FAILED, FULFILLED} from "../../../contracts/type/StateId.sol"; import {StateId} from "../../../contracts/type/StateId.sol"; import {IOracleService} from "../../../contracts/oracle/IOracleService.sol"; -import {INftOwnable} from "../../../contracts/shared/INftOwnable.sol"; +import {ContractLib} from "../../../contracts/shared/ContractLib.sol"; contract TestOracle is GifTest { @@ -207,9 +209,10 @@ contract TestOracle is GifTest { RequestId expectedRequestId = RequestIdLib.toRequestId(1); vm.expectRevert(abi.encodeWithSelector( - INftOwnable.ErrorNftOwnableInvalidType.selector, + ContractLib.ErrorContractLibObjectTypeMismatch.selector, productNftId, - ORACLE())); + ORACLE(), + PRODUCT())); product.createOracleRequest( productNftId, requestText, diff --git a/test/component/pool/PoolRegistration.t.sol b/test/component/pool/PoolRegistration.t.sol index 772ce0079..094368f7f 100644 --- a/test/component/pool/PoolRegistration.t.sol +++ b/test/component/pool/PoolRegistration.t.sol @@ -12,8 +12,11 @@ import {SimplePool} from "../../../contracts/examples/unpermissioned/SimplePool. import {IAuthorization} from "../../../contracts/authorization/IAuthorization.sol"; import {IComponents} from "../../../contracts/instance/module/IComponents.sol"; import {IComponentService} from "../../../contracts/shared/IComponentService.sol"; +import {IInstanceLinkedComponent} from "../../../contracts/shared/IInstanceLinkedComponent.sol"; +import {IRegistry} from "../../../contracts/registry/IRegistry.sol"; +import {IRegistryService} from "../../../contracts/registry/IRegistryService.sol"; import {Registerable} from "../../../contracts/shared/Registerable.sol"; -import {IRelease} from "../../../contracts/registry/IRelease.sol"; +import {ProductMockWithoutInstanceCheck} from "../../mock/ProductMock.sol"; import {VersionPart, VersionPartLib} from "../../../contracts/type/Version.sol"; import {ContractLib} from "../../../contracts/shared/ContractLib.sol"; @@ -72,7 +75,7 @@ contract TestPoolRegistration is GifTest { // WHEN + THEN vm.expectRevert( abi.encodeWithSelector( - IComponentService.ErrorComponentServiceComponentAlreadyRegistered.selector, + IRegistry.ErrorRegistryContractAlreadyRegistered.selector, address(myPool))); vm.startPrank(myProductOwner); @@ -140,7 +143,7 @@ contract TestPoolRegistration is GifTest { // check that pool registration fails for pool with a different release than product function test_poolRegisterAttemptDifferentRelease() public { // // GIVEN - // SimpleProduct myProductV4 = new SimpleProductV4( + // SimpleProduct myProductV4 = new ProductMockV4( // address(registry), // instanceNftId, // new BasicProductAuthorization("MyProductV4"), @@ -173,8 +176,9 @@ contract TestPoolRegistration is GifTest { // WHEN + THEN vm.expectRevert( abi.encodeWithSelector( - IComponentService.ErrorComponentServiceNotComponent.selector, - address(token))); + IRegistryService.ErrorRegistryServiceInterfaceNotSupported.selector, + address(token), + type(IInstanceLinkedComponent).interfaceId)); vm.startPrank(myProductOwner); NftId myNftId = myProduct1.registerComponent(address(token)); @@ -223,7 +227,6 @@ contract TestPoolRegistration is GifTest { returns(SimpleProduct) { return new SimpleProduct( - address(registry), instanceNftId, "SimpleProduct", _getSimpleProductInfo(), @@ -241,37 +244,9 @@ contract TestPoolRegistration is GifTest { returns(SimplePool) { return new SimplePool( - address(registry), productNftId, _getDefaultSimplePoolInfo(), new BasicPoolAuthorization(name), owner); } -} - - -contract SimpleProductV4 is SimpleProduct { - - constructor( - address registry, - NftId instanceNftId, - IComponents.ProductInfo memory productInfo, - IComponents.FeeInfo memory feeInfo, - IAuthorization authorization, - address initialOwner - ) - SimpleProduct( - registry, - instanceNftId, - "SimpleProductV4", - productInfo, - feeInfo, - authorization, - initialOwner - ) - { } - - function getRelease() public override(IRelease, Registerable) pure returns (VersionPart release) { - return VersionPartLib.toVersionPart(4); - } } \ No newline at end of file diff --git a/test/component/product/PolicyServiceLib.t.sol b/test/component/product/PolicyServiceLib.t.sol index 78ba4eb7c..e0f604983 100644 --- a/test/component/product/PolicyServiceLib.t.sol +++ b/test/component/product/PolicyServiceLib.t.sol @@ -226,7 +226,7 @@ contract PolicyServiceLibTest is GifTest { FeeLib.zero()); // performance fees vm.stopPrank(); - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(investor, bundleCapital); vm.stopPrank(); diff --git a/test/component/product/ProductApplication.t.sol b/test/component/product/ProductApplication.t.sol index 2f0243e23..c360013d2 100644 --- a/test/component/product/ProductApplication.t.sol +++ b/test/component/product/ProductApplication.t.sol @@ -297,7 +297,7 @@ contract ProductApplicationTest is GifTest { FeeLib.zero()); // performance fees vm.stopPrank(); - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(investor, bundleCapital); vm.stopPrank(); diff --git a/test/component/product/ProductLifecycle.t.sol b/test/component/product/ProductLifecycle.t.sol index fa165671e..25e0c022a 100644 --- a/test/component/product/ProductLifecycle.t.sol +++ b/test/component/product/ProductLifecycle.t.sol @@ -46,7 +46,7 @@ contract TestProductLifecycle riskId = product.createRisk("Risk_1", ""); vm.stopPrank(); - policyHolder = new MyPolicyHolder(address(registry)); + policyHolder = new MyPolicyHolder(); policyHolderAddress = address(policyHolder); // create application @@ -419,7 +419,7 @@ contract TestProductLifecycle function _fundAccount( address policyHolderAddress ) internal { - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(policyHolderAddress, CUSTOMER_FUNDS); vm.stopPrank(); } diff --git a/test/component/product/ProductPayout.t.sol b/test/component/product/ProductPayout.t.sol index 5d78f27e5..cfa9a2dba 100644 --- a/test/component/product/ProductPayout.t.sol +++ b/test/component/product/ProductPayout.t.sol @@ -1196,7 +1196,7 @@ contract TestProductClaim is GifTest { uint256 premiumAmountInt = instanceReader.getPolicyInfo(policyNftId).premiumAmount.toInt(); // add token allowance to pay premiums - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(policyHolder, premiumAmountInt); vm.stopPrank(); @@ -1371,7 +1371,7 @@ contract TestProductClaim is GifTest { // vm.stopPrank(); // // fund investor and customer - // vm.startPrank(registryOwner); + // vm.startPrank(tokenIssuer); // token.transfer(investor, BUNDLE_CAPITAL); // token.transfer(customer, CUSTOMER_FUNDS); // vm.stopPrank(); diff --git a/test/component/product/ProductPolicy.t.sol b/test/component/product/ProductPolicy.t.sol index 853b298bb..1f38fe822 100644 --- a/test/component/product/ProductPolicy.t.sol +++ b/test/component/product/ProductPolicy.t.sol @@ -108,7 +108,7 @@ contract ProductPolicyTest is GifTest { function test_productCollateralizeWithPayment() public { // GIVEN - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(customer, 1000); vm.stopPrank(); @@ -213,7 +213,7 @@ contract ProductPolicyTest is GifTest { function test_productWithReferralCollateralizeWithPayment() public { // GIVEN - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(customer, 1000); vm.stopPrank(); @@ -416,7 +416,7 @@ contract ProductPolicyTest is GifTest { function test_productWithReferralCollateralizeWithSplitPayment() public { // GIVEN - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(customer, 1000); vm.stopPrank(); @@ -521,7 +521,7 @@ contract ProductPolicyTest is GifTest { function test_productCollateralizeWithReferralExpired() public { // GIVEN - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(customer, 1000); vm.stopPrank(); @@ -808,7 +808,7 @@ contract ProductPolicyTest is GifTest { function test_adjustActivation() public { // GIVEN - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(customer, 1000); vm.stopPrank(); @@ -861,7 +861,7 @@ contract ProductPolicyTest is GifTest { vm.warp(100000); // GIVEN - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(customer, 1000); vm.stopPrank(); @@ -919,7 +919,7 @@ contract ProductPolicyTest is GifTest { vm.warp(100000); // GIVEN - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(customer, 1000); vm.stopPrank(); @@ -976,7 +976,7 @@ contract ProductPolicyTest is GifTest { vm.warp(100000); // GIVEN - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(customer, 1000); vm.stopPrank(); @@ -1028,7 +1028,7 @@ contract ProductPolicyTest is GifTest { function test_productPolicyCollectPremium() public { // GIVEN - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(customer, 1000); vm.stopPrank(); @@ -1135,7 +1135,7 @@ contract ProductPolicyTest is GifTest { function test_productPolicyCloseWithPremiumPayment() public { // GIVEN - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(customer, 1000); vm.stopPrank(); @@ -1230,7 +1230,7 @@ contract ProductPolicyTest is GifTest { function test_productPolicyCloseNoPremiumPayment() public { // GIVEN - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(customer, 1000); vm.stopPrank(); @@ -1290,7 +1290,7 @@ contract ProductPolicyTest is GifTest { /// @dev test that policy expiration works function test_productPolicyExpireHappyCase() public { // GIVEN - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(customer, 1000); vm.stopPrank(); @@ -1350,7 +1350,7 @@ contract ProductPolicyTest is GifTest { /// @dev test that policy expiration works when current timestamp is provided function test_productPolicyExpire_currentTimestamp() public { // GIVEN - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(customer, 1000); vm.stopPrank(); @@ -1409,7 +1409,7 @@ contract ProductPolicyTest is GifTest { /// @dev test that policy expiration works when expireAt is set to 0 function test_productPolicyExpire_earliestPossible() public { // GIVEN - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(customer, 1000); vm.stopPrank(); @@ -1465,7 +1465,7 @@ contract ProductPolicyTest is GifTest { /// @dev test that policy expiration reverts if policy is not active function test_productPolicyExpire_policyNotActive() public { // GIVEN - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(customer, 1000); vm.stopPrank(); @@ -1602,7 +1602,7 @@ contract ProductPolicyTest is GifTest { function test_productCollectPremium_alreadyPaid() public { // GIVEN - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(customer, 1000); vm.stopPrank(); @@ -1651,7 +1651,7 @@ contract ProductPolicyTest is GifTest { /// @dev test that policy expiration reverts if the expireAt timestamp is too late function test_productPolicyExpire_expireAtTooLate() public { // GIVEN - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(customer, 1000); vm.stopPrank(); @@ -1724,7 +1724,7 @@ contract ProductPolicyTest is GifTest { skip(10); // GIVEN - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(customer, 1000); vm.stopPrank(); @@ -1796,7 +1796,7 @@ contract ProductPolicyTest is GifTest { FeeLib.zero()); // performance fees vm.stopPrank(); - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(investor, bundleCapital); vm.stopPrank(); diff --git a/test/component/product/ProductRegistration.t.sol b/test/component/product/ProductRegistration.t.sol index e14ad596a..71d694664 100644 --- a/test/component/product/ProductRegistration.t.sol +++ b/test/component/product/ProductRegistration.t.sol @@ -9,9 +9,11 @@ import {SimpleProduct} from "../../../contracts/examples/unpermissioned/SimplePr import {SimplePool} from "../../../contracts/examples/unpermissioned/SimplePool.sol"; import {IComponents} from "../../../contracts/instance/module/IComponents.sol"; import {IComponentService} from "../../../contracts/shared/IComponentService.sol"; +import {IRegistry} from "../../../contracts/registry/IRegistry.sol"; +import {IRegistryService} from "../../../contracts/registry/IRegistryService.sol"; import {INftOwnable} from "../../../contracts/shared/INftOwnable.sol"; import {PRODUCT, POOL} from "../../../contracts/type/ObjectType.sol"; -import {SimpleProductV4} from "./SimpleProductV4.sol"; +import {ProductMockV4} from "../../mock/ProductMock.sol"; import {Usdc} from "../../mock/Usdc.sol"; @@ -69,7 +71,7 @@ contract TestProductRegistration is GifTest { // WHEN + THEN vm.expectRevert( abi.encodeWithSelector( - IComponentService.ErrorComponentServiceComponentAlreadyRegistered.selector, + IRegistry.ErrorRegistryContractAlreadyRegistered.selector, address(myProduct))); vm.startPrank(instanceOwner); @@ -110,12 +112,15 @@ contract TestProductRegistration is GifTest { vm.stopPrank(); } - - // check that product registration fails for product with a different release than instance + // TODO flawors of different release + // object | parent | service + // a a b + // a b a + // a b b + // a b c function test_productRegisterAttemptDifferentRelease() public { // GIVEN - SimpleProduct myProductV4 = new SimpleProductV4( - address(registry), + ProductMockV4 myProductV4 = new ProductMockV4( instanceNftId, _getSimpleProductInfo(), _getSimpleFeeInfo(), @@ -127,10 +132,10 @@ contract TestProductRegistration is GifTest { // WHEN + THEN vm.expectRevert( abi.encodeWithSelector( - IComponentService.ErrorComponentServiceComponentReleaseMismatch.selector, - address(myProductV4), + IRegistry.ErrorRegistryReleaseMismatch.selector, + myProductV4.getRelease(), instance.getRelease(), - myProductV4.getRelease())); + registryService.getRelease())); vm.startPrank(instanceOwner); instance.registerProduct(address(myProductV4), address(token)); @@ -165,8 +170,10 @@ contract TestProductRegistration is GifTest { // WHEN + THEN vm.expectRevert( abi.encodeWithSelector( - IComponentService.ErrorComponentServiceNotProduct.selector, - address(myPool))); + IRegistryService.ErrorRegistryServiceRegisterableTypeInvalid.selector, + address(myPool), + PRODUCT(), + POOL())); vm.startPrank(instanceOwner); instance.registerProduct(address(myPool), address(token)); @@ -222,7 +229,6 @@ contract TestProductRegistration is GifTest { IComponents.FeeInfo memory feeInfo = _getSimpleFeeInfo(); return new SimpleProduct( - address(registry), instanceNftId, name, productInfo, @@ -240,7 +246,6 @@ contract TestProductRegistration is GifTest { returns(SimplePool) { return new SimplePool( - address(registry), productNftId, _getDefaultSimplePoolInfo(), new BasicPoolAuthorization(name), diff --git a/test/component/product/ProductRisk.t.sol b/test/component/product/ProductRisk.t.sol index ab8ba0ebf..e153e73bb 100644 --- a/test/component/product/ProductRisk.t.sol +++ b/test/component/product/ProductRisk.t.sol @@ -40,7 +40,7 @@ contract TestProductRisk is GifTest { initialPolicyNftId = _createApplication(initialRiskId); // fund and approve customer - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(customer, CUSTOMER_FUNDS); vm.stopPrank(); diff --git a/test/component/product/SimpleProductV4.sol b/test/component/product/SimpleProductV4.sol deleted file mode 100644 index 92d647dd2..000000000 --- a/test/component/product/SimpleProductV4.sol +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.20; - -import {NftId} from "../../../contracts/type/NftId.sol"; -import {SimpleProduct} from "../../../contracts/examples/unpermissioned/SimpleProduct.sol"; -import {IAuthorization} from "../../../contracts/authorization/IAuthorization.sol"; -import {IComponents} from "../../../contracts/instance/module/IComponents.sol"; -import {Registerable} from "../../../contracts/shared/Registerable.sol"; -import {IRelease} from "../../../contracts/registry/IRelease.sol"; -import {VersionPart, VersionPartLib} from "../../../contracts/type/Version.sol"; - - -contract SimpleProductV4 is SimpleProduct { - - constructor( - address registry, - NftId instanceNftId, - IComponents.ProductInfo memory productInfo, - IComponents.FeeInfo memory feeInfo, - IAuthorization authorization, - address initialOwner - ) - SimpleProduct( - registry, - instanceNftId, - "SimpleProductV4", - productInfo, - feeInfo, - authorization, - initialOwner - ) - { } - - function getRelease() public override(IRelease, Registerable) pure returns (VersionPart release) { - return VersionPartLib.toVersionPart(4); - } -} \ No newline at end of file diff --git a/test/component/product/TestProduct.t.sol b/test/component/product/TestProduct.t.sol index 144a12f34..181bd0fd7 100644 --- a/test/component/product/TestProduct.t.sol +++ b/test/component/product/TestProduct.t.sol @@ -183,7 +183,7 @@ contract TestProduct is GifTest { FeeLib.zero()); // performance fees vm.stopPrank(); - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(investor, bundleCapital); vm.stopPrank(); diff --git a/test/component/registration/ComponentTracking.t.sol b/test/component/registration/ComponentTracking.t.sol index 9fe9dbcae..8e04f2dc5 100644 --- a/test/component/registration/ComponentTracking.t.sol +++ b/test/component/registration/ComponentTracking.t.sol @@ -214,7 +214,6 @@ contract ComponentTrackingTest is GifTest { vm.expectRevert(abi.encodeWithSelector( IComponent.ErrorComponentNameLengthZero.selector)); new SimpleProduct( - address(registry), instanceNftId, "", productInfo, @@ -239,7 +238,6 @@ contract ComponentTrackingTest is GifTest { IComponents.FeeInfo memory feeInfo = _getSimpleFeeInfo(); return new SimpleProduct( - address(registry), instanceNftId, name, productInfo, @@ -257,7 +255,6 @@ contract ComponentTrackingTest is GifTest { returns(SimpleDistribution) { return new SimpleDistribution( - address(registry), productNftId, new BasicDistributionAuthorization(name), owner); @@ -272,7 +269,6 @@ contract ComponentTrackingTest is GifTest { returns(SimpleOracle) { return new SimpleOracle( - address(registry), productNftId, new BasicOracleAuthorization(name, COMMIT_HASH), owner); @@ -287,7 +283,6 @@ contract ComponentTrackingTest is GifTest { returns(SimplePool) { return new SimplePool( - address(registry), productNftId, _getDefaultSimplePoolInfo(), new BasicPoolAuthorization(name), diff --git a/test/component/registration/ProductCluster.t.sol b/test/component/registration/ProductCluster.t.sol index 331d60ffb..226e91b62 100644 --- a/test/component/registration/ProductCluster.t.sol +++ b/test/component/registration/ProductCluster.t.sol @@ -6,8 +6,8 @@ import {console} from "forge-std/Test.sol"; import {IApplicationService} from "../../../contracts/product/IApplicationService.sol"; import {IDistributionService} from "../../../contracts/distribution/IDistributionService.sol"; import {IPricingService} from "../../../contracts/product/IPricingService.sol"; -import {IPolicyService} from "../../../contracts/product/IPolicyService.sol"; +import {ContractLib} from "../../../contracts/shared/ContractLib.sol"; import {FeeLib} from "../../../contracts/type/Fee.sol"; import {GifClusterTest} from "../../base/GifClusterTest.sol"; import {NftId} from "../../../contracts/type/NftId.sol"; @@ -18,7 +18,6 @@ import {FeeLib} from "../../../contracts/type/Fee.sol"; import {UFixedLib} from "../../../contracts/type/UFixed.sol"; import {SecondsLib} from "../../../contracts/type/Seconds.sol"; import {Timestamp, TimestampLib} from "../../../contracts/type/Timestamp.sol"; -import {IPolicyService} from "../../../contracts/product/IPolicyService.sol"; import {RiskId} from "../../../contracts/type/RiskId.sol"; import {ReferralId} from "../../../contracts/type/Referral.sol"; import {UFixedLib} from "../../../contracts/type/UFixed.sol"; @@ -144,10 +143,10 @@ contract ProductClusterTest is GifClusterTest { vm.expectRevert( abi.encodeWithSelector( - IPolicyService.ErrorPolicyServicePolicyProductMismatch.selector, - applicationNftId2, - myProductNftId1, // expected (caller) - myProductNftId2)); // actual (from application) + ContractLib.ErrorContractLibObjectParentMismatch.selector, + applicationNftId2, + myProductNftId1, + myProductNftId2)); _createPolicy(myProduct1, applicationNftId2, activateAt); } diff --git a/test/examples/composeability/PoolWithReinsurance.sol b/test/examples/composeability/PoolWithReinsurance.sol index 8fdd62244..afb5bcd58 100644 --- a/test/examples/composeability/PoolWithReinsurance.sol +++ b/test/examples/composeability/PoolWithReinsurance.sol @@ -36,13 +36,11 @@ contract PoolWithReinsurance is UFixed public reinsuranceLevel; constructor( - address registry, NftId instanceNftId, IAuthorization authorization, address initialOwner ) SimplePool( - registry, instanceNftId, IComponents.PoolInfo({ maxBalanceAmount: AmountLib.max(), @@ -61,14 +59,14 @@ contract PoolWithReinsurance is reinsuranceLevel = UFixedLib.toUFixed(8, -1); // 80% of claims are reinsured resinsurancePolicyNftId = NftIdLib.zero(); - _initialize(registry); + _initialize(); } - function _initialize(address registry) + function _initialize() internal initializer() { - _initializePolicyHolder(registry); + __PolicyHolder_init(); } function createReinsurance( diff --git a/test/examples/composeability/ProductWithReinsurance.sol b/test/examples/composeability/ProductWithReinsurance.sol index 5cc6a095f..34d909d1e 100644 --- a/test/examples/composeability/ProductWithReinsurance.sol +++ b/test/examples/composeability/ProductWithReinsurance.sol @@ -24,7 +24,6 @@ contract ProductWithReinsurance is bool public isAutoPayout; constructor( - address registry, NftId instanceNftId, IComponents.ProductInfo memory productInfo, IComponents.FeeInfo memory feeInfo, @@ -32,7 +31,6 @@ contract ProductWithReinsurance is address initialOwner ) SimpleProduct( - registry, instanceNftId, "ProductWithReinsurance", productInfo, diff --git a/test/examples/composeability/ProductWithReinsurance.t.sol b/test/examples/composeability/ProductWithReinsurance.t.sol index 63697ec2f..3b884bea0 100644 --- a/test/examples/composeability/ProductWithReinsurance.t.sol +++ b/test/examples/composeability/ProductWithReinsurance.t.sol @@ -357,7 +357,6 @@ contract ProductWithReinsuranceTest is vm.startPrank(productOwner); productRe = new ProductWithReinsurance( - address(registry), instanceNftId, _getProductWithReinsuranceProductInfo(), _getSimpleFeeInfo(), @@ -381,7 +380,6 @@ contract ProductWithReinsuranceTest is vm.startPrank(poolOwner); poolRe = new PoolWithReinsurance( - address(registry), productReNftId, new PoolWithReinsuranceAuthorization(), poolOwner @@ -395,7 +393,7 @@ contract ProductWithReinsuranceTest is // solhint-disable-next-line console.log("--- fund investor and customer"); - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(investor, DEFAULT_BUNDLE_CAPITALIZATION * 10**token.decimals()); token.transfer(customer, DEFAULT_CUSTOMER_FUNDS * 10**token.decimals()); vm.stopPrank(); diff --git a/test/examples/external/DefaultPool.t.sol b/test/examples/external/DefaultPool.t.sol index efe82720d..2f4b68929 100644 --- a/test/examples/external/DefaultPool.t.sol +++ b/test/examples/external/DefaultPool.t.sol @@ -48,7 +48,7 @@ contract DefaultPoolTest is GifTest { uint256 funding = 12345; Amount fundingAmount = AmountLib.toAmount(funding); - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(poolOwner, fundingAmount.toInt()); vm.stopPrank(); @@ -76,7 +76,7 @@ contract DefaultPoolTest is GifTest { uint256 funding = 12345; Amount fundingAmount = AmountLib.toAmount(funding); - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(poolOwner, fundingAmount.toInt()); vm.stopPrank(); diff --git a/test/examples/external/ExternallyManagedPool.sol b/test/examples/external/ExternallyManagedPool.sol index 138084d17..98f6c72ce 100644 --- a/test/examples/external/ExternallyManagedPool.sol +++ b/test/examples/external/ExternallyManagedPool.sol @@ -29,13 +29,11 @@ contract ExternallyManagedPool is address public bundleOwner; constructor( - address registry, NftId productNftId, IComponents.PoolInfo memory poolInfo, address initialOwner ) SimplePool( - registry, productNftId, poolInfo, new BasicPoolAuthorization("ExternallyManagedPool"), diff --git a/test/examples/external/ExternallyManagedPool.t.sol b/test/examples/external/ExternallyManagedPool.t.sol index 834a4848d..5b03e0bee 100644 --- a/test/examples/external/ExternallyManagedPool.t.sol +++ b/test/examples/external/ExternallyManagedPool.t.sol @@ -66,7 +66,7 @@ contract ExternallyManagedPoolTest is GifTest { uint256 funding = 12345; Amount fundingAmount = AmountLib.toAmount(funding); - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(poolOwner, fundingAmount.toInt()); vm.stopPrank(); @@ -113,7 +113,7 @@ contract ExternallyManagedPoolTest is GifTest { address tokenHandlerAddress = address(emPool.getTokenHandler()); - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(poolOwner, fundingAmount.toInt()); vm.stopPrank(); @@ -162,7 +162,7 @@ contract ExternallyManagedPoolTest is GifTest { Amount bundleAmount = AmountLib.toAmount(10042); - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(investor, bundleAmount.toInt()); vm.stopPrank(); @@ -200,7 +200,7 @@ contract ExternallyManagedPoolTest is GifTest { // WHEN creating a bundle and fund pool wallet Amount bundleAmount = AmountLib.toAmount(10042); - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(poolOwner, bundleAmount.toInt()); vm.stopPrank(); @@ -254,7 +254,7 @@ contract ExternallyManagedPoolTest is GifTest { Amount sumInsuredAmount = AmountLib.toAmount(1000); Amount estimatedPremiumAmount = AmountLib.toAmount(150); - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(customer, estimatedPremiumAmount.toInt()); vm.stopPrank(); @@ -296,7 +296,7 @@ contract ExternallyManagedPoolTest is GifTest { Amount sumInsuredAmount = AmountLib.toAmount(1000); Amount estimatedPremiumAmount = AmountLib.toAmount(150); - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(customer, estimatedPremiumAmount.toInt()); vm.stopPrank(); @@ -339,7 +339,7 @@ contract ExternallyManagedPoolTest is GifTest { Amount sumInsuredAmount = AmountLib.toAmount(1000); Amount estimatedPremiumAmount = AmountLib.toAmount(150); - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(customer, estimatedPremiumAmount.toInt()); vm.stopPrank(); @@ -379,7 +379,7 @@ contract ExternallyManagedPoolTest is GifTest { Amount sumInsuredAmount = AmountLib.toAmount(1000); Amount estimatedPremiumAmount = AmountLib.toAmount(150); - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(customer, estimatedPremiumAmount.toInt()); vm.stopPrank(); @@ -417,7 +417,6 @@ contract ExternallyManagedPoolTest is GifTest { IComponents.FeeInfo memory feeInfo = _getSimpleFeeInfo(); emProduct = new ExternallyManagedProduct( - address(registry), instanceNftId, productInfo, feeInfo, @@ -438,7 +437,6 @@ contract ExternallyManagedPoolTest is GifTest { }); emPool = new ExternallyManagedPool( - address(registry), prdNftId, poolInfo, poolOwner diff --git a/test/examples/external/ExternallyManagedProduct.sol b/test/examples/external/ExternallyManagedProduct.sol index 38731ce22..9902af9dd 100644 --- a/test/examples/external/ExternallyManagedProduct.sol +++ b/test/examples/external/ExternallyManagedProduct.sol @@ -28,14 +28,12 @@ contract ExternallyManagedProduct is ReferralId public referralId; constructor( - address registry, NftId instanceNftId, IComponents.ProductInfo memory productInfo, IComponents.FeeInfo memory feeInfo, address initialOwner ) SimpleProduct( - registry, instanceNftId, "VerifyingProduct", productInfo, diff --git a/test/examples/fire/FireProductClaims.t.sol b/test/examples/fire/FireProductClaims.t.sol index b79fe1d47..e421c8ac8 100644 --- a/test/examples/fire/FireProductClaims.t.sol +++ b/test/examples/fire/FireProductClaims.t.sol @@ -14,9 +14,12 @@ import {FireTestBase} from "./FireTestBase.t.sol"; import {IClaimService} from "../../../contracts/product/IClaimService.sol"; import {IComponent} from "../../../contracts/shared/IComponent.sol"; import {INftOwnable} from "../../../contracts/shared/INftOwnable.sol"; +import {IRegisterable} from "../../../contracts/shared/IRegisterable.sol"; import {IPolicy} from "../../../contracts/instance/module/IPolicy.sol"; +import {IRegisterable} from "../../../contracts/shared/IRegisterable.sol"; import {NftId, NftIdLib} from "../../../contracts/type/NftId.sol"; import {PayoutId} from "../../../contracts/type/PayoutId.sol"; +import {GIF_INITIAL_RELEASE} from "../../../contracts/registry/Registry.sol"; import {Seconds, SecondsLib} from "../../../contracts/type/Seconds.sol"; import {Timestamp, TimestampLib} from "../../../contracts/type/Timestamp.sol"; import {UFixedLib} from "../../../contracts/type/UFixed.sol"; @@ -793,9 +796,10 @@ contract FireProductClaimsTest is FireTestBase { // THEN vm.expectRevert(abi.encodeWithSelector( - INftOwnable.ErrorNftOwnableInvalidType.selector, + IRegisterable.ErrorRegisterableInvalidType.selector, firePoolNftId, - POLICY())); + POLICY(), + GIF_INITIAL_RELEASE())); // WHEN - submit claim for policy that is wrong type fireProduct.submitClaim(firePoolNftId, fireId); diff --git a/test/examples/fire/FireTestBase.t.sol b/test/examples/fire/FireTestBase.t.sol index 171ee8d3a..5da606582 100644 --- a/test/examples/fire/FireTestBase.t.sol +++ b/test/examples/fire/FireTestBase.t.sol @@ -38,7 +38,7 @@ contract FireTestBase is GifTest { vm.stopPrank(); // whitelist fire token and make it active for release 3 - vm.startPrank(registryOwner); + vm.startPrank(gifManager); tokenRegistry.registerToken(address(fireUSD)); tokenRegistry.setActiveForVersion( currentChainId, @@ -52,7 +52,6 @@ contract FireTestBase is GifTest { vm.startPrank(fireProductOwner); FireProductAuthorization productAuth = new FireProductAuthorization("FireProduct"); fireProduct = new FireProduct( - address(registry), instanceNftId, "FireProduct", productAuth @@ -69,7 +68,6 @@ contract FireTestBase is GifTest { vm.startPrank(firePoolOwner); FirePoolAuthorization poolAuth = new FirePoolAuthorization("FirePool"); firePool = new FirePool( - address(registry), fireProductNftId, "FirePool", poolAuth diff --git a/test/examples/flight/FlightBase.t.sol b/test/examples/flight/FlightBase.t.sol index 87a198787..ae4052121 100644 --- a/test/examples/flight/FlightBase.t.sol +++ b/test/examples/flight/FlightBase.t.sol @@ -72,7 +72,7 @@ contract FlightBaseTest is GifTest { vm.stopPrank(); // whitelist fire token and make it active for release 3 - vm.startPrank(registryOwner); + vm.startPrank(gifManager); tokenRegistry.registerToken(address(flightUSD)); tokenRegistry.setActiveForVersion( currentChainId, @@ -95,7 +95,6 @@ contract FlightBaseTest is GifTest { vm.startPrank(flightOwner); FlightProductAuthorization productAuthz = new FlightProductAuthorization("FlightProduct"); flightProduct = new FlightProduct( - address(registry), instanceNftId, "FlightProduct", productAuthz @@ -126,7 +125,6 @@ contract FlightBaseTest is GifTest { vm.startPrank(flightOwner); FlightPoolAuthorization poolAuthz = new FlightPoolAuthorization("FlightPool"); flightPool = new FlightPool( - address(registry), flightProductNftId, "FlightPool", poolAuthz @@ -145,7 +143,6 @@ contract FlightBaseTest is GifTest { vm.startPrank(flightOwner); FlightOracleAuthorization oracleAuthz = new FlightOracleAuthorization("FlightOracle", COMMIT_HASH); flightOracle = new FlightOracle( - address(registry), flightProductNftId, "FlightOracle", oracleAuthz diff --git a/test/examples/verifying/VerifyingPool.sol b/test/examples/verifying/VerifyingPool.sol index 8005c0915..1b7b8b9fc 100644 --- a/test/examples/verifying/VerifyingPool.sol +++ b/test/examples/verifying/VerifyingPool.sol @@ -29,13 +29,11 @@ contract VerifyingPool is address public bundleOwner; constructor( - address registry, NftId productNftId, IComponents.PoolInfo memory poolInfo, address initialOwner ) SimplePool( - registry, productNftId, poolInfo, new BasicPoolAuthorization("VerifyingPool"), diff --git a/test/examples/verifying/VerifyingPool.t.sol b/test/examples/verifying/VerifyingPool.t.sol index 8fbc0e8bb..64947a046 100644 --- a/test/examples/verifying/VerifyingPool.t.sol +++ b/test/examples/verifying/VerifyingPool.t.sol @@ -33,7 +33,7 @@ contract VerifyingPoolTest is GifTest { vProduct.init(); vm.stopPrank(); - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(productOwner, 10000); vm.stopPrank(); @@ -131,7 +131,6 @@ contract VerifyingPoolTest is GifTest { IComponents.FeeInfo memory feeInfo = _getSimpleFeeInfo(); vProduct = new VerifyingProduct( - address(registry), instanceNftId, productInfo, feeInfo, @@ -152,7 +151,6 @@ contract VerifyingPoolTest is GifTest { }); vPool = new VerifyingPool( - address(registry), prdNftId, poolInfo, poolOwner diff --git a/test/examples/verifying/VerifyingProduct.sol b/test/examples/verifying/VerifyingProduct.sol index aec0fa30a..54be55a51 100644 --- a/test/examples/verifying/VerifyingProduct.sol +++ b/test/examples/verifying/VerifyingProduct.sol @@ -29,14 +29,12 @@ contract VerifyingProduct is ReferralId public referralId; constructor( - address registry, NftId instanceNftId, IComponents.ProductInfo memory productInfo, IComponents.FeeInfo memory feeInfo, address initialOwner ) SimpleProduct( - registry, instanceNftId, "VerifyingProduct", productInfo, diff --git a/test/instance/InstanceReader.t.sol b/test/instance/InstanceReader.t.sol index a51519cb8..720b54245 100644 --- a/test/instance/InstanceReader.t.sol +++ b/test/instance/InstanceReader.t.sol @@ -20,7 +20,7 @@ contract InstanceReaderTest is GifTest { function test_instanceReaderUpgradeMasterInstanceReader() public { // GIVEN - vm.startPrank(registryOwner); + vm.startPrank(gifManager); InstanceReader newMasterInstanceReader = _createNewMasterInstanceReader(); // address newMasterInstanceReaderAddress = address(newMasterInstanceReader); @@ -46,13 +46,13 @@ contract InstanceReaderTest is GifTest { IInstanceService.ErrorInstanceServiceInstanceReaderInstanceMismatch.selector)); // WHEN - vm.startPrank(registryOwner); + vm.startPrank(gifManager); instanceService.upgradeMasterInstanceReader(address(newMasterInstanceReader)); } function test_instanceReaderUpgradeMasterInstanceReader_same_reader() public { // GIVEN - vm.startPrank(registryOwner); + vm.startPrank(gifManager); // THEN vm.expectRevert( @@ -65,7 +65,7 @@ contract InstanceReaderTest is GifTest { function test_instanceReaderUpgradeInstanceReaderAuthorized() public { // GIVEN - vm.startPrank(registryOwner); + vm.startPrank(gifManager); InstanceReader newMasterInstanceReader = _createNewMasterInstanceReader(); instanceService.upgradeMasterInstanceReader(address(newMasterInstanceReader)); vm.stopPrank(); @@ -89,7 +89,7 @@ contract InstanceReaderTest is GifTest { function test_instanceReaderUpgradeInstanceReaderNotAuthorized() public { // GIVEN - vm.startPrank(registryOwner); + vm.startPrank(gifManager); InstanceReader newMasterInstanceReader = _createNewMasterInstanceReader(); instanceService.upgradeMasterInstanceReader(address(newMasterInstanceReader)); vm.stopPrank(); diff --git a/test/instance/MockObjectSet.t.sol b/test/instance/MockObjectSet.t.sol index 77b2b97c5..246282b9a 100644 --- a/test/instance/MockObjectSet.t.sol +++ b/test/instance/MockObjectSet.t.sol @@ -32,7 +32,7 @@ contract MockObjectSetTest is GifTest { //authority = new MockAuthority(); // initialize clone - objectSet.initialize(instance.getInstanceAdmin().authority(), address(instance.getRegistry()), address(instance)); + objectSet.initialize(instance.getInstanceAdmin().authority(), address(instance)); } @@ -134,6 +134,6 @@ contract MockObjectSetTest is GifTest { // TODO: fix me function skip_test_MockObjectSetAttemptDoubleInitialization() public { vm.expectRevert(abi.encodeWithSelector(Initializable.InvalidInitialization.selector)); - objectSet.initialize(instance.getInstanceAdmin().authority(), address(instance.getRegistry()), address(instance)); + objectSet.initialize(instance.getInstanceAdmin().authority(), address(instance)); } } diff --git a/test/instance/service/PricingService.t.sol b/test/instance/service/PricingService.t.sol index 1c9d78ba8..76a95f04d 100644 --- a/test/instance/service/PricingService.t.sol +++ b/test/instance/service/PricingService.t.sol @@ -370,7 +370,7 @@ contract PricingServiceTest is GifTest { vm.stopPrank(); // -- create bundle on pool - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(investor, 10000); vm.stopPrank(); diff --git a/test/instance/service/TestDistributionService.t.sol b/test/instance/service/TestDistributionService.t.sol index 21bc5a31f..166087132 100644 --- a/test/instance/service/TestDistributionService.t.sol +++ b/test/instance/service/TestDistributionService.t.sol @@ -23,7 +23,6 @@ contract TestDistributionService is GifTest { function test_distributionServiceRegisterHappyCase() public { vm.startPrank(distributionOwner); distribution = new SimpleDistribution( - address(registry), testProdNftId, new BasicDistributionAuthorization("SimpleDistribution"), distributionOwner diff --git a/test/instance/service/TestPoolService.t.sol b/test/instance/service/TestPoolService.t.sol index 3a7161c48..877391a0d 100644 --- a/test/instance/service/TestPoolService.t.sol +++ b/test/instance/service/TestPoolService.t.sol @@ -26,7 +26,6 @@ contract TestPoolService is GifTest { function test_poolServiceRegisterHappyCase() public { vm.startPrank(outsider); testPool = new SimplePool( - address(registry), testProdNftId, _getDefaultSimplePoolInfo(), new BasicPoolAuthorization("SimplePool"), diff --git a/test/mock/ContractV01.sol b/test/mock/ContractV01.sol index b72a08f21..6c6ccd51a 100644 --- a/test/mock/ContractV01.sol +++ b/test/mock/ContractV01.sol @@ -1,11 +1,13 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; +import {IVersionable} from "../../contracts/shared/IVersionable.sol"; import {Version, VersionLib} from "../../contracts/type/Version.sol"; -import {Versionable} from "../../contracts/upgradeability/Versionable.sol"; +import {Versionable} from "../../contracts/shared/Versionable.sol"; +import {Upgradeable} from "../../contracts/upgradeability/Upgradeable.sol"; -contract ContractV01 is Versionable { +contract ContractV01 is Upgradeable { // keccak256(abi.encode(uint256(keccak256("gif-next.test_forge.mock.contractV01.sol")) - 1)) & ~bytes32(uint256(0xff)); bytes32 public constant LOCATION_V1 = 0x6548007c3f4340f82f348c576c0ff69f4f529cadd5ad41f96aae61abceeaa300; @@ -19,10 +21,10 @@ contract ContractV01 is Versionable { function getVersion() public pure - virtual override + virtual override (IVersionable, Versionable) returns(Version) { - return VersionLib.toVersion(1, 0, 0); + return VersionLib.toVersion(3, 0, 0); } function getDataV01() diff --git a/test/mock/ContractV02.sol b/test/mock/ContractV02.sol index c4940edd3..c790de741 100644 --- a/test/mock/ContractV02.sol +++ b/test/mock/ContractV02.sol @@ -20,7 +20,7 @@ contract ContractV02 is ContractV01 { virtual override returns(Version) { - return VersionLib.toVersion(1, 0, 1); + return VersionLib.toVersion(3, 0, 1); } function getDataV02() external pure returns(bytes memory) { diff --git a/test/mock/MockObjectSet.sol b/test/mock/MockObjectSet.sol index f6cecec78..3f52636d3 100644 --- a/test/mock/MockObjectSet.sol +++ b/test/mock/MockObjectSet.sol @@ -8,12 +8,12 @@ import {ObjectSet} from "../../contracts/instance/base/ObjectSet.sol"; contract MockObjectSet is ObjectSet { - function initialize(address authority, address registry, address instanceAddress) + function initialize(address authority, address instanceAddress) external initializer() { _instanceAddress = instanceAddress; - __Cloneable_init(authority, registry); + __Cloneable_init(authority); emit LogObjectSetInitialized(instanceAddress); } diff --git a/test/mock/MockSizeVersionable.sol b/test/mock/MockSizeVersionable.sol index 1c56d5d04..35a206545 100644 --- a/test/mock/MockSizeVersionable.sol +++ b/test/mock/MockSizeVersionable.sol @@ -1,11 +1,13 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; -import {Versionable} from "../../contracts/upgradeability/Versionable.sol"; +import {Upgradeable} from "../../contracts/upgradeability/Upgradeable.sol"; import {Version, VersionLib} from "../../contracts/type/Version.sol"; +import {IVersionable} from "../../contracts/shared/IVersionable.sol"; +import {Versionable} from "../../contracts/shared/Versionable.sol"; -contract MockSizeVersionable is Versionable { - function getVersion() public pure virtual override returns(Version) { +contract MockSizeUpgradeable is Upgradeable { + function getVersion() public pure virtual override (Versionable, IVersionable) returns(Version) { return VersionLib.zeroVersion(); } } diff --git a/test/mock/MyPolicyHolder.sol b/test/mock/MyPolicyHolder.sol index fd3e7fff5..74c0b87f6 100644 --- a/test/mock/MyPolicyHolder.sol +++ b/test/mock/MyPolicyHolder.sol @@ -27,12 +27,12 @@ contract MyPolicyHolder is PolicyHolder { SimpleProduct public product; bool public isReentrant = false; - constructor (address registryAddress){ - _initialize(registryAddress); + constructor() { + _initialize(); } - function _initialize(address registryAddress) internal initializer() { - _initializePolicyHolder(registryAddress); + function _initialize() internal initializer() { + __PolicyHolder_init(); } // callback when policy is activated diff --git a/test/mock/NftOwnableMock.sol b/test/mock/NftOwnableMock.sol index dd21732ac..16a022f40 100644 --- a/test/mock/NftOwnableMock.sol +++ b/test/mock/NftOwnableMock.sol @@ -5,16 +5,16 @@ import {NftOwnable} from "../../contracts/shared/NftOwnable.sol"; contract NftOwnableMock is NftOwnable { - constructor(address registry) { - initialize(registry); + constructor() { + initialize(); } - function initialize(address registry) public initializer() { - __NftOwnable_init(registry, msg.sender); + function initialize() public initializer() { + __NftOwnable_init(msg.sender); } - function initializeNftOwnable(address owner, address registry) public initializer() { - __NftOwnable_init(registry, owner); + function initializeNftOwnable(address owner) public initializer() { + __NftOwnable_init(owner); } function linkToNftOwnable(address nftOwnableAddress) external { @@ -27,13 +27,12 @@ contract NftOwnableMock is NftOwnable { contract NftOwnableMockUninitialized is NftOwnable { function initialize( - address initialOwner, - address registry + address initialOwner ) public initializer() { - __NftOwnable_init(initialOwner, registry); + __NftOwnable_init(initialOwner); } /* function linkToNftOwnable(address nftOwnableAddress) external { diff --git a/test/mock/ProductMock.sol b/test/mock/ProductMock.sol new file mode 100644 index 000000000..d8eeaf3e0 --- /dev/null +++ b/test/mock/ProductMock.sol @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.20; + +import {AccessManagerCloneable} from "../../contracts/authorization/AccessManagerCloneable.sol"; +import {NftId} from "../../contracts/type/NftId.sol"; +import {SimpleProduct} from "../../contracts/examples/unpermissioned/SimpleProduct.sol"; +import {IAuthorization} from "../../contracts/authorization/IAuthorization.sol"; +import {IComponents} from "../../contracts/instance/module/IComponents.sol"; +import {IInstanceLinkedComponent} from "../../contracts/shared/IInstanceLinkedComponent.sol"; +import {ObjectType} from "../../contracts/type/ObjectType.sol"; +import {SimpleProduct} from "../../contracts/examples/unpermissioned/SimpleProduct.sol"; +import {Version, VersionLib} from "../../contracts/type/Version.sol"; +import {IVersionable} from "../../contracts/shared/IVersionable.sol"; +import {Versionable} from "../../contracts/shared/Versionable.sol"; + + + +contract ProductMockWithoutInstanceCheck is SimpleProduct { + constructor( + NftId instanceNftId, + string memory name, + IComponents.ProductInfo memory productInfo, + IComponents.FeeInfo memory feeInfo, + IAuthorization authorization, + address initialOwner + ) + SimpleProduct( + instanceNftId, + name, + productInfo, + feeInfo, + authorization, + initialOwner + ) + { } + + // instance is not checked nor set + function __InstanceLinkedComponent_init( + NftId parentNftId, + string memory name, + ObjectType componentType, + IAuthorization authorization, + bool isInterceptor, + address initialOwner + ) + internal + virtual override + onlyInitializing() + { + // need v4, for some reason ProductMockV4 have V3... + AccessManagerCloneable accessManager = new AccessManagerCloneable(); + accessManager.initialize(address(this), getRelease()); + + __Component_init( + address(accessManager), + parentNftId, + name, + componentType, + isInterceptor, + initialOwner, + ""); // registry data + + // set instance linked specific parameters + //InstanceLinkedComponentStorage storage $ = _getInstanceLinkedComponentStorage(); + //$._instance = instance; + //$._initialAuthorization = authorization; + + // register interfaces + _registerInterface(type(IInstanceLinkedComponent).interfaceId); + } +} + +contract ProductMockV4 is ProductMockWithoutInstanceCheck { + + constructor( + NftId instanceNftId, + IComponents.ProductInfo memory productInfo, + IComponents.FeeInfo memory feeInfo, + IAuthorization authorization, + address initialOwner + ) + ProductMockWithoutInstanceCheck( + instanceNftId, + "ProductWithoutInstanceCheckV4", + productInfo, + feeInfo, + authorization, + initialOwner + ) + { } + + // for some reason when product is instantiated "accessManager.initialize(address(this));" + // initializes access manager to release 3... + function getVersion() public override(IVersionable, Versionable) pure returns (Version version) { + return VersionLib.toVersion(4, 0, 0); + } +} \ No newline at end of file diff --git a/test/mock/RegisterableMock.sol b/test/mock/RegisterableMock.sol index 49d8a2853..0d03509a4 100644 --- a/test/mock/RegisterableMock.sol +++ b/test/mock/RegisterableMock.sol @@ -7,18 +7,26 @@ import {FoundryRandom} from "foundry-random/FoundryRandom.sol"; import {InitializableERC165} from "../../contracts/shared/InitializableERC165.sol"; import {IRegisterable} from "../../contracts/shared/IRegisterable.sol"; import {IRegistry} from "../../contracts/registry/IRegistry.sol"; -import {IRelease} from "../../contracts/registry/IRelease.sol"; import {MockInterceptor} from "./MockInterceptor.sol"; import {NftId, NftIdLib} from "../../contracts/type/NftId.sol"; import {ObjectType} from "../../contracts/type/ObjectType.sol"; -import {VersionPart, VersionPartLib} from "../../contracts/type/Version.sol"; +import {RegistryLinked} from "../../contracts/shared/RegistryLinked.sol"; +import {Versionable} from "../../contracts/shared/Versionable.sol"; -contract RegisterableMockWithAuthority is InitializableERC165, IRegisterable, MockInterceptor, AccessManaged { +contract RegisterableMockWithAuthority is + IRegisterable, + InitializableERC165, + Versionable, + MockInterceptor, + AccessManaged, + RegistryLinked { error ErrorRegisterableMockIsNotInterceptor(address registerable); IRegistry.ObjectInfo internal _info; + address internal _initialOwner; + bytes internal _data; constructor( address authority, @@ -35,11 +43,12 @@ contract RegisterableMockWithAuthority is InitializableERC165, IRegisterable, Mo nftId, parentNftId, objectType, + getRelease(), isInterceptor, - address(this), - initialOwner, - data + address(this) ); + _initialOwner = initialOwner; + _data = data; initializeMock(); } @@ -54,11 +63,6 @@ contract RegisterableMockWithAuthority is InitializableERC165, IRegisterable, Mo function isActive() external view returns (bool active) { return true; } - // from IRegisterable - function getRelease() public virtual override pure returns (VersionPart release) { - return VersionPartLib.toVersionPart(3); - } - function getInitialInfo() public view @@ -68,6 +72,15 @@ contract RegisterableMockWithAuthority is InitializableERC165, IRegisterable, Mo return _info; } + function getInitialData() + public + view + virtual + returns (bytes memory) + { + return _data; + } + function nftTransferFrom(address from, address to, uint256 tokenId, address operator) public override { if(!_info.isInterceptor) { revert ErrorRegisterableMockIsNotInterceptor(address(this)); @@ -77,12 +90,12 @@ contract RegisterableMockWithAuthority is InitializableERC165, IRegisterable, Mo // from INftOwnable function linkToRegisteredNftId() external returns (NftId) { /*do nothing*/ } + function getOwner() external virtual view returns (address) {return _initialOwner; } + + // from INftOwnable + function getRegistryAddress() external view returns (address) { revert("NotSupported"); } + function getNftId() external view returns (NftId) { revert("NotSupported"); } - // from INftOwnable, DO NOT USE - function getRegistry() external view returns (IRegistry) { revert(); } - function getRegistryAddress() external view returns (address) { revert(); } - function getNftId() external view returns (NftId) { revert(); } - function getOwner() external view returns (address) { revert(); } } diff --git a/test/mock/RegistryServiceManagerMock.sol b/test/mock/RegistryServiceManagerMock.sol index e747eba2c..7665eee32 100644 --- a/test/mock/RegistryServiceManagerMock.sol +++ b/test/mock/RegistryServiceManagerMock.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; -import {Registry} from "../../contracts/registry/Registry.sol"; import {RegistryServiceManager} from "../../contracts/registry/RegistryServiceManager.sol"; import {RegistryServiceHarness} from "../registryService/RegistryServiceHarness.sol"; import {RegistryServiceMock} from "./RegistryServiceMock.sol"; @@ -9,8 +8,8 @@ import {RegistryServiceMock} from "./RegistryServiceMock.sol"; contract RegistryServiceManagerMock is RegistryServiceManager { - constructor(address initialAuthority, address registry, bytes32 salt) - RegistryServiceManager(initialAuthority, registry, salt) + constructor(address initialAuthority, bytes32 salt) + RegistryServiceManager(initialAuthority, salt) { bytes memory emptyUpgradeData; @@ -24,8 +23,8 @@ contract RegistryServiceManagerMock is RegistryServiceManager contract RegistryServiceManagerMockWithHarness is RegistryServiceManager { - constructor(address initialAuthority, address registry, bytes32 salt) - RegistryServiceManager(initialAuthority, registry, salt) + constructor(address initialAuthority, bytes32 salt) + RegistryServiceManager(initialAuthority, salt) { bytes memory emptyUpgradeData; diff --git a/test/mock/RegistryServiceMock.sol b/test/mock/RegistryServiceMock.sol index b3ba06670..c57672945 100644 --- a/test/mock/RegistryServiceMock.sol +++ b/test/mock/RegistryServiceMock.sol @@ -5,8 +5,8 @@ import {ObjectType, REGISTRY} from "../../contracts/type/ObjectType.sol"; import {Version, VersionLib} from "../../contracts/type/Version.sol"; import {Service} from "../../contracts/shared/Service.sol"; -import {IVersionable} from "../../contracts/upgradeability/IVersionable.sol"; -import {Versionable} from "../../contracts/upgradeability/Versionable.sol"; +import {IUpgradeable} from "../../contracts/upgradeability/IUpgradeable.sol"; +import {Upgradeable} from "../../contracts/upgradeability/Upgradeable.sol"; /* contract RegistryServiceMock is Versionable { diff --git a/test/mock/RegistryServiceUpgradeMock.sol b/test/mock/RegistryServiceUpgradeMock.sol index 0a205724b..9c53c3a85 100644 --- a/test/mock/RegistryServiceUpgradeMock.sol +++ b/test/mock/RegistryServiceUpgradeMock.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; -import {IVersionable} from "../../contracts/upgradeability/IVersionable.sol"; -import {Versionable} from "../../contracts/upgradeability/Versionable.sol"; +import {IVersionable} from "../../contracts/shared/IVersionable.sol"; +import {Upgradeable} from "../../contracts/upgradeability/Upgradeable.sol"; import {Service} from "../../contracts/shared/Service.sol"; import {RegistryService} from "../../contracts/registry/RegistryService.sol"; import {Version, VersionLib} from "../../contracts/type/Version.sol"; diff --git a/test/mock/ServiceAuthorizationMock.sol b/test/mock/ServiceAuthorizationMock.sol index 43123f1ac..96318ef35 100644 --- a/test/mock/ServiceAuthorizationMock.sol +++ b/test/mock/ServiceAuthorizationMock.sol @@ -13,7 +13,7 @@ contract ServiceAuthorizationMockWithRegistryService ServiceAuthorization( "ReleaseAdmin", RELEASE(), - uint8(release.toInt()), + release, COMMIT_HASH) {} @@ -37,7 +37,7 @@ contract ServiceAuthorizationMock is ServiceAuthorization ServiceAuthorization( "MockServiceAuthorization", SERVICE(), - uint8(release.toInt()), + release, COMMIT_HASH ) { diff --git a/test/mock/ServiceMock.sol b/test/mock/ServiceMock.sol index dd5bc6e30..ec813096e 100644 --- a/test/mock/ServiceMock.sol +++ b/test/mock/ServiceMock.sol @@ -7,11 +7,13 @@ import {FoundryRandom} from "foundry-random/FoundryRandom.sol"; import {NftId} from "../../contracts/type/NftId.sol"; import {Version, VersionPart, VersionLib, VersionPartLib} from "../../contracts/type/Version.sol"; import {ObjectType, ObjectTypeLib, REGISTRY, SERVICE, PRODUCT, POOL, ORACLE, DISTRIBUTION} from "../../contracts/type/ObjectType.sol"; +import {INftOwnable} from "../../contracts/shared/INftOwnable.sol"; import {IRegisterable} from "../../contracts/shared/IRegisterable.sol"; -import {IRelease} from "../../contracts/registry/IRelease.sol"; +import {IVersionable} from "../../contracts/shared/IVersionable.sol"; import {IService} from "../../contracts/shared/IService.sol"; import {RegisterableMockWithAuthority} from "./RegisterableMock.sol"; import {RoleId, RoleIdLib} from "../../contracts/type/RoleId.sol"; +import {Versionable} from "../../contracts/shared/Versionable.sol"; contract ServiceMock is RegisterableMockWithAuthority, IService { @@ -23,20 +25,19 @@ contract ServiceMock is RegisterableMockWithAuthority, IService { SERVICE(), isInterceptor, initialOwner, - "") + abi.encode(getDomain(), getRelease())) { - _info.data = abi.encode(getDomain(), getVersion().toMajorPart()); - initialize(initialAuthority); + initialize(); } - function initialize(address initialAuthority) internal initializer() { + function initialize() internal initializer() { _registerInterface(type(IService).interfaceId); } // from IRegisterable / IService - function getRelease() public pure virtual override (IRelease, RegisterableMockWithAuthority) returns(VersionPart) { - return VersionPartLib.toVersionPart(3); - } + //function getVersion() public pure virtual override (IVersionable, RegisterableMockWithAuthority) returns(VersionPart) { + // return VersionPartLib.toVersionPart(3); + //} // from IService function getDomain() public pure virtual returns(ObjectType) { @@ -46,31 +47,16 @@ contract ServiceMock is RegisterableMockWithAuthority, IService { function getRoleId() external virtual override pure returns(RoleId serviceRoleId) { return RoleIdLib.toServiceRoleId(getDomain(), getRelease()); } - - // from IVersionable - function getVersion() - public - pure - virtual override// (IVersionable, Versionable) - returns(Version) - { - return VersionLib.toVersion(uint8(getRelease().toInt()),0,0); - } - // from IVersionable, DON NOT USE - function initializeVersionable(address activatedBy, bytes memory activationData) external { revert("not implemented"); } - function upgradeVersionable(bytes memory upgradeData) external { revert("not implemented"); } + // from IUpgradeable, DON NOT USE + function initialize(address activatedBy, bytes memory activationData) external { revert("not implemented"); } + function upgrade(bytes memory upgradeData) external { revert("not implemented"); } } contract SelfOwnedServiceMock is ServiceMock { constructor(NftId nftId, NftId registryNftId, bool isInterceptor, address initialAuthority) - ServiceMock( - nftId, - registryNftId, - isInterceptor, - address(this), - initialAuthority) + ServiceMock(nftId, registryNftId, isInterceptor, address(this), initialAuthority) {} function getDomain() public pure override returns(ObjectType) { @@ -83,12 +69,7 @@ contract ServiceMockWithRandomInvalidType is ServiceMock { ObjectType public immutable _invalidType; constructor(NftId nftId, NftId registryNftId, bool isInterceptor, address initialOwner, address initialAuthority) - ServiceMock( - nftId, - registryNftId, - isInterceptor, - initialOwner, - initialAuthority) + ServiceMock(nftId, registryNftId, isInterceptor, initialOwner, initialAuthority) { FoundryRandom rng = new FoundryRandom(); @@ -115,12 +96,7 @@ contract ServiceMockWithRandomInvalidAddress is ServiceMock { address public immutable _invalidAddress; constructor(NftId nftId, NftId registryNftId, bool isInterceptor, address initialOwner, address initialAuthority) - ServiceMock( - nftId, - registryNftId, - isInterceptor, - initialOwner, - initialAuthority) + ServiceMock(nftId, registryNftId, isInterceptor, initialOwner, initialAuthority) { FoundryRandom rng = new FoundryRandom(); @@ -145,27 +121,19 @@ contract ServiceMockWithRandomInvalidAddress is ServiceMock { contract ServiceMockOldVersion is ServiceMock { constructor(NftId nftId, NftId registryNftId, bool isInterceptor, address initialOwner, address initialAuthority) - ServiceMock( - nftId, - registryNftId, - isInterceptor, - initialOwner, - initialAuthority) + ServiceMock(nftId, registryNftId, isInterceptor, initialOwner, initialAuthority) {} - function getRelease() public pure virtual override returns(VersionPart) { return VersionPartLib.toVersionPart(2); } + function getVersion() public pure virtual override (Versionable, IVersionable) returns(Version) { return VersionLib.toVersion(2, 0, 0); } } contract ServiceMockNewVersion is ServiceMock { constructor(NftId nftId, NftId registryNftId, bool isInterceptor, address initialOwner, address initialAuthority) - ServiceMock( - nftId, - registryNftId, - isInterceptor, - initialOwner, - initialAuthority) + ServiceMock(nftId, registryNftId, isInterceptor, initialOwner, initialAuthority) {} + + function getVersion() public pure virtual override (Versionable, IVersionable) returns(Version) { return VersionLib.toVersion(4, 0, 0); } } contract ServiceMockWithRegistryDomainV3 is ServiceMock { @@ -183,7 +151,7 @@ contract ServiceMockWithRegistryDomainV4 is ServiceMock ServiceMock(nftId, registryNftId, isInterceptor, initialOwner, initialAuthority) {} - function getRelease() public pure virtual override returns(VersionPart) { return VersionPartLib.toVersionPart(4); } + function getVersion() public pure virtual override (Versionable, IVersionable) returns(Version) { return VersionLib.toVersion(4, 0, 0); } function getDomain() public pure virtual override returns(ObjectType) { return REGISTRY(); } } @@ -193,6 +161,6 @@ contract ServiceMockWithRegistryDomainV5 is ServiceMock ServiceMock(nftId, registryNftId, isInterceptor, initialOwner, initialAuthority) {} - function getRelease() public pure virtual override returns(VersionPart) { return VersionPartLib.toVersionPart(5); } + function getVersion() public pure virtual override (Versionable, IVersionable) returns(Version) { return VersionLib.toVersion(5, 0 , 0); } function getDomain() public pure virtual override returns(ObjectType) { return REGISTRY(); } } diff --git a/test/registry/RegistryObjectTypeExtension.t.sol b/test/registry/RegistryObjectTypeExtension.t.sol index 0e8fbab06..9f8759245 100644 --- a/test/registry/RegistryObjectTypeExtension.t.sol +++ b/test/registry/RegistryObjectTypeExtension.t.sol @@ -4,7 +4,8 @@ pragma solidity ^0.8.20; import {console} from "../../lib/forge-std/src/Test.sol"; import {IRegistry} from "../../contracts/registry/IRegistry.sol"; -import {IVersionable} from "../../contracts/upgradeability/IVersionable.sol"; +import {IUpgradeable} from "../../contracts/upgradeability/IUpgradeable.sol"; +import {IVersionable} from "../../contracts/shared/IVersionable.sol"; import {GifTest} from "../base/GifTest.sol"; import {NftId} from "../../contracts/type/NftId.sol"; @@ -43,13 +44,13 @@ contract RegistryServiceUpgraded is RegistryService { } /// @dev permissionless registry function for testing - function register(IRegistry.ObjectInfo memory info) external virtual returns (NftId nftId) { - return getRegistry().register(info); + function register(IRegistry.ObjectInfo memory info, address initialOwner, bytes memory data) external virtual returns (NftId nftId) { + return _getRegistry().register(info, initialOwner, data); } /// @dev permissionless registry function for testing - function registerWithCustomType(IRegistry.ObjectInfo memory info) external virtual returns (NftId nftId) { - return getRegistry().registerWithCustomType(info); + function registerWithCustomType(IRegistry.ObjectInfo memory info, address initialOwner, bytes memory data) external virtual returns (NftId nftId) { + return _getRegistry().registerWithCustomType(info, initialOwner, data); } } @@ -91,11 +92,14 @@ contract RegistryObjectTypeExtensionTest is GifTest { /// @dev register foo type object with REGISTRY as parent function test_registryObjectTypeExtensionRegisterFooWithRegistryParentHappyCase() public { // GIVEN - IRegistry.ObjectInfo memory fooInfo = _toPlainObjectInfo(registryNftId, FOO(), outsider); + IRegistry.ObjectInfo memory fooInfo; + address fooOwner; + bytes memory fooData; + (fooInfo, fooOwner, fooData) = _toPlainObjectInfo(registryNftId, FOO(), outsider); // WHEN vm.prank(outsider); - NftId fooNftId = registryServiceUpgraded.registerWithCustomType(fooInfo); + NftId fooNftId = registryServiceUpgraded.registerWithCustomType(fooInfo, fooOwner, fooData); // THEN assertTrue(fooNftId.gtz(), "fooNftId is zero"); @@ -107,8 +111,7 @@ contract RegistryObjectTypeExtensionTest is GifTest { assertEq(fooInfoOut.objectType.toInt(), FOO().toInt(), "unexpected objectType"); assertFalse(fooInfoOut.isInterceptor, "isInterceptor is true"); assertEq(fooInfoOut.objectAddress, fooInfo.objectAddress, "unexpected objectAddress"); - assertEq(fooInfoOut.initialOwner, outsider, "unexpected initialOwner"); - assertEq(fooInfoOut.data.length, 0, "unexpected data length"); + assertEq(registry.getObjectData(fooNftId).length, 0, "unexpected data length"); assertEq(registry.ownerOf(fooNftId), outsider, "unexpected owner"); } @@ -117,13 +120,16 @@ contract RegistryObjectTypeExtensionTest is GifTest { function test_registryObjectTypeExtensionRegisterFooWithGlobalRegistryParentHappyCase() public { // GIVEN NftId globalRegistryNftId = registry.getParentNftId(registryNftId); - IRegistry.ObjectInfo memory fooInfo = _toPlainObjectInfo(globalRegistryNftId, FOO(), outsider); + IRegistry.ObjectInfo memory fooInfo; + address fooOwner; + bytes memory fooData; + (fooInfo, fooOwner, fooData) = _toPlainObjectInfo(globalRegistryNftId, FOO(), outsider); assertEq(globalRegistryNftId.toInt(), 2101, "unexpected globalRegistryNftId"); // WHEN vm.chainId(1); vm.prank(outsider); - NftId fooNftId = registryServiceUpgraded.registerWithCustomType(fooInfo); + NftId fooNftId = registryServiceUpgraded.registerWithCustomType(fooInfo, fooOwner, fooData); // THEN assertTrue(fooNftId.gtz(), "fooNftId is zero"); @@ -135,8 +141,7 @@ contract RegistryObjectTypeExtensionTest is GifTest { assertEq(fooInfoOut.objectType.toInt(), FOO().toInt(), "unexpected objectType"); assertFalse(fooInfoOut.isInterceptor, "isInterceptor is true"); assertEq(fooInfoOut.objectAddress, fooInfo.objectAddress, "unexpected objectAddress"); - assertEq(fooInfoOut.initialOwner, outsider, "unexpected initialOwner"); - assertEq(fooInfoOut.data.length, 0, "unexpected data length"); + assertEq(registry.getObjectData(fooNftId).length, 0, "unexpected data length"); assertEq(registry.ownerOf(fooNftId), outsider, "unexpected owner"); } @@ -144,13 +149,16 @@ contract RegistryObjectTypeExtensionTest is GifTest { /// @dev register foo type object with INSTANCE as parent function test_registryObjectTypeExtensionRegisterFooWithInstanceParentHappyCase() public { // GIVEN - IRegistry.ObjectInfo memory fooInfo = _toPlainObjectInfo(instanceNftId, FOO(), outsider); + IRegistry.ObjectInfo memory fooInfo; + address fooOwner; + bytes memory fooData; + (fooInfo, fooOwner, fooData) = _toPlainObjectInfo(instanceNftId, FOO(), outsider); assertEq(instance.getNftId().toInt(), instanceNftId.toInt(), "unexpected instanceNftId"); // WHEN vm.chainId(1); vm.prank(outsider); - NftId fooNftId = registryServiceUpgraded.registerWithCustomType(fooInfo); + NftId fooNftId = registryServiceUpgraded.registerWithCustomType(fooInfo, fooOwner, fooData); // THEN assertTrue(fooNftId.gtz(), "fooNftId is zero"); @@ -162,8 +170,7 @@ contract RegistryObjectTypeExtensionTest is GifTest { assertEq(fooInfoOut.objectType.toInt(), FOO().toInt(), "unexpected objectType"); assertFalse(fooInfoOut.isInterceptor, "isInterceptor is true"); assertEq(fooInfoOut.objectAddress, fooInfo.objectAddress, "unexpected objectAddress"); - assertEq(fooInfoOut.initialOwner, outsider, "unexpected initialOwner"); - assertEq(fooInfoOut.data.length, 0, "unexpected data length"); + assertEq(registry.getObjectData(fooNftId).length, 0, "unexpected data length"); assertEq(registry.ownerOf(fooNftId), outsider, "unexpected owner"); } @@ -172,13 +179,16 @@ contract RegistryObjectTypeExtensionTest is GifTest { function test_registryObjectTypeExtensionRegisterFooWithProductParentHappyCase() public { // GIVEN _prepareProduct(); - IRegistry.ObjectInfo memory fooInfo = _toPlainObjectInfo(productNftId, FOO(), outsider); + IRegistry.ObjectInfo memory fooInfo; + address fooOwner; + bytes memory fooData; + (fooInfo, fooOwner, fooData) = _toPlainObjectInfo(productNftId, FOO(), outsider); assertEq(product.getNftId().toInt(), productNftId.toInt(), "unexpected productNftId"); // WHEN vm.chainId(1); vm.prank(outsider); - NftId fooNftId = registryServiceUpgraded.registerWithCustomType(fooInfo); + NftId fooNftId = registryServiceUpgraded.registerWithCustomType(fooInfo, fooOwner, fooData); // THEN assertTrue(fooNftId.gtz(), "fooNftId is zero"); @@ -190,8 +200,7 @@ contract RegistryObjectTypeExtensionTest is GifTest { assertEq(fooInfoOut.objectType.toInt(), FOO().toInt(), "unexpected objectType"); assertFalse(fooInfoOut.isInterceptor, "isInterceptor is true"); assertEq(fooInfoOut.objectAddress, fooInfo.objectAddress, "unexpected objectAddress"); - assertEq(fooInfoOut.initialOwner, outsider, "unexpected initialOwner"); - assertEq(fooInfoOut.data.length, 0, "unexpected data length"); + assertEq(registry.getObjectData(fooNftId).length, 0, "unexpected data length"); assertEq(registry.ownerOf(fooNftId), outsider, "unexpected owner"); } @@ -199,19 +208,25 @@ contract RegistryObjectTypeExtensionTest is GifTest { /// @dev register bar type object with FOO as parent function test_registryObjectTypeExtensionRegisterBarWithFooParentHappyCase() public { - // GIVEN - foo object with registry as parent + // GIVEN - foo object with product as parent _prepareProduct(); - IRegistry.ObjectInfo memory fooInfo = _toPlainObjectInfo(productNftId, FOO(), outsider); + IRegistry.ObjectInfo memory fooInfo; + address fooOwner; + bytes memory fooData; + (fooInfo, fooOwner, fooData) = _toPlainObjectInfo(productNftId, FOO(), outsider); vm.prank(outsider); - NftId fooNftId = registryServiceUpgraded.registerWithCustomType(fooInfo); + NftId fooNftId = registryServiceUpgraded.registerWithCustomType(fooInfo, fooOwner, fooData); // WHEN - create bar object with foo as parent - IRegistry.ObjectInfo memory barInfo = _toPlainObjectInfo(fooNftId, BAR_FOO(), outsider); + IRegistry.ObjectInfo memory barInfo; + address barOwner; + bytes memory barData; + (barInfo, barOwner, barData) = _toPlainObjectInfo(fooNftId, BAR_FOO(), outsider); // modify object address to ensure it is not the same as foo object barInfo.objectAddress = address(123); vm.prank(outsider); - NftId barNftId = registryServiceUpgraded.registerWithCustomType(barInfo); + NftId barNftId = registryServiceUpgraded.registerWithCustomType(barInfo, barOwner, barData); // THEN assertTrue(barNftId.gtz(), "barNftId is zero"); @@ -223,8 +238,7 @@ contract RegistryObjectTypeExtensionTest is GifTest { assertEq(barInfoOut.objectType.toInt(), BAR_FOO().toInt(), "unexpected objectType"); assertFalse(barInfoOut.isInterceptor, "isInterceptor is true"); assertEq(barInfoOut.objectAddress, address(123), "unexpected objectAddress"); - assertEq(barInfoOut.initialOwner, outsider, "unexpected initialOwner"); - assertEq(barInfoOut.data.length, 0, "unexpected data length"); + assertEq(registry.getObjectData(barNftId).length, 0, "unexpected data length"); assertEq(registry.ownerOf(barNftId), outsider, "unexpected owner"); _printObjectHierarchy(barNftId); @@ -235,66 +249,119 @@ contract RegistryObjectTypeExtensionTest is GifTest { /// @dev attempt to register foo type object with global REGISTRY as parent (when not on mainet) function test_registryObjectTypeExtensionRegisterFooWithGlobalRegistryParentNotMainnet() public { - IRegistry.ObjectInfo memory fooInfo = _toPlainObjectInfo(registry.getParentNftId(registryNftId), FOO(), outsider); + IRegistry.ObjectInfo memory fooInfo; + address fooOwner; + bytes memory fooData; + (fooInfo, fooOwner, fooData) = _toPlainObjectInfo(registry.getParentNftId(registryNftId), FOO(), outsider); vm.expectRevert(abi.encodeWithSelector(IRegistry.ErrorRegistryGlobalRegistryAsParent.selector, fooInfo.objectAddress, fooInfo.objectType)); vm.prank(outsider); - NftId fooNftId = registryServiceUpgraded.registerWithCustomType(fooInfo); + NftId fooNftId = registryServiceUpgraded.registerWithCustomType(fooInfo, fooOwner, fooData); } /// @dev attempt to register foo type object with STAKING as parent function test_registryObjectTypeExtensionRegisterFooWithStakingParent() public { - IRegistry.ObjectInfo memory fooInfo = _toPlainObjectInfo(staking.getNftId(), FOO(), outsider); + IRegistry.ObjectInfo memory fooInfo; + address fooOwner; + bytes memory fooData; + (fooInfo, fooOwner, fooData) = _toPlainObjectInfo(staking.getNftId(), FOO(), outsider); vm.expectRevert(abi.encodeWithSelector(IRegistry.ErrorRegistryTypeCombinationInvalid.selector, fooInfo.objectAddress, fooInfo.objectType, STAKING())); vm.prank(outsider); - NftId fooNftId = registryServiceUpgraded.registerWithCustomType(fooInfo); + NftId fooNftId = registryServiceUpgraded.registerWithCustomType(fooInfo, fooOwner, fooData) ; } /// @dev attempt to register foo type object with SERVICE as parent function test_registryObjectTypeExtensionRegisterFooWithServiceParent() public { - IRegistry.ObjectInfo memory fooInfo = _toPlainObjectInfo(registryService.getNftId(), FOO(), outsider); + IRegistry.ObjectInfo memory fooInfo; + address fooOwner; + bytes memory fooData; + (fooInfo, fooOwner, fooData) = _toPlainObjectInfo(registryService.getNftId(), FOO(), outsider); vm.expectRevert(abi.encodeWithSelector(IRegistry.ErrorRegistryTypeCombinationInvalid.selector, fooInfo.objectAddress, fooInfo.objectType, SERVICE())); vm.prank(outsider); - NftId fooNftId = registryServiceUpgraded.registerWithCustomType(fooInfo); + NftId fooNftId = registryServiceUpgraded.registerWithCustomType(fooInfo, fooOwner, fooData); + } + + //---- check custom type object registration with mismatching release versions -----------------------------------// + + function test_registryObjectTypeExtensionRegisterFooWithReleaseTooSmall() public + { + ( + product, + productNftId + ) = _deployAndRegisterNewSimpleProduct("TestProduct"); + + IRegistry.ObjectInfo memory fooInfo; + address fooOwner; + bytes memory fooData; + (fooInfo, fooOwner, fooData) = _toPlainObjectInfo(productNftId, FOO(), outsider); + fooInfo.release = VersionPart.wrap(2); + vm.expectRevert(abi.encodeWithSelector(IRegistry.ErrorRegistryReleaseMismatch.selector, fooInfo.release, product.getRelease(), registryServiceUpgraded.getRelease())); + vm.prank(outsider); + NftId fooNftId = registryServiceUpgraded.registerWithCustomType(fooInfo, fooOwner, fooData); + } + + function test_registryObjectTypeExtensionRegisterFooWithReleaseTooBig() public + { + ( + product, + productNftId + ) = _deployAndRegisterNewSimpleProduct("TestProduct"); + + IRegistry.ObjectInfo memory fooInfo; + address fooOwner; + bytes memory fooData; + (fooInfo, fooOwner, fooData) = _toPlainObjectInfo(productNftId, FOO(), outsider); + fooInfo.release = VersionPart.wrap(4); + vm.expectRevert(abi.encodeWithSelector(IRegistry.ErrorRegistryReleaseMismatch.selector, fooInfo.release, product.getRelease(), registryServiceUpgraded.getRelease())); + vm.prank(outsider); + NftId fooNftId = registryServiceUpgraded.registerWithCustomType(fooInfo, fooOwner, fooData); } //--- check some corner cases -----------------------------------------------------------------------------------// - /// @dev attempt to register instance type via core type register() + /// @dev attempt to register foo type via core type register() function test_registryObjectTypeExtensionRegisterFooViaRegister() public { - IRegistry.ObjectInfo memory fooInfo = _toPlainObjectInfo(registryNftId, FOO(), outsider); + IRegistry.ObjectInfo memory fooInfo; + address fooOwner; + bytes memory fooData; + (fooInfo, fooOwner, fooData) = _toPlainObjectInfo(registryNftId, FOO(), outsider); vm.expectRevert(abi.encodeWithSelector(IRegistry.ErrorRegistryTypeCombinationInvalid.selector, fooInfo.objectAddress, fooInfo.objectType, REGISTRY())); vm.prank(outsider); - NftId fooNftId = registryServiceUpgraded.register(fooInfo); + NftId fooNftId = registryServiceUpgraded.register(fooInfo, fooOwner, fooData); } - /// @dev attempt to register instance type via core type register() function test_registryObjectTypeExtensionRegisterInstanceViaRegisterWithCustomType() public { - IRegistry.ObjectInfo memory fooInfo = _toPlainObjectInfo(instanceNftId, INSTANCE(), outsider); + IRegistry.ObjectInfo memory fooInfo; + address fooOwner; + bytes memory fooData; + (fooInfo, fooOwner, fooData) = _toPlainObjectInfo(instanceNftId, INSTANCE(), outsider); vm.expectRevert(abi.encodeWithSelector(IRegistry.ErrorRegistryCoreTypeRegistration.selector)); vm.prank(outsider); - NftId fooNftId = registryServiceUpgraded.registerWithCustomType(fooInfo); + NftId fooNftId = registryServiceUpgraded.registerWithCustomType(fooInfo, fooOwner, fooData); } //--- helper functions -----------------------------------------------------------------------------------------// - function _toPlainObjectInfo(NftId parentNftId, ObjectType objectType, address owner) internal view returns (IRegistry.ObjectInfo memory info) { - return IRegistry.ObjectInfo({ - nftId: NftId.wrap(0), - parentNftId: parentNftId, - objectType: objectType, - isInterceptor: false, - objectAddress: address(123456789), - initialOwner: owner, - data: emptyData - }); + function _toPlainObjectInfo(NftId parentNftId, ObjectType objectType, address owner) internal view returns (IRegistry.ObjectInfo memory, address, bytes memory) { + return ( + IRegistry.ObjectInfo({ + nftId: NftId.wrap(0), + parentNftId: parentNftId, + objectType: objectType, + release: VersionPart.wrap(3), + isInterceptor: false, + objectAddress: address(123456789) + }), + owner, + emptyData + ); } function _upgradeRegistryService() internal returns (RegistryServiceUpgraded regSvcUpd) { - vm.startPrank(registryOwner); + vm.startPrank(gifManager); registryServiceManager.upgrade(address(new RegistryServiceUpgraded())); vm.stopPrank(); diff --git a/test/registry/RegistrySetMajorVersion.t.sol b/test/registry/RegistrySetMajorVersion.t.solx similarity index 100% rename from test/registry/RegistrySetMajorVersion.t.sol rename to test/registry/RegistrySetMajorVersion.t.solx diff --git a/test/registry/RegistryTestBase.sol b/test/registry/RegistryTestBase.solx similarity index 99% rename from test/registry/RegistryTestBase.sol rename to test/registry/RegistryTestBase.solx index b71f9d661..0f2d6e641 100644 --- a/test/registry/RegistryTestBase.sol +++ b/test/registry/RegistryTestBase.solx @@ -612,13 +612,13 @@ contract RegistryTestBase is GifDeployer, FoundryRandom { assertEq(registry.getProtocolNftId().toInt(), protocolNftId.toInt(), "getProtocolNftId() returned unexpected value"); // TODO mirror release state in local state, use it in this checks - assertEq(registry.getInitialRelease().toInt(), VERSION.toInt(), "getInitialVersion() returned unexpected value"); + assertEq(registry.getInitialVersion().toInt(), VERSION.toInt(), "getInitialVersion() returned unexpected value"); // next version points to: // 1. "initial version - 1" if 0 releases where ever created // 2. the version undergoing deployment // 3. the latest activated version if no new releases where created since then - assertEq(registry.getNextRelease().toInt(), VERSION.toInt(), "getNextVersion() returned unexpected value"); - assertEq(registry.getLatestRelease().toInt(), VERSION.toInt(), "getLatestVersion() returned unexpected value"); + assertEq(registry.getNextVersion().toInt(), VERSION.toInt(), "getNextVersion() returned unexpected value"); + assertEq(registry.getLatestVersion().toInt(), VERSION.toInt(), "getLatestVersion() returned unexpected value"); // check for zero address diff --git a/test/registry/RegistryTestBaseWithPreset.sol b/test/registry/RegistryTestBaseWithPreset.solx similarity index 100% rename from test/registry/RegistryTestBaseWithPreset.sol rename to test/registry/RegistryTestBaseWithPreset.solx diff --git a/test/registry/RegistryTokenWhitelisting.t.sol b/test/registry/RegistryTokenWhitelisting.t.sol index 9c4c0c474..dfc14bf0d 100644 --- a/test/registry/RegistryTokenWhitelisting.t.sol +++ b/test/registry/RegistryTokenWhitelisting.t.sol @@ -74,7 +74,7 @@ contract RegistryTokenWhitelisting is GifTest { assertTrue(tokenRegistry.getTokenInfo(currentChainId, address(dip)).active, "dip not active (1a)"); assertFalse(tokenRegistry.isActive(currentChainId, address(usdc2), releaseRegistry.getLatestVersion()), "usdc2 active in current relase (1)"); - vm.startPrank(registryOwner); + vm.startPrank(gifManager); tokenRegistry.setActive(currentChainId, address(dip), false); vm.stopPrank(); @@ -82,7 +82,7 @@ contract RegistryTokenWhitelisting is GifTest { assertFalse(tokenRegistry.getTokenInfo(currentChainId, address(dip)).active, "dip active (2a)"); assertFalse(tokenRegistry.isActive(currentChainId, address(usdc2), releaseRegistry.getLatestVersion()), "usdc2 active in current relase (2)"); - vm.startPrank(registryOwner); + vm.startPrank(gifManager); tokenRegistry.setActive(currentChainId, address(dip), true); vm.stopPrank(); @@ -94,7 +94,7 @@ contract RegistryTokenWhitelisting is GifTest { function test_tokenRegistryWhitelistHappyCase() public { - vm.startPrank(address(registryOwner)); + vm.startPrank(address(gifManager)); tokenRegistry.registerToken(address(usdc2)); tokenRegistry.setActiveForVersion(currentChainId, address(usdc2), majorVersion3, whitelist); vm.stopPrank(); @@ -110,7 +110,7 @@ contract RegistryTokenWhitelisting is GifTest { function test_tokenRegistryWhitelistTwoReleasesHappyCase() public { - vm.startPrank(address(registryOwner)); + vm.startPrank(address(gifManager)); tokenRegistry.registerToken(address(usdc2)); tokenRegistry.setActiveForVersion(currentChainId, address(usdc2), majorVersion3, whitelist); vm.stopPrank(); @@ -121,7 +121,7 @@ contract RegistryTokenWhitelisting is GifTest { assertTrue(tokenRegistry.isActive(currentChainId, address(usdc2), majorVersion3), "usdc2 not whitelisted in version 3"); assertFalse(tokenRegistry.isActive(currentChainId, address(usdc2), majorVersion4), "usdc2 whitelisted in version 4"); - vm.startPrank(registryOwner); + vm.startPrank(gifManager); bool enforceVersionCheck = false; tokenRegistry.setActiveWithVersionCheck(currentChainId, address(usdc2), majorVersion4, whitelist, enforceVersionCheck); vm.stopPrank(); @@ -138,7 +138,7 @@ contract RegistryTokenWhitelisting is GifTest { uint8 quakDecimals = 3; string memory quakSymbol = "QUAK123"; - vm.startPrank(address(registryOwner)); + vm.startPrank(address(gifManager)); tokenRegistry.registerRemoteToken(quakChainId, quakAddress, quakDecimals, quakSymbol); vm.stopPrank(); @@ -157,7 +157,7 @@ contract RegistryTokenWhitelisting is GifTest { // check is active assertFalse(tokenRegistry.isActive(quakChainId, quakAddress, majorVersion3), "quack active for version 3"); - vm.startPrank(address(registryOwner)); + vm.startPrank(address(gifManager)); tokenRegistry.setActiveForVersion(quakChainId, quakAddress, majorVersion3, whitelist); vm.stopPrank(); @@ -172,7 +172,7 @@ contract RegistryTokenWhitelisting is GifTest { currentChainId, address(usdc2))); - vm.startPrank(address(registryOwner)); + vm.startPrank(address(gifManager)); tokenRegistry.registerRemoteToken(currentChainId, address(usdc2), 3, "dummy"); vm.stopPrank(); } @@ -185,7 +185,7 @@ contract RegistryTokenWhitelisting is GifTest { uint8 quakDecimals = 3; string memory quakSymbol = "QUAK123"; - vm.startPrank(address(registryOwner)); + vm.startPrank(address(gifManager)); tokenRegistry.registerRemoteToken(quakChainId, quakAddress, quakDecimals, quakSymbol); // attempt to register quak token 2nd time @@ -211,7 +211,7 @@ contract RegistryTokenWhitelisting is GifTest { function test_tokenRegistryBlacklistHappyCase() public { - vm.startPrank(address(registryOwner)); + vm.startPrank(address(gifManager)); tokenRegistry.registerToken(address(usdc2)); tokenRegistry.setActiveForVersion(currentChainId, address(usdc2), majorVersion3, whitelist); @@ -232,7 +232,7 @@ contract RegistryTokenWhitelisting is GifTest { currentChainId, address(registryService))); - vm.startPrank(address(registryOwner)); + vm.startPrank(address(gifManager)); tokenRegistry.registerToken(address(registryService)); vm.stopPrank(); } @@ -244,7 +244,7 @@ contract RegistryTokenWhitelisting is GifTest { currentChainId, address(usdc2))); - vm.startPrank(address(registryOwner)); + vm.startPrank(address(gifManager)); tokenRegistry.setActiveForVersion(currentChainId, address(usdc2), majorVersion4, whitelist); vm.stopPrank(); } @@ -256,7 +256,7 @@ contract RegistryTokenWhitelisting is GifTest { currentChainId, address(outsider))); - vm.prank(address(registryOwner)); + vm.prank(address(gifManager)); tokenRegistry.registerToken(outsider); } @@ -269,7 +269,7 @@ contract RegistryTokenWhitelisting is GifTest { TokenRegistry.ErrorTokenRegistryMajorVersionInvalid.selector, majorVersion2)); - vm.prank(registryOwner); + vm.prank(gifManager); tokenRegistry.setActiveForVersion(currentChainId, address(dip), majorVersion2, whitelist); // attempt to whitelist for version 4 (too high) @@ -277,7 +277,7 @@ contract RegistryTokenWhitelisting is GifTest { abi.encodeWithSelector( TokenRegistry.ErrorTokenRegistryMajorVersionInvalid.selector, majorVersion4)); - vm.prank(registryOwner); + vm.prank(gifManager); tokenRegistry.setActiveForVersion(currentChainId, address(dip), majorVersion4, whitelist); } diff --git a/test/registryService/GetAndVerifyContractInfo.t.sol b/test/registryService/GetAndVerifyContractInfo.t.sol index 9d71883c8..72fabce9f 100644 --- a/test/registryService/GetAndVerifyContractInfo.t.sol +++ b/test/registryService/GetAndVerifyContractInfo.t.sol @@ -5,7 +5,7 @@ import { FoundryRandom } from "foundry-random/FoundryRandom.sol"; import {Vm, console} from "../../lib/forge-std/src/Test.sol"; import {NftId, NftIdLib} from "../../contracts/type/NftId.sol"; -import {ObjectType, ObjectTypeLib} from "../../contracts/type/ObjectType.sol"; +import {ObjectType, ObjectTypeLib, COMPONENT, DISTRIBUTION, POOL, ORACLE} from "../../contracts/type/ObjectType.sol"; import {IRegistry} from "../../contracts/registry/IRegistry.sol"; import {RegistryService} from "../../contracts/registry/RegistryService.sol"; @@ -16,37 +16,46 @@ import {RegisterableMock, SelfOwnedRegisterableMock, RegisterableMockWithInvalidAddress} from "../mock/RegisterableMock.sol"; - +// !!! TODO add info.release check tests contract GetAndVerifyContractInfoTest is RegistryServiceHarnessTestBase { function test_withValidRegisterableHappyCase() public { ObjectType registerableType = ObjectTypeLib.toObjectType(randomNumber(type(uint8).max)); + NftId parentNftId = NftIdLib.toNftId(randomNumber(type(uint96).max)); RegisterableMock registerable = new RegisterableMock( NftIdLib.toNftId(randomNumber(type(uint96).max)), // nftId - NftIdLib.toNftId(randomNumber(type(uint96).max)), // parentNftId + parentNftId, registerableType, toBool(randomNumber(1)), // isInterceptor registerableOwner, "" ); - IRegistry.ObjectInfo memory infoFromRegistryService = registryServiceHarness.exposed_getAndVerifyContractInfo( + ( + IRegistry.ObjectInfo memory info, + address owner, + bytes memory data + ) = registryServiceHarness.exposed_getAndVerifyContractInfo( registerable, + parentNftId, registerableType, registerableOwner); - eqObjectInfo(infoFromRegistryService, registerable.getInitialInfo());//, "Info returned by registry service is different from info stored in registerable"); + assertTrue(eqObjectInfo(info, registerable.getInitialInfo()), "Info returned by getAndVerifyContractInfo() is different from info stored in registerable"); + assertEq(owner, registerable.getOwner(), "Owner returned by getAndVerifyContractInfo() is different from owner stored in registerable"); + assertTrue(eqBytes(data, registerable.getInitialData()), "Data returned by getAndVerifyContractInfo() is different from data stored in registerable"); } function test_withInvalidRegisterableAddress() public { ObjectType registerableType = ObjectTypeLib.toObjectType(randomNumber(type(uint8).max)); + NftId parentNftId = NftIdLib.toNftId(randomNumber(type(uint96).max)); RegisterableMockWithInvalidAddress registerable = new RegisterableMockWithInvalidAddress( NftIdLib.toNftId(randomNumber(type(uint96).max)), // nftId - NftIdLib.toNftId(randomNumber(type(uint96).max)), // parentNftId + parentNftId, registerableType, toBool(randomNumber(1)), // isInterceptor address(uint160(randomNumber(type(uint160).max))), @@ -59,16 +68,122 @@ contract GetAndVerifyContractInfoTest is RegistryServiceHarnessTestBase { address(registerable), registerable.getInitialInfo().objectAddress)); - IRegistry.ObjectInfo memory infoFromRegistryService = registryServiceHarness.exposed_getAndVerifyContractInfo( + registryServiceHarness.exposed_getAndVerifyContractInfo( registerable, + parentNftId, registerableType, registerableOwner); } + function test_withRegisterableParentDifferentFromExpectedParent() public + { + ObjectType registerableType = ObjectTypeLib.toObjectType(randomNumber(type(uint8).max)); + NftId parentNftId = NftIdLib.toNftId(randomNumber(type(uint96).max)); + NftId expectedParentNftId = NftIdLib.toNftId(randomNumber(type(uint96).max)); + + if(parentNftId == expectedParentNftId) { + expectedParentNftId = NftIdLib.toNftId(expectedParentNftId.toInt() + 1); + } + + RegisterableMock registerable = new RegisterableMock( + NftIdLib.toNftId(randomNumber(type(uint96).max)), // nftId + parentNftId, + registerableType, + toBool(randomNumber(1)), // isInterceptor + registerableOwner, + "" + ); + + vm.expectRevert(abi.encodeWithSelector( + IRegistryService.ErrorRegistryServiceRegisterableParentInvalid.selector, + address(registerable), + expectedParentNftId, + parentNftId)); + + registryServiceHarness.exposed_getAndVerifyContractInfo( + registerable, + expectedParentNftId, + registerableType, + registerableOwner); + } + + function test_withZeroRegisterableParent() public + { + ObjectType registerableType = ObjectTypeLib.toObjectType(randomNumber(type(uint8).max)); + NftId parentNftId = NftIdLib.zero(); + NftId expectedParentNftId = NftIdLib.toNftId(randomNumber(1, type(uint96).max)); + + RegisterableMock registerable = new RegisterableMock( + NftIdLib.toNftId(randomNumber(type(uint96).max)), // nftId + parentNftId, + registerableType, + toBool(randomNumber(1)), // isInterceptor + registerableOwner, + "" + ); + + vm.expectRevert(abi.encodeWithSelector( + IRegistryService.ErrorRegistryServiceRegisterableParentInvalid.selector, + address(registerable), + expectedParentNftId, + parentNftId)); + + registryServiceHarness.exposed_getAndVerifyContractInfo( + registerable, + expectedParentNftId, + registerableType, + registerableOwner); + } + + function test_whenExpectedParentIsZeroHappyCase() public + { + ObjectType registerableType = ObjectTypeLib.toObjectType(randomNumber(type(uint8).max)); + NftId parentNftId = NftIdLib.toNftId(randomNumber(1, type(uint96).max)); + NftId expectedParentNftId = NftIdLib.zero(); + + RegisterableMock registerable = new RegisterableMock( + NftIdLib.toNftId(randomNumber(type(uint96).max)), // nftId + parentNftId, + registerableType, + toBool(randomNumber(1)), // isInterceptor + registerableOwner, + "" + ); + + registryServiceHarness.exposed_getAndVerifyContractInfo( + registerable, + expectedParentNftId, + registerableType, + registerableOwner); + } + + function test_withZeroRegisterableAndZeroExpectedParentHappyCase() public + { + ObjectType registerableType = ObjectTypeLib.toObjectType(randomNumber(type(uint8).max)); + NftId parentNftId = NftIdLib.zero(); + NftId expectedParentNftId = NftIdLib.zero(); + + RegisterableMock registerable = new RegisterableMock( + NftIdLib.toNftId(randomNumber(type(uint96).max)), // nftId + parentNftId, + registerableType, + toBool(randomNumber(1)), // isInterceptor + registerableOwner, + "" + ); + + registryServiceHarness.exposed_getAndVerifyContractInfo( + registerable, + expectedParentNftId, + registerableType, + registerableOwner); + } + function test_withRegisterableTypeDifferentFromExpectedType() public { ObjectType registerableType = ObjectTypeLib.toObjectType(randomNumber(type(uint8).max)); ObjectType expectedType = ObjectTypeLib.toObjectType(randomNumber(type(uint8).max)); + NftId parentNftId = NftIdLib.toNftId(randomNumber(type(uint96).max)); if(registerableType == expectedType) { expectedType = ObjectTypeLib.toObjectType(expectedType.toInt() + 1); @@ -76,7 +191,7 @@ contract GetAndVerifyContractInfoTest is RegistryServiceHarnessTestBase { RegisterableMock registerable = new RegisterableMock( NftIdLib.toNftId(randomNumber(type(uint96).max)), // nftId - NftIdLib.toNftId(randomNumber(type(uint96).max)), // parentNftId + parentNftId, registerableType, toBool(randomNumber(1)), // isInterceptor registerableOwner, @@ -91,6 +206,7 @@ contract GetAndVerifyContractInfoTest is RegistryServiceHarnessTestBase { registryServiceHarness.exposed_getAndVerifyContractInfo( registerable, + parentNftId, expectedType, registerableOwner); } @@ -99,6 +215,7 @@ contract GetAndVerifyContractInfoTest is RegistryServiceHarnessTestBase { { ObjectType registerableType = ObjectTypeLib.zero(); ObjectType expectedType = ObjectTypeLib.toObjectType(randomNumber(type(uint8).max)); + NftId parentNftId = NftIdLib.toNftId(randomNumber(type(uint96).max)); if(registerableType == expectedType) { expectedType = ObjectTypeLib.toObjectType(expectedType.toInt() + 1); @@ -106,7 +223,7 @@ contract GetAndVerifyContractInfoTest is RegistryServiceHarnessTestBase { RegisterableMock registerable = new RegisterableMock( NftIdLib.toNftId(randomNumber(type(uint96).max)), // nftId - NftIdLib.toNftId(randomNumber(type(uint96).max)), // parentNftId + parentNftId, registerableType, toBool(randomNumber(1)), // isInterceptor registerableOwner, @@ -121,6 +238,7 @@ contract GetAndVerifyContractInfoTest is RegistryServiceHarnessTestBase { registryServiceHarness.exposed_getAndVerifyContractInfo( registerable, + parentNftId, expectedType, registerableOwner); } @@ -129,6 +247,7 @@ contract GetAndVerifyContractInfoTest is RegistryServiceHarnessTestBase { { ObjectType registerableType = ObjectTypeLib.toObjectType(randomNumber(type(uint8).max)); ObjectType expectedType = ObjectTypeLib.zero(); + NftId parentNftId = NftIdLib.toNftId(randomNumber(type(uint96).max)); if(registerableType == expectedType) { registerableType = ObjectTypeLib.toObjectType(registerableType.toInt() + 1); @@ -136,7 +255,40 @@ contract GetAndVerifyContractInfoTest is RegistryServiceHarnessTestBase { RegisterableMock registerable = new RegisterableMock( NftIdLib.toNftId(randomNumber(type(uint96).max)), // nftId - NftIdLib.toNftId(randomNumber(type(uint96).max)), // parentNftId + parentNftId, + registerableType, + toBool(randomNumber(1)), // isInterceptor + registerableOwner, + "" + ); + + vm.expectRevert(abi.encodeWithSelector( + IRegistryService.ErrorRegistryServiceRegisterableTypeInvalid.selector, + address(registerable), + expectedType, + registerableType)); + + registryServiceHarness.exposed_getAndVerifyContractInfo( + registerable, + parentNftId, + expectedType, + registerableOwner); + } + + function test_withRegisterableTypeDifferentFromExpectedTypeWhenExpectedTypeIsCOMPONENT() public + { + ObjectType registerableType = ObjectTypeLib.toObjectType(randomNumber(type(uint8).max)); + ObjectType expectedType = COMPONENT(); + NftId parentNftId = NftIdLib.toNftId(randomNumber(type(uint96).max)); + + // registerable is not COMPONENT + if(registerableType == DISTRIBUTION() || registerableType == POOL() || registerableType == ORACLE()) { + registerableType = ObjectTypeLib.toObjectType(registerableType.toInt() + 1); + } + + RegisterableMock registerable = new RegisterableMock( + NftIdLib.toNftId(randomNumber(type(uint96).max)), // nftId + parentNftId, registerableType, toBool(randomNumber(1)), // isInterceptor registerableOwner, @@ -151,17 +303,78 @@ contract GetAndVerifyContractInfoTest is RegistryServiceHarnessTestBase { registryServiceHarness.exposed_getAndVerifyContractInfo( registerable, + parentNftId, expectedType, registerableOwner); } + function test_whenExpectedTypeIsCOMPONENTHappyCase() public + { + // with DISTRIBUTION + ObjectType registerableType = DISTRIBUTION(); + ObjectType expectedType = COMPONENT(); + NftId parentNftId = NftIdLib.toNftId(randomNumber(type(uint96).max)); + + RegisterableMock registerable = new RegisterableMock( + NftIdLib.toNftId(randomNumber(type(uint96).max)), // nftId + parentNftId, + registerableType, + toBool(randomNumber(1)), // isInterceptor + registerableOwner, + "" + ); + + registryServiceHarness.exposed_getAndVerifyContractInfo( + registerable, + parentNftId, + expectedType, + registerableOwner); + + // with POOL + registerableType = POOL(); + + registerable = new RegisterableMock( + NftIdLib.toNftId(randomNumber(type(uint96).max)), // nftId + parentNftId, + registerableType, + toBool(randomNumber(1)), // isInterceptor + registerableOwner, + "" + ); + + registryServiceHarness.exposed_getAndVerifyContractInfo( + registerable, + parentNftId, + expectedType, + registerableOwner); + + // with ORACLE + registerableType = ORACLE(); + + registerable = new RegisterableMock( + NftIdLib.toNftId(randomNumber(type(uint96).max)), // nftId + parentNftId, + registerableType, + toBool(randomNumber(1)), // isInterceptor + registerableOwner, + "" + ); + + registryServiceHarness.exposed_getAndVerifyContractInfo( + registerable, + parentNftId, + expectedType, + registerableOwner); + } + function test_withRegisterableOwnerDifferentFromExpectedOwner() public { ObjectType registerableType = ObjectTypeLib.toObjectType(randomNumber(type(uint8).max)); + NftId parentNftId = NftIdLib.toNftId(randomNumber(type(uint96).max)); RegisterableMock registerable = new RegisterableMock( NftIdLib.toNftId(randomNumber(type(uint96).max)), // nftId - NftIdLib.toNftId(randomNumber(type(uint96).max)), // parentNftId + parentNftId, registerableType, toBool(randomNumber(1)), // isInterceptor registerableOwner, // initialOwner @@ -176,31 +389,28 @@ contract GetAndVerifyContractInfoTest is RegistryServiceHarnessTestBase { registryServiceHarness.exposed_getAndVerifyContractInfo( registerable, + parentNftId, registerableType, outsider); // expectedOwner } - function test_whenExpectedOwnerIsZero() public + function test_whenExpectedOwnerIsZeroHappyCase() public { ObjectType registerableType = ObjectTypeLib.toObjectType(randomNumber(type(uint8).max)); + NftId parentNftId = NftIdLib.toNftId(randomNumber(type(uint96).max)); RegisterableMock registerable = new RegisterableMock( NftIdLib.toNftId(randomNumber(type(uint96).max)), // nftId - NftIdLib.toNftId(randomNumber(type(uint96).max)), // parentNftId + parentNftId, registerableType, toBool(randomNumber(1)), // isInterceptor registerableOwner, // initialOwner "" ); - vm.expectRevert(abi.encodeWithSelector( - IRegistryService.ErrorRegistryServiceRegisterableOwnerInvalid.selector, - address(registerable), - address(0), - registerableOwner)); - registryServiceHarness.exposed_getAndVerifyContractInfo( registerable, + parentNftId, registerableType, address(0)); // expectedOwner } @@ -208,10 +418,11 @@ contract GetAndVerifyContractInfoTest is RegistryServiceHarnessTestBase { function test_withZeroRegisterableOwner() public { ObjectType registerableType = ObjectTypeLib.toObjectType(randomNumber(type(uint8).max)); + NftId parentNftId = NftIdLib.toNftId(randomNumber(type(uint96).max)); RegisterableMock registerable = new RegisterableMock( NftIdLib.toNftId(randomNumber(type(uint96).max)), // nftId - NftIdLib.toNftId(randomNumber(type(uint96).max)), // parentNftId + parentNftId, registerableType, toBool(randomNumber(1)), // isInterceptor address(0), // initialOwner @@ -226,6 +437,7 @@ contract GetAndVerifyContractInfoTest is RegistryServiceHarnessTestBase { registryServiceHarness.exposed_getAndVerifyContractInfo( registerable, + parentNftId, registerableType, registerableOwner); } @@ -233,10 +445,11 @@ contract GetAndVerifyContractInfoTest is RegistryServiceHarnessTestBase { function test_withZeroRegisterableOwnerAndZeroExpectedOwner() public { ObjectType registerableType = ObjectTypeLib.toObjectType(randomNumber(type(uint8).max)); + NftId parentNftId = NftIdLib.toNftId(randomNumber(type(uint96).max)); RegisterableMock registerable = new RegisterableMock( NftIdLib.toNftId(randomNumber(type(uint96).max)), // nftId - NftIdLib.toNftId(randomNumber(type(uint96).max)), // parentNftId + parentNftId, registerableType, toBool(randomNumber(1)), // isInterceptor address(0), // initialOwner @@ -249,6 +462,7 @@ contract GetAndVerifyContractInfoTest is RegistryServiceHarnessTestBase { registryServiceHarness.exposed_getAndVerifyContractInfo( registerable, + parentNftId, registerableType, address(0)); // expectedOwner } @@ -256,10 +470,11 @@ contract GetAndVerifyContractInfoTest is RegistryServiceHarnessTestBase { function test_withRegisteredRegisterableOwner() public { ObjectType registerableType = ObjectTypeLib.toObjectType(randomNumber(type(uint8).max)); + NftId parentNftId = NftIdLib.toNftId(randomNumber(type(uint96).max)); RegisterableMock registerable = new RegisterableMock( NftIdLib.toNftId(randomNumber(type(uint96).max)), // nftId - NftIdLib.toNftId(randomNumber(type(uint96).max)), // parentNftId + parentNftId, registerableType, toBool(randomNumber(1)), // isInterceptor address(registry), // initialOwner @@ -273,6 +488,7 @@ contract GetAndVerifyContractInfoTest is RegistryServiceHarnessTestBase { registryServiceHarness.exposed_getAndVerifyContractInfo( registerable, + parentNftId, registerableType, address(registry)); // expectedOwner } @@ -280,10 +496,11 @@ contract GetAndVerifyContractInfoTest is RegistryServiceHarnessTestBase { function test_withSelfOwnedRegisterable() public { ObjectType registerableType = ObjectTypeLib.toObjectType(randomNumber(type(uint8).max)); - + NftId parentNftId = NftIdLib.toNftId(randomNumber(type(uint96).max)); + SelfOwnedRegisterableMock selfOwnedRegisterable = new SelfOwnedRegisterableMock( NftIdLib.toNftId(randomNumber(type(uint96).max)), // nftId - NftIdLib.toNftId(randomNumber(type(uint96).max)), // parentNftId + parentNftId, registerableType, toBool(randomNumber(1)), // isInterceptor "" @@ -295,6 +512,7 @@ contract GetAndVerifyContractInfoTest is RegistryServiceHarnessTestBase { registryServiceHarness.exposed_getAndVerifyContractInfo( selfOwnedRegisterable, + parentNftId, registerableType, address(selfOwnedRegisterable)); // expectedOwner } diff --git a/test/registryService/RegistryServiceHarness.sol b/test/registryService/RegistryServiceHarness.sol index bdc6a2aba..668dc2f65 100644 --- a/test/registryService/RegistryServiceHarness.sol +++ b/test/registryService/RegistryServiceHarness.sol @@ -2,41 +2,48 @@ pragma solidity ^0.8.20; import {ObjectType} from "../../contracts/type/ObjectType.sol"; +import {NftId} from "../../contracts/type/NftId.sol"; import {Version, VersionLib} from "../../contracts/type/Version.sol"; -import {IVersionable} from "../../contracts/upgradeability/IVersionable.sol"; -import {Versionable} from "../../contracts/upgradeability/Versionable.sol"; +import {IUpgradeable} from "../../contracts/upgradeability/IUpgradeable.sol"; +import {Upgradeable} from "../../contracts/upgradeability/Upgradeable.sol"; import {IRegisterable} from "../../contracts/shared/IRegisterable.sol"; import {IRegistry} from "../../contracts/registry/IRegistry.sol"; import {Service} from "../../contracts/shared/Service.sol"; import {RegistryService} from "../../contracts/registry/RegistryService.sol"; +import {IVersionable} from "../../contracts/shared/IVersionable.sol"; contract RegistryServiceHarness is RegistryService { function exposed_getAndVerifyContractInfo( IRegisterable registerable, + NftId expectedParent, ObjectType expectedType, address expectedOwner) public - // view + view returns( - IRegistry.ObjectInfo memory info + IRegistry.ObjectInfo memory info, + address owner, + bytes memory data ) { - info = _getAndVerifyContractInfo( + (info, owner, data) = _getAndVerifyContractInfo( registerable, + expectedParent, expectedType, expectedOwner); } function exposed_verifyObjectInfo( IRegistry.ObjectInfo memory info, + address owner, ObjectType objectType ) public view { - _verifyObjectInfo(info, objectType); + _verifyObjectInfo(info, owner, objectType); } function getVersion() diff --git a/test/registryService/RegistryServiceHarnessTestBase.sol b/test/registryService/RegistryServiceHarnessTestBase.sol index 5c7e008a4..c76351cc7 100644 --- a/test/registryService/RegistryServiceHarnessTestBase.sol +++ b/test/registryService/RegistryServiceHarnessTestBase.sol @@ -7,7 +7,7 @@ import {Vm, console} from "../../lib/forge-std/src/Test.sol"; import {AccessManager} from "@openzeppelin/contracts/access/manager/AccessManager.sol"; import {NftId, NftIdLib} from "../../contracts/type/NftId.sol"; -import {ObjectType} from "../../contracts/type/ObjectType.sol"; +import {ObjectType, COMPONENT, DISTRIBUTION, ORACLE, POOL} from "../../contracts/type/ObjectType.sol"; import {VersionPartLib, VersionPart} from "../../contracts/type/Version.sol"; import {RoleId} from "../../contracts/type/RoleId.sol"; @@ -16,7 +16,7 @@ import {IAccessAdmin} from "../../contracts/authorization/IAccessAdmin.sol"; import {Dip} from "../../contracts/mock/Dip.sol"; import {IRegisterable} from "../../contracts/shared/IRegisterable.sol"; import {IRegistry} from "../../contracts/registry/IRegistry.sol"; -import {Registry} from "../../contracts/registry/Registry.sol"; +import {Registry, GIF_INITIAL_RELEASE} from "../../contracts/registry/Registry.sol"; import {IRegistryService} from "../../contracts/registry/IRegistryService.sol"; import {RegistryService} from "../../contracts/registry/RegistryService.sol"; import {RegistryAdmin} from "../../contracts/registry/RegistryAdmin.sol"; @@ -40,16 +40,9 @@ contract RegistryServiceHarnessTestBase is GifDeployer, FoundryRandom { function setUp() public virtual { - globalRegistry = makeAddr("globalRegistry"); - registryOwner = makeAddr("registryOwner"); - // solhint-disable-next-line console.log("tx origin", tx.origin); - address gifAdmin = registryOwner; - address gifManager = registryOwner; - address stakingOwner = registryOwner; - ( , // dip, registry, @@ -58,56 +51,58 @@ contract RegistryServiceHarnessTestBase is GifDeployer, FoundryRandom { , // registryAdmin, , // stakingManager, // staking - ) = deployCore( - globalRegistry, - gifAdmin, - gifManager, - stakingOwner); + ) = deployCore(); registryAddress = address(registry); - vm.startPrank(registryOwner); _deployRegistryServiceHarness(); - vm.stopPrank(); } function _deployRegistryServiceHarness() internal { bytes32 salt = "0x2222"; + vm.prank(gifAdmin); releaseRegistry.createNextRelease(); + vm.startPrank(gifManager); + ( IAccessAdmin releaseAdmin, VersionPart releaseVersion, bytes32 releaseSalt ) = releaseRegistry.prepareNextRelease( - new ServiceAuthorizationMockWithRegistryService(VersionPartLib.toVersionPart(3)), + new ServiceAuthorizationMockWithRegistryService(GIF_INITIAL_RELEASE()), salt); registryServiceManagerWithHarness = new RegistryServiceManagerMockWithHarness{salt: releaseSalt}( releaseAdmin.authority(), - registryAddress, releaseSalt); registryServiceHarness = RegistryServiceHarness(address(registryServiceManagerWithHarness.getRegistryService())); releaseRegistry.registerService(registryServiceHarness); registryServiceManagerWithHarness.linkToProxy(); + vm.stopPrank(); + // TODO check if this nees to be re-enabled // assertEq(serviceAddresses[0], address(registryServiceHarness), "error: registry service address mismatch"); + vm.prank(gifAdmin); releaseRegistry.activateNextRelease(); } function _assert_getAndVerifyContractInfo( IRegisterable registerable, + NftId expectedParent, ObjectType expectedType, address expectedOwner) internal { IRegistry.ObjectInfo memory info = registerable.getInitialInfo(); + address initialOwner = registerable.getOwner(); + bytes memory data = registerable.getInitialData(); bool expectRevert = false; if(info.objectAddress != address(registerable)) { @@ -116,56 +111,80 @@ contract RegistryServiceHarnessTestBase is GifDeployer, FoundryRandom { address(registerable), info.objectAddress)); expectRevert = true; - } else if(info.objectType != expectedType) { + } else if(expectedType != COMPONENT() && info.objectType != expectedType) { + vm.expectRevert(abi.encodeWithSelector( + IRegistryService.ErrorRegistryServiceRegisterableTypeInvalid.selector, + info.objectAddress, + expectedType, + info.objectType)); + expectRevert = true; + } else if(expectedType == COMPONENT() && !(info.objectType == DISTRIBUTION() || info.objectType == ORACLE() || info.objectType == POOL())) { vm.expectRevert(abi.encodeWithSelector( IRegistryService.ErrorRegistryServiceRegisterableTypeInvalid.selector, info.objectAddress, expectedType, info.objectType)); expectRevert = true; - } else if(info.initialOwner != expectedOwner) { - vm.expectRevert(abi.encodeWithSelector( - IRegistryService.ErrorRegistryServiceRegisterableOwnerInvalid.selector, - info.objectAddress, - expectedOwner, - info.initialOwner)); - expectRevert = true; - } else if(info.initialOwner == address(registerable)) { + } else if(expectedParent.gtz() && info.parentNftId != expectedParent) { + vm.expectRevert(abi.encodeWithSelector( + IRegistryService.ErrorRegistryServiceRegisterableParentInvalid.selector, + info.objectAddress, + expectedParent, + info.parentNftId)); + expectRevert = true; + } else if(expectedOwner > address(0) && initialOwner != expectedOwner) { + vm.expectRevert(abi.encodeWithSelector( + IRegistryService.ErrorRegistryServiceRegisterableOwnerInvalid.selector, + info.objectAddress, + expectedOwner, + initialOwner)); + expectRevert = true; + } else if(initialOwner == address(registerable)) { vm.expectRevert(abi.encodeWithSelector( IRegistryService.ErrorRegistryServiceRegisterableSelfRegistration.selector, info.objectAddress)); expectRevert = true; - } else if(info.initialOwner == address(0)) { + } else if(initialOwner == address(0)) { vm.expectRevert(abi.encodeWithSelector(IRegistryService.ErrorRegistryServiceRegisterableOwnerZero.selector, info.objectAddress)); expectRevert = true; - }else if(registry.isRegistered(info.initialOwner)) { + }else if(registry.isRegistered(initialOwner)) { vm.expectRevert(abi.encodeWithSelector(IRegistryService.ErrorRegistryServiceRegisterableOwnerRegistered.selector, info.objectAddress, - info.initialOwner)); + initialOwner)); expectRevert = true; } if(expectRevert) { registryServiceHarness.exposed_getAndVerifyContractInfo( registerable, + expectedParent, expectedType, expectedOwner); } else { - IRegistry.ObjectInfo memory infoFromRegistryService = registryServiceHarness.exposed_getAndVerifyContractInfo( + ( + IRegistry.ObjectInfo memory infoFromRegistryService, + address ownerFromRegistryService, + bytes memory dataFromRegistryService + ) = registryServiceHarness.exposed_getAndVerifyContractInfo( registerable, + expectedParent, expectedType, expectedOwner); - IRegistry.ObjectInfo memory infoFromRegistry = registry.getObjectInfo(address(registerable)); + assertTrue(eqObjectInfo(infoFromRegistryService, info), "Info returned by getAndVerifyContractInfo() is different from the one in registrable"); + assertEq(ownerFromRegistryService, initialOwner, "Owner returned by getAndVerifyContractInfo() is different from the one in registerable"); + assertTrue(eqBytes(dataFromRegistryService, data), "Data returned by getAndVerifyContractInfo() is different from the one in registrable"); - eqObjectInfo(info, infoFromRegistryService); - eqObjectInfo(infoFromRegistry, infoFromRegistryService); + assertTrue(eqObjectInfo(infoFromRegistryService, registry.getObjectInfo(address(registerable))), "Info returned by getAndVerifyContractInfo() is different from the one in registry"); + assertEq(ownerFromRegistryService, registry.ownerOf(address(registerable)), "Owner returned by getAndVerifyContractInfo() is different from the one in registry"); + assertTrue(eqBytes(dataFromRegistryService, registry.getObjectData(address(registerable))), "Data returned by getAndVerifyContractInfo() is different from the one in registry"); } } function _assert_verifyObjectInfo( - IRegistry.ObjectInfo memory info, + IRegistry.ObjectInfo memory info, + address initialOwner, ObjectType expectedType) internal { @@ -178,19 +197,20 @@ contract RegistryServiceHarnessTestBase is GifDeployer, FoundryRandom { IRegistryService.ErrorRegistryServiceObjectTypeInvalid.selector, expectedType, info.objectType)); - } else if(info.initialOwner == address(0)) { + } else if(initialOwner == address(0)) { vm.expectRevert(abi.encodeWithSelector( IRegistryService.ErrorRegistryServiceObjectOwnerZero.selector, info.objectType)); - } else if(registry.isRegistered(info.initialOwner)) { + } else if(registry.isRegistered(initialOwner)) { vm.expectRevert(abi.encodeWithSelector( IRegistryService.ErrorRegistryServiceObjectOwnerRegistered.selector, info.objectType, - info.initialOwner)); + initialOwner)); } registryServiceHarness.exposed_verifyObjectInfo( info, + initialOwner, expectedType); } } diff --git a/test/registryService/RegistryServiceManager.t.sol b/test/registryService/RegistryServiceManager.t.sol index 6b166b173..353840580 100644 --- a/test/registryService/RegistryServiceManager.t.sol +++ b/test/registryService/RegistryServiceManager.t.sol @@ -6,7 +6,7 @@ import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Ini import {Test, console} from "../../lib/forge-std/src/Test.sol"; import {IRegistry} from "../../contracts/registry/IRegistry.sol"; -import {IVersionable} from "../../contracts/upgradeability/IVersionable.sol"; +import {IUpgradeable} from "../../contracts/upgradeability/IUpgradeable.sol"; import {ChainNft} from "../../contracts/registry/ChainNft.sol"; import {Dip} from "../../contracts/mock/Dip.sol"; @@ -17,6 +17,7 @@ import {Registry} from "../../contracts/registry/Registry.sol"; import {RegistryServiceManager} from "../../contracts/registry/RegistryServiceManager.sol"; import {RegistryAdmin} from "../../contracts/registry/RegistryAdmin.sol"; import {RegistryService} from "../../contracts/registry/RegistryService.sol"; +import {GIF_ADMIN_ROLE, GIF_MANAGER_ROLE} from "../../contracts/type/RoleId.sol"; import {Staking} from "../../contracts/staking/Staking.sol"; import {StakingManager} from "../../contracts/staking/StakingManager.sol"; import {TokenRegistry} from "../../contracts/registry/TokenRegistry.sol"; @@ -50,7 +51,8 @@ contract RegistryServiceManagerTest is RegistryServiceTestBase { function test_deployedRegistryAndRegistryService() public { // solhint-disable no-console - console.log("registry owner", address(registryOwner)); + console.log("gif admin", registryAdmin.getRoleMember(GIF_ADMIN_ROLE(), 0)); + console.log("gif manager", registryAdmin.getRoleMember(GIF_MANAGER_ROLE(), 0)); console.log("registry service manager", address(registryServiceManager)); console.log("registry service manager linked to nft", registryServiceManager.getNftId().toInt()); console.log("registry service manager owner", registryServiceManager.getOwner()); @@ -86,8 +88,8 @@ contract RegistryServiceManagerTest is RegistryServiceTestBase { assertEq(registryService.getNftId().toInt(), registry.getNftIdForAddress(address(registryService)).toInt(), "registry service nft id mismatch"); // check ownership - assertEq(registryServiceManager.getOwner(), address(registryOwner), "service manager owner not registry owner"); - assertEq(registryService.getOwner(), address(registryOwner), "registry owner not owner of registry"); + assertEq(registryServiceManager.getOwner(), address(gifManager), "service manager owner not registry owner"); + assertEq(registryService.getOwner(), address(gifManager), "registry owner not owner of registry"); assertEq(registry.getOwner(), address(0x1), "registry owner not owner of registry"); assertEq(registry.getOwner(), registry.ownerOf(address(registry)), "non matching registry owners"); @@ -101,7 +103,7 @@ contract RegistryServiceManagerTest is RegistryServiceTestBase { bytes memory emptyInitializationData; // check ownership - assertEq(registryServiceManager.getOwner(), address(registryOwner), "service manager owner not registry owner"); + assertEq(registryServiceManager.getOwner(), address(gifManager), "service manager owner not registry owner"); // attempt to redeploy with non-owner account vm.expectRevert( @@ -110,7 +112,6 @@ contract RegistryServiceManagerTest is RegistryServiceTestBase { vm.prank(registryOwnerNew); registryServiceManager.initialize( - address(registry), mockImplementation, emptyInitializationData, bytes32("")); @@ -121,16 +122,15 @@ contract RegistryServiceManagerTest is RegistryServiceTestBase { bytes memory emptyInitializationData; // check ownership - assertEq(registryServiceManager.getOwner(), address(registryOwner), "service manager owner not registry owner"); + assertEq(registryServiceManager.getOwner(), address(gifManager), "service manager owner not registry owner"); // attempt to redeploy with owner account vm.expectRevert( abi.encodeWithSelector( Initializable.InvalidInitialization.selector)); - vm.prank(registryOwner); + vm.prank(gifManager); registryServiceManager.initialize( - address(registry), mockImplementation, emptyInitializationData, bytes32("")); @@ -141,7 +141,7 @@ contract RegistryServiceManagerTest is RegistryServiceTestBase { bytes memory emptyUpgradeData; // check ownership - assertEq(registryServiceManager.getOwner(), address(registryOwner), "service manager owner not registry owner"); + assertEq(registryServiceManager.getOwner(), address(gifManager), "service manager owner not registry owner"); // attempt to upgrade with non-owner account vm.expectRevert( @@ -157,7 +157,7 @@ contract RegistryServiceManagerTest is RegistryServiceTestBase { assertEq(registryServiceManager.getVersionCount(), 1, "version count not 1 before upgrade"); // attempt to upgrade with owner account - vm.prank(registryOwner); + vm.prank(gifManager); registryServiceManager.upgrade( upgradeMockImplementation, emptyUpgradeData); @@ -179,15 +179,15 @@ contract RegistryServiceManagerTest is RegistryServiceTestBase { bytes memory emptyUpgradeData; // check initial ownership - assertEq(registry.ownerOf(registryServiceAddress), registryOwner, "registry service owner not registry owner"); - assertEq(registryServiceManager.getOwner(), registryOwner, "registry service manager owner not registry owner"); + assertEq(registry.ownerOf(registryServiceAddress), gifManager, "registry service owner not registry owner"); + assertEq(registryServiceManager.getOwner(), gifManager, "registry service manager owner not registry owner"); // transfer ownership by transferring nft NftId registryServiceNft = registry.getNftIdForAddress(registryServiceAddress); - vm.startPrank(registryOwner); + vm.startPrank(gifManager); chainNft.approve(registryOwnerNew, registryServiceNft.toInt()); - chainNft.safeTransferFrom(registryOwner, registryOwnerNew, registryServiceNft.toInt(), ""); + chainNft.safeTransferFrom(gifManager, registryOwnerNew, registryServiceNft.toInt(), ""); vm.stopPrank(); // check ownership after transfer @@ -198,8 +198,8 @@ contract RegistryServiceManagerTest is RegistryServiceTestBase { vm.expectRevert( abi.encodeWithSelector( INftOwnable.ErrorNotOwner.selector, - registryOwner)); - vm.prank(registryOwner); + gifManager)); + vm.prank(gifManager); registryServiceManager.upgrade( upgradeMockImplementation, emptyUpgradeData); diff --git a/test/registryService/RegistryServiceTestBase.sol b/test/registryService/RegistryServiceTestBase.sol index 234011fd1..615ef1d73 100644 --- a/test/registryService/RegistryServiceTestBase.sol +++ b/test/registryService/RegistryServiceTestBase.sol @@ -31,8 +31,6 @@ import {ServiceAuthorizationV3} from "../../contracts/registry/ServiceAuthorizat import {Dip} from "../../contracts/mock/Dip.sol"; import {ServiceMock} from "../mock/ServiceMock.sol"; import {RegisterableMock} from "../mock/RegisterableMock.sol"; - -import {RegistryTestBase} from "../registry/RegistryTestBase.sol"; import {GifTest} from "../base/GifTest.sol"; @@ -62,7 +60,6 @@ contract RegistryServiceTestBase is GifTest, FoundryRandom { registryServiceManager = new RegistryServiceManager{salt: releaseSalt}( releaseAdmin.authority(), - registryAddress, releaseSalt); registryService = registryServiceManager.getRegistryService(); releaseRegistry.registerService(registryService); @@ -77,6 +74,7 @@ contract RegistryServiceTestBase is GifTest, FoundryRandom { IRegistry.ObjectInfo memory infoFromRegistryService, bytes memory dataFromRegistryService) internal + view { IRegistry.ObjectInfo memory infoFromRegistry = registry.getObjectInfo(registeredContract); IRegistry.ObjectInfo memory infoFromRegisterable = IRegisterable(registeredContract).getInitialInfo(); diff --git a/test/registryService/VerifyObjectInfo.t.sol b/test/registryService/VerifyObjectInfo.t.sol index 3352588c5..b1424dbec 100644 --- a/test/registryService/VerifyObjectInfo.t.sol +++ b/test/registryService/VerifyObjectInfo.t.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.20; import {Vm, console} from "../../lib/forge-std/src/Test.sol"; import {NftId, NftIdLib} from "../../contracts/type/NftId.sol"; import {ObjectType, ObjectTypeLib} from "../../contracts/type/ObjectType.sol"; +import {VersionPartLib} from "../../contracts/type/Version.sol"; import {IRegistry} from "../../contracts/registry/IRegistry.sol"; import {IRegistryService} from "../../contracts/registry/IRegistryService.sol"; @@ -20,14 +21,14 @@ contract VerifyObjectInfoTest is RegistryServiceHarnessTestBase { nftId: NftIdLib.toNftId(randomNumber(type(uint96).max)), parentNftId: NftIdLib.toNftId(randomNumber(type(uint96).max)), objectType: objectType, + release: VersionPartLib.toVersionPart(uint8(randomNumber(type(uint8).max))), isInterceptor: toBool(randomNumber(1)), - objectAddress: address(0), - initialOwner: registerableOwner, - data: "" + objectAddress: address(0) }); registryServiceHarness.exposed_verifyObjectInfo( info, + registerableOwner, objectType); // expectedType } @@ -44,10 +45,9 @@ contract VerifyObjectInfoTest is RegistryServiceHarnessTestBase { nftId: NftIdLib.toNftId(randomNumber(type(uint96).max)), parentNftId: NftIdLib.toNftId(randomNumber(type(uint96).max)), objectType: objectType, + release: VersionPartLib.toVersionPart(uint8(randomNumber(type(uint8).max))), isInterceptor: toBool(randomNumber(1)), - objectAddress: address(0), - initialOwner: registerableOwner, - data: "" + objectAddress: address(0) }); vm.expectRevert(abi.encodeWithSelector( @@ -57,6 +57,7 @@ contract VerifyObjectInfoTest is RegistryServiceHarnessTestBase { registryServiceHarness.exposed_verifyObjectInfo( info, + registerableOwner, expectedType); } @@ -73,10 +74,9 @@ contract VerifyObjectInfoTest is RegistryServiceHarnessTestBase { nftId: NftIdLib.toNftId(randomNumber(type(uint96).max)), parentNftId: NftIdLib.toNftId(randomNumber(type(uint96).max)), objectType: objectType, + release: VersionPartLib.toVersionPart(uint8(randomNumber(type(uint8).max))), isInterceptor: toBool(randomNumber(1)), - objectAddress: address(0), - initialOwner: registerableOwner, - data: "" + objectAddress: address(0) }); vm.expectRevert(abi.encodeWithSelector( @@ -86,6 +86,7 @@ contract VerifyObjectInfoTest is RegistryServiceHarnessTestBase { registryServiceHarness.exposed_verifyObjectInfo( info, + registerableOwner, expectedType); } @@ -102,10 +103,9 @@ contract VerifyObjectInfoTest is RegistryServiceHarnessTestBase { nftId: NftIdLib.toNftId(randomNumber(type(uint96).max)), parentNftId: NftIdLib.toNftId(randomNumber(type(uint96).max)), objectType: objectType, + release: VersionPartLib.toVersionPart(uint8(randomNumber(type(uint8).max))), isInterceptor: toBool(randomNumber(1)), - objectAddress: address(0), - initialOwner: registerableOwner, - data: "" + objectAddress: address(0) }); vm.expectRevert(abi.encodeWithSelector( @@ -115,6 +115,7 @@ contract VerifyObjectInfoTest is RegistryServiceHarnessTestBase { registryServiceHarness.exposed_verifyObjectInfo( info, + registerableOwner, expectedType); } @@ -156,10 +157,9 @@ contract VerifyObjectInfoTest is RegistryServiceHarnessTestBase { nftId: NftIdLib.toNftId(randomNumber(type(uint96).max)), parentNftId: NftIdLib.toNftId(randomNumber(type(uint96).max)), objectType: objectType, + release: VersionPartLib.toVersionPart(uint8(randomNumber(type(uint8).max))), isInterceptor: toBool(randomNumber(1)), - objectAddress: address(0), - initialOwner: address(0), - data: "" + objectAddress: address(0) }); vm.expectRevert(abi.encodeWithSelector( @@ -168,6 +168,7 @@ contract VerifyObjectInfoTest is RegistryServiceHarnessTestBase { registryServiceHarness.exposed_verifyObjectInfo( info, + address(0), // zero owner objectType); // expectedType } @@ -179,10 +180,9 @@ contract VerifyObjectInfoTest is RegistryServiceHarnessTestBase { nftId: NftIdLib.toNftId(randomNumber(type(uint96).max)), parentNftId: NftIdLib.toNftId(randomNumber(type(uint96).max)), objectType: objectType, + release: VersionPartLib.toVersionPart(uint8(randomNumber(type(uint8).max))), isInterceptor: toBool(randomNumber(1)), - objectAddress: address(0), - initialOwner: address(registry), // any registered address - data: "" + objectAddress: address(0) }); vm.expectRevert(abi.encodeWithSelector( @@ -192,6 +192,7 @@ contract VerifyObjectInfoTest is RegistryServiceHarnessTestBase { registryServiceHarness.exposed_verifyObjectInfo( info, + address(registry), // any registered address objectType); // expectedType } } \ No newline at end of file diff --git a/test/release/ReleaseInstance.t.sol b/test/release/ReleaseInstance.t.sol index 543f4d5db..1cb53f9d5 100644 --- a/test/release/ReleaseInstance.t.sol +++ b/test/release/ReleaseInstance.t.sol @@ -5,34 +5,12 @@ import {IAccessManaged} from "@openzeppelin/contracts/access/manager/IAccessMana import {Vm, console} from "../../lib/forge-std/src/Test.sol"; import {GifTest} from "../base/GifTest.sol"; -import {AccessManagerCloneable} from "../../contracts/authorization/AccessManagerCloneable.sol"; -import {Amount, AmountLib} from "../../contracts/type/Amount.sol"; -import {NftId, NftIdLib} from "../../contracts/type/NftId.sol"; -import {ClaimId} from "../../contracts/type/ClaimId.sol"; -import {SimpleProduct} from "../../contracts/examples/unpermissioned/SimpleProduct.sol"; -import {SimplePool} from "../../contracts/examples/unpermissioned/SimplePool.sol"; -import {IComponents} from "../../contracts/instance/module/IComponents.sol"; +import {GIF_INITIAL_RELEASE} from "../../contracts/registry/Registry.sol"; import {IInstance} from "../../contracts/instance/IInstance.sol"; -import {ILifecycle} from "../../contracts/shared/ILifecycle.sol"; -import {IPolicy} from "../../contracts/instance/module/IPolicy.sol"; -import {IBundle} from "../../contracts/instance/module/IBundle.sol"; -import {Fee, FeeLib} from "../../contracts/type/Fee.sol"; -import {UFixedLib} from "../../contracts/type/UFixed.sol"; -import {Seconds, SecondsLib} from "../../contracts/type/Seconds.sol"; -import {Timestamp, TimestampLib} from "../../contracts/type/Timestamp.sol"; -import {IPolicyService} from "../../contracts/product/IPolicyService.sol"; -import {IRisk} from "../../contracts/instance/module/IRisk.sol"; -import {PayoutId, PayoutIdLib} from "../../contracts/type/PayoutId.sol"; -import {POLICY} from "../../contracts/type/ObjectType.sol"; -import {RiskId, RiskIdLib, eqRiskId} from "../../contracts/type/RiskId.sol"; -import {ReferralId, ReferralLib} from "../../contracts/type/Referral.sol"; -import {APPLIED, SUBMITTED, ACTIVE, COLLATERALIZED, CONFIRMED, DECLINED, CLOSED, REVOKED} from "../../contracts/type/StateId.sol"; -import {StateId} from "../../contracts/type/StateId.sol"; -import {VersionPart, VersionPartLib} from "../../contracts/type/Version.sol"; +import {NftId} from "../../contracts/type/NftId.sol"; -contract ReleaseInstanceTest is GifTest { - VersionPart public RELEASE_3 = VersionPartLib.toVersionPart(3); +contract ReleaseInstanceTest is GifTest { function setUp() public override { super.setUp(); @@ -56,8 +34,8 @@ contract ReleaseInstanceTest is GifTest { assertTrue(newInstanceNftId.gtz(), "new instance nft zero"); // WHEN release is locked - vm.startPrank(registryOwner); - releaseRegistry.setActive(RELEASE_3, false); + vm.startPrank(gifAdmin); + releaseRegistry.setActive(GIF_INITIAL_RELEASE(), false); vm.stopPrank(); // THEN instance creation fails diff --git a/test/release/ReleaseRegistryConcrete.t.sol b/test/release/ReleaseRegistryConcrete.t.sol new file mode 100644 index 000000000..ceed2e114 --- /dev/null +++ b/test/release/ReleaseRegistryConcrete.t.sol @@ -0,0 +1,2316 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.20; + +import {IAccessManaged} from "@openzeppelin/contracts/access/manager/IAccessManaged.sol"; +import {FoundryRandom} from "foundry-random/FoundryRandom.sol"; +import {console} from "../../lib/forge-std/src/Test.sol"; + +import {IAccessAdmin} from "../../contracts/authorization/IAccessAdmin.sol"; +import {ILifecycle} from "../../contracts/shared/Lifecycle.sol"; +import {IRegistry} from "../../contracts/registry/IRegistry.sol"; +import {IRelease} from "../../contracts/registry/IRelease.sol"; +import {IService} from "../../contracts/shared/IService.sol"; +import {IServiceAuthorization} from "../../contracts/authorization/IServiceAuthorization.sol"; + +import {AccessManagerCloneable} from "../../contracts/authorization/AccessManagerCloneable.sol"; +import {ChainNft} from "../../contracts/registry/ChainNft.sol"; +import {GifDeployer} from "../base/GifDeployer.sol"; +import {NftId, NftIdLib} from "../../contracts/type/NftId.sol"; +import {NftOwnableMock} from "../mock/NftOwnableMock.sol"; +import {ObjectType, RELEASE, REGISTRY, PRODUCT} from "../../contracts/type/ObjectType.sol"; +import {GIF_INITIAL_RELEASE} from "../../contracts/registry/Registry.sol"; +import {ReleaseAdmin} from "../../contracts/registry/ReleaseAdmin.sol"; +import {ReleaseRegistry} from "../../contracts/registry/ReleaseRegistry.sol"; +import {RoleId, RoleIdLib} from "../../contracts/type/RoleId.sol"; +import {ServiceAuthorizationMock, ServiceAuthorizationMockWithRegistryService} from "../mock/ServiceAuthorizationMock.sol"; +import {ServiceMock, ServiceMockWithRegistryDomainV3, ServiceMockWithRegistryDomainV4, ServiceMockWithRegistryDomainV5} from "../mock/ServiceMock.sol"; +import {StateIdLib, SCHEDULED, DEPLOYING, DEPLOYED, SKIPPED, ACTIVE, PAUSED} from "../../contracts/type/StateId.sol"; +import {TimestampLib, gteTimestamp} from "../../contracts/type/Timestamp.sol"; +import {VersionPart, VersionPartLib} from "../../contracts/type/Version.sol"; + + +contract ReleaseRegistryConcreteTest is GifDeployer, FoundryRandom { + + // keep identical to ReleaseRegistry events + event LogReleaseCreation(IAccessAdmin admin, VersionPart version, bytes32 salt); + event LogReleaseActivation(VersionPart version); + event LogReleaseDisabled(VersionPart version); + event LogReleaseEnabled(VersionPart version); + + address public outsider = makeAddr("outsider"); + + function setUp() public virtual + { + ( + ,//dip, + registry, + ,//tokenRegistry, + releaseRegistry, + registryAdmin, + //stakingManager, + ,//staking + ) = deployCore(); + + chainNft = ChainNft(registry.getChainNftAddress()); + registryNftId = registry.getNftId(); + } + + // assert by version getters + function _assert_releaseRegistry_getters(VersionPart version, IRelease.ReleaseInfo memory info) public view + { + _checkReleaseInfo(info); + + assertEq(releaseRegistry.isActiveRelease(version), (info.activatedAt.gtz() && info.disabledAt > TimestampLib.current()), "isActiveRelease() return unxpected value"); + assertTrue(eqReleaseInfo(releaseRegistry.getReleaseInfo(version), info), "getReleaseInfo() return unxpected value"); + assertEq(releaseRegistry.getState(version).toInt(), info.state.toInt(), "getState() return unexpected value #1"); + assertEq(address(releaseRegistry.getServiceAuthorization(version)), address(info.auth), "getServiceAuthorization() return unexpected value #1"); + } + + function test_releaseRegistry_setUp() public view + { + for(uint8 i = 0; i <= GIF_INITIAL_RELEASE().toInt() + 1; i++) { + _assert_releaseRegistry_getters(VersionPartLib.toVersionPart(i), zeroReleaseInfo()); + } + + assertEq(releaseRegistry.releases(), 0, "releases() return unexpected value"); + assertEq(releaseRegistry.getNextVersion().toInt(), GIF_INITIAL_RELEASE().toInt() - 1, "getNextVersion() return unexpected value"); + assertEq(releaseRegistry.getLatestVersion().toInt(), 0, "getLatestVersion() return unexpected value"); + + assertEq(releaseRegistry.getRemainingServicesToRegister(), 0, "getRemainingServicesToRegister() return unexpected value"); + + assertEq(releaseRegistry.getRegistryAdmin(), address(registryAdmin), "getRegistryAdmin() return unexpected value"); + assertEq(address(releaseRegistry.getRegistry()), address(registry), "getRegistry() return unexpected value"); + } + + //------------------------ create release ------------------------// + + function test_releaseRegistry_createRelease_byNotAuthorizedCaller() public + { + vm.expectRevert(abi.encodeWithSelector(IAccessManaged.AccessManagedUnauthorized.selector, gifManager)); + vm.prank(gifManager); + releaseRegistry.createNextRelease(); + + vm.expectRevert(abi.encodeWithSelector(IAccessManaged.AccessManagedUnauthorized.selector, stakingOwner)); + vm.prank(stakingOwner); + releaseRegistry.createNextRelease(); + + vm.expectRevert(abi.encodeWithSelector(IAccessManaged.AccessManagedUnauthorized.selector, outsider)); + vm.prank(outsider); + releaseRegistry.createNextRelease(); + } + + function test_releaseRegistry_createRelease_createInitialReleaseHappyCase() public + { + VersionPart newReleaseVersion = VersionPartLib.toVersionPart(GIF_INITIAL_RELEASE().toInt()); + VersionPart previousReleaseVersion = VersionPartLib.toVersionPart(GIF_INITIAL_RELEASE().toInt() - 1); + + // pre checks + _assert_releaseRegistry_getters(previousReleaseVersion, zeroReleaseInfo()); + _assert_releaseRegistry_getters(newReleaseVersion, zeroReleaseInfo()); + + assertEq(releaseRegistry.releases(), 0, "releases() return unexpected value #1"); + assertEq(releaseRegistry.getNextVersion().toInt(), previousReleaseVersion.toInt(), "getNextVersion() return unexpected value #1"); + assertEq(releaseRegistry.getLatestVersion().toInt(), 0, "getLatestVersion() return unexpected value #1"); + + // create release + vm.prank(gifAdmin); + VersionPart version = releaseRegistry.createNextRelease(); + + // post checks + assertEq(version.toInt(), newReleaseVersion.toInt(), "createNextRelease() return unexpected value"); + + _assert_releaseRegistry_getters( + newReleaseVersion, + IRelease.ReleaseInfo({ + state: SCHEDULED(), + version: newReleaseVersion, + salt: bytes32(0), + auth: IServiceAuthorization(address(0)), + releaseAdmin: address(0), + activatedAt: TimestampLib.zero(), + disabledAt: TimestampLib.zero() + })); + + _assert_releaseRegistry_getters(previousReleaseVersion, zeroReleaseInfo()); + + assertEq(releaseRegistry.releases(), 1, "releases() return unexpected value #2"); + assertEq(releaseRegistry.getNextVersion().toInt(), newReleaseVersion.toInt(), "getNextVersion() return unexpected value #2"); + assertEq(releaseRegistry.getLatestVersion().toInt(), 0, "getLatestVersion() return unexpected value #2"); + + // check latest version + assertEq(version.toInt(), releaseRegistry.getVersion(0).toInt(), "getReleaseVersion() return unexpected value"); + assertEq(releaseRegistry.getReleaseInfo(version).state.toInt(), SCHEDULED().toInt(), "getReleaseInfo() not SCHEDULED"); + assertEq(releaseRegistry.isActiveRelease(version), false, "isActiveRelease() returned unexpected value"); + } + + function test_releaseRegistry_createRelease_whenReleaseScheduledHappyCase() public + { + VersionPart nextVersion = VersionPartLib.toVersionPart(GIF_INITIAL_RELEASE().toInt()); + VersionPart prevVersion = VersionPartLib.toVersionPart(GIF_INITIAL_RELEASE().toInt() - 1); + IRelease.ReleaseInfo memory nextReleaseInfo; + IRelease.ReleaseInfo memory prevReleaseInfo; + + for(uint256 i = 0; i <= 10; i++) + { + // create - skip + vm.prank(gifAdmin); + VersionPart createdVersion = releaseRegistry.createNextRelease(); + + nextReleaseInfo.state = SCHEDULED(); + nextReleaseInfo.version = nextVersion; + if(i > 0) { + prevReleaseInfo.state = SKIPPED(); + } + + // check create + assertEq(createdVersion.toInt(), nextVersion.toInt(), "createNextRelease() return unexpected value"); + + _assert_releaseRegistry_getters(nextVersion, nextReleaseInfo); + _assert_releaseRegistry_getters(prevVersion, prevReleaseInfo); + + assertEq(releaseRegistry.releases(), i + 1, "releases() return unexpected value #1"); + assertEq(releaseRegistry.getNextVersion().toInt(), nextReleaseInfo.version.toInt(), "getNextVersion() return unexpected value #1"); + assertEq(releaseRegistry.getLatestVersion().toInt(), 0, "getLatestVersion() return unexpected value #1"); + + // check latest version + assertEq(createdVersion.toInt(), releaseRegistry.getVersion(i).toInt(), "getReleaseVersion() return unexpected value"); + assertEq(releaseRegistry.getReleaseInfo(createdVersion).state.toInt(), SCHEDULED().toInt(), "getReleaseInfo() not SCHEDULED"); + assertEq(releaseRegistry.isActiveRelease(createdVersion), false, "isActiveRelease() returned unexpected value"); + + prevVersion = nextVersion; + nextVersion = VersionPartLib.toVersionPart(nextVersion.toInt() + 1); + prevReleaseInfo = nextReleaseInfo; + nextReleaseInfo = zeroReleaseInfo(); + } + } + + function test_releaseRegistry_createRelease_whenReleaseDeployingHappyCase() public + { + VersionPart nextVersion = VersionPartLib.toVersionPart(GIF_INITIAL_RELEASE().toInt()); + VersionPart prevVersion = VersionPartLib.toVersionPart(GIF_INITIAL_RELEASE().toInt() - 1); + IRelease.ReleaseInfo memory nextReleaseInfo; + IRelease.ReleaseInfo memory prevReleaseInfo; + + for(uint256 i = 0; i <= 10; i++) + { + vm.prank(gifAdmin); + VersionPart createdVersion = releaseRegistry.createNextRelease(); + + { + // create - skip + nextReleaseInfo.state = SCHEDULED(); + nextReleaseInfo.version = nextVersion; + if(i > 0) { + prevReleaseInfo.state = SKIPPED(); + + assertTrue( + AccessManagerCloneable( + ReleaseAdmin( + prevReleaseInfo.releaseAdmin).authority()).isLocked(), + "isLocked() return unexpected value"); + } + + // check create + assertEq(createdVersion.toInt(), nextVersion.toInt(), "createNextRelease() return unexpected value"); + + _assert_releaseRegistry_getters(nextVersion, nextReleaseInfo); + _assert_releaseRegistry_getters(prevVersion, prevReleaseInfo); + + assertEq(releaseRegistry.releases(), i + 1, "releases() return unexpected value #1"); + assertEq(releaseRegistry.getNextVersion().toInt(), nextReleaseInfo.version.toInt(), "getNextVersion() return unexpected value #1"); + assertEq(releaseRegistry.getLatestVersion().toInt(), 0, "getLatestVersion() return unexpected value #1"); + + // check latest version + assertEq(createdVersion.toInt(), releaseRegistry.getVersion(i).toInt(), "getReleaseVersion() return unexpected value"); + assertEq(releaseRegistry.getReleaseInfo(createdVersion).state.toInt(), SCHEDULED().toInt(), "getReleaseInfo() not SCHEDULED"); + assertEq(releaseRegistry.isActiveRelease(createdVersion), false, "isActiveRelease() returned unexpected value"); + } + + { + // prepare + IServiceAuthorization nextAuthMock = new ServiceAuthorizationMockWithRegistryService(nextVersion); + bytes32 nextSalt = bytes32(randomNumber(type(uint256).max)); + address nextAdmin = _getNextContractAddress(address(releaseRegistry), 0); + + vm.expectEmit(address(releaseRegistry)); + emit LogReleaseCreation(IAccessAdmin(nextAdmin), nextVersion, nextSalt); + + vm.prank(gifManager); + ( + ReleaseAdmin preparedAdmin, + VersionPart preparedVersion, + bytes32 preparedSalt + ) = releaseRegistry.prepareNextRelease(nextAuthMock, nextSalt); + + nextReleaseInfo.state = DEPLOYING(); + nextReleaseInfo.salt = nextSalt; + nextReleaseInfo.auth = nextAuthMock; + nextReleaseInfo.releaseAdmin = address(preparedAdmin); + + // check prepare + // TODO more release admin checks + // precalculate address and compare with prepared admin address + // precalculate and compare release access manager from prepared address + assertEq(preparedVersion.toInt(), nextVersion.toInt(), "prepareNextRelease() return unexpected releaseVersion"); + assertEq(preparedSalt, nextSalt, "prepareNextRelease() return unexpected releaseSalt"); + assertTrue( + AccessManagerCloneable( + ReleaseAdmin( + nextReleaseInfo.releaseAdmin).authority()).isLocked(), + "isLocked() return unexpected value"); + + if(i > 0) { + assertTrue( + AccessManagerCloneable( + ReleaseAdmin( + nextReleaseInfo.releaseAdmin).authority()).isLocked(), + "isLocked() return unexpected value"); + } + + _assert_releaseRegistry_getters(nextVersion, nextReleaseInfo); + _assert_releaseRegistry_getters(prevVersion, prevReleaseInfo); + + assertEq(releaseRegistry.releases(), i + 1, "releases() return unexpected value #2"); + assertEq(releaseRegistry.getNextVersion().toInt(), nextReleaseInfo.version.toInt(), "getNextVersion() return unexpected value #2"); + assertEq(releaseRegistry.getLatestVersion().toInt(), 0, "getLatestVersion() return unexpected value #2"); + + // check latest version + assertEq(createdVersion.toInt(), releaseRegistry.getVersion(i).toInt(), "getReleaseVersion() return unexpected value"); + assertEq(releaseRegistry.getReleaseInfo(createdVersion).state.toInt(), DEPLOYING().toInt(), "getReleaseInfo() not DEPLOYING"); + assertEq(releaseRegistry.isActiveRelease(createdVersion), false, "isActiveRelease() returned unexpected value"); + } + + prevVersion = nextVersion; + nextVersion = VersionPartLib.toVersionPart(nextVersion.toInt() + 1); + prevReleaseInfo = nextReleaseInfo; + nextReleaseInfo = zeroReleaseInfo(); + } + } + + function test_releaseRegistry_createRelease_whenReleaseDeployedHappyCase() public + { + VersionPart nextVersion = VersionPartLib.toVersionPart(GIF_INITIAL_RELEASE().toInt()); + VersionPart prevVersion = VersionPartLib.toVersionPart(GIF_INITIAL_RELEASE().toInt() - 1); + IRelease.ReleaseInfo memory nextReleaseInfo; + IRelease.ReleaseInfo memory prevReleaseInfo; + + IService service; + + for(uint256 i = 0; i <= 2; i++) + { + vm.prank(gifAdmin); + VersionPart createdVersion = releaseRegistry.createNextRelease(); + + { + // solhint-disable-next-line + console.log("scheduling release", i); + + // create - skip + nextReleaseInfo.state = SCHEDULED(); + nextReleaseInfo.version = nextVersion; + if(i > 0) { + prevReleaseInfo.state = SKIPPED(); + + assertTrue( + AccessManagerCloneable( + ReleaseAdmin( + prevReleaseInfo.releaseAdmin).authority()).isLocked(), + "isLocked() return unexpected value"); + } + + // check create + assertEq(createdVersion.toInt(), nextVersion.toInt(), "createNextRelease() return unexpected value"); + if(i > 0) { + assertTrue( + AccessManagerCloneable( + ReleaseAdmin( + prevReleaseInfo.releaseAdmin).authority()).isLocked(), + "isLocked() return unexpected value"); + } + + _assert_releaseRegistry_getters(nextVersion, nextReleaseInfo); + _assert_releaseRegistry_getters(prevVersion, prevReleaseInfo); + + assertEq(releaseRegistry.releases(), i + 1, "releases() return unexpected value #1"); + assertEq(releaseRegistry.getNextVersion().toInt(), nextReleaseInfo.version.toInt(), "getNextVersion() return unexpected value #1"); + assertEq(releaseRegistry.getLatestVersion().toInt(), 0, "getLatestVersion() return unexpected value #1"); + + // check latest version + assertEq(createdVersion.toInt(), releaseRegistry.getVersion(i).toInt(), "getReleaseVersion() return unexpected value"); + assertEq(releaseRegistry.getReleaseInfo(createdVersion).state.toInt(), SCHEDULED().toInt(), "getReleaseInfo() not DEPLOYING"); + assertEq(releaseRegistry.isActiveRelease(createdVersion), false, "isActiveRelease() returned unexpected value"); + + // solhint-disable-next-line + console.log("scheduled release", i); + } + + { + // solhint-disable-next-line + console.log("deploying release", i); + + // prepare + IServiceAuthorization nextAuthMock = new ServiceAuthorizationMockWithRegistryService(nextVersion); + bytes32 nextSalt = bytes32(randomNumber(type(uint256).max)); + + vm.prank(gifManager); + ( + ReleaseAdmin preparedAdmin, + VersionPart preparedVersion, + bytes32 preparedSalt + ) = releaseRegistry.prepareNextRelease(nextAuthMock, nextSalt); + + nextReleaseInfo.state = DEPLOYING(); + nextReleaseInfo.salt = nextSalt; + nextReleaseInfo.auth = nextAuthMock; + nextReleaseInfo.releaseAdmin = address(preparedAdmin); + + // check prepare + assertEq(preparedVersion.toInt(), nextVersion.toInt(), "prepareNextRelease() return unexpected releaseVersion"); + assertEq(preparedSalt, nextSalt, "prepareNextRelease() return unexpected releaseSalt"); + assertTrue( + AccessManagerCloneable( + ReleaseAdmin( + nextReleaseInfo.releaseAdmin).authority()).isLocked(), + "isLocked() return unexpected value"); + if(i > 0) { + assertTrue( + AccessManagerCloneable( + ReleaseAdmin( + prevReleaseInfo.releaseAdmin).authority()).isLocked(), + "isLocked() return unexpected value"); + } + + _assert_releaseRegistry_getters(nextVersion, nextReleaseInfo); + _assert_releaseRegistry_getters(prevVersion, prevReleaseInfo); + + assertEq(releaseRegistry.releases(), i + 1, "releases() return unexpected value #2"); + assertEq(releaseRegistry.getNextVersion().toInt(), nextReleaseInfo.version.toInt(), "getNextVersion() return unexpected value #2"); + assertEq(releaseRegistry.getLatestVersion().toInt(), 0, "getLatestVersion() return unexpected value #2"); + + // check latest version + assertEq(createdVersion.toInt(), releaseRegistry.getVersion(i).toInt(), "getReleaseVersion() return unexpected value"); + assertEq(releaseRegistry.getReleaseInfo(createdVersion).state.toInt(), DEPLOYING().toInt(), "getReleaseInfo() not DEPLOYING"); + assertEq(releaseRegistry.isActiveRelease(createdVersion), false, "isActiveRelease() returned unexpected value"); + + // solhint-disable-next-line + console.log("deployed release", i); + } + + { + // solhint-disable-next-line + console.log("registering services", i); + + // deploy (register all(1) services) + service = _prepareServiceWithRegistryDomain(nextReleaseInfo.version, ReleaseAdmin(nextReleaseInfo.releaseAdmin)); + assertFalse(registry.isRegisteredService(address(service)), "isRegisteredService() return unexpected value #1"); + + uint256 expectedNftId = chainNft.getNextTokenId(); + + // TODO add AccessAdmin logs + vm.expectEmit(address(registry)); + emit IRegistry.LogRegistryServiceRegistered(nextVersion, REGISTRY()); + + vm.prank(gifManager); + NftId serviceNftId = releaseRegistry.registerService(service); + + nextReleaseInfo.state = DEPLOYED(); + RoleId expectedServiceRoleId = RoleIdLib.toServiceRoleId(REGISTRY(), nextVersion); + + // check registration + assertEq(serviceNftId.toInt(), expectedNftId, "registerService() return unexpected value"); + assertTrue( + AccessManagerCloneable( + ReleaseAdmin( + nextReleaseInfo.releaseAdmin).authority()).isLocked(), + "isLocked() return unexpected value"); + assertTrue(registry.isRegisteredService(address(service)), "isRegisteredService() return unexpected value #2"); + assertFalse(registryAdmin.targetExists(address(service)), "targetExists() return unexpected value"); + + _assert_releaseRegistry_getters(nextVersion, nextReleaseInfo); + _assert_releaseRegistry_getters(prevVersion, prevReleaseInfo); + + assertEq(releaseRegistry.releases(), i + 1, "releases() return unexpected value #3"); + assertEq(releaseRegistry.getNextVersion().toInt(), nextReleaseInfo.version.toInt(), "getNextVersion() return unexpected value #3"); + assertEq(releaseRegistry.getLatestVersion().toInt(), 0, "getLatestVersion() return unexpected value #3"); + + // check latest version + assertEq(createdVersion.toInt(), releaseRegistry.getVersion(i).toInt(), "getReleaseVersion() return unexpected value"); + assertEq(releaseRegistry.getReleaseInfo(createdVersion).state.toInt(), DEPLOYED().toInt(), "getReleaseInfo() not DEPLOYED"); + assertEq(releaseRegistry.isActiveRelease(createdVersion), false, "isActiveRelease() returned unexpected value"); + + // solhint-disable-next-line + console.log("services registered", i); + } + + prevVersion = nextVersion; + nextVersion = VersionPartLib.toVersionPart(nextVersion.toInt() + 1); + prevReleaseInfo = nextReleaseInfo; + nextReleaseInfo = zeroReleaseInfo(); + } + } + + + function test_releaseRegistry_createRelease_whenReleaseActiveHappyCase() public + { + VersionPart nextVersion = VersionPartLib.toVersionPart(GIF_INITIAL_RELEASE().toInt()); + VersionPart prevVersion = VersionPartLib.toVersionPart(GIF_INITIAL_RELEASE().toInt() - 1); + IRelease.ReleaseInfo memory nextReleaseInfo; + IRelease.ReleaseInfo memory prevReleaseInfo; + + IService service; + + for(uint256 i = 0; i <= 2; i++) + { + vm.prank(gifAdmin); + VersionPart createdVersion = releaseRegistry.createNextRelease(); + + { + // solhint-disable-next-line + console.log("scheduling release", i); + + // create - skip + nextReleaseInfo.state = SCHEDULED(); + nextReleaseInfo.version = nextVersion; + + // check create + assertEq(createdVersion.toInt(), nextVersion.toInt(), "createNextRelease() return unexpected value"); + if(i > 0) { + assertFalse( + AccessManagerCloneable( + ReleaseAdmin( + prevReleaseInfo.releaseAdmin).authority()).isLocked(), + "isLocked() return unexpected value"); + } + + _assert_releaseRegistry_getters(nextVersion, nextReleaseInfo); + _assert_releaseRegistry_getters(prevVersion, prevReleaseInfo); + + assertEq(releaseRegistry.releases(), i + 1, "releases() return unexpected value #1"); + assertEq(releaseRegistry.getNextVersion().toInt(), nextReleaseInfo.version.toInt(), "getNextVersion() return unexpected value #1"); + assertEq(releaseRegistry.getLatestVersion().toInt(), prevReleaseInfo.version.toInt(), "getLatestVersion() return unexpected value #1"); + + // solhint-disable-next-line + console.log("scheduled release", i); + } + + { + // solhint-disable-next-line + console.log("deploying release", i); + + // prepare + IServiceAuthorization nextAuthMock = new ServiceAuthorizationMockWithRegistryService(nextVersion); + bytes32 nextSalt = bytes32(randomNumber(type(uint256).max)); + + vm.prank(gifManager); + ( + ReleaseAdmin preparedAdmin, + VersionPart preparedVersion, + bytes32 preparedSalt + ) = releaseRegistry.prepareNextRelease(nextAuthMock, nextSalt); + + nextReleaseInfo.state = DEPLOYING(); + nextReleaseInfo.salt = nextSalt; + nextReleaseInfo.auth = nextAuthMock; + nextReleaseInfo.releaseAdmin = address(preparedAdmin); + + // check prepare + assertEq(preparedVersion.toInt(), nextVersion.toInt(), "prepareNextRelease() return unexpected releaseVersion"); + assertEq(preparedSalt, nextSalt, "prepareNextRelease() return unexpected releaseSalt"); + assertTrue( + AccessManagerCloneable( + ReleaseAdmin( + nextReleaseInfo.releaseAdmin).authority()).isLocked(), + "isLocked() return unexpected value"); + if(i > 0) { + assertFalse( + AccessManagerCloneable( + ReleaseAdmin( + prevReleaseInfo.releaseAdmin).authority()).isLocked(), + "isLocked() return unexpected value"); + } + + _assert_releaseRegistry_getters(nextVersion, nextReleaseInfo); + _assert_releaseRegistry_getters(prevVersion, prevReleaseInfo); + + assertEq(releaseRegistry.releases(), i + 1, "releases() return unexpected value #2"); + assertEq(releaseRegistry.getNextVersion().toInt(), nextReleaseInfo.version.toInt(), "getNextVersion() return unexpected value #2"); + assertEq(releaseRegistry.getLatestVersion().toInt(), prevReleaseInfo.version.toInt(), "getLatestVersion() return unexpected value #2"); + + // solhint-disable-next-line + console.log("deployed release", i); + } + + { +console.log("block 3a, i:", i); + // solhint-disable-next-line + console.log("registering services", i); + + // deploy (register all(1) services) + service = _prepareServiceWithRegistryDomain(nextReleaseInfo.version, ReleaseAdmin(nextReleaseInfo.releaseAdmin)); + assertFalse(registry.isRegisteredService(address(service)), "isRegisteredService() return unexpected value #1"); +console.log("block 3b, i:", i); + + uint256 expectedNftId = chainNft.getNextTokenId(); + + // TODO add AccessAdmin logs + vm.expectEmit(address(registry)); + emit IRegistry.LogRegistryServiceRegistered(nextVersion, REGISTRY()); + + vm.prank(gifManager); + NftId serviceNftId = releaseRegistry.registerService(service); +console.log("block 3c, i:", i); + + nextReleaseInfo.state = DEPLOYED(); + RoleId expectedServiceRoleId = RoleIdLib.toServiceRoleId(REGISTRY(), nextVersion); + + // check registration + assertEq(serviceNftId.toInt(), expectedNftId, "registerService() return unexpected value"); + ReleaseAdmin releaseAdmin = ReleaseAdmin(nextReleaseInfo.releaseAdmin); + assertTrue(AccessManagerCloneable(releaseAdmin.authority()).isLocked(), "isLocked() return unexpected value"); + assertTrue(releaseAdmin.isRoleMember(expectedServiceRoleId, address(service)), "isRoleMember() return unexpected value"); + assertTrue(releaseAdmin.targetExists(address(service)), "targetExists() return unexpected value"); + assertTrue(registry.isRegisteredService(address(service)), "isRegisteredService() return unexpected value #2"); + assertFalse(registryAdmin.targetExists(address(service)), "targetExists() return unexpected value"); +console.log("block 3d, i:", i); + + _assert_releaseRegistry_getters(nextVersion, nextReleaseInfo); +console.log("block 3e, i:", i); + _assert_releaseRegistry_getters(prevVersion, prevReleaseInfo); +console.log("block 3f, i:", i); + + assertEq(releaseRegistry.releases(), i + 1, "releases() return unexpected value #3"); + assertEq(releaseRegistry.getNextVersion().toInt(), nextReleaseInfo.version.toInt(), "getNextVersion() return unexpected value #3"); + assertEq(releaseRegistry.getLatestVersion().toInt(), prevReleaseInfo.version.toInt(), "getLatestVersion() return unexpected value #3"); +console.log("block 3g, i:", i); + + // solhint-disable-next-line + console.log("registered services", i); + } + + { + // solhint-disable-next-line + console.log("activating release", i); + + // activate + vm.expectEmit(address(releaseRegistry)); + emit LogReleaseActivation(nextVersion); + + // TODO add AccessAdmin logs + + vm.prank(gifAdmin); + releaseRegistry.activateNextRelease(); + + nextReleaseInfo.state = ACTIVE(); + nextReleaseInfo.activatedAt = TimestampLib.current(); + nextReleaseInfo.disabledAt = TimestampLib.max(); + RoleId expectedServiceRoleIdForAllVersions = RoleIdLib.toGenericServiceRoleId(REGISTRY()); + + // check activation + assertFalse(AccessManagerCloneable( + ReleaseAdmin( + nextReleaseInfo.releaseAdmin).authority()).isLocked(), + "isLocked() return unexpected value"); + assertTrue(registryAdmin.isRoleMember(expectedServiceRoleIdForAllVersions, address(service)), "isRoleMember() return unexpected value"); + + _assert_releaseRegistry_getters(nextVersion, nextReleaseInfo); + _assert_releaseRegistry_getters(prevVersion, prevReleaseInfo); + + assertEq(releaseRegistry.releases(), i + 1, "releases() return unexpected value #4"); + assertEq(releaseRegistry.getNextVersion().toInt(), nextReleaseInfo.version.toInt(), "getNextVersion() return unexpected value #4"); + assertEq(releaseRegistry.getLatestVersion().toInt(), nextReleaseInfo.version.toInt(), "getLatestVersion() return unexpected value #4"); + + // check latest version + assertEq(createdVersion.toInt(), releaseRegistry.getVersion(i).toInt(), "getReleaseVersion() return unexpected value"); + assertEq(releaseRegistry.getReleaseInfo(createdVersion).state.toInt(), ACTIVE().toInt(), "getReleaseInfo() not ACTIVE"); + assertEq(releaseRegistry.isActiveRelease(createdVersion), true, "isActiveRelease() returned unexpected value"); + + // solhint-disable-next-line + console.log("activated release", i); + } + + prevVersion = nextVersion; + nextVersion = VersionPartLib.toVersionPart(nextVersion.toInt() + 1); + prevReleaseInfo = nextReleaseInfo; + nextReleaseInfo = zeroReleaseInfo(); + } + } + + function test_releaseRegistry_createRelease_whenReleasePausedHappyCase() public + { + VersionPart nextVersion = VersionPartLib.toVersionPart(GIF_INITIAL_RELEASE().toInt()); + VersionPart prevVersion = VersionPartLib.toVersionPart(GIF_INITIAL_RELEASE().toInt() - 1); + IRelease.ReleaseInfo memory nextReleaseInfo; + IRelease.ReleaseInfo memory prevReleaseInfo; + + IService service; + + for(uint256 i = 0; i <= 2; i++) + { + { + // create - skip + vm.prank(gifAdmin); + VersionPart createdVersion = releaseRegistry.createNextRelease(); + + nextReleaseInfo.state = SCHEDULED(); + nextReleaseInfo.version = nextVersion; + + // check create + assertEq(createdVersion.toInt(), nextVersion.toInt(), "createNextRelease() return unexpected value"); + if(i > 0) { + assertTrue(AccessManagerCloneable( + ReleaseAdmin( + prevReleaseInfo.releaseAdmin).authority()).isLocked(), + "isLocked() return unexpected value"); + } + + _assert_releaseRegistry_getters(nextVersion, nextReleaseInfo); + _assert_releaseRegistry_getters(prevVersion, prevReleaseInfo); + + assertEq(releaseRegistry.releases(), i + 1, "releases() return unexpected value #1"); + assertEq(releaseRegistry.getNextVersion().toInt(), nextReleaseInfo.version.toInt(), "getNextVersion() return unexpected value #1"); + assertEq(releaseRegistry.getLatestVersion().toInt(), prevReleaseInfo.version.toInt(), "getLatestVersion() return unexpected value #1"); + } + + { + // prepare + IServiceAuthorization nextAuthMock = new ServiceAuthorizationMockWithRegistryService(nextVersion); + bytes32 nextSalt = bytes32(randomNumber(type(uint256).max)); + + vm.prank(gifManager); + ( + ReleaseAdmin preparedAdmin, + VersionPart preparedVersion, + bytes32 preparedSalt + ) = releaseRegistry.prepareNextRelease(nextAuthMock, nextSalt); + + nextReleaseInfo.state = DEPLOYING(); + nextReleaseInfo.salt = nextSalt; + nextReleaseInfo.auth = nextAuthMock; + nextReleaseInfo.releaseAdmin = address(preparedAdmin); + + // check prepare + assertEq(preparedVersion.toInt(), nextVersion.toInt(), "prepareNextRelease() return unexpected releaseVersion"); + assertEq(preparedSalt, nextSalt, "prepareNextRelease() return unexpected releaseSalt"); + assertTrue(AccessManagerCloneable( + ReleaseAdmin( + nextReleaseInfo.releaseAdmin).authority()).isLocked(), + "isLocked() return unexpected value"); + if(i > 0) { + assertTrue(AccessManagerCloneable( + ReleaseAdmin( + nextReleaseInfo.releaseAdmin).authority()).isLocked(), + "isLocked() return unexpected value"); + } + + _assert_releaseRegistry_getters(nextVersion, nextReleaseInfo); + _assert_releaseRegistry_getters(prevVersion, prevReleaseInfo); + + assertEq(releaseRegistry.releases(), i + 1, "releases() return unexpected value #2"); + assertEq(releaseRegistry.getNextVersion().toInt(), nextReleaseInfo.version.toInt(), "getNextVersion() return unexpected value #2"); + assertEq(releaseRegistry.getLatestVersion().toInt(), prevReleaseInfo.version.toInt(), "getLatestVersion() return unexpected value #2"); + } + + { + // deploy (register all(1) services) + service = _prepareServiceWithRegistryDomain(nextReleaseInfo.version, ReleaseAdmin(nextReleaseInfo.releaseAdmin)); + assertFalse(registry.isRegisteredService(address(service)), "isRegisteredService() return unexpected value #1"); + + uint256 expectedNftId = chainNft.getNextTokenId(); + + // TODO add AccessAdmin logs + vm.expectEmit(address(registry)); + emit IRegistry.LogRegistryServiceRegistered(nextVersion, REGISTRY()); + + vm.prank(gifManager); + NftId serviceNftId = releaseRegistry.registerService(service); + + nextReleaseInfo.state = DEPLOYED(); + RoleId expectedServiceRoleId = RoleIdLib.toServiceRoleId(REGISTRY(), nextVersion); + + // check registration + assertEq(serviceNftId.toInt(), expectedNftId, "registerService() return unexpected value"); + ReleaseAdmin releaseAdmin = ReleaseAdmin(nextReleaseInfo.releaseAdmin); + assertTrue(AccessManagerCloneable(releaseAdmin.authority()).isLocked(), + "isLocked() return unexpected value"); + assertTrue(releaseAdmin.isRoleMember(expectedServiceRoleId, address(service)), "isRoleMember() return unexpected value"); + assertTrue(releaseAdmin.targetExists(address(service)), "targetExists() return unexpected value"); + assertTrue(registry.isRegisteredService(address(service)), "isRegisteredService() return unexpected value #2"); + assertFalse(registryAdmin.targetExists(address(service)), "targetExists() return unexpected value"); + + _assert_releaseRegistry_getters(nextVersion, nextReleaseInfo); + _assert_releaseRegistry_getters(prevVersion, prevReleaseInfo); + + assertEq(releaseRegistry.releases(), i + 1, "releases() return unexpected value #3"); + assertEq(releaseRegistry.getNextVersion().toInt(), nextReleaseInfo.version.toInt(), "getNextVersion() return unexpected value #3"); + assertEq(releaseRegistry.getLatestVersion().toInt(), prevReleaseInfo.version.toInt(), "getLatestVersion() return unexpected value #3"); + } + + { + // activate release + vm.expectEmit(address(releaseRegistry)); + emit LogReleaseActivation(nextVersion); + + // TODO add AccessAdmin logs? + + vm.prank(gifAdmin); + releaseRegistry.activateNextRelease(); + + nextReleaseInfo.state = ACTIVE(); + nextReleaseInfo.activatedAt = TimestampLib.current(); + nextReleaseInfo.disabledAt = TimestampLib.max(); + RoleId expectedServiceRoleIdForAllVersions = RoleIdLib.toGenericServiceRoleId(REGISTRY()); + + // check activation + assertFalse(AccessManagerCloneable(ReleaseAdmin(nextReleaseInfo.releaseAdmin) + .authority()).isLocked(), "isLocked() return unexpected value"); + assertTrue(registryAdmin.isRoleMember(expectedServiceRoleIdForAllVersions, address(service)), "isRoleMember() return unexpected value"); + + _assert_releaseRegistry_getters(nextVersion, nextReleaseInfo); + _assert_releaseRegistry_getters(prevVersion, prevReleaseInfo); + + assertEq(releaseRegistry.releases(), i + 1, "releases() return unexpected value #4"); + assertEq(releaseRegistry.getNextVersion().toInt(), nextReleaseInfo.version.toInt(), "getNextVersion() return unexpected value #4"); + assertEq(releaseRegistry.getLatestVersion().toInt(), nextReleaseInfo.version.toInt(), "getLatestVersion() return unexpected value #4"); + } + + { + // pause + vm.expectEmit(address(releaseRegistry)); + emit LogReleaseDisabled(nextVersion); + + vm.prank(gifAdmin); + releaseRegistry.setActive(nextVersion, false); + + nextReleaseInfo.state = PAUSED(); + nextReleaseInfo.disabledAt = TimestampLib.current(); + + // check pause + assertTrue(AccessManagerCloneable( + ReleaseAdmin( + nextReleaseInfo.releaseAdmin).authority()).isLocked(), + "isLocked() return unexpected value"); + assertTrue(gteTimestamp(nextReleaseInfo.disabledAt, prevReleaseInfo.disabledAt), "Test error: nextPauseTimestamp <= prevPauseTimestamp"); + + _assert_releaseRegistry_getters(nextVersion, nextReleaseInfo); + _assert_releaseRegistry_getters(prevVersion, prevReleaseInfo); + + assertEq(releaseRegistry.releases(), i + 1, "releases() return unexpected value #4"); + assertEq(releaseRegistry.getNextVersion().toInt(), nextReleaseInfo.version.toInt(), "getNextVersion() return unexpected value #4"); + assertEq(releaseRegistry.getLatestVersion().toInt(), nextReleaseInfo.version.toInt(), "getLatestVersion() return unexpected value #4"); + } + + prevVersion = nextVersion; + nextVersion = VersionPartLib.toVersionPart(nextVersion.toInt() + 1); + prevReleaseInfo = nextReleaseInfo; + nextReleaseInfo = zeroReleaseInfo(); + } + } + + function test_releaseRegistry_createRelease_whenReleaseUnpausedHappaCase() public + { + VersionPart nextVersion = VersionPartLib.toVersionPart(GIF_INITIAL_RELEASE().toInt()); + VersionPart prevVersion = VersionPartLib.toVersionPart(GIF_INITIAL_RELEASE().toInt() - 1); + IRelease.ReleaseInfo memory nextReleaseInfo; + IRelease.ReleaseInfo memory prevReleaseInfo; + + IService service; + + for(uint256 i = 0; i <= 2; i++) + { + { + // create - skip + vm.prank(gifAdmin); + VersionPart createdVersion = releaseRegistry.createNextRelease(); + + nextReleaseInfo.state = SCHEDULED(); + nextReleaseInfo.version = nextVersion; + + // check create + assertEq(createdVersion.toInt(), nextVersion.toInt(), "createNextRelease() return unexpected value"); + if(i > 0) { + assertFalse(AccessManagerCloneable(ReleaseAdmin(prevReleaseInfo.releaseAdmin) + .authority()).isLocked(), "isLocked() return unexpected value"); + } + + _assert_releaseRegistry_getters(nextVersion, nextReleaseInfo); + _assert_releaseRegistry_getters(prevVersion, prevReleaseInfo); + + assertEq(releaseRegistry.releases(), i + 1, "releases() return unexpected value #1"); + assertEq(releaseRegistry.getNextVersion().toInt(), nextReleaseInfo.version.toInt(), "getNextVersion() return unexpected value #1"); + assertEq(releaseRegistry.getLatestVersion().toInt(), prevReleaseInfo.version.toInt(), "getLatestVersion() return unexpected value #1"); + } + + { + // prepare + IServiceAuthorization nextAuthMock = new ServiceAuthorizationMockWithRegistryService(nextVersion); + bytes32 nextSalt = bytes32(randomNumber(type(uint256).max)); + + vm.prank(gifManager); + ( + ReleaseAdmin preparedAdmin, + VersionPart preparedVersion, + bytes32 preparedSalt + ) = releaseRegistry.prepareNextRelease(nextAuthMock, nextSalt); + + nextReleaseInfo.state = DEPLOYING(); + nextReleaseInfo.salt = nextSalt; + nextReleaseInfo.auth = nextAuthMock; + nextReleaseInfo.releaseAdmin = address(preparedAdmin); + + // check prepare + assertEq(preparedVersion.toInt(), nextVersion.toInt(), "prepareNextRelease() return unexpected releaseVersion"); + assertEq(preparedSalt, nextSalt, "prepareNextRelease() return unexpected releaseSalt"); + assertTrue(AccessManagerCloneable(ReleaseAdmin(nextReleaseInfo.releaseAdmin) + .authority()).isLocked(), "isLocked() return unexpected value"); + if(i > 0) { + assertFalse(AccessManagerCloneable(ReleaseAdmin(prevReleaseInfo.releaseAdmin) + .authority()).isLocked(), "isLocked() return unexpected value"); + } + + _assert_releaseRegistry_getters(nextVersion, nextReleaseInfo); + _assert_releaseRegistry_getters(prevVersion, prevReleaseInfo); + + assertEq(releaseRegistry.releases(), i + 1, "releases() return unexpected value #2"); + assertEq(releaseRegistry.getNextVersion().toInt(), nextReleaseInfo.version.toInt(), "getNextVersion() return unexpected value #2"); + assertEq(releaseRegistry.getLatestVersion().toInt(), prevReleaseInfo.version.toInt(), "getLatestVersion() return unexpected value #2"); + } + + { + // deploy (register all(1) services) + service = _prepareServiceWithRegistryDomain(nextReleaseInfo.version, ReleaseAdmin(address(ReleaseAdmin(nextReleaseInfo.releaseAdmin) + ))); + assertFalse(registry.isRegisteredService(address(service)), "isRegisteredService() return unexpected value #1"); + + uint256 expectedNftId = chainNft.getNextTokenId(); + + // TODO add AccessAdmin logs + vm.expectEmit(address(registry)); + emit IRegistry.LogRegistryServiceRegistered(nextVersion, REGISTRY()); + + vm.prank(gifManager); + NftId serviceNftId = releaseRegistry.registerService(service); + + nextReleaseInfo.state = DEPLOYED(); + RoleId expectedServiceRoleId = RoleIdLib.toServiceRoleId(REGISTRY(), nextVersion); + + // check registration + assertEq(serviceNftId.toInt(), expectedNftId, "registerService() return unexpected value"); + assertTrue(AccessManagerCloneable(ReleaseAdmin(nextReleaseInfo.releaseAdmin) + .authority()).isLocked(), "isLocked() return unexpected value"); + assertTrue(ReleaseAdmin(nextReleaseInfo.releaseAdmin) + .isRoleMember(expectedServiceRoleId, address(service)), "isRoleMember() return unexpected value"); + assertTrue(ReleaseAdmin(nextReleaseInfo.releaseAdmin) + .targetExists(address(service)), "targetExists() return unexpected value"); + assertTrue(registry.isRegisteredService(address(service)), "isRegisteredService() return unexpected value #2"); + assertFalse(registryAdmin.targetExists(address(service)), "targetExists() return unexpected value"); + + _assert_releaseRegistry_getters(nextVersion, nextReleaseInfo); + _assert_releaseRegistry_getters(prevVersion, prevReleaseInfo); + + assertEq(releaseRegistry.releases(), i + 1, "releases() return unexpected value #3"); + assertEq(releaseRegistry.getNextVersion().toInt(), nextReleaseInfo.version.toInt(), "getNextVersion() return unexpected value #3"); + assertEq(releaseRegistry.getLatestVersion().toInt(), prevReleaseInfo.version.toInt(), "getLatestVersion() return unexpected value #3"); + } + + { + // activate release + vm.expectEmit(address(releaseRegistry)); + emit LogReleaseActivation(nextVersion); + + // TODO add AccessAdmin logs? + + vm.prank(gifAdmin); + releaseRegistry.activateNextRelease(); + + nextReleaseInfo.state = ACTIVE(); + nextReleaseInfo.activatedAt = TimestampLib.current(); + nextReleaseInfo.disabledAt = TimestampLib.max(); + RoleId expectedServiceRoleIdForAllVersions = RoleIdLib.toGenericServiceRoleId(REGISTRY()); + + // check activation + assertFalse(AccessManagerCloneable(ReleaseAdmin(nextReleaseInfo.releaseAdmin) + .authority()).isLocked(), "isLocked() return unexpected value"); + assertTrue(registryAdmin.isRoleMember(expectedServiceRoleIdForAllVersions, address(service)), "isRoleMember() return unexpected value"); + + _assert_releaseRegistry_getters(nextVersion, nextReleaseInfo); + _assert_releaseRegistry_getters(prevVersion, prevReleaseInfo); + + assertEq(releaseRegistry.releases(), i + 1, "releases() return unexpected value #4"); + assertEq(releaseRegistry.getNextVersion().toInt(), nextReleaseInfo.version.toInt(), "getNextVersion() return unexpected value #4"); + assertEq(releaseRegistry.getLatestVersion().toInt(), nextReleaseInfo.version.toInt(), "getLatestVersion() return unexpected value #4"); + } + + { + // pause + vm.expectEmit(address(releaseRegistry)); + emit LogReleaseDisabled(nextVersion); + + vm.prank(gifAdmin); + releaseRegistry.setActive(nextVersion, false); + + nextReleaseInfo.state = PAUSED(); + nextReleaseInfo.disabledAt = TimestampLib.current(); + + // check pause + assertTrue(AccessManagerCloneable(ReleaseAdmin(nextReleaseInfo.releaseAdmin) + .authority()).isLocked(), "isLocked() return unexpected value"); + + _assert_releaseRegistry_getters(nextVersion, nextReleaseInfo); + _assert_releaseRegistry_getters(prevVersion, prevReleaseInfo); + + assertEq(releaseRegistry.releases(), i + 1, "releases() return unexpected value #4"); + assertEq(releaseRegistry.getNextVersion().toInt(), nextReleaseInfo.version.toInt(), "getNextVersion() return unexpected value #4"); + assertEq(releaseRegistry.getLatestVersion().toInt(), nextReleaseInfo.version.toInt(), "getLatestVersion() return unexpected value #4"); + } + + { + // unpause + vm.expectEmit(address(releaseRegistry)); + emit LogReleaseEnabled(nextVersion); + + vm.prank(gifAdmin); + releaseRegistry.setActive(nextVersion, true); + + nextReleaseInfo.state = ACTIVE(); + nextReleaseInfo.disabledAt = TimestampLib.max(); // + + // check unpause + assertFalse(AccessManagerCloneable(ReleaseAdmin(nextReleaseInfo.releaseAdmin) + .authority()).isLocked(), "isLocked() return unexpected value"); + + _assert_releaseRegistry_getters(nextVersion, nextReleaseInfo); + _assert_releaseRegistry_getters(prevVersion, prevReleaseInfo); + + assertEq(releaseRegistry.releases(), i + 1, "releases() return unexpected value #4"); + assertEq(releaseRegistry.getNextVersion().toInt(), nextReleaseInfo.version.toInt(), "getNextVersion() return unexpected value #4"); + assertEq(releaseRegistry.getLatestVersion().toInt(), nextReleaseInfo.version.toInt(), "getLatestVersion() return unexpected value #4"); + } + + prevVersion = nextVersion; + nextVersion = VersionPartLib.toVersionPart(nextVersion.toInt() + 1); + prevReleaseInfo = nextReleaseInfo; + nextReleaseInfo = zeroReleaseInfo(); + } + } + + //------------------------ prepare release ------------------------// + + function test_releaseRegistry_prepareRelease_byNotAuthorizedCaller() public + { + VersionPart releaseVersion = VersionPartLib.toVersionPart(GIF_INITIAL_RELEASE().toInt()); + ServiceAuthorizationMockWithRegistryService serviceAuth = new ServiceAuthorizationMockWithRegistryService(releaseVersion); + + vm.prank(gifAdmin); + releaseRegistry.createNextRelease(); + + vm.expectRevert(abi.encodeWithSelector(IAccessManaged.AccessManagedUnauthorized.selector, gifAdmin)); + vm.prank(gifAdmin); + releaseRegistry.prepareNextRelease(serviceAuth, "0x1234"); + + vm.expectRevert(abi.encodeWithSelector(IAccessManaged.AccessManagedUnauthorized.selector, stakingOwner)); + vm.prank(stakingOwner); + releaseRegistry.prepareNextRelease(serviceAuth, "0x1234"); + + vm.expectRevert(abi.encodeWithSelector(IAccessManaged.AccessManagedUnauthorized.selector, outsider)); + vm.prank(outsider); + releaseRegistry.prepareNextRelease(serviceAuth, "0x1234"); + } + + function test_releaseRegistry_prepareRelease_whenInitialReleaseNotCreated() public + { + VersionPart expectedVersion = VersionPartLib.toVersionPart(GIF_INITIAL_RELEASE().toInt()); + ServiceAuthorizationMockWithRegistryService serviceAuth = new ServiceAuthorizationMockWithRegistryService(expectedVersion); + bytes32 salt = "0x1234"; + + vm.expectRevert(abi.encodeWithSelector( + ILifecycle.ErrorFromStateMissmatch.selector, + address(releaseRegistry), + RELEASE(), + StateIdLib.zero(), + SCHEDULED() + )); + vm.prank(gifManager); + releaseRegistry.prepareNextRelease(serviceAuth, salt); + } + + function test_releaseRegistry_prepareRelease_initialReleaseHappyCase() public + { + VersionPart expectedVersion = VersionPartLib.toVersionPart(GIF_INITIAL_RELEASE().toInt()); + ServiceAuthorizationMockWithRegistryService serviceAuth = new ServiceAuthorizationMockWithRegistryService(expectedVersion); + bytes32 salt = "0x1234"; + address admin = _getNextContractAddress(address(releaseRegistry), 0); + + vm.prank(gifAdmin); + releaseRegistry.createNextRelease(); + + vm.expectEmit(address(releaseRegistry)); + emit LogReleaseCreation(IAccessAdmin(admin), expectedVersion, salt); + + vm.prank(gifManager); + ( + ReleaseAdmin preparedAdmin, + VersionPart preparedVersion, + bytes32 preparedSalt + ) = releaseRegistry.prepareNextRelease(serviceAuth, salt); + + // TODO check release admin in better + assertTrue(address(preparedAdmin) != address(0), "prepareNextRelease() return unexpected authority"); + assertEq(preparedVersion.toInt(), expectedVersion.toInt(), "prepareNextRelease() return unexpected releaseVersion"); + assertEq(preparedSalt, salt, "prepareNextRelease() return unexpected releaseSalt"); + + _assert_releaseRegistry_getters( + expectedVersion, + IRelease.ReleaseInfo({ + state: DEPLOYING(), + version: preparedVersion, + salt: preparedSalt, + auth: serviceAuth, + releaseAdmin: address(preparedAdmin), + activatedAt: TimestampLib.zero(), + disabledAt: TimestampLib.zero() + })); + _assert_releaseRegistry_getters( + VersionPartLib.toVersionPart(GIF_INITIAL_RELEASE().toInt() - 1), + zeroReleaseInfo()); + + assertEq(releaseRegistry.releases(), 1, "releases() return unexpected value"); + assertEq(releaseRegistry.getNextVersion().toInt(), expectedVersion.toInt(), "getNextVersion() return unexpected value"); + assertEq(releaseRegistry.getLatestVersion().toInt(), 0, "getLatestVersion() return unexpected value"); + } + + function test_releaseRegistry_prepareRelease_whenReleaseScheduledHappyCase() public + { + // Equivalent to test_releaseRegistry_createRelease_whenReleaseDeployingHappyCase() + // create release + // prepare release + // loop + } + + function test_releaseRegistry_prepareRelease_whenReleaseDeploying() public + { + for(uint256 i = 0; i <= 2; i++) + { + // create + vm.prank(gifAdmin); + VersionPart createdVersion = releaseRegistry.createNextRelease(); + + // prepare + ServiceAuthorizationMockWithRegistryService serviceAuth = new ServiceAuthorizationMockWithRegistryService(createdVersion); + bytes32 salt = bytes32(randomNumber(type(uint256).max)); + + vm.prank(gifManager); + releaseRegistry.prepareNextRelease(serviceAuth, salt); + + vm.expectRevert(abi.encodeWithSelector( + ILifecycle.ErrorFromStateMissmatch.selector, + address(releaseRegistry), + RELEASE(), + DEPLOYING(), + SCHEDULED() + )); + vm.prank(gifManager); + releaseRegistry.prepareNextRelease(serviceAuth, salt); + } + } + + function test_releaseRegistry_prepareRelease_whenReleaseDeployed() public + { + for(uint256 i = 0; i <= 2; i++) + { + // create - skip + vm.prank(gifAdmin); + VersionPart createdVersion = releaseRegistry.createNextRelease(); + + // prepare + IServiceAuthorization authMock = new ServiceAuthorizationMockWithRegistryService(createdVersion); + bytes32 salt = bytes32(randomNumber(type(uint256).max)); + + IAccessAdmin preparedAdmin; + vm.prank(gifManager); + (preparedAdmin,,) = releaseRegistry.prepareNextRelease(authMock, salt); + + // deploy (register all(1) services) + IService service = _prepareServiceWithRegistryDomain(createdVersion, ReleaseAdmin(address(preparedAdmin))); + + vm.prank(gifManager); + releaseRegistry.registerService(service); + + // prepare with revert + authMock = new ServiceAuthorizationMockWithRegistryService(createdVersion); + salt = bytes32(randomNumber(type(uint256).max)); + + vm.expectRevert(abi.encodeWithSelector( + ILifecycle.ErrorFromStateMissmatch.selector, + address(releaseRegistry), + RELEASE(), + DEPLOYED(), + SCHEDULED() + )); + + vm.prank(gifManager); + releaseRegistry.prepareNextRelease(authMock, salt); + + vm.stopPrank(); + } + } + + function test_releaseRegistry_prepareRelease_whenReleaseActive() public + { + for(uint256 i = 0; i <= 2; i++) + { + // create - skip + vm.prank(gifAdmin); + VersionPart createdVersion = releaseRegistry.createNextRelease(); + + // prepare + IServiceAuthorization authMock = new ServiceAuthorizationMockWithRegistryService(createdVersion); + bytes32 salt = bytes32(randomNumber(type(uint256).max)); + + IAccessAdmin preparedAdmin; + vm.prank(gifManager); + (preparedAdmin,,) = releaseRegistry.prepareNextRelease(authMock, salt); + + // deploy (register all(1) services) + IService service = _prepareServiceWithRegistryDomain(createdVersion, ReleaseAdmin(address(preparedAdmin))); + + vm.prank(gifManager); + releaseRegistry.registerService(service); + + // activate + vm.prank(gifAdmin); + releaseRegistry.activateNextRelease(); + + // prepare with revert + authMock = new ServiceAuthorizationMockWithRegistryService(createdVersion); + salt = bytes32(randomNumber(type(uint256).max)); + + vm.expectRevert(abi.encodeWithSelector( + ILifecycle.ErrorFromStateMissmatch.selector, + address(releaseRegistry), + RELEASE(), + ACTIVE(), + SCHEDULED() + )); + vm.prank(gifManager); + releaseRegistry.prepareNextRelease(authMock, salt); + } + } + + function test_releaseRegistry_prepareRelease_whenReleasePaused() public + { + for(uint256 i = 0; i <= 2; i++) + { + // create - skip + vm.prank(gifAdmin); + VersionPart createdVersion = releaseRegistry.createNextRelease(); + + // prepare + IServiceAuthorization authMock = new ServiceAuthorizationMockWithRegistryService(createdVersion); + bytes32 salt = bytes32(randomNumber(type(uint256).max)); + + IAccessAdmin preparedAdmin; + vm.prank(gifManager); + (preparedAdmin,,) = releaseRegistry.prepareNextRelease(authMock, salt); + + // deploy (register all(1) services) + IService service = _prepareServiceWithRegistryDomain(createdVersion, ReleaseAdmin(address(preparedAdmin))); + + vm.prank(gifManager); + releaseRegistry.registerService(service); + + // activate + vm.prank(gifAdmin); + releaseRegistry.activateNextRelease(); + + // pause + vm.prank(gifAdmin); + releaseRegistry.setActive(createdVersion, false); + + // prepare with revert + authMock = new ServiceAuthorizationMockWithRegistryService(createdVersion); + salt = bytes32(randomNumber(type(uint256).max)); + + vm.expectRevert(abi.encodeWithSelector( + ILifecycle.ErrorFromStateMissmatch.selector, + address(releaseRegistry), + RELEASE(), + PAUSED(), + SCHEDULED() + )); + vm.prank(gifManager); + releaseRegistry.prepareNextRelease(authMock, salt); + } + } + + function test_releaseRegistry_prepareRelease_whenReleaseScheduled_withZeroServiceAuth() public + { + vm.prank(gifAdmin); + releaseRegistry.createNextRelease(); + + vm.expectRevert(); + vm.prank(gifManager); + releaseRegistry.prepareNextRelease(IServiceAuthorization(address(0)), "0x1234"); + } + + /* + // TODO need mocks with fallback function + function test_releaseRegistry_prepareRelease_whenReleaseScheduled_withServiceAuthWithoutIERC165() public + { + FallbackMock fallbackMock = new FallbackMock(); + FallbackMockWithReturn fallbackMockWithReturn = new FallbackMockWithReturn(); + Usdc usdc = new Usdc(); + + vm.prank(gifAdmin); + releaseRegistry.createNextRelease(); + + // EOA + vm.expectRevert(bytes("")); + vm.prank(gifManager); + releaseRegistry.prepareNextRelease(IServiceAuthorization(outsider), "0x1234"); + + // contract without IERC165 and fallback + vm.expectRevert(bytes("")); + vm.prank(gifManager); + releaseRegistry.prepareNextRelease(IServiceAuthorization(address(usdc)), "0x1234"); + + // contract without IERC165 but with fallback + vm.expectRevert(bytes("")); + vm.prank(gifManager); + releaseRegistry.prepareNextRelease(IServiceAuthorization(address(fallbackMock)), "0x1234"); + + // contract without IERC165 but with fallback with return (returns "1") + vm.expectRevert(bytes("")); + vm.prank(gifManager); + releaseRegistry.prepareNextRelease(IServiceAuthorization(address(fallbackMockWithReturn)), "0x1234"); + } + */ + function test_releaseRegistry_prepareRelease_whenReleaseScheduled_withServiceAuthWithIERC165() public + { + NftOwnableMock mock = new NftOwnableMock(); + + vm.prank(gifAdmin); + releaseRegistry.createNextRelease(); + + vm.expectRevert(abi.encodeWithSelector( + ReleaseRegistry.ErrorReleaseRegistryNotServiceAuth.selector, + (address(mock)) + )); + vm.prank(gifManager); + releaseRegistry.prepareNextRelease(IServiceAuthorization(address(mock)), "0x1234"); + } + + function test_releaseRegistry_prepareRelease_whenReleaseScheduled_withServiceAuthVersionTooSmall() public + { + uint8 createdReleases = uint8(randomNumber(2, 10)); + uint8 releaseVersion = GIF_INITIAL_RELEASE().toInt() + createdReleases; + + for(uint256 i = 0; i <= createdReleases; i++) { + vm.prank(gifAdmin); + releaseRegistry.createNextRelease(); + } + + for(uint8 i = 0; i < releaseVersion; i++) + { + VersionPart tooSmallVersion = VersionPartLib.toVersionPart(i); + ObjectType[] memory domains = new ObjectType[](1); + domains[0] = PRODUCT(); + + if (i < VersionPartLib.releaseMin().toInt()) { + vm.expectRevert(abi.encodeWithSelector( + IServiceAuthorization.ErrorAuthorizationReleaseInvalid.selector, + tooSmallVersion)); + } + + IServiceAuthorization authMock = new ServiceAuthorizationMock(tooSmallVersion, domains); + // revert in constructor results in contract address 0x0000000000000000000000000000000000000001 + if (address(authMock) <= address(1)) { + console.log("i", i, "address(authMock)", address(authMock)); + continue; + } + + vm.expectRevert(abi.encodeWithSelector( + ReleaseRegistry.ErrorReleaseRegistryServiceAuthVersionMismatch.selector, + authMock, + releaseVersion, + tooSmallVersion + )); + + vm.prank(gifManager); + releaseRegistry.prepareNextRelease(authMock, "0x1234"); + } + + // check prepareRelease() works for the releaseVersion + } + + function test_releaseRegistry_prepareRelease_whenReleaseScheduled_withServiceAuthVersionTooBig() public + { + uint8 createdReleases = uint8(randomNumber(1, 10)); + uint8 releaseVersion = GIF_INITIAL_RELEASE().toInt() + createdReleases; + + vm.startPrank(gifAdmin); + + for(uint256 i = 0; i <= createdReleases; i++) { + releaseRegistry.createNextRelease(); + } + + vm.stopPrank(); + vm.startPrank(gifManager); + + for(uint8 i = releaseVersion + 1; i < releaseVersion + 5; i++) + { + VersionPart tooBigVersion = VersionPartLib.toVersionPart(i); + ServiceAuthorizationMockWithRegistryService auth = new ServiceAuthorizationMockWithRegistryService(tooBigVersion); + vm.expectRevert(abi.encodeWithSelector( + ReleaseRegistry.ErrorReleaseRegistryServiceAuthVersionMismatch.selector, + auth, + releaseVersion, + tooBigVersion)); + releaseRegistry.prepareNextRelease(auth, "0x1234"); + } + + // check prepareRelease() works for the releaseVersion + + vm.stopPrank(); + } + + function test_releaseRegistry_prepareRelease_whenReleaseScheduled_withServiceAuthDomainCountZero() public + { + VersionPart version = VersionPartLib.toVersionPart(GIF_INITIAL_RELEASE().toInt()); + ObjectType[] memory domains = new ObjectType[](0); + ServiceAuthorizationMock serviceAuth = new ServiceAuthorizationMock(version, domains); + + vm.prank(gifAdmin); + releaseRegistry.createNextRelease(); + + vm.expectRevert(abi.encodeWithSelector( + ReleaseRegistry.ErrorReleaseRegistryServiceAuthDomainsZero.selector, + serviceAuth, + version + )); + vm.prank(gifManager); + releaseRegistry.prepareNextRelease(serviceAuth, "0x1234"); + } + + //------------------------ register service ------------------------// + + function test_releaseRegistry_registerService_byNotAuthorizedCaller() public + { + IService service; + vm.expectRevert(abi.encodeWithSelector(IAccessManaged.AccessManagedUnauthorized.selector, gifAdmin)); + vm.prank(gifAdmin); + releaseRegistry.registerService(service); + + vm.expectRevert(abi.encodeWithSelector(IAccessManaged.AccessManagedUnauthorized.selector, stakingOwner)); + vm.prank(stakingOwner); + releaseRegistry.registerService(service); + + vm.expectRevert(abi.encodeWithSelector(IAccessManaged.AccessManagedUnauthorized.selector, outsider)); + vm.prank(outsider); + releaseRegistry.registerService(service); + } + + function test_releaseRegistry_registerService_whenInitialReleaseNotCreated() public + { + vm.startPrank(gifManager); + ServiceMock serviceMock = new ServiceMock( + NftIdLib.zero(), + registryNftId, + false, // isInterceptor + gifManager, + address(0)); + + vm.expectRevert(abi.encodeWithSelector( + ILifecycle.ErrorFromStateMissmatch.selector, + address(releaseRegistry), + RELEASE(), + StateIdLib.zero(), + DEPLOYING() + )); + releaseRegistry.registerService(serviceMock); + + vm.stopPrank(); + } + + function test_releaseRegistry_registerService_whenReleaseScheduled() public + { + for(uint256 i = 0; i <= 2; i++) + { + // create - skip + vm.prank(gifAdmin); + VersionPart releaseVersion = releaseRegistry.createNextRelease(); + + ServiceMock serviceMock = new ServiceMock( + NftIdLib.zero(), + registryNftId, + false, // isInterceptor + gifManager, + address(0)); + + // register with revert + vm.expectRevert(abi.encodeWithSelector( + ILifecycle.ErrorFromStateMissmatch.selector, + address(releaseRegistry), + RELEASE(), + SCHEDULED(), + DEPLOYING() + )); + vm.prank(gifManager); + releaseRegistry.registerService(serviceMock); + } + } + + function test_releaseRegistry_registerService_whenReleaseDeployingHappyCase() public + { + // Equivalent to test_releaseRegistry_createRelease_whenReleaseDeployedHappyCase() + // create release + // prepare release + // register service + // loop + } + + function test_releaseRegistry_registerService_whenReleaseDeploying_registerLastServiceHappyCase() public + { + // the first registration + + // check DEPLOYING after the first registration + + // check second registration is ok + + // check DEPLOYING after second registration + + // check the last registration is ok + + // check DEPLOYED after the last registration + } + + function test_releaseRegistry_registerService_whenReleaseDeploying_withServiceVersionTooSmall() public + { + uint8 initialVersionInt = GIF_INITIAL_RELEASE().toInt(); + + VersionPart releaseVersion; + for(uint256 i = 0; i <= 2; i++) + { + // create - skip + vm.prank(gifAdmin); + releaseVersion = releaseRegistry.createNextRelease(); + } + + // prepare the last created + IServiceAuthorization nextAuthMock = new ServiceAuthorizationMockWithRegistryService(releaseVersion); + bytes32 nextSalt = bytes32(randomNumber(type(uint256).max)); + + vm.prank(gifManager); + (IAccessAdmin releaseAdmin,,) = releaseRegistry.prepareNextRelease(nextAuthMock, nextSalt); + + for(uint8 i = 0; i < 2; i++) + { + // register with revert + VersionPart serviceVersion = VersionPartLib.toVersionPart(initialVersionInt + i); + IService service = _prepareServiceWithRegistryDomain(serviceVersion, ReleaseAdmin(address(releaseAdmin))); + vm.expectRevert(abi.encodeWithSelector( + ReleaseRegistry.ErrorReleaseRegistryServiceInfoReleaseMismatch.selector, + service, + releaseVersion, + serviceVersion + )); + vm.prank(gifManager); + releaseRegistry.registerService(service); + } + } + + function test_releaseRegistry_registerService_whenReleaseDeploying_withServiceVersionTooBig() public + { + uint8 initialVersionInt = GIF_INITIAL_RELEASE().toInt(); + + // create initial + vm.prank(gifAdmin); + VersionPart releaseVersion = releaseRegistry.createNextRelease(); + + // prepare initial + IServiceAuthorization nextAuthMock = new ServiceAuthorizationMockWithRegistryService(releaseVersion); + bytes32 nextSalt = bytes32(randomNumber(type(uint256).max)); + + vm.prank(gifManager); + (IAccessAdmin releaseAdmin,,) = releaseRegistry.prepareNextRelease(nextAuthMock, nextSalt); + + for(uint8 i = 1; i <= 2; i++) + { + // register with revert + VersionPart serviceVersion = VersionPartLib.toVersionPart(initialVersionInt + i); + IService service = _prepareServiceWithRegistryDomain(serviceVersion, ReleaseAdmin(address(releaseAdmin))); + vm.expectRevert(abi.encodeWithSelector( + ReleaseRegistry.ErrorReleaseRegistryServiceInfoReleaseMismatch.selector, + service, + releaseVersion, + serviceVersion + )); + vm.prank(gifManager); + releaseRegistry.registerService(service); + } + } + + function test_releaseRegistry_registerService_whenReleaseDeploying_withServiceDomainMismatch() public + { + // create initial + vm.prank(gifAdmin); + VersionPart releaseVersion = releaseRegistry.createNextRelease(); + + // prepare initial + IServiceAuthorization nextAuthMock = new ServiceAuthorizationMockWithRegistryService(releaseVersion); + bytes32 nextSalt = bytes32(randomNumber(type(uint256).max)); + + vm.prank(gifManager); + (IAccessAdmin releaseAdmin,,) = releaseRegistry.prepareNextRelease(nextAuthMock, nextSalt); + + // register with revert + // service mock have PRODUCT domain + IService service = new ServiceMock( + NftIdLib.zero(), + registryNftId, + false, // isInterceptor + gifManager, + releaseAdmin.authority()); + + vm.expectRevert(abi.encodeWithSelector( + ReleaseRegistry.ErrorReleaseRegistryServiceDomainMismatch.selector, + service, + REGISTRY(), + PRODUCT() + )); + vm.prank(gifManager); + releaseRegistry.registerService(service); + } + + function test_releaseRegistry_registerService_whenReleaseDeployed() public + { + for(uint256 i = 0; i <= 2; i++) + { + // create - skip + vm.prank(gifAdmin); + VersionPart createdVersion = releaseRegistry.createNextRelease(); + + // prepare + IServiceAuthorization authMock = new ServiceAuthorizationMockWithRegistryService(createdVersion); + bytes32 salt = bytes32(randomNumber(type(uint256).max)); + IAccessAdmin preparedAdmin; + + vm.prank(gifManager); + (preparedAdmin,,) = releaseRegistry.prepareNextRelease(authMock, salt); + + // deploy (register all(1) services) + IService service = _prepareServiceWithRegistryDomain(createdVersion, ReleaseAdmin(address(preparedAdmin))); + + vm.prank(gifManager); + releaseRegistry.registerService(service); + + // register with revert + ServiceMock serviceMock = new ServiceMock( + NftIdLib.zero(), + registryNftId, + false, // isInterceptor + gifManager, + registryAdmin.authority()); + + vm.expectRevert(abi.encodeWithSelector( + ILifecycle.ErrorFromStateMissmatch.selector, + address(releaseRegistry), + RELEASE(), + DEPLOYED(), + DEPLOYING() + )); + vm.prank(gifManager); + releaseRegistry.registerService(serviceMock); + } + } + + function test_releaseRegistry_registerService_whenReleaseActive() public + { + for(uint256 i = 0; i <= 2; i++) + { + // create - skip + vm.prank(gifAdmin); + VersionPart createdVersion = releaseRegistry.createNextRelease(); + + // prepare + IServiceAuthorization authMock = new ServiceAuthorizationMockWithRegistryService(createdVersion); + bytes32 salt = bytes32(randomNumber(type(uint256).max)); + IAccessAdmin preparedAdmin; + + vm.prank(gifManager); + (preparedAdmin,,) = releaseRegistry.prepareNextRelease(authMock, salt); + + // deploy (register all(1) services) + IService service = _prepareServiceWithRegistryDomain(createdVersion, ReleaseAdmin(address(preparedAdmin))); + + vm.prank(gifManager); + releaseRegistry.registerService(service); + + // activate + vm.prank(gifAdmin); + releaseRegistry.activateNextRelease(); + + // register with revert + ServiceMock serviceMock = new ServiceMock( + NftIdLib.zero(), + registryNftId, + false, // isInterceptor + gifManager, + registryAdmin.authority()); + + vm.expectRevert(abi.encodeWithSelector( + ILifecycle.ErrorFromStateMissmatch.selector, + address(releaseRegistry), + RELEASE(), + ACTIVE(), + DEPLOYING() + )); + vm.prank(gifManager); + releaseRegistry.registerService(serviceMock); + } + } + + function test_releaseRegistry_registerService_whenReleasePaused() public + { + for(uint256 i = 0; i <= 2; i++) + { + // create - skip + vm.prank(gifAdmin); + VersionPart createdVersion = releaseRegistry.createNextRelease(); + + // prepare + IServiceAuthorization authMock = new ServiceAuthorizationMockWithRegistryService(createdVersion); + bytes32 salt = bytes32(randomNumber(type(uint256).max)); + IAccessAdmin preparedAdmin; + + vm.prank(gifManager); + (preparedAdmin,,) = releaseRegistry.prepareNextRelease(authMock, salt); + + // deploy (register all(1) services) + IService service = _prepareServiceWithRegistryDomain(createdVersion, ReleaseAdmin(address(preparedAdmin))); + + vm.prank(gifManager); + releaseRegistry.registerService(service); + + // activate + vm.prank(gifAdmin); + releaseRegistry.activateNextRelease(); + + // pause + vm.prank(gifAdmin); + releaseRegistry.setActive(createdVersion, false); + + // register with revert + ServiceMock serviceMock = new ServiceMock( + NftIdLib.zero(), + registryNftId, + false, // isInterceptor + gifManager, + registryAdmin.authority()); + + vm.expectRevert(abi.encodeWithSelector( + ILifecycle.ErrorFromStateMissmatch.selector, + address(releaseRegistry), + RELEASE(), + PAUSED(), + DEPLOYING() + )); + vm.prank(gifManager); + releaseRegistry.registerService(serviceMock); + } + } + + //------------------------ activate release ------------------------// + + function test_releaseRegistry_activateRelease_byNotAuthorizedCaller() public + { + vm.expectRevert(abi.encodeWithSelector(IAccessManaged.AccessManagedUnauthorized.selector, gifManager)); + vm.prank(gifManager); + releaseRegistry.activateNextRelease(); + + //vm.expectRevert(abi.encodeWithSelector(IAccessManaged.AccessManagedUnauthorized.selector, stakingOwner)); + //vm.prank(stakingOwner); + //releaseRegistry.activateNextRelease(); + + vm.expectRevert(abi.encodeWithSelector(IAccessManaged.AccessManagedUnauthorized.selector, outsider)); + vm.prank(outsider); + releaseRegistry.activateNextRelease(); + } + + function test_activateRelease_whenInitialReleaseNotCreated() public + { + vm.expectRevert(abi.encodeWithSelector( + ILifecycle.ErrorFromStateMissmatch.selector, + address(releaseRegistry), + RELEASE(), + StateIdLib.zero(), + DEPLOYED() + )); + vm.prank(gifAdmin); + releaseRegistry.activateNextRelease(); + + } + + function test_releaseRegistry_activateRelease_whenReleaseScheduled() public + { + for(uint256 i = 0; i <= 2; i++) + { + // create - skip + vm.prank(gifAdmin); + releaseRegistry.createNextRelease(); + + // activate with revert + vm.expectRevert(abi.encodeWithSelector( + ILifecycle.ErrorFromStateMissmatch.selector, + address(releaseRegistry), + RELEASE(), + SCHEDULED(), + DEPLOYED() + )); + vm.prank(gifAdmin); + releaseRegistry.activateNextRelease(); + } + } + function test_releaseRegistry_activateRelease_whenReleaseDeploying() public + { + for(uint256 i = 0; i <= 2; i++) + { + // create + vm.prank(gifAdmin); + VersionPart createdVersion = releaseRegistry.createNextRelease(); + + // prepare + ServiceAuthorizationMockWithRegistryService serviceAuth = new ServiceAuthorizationMockWithRegistryService(createdVersion); + bytes32 salt = bytes32(randomNumber(type(uint256).max)); + + vm.prank(gifManager); + releaseRegistry.prepareNextRelease(serviceAuth, salt); + + // activate with revert + vm.expectRevert(abi.encodeWithSelector( + ILifecycle.ErrorFromStateMissmatch.selector, + address(releaseRegistry), + RELEASE(), + DEPLOYING(), + DEPLOYED() + )); + vm.prank(gifAdmin); + releaseRegistry.activateNextRelease(); + } + } + + function test_releaseRegistry_activateRelease_whenReleaseDeployedHappyCase() public + { + // TODO ? + // Equivalent to test_releaseRegistry_createRelease_whenReleaseActiveHappyCase() + // create + // prepare + // register service + // activate + // loop + } + + function test_releaseRegistry_activateRelease_whenReleaseActive() public + { + for(uint256 i = 0; i <= 2; i++) + { + // create + vm.prank(gifAdmin); + VersionPart createdVersion = releaseRegistry.createNextRelease(); + + // prepare + IServiceAuthorization authMock = new ServiceAuthorizationMockWithRegistryService(createdVersion); + bytes32 salt = bytes32(randomNumber(type(uint256).max)); + IAccessAdmin preparedAdmin; + + vm.prank(gifManager); + (preparedAdmin,,) = releaseRegistry.prepareNextRelease(authMock, salt); + + // deploy (register all(1) services) + IService service = _prepareServiceWithRegistryDomain(createdVersion, ReleaseAdmin(address(preparedAdmin))); + + vm.prank(gifManager); + releaseRegistry.registerService(service); + + // activate + vm.prank(gifAdmin); + releaseRegistry.activateNextRelease(); + + // activate with revert + vm.expectRevert(abi.encodeWithSelector( + ILifecycle.ErrorFromStateMissmatch.selector, + address(releaseRegistry), + RELEASE(), + ACTIVE(), + DEPLOYED() + )); + vm.prank(gifAdmin); + releaseRegistry.activateNextRelease(); + } + } + + function test_releaseRegistry_activateRelease_whenReleasePaused() public + { + for(uint256 i = 0; i <= 2; i++) + { + // create + vm.prank(gifAdmin); + VersionPart createdVersion = releaseRegistry.createNextRelease(); + + // prepare + IServiceAuthorization authMock = new ServiceAuthorizationMockWithRegistryService(createdVersion); + bytes32 salt = bytes32(randomNumber(type(uint256).max)); + IAccessAdmin preparedAdmin; + + vm.prank(gifManager); + (preparedAdmin,,) = releaseRegistry.prepareNextRelease(authMock, salt); + + // deploy (register all(1) services) + IService service = _prepareServiceWithRegistryDomain(createdVersion, ReleaseAdmin(address(preparedAdmin))); + + vm.prank(gifManager); + releaseRegistry.registerService(service); + + // activate + vm.prank(gifAdmin); + releaseRegistry.activateNextRelease(); + + // pause + vm.prank(gifAdmin); + releaseRegistry.setActive(createdVersion, false); + + // activate with revert + vm.expectRevert(abi.encodeWithSelector( + ILifecycle.ErrorFromStateMissmatch.selector, + address(releaseRegistry), + RELEASE(), + PAUSED(), + DEPLOYED() + )); + vm.prank(gifAdmin); + releaseRegistry.activateNextRelease(); + } + } + + //------------------------ pauseRelease ------------------------// + function test_releaseRegistry_pauseRelease_byNotAuthorizedCaller() public + { + VersionPart version; + + vm.expectRevert(abi.encodeWithSelector(IAccessManaged.AccessManagedUnauthorized.selector, gifManager)); + vm.prank(gifManager); + releaseRegistry.setActive(version, false); + + vm.expectRevert(abi.encodeWithSelector(IAccessManaged.AccessManagedUnauthorized.selector, stakingOwner)); + vm.prank(stakingOwner); + releaseRegistry.setActive(version, false); + + vm.expectRevert(abi.encodeWithSelector(IAccessManaged.AccessManagedUnauthorized.selector, outsider)); + vm.prank(outsider); + releaseRegistry.setActive(version, false); + } + + function test_pauseRelease_whenInitialReleaseNotCreated() public + { + // loop through first n versions + for(uint8 i = 0; i < 5; i++) + { + VersionPart version = VersionPartLib.toVersionPart(i); + vm.expectRevert(abi.encodeWithSelector( + ILifecycle.ErrorFromStateMissmatch.selector, + address(releaseRegistry), + RELEASE(), + StateIdLib.zero(), + ACTIVE() + )); + vm.prank(gifAdmin); + releaseRegistry.setActive(version, false); + } + } + + function test_releaseRegistry_pauseRelease_whenReleaseScheduled() public + { + for(uint256 i = 0; i <= 2; i++) + { + // create - skip + vm.prank(gifAdmin); + VersionPart createdVersion = releaseRegistry.createNextRelease(); + + // pause with revert + vm.expectRevert(abi.encodeWithSelector( + ILifecycle.ErrorFromStateMissmatch.selector, + address(releaseRegistry), + RELEASE(), + SCHEDULED(), + ACTIVE() + )); + vm.prank(gifAdmin); + releaseRegistry.setActive(createdVersion, false); + } + } + + function test_releaseRegistry_pauseRelease_whenReleaseDeploying() public + { + for(uint256 i = 0; i <= 2; i++) + { + // create + vm.prank(gifAdmin); + VersionPart createdVersion = releaseRegistry.createNextRelease(); + + // prepare + ServiceAuthorizationMockWithRegistryService serviceAuth = new ServiceAuthorizationMockWithRegistryService(createdVersion); + bytes32 salt = bytes32(randomNumber(type(uint256).max)); + + vm.prank(gifManager); + releaseRegistry.prepareNextRelease(serviceAuth, salt); + + // pause with revert + vm.expectRevert(abi.encodeWithSelector( + ILifecycle.ErrorFromStateMissmatch.selector, + address(releaseRegistry), + RELEASE(), + DEPLOYING(), + ACTIVE() + )); + vm.prank(gifAdmin); + releaseRegistry.setActive(createdVersion, false); + } + } + + function test_releaseRegistry_pauseRelease_whenReleaseDeployed() public + { + for(uint256 i = 0; i <= 2; i++) + { + // create + vm.prank(gifAdmin); + VersionPart createdVersion = releaseRegistry.createNextRelease(); + + // prepare + IServiceAuthorization authMock = new ServiceAuthorizationMockWithRegistryService(createdVersion); + bytes32 salt = bytes32(randomNumber(type(uint256).max)); + IAccessAdmin preparedAdmin; + + vm.prank(gifManager); + (preparedAdmin,,) = releaseRegistry.prepareNextRelease(authMock, salt); + + // deploy (register all(1) services) + IService service = _prepareServiceWithRegistryDomain(createdVersion, ReleaseAdmin(address(preparedAdmin))); + + vm.prank(gifManager); + releaseRegistry.registerService(service); + + // pause with revert + vm.expectRevert(abi.encodeWithSelector( + ILifecycle.ErrorFromStateMissmatch.selector, + address(releaseRegistry), + RELEASE(), + DEPLOYED(), + ACTIVE() + )); + vm.prank(gifAdmin); + releaseRegistry.setActive(createdVersion, false); + } + } + + function test_releaseRegistry_pauseRelease_whenReleaseActiveHappyCase() public + { + // Equivalent to test_releaseRegistry_createRelease_whenReleasePausedHappyCase() + // create + // prepare + // register service + // activate + // pause + // loop + } + + function test_releaseRegistry_pauseRelease_whenReleasePaused() public + { + for(uint256 i = 0; i <= 2; i++) + { + // create + vm.prank(gifAdmin); + VersionPart createdVersion = releaseRegistry.createNextRelease(); + + // prepare + IServiceAuthorization authMock = new ServiceAuthorizationMockWithRegistryService(createdVersion); + bytes32 salt = bytes32(randomNumber(type(uint256).max)); + IAccessAdmin preparedAdmin; + + vm.prank(gifManager); + (preparedAdmin,,) = releaseRegistry.prepareNextRelease(authMock, salt); + + // deploy (register all(1) services) + IService service = _prepareServiceWithRegistryDomain(createdVersion, ReleaseAdmin(address(preparedAdmin))); + + vm.prank(gifManager); + releaseRegistry.registerService(service); + + // activate + vm.prank(gifAdmin); + releaseRegistry.activateNextRelease(); + + // pause + vm.prank(gifAdmin); + releaseRegistry.setActive(createdVersion, false); + + // pause with revert + vm.expectRevert(abi.encodeWithSelector( + ILifecycle.ErrorFromStateMissmatch.selector, + address(releaseRegistry), + RELEASE(), + PAUSED(), + ACTIVE() + )); + vm.prank(gifAdmin); + releaseRegistry.setActive(createdVersion, false); + } + } + + // ------------------------ unpauseRelease ----------------------------// + + function test_releaseRegistry_unpauseRelease_byNotAuthorizedCaller() public + { + VersionPart version; + + vm.expectRevert(abi.encodeWithSelector(IAccessManaged.AccessManagedUnauthorized.selector, gifManager)); + vm.prank(gifManager); + releaseRegistry.setActive(version, true); + + vm.expectRevert(abi.encodeWithSelector(IAccessManaged.AccessManagedUnauthorized.selector, stakingOwner)); + vm.prank(stakingOwner); + releaseRegistry.setActive(version, true); + + vm.expectRevert(abi.encodeWithSelector(IAccessManaged.AccessManagedUnauthorized.selector, outsider)); + vm.prank(outsider); + releaseRegistry.setActive(version, true); + } + + function test_unpauseRelease_whenInitialReleaseNotCreated() public + { + // loop through first n versions + for(uint8 i = 0; i < 5; i++) + { + VersionPart version = VersionPartLib.toVersionPart(i); + vm.expectRevert(abi.encodeWithSelector( + ILifecycle.ErrorFromStateMissmatch.selector, + address(releaseRegistry), + RELEASE(), + StateIdLib.zero(), + PAUSED() + )); + vm.prank(gifAdmin); + releaseRegistry.setActive(version, true); + } + } + + function test_releaseRegistry_unpauseRelease_whenReleaseScheduled() public + { + for(uint256 i = 0; i <= 2; i++) + { + // create - skip + vm.prank(gifAdmin); + VersionPart createdVersion = releaseRegistry.createNextRelease(); + + // unpause with revert + vm.expectRevert(abi.encodeWithSelector( + ILifecycle.ErrorFromStateMissmatch.selector, + address(releaseRegistry), + RELEASE(), + SCHEDULED(), + PAUSED() + )); + vm.prank(gifAdmin); + releaseRegistry.setActive(createdVersion, true); + } + } + + function test_releaseRegistry_unpauseRelease_whenReleaseDeploying() public + { + for(uint256 i = 0; i <= 2; i++) + { + // create + vm.prank(gifAdmin); + VersionPart createdVersion = releaseRegistry.createNextRelease(); + + // prepare + ServiceAuthorizationMockWithRegistryService serviceAuth = new ServiceAuthorizationMockWithRegistryService(createdVersion); + bytes32 salt = bytes32(randomNumber(type(uint256).max)); + + vm.prank(gifManager); + releaseRegistry.prepareNextRelease(serviceAuth, salt); + + // unpause with revert + vm.expectRevert(abi.encodeWithSelector( + ILifecycle.ErrorFromStateMissmatch.selector, + address(releaseRegistry), + RELEASE(), + DEPLOYING(), + PAUSED() + )); + vm.prank(gifAdmin); + releaseRegistry.setActive(createdVersion, true); + } + } + + function test_releaseRegistry_unpauseRelease_whenReleaseDeployed() public + { + for(uint256 i = 0; i <= 2; i++) + { + // create + vm.prank(gifAdmin); + VersionPart createdVersion = releaseRegistry.createNextRelease(); + + // prepare + IServiceAuthorization authMock = new ServiceAuthorizationMockWithRegistryService(createdVersion); + bytes32 salt = bytes32(randomNumber(type(uint256).max)); + IAccessAdmin preparedAdmin; + + vm.prank(gifManager); + (preparedAdmin,,) = releaseRegistry.prepareNextRelease(authMock, salt); + + // deploy (register all(1) services) + IService service = _prepareServiceWithRegistryDomain(createdVersion, ReleaseAdmin(address(preparedAdmin))); + + vm.prank(gifManager); + releaseRegistry.registerService(service); + + // unpause with revert + vm.expectRevert(abi.encodeWithSelector( + ILifecycle.ErrorFromStateMissmatch.selector, + address(releaseRegistry), + RELEASE(), + DEPLOYED(), + PAUSED() + )); + vm.prank(gifAdmin); + releaseRegistry.setActive(createdVersion, true); + } + } + + function test_releaseRegistry_unpauseRelease_whenReleaseActive() public + { + for(uint256 i = 0; i <= 2; i++) + { + // create + vm.prank(gifAdmin); + VersionPart createdVersion = releaseRegistry.createNextRelease(); + + // prepare + IServiceAuthorization authMock = new ServiceAuthorizationMockWithRegistryService(createdVersion); + bytes32 salt = bytes32(randomNumber(type(uint256).max)); + IAccessAdmin preparedAdmin; + + vm.prank(gifManager); + (preparedAdmin,,) = releaseRegistry.prepareNextRelease(authMock, salt); + + // deploy (register all(1) services) + IService service = _prepareServiceWithRegistryDomain(createdVersion, ReleaseAdmin(address(preparedAdmin))); + + vm.prank(gifManager); + releaseRegistry.registerService(service); + + // activate + vm.prank(gifAdmin); + releaseRegistry.activateNextRelease(); + + // unpause with revert + vm.expectRevert(abi.encodeWithSelector( + ILifecycle.ErrorFromStateMissmatch.selector, + address(releaseRegistry), + RELEASE(), + ACTIVE(), + PAUSED() + )); + vm.prank(gifAdmin); + releaseRegistry.setActive(createdVersion, true); + } + } + + function _getNextContractAddress(address deployer, uint256 nonceOffset) internal returns (address) { + return vm.computeCreateAddress( + deployer, + vm.getNonce(deployer) + nonceOffset); + } + + function _prepareServiceWithRegistryDomain(VersionPart releaseVersion, ReleaseAdmin releaseAdmin) + public + returns (IService service) + { + if(releaseVersion.toInt() == 3) { + service = new ServiceMockWithRegistryDomainV3( + NftIdLib.zero(), + registryNftId, + false, // isInterceptor + gifManager, + releaseAdmin.authority()); + } else if(releaseVersion.toInt() == 4) { + service = new ServiceMockWithRegistryDomainV4( + NftIdLib.zero(), + registryNftId, + false, // isInterceptor + gifManager, + releaseAdmin.authority()); + } else if(releaseVersion.toInt() == 5) { + service = new ServiceMockWithRegistryDomainV5( + NftIdLib.zero(), + registryNftId, + false, // isInterceptor + gifManager, + releaseAdmin.authority()); + } + } + + function _checkReleaseInfo(IRelease.ReleaseInfo memory info) public view + { + if(info.state == SCHEDULED()) { + assertTrue(info.version.toInt() >= 3, "Test error: unexpected version #1"); + assertTrue(info.salt == bytes32(0), "Test error: unexpected salt #1"); + assertTrue(address(info.auth) == address(0), "Test error: unexpected auth #1"); + assertTrue(info.activatedAt.eqz(), "Test error: unexpected activatedAt #1"); + assertTrue(info.disabledAt.eqz(), "Test error: unexpected disabledAt #1"); + } else if (info.state == DEPLOYING() || info.state == DEPLOYED()) { + assertTrue(info.version.toInt() >= 3, "Test error: unexpected version #2"); + assertTrue(info.salt != bytes32(0), "Test error: unexpected salt #2"); + assertTrue(address(info.auth) != address(0), "Test error: unexpected auth #2"); + assertTrue(info.auth.getRelease() == info.version, "Test error: unexpected auth version #1"); + assertTrue(info.auth.getServiceDomains().length > 0, "Test error: unexpected auth domain num #1"); + assertTrue(info.activatedAt.eqz(), "Test error: unexpected activatedAt #2"); + assertTrue(info.disabledAt.eqz(), "Test error: unexpected disabledAt #2"); + } else if (info.state == ACTIVE()) { + assertTrue(info.version.toInt() >= 3, "Test error: unexpected version #3"); + assertTrue(info.salt != bytes32(0), "Test error: unexpected salt #3"); + assertTrue(address(info.auth) != address(0), "Test error: unexpected auth #3"); + assertTrue(info.auth.getRelease() == info.version, "Test error: unexpected auth version #2"); + assertTrue(info.auth.getServiceDomains().length > 0, "Test error: unexpected auth domain num #2"); + assertTrue(gteTimestamp(TimestampLib.current(), info.activatedAt), "Test error: unexpected activatedAt #3"); + assertTrue(info.disabledAt == TimestampLib.max(), "Test error: unexpected disabledAt #3"); + } else if (info.state == PAUSED()) { + assertTrue(info.version.toInt() >= 3, "Test error: unexpected version #4"); + assertTrue(info.salt != bytes32(0), "Test error: unexpected salt #4"); + assertTrue(address(info.auth) != address(0), "Test error: unexpected auth #4"); + assertTrue(info.auth.getRelease() == info.version, "Test error: unexpected auth version #3"); + assertTrue(info.auth.getServiceDomains().length > 0, "Test error: unexpected auth domain num #3"); + assertTrue(gteTimestamp(TimestampLib.current(), info.activatedAt), "Test error: unexpected activatedAt #4"); + assertTrue(gteTimestamp(TimestampLib.current(), info.disabledAt), "Test error: unexpected disabledAt #4"); + assertTrue(gteTimestamp(info.disabledAt, info.activatedAt), "Test error: disabledAt < activatedAt #4"); + } else if (info.state == SKIPPED()) { + assertTrue(info.version.toInt() >= 3, "Test error: unexpected version #5"); + // salt can have any values + if(address(info.auth) != address(0)) { + assertTrue(info.auth.getRelease() == info.version, "Test error: unexpected auth version #4"); + assertTrue(info.auth.getServiceDomains().length > 0, "Test error: unexpected auth domain num #4"); + } + assertTrue(info.activatedAt.eqz(), "Test error: unexpected activatedAt #5"); + assertTrue(info.disabledAt.eqz(), "Test error: unexpected disabledAt #5"); + } else if (info.state == StateIdLib.zero()) { + assertTrue(info.version.toInt() == 0, "Test error: unexpected version #6"); + assertTrue(info.salt == bytes32(0), "Test error: unexpected salt #6"); + assertTrue(address(info.auth) == address(0), "Test error: unexpected auth #6"); + assertTrue(info.activatedAt.eqz(), "Test error: unexpected activatedAt #6"); + assertTrue(info.disabledAt.eqz(), "Test error: unexpected disabledAt #6"); + } else { + // solhint-disable-next-line + console.log("Unexpected state ", info.state.toInt()); + assertTrue(false, "Test error: unexpected state"); + } + } +} diff --git a/test/release/ReleaseRegistryFuzz.t.sol b/test/release/ReleaseRegistryFuzz.t.sol new file mode 100644 index 000000000..f14cf1d12 --- /dev/null +++ b/test/release/ReleaseRegistryFuzz.t.sol @@ -0,0 +1,223 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.20; + +import {FoundryRandom} from "foundry-random/FoundryRandom.sol"; +import {console} from "../../lib/forge-std/src/Test.sol"; + +import {IRegistry} from "../../contracts/registry/IRegistry.sol"; +import {IRelease} from "../../contracts/registry/IRelease.sol"; +import {IService} from "../../contracts/shared/IService.sol"; + +import {ChainNft} from "../../contracts/registry/ChainNft.sol"; +import {GifDeployer} from "../base/GifDeployer.sol"; +import {NftIdLib} from "../../contracts/type/NftId.sol"; +import {ObjectType, SERVICE} from "../../contracts/type/ObjectType.sol"; +import {ReleaseRegistry} from "../../contracts/registry/ReleaseRegistry.sol"; +import {GIF_INITIAL_RELEASE} from "../../contracts/registry/Registry.sol"; +import {ServiceMockWithRegistryDomainV3, ServiceMockWithRegistryDomainV4, ServiceMockWithRegistryDomainV5} from "../mock/ServiceMock.sol"; +import {StateIdLib, SCHEDULED, DEPLOYING, DEPLOYED, SKIPPED, ACTIVE, PAUSED} from "../../contracts/type/StateId.sol"; +import {TimestampLib, gteTimestamp} from "../../contracts/type/Timestamp.sol"; +import {VersionPart, VersionPartLib} from "../../contracts/type/Version.sol"; + + +contract ReleaseRegistryTest is GifDeployer, FoundryRandom { + + // keep identical to ReleaseRegistry events + event LogReleaseCreation(VersionPart version, bytes32 salt); + event LogReleaseActivation(VersionPart version); + event LogReleaseDisabled(VersionPart version); + event LogReleaseEnabled(VersionPart version); + + address public outsider = makeAddr("outsider"); + mapping(VersionPart version => IService) public serviceByVersion; + + + function setUp() public virtual + { + ( + ,//dip, + registry, + ,//tokenRegistry, + releaseRegistry, + registryAdmin, + //stakingManager, + ,//staking + ) = deployCore(); + + chainNft = ChainNft(registry.getChainNftAddress()); + registryNftId = registry.getNftId(); + + vm.startPrank(gifManager); + + serviceByVersion[VersionPartLib.toVersionPart(3)] = new ServiceMockWithRegistryDomainV3( + NftIdLib.zero(), + registryNftId, + false, // isInterceptor + gifManager, + registryAdmin.authority()); + serviceByVersion[VersionPartLib.toVersionPart(4)] = new ServiceMockWithRegistryDomainV4( + NftIdLib.zero(), + registryNftId, + false, // isInterceptor + gifManager, + registryAdmin.authority()); + serviceByVersion[VersionPartLib.toVersionPart(5)] = new ServiceMockWithRegistryDomainV5( + NftIdLib.zero(), + registryNftId, + false, // isInterceptor + gifManager, + registryAdmin.authority()); + + vm.stopPrank(); + } + + function _getAndVerifyServiceInfoChecks(IService service, address expectedOwner, VersionPart expectedVersion) + public + view + returns(bool expectRevert, bytes memory revertMsg) + { + IRegistry.ObjectInfo memory info; + address owner; + info = service.getInitialInfo(); + owner = service.getOwner(); + + if(info.objectAddress != address(service)) { + revertMsg = abi.encodeWithSelector( + ReleaseRegistry.ErrorReleaseRegistryServiceInfoAddressInvalid.selector, + service, + info.objectAddress + ); + expectRevert = true; + } else if(info.isInterceptor != false) { // service is never interceptor + revertMsg = abi.encodeWithSelector( + ReleaseRegistry.ErrorReleaseRegistryServiceInfoInterceptorInvalid.selector, + service, + info.isInterceptor + ); + expectRevert = true; + } else if(info.objectType != SERVICE()) { + revertMsg = abi.encodeWithSelector( + ReleaseRegistry.ErrorReleaseRegistryServiceInfoTypeInvalid.selector, + service, + SERVICE(), + info.objectType + ); + expectRevert = true; + } else if(info.release != expectedVersion) { + revertMsg = abi.encode( + ReleaseRegistry.ErrorReleaseRegistryServiceInfoReleaseMismatch.selector, + service, + expectedVersion, + info.release); + expectRevert = true; + } else if(owner != expectedOwner) { // registerable owner protection + revertMsg = abi.encodeWithSelector( + ReleaseRegistry.ErrorReleaseRegistryServiceInfoOwnerInvalid.selector, + service, + expectedOwner, + owner + ); + expectRevert = true; + } else if(owner == address(service)) { + revertMsg = abi.encodeWithSelector( + ReleaseRegistry.ErrorReleaseRegistryServiceSelfRegistration.selector, + service + ); + expectRevert = true; + } else if(registry.isRegistered(owner)) { + revertMsg = abi.encodeWithSelector( + ReleaseRegistry.ErrorReleaseRegistryServiceOwnerRegistered.selector, + service, + owner + ); + expectRevert = true; + } + } + function _checkReleaseInfo(IRelease.ReleaseInfo memory info) public view + { + if(info.state == SCHEDULED()) { + assertTrue(info.version.toInt() >= 3, "Test error: unexpected version #1"); + assertTrue(info.salt == bytes32(0), "Test error: unexpected salt #1"); + assertTrue(address(info.auth) == address(0), "Test error: unexpected auth #1"); + assertTrue(info.activatedAt.eqz(), "Test error: unexpected activatedAt #1"); + assertTrue(info.disabledAt.eqz(), "Test error: unexpected disabledAt #1"); + } else if (info.state == DEPLOYING() || info.state == DEPLOYED()) { + assertTrue(info.version.toInt() >= 3, "Test error: unexpected version #2"); + assertTrue(info.salt != bytes32(0), "Test error: unexpected salt #2"); + assertTrue(address(info.auth) != address(0), "Test error: unexpected auth #2"); + assertTrue(info.auth.getRelease() == info.version, "Test error: unexpected auth version #1"); + assertTrue(info.auth.getServiceDomains().length > 0, "Test error: unexpected auth domain num #1"); + assertTrue(info.activatedAt.eqz(), "Test error: unexpected activatedAt #2"); + assertTrue(info.disabledAt.eqz(), "Test error: unexpected disabledAt #2"); + } else if (info.state == ACTIVE()) { + assertTrue(info.version.toInt() >= 3, "Test error: unexpected version #3"); + assertTrue(info.salt != bytes32(0), "Test error: unexpected salt #3"); + assertTrue(address(info.auth) != address(0), "Test error: unexpected auth #3"); + assertTrue(info.auth.getRelease() == info.version, "Test error: unexpected auth version #2"); + assertTrue(info.auth.getServiceDomains().length > 0, "Test error: unexpected auth domain num #2"); + assertTrue(gteTimestamp(TimestampLib.current(), info.activatedAt), "Test error: unexpected activatedAt #3"); + assertTrue(info.disabledAt.eqz(), "Test error: unexpected disabledAt #3"); + } else if (info.state == PAUSED()) { + assertTrue(info.version.toInt() >= 3, "Test error: unexpected version #4"); + assertTrue(info.salt != bytes32(0), "Test error: unexpected salt #4"); + assertTrue(address(info.auth) != address(0), "Test error: unexpected auth #4"); + assertTrue(info.auth.getRelease() == info.version, "Test error: unexpected auth version #3"); + assertTrue(info.auth.getServiceDomains().length > 0, "Test error: unexpected auth domain num #3"); + assertTrue(gteTimestamp(TimestampLib.current(), info.activatedAt), "Test error: unexpected activatedAt #4"); + assertTrue(gteTimestamp(TimestampLib.current(), info.disabledAt), "Test error: unexpected disabledAt #4"); + assertTrue(gteTimestamp(info.disabledAt, info.activatedAt), "Test error: disabledAt < activatedAt #4"); + } else if (info.state == SKIPPED()) { + assertTrue(info.version.toInt() >= 3, "Test error: unexpected version #5"); + // salt can have any values + if(address(info.auth) != address(0)) { + assertTrue(info.auth.getRelease() == info.version, "Test error: unexpected auth version #4"); + assertTrue(info.auth.getServiceDomains().length > 0, "Test error: unexpected auth domain num #4"); + } + assertTrue(info.activatedAt.eqz(), "Test error: unexpected activatedAt #5"); + assertTrue(info.disabledAt.eqz(), "Test error: unexpected disabledAt #5"); + } else if (info.state == StateIdLib.zero()) { + assertTrue(info.version.toInt() == 0, "Test error: unexpected version #6"); + assertTrue(info.salt == bytes32(0), "Test error: unexpected salt #6"); + assertTrue(address(info.auth) == address(0), "Test error: unexpected auth #6"); + assertTrue(info.activatedAt.eqz(), "Test error: unexpected activatedAt #6"); + assertTrue(info.disabledAt.eqz(), "Test error: unexpected disabledAt #6"); + } else { + // solhint-disable next-line + console.log("Unexpected state ", info.state.toInt()); + assertTrue(false, "Test error: unexpected state"); + } + } + + // assert by version getters + function _assert_releaseRegistry_getters(VersionPart version, IRelease.ReleaseInfo memory info) public view + { + _checkReleaseInfo(info); + + assertEq(releaseRegistry.isActiveRelease(version), (info.activatedAt.gtz() && info.disabledAt.eqz()), "isActiveRelease() return unxpected value"); + assertTrue(eqReleaseInfo(releaseRegistry.getReleaseInfo(version), info), "getReleaseInfo() return unxpected value"); + assertEq(releaseRegistry.getState(version).toInt(), info.state.toInt(), "getState() return unexpected value #1"); + assertEq(address(releaseRegistry.getServiceAuthorization(version)), address(info.auth), "getServiceAuthorization() return unexpected value #1"); + } + + function test_releaseRegistry_setUp() public view + { + for(uint8 i = 0; i <= GIF_INITIAL_RELEASE().toInt() + 1; i++) { + _assert_releaseRegistry_getters(VersionPartLib.toVersionPart(i), zeroReleaseInfo()); + } + + assertEq(releaseRegistry.releases(), 0, "releases() return unexpected value"); + assertEq(releaseRegistry.getNextVersion().toInt(), GIF_INITIAL_RELEASE().toInt() - 1, "getNextVersion() return unexpected value"); + assertEq(releaseRegistry.getLatestVersion().toInt(), 0, "getLatestVersion() return unexpected value"); + + assertEq(releaseRegistry.getRemainingServicesToRegister(), 0, "getRemainingServicesToRegister() return unexpected value"); + + assertEq(releaseRegistry.getRegistryAdmin(), address(registryAdmin), "getRegistryAdmin() return unexpected value"); + assertEq(address(releaseRegistry.getRegistry()), address(registry), "getRegistry() return unexpected value"); + } + + + function testFuzz_releaseRegistry_prepareRelease_verifyServiceInfo() public + { + // create harness + } +} diff --git a/test/release/component/ReleaseProduct.t.sol b/test/release/component/ReleaseProduct.t.sol index 3a4b0598d..7ffe9d420 100644 --- a/test/release/component/ReleaseProduct.t.sol +++ b/test/release/component/ReleaseProduct.t.sol @@ -58,7 +58,7 @@ contract ReleaseProductTest is GifTest { policyNftId = _createPolicy(false); // transfer and approve funds - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(customer, CUSTOMER_FUNDS); vm.stopPrank(); vm.startPrank(customer); @@ -73,7 +73,7 @@ contract ReleaseProductTest is GifTest { assertTrue(riskId.gtz(), "new risk id zero"); // WHEN release is locked - vm.startPrank(registryOwner); + vm.startPrank(gifAdmin); releaseRegistry.setActive(RELEASE_3, false); vm.stopPrank(); @@ -99,7 +99,7 @@ contract ReleaseProductTest is GifTest { assertTrue(applNftId.gtz(), "application nft id zero"); // WHEN release is locked - vm.startPrank(registryOwner); + vm.startPrank(gifAdmin); releaseRegistry.setActive(RELEASE_3, false); vm.stopPrank(); @@ -127,7 +127,7 @@ contract ReleaseProductTest is GifTest { assertEq(instanceReader.getPolicyState(applNftId2).toInt(), APPLIED().toInt(), "2 not applied"); // WHEN release is locked - vm.startPrank(registryOwner); + vm.startPrank(gifAdmin); releaseRegistry.setActive(RELEASE_3, false); vm.stopPrank(); @@ -164,7 +164,7 @@ contract ReleaseProductTest is GifTest { assertEq(instanceReader.getPolicyInfo(plcylNftId2).claimsCount, 0, "0 claims expected (2)"); // WHEN release is locked - vm.startPrank(registryOwner); + vm.startPrank(gifAdmin); releaseRegistry.setActive(RELEASE_3, false); vm.stopPrank(); diff --git a/test/shared/NftOwnable.t.sol b/test/shared/NftOwnable.t.sol index 525fbb495..9a557762a 100644 --- a/test/shared/NftOwnable.t.sol +++ b/test/shared/NftOwnable.t.sol @@ -30,7 +30,7 @@ contract NftOwnableTest is GifTest { super.setUp(); vm.startPrank(mockOwner); - mock = new NftOwnableMock(address(registry)); + mock = new NftOwnableMock(); mockUninitialized = new NftOwnableMockUninitialized(); vm.stopPrank(); } @@ -38,7 +38,7 @@ contract NftOwnableTest is GifTest { function test_nftOwnableMockSimple() public { // solhint-disable no-console - console.log("registryOwner", registryOwner); + console.log("gif admin", gifAdmin); console.log("registry address", address(registry)); console.log("registry nft id", registry.getNftIdForAddress(address(registry)).toInt()); console.log("registry owner", registry.ownerOf(address(registry))); @@ -49,7 +49,7 @@ contract NftOwnableTest is GifTest { console.log("mock owner", mock.getOwner()); // solhint-enable - assertTrue(registryOwner != mockOwner, "registry and mock owner the same"); + assertTrue(gifAdmin != mockOwner, "registry and mock owner the same"); assertEq(mock.getOwner(), mockOwner, "unexpected initial mock owner"); } @@ -74,7 +74,7 @@ contract NftOwnableTest is GifTest { } function test_nftOwnableLinkToRegNftIdWithUnregisteredContract() public { - mockUninitialized.initialize(address(registry), mockOwner); + mockUninitialized.initialize(mockOwner); vm.expectRevert( abi.encodeWithSelector( @@ -88,7 +88,6 @@ contract NftOwnableTest is GifTest { function test_nftOwnableInitializeTwice() public { address fakeOwner = makeAddr("fakeOwner"); - address fakeRegistry = makeAddr("fakeRegistry"); // attempt to reinitialize with new initial owner and registry // initializeNftOwnable is not an initializer (and can only be called in the context of an initializer) @@ -96,39 +95,43 @@ contract NftOwnableTest is GifTest { abi.encodeWithSelector( Initializable.InvalidInitialization.selector)); - mock.initializeNftOwnable(fakeRegistry, fakeOwner); + mock.initializeNftOwnable(fakeOwner); } - function test_nftOwnableInitializeNftOwnableInitializeWithZeroRegistry() public { + /*function test_nftOwnableInitializeNftOwnableInitializeWithZeroRegistry() public { // attempt to initialize with zero registry address vm.expectRevert( abi.encodeWithSelector( - IRegistryLinked.ErrorNotRegistry.selector, + IRegistryLinked.ErrorRegistryLinkedNotRegistry.selector, + address(mockUninitialized), address(0))); mockUninitialized.initialize(address(0), mockOwner); - } + }*/ - function test_nftOwnableInitializeNftOwnableInitializeWithNonContract() public { + /*function test_nftOwnableInitializeNftOwnableInitializeWithNonContract() public { + VersionPart release = VersionPartLib.toVersionPart(5); // attempt to initialize with non-registry vm.expectRevert( abi.encodeWithSelector( - IRegistryLinked.ErrorNotRegistry.selector, + IRegistryLinked.ErrorRegistryLinkedNotRegistry.selector, + address(mockUninitialized), address(1))); mockUninitialized.initialize(address(1), mockOwner); - } + }*/ - function test_nftOwnableInitializeNftOwnableInitializeWithNonRegistry() public { + /*function test_nftOwnableInitializeNftOwnableInitializeWithNonRegistry() public { Dip dip = new Dip(); address fakeRegistryAddress = address(dip); // attempt to initialize with non-registry vm.expectRevert( abi.encodeWithSelector( - IRegistryLinked.ErrorNotRegistry.selector, + IRegistryLinked.ErrorRegistryLinkedNotRegistry.selector, + address(mockUninitialized), fakeRegistryAddress)); mockUninitialized.initialize(fakeRegistryAddress, mockOwner); - } + }*/ //--- linkToNftOwnable(address registryAddress, address nftOwnableAddress) tests @@ -167,7 +170,7 @@ contract NftOwnableTest is GifTest { INftOwnable.ErrorNftOwnableAlreadyLinked.selector, mockNftId)); - vm.prank(registryOwner); + vm.prank(mockOwner); mock.linkToNftOwnable(address(registryService)); } } \ No newline at end of file diff --git a/test/shared/TokenHandler.t.sol b/test/shared/TokenHandler.t.sol index 751d370e7..e6d55b850 100644 --- a/test/shared/TokenHandler.t.sol +++ b/test/shared/TokenHandler.t.sol @@ -1,16 +1,10 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; -import {AccessManager} from "@openzeppelin/contracts/access/manager/AccessManager.sol"; import {Amount, AmountLib} from "../../contracts/type/Amount.sol"; -import {ComponentService} from "../../contracts/shared/ComponentService.sol"; -import {Dip} from "../../contracts/mock/Dip.sol"; import {GifTest} from "../base/GifTest.sol"; -import {IVersionable} from "../../contracts/upgradeability/IVersionable.sol"; -import {Service} from "../../contracts/shared/Service.sol"; -import {TokenHandler, TokenHandlerBase} from "../../contracts/shared/TokenHandler.sol"; -import {Version, VersionLib} from "../../contracts/type/Version.sol"; +import {TokenHandlerBase} from "../../contracts/shared/TokenHandler.sol"; contract TokenHandlerEx is TokenHandlerBase { @@ -276,7 +270,7 @@ contract TokenHandlerTest is GifTest { function _fundAndApprove(TokenHandlerEx th, address sender, Amount amount, Amount approval) internal { - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); dip.transfer(sender, amount.toInt()); vm.stopPrank(); @@ -288,13 +282,13 @@ contract TokenHandlerTest is GifTest { function _makeAddrWithFunds(string memory name, uint256 amount) internal returns (address addr) { addr = makeAddr(name); - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); dip.transfer(addr, amount); vm.stopPrank(); } function _fundAddr(address addr, uint256 amount) internal { - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); dip.transfer(addr, amount); vm.stopPrank(); } diff --git a/test/staking/RequiredStaking.t.sol b/test/staking/RequiredStaking.t.sol index 6e33491f5..5a27cc02b 100644 --- a/test/staking/RequiredStaking.t.sol +++ b/test/staking/RequiredStaking.t.sol @@ -61,7 +61,7 @@ contract RequiredStakingTest is GifTest { vm.stopPrank(); // fund customer - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(customer, 100000 * 10 ** token.decimals()); vm.stopPrank(); @@ -497,7 +497,7 @@ contract RequiredStakingTest is GifTest { FeeLib.zero()); // performance fees vm.stopPrank(); - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(investor, bundleCapital); vm.stopPrank(); diff --git a/test/staking/Staking.t.sol b/test/staking/Staking.t.sol index cc76b4f83..0b56d31f1 100644 --- a/test/staking/Staking.t.sol +++ b/test/staking/Staking.t.sol @@ -82,8 +82,8 @@ contract StakingTest is GifTest { assertEq(objectInfo.objectType.toInt(), STAKE().toInt(), "unexpected object type"); assertFalse(objectInfo.isInterceptor, "stake as interceptor"); assertEq(objectInfo.objectAddress, address(0), "stake object address non zero"); - assertEq(objectInfo.initialOwner, staker, "unexpected initial stake owner"); - assertEq(bytes(objectInfo.data).length, 0, "unexpected data size"); + assertEq(registry.ownerOf(stakeNftId), staker, "unexpected initial stake owner"); + assertEq(registry.getObjectData(stakeNftId).length, 0, "unexpected data size"); NftId stakeTargetNftId; Seconds lockingPeriod; @@ -139,8 +139,8 @@ contract StakingTest is GifTest { assertEq(objectInfo.objectType.toInt(), STAKE().toInt(), "unexpected object type"); assertFalse(objectInfo.isInterceptor, "stake as interceptor"); assertEq(objectInfo.objectAddress, address(0), "stake object address non zero"); - assertEq(objectInfo.initialOwner, staker2, "unexpected initial stake owner"); - assertEq(bytes(objectInfo.data).length, 0, "unexpected data size"); + assertEq(registry.ownerOf(stakeNftId), staker2, "unexpected initial stake owner"); + assertEq(registry.getObjectData(stakeNftId).length, 0, "unexpected data size"); Seconds lockingPeriod = stakingReader.getTargetInfo(instanceNftId).lockingPeriod; assertEq(lockingPeriod.toInt(), TargetManagerLib.getDefaultLockingPeriod().toInt(), "unexpected locking period"); @@ -1085,7 +1085,7 @@ contract StakingTest is GifTest { dipAmount = AmountLib.toAmount(myStakeAmount * 10 ** dip.decimals()); if (withFunding) { - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); dip.transfer(myStaker, dipAmount.toInt()); vm.stopPrank(); } diff --git a/test/staking/StakingOwner.t.sol b/test/staking/StakingOwner.t.sol index add045e41..c980f1982 100644 --- a/test/staking/StakingOwner.t.sol +++ b/test/staking/StakingOwner.t.sol @@ -63,7 +63,6 @@ contract StakingOwnerTest is GifTest { console.log("staking nft id (actual)", staking.getNftId().toInt()); // check staking owner - assertEq(stakingOwner, registryOwner, "staking owner not registry owner"); assertTrue(stakingOwner != outsider, "staking owner not outsider"); assertEq(staking.getOwner(), stakingOwner, "unexpected staking owner"); @@ -238,7 +237,7 @@ contract StakingOwnerTest is GifTest { staking.setStakingRate(currentChainId, address(token), newTokenStakingRate); // WHEN + THEN attempt to set staking reader - StakingReader newStakingReader = new StakingReader(registry); + StakingReader newStakingReader = new StakingReader(); vm.expectRevert( abi.encodeWithSelector( INftOwnable.ErrorNftOwnableNotOwner.selector, outsider)); diff --git a/test/staking/StakingProtocolTarget.t.sol b/test/staking/StakingProtocolTarget.t.sol index 920e3ecfe..ba57fc593 100644 --- a/test/staking/StakingProtocolTarget.t.sol +++ b/test/staking/StakingProtocolTarget.t.sol @@ -13,6 +13,7 @@ import {Amount, AmountLib} from "../../contracts/type/Amount.sol"; import {BlocknumberLib} from "../../contracts/type/Blocknumber.sol"; import {GifTest} from "../base/GifTest.sol"; import {NftId, NftIdLib} from "../../contracts/type/NftId.sol"; +import {GIF_ADMIN_ROLE, GIF_MANAGER_ROLE} from "../../contracts/type/RoleId.sol"; import {STAKE} from "../../contracts/type/ObjectType.sol"; import {Seconds, SecondsLib} from "../../contracts/type/Seconds.sol"; import {StakingLib} from "../../contracts/staking/StakingLib.sol"; @@ -36,15 +37,17 @@ contract StakingProtocolTargetTest is GifTest { protocolNftId = registry.getProtocolNftId(); protocolRewardRate = stakingReader.getRewardRate(protocolNftId); - vm.startPrank(staking.getOwner()); + // fund staking owner with DIPs + _prepareAccount(stakingOwner, STAKING_PROTOCOL_REWARD_BALANCE); - // needs component service to be registered + vm.startPrank(stakingOwner); + + // needs staking service to be registered // can therefore only be called after service registration staking.approveTokenHandler(dip, AmountLib.max()); // approve token handler to pull dips from staking owner Amount refillAmount = AmountLib.toAmount(STAKING_PROTOCOL_REWARD_BALANCE * 10 ** dip.decimals()); - dip.approve( address(staking.getTokenHandler()), refillAmount.toInt()); @@ -63,10 +66,12 @@ contract StakingProtocolTargetTest is GifTest { assertEq(protocolNftId.toInt(), 1101, "unexpected protocol nft id"); assertTrue(protocolRewardRate == UFixedLib.toUFixed(5, -2), "unexpected protocol reward rate"); assertEq(staking.getWallet(), address(staking.getTokenHandler()), "unexpected staking wallet"); + assertEq(staking.getOwner(), stakingOwner, "unexpected staking owner"); assertEq(dip.allowance(staking.getWallet(), address(staking.getTokenHandler())), type(uint256).max, "unexpected allowance for staking token handler"); // solhint-disable - console.log("registry owner:", registryOwner); + console.log("gif admin", registryAdmin.getRoleMember(GIF_ADMIN_ROLE(), 0)); + console.log("gif manager", registryAdmin.getRoleMember(GIF_MANAGER_ROLE(), 0)); console.log("staking owner:", staking.getOwner()); console.log("staking nft id:", staking.getNftId().toInt()); console.log("staking address:", address(staking)); @@ -255,7 +260,7 @@ contract StakingProtocolTargetTest is GifTest { dipAmount = AmountLib.toAmount(myStakeAmount * 10 ** dip.decimals()); if (withFunding) { - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); dip.transfer(myStaker, dipAmount.toInt()); vm.stopPrank(); } diff --git a/test/staking/StakingRateManagement.t.sol b/test/staking/StakingRateManagement.t.sol index 561268244..60af78eff 100644 --- a/test/staking/StakingRateManagement.t.sol +++ b/test/staking/StakingRateManagement.t.sol @@ -48,7 +48,7 @@ contract StakingRateManagement is GifTest { token, UFixedLib.toUFixed(10)); // 10 dips required per usdc token - vm.startPrank(registryOwner); + vm.startPrank(stakingOwner); staking.addToken(ChainIdLib.current(), tokenAddress); staking.setStakingRate(ChainIdLib.current(), tokenAddress, tokenStakingRate); vm.stopPrank(); @@ -92,7 +92,7 @@ contract StakingRateManagement is GifTest { tokenStakingRate, // old stakig rate currentBlock); - vm.startPrank(registryOwner); + vm.startPrank(stakingOwner); staking.setStakingRate(currentChainId, tokenAddress, newStakingRate); vm.stopPrank(); diff --git a/test/staking/StakingSetup.t.sol b/test/staking/StakingSetup.t.sol index ab9d811f8..668e454ba 100644 --- a/test/staking/StakingSetup.t.sol +++ b/test/staking/StakingSetup.t.sol @@ -63,13 +63,13 @@ contract StakingSetupTest is GifTest { assertEq(staking.getNftId().toInt(), registry.getNftIdForAddress(address(staking)).toInt(), "unexpected staking nft id (2)"); // staking registry entry - IRegistry.ObjectInfo memory stakingInfo = registry.getObjectInfo(staking.getNftId()); + IRegistry.ObjectInfo memory stakingInfo = registry.getObjectInfo(stakingNftId); assertEq(stakingInfo.nftId.toInt(), stakingNftId.toInt(), "unexpected staking nft id (3)"); assertEq(stakingInfo.parentNftId.toInt(), registryNftId.toInt(), "unexpected parent nft id"); assertEq(stakingInfo.objectType.toInt(), STAKING().toInt(), "unexpected object type"); assertFalse(stakingInfo.isInterceptor, "staking should not be interceptor"); assertEq(stakingInfo.objectAddress, address(staking), "unexpected contract address"); - assertEq(stakingInfo.initialOwner, registryOwner, "unexpected initial owner"); + assertEq(registry.ownerOf(stakingNftId), stakingOwner, "unexpected initial owner"); // staking service manager assertEq(stakingServiceManager.getOwner(), stakingService.getOwner(), "unexpected staking service manager owner"); @@ -81,13 +81,13 @@ contract StakingSetupTest is GifTest { assertEq(stakingService.getNftId().toInt(), stakingServiceNftId.toInt(), "unexpected staking service nft id (1)"); assertEq(stakingService.getNftId().toInt(), registry.getNftIdForAddress(address(stakingService)).toInt(), "unexpected staking service nft id (2)"); - IRegistry.ObjectInfo memory serviceInfo = registry.getObjectInfo(stakingService.getNftId()); + IRegistry.ObjectInfo memory serviceInfo = registry.getObjectInfo(stakingServiceNftId); assertEq(serviceInfo.nftId.toInt(), stakingServiceNftId.toInt(), "unexpected staking service nft id (3)"); assertEq(serviceInfo.parentNftId.toInt(), registryNftId.toInt(), "unexpected parent nft id"); assertEq(serviceInfo.objectType.toInt(), SERVICE().toInt(), "unexpected object type"); assertFalse(serviceInfo.isInterceptor, "staking service should not be interceptor"); assertEq(serviceInfo.objectAddress, address(stakingService), "unexpected contract address"); - assertEq(serviceInfo.initialOwner, registryOwner, "unexpected initial owner"); + assertEq(registry.ownerOf(stakingServiceNftId), gifManager, "unexpected initial owner"); } @@ -139,7 +139,7 @@ contract StakingSetupTest is GifTest { function test_stakingServiceSetStakingReader() public { // GIVEN - StakingReader newStakingReader = new StakingReader(registry); + StakingReader newStakingReader = new StakingReader(); newStakingReader.initialize(address(staking), address(staking.getStakingStore())); vm.startPrank(stakingOwner); diff --git a/test/staking/StakingTarget.t.sol b/test/staking/StakingTarget.t.sol index 8ea3ecfd0..60f3625c7 100644 --- a/test/staking/StakingTarget.t.sol +++ b/test/staking/StakingTarget.t.sol @@ -71,7 +71,6 @@ contract StakingTargetTest is GifTest { NftId protocolNftId = registry.getProtocolNftId(); Amount reservesInitialAmount = stakingReader.getTargetInfo(protocolNftId).reserveAmount; assertEq(reservesInitialAmount.toInt(), 0, "protocol reward reserves not 0"); - uint256 stakingOwnerInitialDipBalance = dip.balanceOf(stakingOwner); address stakingWallet = staking.getWallet(); uint256 refillAmountFullDips = 500; @@ -81,6 +80,8 @@ contract StakingTargetTest is GifTest { assertEq(stakingReader.getReserveBalance(protocolNftId).toInt(), 0, "reward reserves balance not at refill amount (after staking owner funding)"); // WHEN - refill reward reserves for protocol + _prepareAccount(stakingOwner, refillAmountFullDips); + _refillRewardReserves(protocolNftId, refillAmount, stakingOwner); // THEN @@ -89,7 +90,7 @@ contract StakingTargetTest is GifTest { // check dips have been transferred to staking wallet assertEq(dip.balanceOf(stakingWallet), refillAmount.toInt(), "staking wallet dip balance not at refill amount (after reward funding)"); - assertEq(dip.balanceOf(stakingOwner), stakingOwnerInitialDipBalance - refillAmount.toInt(), "unexpected staking owner dip balance (after reward funding)"); + assertEq(dip.balanceOf(stakingOwner), 0, "unexpected staking owner dip balance (after reward funding)"); } @@ -103,6 +104,8 @@ contract StakingTargetTest is GifTest { Amount initialAmount = AmountLib.toAmount(refillAmountFullDips * 10 ** dip.decimals()); Amount withdrawAmount = AmountLib.toAmount(withdrwaAmountFullDips * 10 ** dip.decimals()); + _prepareAccount(stakingOwner, refillAmountFullDips); + _refillRewardReserves(protocolNftId, initialAmount, stakingOwner); // check initial state @@ -137,6 +140,8 @@ contract StakingTargetTest is GifTest { Amount initialAmount = AmountLib.toAmount(refillAmountFullDips * 10 ** dip.decimals()); Amount withdrawAmount = AmountLib.toAmount(withdrwaAmountFullDips * 10 ** dip.decimals()); + _prepareAccount(stakingOwner, refillAmountFullDips); + _refillRewardReserves(protocolNftId, initialAmount, stakingOwner); // WHEN + THEN - outsider attempts to withdraw protocol reward reserves @@ -400,7 +405,7 @@ contract StakingTargetTest is GifTest { ( TokenHandler tokenHandler, Amount refillAmount - ) = _addRewardReserves(instanceNftId, instanceOwner, refillAmountFullDips); + ) = _addRewardReserves(instanceOwner, refillAmountFullDips); // check reward reserve balance from book keeping assertEq(stakingReader.getReserveBalance(instanceNftId).toInt(), refillAmount.toInt(), "reward reserves balance not at refill amount (after reward funding)"); @@ -431,7 +436,7 @@ contract StakingTargetTest is GifTest { // GIVEN uint256 refillAmountFullDips = 500; - (, Amount refillAmount) = _addRewardReserves(instanceNftId, instanceOwner, refillAmountFullDips); + (, Amount refillAmount) = _addRewardReserves(instanceOwner, refillAmountFullDips); // WHEN / THEN (withdraw some reserves as outsider) Amount withdrawAmount = AmountLib.toAmount(refillAmount.toInt() / 2); @@ -470,7 +475,6 @@ contract StakingTargetTest is GifTest { function _addRewardReserves( - NftId, address account, uint256 amount ) @@ -535,12 +539,12 @@ contract StakingTargetTest is GifTest { // return existing dip balance back to registry owner if (reset) { vm.startPrank(myStaker); - dip.transfer(registryOwner, dip.balanceOf(myStaker)); + dip.transfer(tokenIssuer, dip.balanceOf(myStaker)); vm.stopPrank(); } if (withFunding) { - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); dip.transfer(myStaker, dipAmount.toInt()); vm.stopPrank(); } diff --git a/test/staking/TvlCalculation.t.sol b/test/staking/TvlCalculation.t.sol index 235b6e1b9..1e33c0c12 100644 --- a/test/staking/TvlCalculation.t.sol +++ b/test/staking/TvlCalculation.t.sol @@ -480,7 +480,7 @@ contract TvlCalculation is GifTest { ) internal { - vm.startPrank(registryOwner); + vm.startPrank(tokenIssuer); token.transfer(customer, amount); vm.stopPrank(); diff --git a/test/static/LockedEthers.t.sol b/test/static/LockedEthers.t.sol index 452d95a0e..f8545d82f 100644 --- a/test/static/LockedEthers.t.sol +++ b/test/static/LockedEthers.t.sol @@ -2,8 +2,10 @@ pragma solidity ^0.8.20; import {console, Test} from "../../lib/forge-std/src/Test.sol"; +import {AccessAdmin} from "../../contracts/authorization/AccessAdmin.sol"; import {AccessManagerCloneable} from "../../contracts/authorization/AccessManagerCloneable.sol"; import {UpgradableProxyWithAdmin} from "../../contracts/upgradeability/UpgradableProxyWithAdmin.sol"; +import {VersionPartLib} from "../../contracts/type/Version.sol"; contract MockContract { function hello() public pure returns (string memory) { @@ -24,8 +26,13 @@ contract LockedEthersTest is Test { function setUp() public { accessManagerMaster = new AccessManagerCloneable(); + AccessAdmin admin = new AccessAdmin(); + vm.startPrank(initialAdmin); - accessManagerMaster.initialize(initialAdmin); + admin.initialize( + address(accessManagerMaster), + "Test", + VersionPartLib.toVersionPart(5)); vm.stopPrank(); upgradeableProxyWithAdmin = new UpgradableProxyWithAdmin( diff --git a/test/type/NftIdSet.t.sol b/test/type/NftIdSet.t.sol index 26b5ff44d..d9842e076 100644 --- a/test/type/NftIdSet.t.sol +++ b/test/type/NftIdSet.t.sol @@ -21,7 +21,7 @@ contract NftIdSetTest is GifTest { MockObjectSet master = new MockObjectSet(); objectSet = MockObjectSet(Clones.clone(address(master))); - objectSet.initialize(instance.getInstanceAdmin().authority(), address(instance.getRegistry()), address(instance)); + objectSet.initialize(instance.getInstanceAdmin().authority(), address(instance)); } function test_addToSetHappyCase() public {