Skip to content

Instantly share code, notes, and snippets.

@skozin
Created September 24, 2020 20:59
Show Gist options
  • Save skozin/4521cd98820184c358cbbcc41eacbac6 to your computer and use it in GitHub Desktop.
Save skozin/4521cd98820184c358cbbcc41eacbac6 to your computer and use it in GitHub Desktop.
Partial proxy pattern example
pragma solidity 0.4.24;
import "./UnstructuredStorage.sol";
import "./Proxy.sol";
interface ICounter {
function incrementCounter(uint256 _increment) external returns (uint256 prevValue, uint256 newValue);
}
contract CounterStorage {
bytes32 internal constant COUNTER_POSITION = keccak256("depools.DePool.counter");
}
contract App is ICounter, CounterStorage, Proxy {
using UnstructuredStorage for bytes32;
bytes32 internal constant COUNTER_IMPL_POSITION = keccak256("depools.DePool.counterImpl");
constructor(address _counterImpl) public {
COUNTER_IMPL_POSITION.setStorageAddress(_counterImpl);
}
function getCounter() public view returns (uint256) {
return COUNTER_POSITION.getStorageUint256();
}
function incrementCounter(uint256 _increment) public returns (uint256 prevValue, uint256 newValue) {
delegatedFwd(COUNTER_IMPL_POSITION.getStorageAddress(), msg.data);
}
}
contract CounterImpl is ICounter, CounterStorage, DirectCallGuard {
using UnstructuredStorage for bytes32;
function incrementCounter(uint256 _increment) public noDirectCall returns (uint256 prevValue, uint256 newValue) {
prevValue = COUNTER_POSITION.getStorageUint256();
newValue = prevValue + _increment;
COUNTER_POSITION.setStorageUint256(newValue);
}
}
// Modified from: https://github.com/aragon/aragonOS/blob/next/contracts/common/DelegateProxy.sol
pragma solidity 0.4.24;
contract DelegateProxy {
uint256 internal constant FWD_GAS_LIMIT = 10000;
/**
* @dev Performs a delegatecall and returns whatever the delegatecall returned (entire context execution will return!)
* @param _dst Destination address to perform the delegatecall
* @param _calldata Calldata for the delegatecall
*/
function delegatedFwd(address _dst, bytes _calldata) internal {
uint256 fwdGasLimit = FWD_GAS_LIMIT;
assembly {
let result := delegatecall(sub(gas, fwdGasLimit), _dst, add(_calldata, 0x20), mload(_calldata), 0, 0)
let size := returndatasize
let ptr := mload(0x40)
returndatacopy(ptr, 0, size)
// revert instead of invalid() bc if the underlying call failed with invalid() it already wasted gas.
// if the call returned error data, forward it
switch result case 0 { revert(ptr, size) }
default { return(ptr, size) }
}
}
}
pragma solidity 0.4.24;
import "./UnstructuredStorage.sol";
import "./DelegateProxy.sol";
contract ProxyStorage {
bytes32 internal constant PROXY_FLAG_POSITION = keccak256("depools.DePool.proxyFlag");
uint256 internal constant PROXY_FLAG = 1;
}
contract Proxy is ProxyStorage, DelegateProxy {
using UnstructuredStorage for bytes32;
constructor() internal {
PROXY_FLAG_POSITION.setStorageUint256(PROXY_FLAG);
}
}
/**
* Allows to prevent from calling the deployed implementation directly.
*/
contract DirectCallGuard is ProxyStorage {
using UnstructuredStorage for bytes32;
modifier noDirectCall() {
require(PROXY_FLAG_POSITION.getStorageUint256() == PROXY_FLAG, "NO_DIRECT_CALL");
_;
}
}
// Source: https://github.com/aragon/aragonOS/blob/next/contracts/common/UnstructuredStorage.sol
pragma solidity ^0.4.24;
library UnstructuredStorage {
function getStorageBool(bytes32 position) internal view returns (bool data) {
assembly { data := sload(position) }
}
function getStorageAddress(bytes32 position) internal view returns (address data) {
assembly { data := sload(position) }
}
function getStorageBytes32(bytes32 position) internal view returns (bytes32 data) {
assembly { data := sload(position) }
}
function getStorageUint256(bytes32 position) internal view returns (uint256 data) {
assembly { data := sload(position) }
}
function setStorageBool(bytes32 position, bool data) internal {
assembly { sstore(position, data) }
}
function setStorageAddress(bytes32 position, address data) internal {
assembly { sstore(position, data) }
}
function setStorageBytes32(bytes32 position, bytes32 data) internal {
assembly { sstore(position, data) }
}
function setStorageUint256(bytes32 position, uint256 data) internal {
assembly { sstore(position, data) }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment