diff --git a/contracts/identity/Identity.sol b/contracts/identity/Identity.sol index 1e6ea37..0ad4985 100644 --- a/contracts/identity/Identity.sol +++ b/contracts/identity/Identity.sol @@ -46,7 +46,7 @@ contract Identity is ERC725, ERC735, MessageSigned { } /** - * @notices requires called by recovery address + * @notice requires called by recovery address */ modifier recoveryOnly { require( @@ -264,7 +264,6 @@ contract Identity is ERC725, ERC735, MessageSigned { /** * @notice Replaces one `_oldKey` with other `_newKey` - * @param _purpose what purpose being replaced * @param _oldKey key to remove * @param _newKey key to add * @param _newType inform type of `_newKey` @@ -350,7 +349,7 @@ contract Identity is ERC725, ERC735, MessageSigned { _includeClaim(claimHash, _topic, _scheme, _issuer, _signature, _data, _uri); } } else { - require(hasKeyPurpose(keccak256(msg.sender), CLAIM_SIGNER_KEY)); + require(keyHasPurpose(keccak256(msg.sender), CLAIM_SIGNER_KEY)); _requestApproval(0, address(this), 0, msg.data); emit ClaimRequested( claimHash, @@ -424,10 +423,10 @@ contract Identity is ERC725, ERC735, MessageSigned { return (myKey.purposes, myKey.keyType, myKey.key); } - function hasKeyPurpose(bytes32 _key, uint256 _purpose) + function keyHasPurpose(bytes32 _key, uint256 _purpose) public view - returns (bool) + returns (bool exists) { return isKeyPurpose[keccak256(_key, _purpose)]; } @@ -515,7 +514,7 @@ contract Identity is ERC725, ERC735, MessageSigned { returns (uint256 txId) { uint256 requiredPurpose = _to == address(this) ? MANAGEMENT_KEY : ACTION_KEY; - require(hasKeyPurpose(_key, requiredPurpose)); + require(keyHasPurpose(_key, requiredPurpose)); if (purposeThreshold[requiredPurpose] == 1) { txId = nonce++; _commitCall(txId, _to, _value, _data); @@ -582,7 +581,7 @@ contract Identity is ERC725, ERC735, MessageSigned { Transaction memory approvedTx = pendingTx[_txId]; require(approvedTx.approverCount > 0); uint256 requiredKeyPurpose = approvedTx.to == address(this) ? MANAGEMENT_KEY : ACTION_KEY; - require(hasKeyPurpose(_key, requiredKeyPurpose)); + require(keyHasPurpose(_key, requiredKeyPurpose)); require(pendingTx[_txId].approvals[_key] != _approval); if (_approval) { @@ -643,29 +642,8 @@ contract Identity is ERC725, ERC735, MessageSigned { ) private { - bytes32 purposeSaltedHash = keccak256(_purpose, _salt); // salted accounts by purpose array index pointer - // forbidden to remove last management key - if (_purpose == MANAGEMENT_KEY) { - require(keysByPurpose[purposeSaltedHash].length > purposeThreshold[MANAGEMENT_KEY]); - } - bytes32 keySaltedHash = keccak256(_key, _salt); // key storage pointer - bytes32 saltedKeyPurposeHash = keccak256(keySaltedHash, _purpose); // accounts by purpose hash element index pointer - require(isKeyPurpose[saltedKeyPurposeHash]); //not possible to remove what not exists - delete isKeyPurpose[saltedKeyPurposeHash]; //remove authorization - - // remove keys by purpose array key element - uint256 removedKeyIndex = indexes[saltedKeyPurposeHash]; // read old key element index - delete indexes[saltedKeyPurposeHash]; // delete key index - - uint256 replacerKeyIndex = keysByPurpose[purposeSaltedHash].length - 1; // replacer is last element - if (removedKeyIndex != replacerKeyIndex) { // deleted not the last element, replace deleted by last element - bytes32 replacerKey = keysByPurpose[purposeSaltedHash][replacerKeyIndex]; // get replacer key - keysByPurpose[purposeSaltedHash][removedKeyIndex] = replacerKey; // overwrite removed index by replacer - indexes[keccak256(keccak256(replacerKey, _salt), _purpose)] = removedKeyIndex; // update saltedKeyPurposeHash index of replacer - } - keysByPurpose[purposeSaltedHash].length--; // remove last element - + _removeKeyFromPurposes(keySaltedHash, _key, _purpose, _salt); //remove key purposes array purpose element Key storage myKey = keys[keySaltedHash]; //load Key storage pointer uint256 _type = myKey.keyType; //save type for case key deleted @@ -688,7 +666,33 @@ contract Identity is ERC725, ERC735, MessageSigned { emit KeyRemoved(_key, _purpose, _type); } + function _removeKeyFromPurposes(bytes32 keySaltedHash, bytes32 _key, uint256 _purpose, uint256 _salt) private { + bytes32 purposeSaltedHash = keccak256(_purpose, _salt); // salted accounts by purpose array index pointer + // forbidden to remove last management key + if (_purpose == MANAGEMENT_KEY) { + require(keysByPurpose[purposeSaltedHash].length > purposeThreshold[MANAGEMENT_KEY]); + } + + bytes32 saltedKeyPurposeHash = keccak256(keySaltedHash, _purpose); // accounts by purpose hash element index pointer + require(isKeyPurpose[saltedKeyPurposeHash]); //not possible to remove what not exists + delete isKeyPurpose[saltedKeyPurposeHash]; //remove authorization + + // remove keys by purpose array key element + uint256 removedKeyIndex = indexes[saltedKeyPurposeHash]; // read old key element index + delete indexes[saltedKeyPurposeHash]; // delete key index + + uint256 replacerKeyIndex = keysByPurpose[purposeSaltedHash].length - 1; // replacer is last element + if (removedKeyIndex != replacerKeyIndex) { // deleted not the last element, replace deleted by last element + bytes32 replacerKey = keysByPurpose[purposeSaltedHash][replacerKeyIndex]; // get replacer key + keysByPurpose[purposeSaltedHash][removedKeyIndex] = replacerKey; // overwrite removed index by replacer + indexes[keccak256(keccak256(replacerKey, _salt), _purpose)] = removedKeyIndex; // update saltedKeyPurposeHash index of replacer + } + keysByPurpose[purposeSaltedHash].length--; // remove last element + } + function _removePurposeFromKey(bytes32 keySaltedHash, bytes32 _key, uint256 _purpose, uint256 _salt) private { + + } /** * @notice Replaces one `_oldKey` with other `_newKey` * @param _oldKey key to remove @@ -715,28 +719,39 @@ contract Identity is ERC725, ERC735, MessageSigned { delete keys[oldKeySaltedHash]; uint256 len = oldKey.purposes.length; for (uint i = 0; i < len; i++) { - uint256 _purpose = oldKey.purposes[i]; - bytes32 purposeSaltedHash = keccak256(_purpose, _salt); // salted accounts by purpose array index pointer - bytes32 saltedOldKeyPurposeHash = keccak256(oldKeySaltedHash, _purpose); // accounts by purpose hash element index pointer - bytes32 saltedNewKeyPurposeHash = keccak256(newKeySaltedHash, _purpose); // accounts by purpose hash element index pointer - bytes32 oldKeyPurposeSaltedHash = keccak256(_oldKey, _purpose, _salt); //account purpose array element index - bytes32 newKeyPurposeSaltedHash = keccak256(_newKey, _purpose, _salt); //account purpose array element index - - delete isKeyPurpose[saltedOldKeyPurposeHash]; //clear oldKey auth - isKeyPurpose[saltedNewKeyPurposeHash] = true; //set newKey auth - - uint256 replacedKeyElementIndex = indexes[saltedOldKeyPurposeHash]; - delete indexes[saltedOldKeyPurposeHash]; - keysByPurpose[purposeSaltedHash][replacedKeyElementIndex] = _newKey; //replace key at list by purpose - indexes[saltedNewKeyPurposeHash] = replacedKeyElementIndex; // save index - - indexes[newKeyPurposeSaltedHash] = indexes[oldKeyPurposeSaltedHash]; //transfer key purposes list index - delete indexes[oldKeyPurposeSaltedHash]; + _replaceKeyPurpose(oldKeySaltedHash, oldKeySaltedHash, _oldKey, _newKey, oldKey.purposes[i], _salt); } keys[newKeySaltedHash] = Key(oldKey.purposes, _newType, _newKey); //add new key return true; } + function _replaceKeyPurpose( + bytes32 newKeySaltedHash, + bytes32 oldKeySaltedHash, + bytes32 _oldKey, + bytes32 _newKey, + uint256 _purpose, + uint256 _salt + ) internal + { + bytes32 purposeSaltedHash = keccak256(_purpose, _salt); // salted accounts by purpose array index pointer + bytes32 saltedOldKeyPurposeHash = keccak256(oldKeySaltedHash, _purpose); // accounts by purpose hash element index pointer + bytes32 saltedNewKeyPurposeHash = keccak256(newKeySaltedHash, _purpose); // accounts by purpose hash element index pointer + bytes32 oldKeyPurposeSaltedHash = keccak256(_oldKey, _purpose, _salt); //account purpose array element index + bytes32 newKeyPurposeSaltedHash = keccak256(_newKey, _purpose, _salt); //account purpose array element index + + delete isKeyPurpose[saltedOldKeyPurposeHash]; //clear oldKey auth + isKeyPurpose[saltedNewKeyPurposeHash] = true; //set newKey auth + + uint256 replacedKeyElementIndex = indexes[saltedOldKeyPurposeHash]; + delete indexes[saltedOldKeyPurposeHash]; + keysByPurpose[purposeSaltedHash][replacedKeyElementIndex] = _newKey; //replace key at list by purpose + indexes[saltedNewKeyPurposeHash] = replacedKeyElementIndex; // save index + + indexes[newKeyPurposeSaltedHash] = indexes[oldKeyPurposeSaltedHash]; //transfer key purposes list index + delete indexes[oldKeyPurposeSaltedHash]; + } + function _includeClaim( bytes32 _claimHash, uint256 _topic, diff --git a/contracts/identity/IdentityFactory.sol b/contracts/identity/IdentityFactory.sol index 0ac1ce9..e0ee363 100644 --- a/contracts/identity/IdentityFactory.sol +++ b/contracts/identity/IdentityFactory.sol @@ -9,25 +9,49 @@ contract IdentityFactory is Factory { event IdentityCreated(address instance); - function IdentityFactory(bytes _infohash) + constructor(bytes _infohash) public - Factory(new IdentityKernel()) + Factory(new IdentityKernel()) { } function createIdentity() external returns (address) - { - return createIdentity(msg.sender); + { + + bytes32[] memory initKeys = new bytes32[](2); + uint256[] memory initPurposes = new uint256[](2); + uint256[] memory initTypes = new uint256[](2); + initKeys[0] = keccak256(msg.sender); + initKeys[1] = initKeys[0]; + initPurposes[0] = 0; + initPurposes[1] = 1; + initTypes[0] = 0; + initTypes[1] = 0; + return createIdentity( + initKeys, + initPurposes, + initTypes, + 1, + 1, + 0 + ); } - function createIdentity(address _idOwner) + function createIdentity( + bytes32[] _keys, + uint256[] _purposes, + uint256[] _types, + uint256 _managerThreshold, + uint256 _actorThreshold, + address _recoveryContract + ) public returns (address) { IdentityKernel instance = IdentityKernel(new DelayedUpdatableInstance(address(latestKernel))); - instance.initIdentity(_idOwner); + instance.initIdentity(_keys,_purposes,_types,_managerThreshold,_actorThreshold,_recoveryContract); emit IdentityCreated(address(instance)); return instance; } diff --git a/contracts/identity/IdentityKernel.sol b/contracts/identity/IdentityKernel.sol index d40056f..568fb5f 100644 --- a/contracts/identity/IdentityKernel.sol +++ b/contracts/identity/IdentityKernel.sol @@ -5,7 +5,34 @@ import "./Identity.sol"; contract IdentityKernel is DelayedUpdatableInstanceStorage, Identity { - function initIdentity(address _caller) external { - _constructIdentity(_caller); + constructor() + Identity( + new bytes32[](0), + new uint256[](0), + new uint256[](0), + 0, + 0, + 0 + ) + public + { + + } + + function initIdentity( + bytes32[] _keys, + uint256[] _purposes, + uint256[] _types, + uint256 _managerThreshold, + uint256 _actorThreshold, + address _recoveryContract + ) external { + _constructIdentity( + _keys, + _purposes, + _types, + _managerThreshold, + _actorThreshold, + _recoveryContract); } } diff --git a/package.json b/package.json index e188c49..1c84522 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "url": "https://github.com/status-im/contracts/issues" }, "homepage": "https://github.com/status-im/contracts#readme", - "dependencies": { + "dependencies": { + "web3-eth-abi": "^1.0.0-beta.34" } } diff --git a/test/factory.js b/test/factory.js index 4915c07..14f13ec 100644 --- a/test/factory.js +++ b/test/factory.js @@ -1,11 +1,3 @@ -const assert = require('assert'); -const Embark = require('embark'); -let EmbarkSpec = Embark.initTests(); -let web3 = EmbarkSpec.web3; - -const identityJson = require('../dist/contracts/Identity.json'); -const updatedIdentityKernelJson = require('../dist/contracts/UpdatedIdentityKernel.json'); - const TestUtils = require("../utils/testUtils.js") const idUtils = require("../utils/identityUtils.js") diff --git a/test/identity.js b/test/identity.js index 39f5422..25a8aad 100644 --- a/test/identity.js +++ b/test/identity.js @@ -1,8 +1,4 @@ -const assert = require('assert'); -const Embark = require('embark'); -let EmbarkSpec = Embark.initTests(); -let web3 = EmbarkSpec.web3; const TestUtils = require("../utils/testUtils.js"); const idUtils = require('../utils/identityUtils.js');