pragmasolidity^0.8.0;import{Address}from"@openzeppelin/contracts/utils/Address.sol";import{TransparentUpgradeableProxy}from"@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";import{OwnableUpgradeable}from"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";import{Dependant}from"./Dependant.sol";interfaceIContractsRegistry{eventContractAdded(stringname,addresscontractAddress);eventProxyContractAdded(stringname,addresscontractAddress,addressimplementation);eventProxyContractUpgraded(stringname,addressnewImplementation);eventContractRemoved(stringname);functiongetContract(stringmemoryname)externalviewreturns(address);functionhasContract(stringmemoryname)externalviewreturns(bool);functioninjectDependencies(stringmemoryname)external;functioninjectDependenciesWithData(stringmemoryname,bytesmemorydata)external;functionupgradeContract(stringmemoryname,addressnewImplementation)external;functionupgradeContractAndCall(stringmemoryname,addressnewImplementation,bytesmemorydata)external;functionaddContract(stringmemoryname,addresscontractAddress)external;functionaddProxyContract(stringmemoryname,addresscontractAddress)external;functionaddProxyContractAndCall(stringmemoryname,addresscontractAddress,bytesmemorydata)external;functionjustAddProxyContract(stringmemoryname,addresscontractAddress)external;functionremoveContract(stringmemoryname)external;}contractProxyUpgrader{usingAddressforaddress;addressprivateimmutable_OWNER;modifieronlyOwner(){_onlyOwner();_;}constructor(){_OWNER=msg.sender;}functionupgrade(addresswhat_,addressto_,bytescalldatadata_)externalonlyOwner{if(data_.length>0){TransparentUpgradeableProxy(payable(what_)).upgradeToAndCall(to_,data_);}else{TransparentUpgradeableProxy(payable(what_)).upgradeTo(to_);}}functiongetImplementation(addresswhat_)externalviewonlyOwnerreturns(address){// bytes4(keccak256("implementation()")) == 0x5c60da1b
(boolsuccess_,bytesmemoryreturndata_)=address(what_).staticcall(hex"5c60da1b");require(success_,"ProxyUpgrader: not a proxy");returnabi.decode(returndata_,(address));}function_onlyOwner()internalview{require(_OWNER==msg.sender,"ProxyUpgrader: not an owner");}}contractContractsRegistryisIContractsRegistry,OwnableUpgradeable{ProxyUpgraderprivate_proxyUpgrader;mapping(string=>address)private_contracts;mapping(address=>bool)private_isProxy;function__ContractsRegistry_init()publicinitializer{_proxyUpgrader=newProxyUpgrader();__Ownable_init();}functiongetContract(stringmemoryname_)publicviewreturns(address){addresscontractAddress_=_contracts[name_];require(contractAddress_!=address(0),"ContractsRegistry: this mapping doesn't exist");returncontractAddress_;}functionhasContract(stringmemoryname_)publicviewreturns(bool){return_contracts[name_]!=address(0);}functiongetProxyUpgrader()externalviewreturns(address){returnaddress(_proxyUpgrader);}functioninjectDependencies(stringmemoryname_)publicvirtualonlyOwner{injectDependenciesWithData(name_,bytes(""));}functioninjectDependenciesWithData(stringmemoryname_,bytesmemorydata_)publicvirtualonlyOwner{addresscontractAddress_=_contracts[name_];require(contractAddress_!=address(0),"ContractsRegistry: this mapping doesn't exist");Dependantdependant_=Dependant(contractAddress_);dependant_.setDependencies(address(this),data_);}functionupgradeContract(stringmemoryname_,addressnewImplementation_)publicvirtualonlyOwner{upgradeContractAndCall(name_,newImplementation_,bytes(""));}functionupgradeContractAndCall(stringmemoryname_,addressnewImplementation_,bytesmemorydata_)publicvirtualonlyOwner{addresscontractToUpgrade_=_contracts[name_];require(contractToUpgrade_!=address(0),"ContractsRegistry: this mapping doesn't exist");require(_isProxy[contractToUpgrade_],"ContractsRegistry: not a proxy contract");_proxyUpgrader.upgrade(contractToUpgrade_,newImplementation_,data_);emitProxyContractUpgraded(name_,newImplementation_);}functionaddContract(stringmemoryname_,addresscontractAddress_)publicvirtualonlyOwner{require(contractAddress_!=address(0),"ContractsRegistry: zero address is forbidden");_contracts[name_]=contractAddress_;emitContractAdded(name_,contractAddress_);}functionaddProxyContract(stringmemoryname_,addresscontractAddress_)publicvirtualonlyOwner{addProxyContractAndCall(name_,contractAddress_,bytes(""));}functionaddProxyContractAndCall(stringmemoryname_,addresscontractAddress_,bytesmemorydata_)publicvirtualonlyOwner{require(contractAddress_!=address(0),"ContractsRegistry: zero address is forbidden");addressproxyAddr_=_deployProxy(contractAddress_,address(_proxyUpgrader),data_);_contracts[name_]=proxyAddr_;_isProxy[proxyAddr_]=true;emitProxyContractAdded(name_,proxyAddr_,contractAddress_);}functionjustAddProxyContract(stringmemoryname_,addresscontractAddress_)publicvirtualonlyOwner{require(contractAddress_!=address(0),"ContractsRegistry: zero address is forbidden");_contracts[name_]=contractAddress_;_isProxy[contractAddress_]=true;emitProxyContractAdded(name_,contractAddress_,_proxyUpgrader.getImplementation(contractAddress_));}functionremoveContract(stringmemoryname_)publicvirtualonlyOwner{addresscontractAddress_=_contracts[name_];require(contractAddress_!=address(0),"ContractsRegistry: this mapping doesn't exist");delete_isProxy[contractAddress_];delete_contracts[name_];emitContractRemoved(name_);}function_deployProxy(addresscontractAddress_,addressadmin_,bytesmemorydata_)internalvirtualreturns(address){returnaddress(newTransparentUpgradeableProxy(contractAddress_,admin_,data_));}}
Dependant 实现
pragmasolidity^0.8.0;interfaceIDependant{functionsetDependencies(addresscontractsRegistry,bytesmemorydata)external;functionsetInjector(addressinjector)external;functiongetInjector()externalviewreturns(address);}abstractcontractDependantisIDependant{/**
* @dev bytes32(uint256(keccak256("eip6224.dependant.slot")) - 1)
*/bytes32privateconstant_INJECTOR_SLOT=0x3d1f25f1ac447e55e7fec744471c4dab1c6a2b6ffb897825f9ea3d2e8c9be583;modifierdependant(){_checkInjector();_;_setInjector(msg.sender);}functionsetDependencies(addresscontractsRegistry_,bytesmemorydata_)publicvirtual;functionsetInjector(addressinjector_)external{_checkInjector();_setInjector(injector_);}functiongetInjector()publicviewreturns(addressinjector_){bytes32slot_=_INJECTOR_SLOT;assembly{injector_:=sload(slot_)}}function_setInjector(addressinjector_)internal{bytes32slot_=_INJECTOR_SLOT;assembly{sstore(slot_,injector_)}}function_checkInjector()internalview{addressinjector_=getInjector();require(injector_==address(0)||injector_==msg.sender,"Dependant: not an injector");}}