Description:
Proxy contract enabling upgradeable smart contract patterns. Delegates calls to an implementation contract.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"src/common/interfaces/IBeacon.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;
import {ContractType} from "../types/ContractType.sol";
/**
* @dev Interface for Beacon contract
*/
interface IBeacon {
/**
* @dev Returns the implementation address of the Beacon contract
* @return The implementation address
*/
function implementation() external view returns (address);
/**
* @dev Returns the beacon name
* @return The beacon name identifying this beacon/logic pair
*/
function name() external view returns (string memory);
/**
* @dev Returns the contract type of this beacon
* @return contractType The contract type as ContractType enum: NONE (invalid), ERC20Token, ERC721Token, ERC721SoulboundToken, WhitelistComplianceOracle
*/
function contractType() external view returns (ContractType);
}
"
},
"src/common/libraries/StorageSlot.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity 0.8.30;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC-1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(newImplementation.code.length > 0);
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*/
library StorageSlot {
/// @notice The slot for address.
struct AddressSlot {
address value;
}
/// @notice The slot for boolean.
struct BooleanSlot {
bool value;
}
/// @notice The slot for bytes32.
struct Bytes32Slot {
bytes32 value;
}
/// @notice The slot for uint256.
struct Uint256Slot {
uint256 value;
}
/// @notice The slot for string.
struct StringSlot {
string value;
}
/// @notice The slot for bytes.
struct BytesSlot {
bytes value;
}
/// @notice The slot for uint8.
struct Uint8Slot {
uint8 value;
}
/// @notice The slot for bytes array.
struct BytesArraySlot {
bytes[] value;
}
/// @notice The slot for uint256 array.
struct Uint256ArraySlot {
uint256[] value;
}
/// @notice The slot for uint256 mapping.
struct Uint256MappingSlot {
mapping(uint256 => uint256) value;
}
/// @notice The slot for uint256 string mapping.
struct Uint256StringMappingSlot {
mapping(uint256 => string) value;
}
/// @notice The slot for uint256 address mapping.
struct Uint256AddressMappingSlot {
mapping(uint256 => address) value;
}
/// @notice The slot for address uint256 mapping.
struct AddressUint256MappingSlot {
mapping(address => uint256) value;
}
/// @notice The slot for address mapping address boolean mapping.
struct AddressMappingAddressBooleanMappingSlot {
mapping(address => mapping(address => bool)) value;
}
/// @notice The slot for address mapping uint256 mapping.
struct AddressMappingUint256MappingSlot {
mapping(address => mapping(uint256 => uint256)) value;
}
/// @notice The slot for bytes address mapping.
struct BytesAddressMappingSlot {
mapping(bytes => address) value;
}
/// @notice The slot for bytes uint8 mapping.
struct BytesUint8MappingSlot {
mapping(bytes => uint8) value;
}
/// @notice The slot for bytes uint256 mapping.
struct BytesUintMappingSlot {
mapping(bytes => uint256) value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
* @param slot The slot to read from.
* @return r The slot value.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
* @param slot The slot to read from.
* @return r The slot value.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
* @param slot The slot to read from.
* @return r The slot value.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
* @param slot The slot to read from.
* @return r The slot value.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns a `Uint8Slot` with member `value` located at `slot`.
* @param slot The slot to read from.
* @return r The slot value.
*/
function getUint8Slot(bytes32 slot) internal pure returns (Uint8Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
* @param slot The slot to read from.
* @return r The slot value.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
* @param store The storage pointer to read from.
* @return r The slot value.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
* @param slot The slot to read from.
* @return r The slot value.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
* @param store The storage pointer to read from.
* @return r The slot value.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesArraySlot` with member `value` located at `slot`.
* @param slot The slot to read from.
* @return r The slot value.
*/
function getBytesArraySlot(bytes32 slot) internal pure returns (BytesArraySlot storage r) {
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256ArraySlot` with member `value` located at `slot`.
* @param slot The slot to read from.
* @return r The slot value.
*/
function getUint256ArraySlot(bytes32 slot) internal pure returns (Uint256ArraySlot storage r) {
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256MappingSlot` with member `value` located at `slot`.
* @param slot The slot to read from.
* @return r The slot value.
*/
function getUint256MappingSlot(bytes32 slot) internal pure returns (Uint256MappingSlot storage r) {
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256StringMappingSlot` with member `value` located at `slot`.
* @param slot The slot to read from.
* @return r The slot value.
*/
function getUint256StringMappingSlot(bytes32 slot) internal pure returns (Uint256StringMappingSlot storage r) {
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256AddressMappingSlot` with member `value` located at `slot`.
* @param slot The slot to read from.
* @return r The slot value.
*/
function getUint256AddressMappingSlot(bytes32 slot) internal pure returns (Uint256AddressMappingSlot storage r) {
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `AddressUint256MappingSlot` with member `value` located at `slot`.
* @param slot The slot to read from.
* @return r The slot value.
*/
function getAddressUint256MappingSlot(bytes32 slot) internal pure returns (AddressUint256MappingSlot storage r) {
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `AddressMappingAddressBooleanMappingSlot` with member `value` located at `slot`.
* @param slot The slot to read from.
* @return r The slot value.
*/
function getAddressMappingAddressBooleanMappingSlot(bytes32 slot) internal pure returns (AddressMappingAddressBooleanMappingSlot storage r) {
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `AddressMappingUint256MappingSlot` with member `value` located at `slot`.
* @param slot The slot to read from.
* @return r The slot value.
*/
function getAddressMappingUint256MappingSlot(bytes32 slot) internal pure returns (AddressMappingUint256MappingSlot storage r) {
assembly {
r.slot := slot
}
}
/**
* @dev Returns a `BytesAddressMappingSlot` with member `value` located at `slot`.
* @param slot The slot to read from.
* @return r The slot value.
*/
function getBytesAddressMappingSlot(bytes32 slot) internal pure returns (BytesAddressMappingSlot storage r) {
assembly {
r.slot := slot
}
}
/**
* @dev Returns a `BytesUint8MappingSlot` with member `value` located at `slot`.
* @param slot The slot to read from.
* @return r The slot value.
*/
function getBytesUint8MappingSlot(bytes32 slot) internal pure returns (BytesUint8MappingSlot storage r) {
assembly {
r.slot := slot
}
}
/**
* @dev Returns a `BytesUintMappingSlot` with member `value` located at `slot`.
* @param slot The slot to read from.
* @return r The slot value.
*/
function getBytesUintMappingSlot(bytes32 slot) internal pure returns (BytesUintMappingSlot storage r) {
assembly {
r.slot := slot
}
}
}
"
},
"src/common/types/ContractType.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;
/**
* @dev Contract type enumeration for implementation upgrade validation.
* @dev This is used to validate that the implementation address supports the correct interface for the contract type.
* @dev NONE is an explicit placeholder to prevent uninitialized variables from defaulting to a valid contract type.
*/
enum ContractType {
NONE, // 0 - Explicit placeholder for uninitialized variables
ERC20Token, // 1
ERC721Token, // 2
ERC721SoulboundToken, // 3
WhitelistComplianceOracle // 4
} "
},
"src/proxies/Proxy.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.30;
import {IBeacon} from "../common/interfaces/IBeacon.sol";
import {StorageSlot} from "../common/libraries/StorageSlot.sol";
/**
* @title Proxy
* @author Mohammad Salim, WisdomTree Digital Assets
* @notice Implementation of a transparent proxy that delegates calls to implementation contracts
* @dev This contract acts as a transparent proxy that forwards all function calls to an implementation
* contract provided by a beacon. The proxy supports upgrades through beacon changes and includes
* initialization logic for setting up the initial state. All calls except those to specific
* proxy management functions are delegated to the implementation.
* @custom:security-contact security@wisdomtree.com
*/
contract Proxy {
using StorageSlot for StorageSlot.AddressSlot;
/// @notice The slot for the Beacon address.
bytes32 internal constant _BEACON_SLOT = keccak256("proxy.beacon");
/// @notice The slot for the initialization owner address.
bytes32 internal constant _INIT_OWNER_SLOT = keccak256("proxy.initializationOwnerAddress");
/// @notice The event for beacon address change.
event BeaconChanged(address indexed previousBeacon, address indexed newBeacon);
/**
* @notice Constructor to initialize the proxy with a beacon address and initialization owner address.
* Requirements:
* - The `beacon_` address cannot be the zero address.
* @param beacon_ The beacon address.
* @param initData The initialization data.
*/
constructor(
address beacon_,
bytes memory initData
) {
require(beacon_ != address(0), "Proxy: new beacon is the zero address");
StorageSlot.getAddressSlot(_BEACON_SLOT).value = beacon_;
emit BeaconChanged(address(0), beacon_);
StorageSlot.getAddressSlot(_INIT_OWNER_SLOT).value = msg.sender;
address implementationAddress = _implementation();
(bool success, ) = implementationAddress.delegatecall(
initData
);
require(success, "Proxy: Initialization failed");
}
/**
* @notice Fallback function that delegates all calls to the implementation contract
* @dev Uses delegatecall to preserve the proxy's storage context while executing implementation logic
* The implementation address is retrieved from the beacon contract for each call
*/
fallback() external payable {
address impl = _implementation();
require(impl != address(0), "Proxy: implementation is the zero address");
assembly {
let ptr := mload(0x40)
calldatacopy(ptr, 0, calldatasize())
let result := delegatecall(gas(), impl, ptr, calldatasize(), 0, 0)
let size := returndatasize()
returndatacopy(ptr, 0, size)
switch result
case 0 { revert(ptr, size) }
default { return(ptr, size) }
}
}
/**
* @notice Receive function that rejects all Ether deposits
* @dev This proxy does not accept Ether transfers and will revert any attempts
*/
receive() external payable {
revert("Does not accept Ether deposits");
}
/**
* @notice Retrieves the current implementation address from the beacon
* @dev This function exposes the implementation address for transparency
* @return The address of the current implementation contract
*/
function getImplementation() external view returns (address) {
return _implementation();
}
/**
* @dev Internal function to get the implementation address from the beacon
* @return The address of the current implementation contract
*/
function _implementation() internal view returns (address) {
return IBeacon(StorageSlot.getAddressSlot(_BEACON_SLOT).value).implementation();
}
}
"
}
},
"settings": {
"optimizer": {
"enabled": true,
"runs": 200
},
"evmVersion": "paris",
"viaIR": true,
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}
}}
Submitted on: 2025-10-03 09:37:07
Comments
Log in to comment.
No comments yet.