- Updated logic on Identity.sol to reflect changes on EIPs
- Added migration to deploy Identity contract - Updated existing test cases to reflect changes on contract interface
This commit is contained in:
parent
12d3a4d8a9
commit
3448401247
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
131
test/identity.js
131
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) {
|
|||
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue