Skip to content

Commit

Permalink
Merge branch 'mdt/fixed-storage-pattern' into mdt/test-storage-persis…
Browse files Browse the repository at this point in the history
…tence
  • Loading branch information
mdtanrikulu committed Nov 21, 2024
2 parents ea98561 + bfcf334 commit fb49cab
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 38 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ A system for deploying and verifying proxy contracts with predictable storage la

### 2. TransparentVerifiableProxy
- Transparent proxy pattern with verified storage layout
- Fixed storage slots via Diamond Storage pattern:
- Slot 'proxy.verifiable.salt': `salt` (uint256)
- Slot 'proxy.verifiable.owner': `owner` (address)
- Fixed storage slots via [SlotDerivation](https://docs.openzeppelin.com/contracts/5.x/api/utils#SlotDerivation) under `proxy.verifiable` namespace
- `salt` (uint256)
- `owner` (address)
- Immutable `creator` field (set in bytecode)
- Implements secure upgrade mechanism
- Initializable to prevent implementation tampering
Expand Down
2 changes: 1 addition & 1 deletion lib/openzeppelin-contracts
64 changes: 31 additions & 33 deletions src/TransparentVerifiableProxy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,24 @@ pragma solidity ^0.8.20;
import {Proxy} from "@openzeppelin/contracts/proxy/Proxy.sol";
import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol";
import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import {StorageSlot} from "@openzeppelin/contracts/utils/StorageSlot.sol";
import {SlotDerivation} from "@openzeppelin/contracts/utils/SlotDerivation.sol";
import {ITransParentVerifiableProxy} from "./ITransparentVerifiableProxy.sol";

// EIP-2535 Diamond Storage pattern
// ref: https://eips.ethereum.org/EIPS/eip-2535#storage
library StorageSlot {
bytes32 constant SLOT_SALT = keccak256("proxy.verifiable.salt");
bytes32 constant SLOT_OWNER = keccak256("proxy.verifiable.owner");

function getSaltSlot() internal pure returns (bytes32) {
return SLOT_SALT;
}

function getOwnerSlot() internal pure returns (bytes32) {
return SLOT_OWNER;
}
}

interface ITransparentVerifiableProxy is ITransParentVerifiableProxy {
/// @dev See {UUPSUpgradeable-upgradeToAndCall}
function upgradeToAndCall(address newImplementation, bytes calldata data) external payable;
}

contract TransparentVerifiableProxy is Proxy, Initializable {
using StorageSlot for bytes32;
using SlotDerivation for bytes32;
using SlotDerivation for string;

string internal constant _VERIFICATION_SLOT = "proxy.verifiable";
string internal constant _SALT = "salt";
string internal constant _OWNER = "owner";

// immutable variable (in bytecode)
address public immutable creator;

Expand Down Expand Up @@ -64,32 +59,19 @@ contract TransparentVerifiableProxy is Proxy, Initializable {
{
require(implementation != address(0), "New implementation cannot be the zero address");

bytes32 saltSlot = StorageSlot.getSaltSlot();
bytes32 ownerSlot = StorageSlot.getOwnerSlot();
bytes32 baseSlot = _VERIFICATION_SLOT.erc7201Slot();
_setSalt(baseSlot, _salt);
_setOwner(baseSlot, _owner);

assembly {
sstore(saltSlot, _salt)
sstore(ownerSlot, _owner)
}
ERC1967Utils.upgradeToAndCall(implementation, data);
}

function salt() public view returns (uint256) {
bytes32 slot = StorageSlot.getSaltSlot();
uint256 value;
assembly {
value := sload(slot)
}
return value;
return _getSalt(_VERIFICATION_SLOT.erc7201Slot());
}

function owner() public view returns (address) {
bytes32 slot = StorageSlot.getOwnerSlot();
address value;
assembly {
value := sload(slot)
}
return value;
return _getOwner(_VERIFICATION_SLOT.erc7201Slot());
}

/**
Expand Down Expand Up @@ -130,5 +112,21 @@ contract TransparentVerifiableProxy is Proxy, Initializable {
ERC1967Utils.upgradeToAndCall(newImplementation, data);
}

function _getSalt(bytes32 baseSlot) internal view returns (uint256) {
return baseSlot.deriveMapping(_SALT).getUint256Slot().value;
}

function _setSalt(bytes32 baseSlot, uint256 _salt) internal {
baseSlot.deriveMapping(_SALT).getUint256Slot().value = _salt;
}

function _getOwner(bytes32 baseSlot) internal view returns (address) {
return baseSlot.deriveMapping(_OWNER).getAddressSlot().value;
}

function _setOwner(bytes32 baseSlot, address _owner) internal {
baseSlot.deriveMapping(_OWNER).getAddressSlot().value = _owner;
}

receive() external payable {}
}

0 comments on commit fb49cab

Please sign in to comment.