Skip to content

Instantly share code, notes, and snippets.

@Perseverance
Created March 11, 2018 08:34
Show Gist options
  • Save Perseverance/2100df9b1b3c2315a7500898e62cb036 to your computer and use it in GitHub Desktop.
Save Perseverance/2100df9b1b3c2315a7500898e62cb036 to your computer and use it in GitHub Desktop.
pragma solidity 0.4.15;
contract SharedStorage {
address public contractImplementation;
}
contract Forwardable {
/**
* @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 {
assembly {
switch extcodesize(_dst) case 0 { revert(0, 0) }
let result := delegatecall(sub(gas, 10000), _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) }
}
}
}
contract UpgradeableProxy is SharedStorage, Forwardable {
/**
* @dev UpgradeableProxy is a proxy contract to a contract implementation. The implementation
* can update the reference, which effectively upgrades the contract
* @param _contractImpl Address of the contract used as implementation
*/
function UpgradeableProxy(address _contractImpl) public {
contractImplementation = _contractImpl;
}
/**
* @dev All calls made to the proxy are forwarded to the contract implementation via a delegatecall
* @return Any bytes32 value the implementation returns
*/
function () payable public {
delegatedFwd(contractImplementation, msg.data);
}
}
contract UpgradeableImplementation is SharedStorage {
event UpgradedContract(address indexed _newImpl);
function upgradeImplementation(address _newImpl) public {
contractImplementation = _newImpl;
UpgradedContract(_newImpl);
}
}
contract TestProxy is UpgradeableProxy {
function TestProxy(address initialImplementation) UpgradeableProxy(initialImplementation) {}
}
contract ITestImpl {
function rate() public constant returns(uint);
function setRate(uint r) public;
function getRate() public constant returns(uint);
}
contract TestImpl is ITestImpl, UpgradeableImplementation {
uint public rate;
function rate() public constant returns(uint) {
return rate;
}
function setRate(uint r) public {
rate = r;
}
function getRate() public constant returns(uint) {
return 1000;
}
}
let impl = await TestImpl1.new();
let proxy = await TestProxy.new(impl.address);
let implementedContract = await ITestImpl.at(proxy.address);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment