- Fixing typo in Identity.sol

- Reorganizing javascript files used in tests
- Cleaned up unit tests
- Created identityUtils.js to encode function calls sent in execute();
This commit is contained in:
Richard Ramos 2018-03-01 11:42:44 -04:00
parent 3c4f2ab7d1
commit 5ee487a48a
5 changed files with 291 additions and 85 deletions

View File

@ -138,7 +138,7 @@ contract Identity is ERC725, ERC735 {
}
}
function setMininumApprovalsByKeyType(
function setMinimumApprovalsByKeyType(
uint256 _type,
uint8 _minimumApprovals
)

View File

@ -1,4 +1,5 @@
const TestUtils = require("./TestUtils.js")
const TestUtils = require("../utils/testUtils.js")
const idUtils = require("../utils/identityUtils.js")
const web3EthAbi = require("web3-eth-abi");
const Identity = artifacts.require("./identity/Identity.sol");
@ -27,15 +28,18 @@ contract('IdentityFactory', function(accounts) {
assert.equal(
await identity.getKeyPurpose(TestUtils.addressToBytes32(accounts[0])),
1,
idUtils.purposes.MANAGEMENT,
identity.address + ".getKeyPurpose("+accounts[0]+") is not MANAGEMENT_KEY")
});
it("Registers a updated identity contract", async() => {
const infoHash = "0xbbb";
updatedIdentityKernel = await UpdatedIdentityKernel.new({from: accounts[0]});
let tx = await identityFactory.setKernel(updatedIdentityKernel.address, "0xbbb");
assert.strictEqual(tx.logs[0].event, "NewKernel");
await identityFactory.setKernel(updatedIdentityKernel.address, infoHash);
const newKernel = await TestUtils.listenForEvent(identityFactory.NewKernel());
assert(newKernel.infohash, infoHash, "Infohash is not correct");
});
@ -58,16 +62,12 @@ contract('IdentityFactory', function(accounts) {
it("Updates an identity to the latest version", async() => {
let functionPayload = web3EthAbi.encodeFunctionCall({
name: 'updateUpdatableInstance',
type: 'function',
inputs: [{
type: 'address',
name: '_kernel'
}]
}, [updatedIdentityKernel.address]);
let tx1 = await identity.execute(identity.address, 0, functionPayload, {from: accounts[0]} );
let tx1 = await identity.execute(
identity.address,
0,
idUtils.encode.updateUpdatableInstance(updatedIdentityKernel.address),
{from: accounts[0]}
);
assert.strictEqual(tx1.logs[tx1.logs.length - 1].event, "Executed");
// Calling function available in updated identity kernel
@ -75,7 +75,6 @@ contract('IdentityFactory', function(accounts) {
let tx2 = await updatedIdentity1.test({from: accounts[0]});
assert.strictEqual(tx2.logs[tx2.logs.length - 1].event, "TestFunctionExecuted");
assert.equal(
tx2.logs[tx2.logs.length - 1].args.minApprovalsByManagementKeys.toString(10),
1,

View File

@ -1,4 +1,7 @@
const TestUtils = require("./TestUtils.js")
const TestUtils = require("../utils/testUtils.js")
const web3EthAbi = require("web3-eth-abi");
const idUtils = require('../utils/identityUtils.js');
const Identity = artifacts.require("./identity/Identity.sol");
contract('Identity', function(accounts) {
@ -9,129 +12,200 @@ contract('Identity', function(accounts) {
identity = await Identity.new({from: accounts[0]})
})
describe("Identity()", () => {
it("initialize with msg.sender as management key", async () => {
assert.equal(
await identity.getKeyPurpose(TestUtils.addressToBytes32(accounts[0])),
1,
idUtils.purposes.MANAGEMENT,
identity.address + ".getKeyPurpose("+accounts[0]+") is not MANAGEMENT_KEY")
});
});
describe("addKey(address _key, uint256 _type)", () => {
it("MANAGEMENT_KEY add a new address as ACTION_KEY", async () => {
await identity.addKey(TestUtils.addressToBytes32(accounts[1]), 2, 1, {from: accounts[0]})
await identity.execute(
identity.address,
0,
idUtils.encode.addKey(accounts[1], idUtils.purposes.ACTION, idUtils.types.ADDRESS),
{from: accounts[0]}
);
assert.equal(
await identity.getKeyPurpose(TestUtils.addressToBytes32(accounts[1])),
2,
idUtils.purposes.ACTION,
identity.address+".getKeyPurpose("+accounts[1]+") is not ACTION_KEY")
});
it("should not add key by non manager", async () => {
try {
await identity.addKey(TestUtils.addressToBytes32(accounts[1]), 1, 1, {from: accounts[2]})
}catch(e){
await identity.execute(
identity.address,
0,
idUtils.encode.addKey(accounts[1], idUtils.purposes.MANAGEMENT, idUtils.types.ADDRESS),
{from: accounts[2]}
);
assert.fail('should have reverted before');
} catch(error) {
TestUtils.assertJump(error);
}
assert.equal(
await identity.getKeyPurpose(TestUtils.addressToBytes32(accounts[1])),
0,
idUtils.purposes.NONE,
identity.address+".getKeyPurpose("+accounts[1]+") is not correct")
});
it("should not add key type 1 by actor", async () => {
await identity.addKey(TestUtils.addressToBytes32(accounts[2]), 2, 1, {from: accounts[0]})
try {
await identity.addKey(TestUtils.addressToBytes32(accounts[1]), 1, 1, {from: accounts[2]})
} catch(e){
}
await identity.execute(
identity.address,
0,
idUtils.encode.addKey(accounts[2], idUtils.purposes.ACTION, idUtils.types.ADDRESS),
{from: accounts[0]}
);
await identity.execute(
identity.address,
0,
idUtils.encode.addKey(accounts[1], idUtils.purposes.MANAGEMENT, idUtils.types.ADDRESS),
{from: accounts[2]}
);
assert.equal(
await identity.getKeyPurpose(TestUtils.addressToBytes32(accounts[1])),
0,
idUtils.purposes.NONE,
identity.address+".getKeyType("+accounts[1]+") is not correct")
});
it("fire KeyAdded(address indexed key, uint256 indexed type)", async () => {
identity.addKey(TestUtils.addressToBytes32(accounts[1]), 2, 1, {from: accounts[0]})
await identity.execute(
identity.address,
0,
idUtils.encode.addKey(accounts[1], idUtils.purposes.MANAGEMENT, idUtils.types.ADDRESS),
{from: accounts[0]}
);
const keyAdded = await TestUtils.listenForEvent(identity.KeyAdded())
assert(keyAdded.key, TestUtils.addressToBytes32(accounts[1]), "Key is not correct")
assert(keyAdded.keyType, 2, "Type is not correct")
assert(keyAdded.keyType, idUtils.types.ADDRESS, "Type is not correct")
});
});
describe("removeKey(address _key, uint256 _type)", () => {
it("MANAGEMENT_KEY should removes a key", async () => {
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.getKeyPurpose(TestUtils.addressToBytes32(accounts[0])),
it("MANAGEMENT_KEY should remove a key", async () => {
await identity.execute(
identity.address,
0,
identity.address+".getKeyPurpose("+accounts[0]+") is not 0")
});
idUtils.encode.addKey(accounts[1], idUtils.purposes.MANAGEMENT, idUtils.types.ADDRESS),
{from: accounts[0]}
);
await identity.execute(
identity.address,
0,
idUtils.encode.removeKey(accounts[1], idUtils.purposes.MANAGEMENT),
{from: accounts[0]}
);
it("other key should not removes a key", async () => {
await identity.addKey(TestUtils.addressToBytes32(accounts[1]), 1, 1, {from: accounts[0]})
try {
await identity.removeKey(TestUtils.addressToBytes32(accounts[1]), 1, {from: accounts[2]})
}catch (e) {
}
assert.equal(
await identity.getKeyPurpose(TestUtils.addressToBytes32(accounts[1])),
1,
idUtils.purposes.NONE,
identity.address+".getKeyPurpose("+accounts[1]+") is not 0")
});
it("other key should not removes a key", async () => {
await identity.execute(
identity.address,
0,
idUtils.encode.addKey(accounts[1], idUtils.purposes.MANAGEMENT, idUtils.types.ADDRESS),
{from: accounts[0]}
);
try {
await identity.execute(
identity.address,
0,
idUtils.encode.removeKey(accounts[1], idUtils.purposes.MANAGEMENT),
{from: accounts[2]}
);
assert.fail('should have reverted before');
} catch(error) {
TestUtils.assertJump(error);
}
assert.equal(
await identity.getKeyPurpose(TestUtils.addressToBytes32(accounts[1])),
idUtils.purposes.MANAGEMENT,
identity.address+".getKeyPurpose("+accounts[1]+") is not 0")
});
it("actor key should not remove key", async () => {
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(TestUtils.addressToBytes32(accounts[1]), 1, {from: accounts[2]})
}catch (e) {
await identity.execute(
identity.address,
0,
idUtils.encode.addKey(accounts[1], idUtils.purposes.ACTION, idUtils.types.ADDRESS),
{from: accounts[0]}
);
await identity.execute(
identity.address,
0,
idUtils.encode.addKey(accounts[2], idUtils.purposes.ACTION, idUtils.types.ADDRESS),
{from: accounts[0]}
);
await identity.execute(
identity.address,
0,
idUtils.encode.removeKey(accounts[1], idUtils.purposes.ACTION),
{from: accounts[2]}
);
}
assert.equal(
await identity.getKeyPurpose(TestUtils.addressToBytes32(accounts[1])),
2,
idUtils.purposes.ACTION,
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 () => {
let assertJump = (error) => {
assert.isAbove(error.message.search('revert'), -1, 'Revert should happen');
}
try {
await identity.removeKey(TestUtils.addressToBytes32(accounts[0]), 1, {from: accounts[0]});
assert.fail('should have reverted before');
} catch(error) {
assertJump(error);
}
await identity.execute(
identity.address,
0,
idUtils.encode.removeKey(accounts[0], idUtils.purposes.MANAGEMENT),
{from: accounts[0]}
);
assert.equal(
await identity.getKeyPurpose(TestUtils.addressToBytes32(accounts[0])),
idUtils.purposes.MANAGEMENT,
identity.address+".getKeyType("+accounts[0]+") is not 1")
});
it("fire KeyRemoved(address indexed key, uint256 indexed type)", async () => {
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, TestUtils.addressToBytes32(accounts[1]), "Key is not correct")
assert(keyRemoved.keyType, 2, "Type is not correct")
});
await identity.execute(
identity.address,
0,
idUtils.encode.addKey(accounts[1], idUtils.purposes.ACTION, idUtils.types.ADDRESS),
{from: accounts[0]}
);
await identity.execute(
identity.address,
0,
idUtils.encode.removeKey(accounts[1], idUtils.purposes.ACTION),
{from: accounts[0]}
);
const keyRemoved = await TestUtils.listenForEvent(identity.KeyRemoved());
assert(keyRemoved.key, TestUtils.addressToBytes32(accounts[1]), "Key is not correct");
assert(keyRemoved.keyType, idUtils.types.ADDRESS, "Type is not correct");
});
});
/*
describe("getKeyPurpose(address _key)", () => {
it("should start only with initializer as only key", async () => {
@ -259,5 +333,5 @@ contract('Identity', function(accounts) {
});
});
*/
});

View File

@ -1,9 +1,9 @@
const TestUtils = require("./TestUtils.js")
const TestUtils = require("../utils/testUtils.js")
var ethUtils = require('ethereumjs-util')
const Identity = artifacts.require("./identity/Identity.sol");
contract('Identity', function(accounts) {
contract('Identity - Extended Functionality', function(accounts) {
let identity;

133
utils/identityUtils.js Normal file
View File

@ -0,0 +1,133 @@
const web3EthAbi = require("web3-eth-abi");
const _types = {
ADDRESS: 0,
ECDSA: 1,
RSA: 2
}
const _purposes = {
MANAGEMENT: 1,
ACTION: 2,
CLAIM_SIGNER: 3,
ENCRYPTION: 4,
NONE: 0
}
const hexToBytes32 = (input) => {
input = input.replace(/^0x/i,'');
const stringed = "0000000000000000000000000000000000000000000000000000000000000000" + input;
return "0x" + stringed.substring(stringed.length - 64, stringed.length);
}
const _addKey = function(key, purpose, type){
if(!/^(0x)?[0-9a-f]{0,64}$/i.test(key))
throw new Error('Key "'+ key +'" is not a valid hex string');
if (Object.values(_purposes).indexOf(purpose) == -1)
throw new Error('Purpose "'+ purpose +'" is not a valid purpose');
if (Object.values(_types).indexOf(type) == -1)
throw new Error('Type "'+ type +'" is not a valid type');
return web3EthAbi.encodeFunctionCall({
name: 'addKey',
type: 'function',
inputs: [{
type: 'bytes32',
name: '_key'
},{
type: 'uint256',
name: '_purpose'
},{
type: 'uint256',
name: '_type'
}]
}, [hexToBytes32(key), purpose, type]);
}
const _removeKey = function(key, purpose){
if(!/^(0x)?[0-9a-f]{0,64}$/i.test(key))
throw new Error('Key "'+ key +'" is not a valid hex string');
if (Object.values(_purposes).indexOf(purpose) == -1)
throw new Error('Purpose "'+ purpose +'" is not a valid purpose');
return web3EthAbi.encodeFunctionCall({
name: 'removeKey',
type: 'function',
inputs: [{
type: 'bytes32',
name: '_key'
},{
type: 'uint256',
name: '_purpose'
}]
}, [hexToBytes32(key), purpose]);
}
const _setMinimumApprovalsByKeyType = function(type, minimumApprovals) {
if (Object.values(_types).indexOf(type) == -1)
throw new Error('Type "'+ type +'" is not a valid type');
// TODO valdate minimumApprovals
return web3EthAbi.encodeFunctionCall({
name: 'setMinimumApprovalsByKeyType',
type: 'function',
inputs: [{
type: 'uint256',
name: '_type'
},{
type: 'uint8',
name: '_minimumApprovals'
}]
}, arguments);
}
const _setupRecovery = function(address){
if(!/^(0x)?[0-9a-f]{0,40}$/i.test(address))
throw new Error('Address "'+ address +'" is not a valid Ethereum address.');
return web3EthAbi.encodeFunctionCall({
name: 'setupRecovery',
type: 'function',
inputs: [{
type: 'address',
name: '_recoveryContract'
}]
}, [address]);
}
const _updateUpdatableInstance = function(address){
if(!/^(0x)?[0-9a-f]{0,40}$/i.test(address))
throw new Error('Address "'+ address +'" is not a valid Ethereum address.');
return web3EthAbi.encodeFunctionCall({
name: 'updateUpdatableInstance',
type: 'function',
inputs: [{
type: 'address',
name: '_kernel'
}]
}, [address]);
}
module.exports = {
types: _types,
purposes: _purposes,
encode: {
addKey: _addKey,
removeKey: _removeKey,
setMinimumApprovalsByKeyType: _setMinimumApprovalsByKeyType,
setupRecovery: _setupRecovery,
updateUpdatableInstance: _updateUpdatableInstance
}
}