Contract Source Code:
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.11 <0.9.0;
/**
* @title Library for access related errors.
*/
library AccessError {
/**
* @dev Thrown when an address tries to perform an unauthorized action.
* @param addr The address that attempts the action.
*/
error Unauthorized(address addr);
}
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.11 <0.9.0;
/**
* @title Library for address related errors.
*/
library AddressError {
/**
* @dev Thrown when a zero address was passed as a function parameter (0x0000000000000000000000000000000000000000).
*/
error ZeroAddress();
/**
* @dev Thrown when an address representing a contract is expected, but no code is found at the address.
* @param contr The address that was expected to be a contract.
*/
error NotAContract(address contr);
}
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.11 <0.9.0;
import "../errors/AccessError.sol";
library OwnableStorage {
bytes32 private constant _SLOT_OWNABLE_STORAGE =
keccak256(abi.encode("io.synthetix.core-contracts.Ownable"));
struct Data {
address owner;
address nominatedOwner;
}
function load() internal pure returns (Data storage store) {
bytes32 s = _SLOT_OWNABLE_STORAGE;
assembly {
store.slot := s
}
}
function onlyOwner() internal view {
if (msg.sender != getOwner()) {
revert AccessError.Unauthorized(msg.sender);
}
}
function getOwner() internal view returns (address) {
return OwnableStorage.load().owner;
}
}
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.11 <0.9.0;
abstract contract AbstractProxy {
fallback() external payable {
_forward();
}
receive() external payable {
_forward();
}
function _forward() internal {
address implementation = _getImplementation();
// solhint-disable-next-line no-inline-assembly
assembly {
calldatacopy(0, 0, calldatasize())
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
returndatacopy(0, 0, returndatasize())
switch result
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
function _getImplementation() internal view virtual returns (address);
}
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.11 <0.9.0;
contract ProxyStorage {
bytes32 private constant _SLOT_PROXY_STORAGE =
keccak256(abi.encode("io.synthetix.core-contracts.Proxy"));
struct ProxyStore {
address implementation;
bool simulatingUpgrade;
}
function _proxyStore() internal pure returns (ProxyStore storage store) {
bytes32 s = _SLOT_PROXY_STORAGE;
assembly {
store.slot := s
}
}
}
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.11 <0.9.0;
import "./AbstractProxy.sol";
import "./ProxyStorage.sol";
import "../errors/AddressError.sol";
import "../utils/AddressUtil.sol";
contract UUPSProxy is AbstractProxy, ProxyStorage {
constructor(address firstImplementation) {
if (firstImplementation == address(0)) {
revert AddressError.ZeroAddress();
}
if (!AddressUtil.isContract(firstImplementation)) {
revert AddressError.NotAContract(firstImplementation);
}
_proxyStore().implementation = firstImplementation;
}
function _getImplementation() internal view virtual override returns (address) {
return _proxyStore().implementation;
}
}
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.11 <0.9.0;
import {UUPSProxy} from "./UUPSProxy.sol";
import {OwnableStorage} from "../ownership/OwnableStorage.sol";
contract UUPSProxyWithOwner is UUPSProxy {
// solhint-disable-next-line no-empty-blocks
constructor(address firstImplementation, address initialOwner) UUPSProxy(firstImplementation) {
OwnableStorage.load().owner = initialOwner;
}
}
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.11 <0.9.0;
library AddressUtil {
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly {
size := extcodesize(account)
}
return size > 0;
}
}
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.11 <0.9.0;
import {UUPSProxyWithOwner} from "@synthetixio/core-contracts/contracts/proxy/UUPSProxyWithOwner.sol";
contract Proxy is UUPSProxyWithOwner {
constructor(
address firstImplementation,
address initialOwner
) UUPSProxyWithOwner(firstImplementation, initialOwner) {} // solhint-disable-line no-empty-blocks
}