Upgradable experiments

This commit is contained in:
2018-03-11 23:12:29 +01:00
commit 9efe30afda
16 changed files with 321 additions and 0 deletions

23
contracts/Migrations.sol Normal file
View File

@@ -0,0 +1,23 @@
pragma solidity ^0.4.17;
contract Migrations {
address public owner;
uint public last_completed_migration;
modifier restricted() {
if (msg.sender == owner) _;
}
function Migrations() public {
owner = msg.sender;
}
function setCompleted(uint completed) public restricted {
last_completed_migration = completed;
}
function upgrade(address new_address) public restricted {
Migrations upgraded = Migrations(new_address);
upgraded.setCompleted(last_completed_migration);
}
}

16
contracts/Token1.sol Normal file
View File

@@ -0,0 +1,16 @@
pragma solidity ^0.4.4;
import './upgradeable/Upgradeable.sol';
contract Token1 is Upgradeable {
uint public value;
function Token() public {
value = 1;
}
function mint() public {
value += 10;
}
}

11
contracts/Token2.sol Normal file
View File

@@ -0,0 +1,11 @@
pragma solidity ^0.4.4;
import './Token1.sol';
contract Token2 is Token1 {
function mint() public {
value += 20;
}
}

View File

@@ -0,0 +1,34 @@
pragma solidity ^0.4.18;
/**
* @title IRegistry
* @dev This contract represents the interface of a registry contract
*/
interface IRegistry {
/**
* @dev This event will be emitted every time a new proxy is created
* @param proxy representing the address of the proxy created
*/
event ProxyCreated(address proxy);
/**
* @dev This event will be emitted every time a new implementation is registered
* @param version representing the version name of the registered implementation
* @param implementation representing the address of the registered implementation
*/
event VersionAdded(string version, address implementation);
/**
* @dev Registers a new version with its implementation address
* @param version representing the version name of the new implementation to be registered
* @param implementation representing the address of the new implementation to be registered
*/
function addVersion(string version, address implementation) public;
/**
* @dev Tells the address of the implementation for a given version
* @param version to query the implementation of
* @return address of the implementation registered for the given version
*/
function getVersion(string version) public view returns (address);
}

View File

@@ -0,0 +1,23 @@
pragma solidity ^0.4.17;
contract Migrations {
address public owner;
uint public last_completed_migration;
modifier restricted() {
if (msg.sender == owner) _;
}
function Migrations() public {
owner = msg.sender;
}
function setCompleted(uint completed) public restricted {
last_completed_migration = completed;
}
function upgrade(address new_address) public restricted {
Migrations upgraded = Migrations(new_address);
upgraded.setCompleted(last_completed_migration);
}
}

View File

@@ -0,0 +1,36 @@
pragma solidity ^0.4.18;
/**
* @title Proxy
* @dev Gives the possibility to delegate any call to a foreign implementation.
*/
contract Proxy {
/**
* @dev Tells the address of the implementation where every call will be delegated.
* @return address of the implementation to which it will be delegated
*/
function implementation() public view returns (address);
/**
* @dev Fallback function allowing to perform a delegatecall to the given implementation.
* This function will return whatever the implementation call returns
*/
function () payable public {
address _impl = implementation();
require(_impl != address(0));
bytes memory data = msg.data;
assembly {
let result := delegatecall(gas, _impl, add(data, 0x20), mload(data), 0, 0)
let size := returndatasize
let ptr := mload(0x40)
returndatacopy(ptr, 0, size)
switch result
case 0 { revert(ptr, size) }
default { return(ptr, size) }
}
}
}

View File

@@ -0,0 +1,46 @@
pragma solidity ^0.4.18;
import './IRegistry.sol';
import './Upgradeable.sol';
import './UpgradeabilityProxy.sol';
/**
* @title Registry
* @dev This contract works as a registry of versions, it holds the implementations for the registered versions.
*/
contract Registry is IRegistry {
// Mapping of versions to implementations of different functions
mapping (string => address) internal versions;
/**
* @dev Registers a new version with its implementation address
* @param version representing the version name of the new implementation to be registered
* @param implementation representing the address of the new implementation to be registered
*/
function addVersion(string version, address implementation) public {
require(versions[version] == 0x0);
versions[version] = implementation;
VersionAdded(version, implementation);
}
/**
* @dev Tells the address of the implementation for a given version
* @param version to query the implementation of
* @return address of the implementation registered for the given version
*/
function getVersion(string version) public view returns (address) {
return versions[version];
}
/**
* @dev Creates an upgradeable proxy
* @param version representing the first version to be set for the proxy
* @return address of the new proxy created
*/
function createProxy(string version) public payable returns (UpgradeabilityProxy) {
UpgradeabilityProxy proxy = new UpgradeabilityProxy(version);
Upgradeable(proxy).initialize.value(msg.value)(msg.sender);
ProxyCreated(proxy);
return proxy;
}
}

View File

@@ -0,0 +1,29 @@
pragma solidity ^0.4.18;
import './Proxy.sol';
import './IRegistry.sol';
import './UpgradeabilityStorage.sol';
/**
* @title UpgradeabilityProxy
* @dev This contract represents a proxy where the implementation address to which it will delegate can be upgraded
*/
contract UpgradeabilityProxy is Proxy, UpgradeabilityStorage {
/**
* @dev Constructor function
*/
function UpgradeabilityProxy(string _version) public {
registry = IRegistry(msg.sender);
upgradeTo(_version);
}
/**
* @dev Upgrades the implementation to the requested version
* @param _version representing the version name of the new implementation to be set
*/
function upgradeTo(string _version) public {
_implementation = registry.getVersion(_version);
}
}

View File

@@ -0,0 +1,23 @@
pragma solidity ^0.4.18;
import './IRegistry.sol';
/**
* @title UpgradeabilityStorage
* @dev This contract holds all the necessary state variables to support the upgrade functionality
*/
contract UpgradeabilityStorage {
// Versions registry
IRegistry internal registry;
// Address of the current implementation
address internal _implementation;
/**
* @dev Tells the address of the current implementation
* @return address of the current implementation
*/
function implementation() public view returns (address) {
return _implementation;
}
}

View File

@@ -0,0 +1,19 @@
pragma solidity ^0.4.18;
import './UpgradeabilityStorage.sol';
/**
* @title Upgradeable
* @dev This contract holds all the minimum required functionality for a behavior to be upgradeable.
* This means, required state variables for owned upgradeability purpose and simple initialization validation.
*/
contract Upgradeable is UpgradeabilityStorage {
/**
* @dev Validates the caller is the versions registry.
* THIS FUNCTION SHOULD BE OVERRIDDEN CALLING SUPER
* @param sender representing the address deploying the initial behavior of the contract
*/
function initialize(address sender) public payable {
require(msg.sender == address(registry));
}
}