Created
September 24, 2020 20:59
-
-
Save skozin/4521cd98820184c358cbbcc41eacbac6 to your computer and use it in GitHub Desktop.
Partial proxy pattern example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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) } | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"); | |
_; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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