// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;// We can't use the default implementation of OpenZeppelin's Ownable because it uses a constructor which doesn't work with Proxy contractsabstractcontractOwnable{
addressinternal _owner;
functionowner() publicviewreturns (address) {
return _owner;
}
modifieronlyOwner() {
require(owner() ==msg.sender, "Ownable: caller is not the owner");
_;
}
constructor () {
_owner =msg.sender;
}
functionSetOwner(address newOwner) externalonlyOwner{
require(newOwner !=address(0), "Ownable: new owner is the zero address");
_owner = newOwner;
}
}
Contract Source Code
File 3 of 3: Proxy.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import"./Ownable.sol";
// This is mostly lifted from: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/proxy/Proxy.sol// Honorably mentions should be: https://fravoll.github.io/solidity-patterns/proxy_delegate.html// which guided me to: https://github.com/fravoll/solidity-patterns/tree/master/ProxyDelegate// Good Info here: https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable// Sample ERC721 Upgradable contract: https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/tree/master/contracts/token/ERC721abstractcontractProxyisOwnable{
addressinternal _delegateAddress;
functionGetLogic() externalviewonlyOwnerreturns (address) {
return _delegateAddress;
}
functionSetLogic(address delegate) externalonlyOwner{
_delegateAddress = delegate;
}
fallback () externalpayable{
_delegate(_delegateAddress);
}
receive () externalpayable{
_delegate(_delegateAddress);
}
function_delegate(address implementation) internal{
// solhint-disable-next-line no-inline-assemblyassembly {
//Optional, if we wan't to get rid of the param to this function, load from member variable//let _target := sload(0)// Copy msg.data. We take full control of memory in this inline assembly// block because it will not return to Solidity code. We overwrite the// Solidity scratch pad at memory position 0.calldatacopy(0, 0, calldatasize())
// Call the implementation.// out and outsize are 0 because we don't know the size yet.let result :=delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
// Copy the returned data.returndatacopy(0, 0, returndatasize())
switch result
// delegatecall returns 0 on error.case0 { revert(0, returndatasize()) }
default { return(0, returndatasize()) }
}
}
}
abstractcontractProxyTargetisOwnable{
addressinternal _delegateAddress;
functionGetLogicContract() externalviewonlyOwnerreturns (address) {
return _delegateAddress;
}
}