Skip to content
This repository has been archived by the owner on Apr 15, 2020. It is now read-only.

Commit

Permalink
Merge branch 'develop' into feature/146382715-metatx-controller
Browse files Browse the repository at this point in the history
  • Loading branch information
naterush authored Jul 10, 2017
2 parents 7b6ed37 + f41b224 commit cda3b71
Show file tree
Hide file tree
Showing 11 changed files with 201 additions and 143 deletions.
2 changes: 2 additions & 0 deletions .soliumignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
contracts/misc/Migrations.sol
22 changes: 22 additions & 0 deletions .soliumrc.json
Original file line number Diff line number Diff line change
@@ -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
}
}
1 change: 1 addition & 0 deletions contracts/IdentityFactory.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pragma solidity 0.4.11;
import "./RecoveryQuorum.sol";


contract IdentityFactory {
event IdentityCreated(
address indexed userKey,
Expand Down
1 change: 1 addition & 0 deletions contracts/IdentityFactoryWithRecoveryKey.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pragma solidity 0.4.11;
import "./RecoverableController.sol";


contract IdentityFactoryWithRecoveryKey {
event IdentityCreated(
address indexed userKey,
Expand Down
17 changes: 10 additions & 7 deletions contracts/Proxy.sol
Original file line number Diff line number Diff line change
@@ -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);
}
}
158 changes: 85 additions & 73 deletions contracts/RecoverableController.sol
Original file line number Diff line number Diff line change
@@ -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;
}
}
63 changes: 34 additions & 29 deletions contracts/RecoveryQuorum.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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({
Expand All @@ -35,19 +38,19 @@ 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);
}
}

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;
Expand All @@ -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++;
}
}
}
Expand All @@ -81,30 +84,30 @@ 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++;
}
}
return currentDelegateCount/2 + 1;
}

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;
Expand All @@ -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++;
}
}
}

Expand Down
Loading

0 comments on commit cda3b71

Please sign in to comment.