├── .circleci └── config.yml ├── .editorconfig ├── .gitignore ├── .prettierrc ├── .vscode └── settings.json ├── LICENSE ├── bn.js.d.ts ├── contracts ├── ERC20.sol ├── ERC725.sol ├── Encoder.sol ├── Identity.sol ├── Migrations.sol ├── Ownable.sol ├── Registry.sol ├── SafeMath.sol ├── SignatureValidator.sol ├── StandardToken.sol └── ZincAccessor.sol ├── generate-contacts-types.ts ├── migrations ├── 1_initial_migration.js └── 2_deploy_contracts.js ├── nodemon.json ├── package.json ├── readme.md ├── test ├── Identity.test.ts ├── Registry.test.ts └── ZincAcessor.test.ts ├── truffle-config.js ├── truffle.d.ts ├── truffle.js ├── tsconfig.json ├── tslint.json ├── web3.d.ts └── yarn.lock /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build: 4 | working_directory: ~/test 5 | docker: 6 | - image: circleci/node:8.11.1 7 | steps: 8 | - checkout 9 | - run: 10 | name: update-npm 11 | command: "sudo npm install -g npm@latest" 12 | - restore_cache: 13 | key: dependency-cache-{{ checksum "package.json" }} 14 | - run: 15 | name: yarn-install 16 | command: yarn install 17 | - save_cache: 18 | key: dependency-cache-{{ checksum "package.json" }} 19 | paths: 20 | - ./node_modules 21 | - run: 22 | name: yarn-format 23 | command: yarn format 24 | - run: 25 | name: yarn-lint 26 | command: yarn lint 27 | - run: 28 | name: yarn-test 29 | command: yarn test 30 | - run: 31 | name: yarn-build 32 | command: yarn build 33 | - store_artifacts: 34 | path: ./build 35 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | end_of_line = lf 8 | indent_size = 2 9 | indent_style = space 10 | insert_final_newline = true 11 | trim_trailing_whitespace = true 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | lib 4 | build 5 | test/Registry.test.js 6 | 7 | *.DS_Store 8 | *.log 9 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "arrowParens": "always" 4 | } 5 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true, 3 | "files.exclude": { 4 | "node_modules": true 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 ZINC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /bn.js.d.ts: -------------------------------------------------------------------------------- 1 | declare module "bn.js" 2 | -------------------------------------------------------------------------------- /contracts/ERC20.sol: -------------------------------------------------------------------------------- 1 | // https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/token/ERC20/ERC20.sol 2 | pragma solidity ^0.4.24; 3 | 4 | 5 | /** 6 | * @title ERC20 interface 7 | * @dev see https://github.com/ethereum/EIPs/issues/20 8 | */ 9 | contract ERC20 { 10 | function totalSupply() public view returns (uint256); 11 | 12 | function balanceOf(address _who) public view returns (uint256); 13 | 14 | function allowance(address _owner, address _spender) public view returns (uint256); 15 | 16 | function transfer(address _to, uint256 _value) public returns (bool); 17 | 18 | function approve(address _spender, uint256 _value) public returns (bool); 19 | 20 | function transferFrom(address _from, address _to, uint256 _value) public returns (bool); 21 | 22 | event Transfer( 23 | address indexed from, 24 | address indexed to, 25 | uint256 value 26 | ); 27 | 28 | event Approval( 29 | address indexed owner, 30 | address indexed spender, 31 | uint256 value 32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /contracts/ERC725.sol: -------------------------------------------------------------------------------- 1 | // Taken from https://github.com/OriginProtocol/identity-playground/blob/0c9ba5c008d410e1ca82a2b1eed15705db49af0f/contracts/ERC725.sol 2 | // with some modifications 3 | pragma solidity ^0.4.22; 4 | 5 | contract ERC725 { 6 | 7 | uint256 public constant MANAGEMENT_KEY = 1; 8 | uint256 public constant ACTION_KEY = 2; 9 | uint256 public constant CLAIM_SIGNER_KEY = 3; 10 | uint256 public constant ENCRYPTION_KEY = 4; 11 | 12 | event KeyAdded(bytes32 indexed key, uint256 indexed purpose, uint256 indexed keyType); 13 | event KeyRemoved(bytes32 indexed key, uint256 indexed purpose, uint256 indexed keyType); 14 | event ExecutionRequested(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data); 15 | event Executed(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data); 16 | event Approved(uint256 indexed executionId, bool approved); 17 | 18 | struct Key { 19 | uint256[] purpose; //e.g., MANAGEMENT_KEY = 1, ACTION_KEY = 2, etc. 20 | uint256 keyType; // e.g. 1 = ECDSA, 2 = RSA, etc. 21 | bytes32 key; 22 | } 23 | 24 | function getKey(bytes32 _key) public constant returns(uint256[] purpose, uint256 keyType, bytes32 key); 25 | function getKeyPurpose(bytes32 _key) public constant returns(uint256[] purpose); 26 | function getKeysByPurpose(uint256 _purpose) public constant returns(bytes32[] keys); 27 | function addKey(bytes32 _key, uint256 _purpose, uint256 _keyType) public returns (bool success); 28 | function removeKey(bytes32 _key, uint256 _purpose) public returns (bool success); 29 | function execute(address _to, uint256 _value, bytes _data) public returns (uint256 executionId); 30 | function approve(uint256 _id, bool _approve) public returns (bool success); 31 | } 32 | -------------------------------------------------------------------------------- /contracts/Encoder.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | contract Encoder { 4 | 5 | function uintToChar(uint8 _uint) internal pure returns(string) { 6 | byte b = "\x30"; // ASCII code for 0 7 | if (_uint > 9) { 8 | b = "\x60"; // ASCII code for the char before a 9 | _uint -= 9; 10 | } 11 | bytes memory bs = new bytes(1); 12 | bs[0] = b | byte(_uint); 13 | return string(bs); 14 | } 15 | 16 | /** 17 | * Encodes the string representation of a uint8 into bytes 18 | */ 19 | function encodeUInt(uint256 _uint) public pure returns(bytes memory) { 20 | if (_uint == 0) { 21 | return abi.encodePacked(uintToChar(0)); 22 | } 23 | 24 | bytes memory result; 25 | uint256 x = _uint; 26 | while (x > 0) { 27 | result = abi.encodePacked(uintToChar(uint8(x % 10)), result); 28 | x /= 10; 29 | } 30 | return result; 31 | } 32 | 33 | /** 34 | * Encodes the string representation of an address into bytes 35 | */ 36 | function encodeAddress(address _address) public pure returns (bytes memory res) { 37 | for (uint i = 0; i < 20; i++) { 38 | // get each byte of the address 39 | byte b = byte(uint8(uint(_address) / (2**(8*(19 - i))))); 40 | 41 | // split it into two 42 | uint8 high = uint8(b >> 4); 43 | uint8 low = uint8(b) & 15; 44 | 45 | // and encode them as chars 46 | res = abi.encodePacked(res, uintToChar(high), uintToChar(low)); 47 | } 48 | return res; 49 | } 50 | 51 | /** 52 | * Encodes a string into bytes 53 | */ 54 | function encodeString(string _str) public pure returns (bytes memory) { 55 | return abi.encodePacked(_str); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /contracts/Identity.sol: -------------------------------------------------------------------------------- 1 | // Taken from https://github.com/OriginProtocol/identity-playground/blob/0c9ba5c008d410e1ca82a2b1eed15705db49af0f/contracts/KeyHolder.sol 2 | // with some modifitcatioms 3 | 4 | pragma solidity ^0.4.22; 5 | 6 | import "./ERC725.sol"; 7 | 8 | contract ERC20Basic { 9 | function balanceOf(address _who) public constant returns (uint256); 10 | function transfer(address _to, uint256 _value) public returns (bool); 11 | } 12 | 13 | contract Identity is ERC725 { 14 | 15 | uint256 constant LOGIN_KEY = 10; 16 | uint256 constant FUNDS_MANAGEMENT = 11; 17 | 18 | uint256 executionNonce; 19 | 20 | struct Execution { 21 | address to; 22 | uint256 value; 23 | bytes data; 24 | bool approved; 25 | bool executed; 26 | } 27 | 28 | mapping (bytes32 => Key) keys; 29 | mapping (uint256 => bytes32[]) keysByPurpose; 30 | mapping (uint256 => Execution) executions; 31 | 32 | event ExecutionFailed(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data); 33 | 34 | modifier onlyManagement() { 35 | require(keyHasPurpose(keccak256(msg.sender), MANAGEMENT_KEY), "Sender does not have management key"); 36 | _; 37 | } 38 | 39 | modifier onlyAction() { 40 | require(keyHasPurpose(keccak256(msg.sender), ACTION_KEY), "Sender does not have action key"); 41 | _; 42 | } 43 | 44 | modifier onlyFundsManagement() { 45 | require(keyHasPurpose(keccak256(msg.sender), FUNDS_MANAGEMENT), "Sender does not have funds key"); 46 | _; 47 | } 48 | 49 | constructor() public { 50 | bytes32 _key = keccak256(msg.sender); 51 | keys[_key].key = _key; 52 | keys[_key].purpose = [MANAGEMENT_KEY]; 53 | keys[_key].keyType = 1; 54 | keysByPurpose[MANAGEMENT_KEY].push(_key); 55 | emit KeyAdded(_key, MANAGEMENT_KEY, 1); 56 | } 57 | 58 | function getKey(bytes32 _key) 59 | public 60 | view 61 | returns(uint256[] purpose, uint256 keyType, bytes32 key) 62 | { 63 | return (keys[_key].purpose, keys[_key].keyType, keys[_key].key); 64 | } 65 | 66 | function getKeyPurpose(bytes32 _key) 67 | public 68 | view 69 | returns(uint256[] purpose) 70 | { 71 | return (keys[_key].purpose); 72 | } 73 | 74 | function getKeysByPurpose(uint256 _purpose) 75 | public 76 | view 77 | returns(bytes32[] _keys) 78 | { 79 | return keysByPurpose[_purpose]; 80 | } 81 | 82 | function addKey(bytes32 _key, uint256 _purpose, uint256 _type) 83 | public 84 | onlyManagement 85 | returns (bool success) 86 | { 87 | if (keyHasPurpose(_key, _purpose)) { 88 | return true; 89 | } 90 | 91 | keys[_key].key = _key; 92 | keys[_key].purpose.push(_purpose); 93 | keys[_key].keyType = _type; 94 | 95 | keysByPurpose[_purpose].push(_key); 96 | 97 | emit KeyAdded(_key, _purpose, _type); 98 | 99 | return true; 100 | } 101 | 102 | function approve(uint256 _id, bool _approve) 103 | public 104 | onlyAction 105 | returns (bool success) 106 | { 107 | emit Approved(_id, _approve); 108 | 109 | if (_approve == true) { 110 | executions[_id].approved = true; 111 | success = executions[_id].to.call(executions[_id].data, 0); 112 | if (success) { 113 | executions[_id].executed = true; 114 | emit Executed( 115 | _id, 116 | executions[_id].to, 117 | executions[_id].value, 118 | executions[_id].data 119 | ); 120 | } else { 121 | emit ExecutionFailed( 122 | _id, 123 | executions[_id].to, 124 | executions[_id].value, 125 | executions[_id].data 126 | ); 127 | } 128 | return success; 129 | } else { 130 | executions[_id].approved = false; 131 | } 132 | return true; 133 | } 134 | 135 | function execute(address _to, uint256 _value, bytes _data) 136 | public 137 | returns (uint256 executionId) 138 | { 139 | require(!executions[executionNonce].executed, "Already executed"); 140 | executions[executionNonce].to = _to; 141 | executions[executionNonce].value = _value; 142 | executions[executionNonce].data = _data; 143 | 144 | emit ExecutionRequested(executionNonce, _to, _value, _data); 145 | 146 | if (keyHasPurpose(keccak256(msg.sender), ACTION_KEY)) { 147 | approve(executionNonce, true); 148 | } 149 | 150 | executionNonce++; 151 | return executionNonce-1; 152 | } 153 | 154 | function removeKey(bytes32 _key, uint256 _purpose) 155 | public 156 | onlyManagement 157 | returns (bool success) 158 | { 159 | require(keys[_key].key == _key, "No such key"); 160 | 161 | if (!keyHasPurpose(_key, _purpose)) { 162 | return false; 163 | } 164 | 165 | uint256 arrayLength = keys[_key].purpose.length; 166 | int index = -1; 167 | for (uint i = 0; i < arrayLength; i++) { 168 | if (keys[_key].purpose[i] == _purpose) { 169 | index = int(i); 170 | break; 171 | } 172 | } 173 | 174 | if (index != -1) { 175 | keys[_key].purpose[uint(index)] = keys[_key].purpose[arrayLength - 1]; 176 | delete keys[_key].purpose[arrayLength - 1]; 177 | keys[_key].purpose.length--; 178 | } 179 | 180 | uint256 purposesLen = keysByPurpose[_purpose].length; 181 | for (uint j = 0; j < purposesLen; j++) { 182 | if (keysByPurpose[_purpose][j] == _key) { 183 | keysByPurpose[_purpose][j] = keysByPurpose[_purpose][purposesLen - 1]; 184 | delete keysByPurpose[_purpose][purposesLen - 1]; 185 | keysByPurpose[_purpose].length--; 186 | break; 187 | } 188 | } 189 | 190 | emit KeyRemoved(_key, _purpose, keys[_key].keyType); 191 | 192 | return true; 193 | } 194 | 195 | function keyHasPurpose(bytes32 _key, uint256 _purpose) 196 | public 197 | view 198 | returns(bool result) 199 | { 200 | if (keys[_key].key == 0) return false; 201 | uint256 arrayLength = keys[_key].purpose.length; 202 | for (uint i = 0; i < arrayLength; i++) { 203 | if (keys[_key].purpose[i] == _purpose) { 204 | return true; 205 | } 206 | } 207 | return false; 208 | } 209 | 210 | /** 211 | * Send all ether to msg.sender 212 | * Requires FUNDS_MANAGEMENT purpose for msg.sender 213 | */ 214 | function withdraw() public onlyFundsManagement { 215 | msg.sender.transfer(address(this).balance); 216 | } 217 | 218 | /** 219 | * Transfer ether to _account 220 | * @param _amount amount to transfer in wei 221 | * @param _account recepient 222 | * Requires FUNDS_MANAGEMENT purpose for msg.sender 223 | */ 224 | function transferEth(uint _amount, address _account) public onlyFundsManagement { 225 | require(_amount <= address(this).balance, "Amount should be less than total balance of the contract"); 226 | require(_account != address(0), "must be valid address"); 227 | _account.transfer(_amount); 228 | } 229 | 230 | /** 231 | * Returns contract eth balance 232 | */ 233 | function getBalance() public view returns(uint) { 234 | return address(this).balance; 235 | } 236 | 237 | /** 238 | * Returns ERC20 token balance for _token 239 | * @param _token token address 240 | */ 241 | function getTokenBalance(address _token) public view returns (uint) { 242 | return ERC20Basic(_token).balanceOf(this); 243 | } 244 | 245 | /** 246 | * Send all tokens for _token to msg.sender 247 | * @param _token ERC20 contract address 248 | * Requires FUNDS_MANAGEMENT purpose for msg.sender 249 | */ 250 | function withdrawTokens(address _token) public onlyFundsManagement { 251 | require(_token != address(0)); 252 | ERC20Basic token = ERC20Basic(_token); 253 | uint balance = token.balanceOf(this); 254 | // token returns true on successful transfer 255 | assert(token.transfer(msg.sender, balance)); 256 | } 257 | 258 | /** 259 | * Send tokens for _token to _to 260 | * @param _token ERC20 contract address 261 | * @param _to recepient 262 | * @param _amount amount in 263 | * Requires FUNDS_MANAGEMENT purpose for msg.sender 264 | */ 265 | function transferTokens(address _token, address _to, uint _amount) public onlyFundsManagement { 266 | require(_token != address(0)); 267 | require(_to != address(0)); 268 | ERC20Basic token = ERC20Basic(_token); 269 | uint balance = token.balanceOf(this); 270 | require(_amount <= balance); 271 | assert(token.transfer(_to, _amount)); 272 | } 273 | 274 | function () public payable {} 275 | 276 | } 277 | -------------------------------------------------------------------------------- /contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | // THIS IS AUTO-GENERATED BY TRUFFLE 2 | pragma solidity ^0.4.23; 3 | 4 | contract Migrations { 5 | address public owner; 6 | uint public last_completed_migration; 7 | 8 | constructor() public { 9 | owner = msg.sender; 10 | } 11 | 12 | modifier restricted() { 13 | if (msg.sender == owner) _; 14 | } 15 | 16 | function setCompleted(uint completed) public restricted { 17 | last_completed_migration = completed; 18 | } 19 | 20 | function upgrade(address new_address) public restricted { 21 | Migrations upgraded = Migrations(new_address); 22 | upgraded.setCompleted(last_completed_migration); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /contracts/Ownable.sol: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT. TAKEN FROM https://github.com/OpenZeppelin/openzeppelin-solidity/commit/5daaf60d11ee2075260d0f3adfb22b1c536db983 2 | pragma solidity ^0.4.24; 3 | 4 | 5 | /** 6 | * @title Ownable 7 | * @dev The Ownable contract has an owner address, and provides basic authorization control 8 | * functions, this simplifies the implementation of "user permissions". 9 | */ 10 | contract Ownable { 11 | address public owner; 12 | 13 | 14 | event OwnershipRenounced(address indexed previousOwner); 15 | event OwnershipTransferred( 16 | address indexed previousOwner, 17 | address indexed newOwner 18 | ); 19 | 20 | 21 | /** 22 | * @dev The Ownable constructor sets the original `owner` of the contract to the sender 23 | * account. 24 | */ 25 | constructor() public { 26 | owner = msg.sender; 27 | } 28 | 29 | /** 30 | * @dev Throws if called by any account other than the owner. 31 | */ 32 | modifier onlyOwner() { 33 | require(msg.sender == owner); 34 | _; 35 | } 36 | 37 | /** 38 | * @dev Allows the current owner to relinquish control of the contract. 39 | * @notice Renouncing to ownership will leave the contract without an owner. 40 | * It will not be possible to call the functions with the `onlyOwner` 41 | * modifier anymore. 42 | */ 43 | function renounceOwnership() public onlyOwner { 44 | emit OwnershipRenounced(owner); 45 | owner = address(0); 46 | } 47 | 48 | /** 49 | * @dev Allows the current owner to transfer control of the contract to a newOwner. 50 | * @param _newOwner The address to transfer ownership to. 51 | */ 52 | function transferOwnership(address _newOwner) public onlyOwner { 53 | _transferOwnership(_newOwner); 54 | } 55 | 56 | /** 57 | * @dev Transfers control of the contract to a newOwner. 58 | * @param _newOwner The address to transfer ownership to. 59 | */ 60 | function _transferOwnership(address _newOwner) internal { 61 | require(_newOwner != address(0)); 62 | emit OwnershipTransferred(owner, _newOwner); 63 | owner = _newOwner; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /contracts/Registry.sol: -------------------------------------------------------------------------------- 1 | // This is an implementation (with some adaptations) of uPort erc780: https://etherscan.io/address/0xdb55d40684e7dc04655a9789937214b493a2c2c6#code && https://github.com/ethereum/EIPs/issues/780 2 | pragma solidity ^0.4.24; 3 | 4 | import "./Ownable.sol"; 5 | 6 | contract Registry is Ownable { 7 | 8 | mapping(address => 9 | mapping(address => 10 | mapping(bytes32 => 11 | mapping(bytes32 => bytes32)))) registry; 12 | 13 | event ClaimSet( 14 | address indexed subject, 15 | address indexed issuer, 16 | bytes32 indexed id, 17 | bytes32 key, 18 | bytes32 data, 19 | uint updatedAt 20 | ); 21 | 22 | event ClaimRemoved( 23 | address indexed subject, 24 | address indexed issuer, 25 | bytes32 indexed id, 26 | bytes32 key, 27 | uint removedAt 28 | ); 29 | 30 | function setClaim( 31 | address subject, 32 | address issuer, 33 | bytes32 id, 34 | bytes32 key, 35 | bytes32 data 36 | ) public { 37 | require(msg.sender == issuer || msg.sender == owner); 38 | registry[subject][issuer][id][key] = data; 39 | emit ClaimSet(subject, issuer, id, key, data, now); 40 | } 41 | 42 | function getClaim( 43 | address subject, 44 | address issuer, 45 | bytes32 id, 46 | bytes32 key 47 | ) 48 | public view returns(bytes32) { 49 | return registry[subject][issuer][id][key]; 50 | } 51 | 52 | function removeClaim( 53 | address subject, 54 | address issuer, 55 | bytes32 id, 56 | bytes32 key 57 | ) public { 58 | require( 59 | msg.sender == subject || msg.sender == issuer || msg.sender == owner 60 | ); 61 | delete registry[subject][issuer][id][key]; 62 | emit ClaimRemoved(subject, issuer, id, key, now); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /contracts/SafeMath.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | 4 | /** 5 | * @title SafeMath 6 | * @dev Math operations with safety checks that revert on error 7 | */ 8 | library SafeMath { 9 | 10 | /** 11 | * @dev Multiplies two numbers, reverts on overflow. 12 | */ 13 | function mul(uint256 _a, uint256 _b) internal pure returns (uint256) { 14 | // Gas optimization: this is cheaper than requiring 'a' not being zero, but the 15 | // benefit is lost if 'b' is also tested. 16 | // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 17 | if (_a == 0) { 18 | return 0; 19 | } 20 | 21 | uint256 c = _a * _b; 22 | require(c / _a == _b); 23 | 24 | return c; 25 | } 26 | 27 | /** 28 | * @dev Integer division of two numbers truncating the quotient, reverts on division by zero. 29 | */ 30 | function div(uint256 _a, uint256 _b) internal pure returns (uint256) { 31 | require(_b > 0); // Solidity only automatically asserts when dividing by 0 32 | uint256 c = _a / _b; 33 | // assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold 34 | 35 | return c; 36 | } 37 | 38 | /** 39 | * @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend). 40 | */ 41 | function sub(uint256 _a, uint256 _b) internal pure returns (uint256) { 42 | require(_b <= _a); 43 | uint256 c = _a - _b; 44 | 45 | return c; 46 | } 47 | 48 | /** 49 | * @dev Adds two numbers, reverts on overflow. 50 | */ 51 | function add(uint256 _a, uint256 _b) internal pure returns (uint256) { 52 | uint256 c = _a + _b; 53 | require(c >= _a); 54 | 55 | return c; 56 | } 57 | 58 | /** 59 | * @dev Divides two numbers and returns the remainder (unsigned integer modulo), 60 | * reverts when dividing by zero. 61 | */ 62 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 63 | require(b != 0); 64 | return a % b; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /contracts/SignatureValidator.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | 4 | contract SignatureValidator { 5 | 6 | function doHash(string _message1, uint32 _message2, string _header1, string _header2) 7 | pure internal returns (bytes32) { 8 | return keccak256( 9 | abi.encodePacked( 10 | keccak256(abi.encodePacked(_header1, _header2)), 11 | keccak256(abi.encodePacked(_message1, _message2))) 12 | ); 13 | } 14 | 15 | /** 16 | * Returns address of signer for a signed message 17 | * @param _message1 message that was signed 18 | * @param _nonce nonce that was part of the signed message 19 | * @param _header1 header for the message (ex: "string Message") 20 | * @param _header2 header for the nonce (ex: "uint32 nonce") 21 | * @param _r r from ECDSA 22 | * @param _s s from ECDSA 23 | * @param _v recovery id 24 | */ 25 | function checkSignature(string _message1, uint32 _nonce, string _header1, string _header2, bytes32 _r, bytes32 _s, uint8 _v) 26 | public pure returns (address) { 27 | bytes32 hash = doHash(_message1, _nonce, _header1, _header2); 28 | return ecrecover(hash, _v, _r, _s); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /contracts/StandardToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | import "./ERC20.sol"; 4 | import "./SafeMath.sol"; 5 | 6 | 7 | /** 8 | * @title Standard ERC20 token 9 | * 10 | * @dev Implementation of the basic standard token. 11 | * https://github.com/ethereum/EIPs/issues/20 12 | * Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol 13 | */ 14 | contract StandardToken is ERC20 { 15 | using SafeMath for uint256; 16 | 17 | mapping(address => uint256) balances; 18 | 19 | mapping (address => mapping (address => uint256)) internal allowed; 20 | 21 | uint256 totalSupply_; 22 | /** 23 | Add missing constructor 24 | */ 25 | 26 | constructor(uint256 _totalSupply) public { 27 | balances[msg.sender] = _totalSupply; 28 | totalSupply_ = _totalSupply; 29 | } 30 | 31 | /** 32 | * @dev Total number of tokens in existence 33 | */ 34 | function totalSupply() public view returns (uint256) { 35 | return totalSupply_; 36 | } 37 | 38 | /** 39 | * @dev Gets the balance of the specified address. 40 | * @param _owner The address to query the the balance of. 41 | * @return An uint256 representing the amount owned by the passed address. 42 | */ 43 | function balanceOf(address _owner) public view returns (uint256) { 44 | return balances[_owner]; 45 | } 46 | 47 | /** 48 | * @dev Function to check the amount of tokens that an owner allowed to a spender. 49 | * @param _owner address The address which owns the funds. 50 | * @param _spender address The address which will spend the funds. 51 | * @return A uint256 specifying the amount of tokens still available for the spender. 52 | */ 53 | function allowance( 54 | address _owner, 55 | address _spender 56 | ) 57 | public 58 | view 59 | returns (uint256) 60 | { 61 | return allowed[_owner][_spender]; 62 | } 63 | 64 | /** 65 | * @dev Transfer token for a specified address 66 | * @param _to The address to transfer to. 67 | * @param _value The amount to be transferred. 68 | */ 69 | function transfer(address _to, uint256 _value) public returns (bool) { 70 | require(_value <= balances[msg.sender]); 71 | require(_to != address(0)); 72 | 73 | balances[msg.sender] = balances[msg.sender].sub(_value); 74 | balances[_to] = balances[_to].add(_value); 75 | emit Transfer(msg.sender, _to, _value); 76 | return true; 77 | } 78 | 79 | /** 80 | * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. 81 | * Beware that changing an allowance with this method brings the risk that someone may use both the old 82 | * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this 83 | * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: 84 | * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 85 | * @param _spender The address which will spend the funds. 86 | * @param _value The amount of tokens to be spent. 87 | */ 88 | function approve(address _spender, uint256 _value) public returns (bool) { 89 | allowed[msg.sender][_spender] = _value; 90 | emit Approval(msg.sender, _spender, _value); 91 | return true; 92 | } 93 | 94 | /** 95 | * @dev Transfer tokens from one address to another 96 | * @param _from address The address which you want to send tokens from 97 | * @param _to address The address which you want to transfer to 98 | * @param _value uint256 the amount of tokens to be transferred 99 | */ 100 | function transferFrom( 101 | address _from, 102 | address _to, 103 | uint256 _value 104 | ) 105 | public 106 | returns (bool) 107 | { 108 | require(_value <= balances[_from]); 109 | require(_value <= allowed[_from][msg.sender]); 110 | require(_to != address(0)); 111 | 112 | balances[_from] = balances[_from].sub(_value); 113 | balances[_to] = balances[_to].add(_value); 114 | allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); 115 | emit Transfer(_from, _to, _value); 116 | return true; 117 | } 118 | 119 | /** 120 | * @dev Increase the amount of tokens that an owner allowed to a spender. 121 | * approve should be called when allowed[_spender] == 0. To increment 122 | * allowed value is better to use this function to avoid 2 calls (and wait until 123 | * the first transaction is mined) 124 | * From MonolithDAO Token.sol 125 | * @param _spender The address which will spend the funds. 126 | * @param _addedValue The amount of tokens to increase the allowance by. 127 | */ 128 | function increaseApproval( 129 | address _spender, 130 | uint256 _addedValue 131 | ) 132 | public 133 | returns (bool) 134 | { 135 | allowed[msg.sender][_spender] = ( 136 | allowed[msg.sender][_spender].add(_addedValue)); 137 | emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]); 138 | return true; 139 | } 140 | 141 | /** 142 | * @dev Decrease the amount of tokens that an owner allowed to a spender. 143 | * approve should be called when allowed[_spender] == 0. To decrement 144 | * allowed value is better to use this function to avoid 2 calls (and wait until 145 | * the first transaction is mined) 146 | * From MonolithDAO Token.sol 147 | * @param _spender The address which will spend the funds. 148 | * @param _subtractedValue The amount of tokens to decrease the allowance by. 149 | */ 150 | function decreaseApproval( 151 | address _spender, 152 | uint256 _subtractedValue 153 | ) 154 | public 155 | returns (bool) 156 | { 157 | uint256 oldValue = allowed[msg.sender][_spender]; 158 | if (_subtractedValue >= oldValue) { 159 | allowed[msg.sender][_spender] = 0; 160 | } else { 161 | allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue); 162 | } 163 | emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]); 164 | return true; 165 | } 166 | 167 | } 168 | -------------------------------------------------------------------------------- /contracts/ZincAccessor.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | import "./Identity.sol"; 4 | import "./Encoder.sol"; 5 | import "./SignatureValidator.sol"; 6 | 7 | /** 8 | * ZincAccesor contract used for constructing and managing Identity contracts 9 | * Access control is based on signed messages 10 | * This contract can be used as a trustless entity that creates an Identity contract and is used to manage it. 11 | * It operates as a proxy in order to allow users to interact with it based on signed messages and not spend any gas 12 | * It can be upgraded with the user consent by adding a instance of a new version and removing the old one. 13 | */ 14 | 15 | contract ZincAccessor is SignatureValidator, Encoder { 16 | 17 | uint256 public nonce = 0; 18 | 19 | event UserIdentityCreated(address indexed userAddress, address indexed identityContractAddress); 20 | event AccessorAdded(address indexed identityContractAddress, address indexed keyAddress, uint256 indexed purpose); 21 | event AccessorRemoved(address indexed identityContractAddress, address indexed keyAddress, uint256 indexed purpose); 22 | 23 | function checkUserSignature( 24 | address _userAddress, 25 | string _message1, 26 | uint32 _nonce, 27 | string _header1, 28 | string _header2, 29 | bytes32 _r, 30 | bytes32 _s, 31 | uint8 _v) 32 | pure internal returns (bool) { 33 | require( 34 | checkSignature(_message1, _nonce, _header1, _header2, _r, _s, _v) == _userAddress, 35 | "User signature must be the same as signed message"); 36 | return true; 37 | } 38 | 39 | modifier checknonce(uint _nonce) { 40 | require(++nonce == _nonce, "Wrong nonce"); 41 | _; 42 | } 43 | 44 | /** 45 | * Constructs an Identity contract and returns its address 46 | * Requires a signed message to verify the identity of the initial user address 47 | * @param _userAddress user address 48 | * @param _message1 message that was signed 49 | * @param _nonce nonce that was part of the signed message 50 | * @param _header1 header for the message (ex: "string Message") 51 | * @param _header2 header for the nonce (ex: "uint32 nonce") 52 | * @param _r r from ECDSA 53 | * @param _s s from ECDSA 54 | * @param _v recovery id 55 | */ 56 | function constructUserIdentity( 57 | address _userAddress, 58 | string _message1, 59 | uint32 _nonce, 60 | string _header1, 61 | string _header2, 62 | bytes32 _r, 63 | bytes32 _s, 64 | uint8 _v) 65 | public 66 | returns (address) { 67 | require( 68 | checkUserSignature(_userAddress, _message1, _nonce, _header1, _header2, _r, _s, _v), 69 | "User Signature does not match"); 70 | 71 | Identity id = new Identity(); 72 | id.addKey(keccak256(_userAddress), id.MANAGEMENT_KEY(), 1); 73 | 74 | emit UserIdentityCreated(_userAddress, address(id)); 75 | 76 | return address(id); 77 | } 78 | 79 | /** 80 | * Adds an accessor to an Identity contract 81 | * Requires a signed message to verify the identity of the initial user address 82 | * Requires _userAddress to have KEY_MANAGEMENT purpose on the Identity contract 83 | * Emits AccessorAdded 84 | * @param _key key to add to Identity 85 | * @param _purpose purpose for _key 86 | * @param _idContract address if Identity contract 87 | * @param _userAddress user address 88 | * @param _message1 message that was signed of the form "Add {_key} to {_idContract} with purpose {_purpose}" 89 | * @param _nonce nonce that was part of the signed message 90 | * @param _header1 header for the message (ex: "string Message") 91 | * @param _header2 header for the nonce (ex: "uint32 nonce") 92 | * @param _r r from ECDSA 93 | * @param _s s from ECDSA 94 | * @param _v recovery id 95 | */ 96 | function addAccessor( 97 | address _key, 98 | address _idContract, 99 | uint256 _purpose, 100 | address _userAddress, 101 | string _message1, 102 | uint32 _nonce, 103 | string _header1, 104 | string _header2, 105 | bytes32 _r, 106 | bytes32 _s, 107 | uint8 _v) 108 | public checknonce(_nonce) returns (bool) { 109 | require(checkUserSignature(_userAddress, _message1, _nonce, _header1, _header2, _r, _s, _v)); 110 | require( 111 | keccak256(abi.encodePacked("Add 0x", encodeAddress(_key), " to 0x", encodeAddress(_idContract), " with purpose ", encodeUInt(_purpose))) == 112 | keccak256(encodeString(_message1)), "Message incorrect"); 113 | 114 | Identity id = Identity(_idContract); 115 | require(id.keyHasPurpose(keccak256(_userAddress), id.MANAGEMENT_KEY())); 116 | 117 | id.addKey(keccak256(_key), _purpose, 1); 118 | emit AccessorAdded(_idContract, _key, _purpose); 119 | return true; 120 | } 121 | 122 | /** 123 | * Remove an accessor from Identity contract 124 | * Requires a signed message to verify the identity of the initial user address 125 | * Requires _userAddress to have KEY_MANAGEMENT purpose on the Identity contract 126 | * Emits AccessorRemoved 127 | * @param _key key to add to Identity 128 | * @param _idContract address if Identity contract 129 | * @param _userAddress user address 130 | * @param _message1 message that was signed of the form "Remove {_key} from {_idContract}" 131 | * @param _nonce nonce that was part of the signed message 132 | * @param _header1 header for the message (ex: "string Message") 133 | * @param _header2 header for the nonce (ex: "uint32 nonce") 134 | * @param _r r from ECDSA 135 | * @param _s s from ECDSA 136 | * @param _v recovery id 137 | */ 138 | function removeAccessor( 139 | address _key, 140 | address _idContract, 141 | uint256 _purpose, 142 | address _userAddress, 143 | string _message1, 144 | uint32 _nonce, 145 | string _header1, 146 | string _header2, 147 | bytes32 _r, 148 | bytes32 _s, 149 | uint8 _v) 150 | public checknonce(_nonce) returns (bool) { 151 | require(checkUserSignature(_userAddress, _message1, _nonce, _header1, _header2, _r, _s, _v)); 152 | require( 153 | keccak256(abi.encodePacked("Remove 0x", encodeAddress(_key), " from 0x", encodeAddress(_idContract), " with purpose ", encodeUInt(_purpose))) == 154 | keccak256(encodeString(_message1)), "Message incorrect"); 155 | 156 | Identity id = Identity(_idContract); 157 | require(id.keyHasPurpose(keccak256(_userAddress), id.MANAGEMENT_KEY())); 158 | 159 | id.removeKey(keccak256(_key), _purpose); 160 | 161 | emit AccessorRemoved(_idContract, _key, _purpose); 162 | return true; 163 | } 164 | 165 | } 166 | -------------------------------------------------------------------------------- /generate-contacts-types.ts: -------------------------------------------------------------------------------- 1 | // Taken from https://github.com/hellobloom/core/blob/2bd20a9096c0e3bafa0c5d3fb168a130573402a3/generate.ts 2 | // with some modifications 3 | 4 | interface ConstructorMember { 5 | inputs: FunctionMemberInput[] 6 | payable: false 7 | type: "constructor" 8 | } 9 | 10 | interface EventMember { 11 | inputs: FunctionMemberInput[] 12 | name: string 13 | type: "event" 14 | } 15 | 16 | interface FunctionMember { 17 | inputs: FunctionMemberInput[] 18 | outputs: FunctionMemberInput[] 19 | name: string 20 | constant: boolean 21 | payable: boolean 22 | type: "function" 23 | } 24 | 25 | interface FallbackMember { 26 | type: "fallback" 27 | payable: boolean 28 | } 29 | 30 | interface UnknownMember { 31 | type: string 32 | } 33 | 34 | type SolidityType = 35 | | "address" 36 | | "address[]" 37 | | "bool" 38 | | "bytes" 39 | | "bytes32" 40 | | "bytes32[]" 41 | | "string" 42 | | "uint8" 43 | | "uint8[]" 44 | | "uint32" 45 | | "uint64" 46 | | "uint256" 47 | | "uint256[]" 48 | 49 | interface FunctionMemberInput { 50 | name: string 51 | type: SolidityType 52 | } 53 | 54 | type Member = ConstructorMember | EventMember | FunctionMember | FallbackMember 55 | 56 | type Abi = (EventMember | FunctionMember | ConstructorMember)[] 57 | 58 | interface Definition { 59 | contractName: string 60 | abi: Abi 61 | } 62 | 63 | function generateHeader(): string { 64 | return ` 65 | // Autogenerated file 66 | // DO NOT EDIT!!! 67 | // You can update it by running \`yarn generate-types\` 68 | 69 | import * as Web3 from "web3"; 70 | import * as BigNumber from "bignumber.js"; 71 | 72 | type Address = string; 73 | type TransactionOptions = Partial; 74 | type UInt = number | BigNumber.BigNumber; 75 | 76 | interface Transaction { 77 | hash: string; 78 | nonce: number; 79 | blockHash: string | null; 80 | blockNumber: number | null; 81 | transactionIndex: number | null; 82 | from: Address | ContractInstance; 83 | to: string | null; 84 | value: UInt; 85 | gasPrice: UInt; 86 | gas: number; 87 | input: string; 88 | } 89 | 90 | interface ContractInstance { 91 | address: string; 92 | sendTransaction(options?: TransactionOptions): Promise; 93 | } 94 | ` 95 | } 96 | 97 | function generateFooter(contractInstances: string[]): string { 98 | let result = ` 99 | declare type _contractTest = (accounts: string[]) => void; 100 | declare interface TransactionMeta { 101 | from: string, 102 | } 103 | 104 | interface Artifacts {` 105 | 106 | for (const contract of contractInstances) { 107 | result = result.concat( 108 | `require(name: "${contract}"): ${contract}Contract\n` 109 | ) 110 | } 111 | 112 | const end = ` 113 | } 114 | 115 | declare global { 116 | var artifacts: Artifacts 117 | var web3: Web3 118 | function contract(name: string, test: _contractTest): void 119 | function it(name: string, test: (accounts: string[]) => void): void 120 | } 121 | ` 122 | 123 | return result.concat(end) 124 | } 125 | 126 | function buildContract(definition: Definition) { 127 | return ` 128 | export interface ${ 129 | definition.contractName 130 | }Instance extends ContractInstance { 131 | ${buildMembers(definition.abi)} 132 | } 133 | 134 | export interface ${definition.contractName}Contract { 135 | new: (${buildConstructorArguments(definition.abi)}) => Promise<${ 136 | definition.contractName 137 | }Instance>; 138 | deployed(): Promise<${definition.contractName}Instance>; 139 | at(address: string): ${definition.contractName}Instance; 140 | } 141 | ` 142 | } 143 | 144 | function buildMembers(abi: Abi): string { 145 | return abi.map(buildMember).join("\n") 146 | } 147 | 148 | function buildMember(member: Member): string { 149 | switch (member.type) { 150 | case "function": 151 | return buildFunctionMember(member) 152 | case "event": 153 | return buildEventMember(member) 154 | case "constructor": 155 | return buildConstructorMember(member) 156 | case "fallback": 157 | return buildFallbackMember(member) 158 | default: 159 | throw "Exhaustiveness miss!" 160 | } 161 | } 162 | 163 | function buildConstructorArguments(abi: Abi): string { 164 | const constructorMember = abi.find((member) => member.type === "constructor") 165 | 166 | if (!constructorMember) { 167 | return "" 168 | } 169 | 170 | return constructorMember.inputs.map(buildFunctionArgument).join(", ") 171 | } 172 | 173 | function buildFunctionMember(member: FunctionMember) { 174 | let args = member.inputs.map(buildFunctionArgument).join(", ") 175 | 176 | if (args.length > 0) { 177 | args += ", " 178 | } 179 | 180 | const functionSignature = `(${args}options?: TransactionOptions)` 181 | return `${member.name}: { 182 | ${functionSignature}: Promise 183 | call:${functionSignature} => ${translateOutputs(member.outputs)} 184 | estimateGas: ( 185 | subject: string, 186 | issuer: string, 187 | id: string, 188 | key: string, 189 | data?: string, 190 | options?: { 191 | from?: string 192 | gas?: number 193 | } 194 | ) => number 195 | }` 196 | } 197 | 198 | function translateOutputs(outputs: FunctionMemberInput[]) { 199 | let valueType 200 | if (outputs.length === 1) { 201 | valueType = translateOutput(outputs[0]) 202 | } else if (outputs.length === 0) { 203 | valueType = "Web3.TransactionReceipt" 204 | } else { 205 | valueType = `[${outputs.map(translateOutput).join(", ")}]` 206 | } 207 | 208 | return `Promise<${valueType}>` 209 | } 210 | 211 | function translateOutput(output: FunctionMemberInput) { 212 | return translateType(output.type, { UInt: "BigNumber.BigNumber" }) 213 | } 214 | 215 | let unnamedArgumentNumber = 0 216 | 217 | function unnamedArgumentName(): string { 218 | return `unnamed${unnamedArgumentNumber++}` 219 | } 220 | 221 | function buildFunctionArgument(input: FunctionMemberInput): string { 222 | let name = input.name 223 | if (name[0] == "_") { 224 | name = name.slice(1) 225 | } 226 | const type = translateType(input.type) 227 | 228 | if (name.length === 0) { 229 | name = unnamedArgumentName() 230 | } 231 | 232 | return `${name}: ${type}` 233 | } 234 | 235 | function translateType(type: SolidityType, options = { UInt: "UInt" }): string { 236 | switch (type) { 237 | case "string": 238 | return "string" 239 | case "address": 240 | return "Address" 241 | case "address[]": 242 | return "Address[]" 243 | case "bool": 244 | return "boolean" 245 | case "bytes": 246 | return "string" 247 | case "bytes32": 248 | return "string" 249 | case "bytes32[]": 250 | return "string[]" 251 | case "uint8": 252 | case "uint32": 253 | case "uint64": 254 | case "uint256": 255 | return options.UInt 256 | case "uint8[]": 257 | case "uint256[]": 258 | return `${options.UInt}[]` 259 | default: 260 | throw `Unexpected case! ${type}` 261 | } 262 | } 263 | 264 | function buildEventMember(_member: Member) { 265 | return "" 266 | } 267 | 268 | function buildConstructorMember(_member: Member) { 269 | return "" 270 | } 271 | 272 | function buildFallbackMember(_member: Member) { 273 | return "" 274 | } 275 | 276 | const glob = require("glob") 277 | 278 | glob("./build/contracts/*.json", {}, (err: string, files: string[]) => { 279 | if (err) { 280 | console.log("Error!", err) 281 | return 282 | } 283 | 284 | console.log(generateHeader()) 285 | let contractInstances: string[] = [] 286 | 287 | files.forEach((file) => { 288 | let definition: Definition = require(file) 289 | contractInstances.push(definition.contractName) 290 | console.log(buildContract(definition)) 291 | }) 292 | console.log(generateFooter(contractInstances)) 293 | }) 294 | -------------------------------------------------------------------------------- /migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | // THIS IS AUTO-GENERATED BY TRUFFLE 2 | var Migrations = artifacts.require("./Migrations.sol") 3 | 4 | module.exports = function(deployer) { 5 | deployer.deploy(Migrations) 6 | } 7 | -------------------------------------------------------------------------------- /migrations/2_deploy_contracts.js: -------------------------------------------------------------------------------- 1 | // const Registry = artifacts.require("Registry") 2 | const ZincAccessor = artifacts.require("ZincAccessor") 3 | 4 | module.exports = function(deployer) { 5 | deployer.deploy(ZincAccessor) 6 | } 7 | -------------------------------------------------------------------------------- /nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "ext": "ts", 3 | "watch": "server", 4 | "exec": "ts-node server" 5 | } 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mvp-blockchain", 3 | "version": "0.0.0", 4 | "license": "MIT", 5 | "author": "George Bennett", 6 | "scripts": { 7 | "build": "truffle compile", 8 | "reset": "rimraf build test/*.js", 9 | "test": "tsc && truffle test --network develop && rimraf test/*.js", 10 | "generate-types": 11 | "truffle compile && ts-node generate-contacts-types.ts > truffle.d.ts && yarn format", 12 | "lint": "tslint --format codeFrame --fix '{test,contracts}/**/*.ts'", 13 | "format": 14 | "prettier '*.{js,json,md}' '{test,contracts}/**/*.ts' '*.ts' --write", 15 | "precommit": "yarn format && yarn lint && yarn test" 16 | }, 17 | "dependencies": { 18 | "@types/chai": "^4.1.4", 19 | "@types/node": "^10.5.7", 20 | "bignumber.js": "^7.2.1", 21 | "chai": "^4.1.2", 22 | "debug": "^3.1.0", 23 | "eth-sig-util": "1.4.2", 24 | "supertest": "^3.1.0", 25 | "truffle": "^4.1.11", 26 | "truffle-hdwallet-provider": "^0.0.6" 27 | }, 28 | "devDependencies": { 29 | "husky": "^0.14.3", 30 | "nodemon": "^1.17.4", 31 | "prettier": "1.12.1", 32 | "rimraf": "^2.6.2", 33 | "ts-jest": "^22.4.6", 34 | "ts-node": "^6.0.3", 35 | "tslint": "^5.10.0", 36 | "tslint-config-prettier": "^1.12.0", 37 | "typescript": "^2.8.3" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | The contract architecture is inspired by ERC780 & ERC725 with a claims registry and individual user contracts. 4 | 5 | The philosophy of the achitecture is that each user will have an Identity Contract which only they control and can revoke permissions of other apps as they wish. The idea is that different dApp contracts can ask the user for permission to interact with their identity contract and the user can allow for certain permissions. The dApp contract’s address gets added to the users Identity Contract. We folllowed the upgradability ethos that the user can decide to stick with the current logic or upgrade and still use the system. 6 | 7 | We developed our own version of a Transaction Relay which will facilitate the user to use our platform without using gas/ether. Zinc will relay the transactions in a trustless fashion. We decided to use ECDSA signatures within the smart contract to verify user’s consent for interacting with their Identity or performing any function on their behalf. The transaction relay works by asking the user to sign a message through MetaMask, the signed message then gets relayed to the ZincAccessor contract which verifies the contents of the message through the Encoder contract and verifies the signature by using SignatureValidator, once these checks are performed, the action is performed with the Identity Contract. 8 | 9 | ![contracts](https://user-images.githubusercontent.com/23189295/70504386-97065e80-1b1d-11ea-8857-edb5b2f2daab.png) 10 | 11 | 12 | This project uses [yarn][yarn] to manage project dependencies. 13 | 14 | Please ensure you [install][yarn-install] and use it in place of npm. 15 | 16 | ## IDE Plugins 17 | 18 | Please install the following plugins for your IDE: 19 | 20 | * [EditorConfig](http://editorconfig.org/#download) 21 | * [Prettier](https://prettier.io/docs/en/editors.html) 22 | * [TSLint](https://palantir.github.io/tslint) 23 | 24 | ## Scripts 25 | 26 | | Command | Description | 27 | | ------------- | ---------------------------------------------------------------------------------- | 28 | | `yarn build` | Compiles the Solidity source files into JSON (ABI) located in a `build` directory. | 29 | | `yarn test` | Compiles all TypeScript files and runs the truffle test suite. | 30 | | `yarn reset` | Deletes the `build` directories and compiled `test.js` files. | 31 | | `yarn lint` | Lints the source TypeScript files using [TSLint][tslint]. | 32 | | `yarn format` | Formats all files using [Prettier][prettier]. | 33 | 34 | [prettier]: https://prettier.io 35 | [tslint]: https://palantir.github.io/tslint 36 | [yarn]: https://yarnpkg.com 37 | [yarn-install]: https://yarnpkg.com/en/docs/install 38 | 39 | ## License 40 | 41 | MIT 42 | -------------------------------------------------------------------------------- /test/Identity.test.ts: -------------------------------------------------------------------------------- 1 | import { assert } from "chai" 2 | 3 | const IdentityContract = artifacts.require("Identity") 4 | 5 | const StandardToken = artifacts.require("StandardToken") 6 | 7 | contract("Identity", (accounts) => { 8 | it("can create identity contract", async () => { 9 | const id = await IdentityContract.new() 10 | assert.isDefined(id) 11 | }) 12 | 13 | it("random address has 0 privileges", async () => { 14 | const id = await IdentityContract.new() 15 | const accessorPurpose = await id.getKeyPurpose.call( 16 | "0xbd32ccace9e69756620fda04ee0b6738c9c74043" 17 | ) 18 | 19 | assert.deepStrictEqual(accessorPurpose, []) 20 | }) 21 | 22 | it("can add accessor", async () => { 23 | const id = await IdentityContract.new() 24 | 25 | const receipt = await id.addKey( 26 | web3.sha3(accounts[1], { encoding: "hex" }), 27 | 11, 28 | 1 29 | ) // Give accounts[1] FUNDS_MANAGEMENT purpose 30 | 31 | // actual gas cost 148523 32 | assert( 33 | receipt.receipt.gasUsed < 150000, 34 | "Too much gas used to add accessor from Identity" 35 | ) 36 | 37 | assert( 38 | await id.keyHasPurpose.call( 39 | web3.sha3(accounts[1], { encoding: "hex" }), 40 | 11 41 | ) 42 | ) 43 | }) 44 | 45 | it("can remove key with purpose", async () => { 46 | const id = await IdentityContract.new() 47 | await id.addKey(web3.sha3(accounts[1], { encoding: "hex" }), 11, 1) // Give accounts[1] FUNDS_MANAGEMENT purpose 48 | 49 | assert( 50 | await id.keyHasPurpose.call( 51 | web3.sha3(accounts[1], { encoding: "hex" }), 52 | 11 53 | ) 54 | ) 55 | const receipt = await id.removeKey( 56 | web3.sha3(accounts[1], { encoding: "hex" }), 57 | 11 58 | ) 59 | 60 | // actual gas used 37678 61 | assert( 62 | receipt.receipt.gasUsed < 38000, 63 | "Too much gas used to remove accessor from Identity" 64 | ) 65 | 66 | assert( 67 | !(await id.keyHasPurpose.call( 68 | web3.sha3(accounts[1], { encoding: "hex" }), 69 | 11 70 | )) 71 | ) 72 | }) 73 | 74 | it("can send and retrieve eth", async () => { 75 | const id = await IdentityContract.new() 76 | await id.addKey(web3.sha3(accounts[1], { encoding: "hex" }), 11, 1) // Give accounts[1] FUNDS_MANAGEMENT purpose 77 | 78 | const val = parseInt(web3.toWei(1, "ether"), 10) 79 | await id.sendTransaction({ 80 | from: accounts[1], 81 | value: val 82 | }) 83 | 84 | const contractBalance = web3.fromWei( 85 | web3.eth.getBalance(id.address).toString(), 86 | "ether" 87 | ) 88 | // comparison is done in eth 89 | assert.deepStrictEqual(parseInt(contractBalance, 10), 1) 90 | 91 | const receipt: any = await id.withdraw({ from: accounts[1] }) 92 | 93 | // actual gas used 30788 94 | assert( 95 | receipt.receipt.gasUsed < 31000, 96 | "Too much gas used to withdraw funds" 97 | ) 98 | 99 | const contractNewBalance = web3.fromWei( 100 | web3.eth.getBalance(id.address).toString(), 101 | "ether" 102 | ) 103 | // comparison is done in eth 104 | assert.deepStrictEqual(parseInt(contractNewBalance, 10), 0) 105 | }) 106 | 107 | it("person with non funds management privileges cannot withdraw", async () => { 108 | const id = await IdentityContract.new() 109 | const val = parseInt(web3.toWei(1, "ether"), 10) 110 | await id.addKey(web3.sha3(accounts[1], { encoding: "hex" }), 11, 1) // Give accounts[1] FUNDS_MANAGEMENT purpose 111 | await id.sendTransaction({ 112 | from: accounts[1], 113 | value: val 114 | }) 115 | 116 | const contractBalance = web3.fromWei( 117 | web3.eth.getBalance(id.address).toString(), 118 | "ether" 119 | ) 120 | // comparison is done in eth 121 | assert.deepStrictEqual(parseInt(contractBalance, 10), 1) 122 | 123 | try { 124 | await id.withdraw({ from: accounts[0] }) 125 | } catch (error) { 126 | assert.deepStrictEqual( 127 | error.message, 128 | "VM Exception while processing transaction: revert" 129 | ) 130 | } 131 | }) 132 | 133 | it("can receive and withdraw erc20 tokens", async () => { 134 | const token = await StandardToken.new(100) 135 | const accountTokenBalance = await token.balanceOf(accounts[0]) 136 | assert.deepStrictEqual(accountTokenBalance.toNumber(), 100) 137 | 138 | const id = await IdentityContract.new() 139 | await id.addKey(web3.sha3(accounts[0], { encoding: "hex" }), 11, 1) // Give accounts[0] FUNDS_MANAGEMENT purpose 140 | 141 | const receipt = await token.transfer(id.address, 100, { 142 | from: accounts[0] 143 | }) 144 | 145 | // actual gas used 36496 146 | assert(receipt.receipt.gasUsed < 37000, "Too much gas used!") 147 | 148 | const balance = await token.balanceOf.call(id.address) 149 | assert.deepStrictEqual(balance.toNumber(), 100) 150 | assert.deepStrictEqual( 151 | balance.toNumber(), 152 | (await id.getTokenBalance.call(token.address)).toNumber() 153 | ) 154 | 155 | const rec = await id.transferTokens(token.address, accounts[0], 100) 156 | const accountTokenBalance1 = await token.balanceOf.call(accounts[0]) 157 | // actual gas used 44865 158 | assert(rec.receipt.gasUsed < 45000, "Too much gas used to transfer tokens") 159 | assert.deepStrictEqual(accountTokenBalance1.toNumber(), 100) 160 | assert.deepStrictEqual( 161 | (await token.balanceOf.call(id.address)).toNumber(), 162 | 0 163 | ) 164 | }) 165 | }) 166 | -------------------------------------------------------------------------------- /test/Registry.test.ts: -------------------------------------------------------------------------------- 1 | import { assert } from "chai" 2 | 3 | const Registry = artifacts.require("Registry") 4 | 5 | const subject = "0x627306090abab3a6e1400e9345bc60c78a8bef57" // = accounts[0] = owner 6 | const issuer = "0xf17f52151ebef6c7334fad080c5704d77216b732" // = accounts[1] 7 | const id = "0x308cc5f7b4fe1e2ff905e309c501118487de4e83000000000000000000000000" 8 | const key = "0x308cc5f7b4fe1e2ff905e309c501118487de4e84000000000000000000000000" 9 | const data = 10 | "0x308cc5f7b4fe1e2ff905e309c501118487de4e85000000000000000000000000" 11 | 12 | contract("Registry", (accounts) => { 13 | it("owner can add claim for less than 38000 gas", async () => { 14 | const registry = await Registry.new() 15 | await registry.setClaim(subject, issuer, id, key, data, { 16 | gas: 1000000 17 | }) 18 | let totalGas = 0 19 | totalGas += await registry.setClaim.estimateGas( 20 | subject, 21 | issuer, 22 | id, 23 | key, 24 | data, 25 | { gas: 1000000 } 26 | ) 27 | assert.isBelow(totalGas, 38000) 28 | }) 29 | 30 | it("issuer can add claim", async () => { 31 | const registry = await Registry.new() 32 | await registry.setClaim( 33 | subject, 34 | issuer, 35 | id, 36 | key, 37 | data, 38 | { from: accounts[1], gas: 1000000 } // msg.sender = issuer 39 | ) 40 | }) 41 | 42 | it("add claim method throws if sender isn't issuer or owner", async () => { 43 | const registry = await Registry.new() 44 | registry 45 | .setClaim( 46 | "0xf17f52151ebef6c7334fad080c5704d77216b732", 47 | "0x627306090abab3a6e1400e9345bc60c78a8bef57", 48 | id, 49 | key, 50 | data, 51 | { from: accounts[1], gas: 1000000 } // msg.sender = subject 52 | ) 53 | .then(assert.fail) 54 | .catch((error: any) => { 55 | assert.include( 56 | error.message, 57 | "Exception while processing transaction: revert", 58 | "didn't throw a revert exception." 59 | ) 60 | }) 61 | }) 62 | 63 | it("emits ClaimSet event", async () => { 64 | const registry = await Registry.new() 65 | const result = await registry.setClaim(subject, issuer, id, key, data, { 66 | gas: 1000000 67 | }) 68 | assert.deepStrictEqual(result.logs[0].args, { 69 | subject, 70 | issuer, 71 | id, 72 | key, 73 | data, 74 | updatedAt: result.logs[0].args.updatedAt 75 | }) 76 | }) 77 | 78 | it("gets claim", async () => { 79 | const registry = await Registry.new() 80 | await registry.setClaim(subject, issuer, id, key, data, { 81 | gas: 1000000 82 | }) 83 | const receivedData = await registry.getClaim.call(subject, issuer, id, key) 84 | assert.deepStrictEqual(receivedData, data) 85 | }) 86 | 87 | it("subject can remove claim for less than 21000 gas", async () => { 88 | const registry = await Registry.new() 89 | await registry.setClaim(subject, issuer, id, key, data, { 90 | gas: 1000000 91 | }) 92 | let totalGas = 0 93 | totalGas += await registry.removeClaim.estimateGas(subject, issuer, id, key) 94 | assert.isBelow(totalGas, 21000) 95 | await registry.removeClaim(subject, issuer, id, key) 96 | const receivedData2 = await registry.getClaim.call(subject, issuer, id, key) 97 | assert.deepStrictEqual( 98 | receivedData2, 99 | "0x0000000000000000000000000000000000000000000000000000000000000000" 100 | ) 101 | }) 102 | 103 | it("issuer can remove claim", async () => { 104 | const registry = await Registry.new() 105 | await registry.setClaim(subject, issuer, id, key, data, { 106 | gas: 1000000 107 | }) 108 | await registry.removeClaim(subject, issuer, id, key, { 109 | from: accounts[1] // msg.sender = issuer 110 | }) 111 | const receivedData3 = await registry.getClaim.call(subject, issuer, id, key) 112 | assert.deepStrictEqual( 113 | receivedData3, 114 | "0x0000000000000000000000000000000000000000000000000000000000000000" 115 | ) 116 | }) 117 | 118 | it("owner can remove claim", async () => { 119 | const registry = await Registry.new() 120 | await registry.setClaim( 121 | "0xdeadbeef0abab3a6e1400e9345bc60c78a8bef57", 122 | "0xdeadbeef0abab3a6e1400e9345bc60c78a8bef57", 123 | id, 124 | key, 125 | data, 126 | { 127 | gas: 1000000 128 | } 129 | ) 130 | await registry.removeClaim( 131 | "0xdeadbeef0abab3a6e1400e9345bc60c78a8bef57", 132 | "0xdeadbeef0abab3a6e1400e9345bc60c78a8bef57", 133 | id, 134 | key, 135 | { 136 | from: accounts[0] // msg.sender = owner 137 | } 138 | ) 139 | const receivedData4 = await registry.getClaim.call( 140 | "0xdeadbeef0abab3a6e1400e9345bc60c78a8bef57", 141 | "0xdeadbeef0abab3a6e1400e9345bc60c78a8bef57", 142 | id, 143 | key 144 | ) 145 | assert.deepStrictEqual( 146 | receivedData4, 147 | "0x0000000000000000000000000000000000000000000000000000000000000000" 148 | ) 149 | }) 150 | 151 | it("remove claim method throws if sender isn't subject/issuer/owner", async () => { 152 | const registry = await Registry.new() 153 | await registry.setClaim(subject, issuer, id, key, data, { 154 | gas: 1000000 155 | }) 156 | registry 157 | .removeClaim(subject, issuer, id, key, { from: accounts[2] }) // msg.sender != issuer && != subject && != owner 158 | .then(assert.fail) 159 | .catch((error: any) => { 160 | assert.include( 161 | error.message, 162 | "Exception while processing transaction: revert", 163 | "didn't throw a revert exception." 164 | ) 165 | }) 166 | const receivedData6 = await registry.getClaim.call(subject, issuer, id, key) 167 | assert.deepStrictEqual(receivedData6, data) 168 | }) 169 | 170 | it("emits ClaimRemoved event", async () => { 171 | const registry = await Registry.new() 172 | await registry.setClaim(subject, issuer, id, key, data, { 173 | gas: 1000000 174 | }) 175 | const remove = await registry.removeClaim(subject, issuer, id, key) 176 | assert.deepStrictEqual(remove.logs[0].args, { 177 | subject, 178 | issuer, 179 | id, 180 | key, 181 | removedAt: remove.logs[0].args.removedAt 182 | }) 183 | }) 184 | }) 185 | -------------------------------------------------------------------------------- /test/ZincAcessor.test.ts: -------------------------------------------------------------------------------- 1 | import BigNumber from "bignumber.js" 2 | import { assert } from "chai" 3 | 4 | /*tslint:disable-next-line:no-var-requires*/ 5 | const ethSigUtil = require("eth-sig-util") 6 | const header1 = "string message" 7 | const header2 = "uint32 nonce" 8 | const privateKey = 9 | "7590B571C1F46A962F8507C162937E7B6AE934ED2CEA9AEE1F05691793DACA3C" 10 | const publicKey = "0x3D158a6D12d82B925E264217f834c8C9EdC5F3D5" 11 | const keyToAdd = "0x91f04cfa7c6c26cb080cc00e100403ca3bb86211" 12 | const eventSha = web3.sha3("UserIdentityCreated(address,address)") 13 | 14 | function createSignedMessage(key: string, nonce: number, message: string) { 15 | if (key.startsWith("0x")) { 16 | key = key.substr(2) 17 | } 18 | const data = [ 19 | { 20 | type: "string", 21 | name: "message", 22 | value: message 23 | }, 24 | { 25 | type: "uint32", 26 | name: "nonce", 27 | value: nonce 28 | } 29 | ] 30 | 31 | return { 32 | data, 33 | sig: ethSigUtil.signTypedData(Buffer.from(key, "hex"), { data }) 34 | } 35 | } 36 | 37 | function bigNumberArrayToNumber(arr: BigNumber[]) { 38 | return arr.map((x) => x.toNumber()) 39 | } 40 | 41 | const ZincAcessor = artifacts.require("ZincAccessor") 42 | const Identity = artifacts.require("Identity") 43 | 44 | contract("ZincAccessor", (accounts) => { 45 | it("should construct ZincAccessor and make a user Identity", async () => { 46 | const zinc = await ZincAcessor.new() 47 | const userAddress = "0x45896ebf214e6691bf83c1da386604d3a4e690b1" 48 | const receipt: any = await zinc.constructUserIdentity( 49 | userAddress, 50 | "Hi, user! Please sign this message so that we can verify you have the private key to this address", 51 | 2, 52 | header1, 53 | header2, 54 | "0x4d635a8daac62936e6c91a4c08bfe38cc03bb24533965db62f21301e18fc40e7", 55 | "0x0b4181429e289f8bb0e891bde0020487d82709fba61bc21367b0d8890ddf702b", 56 | 28 57 | ) 58 | 59 | // actual gas used 1506808 60 | assert( 61 | receipt.receipt.gasUsed < 1600000, 62 | "Too much gas used for constructUserIdentity" 63 | ) 64 | 65 | let idContractAddress 66 | 67 | if ( 68 | receipt.receipt.status && 69 | receipt.receipt.transactionHash && 70 | receipt.receipt.logs 71 | ) { 72 | for (const log of receipt.receipt.logs) { 73 | if (log.topics[0] === eventSha) { 74 | idContractAddress = `0x${log.topics[2].slice(-40)}` 75 | break 76 | } 77 | } 78 | const id = Identity.at(idContractAddress) 79 | 80 | const userPrivileges = await id.getKeyPurpose.call( 81 | web3.sha3(userAddress, { encoding: "hex" }) 82 | ) 83 | assert.deepStrictEqual(bigNumberArrayToNumber(userPrivileges), [1]) 84 | 85 | const zincPrivileges = await id.getKeyPurpose.call( 86 | web3.sha3(zinc.address, { encoding: "hex" }) 87 | ) 88 | assert.deepStrictEqual(bigNumberArrayToNumber(zincPrivileges), [1]) 89 | } 90 | }) 91 | 92 | it("can add accessor with a valid purpose", async () => { 93 | const purpose = 3 94 | 95 | const zinc = await ZincAcessor.new() 96 | const id = await Identity.new() 97 | await id.addKey(web3.sha3(zinc.address, { encoding: "hex" }), 1, 1) 98 | await id.addKey(web3.sha3(publicKey, { encoding: "hex" }), 1, 1) 99 | 100 | const message1 = `Add ${keyToAdd} to ${id.address} with purpose ${purpose}` 101 | 102 | let { sig } = createSignedMessage(privateKey, 1, message1) 103 | 104 | sig = sig.substr(2) // remove 0x 105 | const r = "0x" + sig.slice(0, 64) 106 | const s = "0x" + sig.slice(64, 128) 107 | const v = "0x" + sig.slice(128, 130) 108 | const vDecimal = web3.toDecimal(v) 109 | 110 | const receipt: any = await zinc.addAccessor( 111 | keyToAdd, 112 | id.address, 113 | purpose, 114 | publicKey, 115 | message1, 116 | 1, // nonce 117 | header1, 118 | header2, 119 | r, 120 | s, 121 | vDecimal 122 | ) 123 | 124 | // actual gas used 268273 125 | assert( 126 | receipt.receipt.gasUsed < 270000, 127 | "Too much gas used to add accessor" 128 | ) 129 | 130 | const purposeShouldBe = await id.getKeyPurpose.call( 131 | web3.sha3(keyToAdd, { encoding: "hex" }) 132 | ) 133 | 134 | assert.deepStrictEqual(bigNumberArrayToNumber(purposeShouldBe), [purpose]) 135 | }) 136 | 137 | it("can add and remove accessor with a valid purpose", async () => { 138 | const purpose = 3 139 | let nonce = 1 140 | 141 | const zinc = await ZincAcessor.new() 142 | const id = await Identity.new() 143 | await id.addKey(web3.sha3(zinc.address, { encoding: "hex" }), 1, 1) 144 | await id.addKey(web3.sha3(publicKey, { encoding: "hex" }), 1, 1) 145 | 146 | let message1 = `Add ${keyToAdd} to ${id.address} with purpose ${purpose}` 147 | 148 | let { sig } = createSignedMessage(privateKey, nonce, message1) 149 | 150 | sig = sig.substr(2) // remove 0x 151 | let r = "0x" + sig.slice(0, 64) 152 | let s = "0x" + sig.slice(64, 128) 153 | let v = "0x" + sig.slice(128, 130) 154 | let vDecimal = web3.toDecimal(v) 155 | 156 | await zinc.addAccessor( 157 | keyToAdd, 158 | id.address, 159 | purpose, 160 | publicKey, 161 | message1, 162 | nonce, 163 | header1, 164 | header2, 165 | r, 166 | s, 167 | vDecimal 168 | ) 169 | const purposeShouldBe = await id.getKeyPurpose.call( 170 | web3.sha3(keyToAdd, { encoding: "hex" }) 171 | ) 172 | 173 | assert.deepStrictEqual(bigNumberArrayToNumber(purposeShouldBe), [purpose]) 174 | 175 | // Code for removeAccessor begins here: 176 | 177 | ++nonce 178 | message1 = `Remove ${keyToAdd} from ${id.address} with purpose ${purpose}` 179 | 180 | sig = createSignedMessage(privateKey, nonce, message1).sig 181 | 182 | sig = sig.substr(2) // remove 0x 183 | r = "0x" + sig.slice(0, 64) 184 | s = "0x" + sig.slice(64, 128) 185 | v = "0x" + sig.slice(128, 130) 186 | vDecimal = web3.toDecimal(v) 187 | 188 | const receipt: any = await zinc.removeAccessor( 189 | keyToAdd, 190 | id.address, 191 | purpose, 192 | publicKey, 193 | message1, 194 | nonce, 195 | header1, 196 | header2, 197 | r, 198 | s, 199 | vDecimal 200 | ) 201 | 202 | // actual gas used 120708 203 | assert( 204 | receipt.receipt.gasUsed < 130000, 205 | "Too much gas used for removing accessor" 206 | ) 207 | 208 | const purposeShouldBeZero = await id.getKeyPurpose.call( 209 | web3.sha3(keyToAdd, { encoding: "hex" }) 210 | ) 211 | 212 | assert.deepStrictEqual(bigNumberArrayToNumber(purposeShouldBeZero), []) 213 | }) 214 | }) 215 | -------------------------------------------------------------------------------- /truffle-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // See 3 | // to customize your Truffle configuration! 4 | } 5 | -------------------------------------------------------------------------------- /truffle.d.ts: -------------------------------------------------------------------------------- 1 | // Autogenerated file 2 | // DO NOT EDIT!!! 3 | // You can update it by running `yarn generate-types` 4 | 5 | import * as Web3 from "web3" 6 | import * as BigNumber from "bignumber.js" 7 | 8 | type Address = string 9 | type TransactionOptions = Partial 10 | type UInt = number | BigNumber.BigNumber 11 | 12 | interface Transaction { 13 | hash: string 14 | nonce: number 15 | blockHash: string | null 16 | blockNumber: number | null 17 | transactionIndex: number | null 18 | from: Address | ContractInstance 19 | to: string | null 20 | value: UInt 21 | gasPrice: UInt 22 | gas: number 23 | input: string 24 | } 25 | 26 | interface ContractInstance { 27 | address: string 28 | sendTransaction(options?: TransactionOptions): Promise 29 | } 30 | 31 | export interface EncoderInstance extends ContractInstance { 32 | encodeUInt: { 33 | (uint: UInt, options?: TransactionOptions): Promise 34 | call: (uint: UInt, options?: TransactionOptions) => Promise 35 | estimateGas: ( 36 | subject: string, 37 | issuer: string, 38 | id: string, 39 | key: string, 40 | data?: string, 41 | options?: { 42 | from?: string 43 | gas?: number 44 | } 45 | ) => number 46 | } 47 | encodeAddress: { 48 | (address: Address, options?: TransactionOptions): Promise< 49 | Web3.TransactionReceipt 50 | > 51 | call: (address: Address, options?: TransactionOptions) => Promise 52 | estimateGas: ( 53 | subject: string, 54 | issuer: string, 55 | id: string, 56 | key: string, 57 | data?: string, 58 | options?: { 59 | from?: string 60 | gas?: number 61 | } 62 | ) => number 63 | } 64 | encodeString: { 65 | (str: string, options?: TransactionOptions): Promise< 66 | Web3.TransactionReceipt 67 | > 68 | call: (str: string, options?: TransactionOptions) => Promise 69 | estimateGas: ( 70 | subject: string, 71 | issuer: string, 72 | id: string, 73 | key: string, 74 | data?: string, 75 | options?: { 76 | from?: string 77 | gas?: number 78 | } 79 | ) => number 80 | } 81 | } 82 | 83 | export interface EncoderContract { 84 | new: () => Promise 85 | deployed(): Promise 86 | at(address: string): EncoderInstance 87 | } 88 | 89 | export interface ERC20Instance extends ContractInstance { 90 | totalSupply: { 91 | (options?: TransactionOptions): Promise 92 | call: (options?: TransactionOptions) => Promise 93 | estimateGas: ( 94 | subject: string, 95 | issuer: string, 96 | id: string, 97 | key: string, 98 | data?: string, 99 | options?: { 100 | from?: string 101 | gas?: number 102 | } 103 | ) => number 104 | } 105 | balanceOf: { 106 | (who: Address, options?: TransactionOptions): Promise< 107 | Web3.TransactionReceipt 108 | > 109 | call: ( 110 | who: Address, 111 | options?: TransactionOptions 112 | ) => Promise 113 | estimateGas: ( 114 | subject: string, 115 | issuer: string, 116 | id: string, 117 | key: string, 118 | data?: string, 119 | options?: { 120 | from?: string 121 | gas?: number 122 | } 123 | ) => number 124 | } 125 | allowance: { 126 | (owner: Address, spender: Address, options?: TransactionOptions): Promise< 127 | Web3.TransactionReceipt 128 | > 129 | call: ( 130 | owner: Address, 131 | spender: Address, 132 | options?: TransactionOptions 133 | ) => Promise 134 | estimateGas: ( 135 | subject: string, 136 | issuer: string, 137 | id: string, 138 | key: string, 139 | data?: string, 140 | options?: { 141 | from?: string 142 | gas?: number 143 | } 144 | ) => number 145 | } 146 | transfer: { 147 | (to: Address, value: UInt, options?: TransactionOptions): Promise< 148 | Web3.TransactionReceipt 149 | > 150 | call: ( 151 | to: Address, 152 | value: UInt, 153 | options?: TransactionOptions 154 | ) => Promise 155 | estimateGas: ( 156 | subject: string, 157 | issuer: string, 158 | id: string, 159 | key: string, 160 | data?: string, 161 | options?: { 162 | from?: string 163 | gas?: number 164 | } 165 | ) => number 166 | } 167 | approve: { 168 | (spender: Address, value: UInt, options?: TransactionOptions): Promise< 169 | Web3.TransactionReceipt 170 | > 171 | call: ( 172 | spender: Address, 173 | value: UInt, 174 | options?: TransactionOptions 175 | ) => Promise 176 | estimateGas: ( 177 | subject: string, 178 | issuer: string, 179 | id: string, 180 | key: string, 181 | data?: string, 182 | options?: { 183 | from?: string 184 | gas?: number 185 | } 186 | ) => number 187 | } 188 | transferFrom: { 189 | ( 190 | from: Address, 191 | to: Address, 192 | value: UInt, 193 | options?: TransactionOptions 194 | ): Promise 195 | call: ( 196 | from: Address, 197 | to: Address, 198 | value: UInt, 199 | options?: TransactionOptions 200 | ) => Promise 201 | estimateGas: ( 202 | subject: string, 203 | issuer: string, 204 | id: string, 205 | key: string, 206 | data?: string, 207 | options?: { 208 | from?: string 209 | gas?: number 210 | } 211 | ) => number 212 | } 213 | } 214 | 215 | export interface ERC20Contract { 216 | new: () => Promise 217 | deployed(): Promise 218 | at(address: string): ERC20Instance 219 | } 220 | 221 | export interface ERC20BasicInstance extends ContractInstance { 222 | balanceOf: { 223 | (who: Address, options?: TransactionOptions): Promise< 224 | Web3.TransactionReceipt 225 | > 226 | call: ( 227 | who: Address, 228 | options?: TransactionOptions 229 | ) => Promise 230 | estimateGas: ( 231 | subject: string, 232 | issuer: string, 233 | id: string, 234 | key: string, 235 | data?: string, 236 | options?: { 237 | from?: string 238 | gas?: number 239 | } 240 | ) => number 241 | } 242 | transfer: { 243 | (to: Address, value: UInt, options?: TransactionOptions): Promise< 244 | Web3.TransactionReceipt 245 | > 246 | call: ( 247 | to: Address, 248 | value: UInt, 249 | options?: TransactionOptions 250 | ) => Promise 251 | estimateGas: ( 252 | subject: string, 253 | issuer: string, 254 | id: string, 255 | key: string, 256 | data?: string, 257 | options?: { 258 | from?: string 259 | gas?: number 260 | } 261 | ) => number 262 | } 263 | } 264 | 265 | export interface ERC20BasicContract { 266 | new: () => Promise 267 | deployed(): Promise 268 | at(address: string): ERC20BasicInstance 269 | } 270 | 271 | export interface ERC725Instance extends ContractInstance { 272 | MANAGEMENT_KEY: { 273 | (options?: TransactionOptions): Promise 274 | call: (options?: TransactionOptions) => Promise 275 | estimateGas: ( 276 | subject: string, 277 | issuer: string, 278 | id: string, 279 | key: string, 280 | data?: string, 281 | options?: { 282 | from?: string 283 | gas?: number 284 | } 285 | ) => number 286 | } 287 | ACTION_KEY: { 288 | (options?: TransactionOptions): Promise 289 | call: (options?: TransactionOptions) => Promise 290 | estimateGas: ( 291 | subject: string, 292 | issuer: string, 293 | id: string, 294 | key: string, 295 | data?: string, 296 | options?: { 297 | from?: string 298 | gas?: number 299 | } 300 | ) => number 301 | } 302 | ENCRYPTION_KEY: { 303 | (options?: TransactionOptions): Promise 304 | call: (options?: TransactionOptions) => Promise 305 | estimateGas: ( 306 | subject: string, 307 | issuer: string, 308 | id: string, 309 | key: string, 310 | data?: string, 311 | options?: { 312 | from?: string 313 | gas?: number 314 | } 315 | ) => number 316 | } 317 | CLAIM_SIGNER_KEY: { 318 | (options?: TransactionOptions): Promise 319 | call: (options?: TransactionOptions) => Promise 320 | estimateGas: ( 321 | subject: string, 322 | issuer: string, 323 | id: string, 324 | key: string, 325 | data?: string, 326 | options?: { 327 | from?: string 328 | gas?: number 329 | } 330 | ) => number 331 | } 332 | 333 | getKey: { 334 | (key: string, options?: TransactionOptions): Promise< 335 | Web3.TransactionReceipt 336 | > 337 | call: ( 338 | key: string, 339 | options?: TransactionOptions 340 | ) => Promise<[BigNumber.BigNumber[], BigNumber.BigNumber, string]> 341 | estimateGas: ( 342 | subject: string, 343 | issuer: string, 344 | id: string, 345 | key: string, 346 | data?: string, 347 | options?: { 348 | from?: string 349 | gas?: number 350 | } 351 | ) => number 352 | } 353 | getKeyPurpose: { 354 | (key: string, options?: TransactionOptions): Promise< 355 | Web3.TransactionReceipt 356 | > 357 | call: ( 358 | key: string, 359 | options?: TransactionOptions 360 | ) => Promise 361 | estimateGas: ( 362 | subject: string, 363 | issuer: string, 364 | id: string, 365 | key: string, 366 | data?: string, 367 | options?: { 368 | from?: string 369 | gas?: number 370 | } 371 | ) => number 372 | } 373 | getKeysByPurpose: { 374 | (purpose: UInt, options?: TransactionOptions): Promise< 375 | Web3.TransactionReceipt 376 | > 377 | call: (purpose: UInt, options?: TransactionOptions) => Promise 378 | estimateGas: ( 379 | subject: string, 380 | issuer: string, 381 | id: string, 382 | key: string, 383 | data?: string, 384 | options?: { 385 | from?: string 386 | gas?: number 387 | } 388 | ) => number 389 | } 390 | addKey: { 391 | ( 392 | key: string, 393 | purpose: UInt, 394 | keyType: UInt, 395 | options?: TransactionOptions 396 | ): Promise 397 | call: ( 398 | key: string, 399 | purpose: UInt, 400 | keyType: UInt, 401 | options?: TransactionOptions 402 | ) => Promise 403 | estimateGas: ( 404 | subject: string, 405 | issuer: string, 406 | id: string, 407 | key: string, 408 | data?: string, 409 | options?: { 410 | from?: string 411 | gas?: number 412 | } 413 | ) => number 414 | } 415 | removeKey: { 416 | (key: string, purpose: UInt, options?: TransactionOptions): Promise< 417 | Web3.TransactionReceipt 418 | > 419 | call: ( 420 | key: string, 421 | purpose: UInt, 422 | options?: TransactionOptions 423 | ) => Promise 424 | estimateGas: ( 425 | subject: string, 426 | issuer: string, 427 | id: string, 428 | key: string, 429 | data?: string, 430 | options?: { 431 | from?: string 432 | gas?: number 433 | } 434 | ) => number 435 | } 436 | execute: { 437 | ( 438 | to: Address, 439 | value: UInt, 440 | data: string, 441 | options?: TransactionOptions 442 | ): Promise 443 | call: ( 444 | to: Address, 445 | value: UInt, 446 | data: string, 447 | options?: TransactionOptions 448 | ) => Promise 449 | estimateGas: ( 450 | subject: string, 451 | issuer: string, 452 | id: string, 453 | key: string, 454 | data?: string, 455 | options?: { 456 | from?: string 457 | gas?: number 458 | } 459 | ) => number 460 | } 461 | approve: { 462 | (id: UInt, approve: boolean, options?: TransactionOptions): Promise< 463 | Web3.TransactionReceipt 464 | > 465 | call: ( 466 | id: UInt, 467 | approve: boolean, 468 | options?: TransactionOptions 469 | ) => Promise 470 | estimateGas: ( 471 | subject: string, 472 | issuer: string, 473 | id: string, 474 | key: string, 475 | data?: string, 476 | options?: { 477 | from?: string 478 | gas?: number 479 | } 480 | ) => number 481 | } 482 | } 483 | 484 | export interface ERC725Contract { 485 | new: () => Promise 486 | deployed(): Promise 487 | at(address: string): ERC725Instance 488 | } 489 | 490 | export interface IdentityInstance extends ContractInstance { 491 | MANAGEMENT_KEY: { 492 | (options?: TransactionOptions): Promise 493 | call: (options?: TransactionOptions) => Promise 494 | estimateGas: ( 495 | subject: string, 496 | issuer: string, 497 | id: string, 498 | key: string, 499 | data?: string, 500 | options?: { 501 | from?: string 502 | gas?: number 503 | } 504 | ) => number 505 | } 506 | ACTION_KEY: { 507 | (options?: TransactionOptions): Promise 508 | call: (options?: TransactionOptions) => Promise 509 | estimateGas: ( 510 | subject: string, 511 | issuer: string, 512 | id: string, 513 | key: string, 514 | data?: string, 515 | options?: { 516 | from?: string 517 | gas?: number 518 | } 519 | ) => number 520 | } 521 | ENCRYPTION_KEY: { 522 | (options?: TransactionOptions): Promise 523 | call: (options?: TransactionOptions) => Promise 524 | estimateGas: ( 525 | subject: string, 526 | issuer: string, 527 | id: string, 528 | key: string, 529 | data?: string, 530 | options?: { 531 | from?: string 532 | gas?: number 533 | } 534 | ) => number 535 | } 536 | CLAIM_SIGNER_KEY: { 537 | (options?: TransactionOptions): Promise 538 | call: (options?: TransactionOptions) => Promise 539 | estimateGas: ( 540 | subject: string, 541 | issuer: string, 542 | id: string, 543 | key: string, 544 | data?: string, 545 | options?: { 546 | from?: string 547 | gas?: number 548 | } 549 | ) => number 550 | } 551 | 552 | getKey: { 553 | (key: string, options?: TransactionOptions): Promise< 554 | Web3.TransactionReceipt 555 | > 556 | call: ( 557 | key: string, 558 | options?: TransactionOptions 559 | ) => Promise<[BigNumber.BigNumber[], BigNumber.BigNumber, string]> 560 | estimateGas: ( 561 | subject: string, 562 | issuer: string, 563 | id: string, 564 | key: string, 565 | data?: string, 566 | options?: { 567 | from?: string 568 | gas?: number 569 | } 570 | ) => number 571 | } 572 | getKeyPurpose: { 573 | (key: string, options?: TransactionOptions): Promise< 574 | Web3.TransactionReceipt 575 | > 576 | call: ( 577 | key: string, 578 | options?: TransactionOptions 579 | ) => Promise 580 | estimateGas: ( 581 | subject: string, 582 | issuer: string, 583 | id: string, 584 | key: string, 585 | data?: string, 586 | options?: { 587 | from?: string 588 | gas?: number 589 | } 590 | ) => number 591 | } 592 | getKeysByPurpose: { 593 | (purpose: UInt, options?: TransactionOptions): Promise< 594 | Web3.TransactionReceipt 595 | > 596 | call: (purpose: UInt, options?: TransactionOptions) => Promise 597 | estimateGas: ( 598 | subject: string, 599 | issuer: string, 600 | id: string, 601 | key: string, 602 | data?: string, 603 | options?: { 604 | from?: string 605 | gas?: number 606 | } 607 | ) => number 608 | } 609 | addKey: { 610 | ( 611 | key: string, 612 | purpose: UInt, 613 | type: UInt, 614 | options?: TransactionOptions 615 | ): Promise 616 | call: ( 617 | key: string, 618 | purpose: UInt, 619 | type: UInt, 620 | options?: TransactionOptions 621 | ) => Promise 622 | estimateGas: ( 623 | subject: string, 624 | issuer: string, 625 | id: string, 626 | key: string, 627 | data?: string, 628 | options?: { 629 | from?: string 630 | gas?: number 631 | } 632 | ) => number 633 | } 634 | approve: { 635 | (id: UInt, approve: boolean, options?: TransactionOptions): Promise< 636 | Web3.TransactionReceipt 637 | > 638 | call: ( 639 | id: UInt, 640 | approve: boolean, 641 | options?: TransactionOptions 642 | ) => Promise 643 | estimateGas: ( 644 | subject: string, 645 | issuer: string, 646 | id: string, 647 | key: string, 648 | data?: string, 649 | options?: { 650 | from?: string 651 | gas?: number 652 | } 653 | ) => number 654 | } 655 | execute: { 656 | ( 657 | to: Address, 658 | value: UInt, 659 | data: string, 660 | options?: TransactionOptions 661 | ): Promise 662 | call: ( 663 | to: Address, 664 | value: UInt, 665 | data: string, 666 | options?: TransactionOptions 667 | ) => Promise 668 | estimateGas: ( 669 | subject: string, 670 | issuer: string, 671 | id: string, 672 | key: string, 673 | data?: string, 674 | options?: { 675 | from?: string 676 | gas?: number 677 | } 678 | ) => number 679 | } 680 | removeKey: { 681 | (key: string, purpose: UInt, options?: TransactionOptions): Promise< 682 | Web3.TransactionReceipt 683 | > 684 | call: ( 685 | key: string, 686 | purpose: UInt, 687 | options?: TransactionOptions 688 | ) => Promise 689 | estimateGas: ( 690 | subject: string, 691 | issuer: string, 692 | id: string, 693 | key: string, 694 | data?: string, 695 | options?: { 696 | from?: string 697 | gas?: number 698 | } 699 | ) => number 700 | } 701 | keyHasPurpose: { 702 | (key: string, purpose: UInt, options?: TransactionOptions): Promise< 703 | Web3.TransactionReceipt 704 | > 705 | call: ( 706 | key: string, 707 | purpose: UInt, 708 | options?: TransactionOptions 709 | ) => Promise 710 | estimateGas: ( 711 | subject: string, 712 | issuer: string, 713 | id: string, 714 | key: string, 715 | data?: string, 716 | options?: { 717 | from?: string 718 | gas?: number 719 | } 720 | ) => number 721 | } 722 | withdraw: { 723 | (options?: TransactionOptions): Promise 724 | call: (options?: TransactionOptions) => Promise 725 | estimateGas: ( 726 | subject: string, 727 | issuer: string, 728 | id: string, 729 | key: string, 730 | data?: string, 731 | options?: { 732 | from?: string 733 | gas?: number 734 | } 735 | ) => number 736 | } 737 | transferEth: { 738 | (amount: UInt, account: Address, options?: TransactionOptions): Promise< 739 | Web3.TransactionReceipt 740 | > 741 | call: ( 742 | amount: UInt, 743 | account: Address, 744 | options?: TransactionOptions 745 | ) => Promise 746 | estimateGas: ( 747 | subject: string, 748 | issuer: string, 749 | id: string, 750 | key: string, 751 | data?: string, 752 | options?: { 753 | from?: string 754 | gas?: number 755 | } 756 | ) => number 757 | } 758 | getBalance: { 759 | (options?: TransactionOptions): Promise 760 | call: (options?: TransactionOptions) => Promise 761 | estimateGas: ( 762 | subject: string, 763 | issuer: string, 764 | id: string, 765 | key: string, 766 | data?: string, 767 | options?: { 768 | from?: string 769 | gas?: number 770 | } 771 | ) => number 772 | } 773 | getTokenBalance: { 774 | (token: Address, options?: TransactionOptions): Promise< 775 | Web3.TransactionReceipt 776 | > 777 | call: ( 778 | token: Address, 779 | options?: TransactionOptions 780 | ) => Promise 781 | estimateGas: ( 782 | subject: string, 783 | issuer: string, 784 | id: string, 785 | key: string, 786 | data?: string, 787 | options?: { 788 | from?: string 789 | gas?: number 790 | } 791 | ) => number 792 | } 793 | withdrawTokens: { 794 | (token: Address, options?: TransactionOptions): Promise< 795 | Web3.TransactionReceipt 796 | > 797 | call: ( 798 | token: Address, 799 | options?: TransactionOptions 800 | ) => Promise 801 | estimateGas: ( 802 | subject: string, 803 | issuer: string, 804 | id: string, 805 | key: string, 806 | data?: string, 807 | options?: { 808 | from?: string 809 | gas?: number 810 | } 811 | ) => number 812 | } 813 | transferTokens: { 814 | ( 815 | token: Address, 816 | to: Address, 817 | amount: UInt, 818 | options?: TransactionOptions 819 | ): Promise 820 | call: ( 821 | token: Address, 822 | to: Address, 823 | amount: UInt, 824 | options?: TransactionOptions 825 | ) => Promise 826 | estimateGas: ( 827 | subject: string, 828 | issuer: string, 829 | id: string, 830 | key: string, 831 | data?: string, 832 | options?: { 833 | from?: string 834 | gas?: number 835 | } 836 | ) => number 837 | } 838 | } 839 | 840 | export interface IdentityContract { 841 | new: () => Promise 842 | deployed(): Promise 843 | at(address: string): IdentityInstance 844 | } 845 | 846 | export interface MigrationsInstance extends ContractInstance { 847 | last_completed_migration: { 848 | (options?: TransactionOptions): Promise 849 | call: (options?: TransactionOptions) => Promise 850 | estimateGas: ( 851 | subject: string, 852 | issuer: string, 853 | id: string, 854 | key: string, 855 | data?: string, 856 | options?: { 857 | from?: string 858 | gas?: number 859 | } 860 | ) => number 861 | } 862 | owner: { 863 | (options?: TransactionOptions): Promise 864 | call: (options?: TransactionOptions) => Promise
865 | estimateGas: ( 866 | subject: string, 867 | issuer: string, 868 | id: string, 869 | key: string, 870 | data?: string, 871 | options?: { 872 | from?: string 873 | gas?: number 874 | } 875 | ) => number 876 | } 877 | 878 | setCompleted: { 879 | (completed: UInt, options?: TransactionOptions): Promise< 880 | Web3.TransactionReceipt 881 | > 882 | call: ( 883 | completed: UInt, 884 | options?: TransactionOptions 885 | ) => Promise 886 | estimateGas: ( 887 | subject: string, 888 | issuer: string, 889 | id: string, 890 | key: string, 891 | data?: string, 892 | options?: { 893 | from?: string 894 | gas?: number 895 | } 896 | ) => number 897 | } 898 | upgrade: { 899 | (new_address: Address, options?: TransactionOptions): Promise< 900 | Web3.TransactionReceipt 901 | > 902 | call: ( 903 | new_address: Address, 904 | options?: TransactionOptions 905 | ) => Promise 906 | estimateGas: ( 907 | subject: string, 908 | issuer: string, 909 | id: string, 910 | key: string, 911 | data?: string, 912 | options?: { 913 | from?: string 914 | gas?: number 915 | } 916 | ) => number 917 | } 918 | } 919 | 920 | export interface MigrationsContract { 921 | new: () => Promise 922 | deployed(): Promise 923 | at(address: string): MigrationsInstance 924 | } 925 | 926 | export interface OwnableInstance extends ContractInstance { 927 | owner: { 928 | (options?: TransactionOptions): Promise 929 | call: (options?: TransactionOptions) => Promise
930 | estimateGas: ( 931 | subject: string, 932 | issuer: string, 933 | id: string, 934 | key: string, 935 | data?: string, 936 | options?: { 937 | from?: string 938 | gas?: number 939 | } 940 | ) => number 941 | } 942 | 943 | renounceOwnership: { 944 | (options?: TransactionOptions): Promise 945 | call: (options?: TransactionOptions) => Promise 946 | estimateGas: ( 947 | subject: string, 948 | issuer: string, 949 | id: string, 950 | key: string, 951 | data?: string, 952 | options?: { 953 | from?: string 954 | gas?: number 955 | } 956 | ) => number 957 | } 958 | transferOwnership: { 959 | (newOwner: Address, options?: TransactionOptions): Promise< 960 | Web3.TransactionReceipt 961 | > 962 | call: ( 963 | newOwner: Address, 964 | options?: TransactionOptions 965 | ) => Promise 966 | estimateGas: ( 967 | subject: string, 968 | issuer: string, 969 | id: string, 970 | key: string, 971 | data?: string, 972 | options?: { 973 | from?: string 974 | gas?: number 975 | } 976 | ) => number 977 | } 978 | } 979 | 980 | export interface OwnableContract { 981 | new: () => Promise 982 | deployed(): Promise 983 | at(address: string): OwnableInstance 984 | } 985 | 986 | export interface RegistryInstance extends ContractInstance { 987 | renounceOwnership: { 988 | (options?: TransactionOptions): Promise 989 | call: (options?: TransactionOptions) => Promise 990 | estimateGas: ( 991 | subject: string, 992 | issuer: string, 993 | id: string, 994 | key: string, 995 | data?: string, 996 | options?: { 997 | from?: string 998 | gas?: number 999 | } 1000 | ) => number 1001 | } 1002 | owner: { 1003 | (options?: TransactionOptions): Promise 1004 | call: (options?: TransactionOptions) => Promise
1005 | estimateGas: ( 1006 | subject: string, 1007 | issuer: string, 1008 | id: string, 1009 | key: string, 1010 | data?: string, 1011 | options?: { 1012 | from?: string 1013 | gas?: number 1014 | } 1015 | ) => number 1016 | } 1017 | transferOwnership: { 1018 | (newOwner: Address, options?: TransactionOptions): Promise< 1019 | Web3.TransactionReceipt 1020 | > 1021 | call: ( 1022 | newOwner: Address, 1023 | options?: TransactionOptions 1024 | ) => Promise 1025 | estimateGas: ( 1026 | subject: string, 1027 | issuer: string, 1028 | id: string, 1029 | key: string, 1030 | data?: string, 1031 | options?: { 1032 | from?: string 1033 | gas?: number 1034 | } 1035 | ) => number 1036 | } 1037 | 1038 | setClaim: { 1039 | ( 1040 | subject: Address, 1041 | issuer: Address, 1042 | id: string, 1043 | key: string, 1044 | data: string, 1045 | options?: TransactionOptions 1046 | ): Promise 1047 | call: ( 1048 | subject: Address, 1049 | issuer: Address, 1050 | id: string, 1051 | key: string, 1052 | data: string, 1053 | options?: TransactionOptions 1054 | ) => Promise 1055 | estimateGas: ( 1056 | subject: string, 1057 | issuer: string, 1058 | id: string, 1059 | key: string, 1060 | data?: string, 1061 | options?: { 1062 | from?: string 1063 | gas?: number 1064 | } 1065 | ) => number 1066 | } 1067 | getClaim: { 1068 | ( 1069 | subject: Address, 1070 | issuer: Address, 1071 | id: string, 1072 | key: string, 1073 | options?: TransactionOptions 1074 | ): Promise 1075 | call: ( 1076 | subject: Address, 1077 | issuer: Address, 1078 | id: string, 1079 | key: string, 1080 | options?: TransactionOptions 1081 | ) => Promise 1082 | estimateGas: ( 1083 | subject: string, 1084 | issuer: string, 1085 | id: string, 1086 | key: string, 1087 | data?: string, 1088 | options?: { 1089 | from?: string 1090 | gas?: number 1091 | } 1092 | ) => number 1093 | } 1094 | removeClaim: { 1095 | ( 1096 | subject: Address, 1097 | issuer: Address, 1098 | id: string, 1099 | key: string, 1100 | options?: TransactionOptions 1101 | ): Promise 1102 | call: ( 1103 | subject: Address, 1104 | issuer: Address, 1105 | id: string, 1106 | key: string, 1107 | options?: TransactionOptions 1108 | ) => Promise 1109 | estimateGas: ( 1110 | subject: string, 1111 | issuer: string, 1112 | id: string, 1113 | key: string, 1114 | data?: string, 1115 | options?: { 1116 | from?: string 1117 | gas?: number 1118 | } 1119 | ) => number 1120 | } 1121 | } 1122 | 1123 | export interface RegistryContract { 1124 | new: () => Promise 1125 | deployed(): Promise 1126 | at(address: string): RegistryInstance 1127 | } 1128 | 1129 | export interface SafeMathInstance extends ContractInstance {} 1130 | 1131 | export interface SafeMathContract { 1132 | new: () => Promise 1133 | deployed(): Promise 1134 | at(address: string): SafeMathInstance 1135 | } 1136 | 1137 | export interface SignatureValidatorInstance extends ContractInstance { 1138 | checkSignature: { 1139 | ( 1140 | message1: string, 1141 | nonce: UInt, 1142 | header1: string, 1143 | header2: string, 1144 | r: string, 1145 | s: string, 1146 | v: UInt, 1147 | options?: TransactionOptions 1148 | ): Promise 1149 | call: ( 1150 | message1: string, 1151 | nonce: UInt, 1152 | header1: string, 1153 | header2: string, 1154 | r: string, 1155 | s: string, 1156 | v: UInt, 1157 | options?: TransactionOptions 1158 | ) => Promise
1159 | estimateGas: ( 1160 | subject: string, 1161 | issuer: string, 1162 | id: string, 1163 | key: string, 1164 | data?: string, 1165 | options?: { 1166 | from?: string 1167 | gas?: number 1168 | } 1169 | ) => number 1170 | } 1171 | } 1172 | 1173 | export interface SignatureValidatorContract { 1174 | new: () => Promise 1175 | deployed(): Promise 1176 | at(address: string): SignatureValidatorInstance 1177 | } 1178 | 1179 | export interface StandardTokenInstance extends ContractInstance { 1180 | totalSupply: { 1181 | (options?: TransactionOptions): Promise 1182 | call: (options?: TransactionOptions) => Promise 1183 | estimateGas: ( 1184 | subject: string, 1185 | issuer: string, 1186 | id: string, 1187 | key: string, 1188 | data?: string, 1189 | options?: { 1190 | from?: string 1191 | gas?: number 1192 | } 1193 | ) => number 1194 | } 1195 | balanceOf: { 1196 | (owner: Address, options?: TransactionOptions): Promise< 1197 | Web3.TransactionReceipt 1198 | > 1199 | call: ( 1200 | owner: Address, 1201 | options?: TransactionOptions 1202 | ) => Promise 1203 | estimateGas: ( 1204 | subject: string, 1205 | issuer: string, 1206 | id: string, 1207 | key: string, 1208 | data?: string, 1209 | options?: { 1210 | from?: string 1211 | gas?: number 1212 | } 1213 | ) => number 1214 | } 1215 | allowance: { 1216 | (owner: Address, spender: Address, options?: TransactionOptions): Promise< 1217 | Web3.TransactionReceipt 1218 | > 1219 | call: ( 1220 | owner: Address, 1221 | spender: Address, 1222 | options?: TransactionOptions 1223 | ) => Promise 1224 | estimateGas: ( 1225 | subject: string, 1226 | issuer: string, 1227 | id: string, 1228 | key: string, 1229 | data?: string, 1230 | options?: { 1231 | from?: string 1232 | gas?: number 1233 | } 1234 | ) => number 1235 | } 1236 | transfer: { 1237 | (to: Address, value: UInt, options?: TransactionOptions): Promise< 1238 | Web3.TransactionReceipt 1239 | > 1240 | call: ( 1241 | to: Address, 1242 | value: UInt, 1243 | options?: TransactionOptions 1244 | ) => Promise 1245 | estimateGas: ( 1246 | subject: string, 1247 | issuer: string, 1248 | id: string, 1249 | key: string, 1250 | data?: string, 1251 | options?: { 1252 | from?: string 1253 | gas?: number 1254 | } 1255 | ) => number 1256 | } 1257 | approve: { 1258 | (spender: Address, value: UInt, options?: TransactionOptions): Promise< 1259 | Web3.TransactionReceipt 1260 | > 1261 | call: ( 1262 | spender: Address, 1263 | value: UInt, 1264 | options?: TransactionOptions 1265 | ) => Promise 1266 | estimateGas: ( 1267 | subject: string, 1268 | issuer: string, 1269 | id: string, 1270 | key: string, 1271 | data?: string, 1272 | options?: { 1273 | from?: string 1274 | gas?: number 1275 | } 1276 | ) => number 1277 | } 1278 | transferFrom: { 1279 | ( 1280 | from: Address, 1281 | to: Address, 1282 | value: UInt, 1283 | options?: TransactionOptions 1284 | ): Promise 1285 | call: ( 1286 | from: Address, 1287 | to: Address, 1288 | value: UInt, 1289 | options?: TransactionOptions 1290 | ) => Promise 1291 | estimateGas: ( 1292 | subject: string, 1293 | issuer: string, 1294 | id: string, 1295 | key: string, 1296 | data?: string, 1297 | options?: { 1298 | from?: string 1299 | gas?: number 1300 | } 1301 | ) => number 1302 | } 1303 | increaseApproval: { 1304 | (spender: Address, addedValue: UInt, options?: TransactionOptions): Promise< 1305 | Web3.TransactionReceipt 1306 | > 1307 | call: ( 1308 | spender: Address, 1309 | addedValue: UInt, 1310 | options?: TransactionOptions 1311 | ) => Promise 1312 | estimateGas: ( 1313 | subject: string, 1314 | issuer: string, 1315 | id: string, 1316 | key: string, 1317 | data?: string, 1318 | options?: { 1319 | from?: string 1320 | gas?: number 1321 | } 1322 | ) => number 1323 | } 1324 | decreaseApproval: { 1325 | ( 1326 | spender: Address, 1327 | subtractedValue: UInt, 1328 | options?: TransactionOptions 1329 | ): Promise 1330 | call: ( 1331 | spender: Address, 1332 | subtractedValue: UInt, 1333 | options?: TransactionOptions 1334 | ) => Promise 1335 | estimateGas: ( 1336 | subject: string, 1337 | issuer: string, 1338 | id: string, 1339 | key: string, 1340 | data?: string, 1341 | options?: { 1342 | from?: string 1343 | gas?: number 1344 | } 1345 | ) => number 1346 | } 1347 | } 1348 | 1349 | export interface StandardTokenContract { 1350 | new: (totalSupply: UInt) => Promise 1351 | deployed(): Promise 1352 | at(address: string): StandardTokenInstance 1353 | } 1354 | 1355 | export interface ZincAccessorInstance extends ContractInstance { 1356 | checkSignature: { 1357 | ( 1358 | message1: string, 1359 | nonce: UInt, 1360 | header1: string, 1361 | header2: string, 1362 | r: string, 1363 | s: string, 1364 | v: UInt, 1365 | options?: TransactionOptions 1366 | ): Promise 1367 | call: ( 1368 | message1: string, 1369 | nonce: UInt, 1370 | header1: string, 1371 | header2: string, 1372 | r: string, 1373 | s: string, 1374 | v: UInt, 1375 | options?: TransactionOptions 1376 | ) => Promise
1377 | estimateGas: ( 1378 | subject: string, 1379 | issuer: string, 1380 | id: string, 1381 | key: string, 1382 | data?: string, 1383 | options?: { 1384 | from?: string 1385 | gas?: number 1386 | } 1387 | ) => number 1388 | } 1389 | encodeUInt: { 1390 | (uint: UInt, options?: TransactionOptions): Promise 1391 | call: (uint: UInt, options?: TransactionOptions) => Promise 1392 | estimateGas: ( 1393 | subject: string, 1394 | issuer: string, 1395 | id: string, 1396 | key: string, 1397 | data?: string, 1398 | options?: { 1399 | from?: string 1400 | gas?: number 1401 | } 1402 | ) => number 1403 | } 1404 | nonce: { 1405 | (options?: TransactionOptions): Promise 1406 | call: (options?: TransactionOptions) => Promise 1407 | estimateGas: ( 1408 | subject: string, 1409 | issuer: string, 1410 | id: string, 1411 | key: string, 1412 | data?: string, 1413 | options?: { 1414 | from?: string 1415 | gas?: number 1416 | } 1417 | ) => number 1418 | } 1419 | encodeAddress: { 1420 | (address: Address, options?: TransactionOptions): Promise< 1421 | Web3.TransactionReceipt 1422 | > 1423 | call: (address: Address, options?: TransactionOptions) => Promise 1424 | estimateGas: ( 1425 | subject: string, 1426 | issuer: string, 1427 | id: string, 1428 | key: string, 1429 | data?: string, 1430 | options?: { 1431 | from?: string 1432 | gas?: number 1433 | } 1434 | ) => number 1435 | } 1436 | encodeString: { 1437 | (str: string, options?: TransactionOptions): Promise< 1438 | Web3.TransactionReceipt 1439 | > 1440 | call: (str: string, options?: TransactionOptions) => Promise 1441 | estimateGas: ( 1442 | subject: string, 1443 | issuer: string, 1444 | id: string, 1445 | key: string, 1446 | data?: string, 1447 | options?: { 1448 | from?: string 1449 | gas?: number 1450 | } 1451 | ) => number 1452 | } 1453 | 1454 | constructUserIdentity: { 1455 | ( 1456 | userAddress: Address, 1457 | message1: string, 1458 | nonce: UInt, 1459 | header1: string, 1460 | header2: string, 1461 | r: string, 1462 | s: string, 1463 | v: UInt, 1464 | options?: TransactionOptions 1465 | ): Promise 1466 | call: ( 1467 | userAddress: Address, 1468 | message1: string, 1469 | nonce: UInt, 1470 | header1: string, 1471 | header2: string, 1472 | r: string, 1473 | s: string, 1474 | v: UInt, 1475 | options?: TransactionOptions 1476 | ) => Promise
1477 | estimateGas: ( 1478 | subject: string, 1479 | issuer: string, 1480 | id: string, 1481 | key: string, 1482 | data?: string, 1483 | options?: { 1484 | from?: string 1485 | gas?: number 1486 | } 1487 | ) => number 1488 | } 1489 | addAccessor: { 1490 | ( 1491 | key: Address, 1492 | idContract: Address, 1493 | purpose: UInt, 1494 | userAddress: Address, 1495 | message1: string, 1496 | nonce: UInt, 1497 | header1: string, 1498 | header2: string, 1499 | r: string, 1500 | s: string, 1501 | v: UInt, 1502 | options?: TransactionOptions 1503 | ): Promise 1504 | call: ( 1505 | key: Address, 1506 | idContract: Address, 1507 | purpose: UInt, 1508 | userAddress: Address, 1509 | message1: string, 1510 | nonce: UInt, 1511 | header1: string, 1512 | header2: string, 1513 | r: string, 1514 | s: string, 1515 | v: UInt, 1516 | options?: TransactionOptions 1517 | ) => Promise 1518 | estimateGas: ( 1519 | subject: string, 1520 | issuer: string, 1521 | id: string, 1522 | key: string, 1523 | data?: string, 1524 | options?: { 1525 | from?: string 1526 | gas?: number 1527 | } 1528 | ) => number 1529 | } 1530 | removeAccessor: { 1531 | ( 1532 | key: Address, 1533 | idContract: Address, 1534 | purpose: UInt, 1535 | userAddress: Address, 1536 | message1: string, 1537 | nonce: UInt, 1538 | header1: string, 1539 | header2: string, 1540 | r: string, 1541 | s: string, 1542 | v: UInt, 1543 | options?: TransactionOptions 1544 | ): Promise 1545 | call: ( 1546 | key: Address, 1547 | idContract: Address, 1548 | purpose: UInt, 1549 | userAddress: Address, 1550 | message1: string, 1551 | nonce: UInt, 1552 | header1: string, 1553 | header2: string, 1554 | r: string, 1555 | s: string, 1556 | v: UInt, 1557 | options?: TransactionOptions 1558 | ) => Promise 1559 | estimateGas: ( 1560 | subject: string, 1561 | issuer: string, 1562 | id: string, 1563 | key: string, 1564 | data?: string, 1565 | options?: { 1566 | from?: string 1567 | gas?: number 1568 | } 1569 | ) => number 1570 | } 1571 | } 1572 | 1573 | export interface ZincAccessorContract { 1574 | new: () => Promise 1575 | deployed(): Promise 1576 | at(address: string): ZincAccessorInstance 1577 | } 1578 | 1579 | declare type _contractTest = (accounts: string[]) => void 1580 | declare interface TransactionMeta { 1581 | from: string 1582 | } 1583 | 1584 | interface Artifacts { 1585 | require(name: "Encoder"): EncoderContract 1586 | require(name: "ERC20"): ERC20Contract 1587 | require(name: "ERC20Basic"): ERC20BasicContract 1588 | require(name: "ERC725"): ERC725Contract 1589 | require(name: "Identity"): IdentityContract 1590 | require(name: "Migrations"): MigrationsContract 1591 | require(name: "Ownable"): OwnableContract 1592 | require(name: "Registry"): RegistryContract 1593 | require(name: "SafeMath"): SafeMathContract 1594 | require(name: "SignatureValidator"): SignatureValidatorContract 1595 | require(name: "StandardToken"): StandardTokenContract 1596 | require(name: "ZincAccessor"): ZincAccessorContract 1597 | } 1598 | 1599 | declare global { 1600 | var artifacts: Artifacts 1601 | var web3: Web3 1602 | function contract(name: string, test: _contractTest): void 1603 | function it(name: string, test: (accounts: string[]) => void): void 1604 | } 1605 | -------------------------------------------------------------------------------- /truffle.js: -------------------------------------------------------------------------------- 1 | var HDWalletProvider = require("truffle-hdwallet-provider") 2 | var mnemonic = process.env.MNEMONIC 3 | 4 | module.exports = { 5 | // See 6 | // to customize your Truffle configuration! 7 | solc: { 8 | optimizer: { 9 | enabled: true, 10 | runs: 200 11 | } 12 | }, 13 | networks: { 14 | ropsten: { 15 | provider: function() { 16 | return new HDWalletProvider( 17 | mnemonic, 18 | "https://ropsten.infura.io/1bdb589f8c81498db03f2cf872600709" 19 | ) 20 | }, 21 | network_id: 3, 22 | gas: 3000000 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "noEmitOnError": true, 5 | "noImplicitAny": true, 6 | "noImplicitThis": true, 7 | "noUnusedLocals": true, 8 | "removeComments": true, 9 | "target": "es6", 10 | "lib": ["es6", "es2017", "dom"], 11 | "pretty": true, 12 | "skipLibCheck": true 13 | }, 14 | "include": ["./truffle.d.ts", "./web3.d.ts", "./bn.js.d.ts", "test/**/*.ts"] 15 | } 16 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:latest", "tslint-config-prettier"], 3 | "rules": { 4 | "object-literal-sort-keys": false 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /web3.d.ts: -------------------------------------------------------------------------------- 1 | // Taken from https://github.com/hellobloom/core/blob/2bd20a9096c0e3bafa0c5d3fb168a130573402a3/web3.d.ts 2 | // Slightly modified typings from https://github.com/0xProject/web3-typescript-typings 3 | 4 | declare module "web3" { 5 | import * as BigNumber from "bignumber.js" 6 | 7 | type MixedData = string | number | object | any[] | BigNumber.BigNumber 8 | 9 | class Web3 { 10 | public BigNumber: typeof BigNumber 11 | 12 | public static providers: typeof providers 13 | public currentProvider: Web3.Provider 14 | 15 | public eth: Web3.EthApi 16 | public personal: Web3.PersonalApi | undefined 17 | public version: Web3.VersionApi 18 | public net: Web3.NetApi 19 | 20 | public constructor(provider?: Web3.Provider) 21 | 22 | public isConnected(): boolean 23 | public setProvider(provider: Web3.Provider): void 24 | public reset(keepIsSyncing: boolean): void 25 | public toHex(data: MixedData): string 26 | public toAscii(hex: string): string 27 | public fromAscii(ascii: string, padding?: number): string 28 | public toDecimal(hex: string): number 29 | public fromDecimal(value: number | string): string 30 | public fromWei(value: number | string, unit: Web3.Unit): string 31 | public fromWei( 32 | value: BigNumber.BigNumber, 33 | unit: Web3.Unit 34 | ): BigNumber.BigNumber 35 | public toWei(amount: number | string, unit: Web3.Unit): string 36 | public toWei( 37 | amount: BigNumber.BigNumber, 38 | unit: Web3.Unit 39 | ): BigNumber.BigNumber 40 | public toBigNumber(value: number | string): BigNumber.BigNumber 41 | public isAddress(address: string): boolean 42 | public isChecksumAddress(address: string): boolean 43 | public sha3(value: string, options?: Web3.Sha3Options): string 44 | } 45 | 46 | namespace providers { 47 | class HttpProvider implements Web3.Provider { 48 | constructor( 49 | url?: string, 50 | timeout?: number, 51 | username?: string, 52 | password?: string 53 | ) 54 | sendAsync( 55 | payload: Web3.JSONRPCRequestPayload, 56 | callback: (err: Error, result: Web3.JSONRPCResponsePayload) => void 57 | ): void 58 | } 59 | } 60 | 61 | namespace Web3 { 62 | type ContractAbi = AbiDefinition[] 63 | 64 | type AbiDefinition = FunctionAbi | EventAbi 65 | 66 | type FunctionAbi = MethodAbi | ConstructorAbi | FallbackAbi 67 | 68 | interface MethodAbi { 69 | type: "function" 70 | name: string 71 | inputs: FunctionParameter[] 72 | outputs: FunctionParameter[] 73 | constant: boolean 74 | payable: boolean 75 | } 76 | 77 | interface ConstructorAbi { 78 | type: "constructor" 79 | inputs: FunctionParameter[] 80 | payable: boolean 81 | } 82 | 83 | interface FallbackAbi { 84 | type: "fallback" 85 | payable: boolean 86 | } 87 | 88 | interface EventParameter { 89 | name: string 90 | type: string 91 | indexed: boolean 92 | } 93 | 94 | interface EventAbi { 95 | type: "event" 96 | name: string 97 | inputs: EventParameter[] 98 | anonymous: boolean 99 | } 100 | 101 | interface FunctionParameter { 102 | name: string 103 | type: string 104 | } 105 | 106 | interface ContractInstance { 107 | address: string 108 | abi: Web3.ContractAbi 109 | [name: string]: any 110 | } 111 | 112 | interface Contract { 113 | at(address: string): A 114 | } 115 | 116 | interface FilterObject { 117 | fromBlock: number | string 118 | toBlock: number | string 119 | address: string 120 | topics: string[] 121 | } 122 | 123 | interface SolidityEvent { 124 | event: string 125 | address: string 126 | args: A 127 | } 128 | 129 | interface FilterResult { 130 | get(callback: () => void): void 131 | watch(callback: (err: Error, result: SolidityEvent) => void): void 132 | stopWatching(callback: () => void): void 133 | } 134 | 135 | export interface JSONRPCRequestPayload { 136 | params?: any[] 137 | method: string 138 | id: number 139 | jsonrpc: string 140 | } 141 | 142 | export interface JSONRPCResponsePayload { 143 | result: any 144 | id: number 145 | jsonrpc: string 146 | } 147 | 148 | interface Provider { 149 | sendAsync( 150 | payload: JSONRPCRequestPayload, 151 | callback: (err: Error, result: JSONRPCResponsePayload) => void 152 | ): void 153 | } 154 | 155 | interface Sha3Options { 156 | encoding: "hex" 157 | } 158 | 159 | interface EthApi { 160 | coinbase: string 161 | mining: boolean 162 | hashrate: number 163 | gasPrice: BigNumber.BigNumber 164 | accounts: string[] 165 | blockNumber: number 166 | defaultAccount: string 167 | defaultBlock: Web3.BlockParam 168 | syncing: Web3.SyncingResult 169 | compile: { 170 | solidity( 171 | sourceString: string, 172 | cb?: (err: Error, result: any) => void 173 | ): object 174 | } 175 | getMining(cd: (err: Error, mining: boolean) => void): void 176 | getHashrate(cd: (err: Error, hashrate: number) => void): void 177 | getGasPrice(cd: (err: Error, gasPrice: BigNumber.BigNumber) => void): void 178 | getAccounts(cd: (err: Error, accounts: string[]) => void): void 179 | getBlockNumber(callback: (err: Error, blockNumber: number) => void): void 180 | getSyncing(cd: (err: Error, syncing: Web3.SyncingResult) => void): void 181 | isSyncing( 182 | cb: ( 183 | err: Error, 184 | isSyncing: boolean, 185 | syncingState: Web3.SyncingState 186 | ) => void 187 | ): Web3.IsSyncing 188 | 189 | getBlock( 190 | hashStringOrBlockNumber: string | Web3.BlockParam 191 | ): Web3.BlockWithoutTransactionData 192 | getBlock( 193 | hashStringOrBlockNumber: string | Web3.BlockParam, 194 | callback: ( 195 | err: Error, 196 | blockObj: Web3.BlockWithoutTransactionData 197 | ) => void 198 | ): void 199 | getBlock( 200 | hashStringOrBlockNumber: string | Web3.BlockParam, 201 | returnTransactionObjects: true 202 | ): Web3.BlockWithTransactionData 203 | getBlock( 204 | hashStringOrBlockNumber: string | Web3.BlockParam, 205 | returnTransactionObjects: true, 206 | callback: (err: Error, blockObj: Web3.BlockWithTransactionData) => void 207 | ): void 208 | 209 | getBlockTransactionCount( 210 | hashStringOrBlockNumber: string | Web3.BlockParam 211 | ): number 212 | getBlockTransactionCount( 213 | hashStringOrBlockNumber: string | Web3.BlockParam, 214 | callback: (err: Error, blockTransactionCount: number) => void 215 | ): void 216 | 217 | // TODO returnTransactionObjects 218 | getUncle( 219 | hashStringOrBlockNumber: string | Web3.BlockParam, 220 | uncleNumber: number 221 | ): Web3.BlockWithoutTransactionData 222 | getUncle( 223 | hashStringOrBlockNumber: string | Web3.BlockParam, 224 | uncleNumber: number, 225 | callback: (err: Error, uncle: Web3.BlockWithoutTransactionData) => void 226 | ): void 227 | 228 | getTransaction(transactionHash: string): Web3.Transaction 229 | getTransaction( 230 | transactionHash: string, 231 | callback: (err: Error, transaction: Web3.Transaction) => void 232 | ): void 233 | 234 | getTransactionFromBlock( 235 | hashStringOrBlockNumber: string | Web3.BlockParam, 236 | indexNumber: number 237 | ): Web3.Transaction 238 | getTransactionFromBlock( 239 | hashStringOrBlockNumber: string | Web3.BlockParam, 240 | indexNumber: number, 241 | callback: (err: Error, transaction: Web3.Transaction) => void 242 | ): void 243 | 244 | contract(abi: Web3.AbiDefinition[]): Web3.Contract 245 | 246 | // TODO block param 247 | getBalance(addressHexString: string): BigNumber.BigNumber 248 | getBalance( 249 | addressHexString: string, 250 | callback: (err: Error, result: BigNumber.BigNumber) => void 251 | ): void 252 | 253 | // TODO block param 254 | getStorageAt(address: string, position: number): string 255 | getStorageAt( 256 | address: string, 257 | position: number, 258 | callback: (err: Error, storage: string) => void 259 | ): void 260 | 261 | // TODO block param 262 | getCode(addressHexString: string): string 263 | getCode( 264 | addressHexString: string, 265 | callback: (err: Error, code: string) => void 266 | ): void 267 | 268 | filter(value: string | Web3.FilterObject): Web3.FilterResult 269 | 270 | sendTransaction(txData: Web3.TxData): string 271 | sendTransaction( 272 | txData: Web3.TxData, 273 | callback: (err: Error, value: string) => void 274 | ): void 275 | 276 | sendRawTransaction(rawTxData: string): string 277 | sendRawTransaction( 278 | rawTxData: string, 279 | callback: (err: Error, value: string) => void 280 | ): void 281 | 282 | sign(address: string, data: string): string 283 | sign( 284 | address: string, 285 | data: string, 286 | callback: (err: Error, signature: string) => void 287 | ): void 288 | 289 | getTransactionReceipt(txHash: string): Web3.TransactionReceipt 290 | getTransactionReceipt( 291 | txHash: string, 292 | callback: (err: Error, receipt: Web3.TransactionReceipt) => void 293 | ): void 294 | 295 | // TODO block param 296 | call(callData: Web3.CallData): string 297 | call( 298 | callData: Web3.CallData, 299 | callback: (err: Error, result: string) => void 300 | ): void 301 | 302 | estimateGas(callData: Web3.CallData): number 303 | estimateGas( 304 | callData: Web3.CallData, 305 | callback: (err: Error, gas: number) => void 306 | ): void 307 | 308 | // TODO defaultBlock 309 | getTransactionCount(address: string): number 310 | getTransactionCount( 311 | address: string, 312 | callback: (err: Error, count: number) => void 313 | ): void 314 | } 315 | 316 | interface VersionApi { 317 | api: string 318 | network: string 319 | node: string 320 | ethereum: string 321 | whisper: string 322 | getNetwork(cd: (err: Error, networkId: string) => void): void 323 | getNode(cd: (err: Error, nodeVersion: string) => void): void 324 | getEthereum(cd: (err: Error, ethereum: string) => void): void 325 | getWhisper(cd: (err: Error, whisper: string) => void): void 326 | } 327 | 328 | interface PersonalApi { 329 | listAccounts: string[] | undefined 330 | newAccount(password?: string): string 331 | unlockAccount( 332 | address: string, 333 | password?: string, 334 | duration?: number 335 | ): boolean 336 | lockAccount(address: string): boolean 337 | sign(message: string, account: string, password: string): string 338 | } 339 | 340 | interface NetApi { 341 | listening: boolean 342 | peerCount: boolean 343 | getListening(cd: (err: Error, listening: boolean) => void): void 344 | getPeerCount(cd: (err: Error, peerCount: number) => void): void 345 | } 346 | 347 | type BlockParam = number | "earliest" | "latest" | "pending" 348 | 349 | type Unit = 350 | | "kwei" 351 | | "ada" 352 | | "mwei" 353 | | "babbage" 354 | | "gwei" 355 | | "shannon" 356 | | "szabo" 357 | | "finney" 358 | | "ether" 359 | | "kether" 360 | | "grand" 361 | | "einstein" 362 | | "mether" 363 | | "gether" 364 | | "tether" 365 | 366 | interface SyncingState { 367 | startingBlock: number 368 | currentBlock: number 369 | highestBlock: number 370 | } 371 | type SyncingResult = false | SyncingState 372 | 373 | interface IsSyncing { 374 | addCallback( 375 | cb: (err: Error, isSyncing: boolean, syncingState: SyncingState) => void 376 | ): void 377 | stopWatching(): void 378 | } 379 | 380 | interface AbstractBlock { 381 | number: number | null 382 | hash: string | null 383 | parentHash: string 384 | nonce: string | null 385 | sha3Uncles: string 386 | logsBloom: string | null 387 | transactionsRoot: string 388 | stateRoot: string 389 | miner: string 390 | difficulty: BigNumber.BigNumber 391 | totalDifficulty: BigNumber.BigNumber 392 | extraData: string 393 | size: number 394 | gasLimit: number 395 | gasUser: number 396 | timestamp: number 397 | uncles: string[] 398 | } 399 | interface BlockWithoutTransactionData extends AbstractBlock { 400 | transactions: string[] 401 | } 402 | interface BlockWithTransactionData extends AbstractBlock { 403 | transactions: Transaction[] 404 | } 405 | 406 | interface Transaction { 407 | hash: string 408 | nonce: number 409 | blockHash: string | null 410 | blockNumber: number | null 411 | transactionIndex: number | null 412 | from: string 413 | to: string | null 414 | value: BigNumber.BigNumber 415 | gasPrice: BigNumber.BigNumber 416 | gas: number 417 | input: string 418 | } 419 | 420 | interface CallTxDataBase { 421 | to?: string 422 | value?: number | string | BigNumber.BigNumber 423 | gas?: number | string | BigNumber.BigNumber 424 | gasPrice?: number | string | BigNumber.BigNumber 425 | data?: string 426 | nonce?: number 427 | } 428 | 429 | interface TxData extends CallTxDataBase { 430 | from: string 431 | } 432 | 433 | interface CallData extends CallTxDataBase { 434 | from?: string 435 | } 436 | 437 | interface TransactionReceipt< 438 | EventArgs = { [key: string]: string | BigNumber.BigNumber } 439 | > { 440 | blockHash: string 441 | blockNumber: number 442 | transactionHash: string 443 | transactionIndex: number 444 | from: string 445 | to: string 446 | cumulativeGasUsed: number 447 | receipt: { 448 | gasUsed: number 449 | } 450 | contractAddress: string | null 451 | logs: LogEntry[] 452 | toNumber: () => number 453 | } 454 | 455 | interface LogEntry extends SolidityEvent { 456 | logIndex: number | null 457 | transactionIndex: number 458 | transactionHash: string 459 | blockHash: string | null 460 | blockNumber: number | null 461 | address: string 462 | data: string 463 | topics: string[] 464 | } 465 | } 466 | /* tslint:disable */ 467 | export = Web3 468 | /* tslint:enable */ 469 | } 470 | --------------------------------------------------------------------------------