-
Notifications
You must be signed in to change notification settings - Fork 7
/
KeyHolder.sol
125 lines (100 loc) · 4.04 KB
/
KeyHolder.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
pragma solidity ^0.4.18;
import './ByteArr.sol';
import './ERC725.sol';
contract KeyHolder is ERC725 {
using ByteArr for bytes;
using ByteArr for bytes32[];
using ByteArr for uint256[];
uint256 executionNonce;
mapping (bytes32 => Key) keys;
mapping (uint256 => bytes32[]) keysByPurpose;
mapping (uint256 => Execution) executions;
constructor() public {
bytes32 _key = keccak256(msg.sender);
keys[_key].key = _key;
keys[_key].purposes = [1];
keys[_key].keyType = 1;
keysByPurpose[1].push(_key);
emit KeyAdded(_key, keys[_key].purposes, 1);
}
function addKey(bytes32 _key, uint256[] _purposes, uint256 _type) external returns (bool success) {
require(keys[_key].key != _key);
keys[_key].key = _key;
keys[_key].purposes = _purposes;
keys[_key].keyType = _type;
for (uint i = 0; i < _purposes.length; i++) {
keysByPurpose[_purposes[i]].push(_key);
}
emit KeyAdded(_key, _purposes, _type);
return true;
}
// "a820f50a": "addKey(bytes32,uint256[],uint256)",
// "747442d3": "approve(uint256,bool)",
// "b61d27f6": "execute(address,uint256,bytes)",
// "862642f5": "removeKey(bytes32)"
function approve(uint256 _id, bool _approve) public returns (bool success) {
address to = executions[_id].to;
bytes4 fHash = executions[_id].data.getFuncHash();
if (to == address(this)) {
if (fHash == 0xa820f50a || fHash == 0x862642f5) {
require(keyHasPurpose(keccak256(msg.sender), 1));
} else {
require(keyHasPurpose(keccak256(msg.sender), 2));
}
} else {
require(keyHasPurpose(keccak256(msg.sender), 2));
}
emit Approved(_id, _approve);
if (_approve == true) {
executions[_id].approved = true;
success = executions[_id].to.call.value(executions[_id].value)(executions[_id].data);
if (success) {
executions[_id].executed = true;
emit Executed(_id, executions[_id].to, executions[_id].value, executions[_id].data);
return;
} else {
return;
}
} else {
executions[_id].approved = false;
}
return true;
}
function execute(address _to, uint256 _value, bytes _data) public returns (uint256 executionId) {
require(!executions[executionNonce].executed);
executions[executionNonce].to = _to;
executions[executionNonce].value = _value;
executions[executionNonce].data = _data;
if (keyHasPurpose(keccak256(msg.sender),1) || keyHasPurpose(keccak256(msg.sender),2)) {
approve(executionNonce, true);
}
emit ExecutionRequested(executionNonce, _to, _value, _data);
executionNonce++;
return executionNonce-1;
}
function removeKey(bytes32 _key) external returns (bool success) {
require(keys[_key].key == _key);
emit KeyRemoved(keys[_key].key, keys[_key].purposes, keys[_key].keyType);
for (uint i = 0; i < keys[_key].purposes.length; i++) {
uint index;
(index,) = keysByPurpose[keys[_key].purposes[i]].indexOf(_key);
keysByPurpose[keys[_key].purposes[i]].removeByIndex(index);
}
delete keys[_key];
return true;
}
function getKey(bytes32 _key) public view returns (uint256[] purposes, uint256 keyType, bytes32 key){
return (keys[_key].purposes, keys[_key].keyType, keys[_key].key);
}
function getKeyPurposes(bytes32 _key) public view returns (uint256[] purposes) {
return keys[_key].purposes;
}
function getKeysByPurpose(uint256 _purpose) public view returns (bytes32[] _keys) {
return keysByPurpose[_purpose];
}
function keyHasPurpose(bytes32 _key, uint256 _purpose) public view returns (bool result) {
bool isThere;
(,isThere) = keys[_key].purposes.indexOf(_purpose);
return isThere;
}
}