Upgradable experiments
This commit is contained in:
		
						commit
						9efe30afda
					
				
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
build
 | 
			
		||||
							
								
								
									
										9
									
								
								README.mdown
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								README.mdown
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,9 @@
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Development
 | 
			
		||||
 | 
			
		||||
For local development it is recommended to use [ganache-cli](https://github.com/trufflesuite/ganache-cli) to run a local development chain.
 | 
			
		||||
 | 
			
		||||
We default to port 7545 for development to not get in conflict with the default Ethereum RPC port. 
 | 
			
		||||
 | 
			
		||||
  $ ganache-cli -p 7545
 | 
			
		||||
							
								
								
									
										23
									
								
								contracts/Migrations.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								contracts/Migrations.sol
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										16
									
								
								contracts/Token1.sol
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										11
									
								
								contracts/Token2.sol
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
			
		||||
pragma solidity ^0.4.4;
 | 
			
		||||
 | 
			
		||||
import './Token1.sol';
 | 
			
		||||
 | 
			
		||||
contract Token2 is Token1 {
 | 
			
		||||
 | 
			
		||||
  function mint() public {
 | 
			
		||||
    value += 20;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										34
									
								
								contracts/upgradeable/IRegistry.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								contracts/upgradeable/IRegistry.sol
									
									
									
									
									
										Normal 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);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										23
									
								
								contracts/upgradeable/Migrations.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								contracts/upgradeable/Migrations.sol
									
									
									
									
									
										Normal 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);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										36
									
								
								contracts/upgradeable/Proxy.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								contracts/upgradeable/Proxy.sol
									
									
									
									
									
										Normal 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) }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										46
									
								
								contracts/upgradeable/Registry.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								contracts/upgradeable/Registry.sol
									
									
									
									
									
										Normal 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;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								contracts/upgradeable/UpgradeabilityProxy.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								contracts/upgradeable/UpgradeabilityProxy.sol
									
									
									
									
									
										Normal 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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										23
									
								
								contracts/upgradeable/UpgradeabilityStorage.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								contracts/upgradeable/UpgradeabilityStorage.sol
									
									
									
									
									
										Normal 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;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								contracts/upgradeable/Upgradeable.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								contracts/upgradeable/Upgradeable.sol
									
									
									
									
									
										Normal 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));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										22
									
								
								migrations/1520798600_setup.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								migrations/1520798600_setup.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
			
		||||
var Registry = artifacts.require('./upgradeable/Registry.sol');
 | 
			
		||||
 | 
			
		||||
var Token = artifacts.require('./Token1.sol');
 | 
			
		||||
 | 
			
		||||
module.exports = function(deployer) {
 | 
			
		||||
  deployer.deploy(Registry).then(function() {
 | 
			
		||||
    return Registry.deployed();
 | 
			
		||||
  }).then(function(registry) {
 | 
			
		||||
    return deployer.deploy(Token);
 | 
			
		||||
  }).then(function(token) {
 | 
			
		||||
    console.log('Registry address: ', Registry.address);
 | 
			
		||||
    console.log('Token address: ', Token.address);
 | 
			
		||||
    Registry.deployed().then(function(registry) {
 | 
			
		||||
      registry.addVersion('Token_1.0', Token.address);
 | 
			
		||||
      registry.createProxy('Token_1.0').then(function(r) {
 | 
			
		||||
        console.log(r.logs[0]);
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										14
									
								
								migrations/1520802793_upgrade.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								migrations/1520802793_upgrade.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,14 @@
 | 
			
		||||
var Token = artifacts.require('./Token2.sol');
 | 
			
		||||
var Registry = artifacts.require('./upgradeable/Registry');
 | 
			
		||||
var UpgradeabilityProxy = artifacts.require('./upgradeable/UpgradeabilityProxy');
 | 
			
		||||
 | 
			
		||||
module.exports = function(deployer) {
 | 
			
		||||
  deployer.deploy(Token).then(function(t) {
 | 
			
		||||
    return Token.deployed();
 | 
			
		||||
  }).then(function(token) {
 | 
			
		||||
    Registry.deployed().then(function(registry) {
 | 
			
		||||
      console.log('Token address: ', Token.address);
 | 
			
		||||
      registry.addVersion('Token_2.0', Token.address);
 | 
			
		||||
    });
 | 
			
		||||
  })
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										5
									
								
								migrations/1_initial_migration.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								migrations/1_initial_migration.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
			
		||||
var Migrations = artifacts.require("./Migrations.sol");
 | 
			
		||||
 | 
			
		||||
module.exports = function(deployer) {
 | 
			
		||||
  deployer.deploy(Migrations);
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										10
									
								
								truffle.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								truffle.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
			
		||||
module.exports = {
 | 
			
		||||
  // See <http://truffleframework.com/docs/advanced/configuration>
 | 
			
		||||
  networks: {
 | 
			
		||||
    development: {
 | 
			
		||||
      host: "127.0.0.1",
 | 
			
		||||
      port: 7545,
 | 
			
		||||
      network_id: "*" // Match any network id
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user