diff --git a/contracts/identity/ERC725.sol b/contracts/identity/ERC725.sol index 8d2d25e..3c8f5e1 100644 --- a/contracts/identity/ERC725.sol +++ b/contracts/identity/ERC725.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.4.17; +pragma solidity ^0.4.18; contract ERC725 { @@ -6,19 +6,24 @@ contract ERC725 { uint256 constant ACTION_KEY = 2; uint256 constant CLAIM_SIGNER_KEY = 3; uint256 constant ENCRYPTION_KEY = 4; + + event KeyAdded(bytes32 indexed key, uint256 indexed purpose, uint256 indexed keyType); + event KeyRemoved(bytes32 indexed key, uint256 indexed purpose, uint256 indexed keyType); + event ExecutionRequested(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data); + event Executed(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data); + event Approved(uint256 indexed executionId, bool approved); - event KeyAdded(address indexed key, uint256 indexed keyType); - event KeyRemoved(address indexed key, uint256 indexed keyType); - event KeyReplaced(address indexed oldKey, address indexed newKey, uint256 indexed keyType); - event ExecutionRequested(bytes32 indexed executionId, address indexed to, uint256 indexed value, bytes data); - event Executed(bytes32 indexed executionId, address indexed to, uint256 indexed value, bytes data); - event Approved(bytes32 indexed executionId, bool approved); + struct Key { + uint256 purpose; //e.g., MANAGEMENT_KEY = 1, ACTION_KEY = 2, etc. + uint256 keyType; // e.g. 1 = ECDSA, 2 = RSA, etc. + bytes32 key; + } - function getKeyType(address _key) public constant returns(uint256 keyType); - function getKeysByType(uint256 _type) public constant returns(address[]); - function addKey(address _key, uint256 _type) public returns (bool success); - function removeKey(address _key) public returns (bool success); - function replaceKey(address _oldKey, address _newKey) public returns (bool success); - function execute(address _to, uint256 _value, bytes _data) public returns (bytes32 executionId); - function approve(bytes32 _id, bool _approve) public returns (bool success); + function getKey(bytes32 _key, uint256 _purpose) public constant returns(uint256 purpose, uint256 keyType, bytes32 key); + function getKeyPurpose(bytes32 _key) public constant returns(uint256[] purpose); + function getKeysByPurpose(uint256 _purpose) public constant returns(bytes32[] keys); + function addKey(bytes32 _key, uint256 _purpose, uint256 _keyType) public returns (bool success); + function removeKey(bytes32 _key, uint256 _purpose) returns (bool success); + function execute(address _to, uint256 _value, bytes _data) public returns (uint256 executionId); + function approve(uint256 _id, bool _approve) public returns (bool success); } \ No newline at end of file diff --git a/contracts/identity/ERC735.sol b/contracts/identity/ERC735.sol index ea5f8f5..2109d28 100644 --- a/contracts/identity/ERC735.sol +++ b/contracts/identity/ERC735.sol @@ -1,23 +1,23 @@ -pragma solidity ^0.4.17; +pragma solidity ^0.4.18; contract ERC735 { - event ClaimRequested(bytes32 indexed claimId, uint256 indexed claimType, address indexed issuer, uint256 signatureType, bytes signature, bytes claim, string uri); - event ClaimAdded(bytes32 indexed claimId, uint256 indexed claimType, address indexed issuer, uint256 signatureType, bytes signature, bytes claim, string uri); - event ClaimRemoved(bytes32 indexed claimId, uint256 indexed claimType, address indexed issuer, uint256 signatureType, bytes signature, bytes claim, string uri); - event ClaimChanged(bytes32 indexed claimId, uint256 indexed claimType, address indexed issuer, uint256 signatureType, bytes signature, bytes claim, string uri); + event ClaimRequested(bytes32 indexed claimRequestId, uint256 indexed claimType, uint256 scheme, address indexed issuer, bytes signature, bytes data, string uri); + event ClaimAdded(bytes32 indexed claimId, uint256 indexed claimType, uint256 scheme, address indexed issuer, bytes signature, bytes data, string uri); + event ClaimRemoved(bytes32 indexed claimId, uint256 indexed claimType, uint256 scheme, address indexed issuer, bytes signature, bytes data, string uri); + event ClaimChanged(bytes32 indexed claimId, uint256 indexed claimType, uint256 scheme, address indexed issuer, bytes signature, bytes data, string uri); struct Claim { uint256 claimType; + uint256 scheme; address issuer; // msg.sender - uint256 signatureType; // The type of signature - bytes signature; // this.address + claimType + claim - bytes claim; + bytes signature; // this.address + claimType + data + bytes data; string uri; } - function getClaim(bytes32 _claimId) public constant returns(uint256 claimType, address issuer, uint256 signatureType, bytes signature, bytes claim, string uri); - function getClaimsIdByType(uint256 _claimType) public constant returns(bytes32[]); - function addClaim(uint256 _claimType, address issuer, uint256 signatureType, bytes _signature, bytes _claim, string _uri) public returns (bytes32 claimId); + function getClaim(bytes32 _claimId) public constant returns(uint256 claimType, uint256 scheme, address issuer, bytes signature, bytes data, string uri); + function getClaimIdsByType(uint256 _claimType) public constant returns(bytes32[] claimIds); + function addClaim(uint256 _claimType, uint256 _scheme, address _issuer, bytes _signature, bytes _data, string _uri) public returns (bytes32 claimRequestId); function removeClaim(bytes32 _claimId) public returns (bool success); } \ No newline at end of file diff --git a/contracts/identity/Identity.sol b/contracts/identity/Identity.sol index 30f903f..13c5357 100644 --- a/contracts/identity/Identity.sol +++ b/contracts/identity/Identity.sol @@ -1,214 +1,281 @@ - pragma solidity ^0.4.17; +pragma solidity ^0.4.17; - import "./ERC725.sol"; - import "./ERC735.sol"; - - contract Identity is ERC725, ERC735 { - - mapping (address => uint256) keys; - mapping (bytes32 => Claim) claims; - mapping (uint256 => address[]) keysByType; - mapping (uint256 => bytes32[]) claimsByType; - mapping (bytes32 => uint256) indexes; - mapping (bytes32 => Transaction) txx; - - uint nonce = 0; - - struct Transaction { - address to; - uint value; - bytes data; - uint nonce; - } +import "./ERC725.sol"; +import "./ERC735.sol"; - modifier managerOnly { - require(keys[msg.sender] == MANAGEMENT_KEY); - _; - } +contract Identity is ERC725, ERC735 { - modifier managerOrSelf { - require(keys[msg.sender] == MANAGEMENT_KEY || msg.sender == address(this)); - _; - } - - modifier actorOnly { - require(keys[msg.sender] == ACTION_KEY); - _; - } - - modifier claimSignerOnly { - require(keys[msg.sender] == CLAIM_SIGNER_KEY); - _; - } - - - function Identity() public { - _addKey(msg.sender, MANAGEMENT_KEY); - } - - - function addKey(address _key, uint256 _type) public managerOrSelf returns (bool success) { - _addKey(_key, _type); - } - - - function removeKey(address _key) public managerOrSelf returns (bool success) { - _removeKey(_key); - } - - - function replaceKey(address _oldKey, address _newKey) public managerOrSelf returns (bool success) { - _addKey(_newKey, getKeyType(_oldKey)); - _removeKey(_oldKey); - return true; - } - - - - function execute( - address _to, - uint256 _value, - bytes _data - ) - public - returns (bytes32 executionId) - { - uint256 senderKey = keys[msg.sender]; - require(senderKey == MANAGEMENT_KEY || senderKey == ACTION_KEY); - executionId = keccak256(_to, _value, _data, nonce); - ExecutionRequested(executionId, _to, _value, _data); - txx[executionId] = Transaction ( - { - to: _to, - value: _value, - data: _data, - nonce: nonce - }); - if (senderKey == MANAGEMENT_KEY) { - approve(executionId, true); - } - } - - function approve( - bytes32 _id, - bool _approve - ) - public - managerOnly - returns (bool success) - { - require(txx[_id].nonce == nonce); - nonce++; - if (_approve) { - success = txx[_id].to.call.value(txx[_id].value)(txx[_id].data); - } - } - - - function addClaim( - uint256 _claimType, - address _issuer, - uint256 _signatureType, - bytes _signature, - bytes _claim, - string _uri - ) - public - claimSignerOnly - returns (bytes32 claimId) - { - claimId = keccak256(_issuer, _claimType); - claims[claimId] = Claim( - { - claimType: _claimType, - issuer: _issuer, - signatureType: _signatureType, - signature: _signature, - claim: _claim, - uri: _uri - } - ); - indexes[keccak256(_issuer, _claimType)] = claimsByType[_claimType].length; - claimsByType[_claimType].push(claimId); - } - - - function removeClaim(bytes32 _claimId) public returns (bool success) { - Claim memory c = claims[_claimId]; - require(msg.sender == c.issuer || keys[msg.sender] == MANAGEMENT_KEY || msg.sender == address(this)); - uint claimIdTypePos = indexes[_claimId]; - delete indexes[_claimId]; - bytes32[] storage claimsTypeArr = claimsByType[c.claimType]; - bytes32 replacer = claimsTypeArr[claimsTypeArr.length-1]; - claimsTypeArr[claimIdTypePos] = replacer; - indexes[replacer] = claimIdTypePos; - delete claims[_claimId]; - claimsTypeArr.length--; - return true; - } - - - function _addKey(address _key, uint256 _type) private { - require(keys[_key] == 0); - KeyAdded(_key, _type); - keys[_key] = _type; - indexes[keccak256(_key, _type)] = keysByType[_type].length; - keysByType[_type].push(_key); - } - - - function _removeKey(address _key) private { - uint256 kType = keys[_key]; - KeyRemoved(_key, kType); - address[] storage keyArr = keysByType[kType]; - if (msg.sender != address(this) && kType == MANAGEMENT_KEY && keyArr.length == 1) { - revert(); - } - bytes32 oldIndex = keccak256(_key, kType); - uint index = indexes[oldIndex]; - delete indexes[oldIndex]; - address replacer = keyArr[keyArr.length-1]; - keyArr[index] = replacer; - indexes[keccak256(replacer, keys[replacer])] = index; - keyArr.length--; - delete keys[_key]; - } - - - function getKeyType(address _key) public constant returns(uint256 keyType) { - return keys[_key]; - } - - - function getKeysByType(uint256 _type) public constant returns(address[]) { - return keysByType[_type]; - } - - - function getClaim( - bytes32 _claimId - ) - public - constant - returns - (uint256 claimType, - address issuer, - uint256 signatureType, - bytes signature, - bytes claim, - string uri) - { - Claim memory _claim = claims[_claimId]; - return (_claim.claimType, _claim.issuer, _claim.signatureType, _claim.signature, _claim.claim, _claim.uri); - } - - - function getClaimsIdByType(uint256 _claimType) public constant returns(bytes32[]) { - return claimsByType[_claimType]; - } + mapping (bytes32 => Key) keys; + mapping (bytes32 => Claim) claims; + mapping (uint256 => bytes32[]) keysByPurpose; + mapping (uint256 => bytes32[]) claimsByType; + mapping (bytes32 => uint256) indexes; + mapping (uint => Transaction) txx; + mapping (uint256 => uint8) minimumApprovalsByKeyType; + bytes32[] pendingTransactions; + + uint nonce = 0; + struct Transaction { + address to; + uint value; + bytes data; + uint nonce; + + uint approverCount; + mapping(uint256 => uint8) approvalsByKeyType; + mapping(bytes32 => bool) approvals; } + modifier managerOnly { + require(keys[keccak256(bytes32(msg.sender), MANAGEMENT_KEY)].purpose == MANAGEMENT_KEY); + _; + } + + modifier managerOrSelf { + require(keys[keccak256(bytes32(msg.sender), MANAGEMENT_KEY)].purpose == MANAGEMENT_KEY || msg.sender == address(this)); + _; + } + + modifier actorOnly { + require(keys[keccak256(bytes32(msg.sender), ACTION_KEY)].purpose == ACTION_KEY); + _; + } + + modifier claimSignerOnly { + require(keys[keccak256(bytes32(msg.sender), CLAIM_SIGNER_KEY)].purpose == CLAIM_SIGNER_KEY); + _; + } + + modifier managerOrActor { + require(keys[keccak256(bytes32(msg.sender), MANAGEMENT_KEY)].purpose == MANAGEMENT_KEY + || keys[keccak256(bytes32(msg.sender), ACTION_KEY)].purpose == ACTION_KEY + || msg.sender == address(this)); + _; + } + + function Identity() public { + _addKey(bytes32(msg.sender), MANAGEMENT_KEY, 1); + minimumApprovalsByKeyType[MANAGEMENT_KEY] = 1; + } + + function addKey(bytes32 _key, uint256 _purpose, uint256 _type) public managerOrSelf returns (bool success) { + _addKey(_key, _purpose, _type); + return true; + } + + function removeKey(bytes32 _key, uint256 _purpose) public managerOrSelf returns (bool success) { + _removeKey(_key, _purpose); + return true; + } + + function execute(address _to, uint256 _value, bytes _data) + public + managerOrActor + returns (uint256 executionId) + { + executionId = nonce; + ExecutionRequested(executionId, _to, _value, _data); + txx[executionId] = Transaction( + { + to: _to, + value: _value, + data: _data, + nonce: nonce, + approverCount: 0 + }); + nonce++; + } + + function approve(uint256 _id, bool _approve) + public + managerOrActor + returns (bool success) + { + Transaction storage trx = txx[_id]; + + bytes32 managerKeyHash = keccak256(bytes32(msg.sender), MANAGEMENT_KEY); + bytes32 actorKeyHash = keccak256(bytes32(msg.sender), ACTION_KEY); + + uint8 approvalCount; + uint256 requiredKeyType; + + if (trx.to == address(this)) { + requiredKeyType = MANAGEMENT_KEY; + if (keys[managerKeyHash].purpose == MANAGEMENT_KEY) { + approvalCount = _calculateApprovals(managerKeyHash, MANAGEMENT_KEY, _approve, trx); + } + } else { + requiredKeyType = ACTION_KEY; + if (keys[managerKeyHash].purpose == ACTION_KEY) { + approvalCount = _calculateApprovals(actorKeyHash, ACTION_KEY, _approve, trx); + } + } + + if (approvalCount >= minimumApprovalsByKeyType[requiredKeyType]) + success = trx.to.call.value(txx[_id].value)(txx[_id].data); + + } + + function setMiminumApprovalsByKeyType(uint256 _type, uint8 _minimumApprovals) public managerOrSelf { + minimumApprovalsByKeyType[_type] = _minimumApprovals; + } + + function _calculateApprovals(bytes32 _keyHash, uint256 _keyType, bool _approve, Transaction storage trx) + private + returns (uint8 approvalCount) + { + if (trx.approvals[_keyHash] == false && _approve){ + trx.approvalsByKeyType[_keyType]++; + } else if (trx.approvals[_keyHash] == true && !_approve && trx.approverCount > 0) { + trx.approvalsByKeyType[_keyType]--; + } + trx.approvals[_keyHash] = _approve; + trx.approverCount++; + return trx.approvalsByKeyType[_keyType]; + } + + function addClaim(uint256 _claimType, uint256 _scheme, address _issuer, bytes _signature, bytes _data, string _uri) + public + claimSignerOnly + returns (bytes32 claimRequestId) + { + + bytes32 claimHash = keccak256(_issuer, _claimType); + + claimRequestId = claimHash; + + if (claims[claimHash].claimType > 0) { + // Claim existed + ClaimChanged(claimRequestId, _claimType, _scheme, _issuer, _signature, _data, _uri); + } else { + // TODO Triggers if the claim is new Event and approval process exists: ClaimRequested + ClaimRequested(claimRequestId, _claimType, _scheme, _issuer, _signature, _data, _uri); + } + + claims[claimHash] = Claim( + { + claimType: _claimType, + scheme: _scheme, + issuer: _issuer, + signature: _signature, + data: _data, + uri: _uri + } + ); + + indexes[claimHash] = claimsByType[_claimType].length; + + claimsByType[_claimType].push(claimRequestId); + + // TODO This SHOULD create a pending claim, which SHOULD to be approved or rejected by n of m approve calls from keys of purpose 1. + } + + function removeClaim(bytes32 _claimId) public returns (bool success) { + Claim memory c = claims[_claimId]; + + require(msg.sender == c.issuer + || msg.sender == address(this) + || keys[keccak256(bytes32(msg.sender), MANAGEMENT_KEY)].purpose == MANAGEMENT_KEY); + + // MUST only be done by the issuer of the claim, or KEYS OF PURPOSE 1, or the identity itself. + // TODO If its the identity itself, the approval process will determine its approval. + + uint claimIdTypePos = indexes[_claimId]; + delete indexes[_claimId]; + bytes32[] storage claimsTypeArr = claimsByType[c.claimType]; + bytes32 replacer = claimsTypeArr[claimsTypeArr.length-1]; + claimsTypeArr[claimIdTypePos] = replacer; + indexes[replacer] = claimIdTypePos; + delete claims[_claimId]; + claimsTypeArr.length--; + return true; + } + + function _addKey(bytes32 _key, uint256 _purpose, uint256 _type) private { + bytes32 keyHash = keccak256(_key, _purpose); + + require(keys[keyHash].purpose == 0); + require(_purpose == MANAGEMENT_KEY || _purpose == ACTION_KEY + || _purpose == CLAIM_SIGNER_KEY || _purpose == ENCRYPTION_KEY); + KeyAdded(_key, _purpose, _type); + keys[keyHash] = Key(_purpose, _type, _key); + indexes[keyHash] = keysByPurpose[_purpose].push(_key) - 1; + } + + function _removeKey(bytes32 _key, uint256 _purpose) private { + bytes32 keyHash = keccak256(_key, _purpose); + Key storage myKey = keys[keyHash]; + KeyRemoved(myKey.key, myKey.purpose, myKey.keyType); + + uint index = indexes[keyHash]; + delete indexes[keyHash]; + bytes32 replacer = keysByPurpose[_purpose][keysByPurpose[_purpose].length - 1]; + keysByPurpose[_purpose][index] = replacer; + indexes[ keccak256(replacer, _purpose)] = index; + keysByPurpose[_purpose].length--; + + if (_purpose == MANAGEMENT_KEY) { + require(keysByPurpose[MANAGEMENT_KEY].length >= 1); + } + + delete keys[keyHash]; + + // MUST only be done by keys of purpose 1, or the identity itself. + // TODO If its the identity itself, the approval process will determine its approval. + } + + function getKey(bytes32 _key, uint256 _purpose) public constant returns(uint256 purpose, uint256 keyType, bytes32 key) { + Key storage myKey = keys[keccak256(_key, _purpose)]; + return (myKey.purpose, myKey.keyType, myKey.key); + } + + function getKeyPurpose(bytes32 _key) public constant returns(uint256[] purpose) { + + uint256[] memory purposeHolder = new uint256[](4); + uint8 counter = 0; + + if (keys[keccak256(_key, MANAGEMENT_KEY)].purpose == MANAGEMENT_KEY) { + purposeHolder[counter] = MANAGEMENT_KEY; + counter++; + } + + if (keys[keccak256(_key, ACTION_KEY)].purpose == ACTION_KEY) { + purposeHolder[counter] = ACTION_KEY; + counter++; + } + + if (keys[keccak256(_key, CLAIM_SIGNER_KEY)].purpose == CLAIM_SIGNER_KEY) { + purposeHolder[counter] = CLAIM_SIGNER_KEY; + counter++; + } + + if (keys[keccak256(_key, ENCRYPTION_KEY)].purpose == ENCRYPTION_KEY) { + purposeHolder[counter] = ENCRYPTION_KEY; + counter++; + } + + uint256[] memory result = new uint256[](counter); + for (uint8 i = 0; i < counter; i++) + result[i] = purposeHolder[i]; + + return result; + } + + function getKeysByPurpose(uint256 _purpose) public constant returns(bytes32[] keys) { + return keysByPurpose[_purpose]; + } + + function getClaim(bytes32 _claimId) public constant returns(uint256 claimType, uint256 scheme, address issuer, bytes signature, bytes data, string uri) { + Claim memory _claim = claims[_claimId]; + return (_claim.claimType, _claim.scheme, _claim.issuer, _claim.signature, _claim.data, _claim.uri); + } + + function getClaimIdsByType(uint256 _claimType) public constant returns(bytes32[] claimIds) { + return claimsByType[_claimType]; + } +} + diff --git a/test/identity.js b/test/identity.js index 55a046d..60d7c25 100644 --- a/test/identity.js +++ b/test/identity.js @@ -4,18 +4,18 @@ const Identity = artifacts.require("./identity/Identity.sol"); contract('Identity', function(accounts) { let identity; + beforeEach(async () => { identity = await Identity.new({from: accounts[0]}) }) describe("Identity()", () => { - it("initialize with msg.sender as management key", async () => { assert.equal( - await identity.getKeyType(accounts[0]), + await identity.getKeyPurpose(TestUtils.addressToBytes32(accounts[0])), 1, - identity.address+".getKeyType("+accounts[0]+") is not MANAGEMENT_KEY") + identity.address + ".getKeyPurpose("+accounts[0]+") is not MANAGEMENT_KEY") }); }); @@ -24,33 +24,33 @@ contract('Identity', function(accounts) { describe("addKey(address _key, uint256 _type)", () => { it("MANAGEMENT_KEY add a new address as ACTION_KEY", async () => { - await identity.addKey(accounts[1], 2, {from: accounts[0]}) + await identity.addKey(TestUtils.addressToBytes32(accounts[1]), 2, 1, {from: accounts[0]}) assert.equal( - await identity.getKeyType(accounts[1]), + await identity.getKeyPurpose(TestUtils.addressToBytes32(accounts[1])), 2, - identity.address+".getKeyType("+accounts[1]+") is not ACTION_KEY") + identity.address+".getKeyPurpose("+accounts[1]+") is not ACTION_KEY") }); it("should not add key by non manager", async () => { try { - await identity.addKey(accounts[1], 1, {from: accounts[2]}) + await identity.addKey(TestUtils.addressToBytes32(accounts[1]), 1, 1, {from: accounts[2]}) }catch(e){ } assert.equal( - await identity.getKeyType(accounts[1]), + await identity.getKeyPurpose(TestUtils.addressToBytes32(accounts[1])), 0, - identity.address+".getKeyType("+accounts[1]+") is not correct") + identity.address+".getKeyPurpose("+accounts[1]+") is not correct") }); it("should not add key type 1 by actor", async () => { - await identity.addKey(accounts[2], 2, {from: accounts[0]}) + await identity.addKey(TestUtils.addressToBytes32(accounts[2]), 2, 1, {from: accounts[0]}) try { - await identity.addKey(accounts[1], 1, {from: accounts[2]}) + await identity.addKey(TestUtils.addressToBytes32(accounts[1]), 1, 1, {from: accounts[2]}) } catch(e){ } assert.equal( - await identity.getKeyType(accounts[1]), + await identity.getKeyPurpose(TestUtils.addressToBytes32(accounts[1])), 0, identity.address+".getKeyType("+accounts[1]+") is not correct") }); @@ -58,9 +58,9 @@ contract('Identity', function(accounts) { it("fire KeyAdded(address indexed key, uint256 indexed type)", async () => { - identity.addKey(accounts[1], 2, {from: accounts[0]}) + identity.addKey(TestUtils.addressToBytes32(accounts[1]), 2, 1, {from: accounts[0]}) const keyAdded = await TestUtils.listenForEvent(identity.KeyAdded()) - assert(keyAdded.key, accounts[1], "Key is not correct") + assert(keyAdded.key, TestUtils.addressToBytes32(accounts[1]), "Key is not correct") assert(keyAdded.keyType, 2, "Type is not correct") }); @@ -70,100 +70,101 @@ contract('Identity', function(accounts) { describe("removeKey(address _key, uint256 _type)", () => { it("MANAGEMENT_KEY should removes a key", async () => { - await identity.addKey(accounts[1], 1, {from: accounts[0]}) - await identity.removeKey(accounts[0], {from: accounts[1]}) + await identity.addKey(TestUtils.addressToBytes32(accounts[1]), 1, 1, {from: accounts[0]}) + await identity.removeKey(TestUtils.addressToBytes32(accounts[0]), 1, {from: accounts[1]}) assert.equal( - await identity.getKeyType(accounts[0]), + await identity.getKeyPurpose(TestUtils.addressToBytes32(accounts[0])), 0, - identity.address+".getKeyType("+accounts[0]+") is not 0") + identity.address+".getKeyPurpose("+accounts[0]+") is not 0") }); it("other key should not removes a key", async () => { - await identity.addKey(accounts[1], 1, {from: accounts[0]}) + await identity.addKey(TestUtils.addressToBytes32(accounts[1]), 1, 1, {from: accounts[0]}) try { - await identity.removeKey(accounts[1], {from: accounts[2]}) + await identity.removeKey(TestUtils.addressToBytes32(accounts[1]), 1, {from: accounts[2]}) }catch (e) { } assert.equal( - await identity.getKeyType(accounts[1]), + await identity.getKeyPurpose(TestUtils.addressToBytes32(accounts[1])), 1, - identity.address+".getKeyType("+accounts[1]+") is not 0") + identity.address+".getKeyPurpose("+accounts[1]+") is not 0") }); it("actor key should not remove key", async () => { - await identity.addKey(accounts[1], 2, {from: accounts[0]}) - await identity.addKey(accounts[2], 2, {from: accounts[0]}) + await identity.addKey(TestUtils.addressToBytes32(accounts[1]), 2, 1, {from: accounts[0]}) + await identity.addKey(TestUtils.addressToBytes32(accounts[2]), 2, 1, {from: accounts[0]}) try { - await identity.removeKey(accounts[1], {from: accounts[2]}) + await identity.removeKey(TestUtils.addressToBytes32(accounts[1]), 1, {from: accounts[2]}) }catch (e) { } assert.equal( - await identity.getKeyType(accounts[1]), + await identity.getKeyPurpose(TestUtils.addressToBytes32(accounts[1])), 2, identity.address+".getKeyType("+accounts[1]+") is not 0") }); it("MANAGEMENT_KEY should not remove itself MANAGEMENT_KEY when there is no other MANAGEMENT_KEY", async () => { - try { - await identity.removeKey(accounts[0], {from: accounts[0]}) - } catch(e) { - //nothing + let assertJump = (error) => { + assert.isAbove(error.message.search('revert'), -1, 'Revert should happen'); } - assert.equal( - await identity.getKeyType(accounts[0]), - 1, - identity.address+".getKeyType("+accounts[0]+") is not MANAGEMENT_KEY") - + try { + await identity.removeKey(TestUtils.addressToBytes32(accounts[0]), 1, {from: accounts[0]}); + assert.fail('should have reverted before'); + } catch(error) { + assertJump(error); + } + + }); it("fire KeyRemoved(address indexed key, uint256 indexed type)", async () => { - await identity.addKey(accounts[1], 2, {from: accounts[0]}) - identity.removeKey(accounts[1], {from: accounts[0]}) + await identity.addKey(TestUtils.addressToBytes32(accounts[1]), 2, 1,{from: accounts[0]}) + identity.removeKey(TestUtils.addressToBytes32(accounts[1]), 2, {from: accounts[0]}) const keyRemoved = await TestUtils.listenForEvent(identity.KeyRemoved()) - assert(keyRemoved.key, accounts[1], "Key is not correct") + assert(keyRemoved.key, TestUtils.addressToBytes32(accounts[1]), "Key is not correct") assert(keyRemoved.keyType, 2, "Type is not correct") }); }); - describe("getKeyType(address _key)", () => { + describe("getKeyPurpose(address _key)", () => { it("should start only with initializer as only key", async () => { assert.equal( - await identity.getKeyType(accounts[0]), + await identity.getKeyPurpose(TestUtils.addressToBytes32(accounts[0])), 1, - identity.address+".getKeyType("+accounts[0]+") is not correct") + identity.address+".getKeyPurpose("+accounts[0]+") is not correct") assert.equal( - await identity.getKeyType(accounts[1]), + await identity.getKeyPurpose(TestUtils.addressToBytes32(accounts[1])), 0, - identity.address+".getKeyType("+accounts[1]+") is not correct") + identity.address+".getKeyPurpose("+accounts[1]+") is not correct") }); it("should get type 2 after addKey type 2", async () => { - await identity.addKey(accounts[1], 2, {from: accounts[0]}) + await identity.addKey(TestUtils.addressToBytes32(accounts[1]), 2, 1, {from: accounts[0]}) assert.equal( - await identity.getKeyType(accounts[1]), + await identity.getKeyPurpose(TestUtils.addressToBytes32(accounts[1])), 2, - identity.address+".getKeyType("+accounts[1]+") is not correct") + identity.address+".getKeyPurpose("+accounts[1]+") is not correct") }); - it("should get type 999 after addKey type 999", async () => { - await identity.addKey(accounts[1], 999, {from: accounts[0]}) + it("should get type 3 after addKey type 3", async () => { + await identity.addKey(TestUtils.addressToBytes32(accounts[1]), 3, 1, {from: accounts[0]}) assert.equal( - await identity.getKeyType(accounts[1]), - 999, - identity.address+".getKeyType("+accounts[1]+") is not correct") + await identity.getKeyPurpose(TestUtils.addressToBytes32(accounts[1])), + 3, + identity.address+".getKeyPurpose("+accounts[1]+") is not correct") }); }); - + describe("getKeysByType(uint256 _type)", () => { it("at initialization", async () => { @@ -185,30 +186,6 @@ contract('Identity', function(accounts) { }); - describe("replaceKey(address _oldKey, address _newKey)", () => { - - it("MANAGEMENT_KEY replace itself (alone)", async () => { - - }); - - it("MANAGEMENT_KEY replace a key between others", async () => { - - }); - - it("MANAGEMENT_KEY replace the first key", async () => { - - }); - - it("MANAGEMENT_KEY replace the last key", async () => { - - }); - - it("fire KeyReplaced(address indexed oldKey, address indexed newKey, uint256 indexed type)", async () => { - - }); - - }); - describe("execute(address _to, uint256 _value, bytes _data)", () => { @@ -282,5 +259,5 @@ contract('Identity', function(accounts) { }); }); - + });