Skip to content

Commit

Permalink
Merge pull request #1 from luciditytech/feature/develop-alpha
Browse files Browse the repository at this point in the history
feat(*): developing alpha version
  • Loading branch information
DZariusz authored Mar 14, 2019
2 parents 4c49d0e + 23e3d86 commit 0639559
Show file tree
Hide file tree
Showing 56 changed files with 9,356 additions and 1 deletion.
3 changes: 3 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"presets": ["env"]
}
11 changes: 11 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Unifying editor configurations for all developers:
# For details see http://editorconfig.org/

root = true

[*]
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
26 changes: 26 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"extends": "airbnb-base",
"env": {
"mocha": true
},
"globals": {
"artifacts": true,
"assert": true,
"beforeEach": true,
"contract": true,
"describe": true,
"it": true,
"web3": true
},
"rules": {
"no-console": "off",
"prefer-destructuring": ["error", {
"AssignmentExpression": {
"array": false, // this will allow for: var bar = foo[0] <- access array with index
"object": true
}
}, {
"enforceForRenamedProperties": false
}]
}
}
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.sol linguist-language=Solidity
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.idea
build/
node_modules/
all.sol
8 changes: 8 additions & 0 deletions .solcover.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
copyPackages: ['openzeppelin-solidity', 'token-sale-contracts'],
port: 8555,
norpc: false,
compileCommand: 'truffle compile --all',
testCommand: 'truffle test --network coverage',
skipFiles: []
};
5 changes: 5 additions & 0 deletions .soliumignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules
helpers
migrations
test
contracts/Migrations.sol
18 changes: 18 additions & 0 deletions .soliumrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"extends": "solium:recommended",
"plugins": [
"security"
],
"rules": {
"quotes": [
"error",
"double"
],
"indentation": [
"error",
2
],
"security/no-inline-assembly": 0,
"security/no-low-level-calls": 0
}
}
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Changelog
All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Added
- First version of `ContractRegistry`.
- External deployer that can be used in any external repository.
31 changes: 30 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,30 @@
# contract-registry
# Contract Registry

## Overview

`ContractRegistry.sol` solution comes with predefined interfaces
for other contracts that need to be updatable.

## Install

```
git clone <this-repo>
git hf init
npm install
```

## Testing

```
npm run lint
npm run test
```

## Resources

See [SLab: updatable contracts - best way to do it](https://lucidity.slab.com/drafts/updatable-contracts-best-way-to-do-it-draft-010a2fef).

## Addresses

* development: [0x09dffc2f5747f6484d9b757dbdb727f48bcf699d](https://ropsten.etherscan.io/address/0x09dffc2f5747f6484d9b757dbdb727f48bcf699d#code)
* staging: [0x3c5c8a1a2ef948e97495b785eb4b45c9de70911e](https://ropsten.etherscan.io/address/0x3c5c8a1a2ef948e97495b785eb4b45c9de70911e#code)
58 changes: 58 additions & 0 deletions contracts/ContractRegistry.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
pragma solidity 0.5.0;

import "openzeppelin-solidity/contracts/ownership/Ownable.sol";
import "./interfaces/IRegistrable.sol";
import "./interfaces/IContractRegistry.sol";

contract ContractRegistry is IContractRegistry, Ownable {

mapping(bytes32 => IRegistrable) private _contractsByName;

event LogAdd(address indexed executor, bytes32 instanceName, IRegistrable instance);
event LogUpdate(address indexed executor, bytes32 instanceName, IRegistrable oldInstance, IRegistrable newInstance);

constructor() public {}

function contractByName(bytes32 _name) external view returns (address) {
return address(_contractsByName[_name]);
}

function add(IRegistrable _instance)
public
onlyOwner
returns(bool) {
require(address(_instance) != address(0x0), "[add] Contract address is empty");
bytes32 name = _instance.contractName();
require(name != 0, "[add] Contract name is empty");
require(address(_contractsByName[name]) == address(0x0), "[add] This name is already in use");

require(_instance.register(), "[add] register failed");

_contractsByName[name] = _instance;

emit LogAdd(msg.sender, name, _instance);

return true;
}

function update(IRegistrable _newInstance)
public
onlyOwner
returns(bool) {
bytes32 name = _newInstance.contractName();
IRegistrable oldInstance = _contractsByName[name];

require(address(oldInstance) != address(0x0), "[update] Instance with provided name do not exists");
require(address(_newInstance) != address(0x0), "[update] New instance address is empty");
require(oldInstance != _newInstance, "[update] New and old address are the same");

oldInstance.unregister(_newInstance);
require(_newInstance.register(), "[update] registration failed");

_contractsByName[name] = _newInstance;

emit LogUpdate(msg.sender, name, oldInstance, _newInstance);

return true;
}
}
23 changes: 23 additions & 0 deletions contracts/Migrations.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
pragma solidity 0.5.0;

contract Migrations {
address public owner;
uint public last_completed_migration;

modifier restricted() {
if (msg.sender == owner) _;
}

constructor () 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);
}
}
23 changes: 23 additions & 0 deletions contracts/helpers/Killable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
pragma solidity 0.5.0;

contract Killable {

address payable private _payableOwner;

event LogKill(
uint256 balance,
address indexed balanceReceiver
);

constructor () public {
_payableOwner = msg.sender;
}

function kill()
external {
require(msg.sender == _payableOwner, "[kill] access denied");

emit LogKill(address(this).balance, _payableOwner);
selfdestruct(_payableOwner);
}
}
21 changes: 21 additions & 0 deletions contracts/helpers/Suicidal.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
pragma solidity 0.5.0;

contract Suicidal {

address payable private _payableOwner;

event LogSuicide(
uint256 balance,
address indexed balanceReceiver
);

constructor () public {
_payableOwner = msg.sender;
}

function _suicide()
internal {
emit LogSuicide(address(this).balance, _payableOwner);
selfdestruct(_payableOwner);
}
}
10 changes: 10 additions & 0 deletions contracts/interfaces/IContractRegistry.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
pragma solidity 0.5.0;

import "./IRegistrable.sol";

interface IContractRegistry {
function add(IRegistrable) external returns(bool);
function update(IRegistrable) external returns(bool);

function contractByName(bytes32) external view returns (address);
}
8 changes: 8 additions & 0 deletions contracts/interfaces/IRegistrable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
pragma solidity 0.5.0;

interface IRegistrable {
function contractName() external view returns (bytes32);
function register() external returns (bool);
function isRegistered() external view returns (bool);
function unregister(IRegistrable _newInstance) external;
}
82 changes: 82 additions & 0 deletions contracts/interfaces/Registrable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
pragma solidity 0.5.0;

import "../helpers/Suicidal.sol";
import "./IRegistrable.sol";
import "./IContractRegistry.sol";

contract Registrable is IRegistrable, Suicidal {

IContractRegistry public contractRegistry;

bool private _isRegistered;

modifier needContractRegistrySetup {
require(address(contractRegistry) != address(0x0), "[needContractRegistrySetup] contractRegistry address is empty");
require(_isRegistered, "[needContractRegistrySetup] contract is not registered");
_;
}

modifier onlyFromContractRegistry() {
require(msg.sender == address(contractRegistry), "[onlyFromContractRegistry] access denied");
_;
}

modifier onlyFromContract(bytes32 _name) {
require(_name != bytes32(0), "contract name is not set");
require(msg.sender == contractRegistry.contractByName(_name), "[onlyFromContract...] access denied");
_;
}

event LogRegister(address indexed executor, address indexed registered, bool isRegistered);

constructor (address _contractRegistry) public {
require(address(_contractRegistry) != address(0x0), "_contractRegistry address is empty");

contractRegistry = IContractRegistry(_contractRegistry);
}

function isRegistered() external view returns (bool) {
return _isRegistered;
}

function register()
external
onlyFromContractRegistry
returns (bool) {
return _register();
}

function _register()
internal
returns (bool) {
require(!_isRegistered, "i'm already register");

_isRegistered = true;
emit LogRegister(msg.sender, address(this), true);

return true;
}

function unregister(IRegistrable _newInstance)
external
onlyFromContractRegistry {
_unregister(_newInstance);

/// @dev it is important that contract be killed once it is replaced by new one,
/// so there be no case when we allow to use old methods (including getters)
_suicide();
}

function _unregister(IRegistrable _newInstance)
internal
returns (bool) {
require(_isRegistered, "i'm not even register");
require(address(_newInstance) != address(0x0), "[unregister] _newInstance address is empty");
require(address(_newInstance) != address(this), "[unregister] _newInstance is me");

_isRegistered = false;
emit LogRegister(msg.sender, address(this), false);

return true;
}
}
32 changes: 32 additions & 0 deletions contracts/interfaces/RegistrableWithSingleStorage.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
pragma solidity 0.5.0;

import "./Registrable.sol";
import "../storage/interfaces/IStorageBase.sol";
import "../storageStrategy/interfaces/IStorageStrategy.sol";
import "../storageStrategy/SingleStorageStrategy.sol";

contract RegistrableWithSingleStorage is Registrable, SingleStorageStrategy {

constructor (address _contractRegistry, IStorageBase _storage)
public
Registrable(_contractRegistry)
SingleStorageStrategy (_storage) {}

function register()
external
onlyFromContractRegistry
returns (bool) {
require(address(singleStorage) != address(0x0), "[register] contract do not have storage attached");

return _register();
}

function unregister(IRegistrable _newInstance)
external
onlyFromContractRegistry {
_unregister(_newInstance);

IStorageStrategy newInstance = IStorageStrategy(address(_newInstance));
detachFromStorage(address(newInstance));
}
}
Loading

0 comments on commit 0639559

Please sign in to comment.