Contract Source Code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./Proxy.sol";
contract Evaverse is Proxy {
constructor (address logicAddress) {
_delegateAddress = logicAddress;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^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 contracts
abstract contract Ownable {
address internal _owner;
function owner() public view returns (address) {
return _owner;
}
modifier onlyOwner() {
require(owner() == msg.sender, "Ownable: caller is not the owner");
_;
}
constructor () {
_owner = msg.sender;
}
function SetOwner(address newOwner) external onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_owner = newOwner;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^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/ERC721
abstract contract Proxy is Ownable {
address internal _delegateAddress;
function GetLogic() external view onlyOwner returns (address) {
return _delegateAddress;
}
function SetLogic(address delegate) external onlyOwner {
_delegateAddress = delegate;
}
fallback () external payable {
_delegate(_delegateAddress);
}
receive () external payable {
_delegate(_delegateAddress);
}
function _delegate(address implementation) internal {
// solhint-disable-next-line no-inline-assembly
assembly {
//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.
case 0 { revert(0, returndatasize()) }
default { return(0, returndatasize()) }
}
}
}
abstract contract ProxyTarget is Ownable {
address internal _delegateAddress;
function GetLogicContract() external view onlyOwner returns (address) {
return _delegateAddress;
}
}