diff --git a/.soliumignore b/.soliumignore new file mode 100644 index 0000000..22b32ca --- /dev/null +++ b/.soliumignore @@ -0,0 +1,2 @@ +node_modules +contracts/misc/Migrations.sol diff --git a/.soliumrc.json b/.soliumrc.json new file mode 100644 index 0000000..65b4d5f --- /dev/null +++ b/.soliumrc.json @@ -0,0 +1,22 @@ +{ + "custom-rules-filename": null, + "rules": { + "imports-on-top": true, + "variable-declarations": true, + "array-declarations": true, + "operator-whitespace": true, + "lbrace": false, + "mixedcase": true, + "camelcase": true, + "uppercase": true, + "no-with": true, + "no-empty-blocks": true, + "no-unused-vars": true, + "double-quotes": true, + "blank-lines": true, + "indentation": false, + "whitespace": true, + "deprecated-suicide": true, + "pragma-on-top": true + } +} diff --git a/contracts/IdentityFactory.sol b/contracts/IdentityFactory.sol index 70269b8..5c83695 100644 --- a/contracts/IdentityFactory.sol +++ b/contracts/IdentityFactory.sol @@ -1,6 +1,7 @@ pragma solidity 0.4.11; import "./RecoveryQuorum.sol"; + contract IdentityFactory { event IdentityCreated( address indexed userKey, diff --git a/contracts/IdentityFactoryWithRecoveryKey.sol b/contracts/IdentityFactoryWithRecoveryKey.sol index 3c6fea1..1ee2ece 100644 --- a/contracts/IdentityFactoryWithRecoveryKey.sol +++ b/contracts/IdentityFactoryWithRecoveryKey.sol @@ -1,6 +1,7 @@ pragma solidity 0.4.11; import "./RecoverableController.sol"; + contract IdentityFactoryWithRecoveryKey { event IdentityCreated( address indexed userKey, diff --git a/contracts/Proxy.sol b/contracts/Proxy.sol index fe07a1a..ff32e2e 100644 --- a/contracts/Proxy.sol +++ b/contracts/Proxy.sol @@ -1,14 +1,17 @@ pragma solidity 0.4.11; import "./libs/Owned.sol"; + contract Proxy is Owned { - event Forwarded (address indexed destination, uint value, bytes data ); - event Received (address indexed sender, uint value); + event Forwarded (address indexed destination, uint value, bytes data); + event Received (address indexed sender, uint value); - function () payable { Received(msg.sender, msg.value); } + function () payable { Received(msg.sender, msg.value); } - function forward(address destination, uint value, bytes data) onlyOwner { - if (!destination.call.value(value)(data)) { throw; } - Forwarded(destination, value, data); - } + function forward(address destination, uint value, bytes data) onlyOwner { + if (!destination.call.value(value)(data)) { + throw; + } + Forwarded(destination, value, data); + } } diff --git a/contracts/RecoverableController.sol b/contracts/RecoverableController.sol index 49341b0..9e9f9bf 100644 --- a/contracts/RecoverableController.sol +++ b/contracts/RecoverableController.sol @@ -1,82 +1,94 @@ pragma solidity 0.4.11; import "./Proxy.sol"; + contract RecoverableController { - uint public version; - Proxy public proxy; - - address public userKey; - address public proposedUserKey; - uint public proposedUserKeyPendingUntil; - - address public recoveryKey; - address public proposedRecoveryKey; - uint public proposedRecoveryKeyPendingUntil; - - address public proposedController; - uint public proposedControllerPendingUntil; - - uint public shortTimeLock;// use 900 for 15 minutes - uint public longTimeLock; // use 259200 for 3 days - - event RecoveryEvent(string action, address initiatedBy); - - modifier onlyUserKey() { if (msg.sender == userKey) _; } - modifier onlyRecoveryKey() { if (msg.sender == recoveryKey) _; } - - function RecoverableController(address proxyAddress, address _userKey, uint _longTimeLock, uint _shortTimeLock) { - version = 1; - proxy = Proxy(proxyAddress); - userKey = _userKey; - shortTimeLock = _shortTimeLock; - longTimeLock = _longTimeLock; - recoveryKey = msg.sender; - } - - function forward(address destination, uint value, bytes data) onlyUserKey { - proxy.forward(destination, value, data); - } - //pass 0x0 to cancel - function signRecoveryChange(address _proposedRecoveryKey) onlyUserKey{ - proposedRecoveryKeyPendingUntil = now + longTimeLock; - proposedRecoveryKey = _proposedRecoveryKey; - RecoveryEvent("signRecoveryChange", msg.sender); - } - function changeRecovery() { - if(proposedRecoveryKeyPendingUntil < now && proposedRecoveryKey != 0x0){ - recoveryKey = proposedRecoveryKey; - delete proposedRecoveryKey; + uint public version; + Proxy public proxy; + + address public userKey; + address public proposedUserKey; + uint public proposedUserKeyPendingUntil; + + address public recoveryKey; + address public proposedRecoveryKey; + uint public proposedRecoveryKeyPendingUntil; + + address public proposedController; + uint public proposedControllerPendingUntil; + + uint public shortTimeLock; // use 900 for 15 minutes + uint public longTimeLock; // use 259200 for 3 days + + event RecoveryEvent(string action, address initiatedBy); + + modifier onlyUserKey() { + if (msg.sender == userKey) _; + } + modifier onlyRecoveryKey() { + if (msg.sender == recoveryKey) _; + } + + function RecoverableController(address proxyAddress, address _userKey, uint _longTimeLock, uint _shortTimeLock) { + version = 1; + proxy = Proxy(proxyAddress); + userKey = _userKey; + shortTimeLock = _shortTimeLock; + longTimeLock = _longTimeLock; + recoveryKey = msg.sender; + } + + function forward(address destination, uint value, bytes data) onlyUserKey { + proxy.forward(destination, value, data); } - } - //pass 0x0 to cancel - function signControllerChange(address _proposedController) onlyUserKey{ - proposedControllerPendingUntil = now + longTimeLock; - proposedController = _proposedController; - RecoveryEvent("signControllerChange", msg.sender); - } - function changeController() { - if(proposedControllerPendingUntil < now && proposedController != 0x0){ - proxy.transfer(proposedController); - suicide(proposedController); + + //pass 0x0 to cancel + function signRecoveryChange(address _proposedRecoveryKey) onlyUserKey { + proposedRecoveryKeyPendingUntil = now + longTimeLock; + proposedRecoveryKey = _proposedRecoveryKey; + RecoveryEvent("signRecoveryChange", msg.sender); + } + + function changeRecovery() { + if (proposedRecoveryKeyPendingUntil < now && proposedRecoveryKey != 0x0) { + recoveryKey = proposedRecoveryKey; + delete proposedRecoveryKey; + } + } + + //pass 0x0 to cancel + function signControllerChange(address _proposedController) onlyUserKey { + proposedControllerPendingUntil = now + longTimeLock; + proposedController = _proposedController; + RecoveryEvent("signControllerChange", msg.sender); + } + + function changeController() { + if (proposedControllerPendingUntil < now && proposedController != 0x0) { + proxy.transfer(proposedController); + selfdestruct(proposedController); + } + } + + //pass 0x0 to cancel + function signUserKeyChange(address _proposedUserKey) onlyUserKey { + proposedUserKeyPendingUntil = now + shortTimeLock; + proposedUserKey = _proposedUserKey; + RecoveryEvent("signUserKeyChange", msg.sender); } - } - //pass 0x0 to cancel - function signUserKeyChange(address _proposedUserKey) onlyUserKey{ - proposedUserKeyPendingUntil = now + shortTimeLock; - proposedUserKey = _proposedUserKey; - RecoveryEvent("signUserKeyChange", msg.sender); - } - function changeUserKey(){ - if(proposedUserKeyPendingUntil < now && proposedUserKey != 0x0){ - userKey = proposedUserKey; - delete proposedUserKey; - RecoveryEvent("changeUserKey", msg.sender); + + function changeUserKey(){ + if (proposedUserKeyPendingUntil < now && proposedUserKey != 0x0) { + userKey = proposedUserKey; + delete proposedUserKey; + RecoveryEvent("changeUserKey", msg.sender); + } } - } - function changeRecoveryFromRecovery(address _recoveryKey) onlyRecoveryKey{ recoveryKey = _recoveryKey; } - function changeUserKeyFromRecovery(address _userKey) onlyRecoveryKey{ - delete proposedUserKey; - userKey = _userKey; - } + function changeRecoveryFromRecovery(address _recoveryKey) onlyRecoveryKey{ recoveryKey = _recoveryKey; } + + function changeUserKeyFromRecovery(address _userKey) onlyRecoveryKey{ + delete proposedUserKey; + userKey = _userKey; + } } diff --git a/contracts/RecoveryQuorum.sol b/contracts/RecoveryQuorum.sol index 42a1358..4d78de6 100644 --- a/contracts/RecoveryQuorum.sol +++ b/contracts/RecoveryQuorum.sol @@ -2,6 +2,7 @@ pragma solidity 0.4.11; import "./RecoverableController.sol"; import "./libs/ArrayLib.sol"; + contract RecoveryQuorum { RecoverableController public controller; uint constant MAX_DELEGATES = 15; @@ -17,13 +18,15 @@ contract RecoveryQuorum { event RecoveryEvent(string action, address initiatedBy); - modifier onlyUserKey(){ if (msg.sender == controller.userKey()) _; } + modifier onlyUserKey(){ + if (msg.sender == controller.userKey()) _; + } function RecoveryQuorum(address _controller, address[] _delegates) { controller = RecoverableController(_controller); - for(uint i = 0; i < _delegates.length; i++) { + for (uint i = 0; i < _delegates.length; i++) { if (i >= MAX_DELEGATES) { - break; + break; } delegateAddresses.push(_delegates[i]); delegates[_delegates[i]] = Delegate({ @@ -35,7 +38,7 @@ contract RecoveryQuorum { } function signUserChange(address proposedUserKey) public { - if(delegateRecordExists(delegates[msg.sender])) { + if (delegateRecordExists(delegates[msg.sender])) { delegates[msg.sender].proposedUserKey = proposedUserKey; changeUserKey(proposedUserKey); RecoveryEvent("signUserChange", msg.sender); @@ -43,11 +46,11 @@ contract RecoveryQuorum { } function changeUserKey(address newUserKey) public { - if(collectedSignatures(newUserKey) >= neededSignatures()) { + if (collectedSignatures(newUserKey) >= neededSignatures()) { controller.changeUserKeyFromRecovery(newUserKey); - for(uint i = 0 ; i < delegateAddresses.length ; i++) { + for (uint i = 0; i < delegateAddresses.length; i++) { //remove any pending delegates after a recovery - if(delegates[delegateAddresses[i]].pendingUntil > now) { + if (delegates[delegateAddresses[i]].pendingUntil > now) { delegates[delegateAddresses[i]].deletedAfter = now; } delete delegates[delegateAddresses[i]].proposedUserKey; @@ -56,21 +59,21 @@ contract RecoveryQuorum { } function replaceDelegates(address[] delegatesToRemove, address[] delegatesToAdd) onlyUserKey { - for(uint i = 0 ; i < delegatesToRemove.length ; i++) { + for (uint i = 0; i < delegatesToRemove.length; i++) { removeDelegate(delegatesToRemove[i]); } garbageCollect(); - for(uint j = 0 ; j < delegatesToAdd.length ; j++) { + for (uint j = 0; j < delegatesToAdd.length; j++) { addDelegate(delegatesToAdd[j]); } RecoveryEvent("replaceDelegates", msg.sender); } function collectedSignatures(address _proposedUserKey) constant returns (uint signatures) { - for(uint i = 0 ; i < delegateAddresses.length ; i++) { - if (delegateHasValidSignature(delegates[delegateAddresses[i]]) - && delegates[delegateAddresses[i]].proposedUserKey == _proposedUserKey) { - signatures++; + for (uint i = 0; i < delegateAddresses.length; i++) { + if (delegateHasValidSignature(delegates[delegateAddresses[i]]) && + delegates[delegateAddresses[i]].proposedUserKey == _proposedUserKey) { + signatures++; } } } @@ -81,8 +84,8 @@ contract RecoveryQuorum { function neededSignatures() constant returns (uint) { uint currentDelegateCount; //always 0 at this point - for(uint i = 0 ; i < delegateAddresses.length ; i++) { - if(delegateIsCurrent(delegates[delegateAddresses[i]])) { + for (uint i = 0; i < delegateAddresses.length; i++) { + if (delegateIsCurrent(delegates[delegateAddresses[i]])) { currentDelegateCount++; } } @@ -90,21 +93,21 @@ contract RecoveryQuorum { } function addDelegate(address delegate) private { - if(!delegateRecordExists(delegates[delegate]) - && delegateAddresses.length < MAX_DELEGATES) { - delegates[delegate] = Delegate({ - proposedUserKey: 0x0, - pendingUntil: now + controller.longTimeLock(), - deletedAfter: NEVER - }); - delegateAddresses.push(delegate); - } + if (!delegateRecordExists(delegates[delegate]) && + delegateAddresses.length < MAX_DELEGATES) { + delegates[delegate] = Delegate({ + proposedUserKey: 0x0, + pendingUntil: now + controller.longTimeLock(), + deletedAfter: NEVER + }); + delegateAddresses.push(delegate); + } } function removeDelegate(address delegate) private { - if(delegates[delegate].deletedAfter > controller.longTimeLock() + now) { + if (delegates[delegate].deletedAfter > controller.longTimeLock() + now) { //remove right away if they are still pending - if(delegates[delegate].pendingUntil > now) { + if (delegates[delegate].pendingUntil > now) { delegates[delegate].deletedAfter = now; } else { delegates[delegate].deletedAfter = controller.longTimeLock() + now; @@ -114,11 +117,13 @@ contract RecoveryQuorum { function garbageCollect() private { uint i = 0; - while(i < delegateAddresses.length) { - if(delegateIsDeleted(delegates[delegateAddresses[i]])) { + while (i < delegateAddresses.length) { + if (delegateIsDeleted(delegates[delegateAddresses[i]])) { delete delegates[delegateAddresses[i]]; ArrayLib.removeAddress(i, delegateAddresses); - } else { i++; } + } else { + i++; + } } } diff --git a/contracts/libs/ArrayLib.sol b/contracts/libs/ArrayLib.sol index 57c4785..534038e 100644 --- a/contracts/libs/ArrayLib.sol +++ b/contracts/libs/ArrayLib.sol @@ -1,17 +1,20 @@ pragma solidity 0.4.11; + library ArrayLib { - function findAddress(address a, address[] storage arry) returns (int){ - for (uint i = 0 ; i < arry.length ; i++){ - if(arry[i] == a){return int(i);} + function findAddress(address a, address[] storage arry) returns (int){ + for (uint i = 0 ; i < arry.length ; i++){ + if (arry[i] == a) { + return int(i); + } + } + return -1; } - return -1; - } - function removeAddress(uint i, address[] storage arry){ - uint lengthMinusOne = arry.length - 1; - arry[i] = arry[lengthMinusOne]; - delete arry[lengthMinusOne]; - arry.length = lengthMinusOne; - } + function removeAddress(uint i, address[] storage arry){ + uint lengthMinusOne = arry.length - 1; + arry[i] = arry[lengthMinusOne]; + delete arry[lengthMinusOne]; + arry.length = lengthMinusOne; + } } diff --git a/contracts/libs/Owned.sol b/contracts/libs/Owned.sol index 832e076..a042af9 100644 --- a/contracts/libs/Owned.sol +++ b/contracts/libs/Owned.sol @@ -1,21 +1,22 @@ pragma solidity 0.4.11; + contract Owned { - address public owner; - modifier onlyOwner() { - if (!isOwner(msg.sender)) { - throw; + address public owner; + modifier onlyOwner() { + if (!isOwner(msg.sender)) { + throw; + } + _; } - _; - } - function Owned() { owner = msg.sender; } + function Owned() { owner = msg.sender; } - function isOwner(address addr) public returns(bool) { return addr == owner; } + function isOwner(address addr) public returns(bool) { return addr == owner; } - function transfer(address _owner) onlyOwner { - if (_owner != address(this)) { - owner = _owner; + function transfer(address _owner) onlyOwner { + if (_owner != address(this)) { + owner = _owner; + } } - } } diff --git a/contracts/misc/TestRegistry.sol b/contracts/misc/TestRegistry.sol index 4eebd15..862726a 100644 --- a/contracts/misc/TestRegistry.sol +++ b/contracts/misc/TestRegistry.sol @@ -1,19 +1,25 @@ +// This contract is only used for testing purposes. pragma solidity 0.4.11; -// This contract is only used for testing purposes. + contract TestRegistry { - mapping(address => uint) public registry; + mapping(address => uint) public registry; - function register(uint x) { - registry[msg.sender] = x; - } + function register(uint x) { + registry[msg.sender] = x; + } - function reallyLongFunctionName(uint with, address many, string strange, uint params) { - registry[many] = params; - } + function reallyLongFunctionName( + uint with, + address many, + string strange, + uint params + ) { + registry[many] = params; + } - function testThrow() { - throw; - } + function testThrow() { + throw; + } } diff --git a/package.json b/package.json index 4a4f8cf..bdc7deb 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "deploy-local": "npm run _deploy local", "generate-readme": "./scripts/generate-readme.js", "test": "./node_modules/.bin/truffle test --network in_memory", + "lint": "./node_modules/.bin/solium -d contracts", "diagrams": "bash scripts/make-diagrams.bash" }, "license": "Apache-2", @@ -39,6 +40,7 @@ "ethjs-abi": "^0.1.9", "left-pad": "^1.1.3", "node-plantuml": "^0.5.0", + "solium": "^0.5.3", "truffle": "^3.4.3", "truffle-contract": "^1.1.10", "truffle-hdwallet-provider": "0.0.3"