Skip to content

Instantly share code, notes, and snippets.

@paulperegud
Created May 8, 2018 12:25
Show Gist options
  • Save paulperegud/6d0acad82a785d3ca91630f56f52d472 to your computer and use it in GitHub Desktop.
Save paulperegud/6d0acad82a785d3ca91630f56f52d472 to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.4.23+commit.124ca40d.js&optimize=false&gist=
pragma solidity ^0.4.18;
interface IRegistry {
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);
}
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));
assembly {
let ptr := mload(0x40)
calldatacopy(ptr, 0, calldatasize)
let result := delegatecall(gas, _impl, ptr, calldatasize, 0, 0)
let size := returndatasize
returndatacopy(ptr, 0, size)
switch result
case 0 { revert(ptr, size) }
default { return(ptr, size) }
}
}
}
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;
}
}
/**
* @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));
}
}
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);
}
}
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;
}
}
contract TokenV1_0 is Upgradeable {
mapping (address => uint) balances;
event Transfer(address indexed from, address indexed to, uint256 _value);
function initialize(address sender) public payable {
super.initialize(sender);
mint(sender, 10000);
}
function balanceOf(address addr) public view returns (uint) {
return balances[addr];
}
function transfer(address to, uint256 value) public {
require(balances[msg.sender] >= value);
balances[msg.sender] -= value;
balances[to] += value;
Transfer(msg.sender, to, value);
}
function mint(address to, uint256 value) public {
balances[to] += value;
Transfer(0x0, to, value);
}
}
contract TokenV1_1 is TokenV1_0 {
mapping (address => mapping (address => uint)) allowances;
function transferFrom(address from, address to, uint256 value) public {
require(allowances[from][msg.sender] >= value);
allowances[from][msg.sender] -= value;
balances[from] -= value;
balances[to] += value;
Transfer(from, to, value);
}
function approve(address spender, uint256 value) public {
allowances[msg.sender][spender] = value;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment