├── .babelrc ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── jest-setup.js ├── jest.config.js ├── package.json ├── src ├── __tests__ │ ├── address.fixtures.ts │ ├── checksum.fixtures.ts │ ├── keypairs.fixtures.ts │ ├── node.spec.ts │ ├── schnorr.fixtures.ts │ └── util.spec.ts ├── config.json ├── index.ts ├── node.ts ├── schnorr.ts ├── types.ts ├── util.ts └── zilliqa.ts ├── tsconfig.json ├── tslint.json ├── typings ├── bn.d.ts ├── elliptic.d.ts ├── json.d.ts ├── signature.d.ts └── window.d.ts ├── webpack.config.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/env", 5 | { 6 | "modules": false, 7 | "targets": { 8 | "browsers": [ 9 | ">0.25%" 10 | ] 11 | }, 12 | "useBuiltIns": "usage" 13 | } 14 | ], 15 | "@babel/typescript" 16 | ], 17 | "env": { 18 | "development": { 19 | "plugins": [ 20 | "@babel/transform-runtime" 21 | ] 22 | }, 23 | "production": { 24 | "plugins": [ 25 | "@babel/transform-runtime", 26 | "transform-remove-console" 27 | ] 28 | }, 29 | "test": { 30 | "presets": [ 31 | [ 32 | "@babel/env", 33 | { 34 | "modules": "commonjs", 35 | "targets": { 36 | "node": "current" 37 | } 38 | } 39 | ], 40 | "@babel/typescript" 41 | ] 42 | } 43 | }, 44 | "plugins": [ 45 | "@babel/plugin-syntax-dynamic-import", 46 | "@babel/plugin-syntax-import-meta", 47 | "@babel/plugin-proposal-class-properties", 48 | "@babel/plugin-proposal-json-strings", 49 | [ 50 | "@babel/plugin-proposal-decorators", 51 | { 52 | "legacy": true 53 | } 54 | ], 55 | "@babel/plugin-proposal-function-sent", 56 | "@babel/plugin-proposal-export-namespace-from", 57 | "@babel/plugin-proposal-numeric-separator", 58 | "@babel/plugin-proposal-throw-expressions", 59 | "@babel/plugin-proposal-export-default-from", 60 | "@babel/plugin-proposal-logical-assignment-operators", 61 | "@babel/plugin-proposal-optional-chaining", 62 | [ 63 | "@babel/plugin-proposal-pipeline-operator", 64 | { 65 | "proposal": "minimal" 66 | } 67 | ], 68 | "@babel/plugin-proposal-nullish-coalescing-operator", 69 | "@babel/plugin-proposal-do-expressions" 70 | ] 71 | } 72 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Describe the bug** 8 | A clear and concise description of what the bug is. 9 | 10 | **To Reproduce** 11 | Steps to reproduce the behavior: 12 | 1. Go to '...' 13 | 2. Click on '....' 14 | 3. Scroll down to '....' 15 | 4. See error 16 | 17 | **Expected behavior** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **Screenshots** 21 | If applicable, add screenshots to help explain your problem. 22 | 23 | **Desktop (please complete the following information):** 24 | - OS: [e.g. iOS] 25 | - Browser [e.g. chrome, safari] 26 | - Version [e.g. 22] 27 | 28 | **Smartphone (please complete the following information):** 29 | - Device: [e.g. iPhone6] 30 | - OS: [e.g. iOS8.1] 31 | - Browser [e.g. stock browser, safari] 32 | - Version [e.g. 22] 33 | 34 | **Additional context** 35 | Add any other context about the problem here. 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. 12 | 13 | **Describe alternatives you've considered** 14 | A clear and concise description of any alternative solutions or features you've considered. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | 4 | 5 | 6 | ## Review Suggestion 7 | 8 | 9 | 10 | ## Status 11 | 12 | ### Implementation 13 | 14 | - [ ] **ready for review** 15 | 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | \.DS_STORE 3 | \.rpt2_cache 4 | yarn-error\.log 5 | dist -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | sudo: true 3 | dist: trusty 4 | node_js: 5 | - 10 6 | branches: 7 | except: 8 | - /^v[0-9]/ 9 | install: 10 | - yarn install --pure-lockfile 11 | script: 12 | - yarn run test 13 | cache: 14 | directories: 15 | - "$HOME/.yarn-cache" 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This source code is being disclosed to you solely for the purpose of your participation in 2 | testing Zilliqa. You may view, compile and run the code for that purpose and pursuant to 3 | the protocols and algorithms that are programmed into, and intended by, the code. You may 4 | not do anything else with the code without express permission from Zilliqa Research Pte. Ltd., 5 | including modifying or publishing the code (or any part of it), and developing or forming 6 | another public or private blockchain network. This source code is provided ‘as is’ and no 7 | warranties are given as to title or non-infringement, merchantability or fitness for purpose 8 | and, to the extent permitted by law, all liability for your use of the code is disclaimed. 9 | Some programs in this code are governed by the GNU General Public License v3.0 (available at 10 | https://www.gnu.org/licenses/gpl-3.0.en.html) (‘GPLv3’). The programs that are governed by 11 | GPLv3.0 are those programs that are located in the folders src/depends and tests/depends 12 | and which include a reference to GPLv3 in their program files. 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Zilliqa-JavaScript-Library API 2 | [![npm version](https://badge.fury.io/js/zilliqa-js.svg)](https://badge.fury.io/js/zilliqa-js) 3 | [![Build Status](https://travis-ci.com/Zilliqa/Zilliqa-JavaScript-Library.svg?branch=master)](https://travis-ci.com/Zilliqa/Zilliqa-JavaScript-Library) 4 | [![Gitter chat](http://img.shields.io/badge/chat-on%20gitter-077a8f.svg)](https://gitter.im/Zilliqa/) 5 | 6 | ## Installation 7 | 8 | To use Zilliqa's Javascript API library, run ONE of the following commands from the root of your project directory. 9 | ### Yarn 10 | `yarn add zilliqa-js` 11 | 12 | ### NPM 13 | `npm install zilliqa-js` 14 | 15 | ### Build Project 16 | 17 | To build the project, run the following commands: 18 | 19 | ``` 20 | yarn install 21 | yarn build 22 | ``` 23 | 24 | This runs the TypeScript source files through Webpack, that in turn relies on 25 | Babel to transpile them to a browser-friendly bundle. Type definitions are 26 | also automatically generated. 27 | 28 | ### Run Tests 29 | 30 | ``` 31 | yarn test 32 | ``` 33 | 34 | Will run all test suites in any folder `__tests__` within the `src` directory. 35 | 36 | ## Usage 37 | 38 | ### Getting Started 39 | 40 | To get started, you have to specify the network and set some function definitions. Once that is done, you can start to call the APIs. Here are some examples to get you started: 41 | 42 | ```js 43 | 44 | /* 45 | Setting Up 46 | */ 47 | 48 | let { Zilliqa } = require('zilliqa-js'); 49 | 50 | //For local testing, use URL = 'http://localhost:4201' 51 | //To connect to the external network, use URL = 'https://api-scilla.zilliqa.com' 52 | let URL = 'https://api-scilla.zilliqa.com' 53 | let zilliqa = new Zilliqa({ 54 | nodeUrl: URL 55 | }); 56 | 57 | let node = zilliqa.getNode(); 58 | 59 | 60 | // callback receives 2 parameters, error and result 61 | function callback (err, data) { 62 | if (err || data.error) { 63 | console.log('Error') 64 | } else { 65 | console.log(data.result) 66 | } 67 | } 68 | 69 | // generate a private key and its public address. You can change these to point to your own wallet if you have. 70 | let privateKey = zilliqa.util.generatePrivateKey(); 71 | let address = zilliqa.util.getAddressFromPrivateKey(privateKey); 72 | 73 | /* 74 | APIs 75 | */ 76 | 77 | node.getBalance({ address: 'E8A67C0B1F19DF61A28E8E8FB5D830377045BCC7' }, callback); 78 | 79 | ``` 80 | Other than `getBalance(address)`, you can also try to create a transaction or deploy a contract. 81 | 82 | ### Example: Create a Transaction 83 | 84 | ```js 85 | // always use BN for `amount` to prevent overflows. 86 | import BN from 'bn.js' 87 | 88 | // transaction details 89 | const txnDetails = { 90 | version: 0, 91 | nonce: 1, 92 | to: 'E8A67C0B1F19DF61A28E8E8FB5D830377045BCC7', 93 | amount: new BN(0), 94 | gasPrice: 1, 95 | gasLimit: 1 96 | }; 97 | 98 | // sign the transaction using util methods 99 | let txn = zilliqa.util.createTransactionJson(privateKey, txnDetails); 100 | 101 | // send the transaction to the node 102 | node.createTransaction(txn, callback); 103 | ``` 104 | 105 | ### Example: Deploy a Contract 106 | 107 | ```js 108 | // contains the scilla code as a string 109 | let code = "Scilla Code"; 110 | 111 | // the immutable initialisation variables 112 | let initParams = [ 113 | { 114 | "vname" : "owner", 115 | "type" : "Address", 116 | "value" : "0x1234567890123456789012345678901234567890" 117 | }, 118 | { 119 | "vname" : "total_tokens", 120 | "type" : "Uint128", 121 | "value" : "10000" 122 | }]; 123 | 124 | // transaction details 125 | let txnDetails = { 126 | version: 0, 127 | nonce: 1, 128 | to: '0000000000000000000000000000000000000000', 129 | amount: 0, 130 | gasPrice: 1, 131 | gasLimit: 50, 132 | code: code, 133 | data: JSON.stringify(initParams).replace(/\\"/g, '"') 134 | }; 135 | 136 | // sign the transaction using util methods 137 | let txn = zilliqa.util.createTransactionJson(privateKey, txnDetails); 138 | 139 | // send the transaction to the node 140 | node.createTransaction(txn, callback); 141 | ``` 142 | 143 | 144 | ## API Methods 145 | 146 | - **[getNetworkId](#getnetworkid)** 147 | - **[createTransaction](#createtransaction)** 148 | - **[getTransaction](#gettransaction)** 149 | - **[getDsBlock](#getdsblock)** 150 | - **[getTxBlock](#gettxblock)** 151 | - **[getLatestDsBlock](#getlatestdsblock)** 152 | - **[getLatestTxBlock](#getlatesttxblock)** 153 | - **[getBalance](#getbalance)** 154 | - **[getSmartContractState](#getsmartcontractstate)** 155 | - **[getSmartContractCode](#getsmartcontractcode)** 156 | - **[getSmartContractInit](#getsmartcontractinit)** 157 | - **[getSmartContracts](#getsmartcontracts)** 158 | - **[getBlockchainInfo](#getblockchaininfo)** 159 | - **[isConnected](#isconnected)** 160 | 161 | ## Util Methods 162 | - **[generatePrivateKey](#generateprivatekey)** 163 | - **[verifyPrivateKey](#verifyprivatekey)** 164 | - **[getAddressFromPrivateKey](#getaddressfromprivatekey)** 165 | - **[getPubKeyFromPrivateKey](#getpubkeyfromprivatekey)** 166 | - **[createTransactionJson](#createtransactionjson)** 167 | - **[getAddressFromPublicKey](#getaddressfrompublickey)** 168 | - **[isPubKey](#isPubKey)** 169 | - **[isAddress](#isAddress)** 170 | - **[intToByteArray](#intToByteArray)** 171 | - **[compressPublicKey](#compressPublicKey)** 172 | 173 | ## Library Methods 174 | - **[getLibraryVersion](#getlibraryversion)** 175 | - **[setNode](#setnode)** 176 | - **[currentNode](#currentnode)** 177 | 178 | 179 | 180 | ## API Reference 181 | 182 | ### `getNetworkId` 183 | 184 | Returns the current network id 185 | 186 | **Parameters** 187 | 188 | none 189 | 190 | **Returns** 191 | 192 | `result`: `String` - The current network id name 193 | 194 | **Usage** 195 | 196 | ```js 197 | zilliqa.node.getNetworkId(function(err, data) { 198 | if (err || !data.result) { 199 | console.log(err) 200 | } else { 201 | console.log(data.result) 202 | } 203 | }) 204 | ``` 205 | 206 | 207 | ### `createTransaction` 208 | 209 | Creates a new transaction or a contract creation, if the data field contains code 210 | 211 | **Parameters** 212 | 213 | - `version` (32 bits): the current version 214 | - `nonce` (64 bits): Counter equal to the number of transactions sent by the sender of this transaction. It's value is always (current account nonce + 1). 215 | - `to` (160 bits): Destination account address. Incase of new contract account, set as `0000000000000000000000000000000000000000` 216 | - `pubkey` (264 bits): An EC-Schnorr public key that should be used to verify the signature. Determines the sending address of the transaction 217 | - `amount` (128 bits): Transaction amount to be transferred to the destination address. 218 | - `gasPrice` (128 bits): amount that the sender is willing to pay per unit of gas for computations incurred in transaction processing 219 | - `gasLimit` (128 bits): the maximum amount of gas that should be used while processing this transaction 220 | - `code` (unlimited): expandable byte array that specifies the contract code. It is present only when the transaction creates a new contract account 221 | - `data` (unlimited): expandable byte array that specifies the data that should be used to process the transaction, present only when the transaction invokes a call to a contract at the destination address. 222 | - `signature` (512 bits): An EC-Schnorr signature of the entire object 223 | 224 | Each transaction is uniquely identified by a 225 | `transaction ID` — a SHA3-256 digest of the transaction data that excludes the `signature`field. 226 | 227 | **Returns** 228 | 229 | `result`: `String` - transaction id of the newly created transaction 230 | 231 | **Usage** 232 | 233 | ```js 234 | let txn = zilliqa.util.createTransactionJson(privateKey, { 235 | version: 0, 236 | nonce: 1, 237 | to: address, 238 | amount: 0, 239 | gasPrice: 1, // default 240 | gasLimit: 1 // 1 - send tokens, 10 - contract invocation, 50 - contract creation 241 | }) 242 | 243 | zilliqa.node.createTransaction(txn, function(err, data) { 244 | if (err || data.error) { 245 | console.log(err) 246 | } else { 247 | console.log(data.result) 248 | } 249 | }) 250 | ``` 251 | 252 | 253 | ### `getTransaction` 254 | 255 | Returns the information about a transaction requested by transaction hash 256 | 257 | **Parameters** 258 | 259 | `txHash`: `String` - the transaction ID to retrieve details of 260 | 261 | **Returns** 262 | 263 | `result`: `Object` - A transaction object 264 | - `version` (32 bits): the current version 265 | - `nonce` (64 bits): Counter equal to the number of transactions sent by the sender of this transaction 266 | - `to` (160 bits): Destination account address 267 | - `from` (160 bits): Sender account address 268 | - `amount` (128 bits): Transaction amount transferred from sender to destination 269 | - `pubKey` (264 bits): An EC-Schnorr public key that should be used to verify the signature. The pubkey field also determines the sending address of the transaction 270 | - `signature` (512 bits): An EC-Schnorr signature of the entire object 271 | 272 | **Usage** 273 | 274 | ```js 275 | let txnId = 'c699d0ea1d4a447762bb0617f742a43b8de6792d06c56f9a2a109f0e06532f1c' // sample 64-char hex id 276 | zilliqa.node.getTransaction({ txHash: txnId }, function(err, data) { 277 | if (err || data.result.error || !data.result['ID']) { 278 | console.log(err) 279 | } else { 280 | console.log(data.result) 281 | } 282 | }) 283 | ``` 284 | 285 | 286 | ### `getDsBlock` 287 | 288 | Returns information about a Directory Service block by block number. 289 | 290 | **Parameters** 291 | 292 | `blockNumber`: `String` - Block number to fetch details of 293 | 294 | **Returns** 295 | 296 | `result`: `Object` - A block object with header and signature fields 297 | 298 | header: 299 | - `version` (32 bits): Current version. 300 | - `previous hash` (256 bits): The SHA3-256 digest of its parent's block header 301 | - `pubkey` (264 bits): The public key of the miner who did PoW on this block header 302 | - `difficulty` (64 bits): This can be calculated from the 303 | previous block’s difficulty and the block number. It stores 304 | the difficulty of the PoW puzzle. 305 | - `number` (256 bits): The number of ancestor blocks. The genesis block has a block number of 0 306 | - `timestamp` (64 bits): Unix’s time() at the time of creation of this block 307 | - `mixHash` (256 bits): A digest calculated from nonce which allows detecting DoS attacks 308 | - `nonce` (64 bits): A solution to the PoW 309 | 310 | signature: 311 | - `signature` (512 bits): The signature is an EC-Schnorr based multisignature on the DS-Block header signed by DS nodes 312 | - `bitmap` (1024 bits): It records which DS nodes participated in the multisignature. We denote the bitmap by a bit vector B, where, B[i] = 1 if the i-th node signed the header else B[i] = 0. 313 | 314 | **Usage** 315 | 316 | ```js 317 | zilliqa.node.getDsBlock({ blockNumber: 5 }, function(err, data) { 318 | if (err || !data.result) { 319 | console.log(err) 320 | } else { 321 | console.log(data.result) 322 | } 323 | }) 324 | ``` 325 | 326 | 327 | ### `getTxBlock` 328 | 329 | Returns information about a Transaction block by block number. 330 | 331 | **Parameters** 332 | 333 | `blockNumber`: `String` - Block number to fetch details of 334 | 335 | **Returns** 336 | 337 | `result`: `Object` - A block object with header and signature fields 338 | 339 | header: 340 | - `type` (8 bits): A TX-Block is of two types, micro block (0x00) and final block (0x01) 341 | - `version` (32 bits): Current version 342 | - `previous hash` (256 bits): The SHA3-256 digest of its parent block header 343 | - `gas limit` (128 bits): Current limit for gas expenditure per block 344 | - `gas used` (128 bits): Total gas used by transactions in this block 345 | - `number` (256 bits): The number of ancestor blocks. The genesis block has a block number of 0 346 | - `timestamp` (64 bits): Unix’s time() at the time of creation of this block 347 | - `state root` (256 bits): It is a SHA3-256 digest that represents the global state after all transactions are executed and finalized. If the global state is stored as a trie, then state root is the digest of the root of the trie 348 | - `transaction root` (256 bits): It is a SHA3-256 digest that represents the root of the Merkle tree that stores all transactions that are present in this block 349 | - `tx hashes` (each 256 bits): A list of SHA3-256 digests of the transactions. The signature part of the transaction is also hashed 350 | - `pubkey` (264 bits): It is the EC-Schnorr public key of the leader who proposed the block 351 | - `pubkey micro blocks` (unlimited): It is a list of EC-Schnorr public keys (each 264 bits in length). The list contains the public keys of the leaders who proposed transactions. The field is present only if it is a final block 352 | - `parent block hash` (256 bits): It is the SHA3-256 digest of the previous final block header 353 | - `parent ds hash` (256 bits): It is the SHA3-256 digest of its parent DS-Block header 354 | - `parent ds block number` (256 bits): It is the parent DS-Block number 355 | 356 | data: 357 | - `tx count` (32 bits): The number of transactions in this block 358 | - `tx list` (unlimited): A list of transactions 359 | 360 | signature: 361 | - `signature` (512 bits): The signature is an EC-Schnorr based multisignature on the TX-Block header signed by a set of nodes. The signature is produced by a different set of nodes depending on whether it is a micro block or a final block 362 | - `bitmap` (1024 bits): It records which nodes participated in the multisignature. We denote the bitmap by a bit vector B, where, B[i] = 1 if the i-th node signed the header else B[i] = 0 363 | 364 | **Usage** 365 | 366 | ```js 367 | zilliqa.node.getTxBlock({ blockNumber: 5 }, function(err, data) { 368 | if (err || !data.result) { 369 | console.log(err) 370 | } else { 371 | console.log(data.result) 372 | } 373 | }) 374 | ``` 375 | 376 | 377 | ### `getLatestDsBlock` 378 | 379 | Returns the most recent DS block 380 | 381 | **Parameters** 382 | 383 | none 384 | 385 | **Returns** 386 | 387 | `result`: `Object` - DS Block object 388 | 389 | **Usage** 390 | 391 | ```js 392 | zilliqa.node.getLatestDsBlock(function(err, data) { 393 | if (err || !data.result) { 394 | console.log(err) 395 | } else { 396 | console.log(data.result) 397 | } 398 | }) 399 | ``` 400 | 401 | 402 | ### `getLatestTxBlock` 403 | 404 | Returns the most recent TX block 405 | 406 | **Parameters** 407 | 408 | none 409 | 410 | **Returns** 411 | 412 | `result`: `Object` - TX Block object 413 | 414 | **Usage** 415 | 416 | ```js 417 | zilliqa.node.getLatestTxBlock(function(err, data) { 418 | if (err || !data.result) { 419 | console.log(err) 420 | } else { 421 | console.log(data.result) 422 | } 423 | }) 424 | ``` 425 | 426 | 427 | ### `getBalance` 428 | 429 | Returns the balance of a given address 430 | 431 | **Parameters** 432 | 433 | `address`: `String` (40 chars) - address to fetch balance and nonce of 434 | 435 | **Returns** 436 | 437 | `result.balance` - the current balance in ZIL 438 | `result.nonce` - the current nonce of the account 439 | 440 | **Usage** 441 | 442 | ```js 443 | zilliqa.node.getBalance({ address: 'E8A67C0B1F19DF61A28E8E8FB5D830377045BCC7' }, function(err, data) { 444 | if (err || data.error) { 445 | console.log(err) 446 | } else { 447 | console.log(data.result) 448 | } 449 | }) 450 | ``` 451 | 452 | 453 | ### `getSmartContractState` 454 | 455 | Returns the state variables (mutable) of a given smart contract address 456 | 457 | **Parameters** 458 | 459 | `address`: `String` (40 chars) - smart contract address 460 | 461 | **Returns** 462 | 463 | `result` - json object of all the state variables 464 | 465 | **Usage** 466 | 467 | ```js 468 | zilliqa.node.getSmartContractState({ address: 'E8A67C0B1F19DF61A28E8E8FB5D830377045BCC7' }, function(err, data) { 469 | if (err || (data.result && data.result.Error)) { 470 | console.log(err) 471 | } else { 472 | console.log(data.result) 473 | } 474 | }) 475 | ``` 476 | 477 | 478 | ### `getSmartContractCode` 479 | 480 | Returns the smart contract code of a given address smart contract address 481 | 482 | **Parameters** 483 | 484 | `address`: `String` (40 chars) - smart contract address 485 | 486 | **Returns** 487 | 488 | `result.code` - string containing the code of the smart contract 489 | 490 | **Usage** 491 | 492 | ```js 493 | zilliqa.node.getSmartContractCode({ address: 'E8A67C0B1F19DF61A28E8E8FB5D830377045BCC7' }, function(err, data) { 494 | if (err || (data.result && data.result.Error)) { 495 | console.log(err) 496 | } else { 497 | console.log(data.result) 498 | } 499 | }) 500 | ``` 501 | 502 | 503 | ### `getSmartContractInit` 504 | 505 | Returns the initialization parameters (immutable) of a given smart contract address 506 | 507 | **Parameters** 508 | 509 | `address`: `String` (40 chars) - smart contract address 510 | 511 | **Returns** 512 | 513 | `result` - json object containing the initialization parameters of the smart contract 514 | 515 | **Usage** 516 | 517 | ```js 518 | zilliqa.node.getSmartContractInit({ address: 'E8A67C0B1F19DF61A28E8E8FB5D830377045BCC7' }, function(err, data) { 519 | if (err || (data.result && data.result.Error)) { 520 | console.log(err) 521 | } else { 522 | console.log(data.result) 523 | } 524 | }) 525 | ``` 526 | 527 | 528 | ### `getSmartContracts` 529 | Returns the list of smart contracts created by an account 530 | 531 | **Parameters** 532 | 533 | `address`: `String` (40 chars) - address that deployed the smart contracts 534 | 535 | **Returns** 536 | 537 | `result`: `Array` - list of smart contract addresses created by the given address 538 | 539 | **Usage** 540 | 541 | ```js 542 | zilliqa.node.getSmartContracts({ address: 'E8A67C0B1F19DF61A28E8E8FB5D830377045BCC7' }, function(err, data) { 543 | if (err || data.error) { 544 | console.log(err) 545 | } else { 546 | console.log(data.result) 547 | } 548 | }) 549 | ``` 550 | 551 | 552 | ### `getBlockchainInfo` 553 | 554 | Returns statistics about the zilliqa node currently connected to 555 | 556 | **Parameters** 557 | 558 | empty object 559 | 560 | **Returns** 561 | 562 | `Object` - json object containing various properties 563 | - `NumPeers` : 564 | - `NumTxBlocks` : 565 | - `NumDSBlocks` : 566 | - `NumTransactions` : 567 | - `TransactionRate` : 568 | - `TxBlockRate` : 569 | - `DSBlockRate` : 570 | - `CurrentMiniEpoch` : 571 | - `CurrentDSEpoch` : 572 | - `NumTxnsDSEpoch` : 573 | - `NumTxnsTxEpoch` : 574 | 575 | **Usage** 576 | 577 | ```js 578 | zilliqa.node.getBlockchainInfo({}, function(err, data) { 579 | if (err) { 580 | console.log(err) 581 | } else { 582 | console.log(data.result) 583 | } 584 | }) 585 | ``` 586 | 587 | 588 | ### `isConnected` 589 | 590 | Checks whether a node is connected or not 591 | 592 | **Parameters** 593 | 594 | none 595 | 596 | **Returns** 597 | 598 | `Bool` 599 | 600 | **Usage** 601 | 602 | ```js 603 | zilliqa.node.isConnected(function(err, data) { 604 | if (err) { 605 | console.log(err) 606 | } else { 607 | // connected 608 | } 609 | }) 610 | ``` 611 | 612 | 613 | ## Util Methods 614 | 615 | ### `generatePrivateKey` 616 | 617 | Generate a new private key using the secp256k1 curve 618 | 619 | **Parameters** 620 | 621 | none 622 | 623 | **Returns** 624 | 625 | `Buffer` - private key object 626 | 627 | **Usage** 628 | 629 | ```js 630 | let pk = zilliqa.util.generatePrivateKey(); 631 | console.log(pk.toString('hex')); 632 | ``` 633 | 634 | 635 | ### `verifyPrivateKey` 636 | Verify if a private key is valid for the secp256k1 curve 637 | 638 | **Parameters** 639 | 640 | `String`/`Buffer` - the private key to verify 641 | 642 | **Returns** 643 | 644 | `Bool` - true if input string/Buffer is a valid private key else false 645 | 646 | **Usage** 647 | 648 | ```js 649 | let pk = zilliqa.util.generatePrivateKey(); 650 | console.log(zilliqa.util.verifyPrivateKey(pk)); // true 651 | console.log(zilliqa.util.verifyPrivateKey("abcxyz")); // false 652 | ``` 653 | 654 | 655 | ### `getAddressFromPrivateKey` 656 | 657 | Get the public address of an account using its private key 658 | 659 | **Parameters** 660 | 661 | `String`/`Buffer` - the private key to get the public address of 662 | 663 | **Returns** 664 | 665 | `Buffer` - the public address of the input private key 666 | 667 | **Usage** 668 | 669 | ```js 670 | let address = zilliqa.util.getAddressFromPrivateKey(privateKey); 671 | console.log(address.toString('hex')); 672 | ``` 673 | 674 | 675 | ### `getPubKeyFromPrivateKey` 676 | 677 | Get the public key of an account using its private key 678 | 679 | **Parameters** 680 | 681 | `String`/`Buffer` - the private key to get the public key of 682 | 683 | **Returns** 684 | 685 | `Buffer` - the public key of the input private key 686 | 687 | **Usage** 688 | 689 | ```js 690 | let pubkey = zilliqa.util.getPubKeyFromPrivateKey(privateKey); 691 | console.log(pubkey.toString('hex')); 692 | ``` 693 | 694 | 695 | ### `createTransactionJson` 696 | 697 | Construct the transaction object for use in `createTransaction` API 698 | 699 | **Parameters** 700 | 701 | `String`/`Buffer` - the private key of the account creating the transaction, used to sign the transaction 702 | `Object` - object containing the following transaction details: 703 | - `version` - current version (set as 0) 704 | - `nonce` - counter equal to the number of transactions created by the transaction sender 705 | - `to` - destination account address. Incase of new contract account, set as `0000000000000000000000000000000000000000` 706 | - `amount` - transaction amount to be transferred to the destination address. 707 | - `gasPrice` - amount that the sender is willing to pay per unit of gas for computations incurred in transaction processing (default 1) 708 | - `gasLimit` - the amount of gas that should be used while processing this transaction (1 for regular transaction, 10 for contract invocation, 50 for contract creation) 709 | - `code` (optional) - string specifying the contract code. Present only when creating a new contract account 710 | - `data` (optional) - stringified JSON object specifying initialization parameters 711 | 712 | **Returns** 713 | 714 | `result`: `String` - number of transactions in the latest DS block 715 | 716 | **Usage** 717 | 718 | ```js 719 | let privateKey = zilliqa.util.generatePrivateKey(); 720 | 721 | // transaction details 722 | let txnDetails = { 723 | version: 0, 724 | nonce: 1, 725 | to: 'E8A67C0B1F19DF61A28E8E8FB5D830377045BCC7', 726 | amount: 0, 727 | gasPrice: 1, 728 | gasLimit: 1 729 | }; 730 | 731 | // sign the transaction using util methods 732 | let txn = zilliqa.util.createTransactionJson(privateKey, txnDetails); 733 | ``` 734 | 735 | ### `getAddressFromPubKey` 736 | 737 | Get the public address of an account using its public key 738 | 739 | **Parameters** 740 | 741 | `String`/`Buffer` - the public key to get the public address of 742 | 743 | **Returns** 744 | 745 | `Buffer` - the public address of the input private key 746 | 747 | **Usage** 748 | 749 | ```js 750 | let address = zilliqa.util.getAddressFromPubKey(pubKey); 751 | console.log(address.toString('hex')); 752 | ``` 753 | 754 | ### `isAddress` 755 | 756 | Verify if an address syntax is valid 757 | 758 | **Parameters** 759 | 760 | `String`/`Buffer` - the address to verify 761 | 762 | **Returns** 763 | 764 | `Bool` - true if input string/buffer is a valid address syntax 765 | 766 | **Usage** 767 | 768 | ```js 769 | let pk = zilliqa.util.generatePrivateKey(); 770 | let address = zilliqa.util.getAddressFromPrivateKey(pk); 771 | console.log(zilliqa.util.isAddress(address)); // true 772 | console.log(zilliqa.util.isAddress('0'.repeat(30))); // false 773 | ``` 774 | 775 | ### `isPubKey` 776 | 777 | Verify if an public key syntax is valid 778 | 779 | **Parameters** 780 | 781 | `String`/`Buffer` - the public key to verify 782 | 783 | **Returns** 784 | 785 | `Bool` - true if input string/buffer is a valid public key syntax 786 | 787 | **Usage** 788 | 789 | ```js 790 | let pk = zilliqa.util.generatePrivateKey(); 791 | let pubKey = zilliqa.util.getPubKeyFromPrivateKey(pk); 792 | console.log(zilliqa.util.isPubKey(pubKey)); // true 793 | console.log(zilliqa.util.isPubKey('0'.repeat(30))); // false 794 | ``` 795 | 796 | ### `intToByteArray` 797 | Converts number to array representing the padded hex form 798 | 799 | **Parameters** 800 | * `number`: Integer to be converted into bytes 801 | * `paddedSize`: Integer specifying the padded size 802 | 803 | **Returns** 804 | * `byteArray`: Byte array of integer 805 | 806 | **Usage** 807 | ``` 808 | let nonceStr = zilliqa.util.intToByteArray(nonce, 64).join(""); 809 | ``` 810 | 811 | ### `compressPublicKey` 812 | Compresses a public key into fewer bytes 813 | 814 | **Parameters** 815 | `String` - the public key to be compressed 816 | 817 | **Returns** 818 | `String` - Compressed version of the public key 819 | ## Library Methods 820 | 821 | ### `getLibraryVersion` 822 | 823 | Returns the library version number 824 | 825 | **Parameters** 826 | 827 | none 828 | 829 | **Returns** 830 | 831 | `String` - the library version 832 | 833 | 834 | ### `setNode` 835 | 836 | Sets the node to connect to 837 | 838 | **Parameters** 839 | 840 | `String` - http url of the node 841 | 842 | **Returns** 843 | 844 | null 845 | 846 | 847 | ### `getNode` 848 | 849 | Returns the node currently connected to 850 | 851 | **Parameters** 852 | 853 | none 854 | 855 | **Returns** 856 | 857 | `Object` - the currently connected node object 858 | 859 | ## Licence 860 | You can view our [licence here](https://github.com/Zilliqa/zilliqa/blob/master/LICENSE). 861 | -------------------------------------------------------------------------------- /jest-setup.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Zilliqa 2 | // This source code is being disclosed to you solely for the purpose of your participation in 3 | // testing Zilliqa. You may view, compile and run the code for that purpose and pursuant to 4 | // the protocols and algorithms that are programmed into, and intended by, the code. You may 5 | // not do anything else with the code without express permission from Zilliqa Research Pte. Ltd., 6 | // including modifying or publishing the code (or any part of it), and developing or forming 7 | // another public or private blockchain network. This source code is provided ‘as is’ and no 8 | // warranties are given as to title or non-infringement, merchantability or fitness for purpose 9 | // and, to the extent permitted by law, all liability for your use of the code is disclaimed. 10 | window.crypto = require('@trust/webcrypto'); 11 | window.fetch = require('jest-fetch-mock'); 12 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Zilliqa 2 | // This source code is being disclosed to you solely for the purpose of your participation in 3 | // testing Zilliqa. You may view, compile and run the code for that purpose and pursuant to 4 | // the protocols and algorithms that are programmed into, and intended by, the code. You may 5 | // not do anything else with the code without express permission from Zilliqa Research Pte. Ltd., 6 | // including modifying or publishing the code (or any part of it), and developing or forming 7 | // another public or private blockchain network. This source code is provided ‘as is’ and no 8 | // warranties are given as to title or non-infringement, merchantability or fitness for purpose 9 | // and, to the extent permitted by law, all liability for your use of the code is disclaimed. 10 | const config = { 11 | transform: { 12 | '^.+\\.(t|j)s$': 'ts-jest', 13 | }, 14 | testMatch: [ 15 | // '/src/**/__tests__/**/*.ts', 16 | '/src/**/?(*.)+(spec|test).ts', 17 | ], 18 | moduleDirectories: ['src', 'node_modules'], 19 | moduleFileExtensions: ['js', 'ts'], 20 | globals: { 21 | 'ts-jest': { useBabelrc: true }, 22 | }, 23 | testURL: 'http://localhost', 24 | coverageThreshold: { 25 | global: { 26 | branches: 80, 27 | functions: 80, 28 | lines: 80, 29 | statements: 80, 30 | }, 31 | }, 32 | setupFiles: ['/jest-setup.js'], 33 | watchPlugins: [ 34 | 'jest-watch-typeahead/filename', 35 | 'jest-watch-typeahead/testname', 36 | ], 37 | } 38 | 39 | module.exports = config; 40 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zilliqa-js", 3 | "version": "0.1.19", 4 | "license": "SEE LICENSE in LICENSE", 5 | "description": "zilliqa js library", 6 | "repository": "https://github.com/Zilliqa/Zilliqa-Javascript-Library", 7 | "main": "dist/zilliqa.server.js", 8 | "browser": "dist/zilliqa.client.js", 9 | "typings": "dist/index.d.ts", 10 | "sideEffects": [ 11 | "./src/index.ts" 12 | ], 13 | "scripts": { 14 | "build": "rimraf dist/* && tsc --emitDeclarationOnly && cross-env NODE_ENV=production webpack --config webpack.config.js", 15 | "test": "jest -c jest.config.js" 16 | }, 17 | "dependencies": { 18 | "bn.js": "^4.11.8", 19 | "bsert": "^0.0.3", 20 | "cross-fetch": "^2.2.2", 21 | "elliptic": "^6.4.0", 22 | "encoding": "^0.1.12", 23 | "hash.js": "^1.1.5", 24 | "hmac-drbg": "^1.0.1", 25 | "node-fetch-polyfill": "^2.0.6", 26 | "randombytes": "^2.0.6", 27 | "valid-url": "^1.0.9", 28 | "whatwg-fetch": "^2.0.4" 29 | }, 30 | "devDependencies": { 31 | "@babel/cli": "^7.0.0-beta.56", 32 | "@babel/core": "7.0.0-beta.54", 33 | "@babel/plugin-proposal-class-properties": "7.0.0-beta.54", 34 | "@babel/plugin-proposal-decorators": "7.0.0-beta.54", 35 | "@babel/plugin-proposal-do-expressions": "7.0.0-beta.54", 36 | "@babel/plugin-proposal-export-default-from": "7.0.0-beta.54", 37 | "@babel/plugin-proposal-export-namespace-from": "7.0.0-beta.54", 38 | "@babel/plugin-proposal-function-sent": "7.0.0-beta.54", 39 | "@babel/plugin-proposal-json-strings": "7.0.0-beta.54", 40 | "@babel/plugin-proposal-logical-assignment-operators": "7.0.0-beta.54", 41 | "@babel/plugin-proposal-nullish-coalescing-operator": "7.0.0-beta.54", 42 | "@babel/plugin-proposal-numeric-separator": "7.0.0-beta.54", 43 | "@babel/plugin-proposal-optional-chaining": "7.0.0-beta.54", 44 | "@babel/plugin-proposal-pipeline-operator": "7.0.0-beta.54", 45 | "@babel/plugin-proposal-throw-expressions": "7.0.0-beta.54", 46 | "@babel/plugin-syntax-dynamic-import": "7.0.0-beta.54", 47 | "@babel/plugin-syntax-import-meta": "7.0.0-beta.54", 48 | "@babel/plugin-transform-runtime": "^7.0.0-beta.56", 49 | "@babel/polyfill": "7.0.0-beta.54", 50 | "@babel/preset-env": "7.0.0-beta.54", 51 | "@babel/preset-typescript": "^7.0.0-beta.56", 52 | "@babel/runtime": "^7.0.0-beta.56", 53 | "@trust/webcrypto": "^0.9.2", 54 | "@types/jest": "^23.3.1", 55 | "@types/node": "^10.5.6", 56 | "@types/valid-url": "^1.0.2", 57 | "babel-core": "^7.0.0-bridge.0", 58 | "babel-jest": "^23.4.2", 59 | "babel-loader": "^8.0.0-beta.0", 60 | "babel-plugin-transform-remove-console": "^6.9.4", 61 | "babelify": "^8.0.0", 62 | "browserify": "^16.2.2", 63 | "chai": "*", 64 | "cross-env": "^5.2.0", 65 | "gulp": "^3.9.1", 66 | "gulp-uglify-es": "^1.0.4", 67 | "gulp-util": "^3.0.8", 68 | "hoek": "^5.0.3", 69 | "jest": "^23.4.2", 70 | "jest-fetch-mock": "^1.6.5", 71 | "jest-watch-typeahead": "^0.2.0", 72 | "mocha": "^5.2.0", 73 | "ts-jest": "^23.1.3", 74 | "tslint": "^5.11.0", 75 | "typescript": "^3.0.1", 76 | "uglifyjs-webpack-plugin": "^1.2.7", 77 | "vinyl-buffer": "^1.0.1", 78 | "vinyl-source-stream": "^1.1.2", 79 | "webpack": "^4.16.5", 80 | "webpack-command": "^0.4.1" 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/__tests__/address.fixtures.ts: -------------------------------------------------------------------------------- 1 | export const addresses = [ 2 | { 3 | public: '0314738163B9BB67AD11AA464FE69A1147DF263E8970D7DCFD8F993DDD39E81BD9', 4 | private: 'B4EB8E8B343E2CCE46DB4E7571EC1D9654693CCA200BC41CC20148355CA62ED9', 5 | address: '4BAF5FADA8E5DB92C3D3242618C5B47133AE003C', 6 | }, 7 | { 8 | public: '034CE268AC5A340038D8ACEBBDD7363611A5B1197916775E32481F5D6B104FAF65', 9 | private: 'FD906F4A20A0507813FCB0D8D166CF45C1B17F217B776A003B3C3CC628C7E513', 10 | address: '448261915A80CDE9BDE7C7A791685200D3A0BF4E', 11 | }, 12 | { 13 | public: '02FA7A501F323CC53E070C0A945370368679E7572960EC24D8A0387EF3B50A2285', 14 | private: 'C1FE69C394EE8564D0EA525FF74E5F37DF5267CF5C74F2E224757B7D9E594B73', 15 | address: 'DED02FD979FC2E55C0243BD2F52DF022C40ADA1E', 16 | }, 17 | { 18 | public: '036F8676E473AF20B4CCE7D327103DE4504A9C00EAE7EA03D0A365FB48817AC97F', 19 | private: 'F197920FF83E3BD727560E1E08A4825910E3AA772B40EC4DEFFE241EE3A51D20', 20 | address: '13F06E60297BEA6A3C402F6F64C416A6B31E586E', 21 | }, 22 | { 23 | public: '034C39363529C2D4078F72B8C498C4CBC5BA5E10D8666FE06F104A27E0E44242A0', 24 | private: '3D0C4009DA5B4630D292E93FC8DF7A55E9B8B31E182A50D113DE6E7A7A728B5B', 25 | address: '1A90C25307C3CC71958A83FA213A2362D859CF33', 26 | }, 27 | { 28 | public: '026DA5BF6C3A3C91C08A3DD7FBCE0BEAF5D436039C97B07A0F61AA4B9493E46787', 29 | private: '8A06825735F2F374E5F60F0E08E06EF7169E2AE47532B741700574B9E1603DC0', 30 | address: '625ABAEBD87DAE9AB128F3B3AE99688813D9C5DF', 31 | }, 32 | { 33 | public: '032A661F9D4AB8DD9818CED2F62F3DA14FDD23E68E58D01A4AE186231D7FB609BB', 34 | private: '715AB4286ECCB4E8E3AEC0AA8B6FB0E13C105B727E89AAE449F87F5DF4CFA53F', 35 | address: '36BA34097F861191C48C839C9B1A8B5912F583CF', 36 | }, 37 | { 38 | public: '036A94E925BB200DCE41A46C9026E023B226DD5B4CB227CE766D60CC8FAB218148', 39 | private: 'B9056706EF197125598E7D5CA5AC9C47339B5C894C0656D33113052470BAF149', 40 | address: 'D2453AE76C9A86AAE544FCA699DBDC5C576AEF3A', 41 | }, 42 | { 43 | public: '0247F13639C7597C8AE2467DD29D219C2749260F690D4069930FDEB7866B2BC1FA', 44 | private: 'A6DEDD1BE3A36945517A6C8A0E1353414DEBC04C50C9E036361C2A2D95EEF947', 45 | address: '72220E84947C36118CDBC580454DFAA3B918CD97', 46 | }, 47 | { 48 | public: '02883100F00EAB9FB6FD79034BBA84235C22ED642470FF6C1DB7CF7F782902D9DC', 49 | private: '57489B87A3E726267EC5150FAB6E202694E806EC8FBBE386572CDE640BB3EE4B', 50 | address: '50F92304C892D94A385CA6CE6CD6950CE9A36839', 51 | }, 52 | ]; 53 | 54 | -------------------------------------------------------------------------------- /src/__tests__/checksum.fixtures.ts: -------------------------------------------------------------------------------- 1 | export const checksummedStore = [{ 2 | original: "4BAF5FADA8E5DB92C3D3242618C5B47133AE003C", 3 | good_no0x:"4BaF5fADa8E5Db92c3D3242618c5b47133Ae003c", 4 | good: "0x4BaF5fADa8E5Db92c3D3242618c5b47133Ae003c", 5 | bad: "0x4baF5fADa8E5Db92c3D3242618c5b47133Ae003c", // first b is lowercase 6 | }, 7 | { 8 | original: "448261915A80CDE9BDE7C7A791685200D3A0BF4E", 9 | good_no0x:"448261915a80CDe9bde7C7A791685200d3A0BF4e", 10 | good: "0x448261915a80CDe9bde7C7A791685200d3A0BF4e", 11 | bad: "0x448261915a80cDe9bde7C7A791685200d3A0BF4e", // first c is lowercase 12 | }, 13 | { 14 | original: "DED02FD979FC2E55C0243BD2F52DF022C40ADA1E", 15 | good_no0x:"DED02FD979fC2e55c0243Bd2f52DF022C40aDa1E", 16 | good: "0xDED02FD979fC2e55c0243Bd2f52DF022C40aDa1E", 17 | bad: "0xdED02FD979fC2e55c0243Bd2f52DF022C40aDa1E", // first d is lowercase 18 | }, 19 | { 20 | original: "13F06E60297BEA6A3C402F6F64C416A6B31E586E", 21 | good_no0x:"13f06E60297bEA6A3C402F6F64c416a6B31e586e", 22 | good: "0x13f06E60297bEA6A3C402F6F64c416a6B31e586e", 23 | bad: "0x13F06E60297bEA6A3C402F6F64c416a6B31e586e", // first f is uppercase 24 | }, 25 | { 26 | original: "1A90C25307C3CC71958A83FA213A2362D859CF33", 27 | good_no0x:"1a90c25307c3Cc71958A83fa213a2362D859cF33", 28 | good: "0x1a90c25307c3Cc71958A83fa213a2362D859cF33", 29 | bad: "0x1A90c25307c3Cc71958A83fa213a2362D859cF33", // first a is uppercase 30 | 31 | }, 32 | { 33 | original: "625ABAEBD87DAE9AB128F3B3AE99688813D9C5DF", 34 | good_no0x:"625aBAEBd87Dae9AB128F3b3ae99688813d9C5Df", 35 | good: "0x625aBAEBd87Dae9AB128F3b3ae99688813d9C5Df", 36 | bad: "0x625AbAEBd87Dae9AB128F3b3ae99688813d9C5Df", // first A is uppercase, b is lowercase 37 | }, 38 | { 39 | original: "36BA34097F861191C48C839C9B1A8B5912F583CF", 40 | good_no0x:"36BA34097f861191c48c839c9B1A8B5912f583cf", 41 | good: "0x36BA34097f861191c48c839c9B1A8B5912f583cf", 42 | bad: "0x36bA34097f861191c48c839c9B1A8B5912f583cF", // first b is lowercase, last F is uppercase 43 | }, 44 | { 45 | original: "D2453AE76C9A86AAE544FCA699DBDC5C576AEF3A", 46 | good_no0x:"D2453AE76c9a86AAE544FCa699DBdC5C576aEf3A", 47 | good: "0xD2453AE76c9a86AAE544FCa699DBdC5C576aEf3A", 48 | bad: "0xd2453aE76c9a86AaE544FCA699DBdC5C576Aef3A", // random lowercase / upperacase 49 | }, 50 | { 51 | original: "72220E84947C36118CDBC580454DFAA3B918CD97", 52 | good_no0x:"72220E84947c36118CDbc580454DfaA3B918cd97", 53 | good: "0x72220E84947c36118CDbc580454DfaA3B918cd97", 54 | bad: "0x72220e84947C36118cdBC580454dFAa3b918CD97", // inverted cases 55 | }, 56 | { 57 | original: "50F92304C892D94A385CA6CE6CD6950CE9A36839", 58 | good_no0x:"50f92304c892d94A385Ca6ce6cD6950ce9A36839", 59 | good: "0x50f92304c892d94A385Ca6ce6cD6950ce9A36839", 60 | bad: "0x50F92304c892D94A385Ca6ce6CD6950ce9A36839", // random lowercase / upperacase 61 | } 62 | ]; 63 | -------------------------------------------------------------------------------- /src/__tests__/keypairs.fixtures.ts: -------------------------------------------------------------------------------- 1 | export const pairs = [ 2 | { 3 | private: 'b776d8f068d11b3c3f5b94db0fb30efea05b73ddb9af1bbd5da8182d94245f0b', 4 | public: 5 | '04cfa555bb63231d167f643f1a23ba66e6ca1458d416ddb9941e95b5fd28df0ac513075403c996efbbc15d187868857e31cf7be4d109b4f8cb3fd40499839f150a', 6 | digest: '0e3e927f8be54eb20f4f47baa2f4d23649433591ea1b967127b971de2288609e', 7 | }, 8 | { 9 | private: '24180e6b0c3021aedb8f5a86f75276ee6fc7ff46e67e98e716728326102e91c9', 10 | public: 11 | '04163fa604c65aebeb7048c5548875c11418d6d106a20a0289d67b59807abdd299d4cf0efcf07e96e576732dae122b9a8ac142214a6bc133b77aa5b79ba46b3e20', 12 | digest: 'f5b2dfddfdbd0d13a67085a5ad5744c0c6246d9704592116fccbf41978fe99c8', 13 | }, 14 | { 15 | private: 'af71626e38926401a6d2fd8fdf91c97f785b8fb2b867e7f8a884351e59ee9aa6', 16 | public: 17 | '0485c34ff11ea1e06f44d35afe3cc1748b6b122bb06df021a4767db4ef5fbcf1cdbed73c821d89724b59a0fc5e2f2e3e1a9c121d698fff36d750ee463117438a14', 18 | digest: 'f8b9842a5f695139d22f49d1f706173b76fe0b5f680779558f23635a35425154', 19 | }, 20 | { 21 | private: 'b94289721618d1a8100bea8502fee149bae7313fcbaebf5ad6a867d557e82971', 22 | public: 23 | '04c7d47ad99dd1db85c9d0b6abe89ffc137f230c991a33890c05436a14974543a29d58bc4655269db6bcd6ea27adca287f956355c64d676cefcfea14051b5239c9', 24 | digest: 'f6dae5bbe10084a0afcf363d11b08e4f6941d09dfbd39ce6474e115ff7908e05', 25 | }, 26 | { 27 | private: 'c577711506abf9dbdabd09c5ae66492e77d6450e8d739ce6493728e781150236', 28 | public: 29 | '0484929ab70d2b39703319a94144802ea9b9a7c8c1a673b10f01738db5b5c40ea8f534bc21ef1b167ffcac7d1a087ed5be2a5d1fa720bc016fbfbd9fb869aee4c6', 30 | digest: '688c722f9c72cc4d760fd5967b3e26c3628bb4b3eb4b397ab7a2c3f26d312931', 31 | }, 32 | { 33 | private: 'e9521f5f9f2ac16f4e22681d43f2c1e15163ffe56e5912d57540dd59d71f2877', 34 | public: 35 | '04db0535d0e4337e5ada6d87b07569308f3f3de19aad15ba1f95108e96f855e17195e5b86773f7570645832048cb5e13e1721784ecce6bf69a0342f873e3afef58', 36 | digest: '80a0001162a8230c4d3b624f8acf90b9c4d9d8f625703936a1e02aecb7d84d41', 37 | }, 38 | { 39 | private: 'def6ac38d746349abd8a28903c6b98b06156f6f3925d1c32dec9964541fbbfa1', 40 | public: 41 | '04dc5ca31dff767cb18f92d208fd74e36e800508d3b88bee61680bb7cefa0515943f2801d25bbce9c6a65721427f2443532980a0f7b7aae71b1fe0501179b8f641', 42 | digest: 'c3f72427150375b7f9838f1a82873a66fcff822f529ad313e88c7785726f3ec1', 43 | }, 44 | { 45 | private: '93fe1b32f4f1358d6809982bce53b9e95c083eb889d14b0c2d0f96012074dc6b', 46 | public: 47 | '04987f1f6a2fe56cd0c2461f2920e3e0d9bd9de96a8febf9246e187e057c6141c494b697455dccefa29361b976698594082ed962da42bce09ef0ce59bd05510dd4', 48 | digest: 'a26c10e3afcaa7aa20f21ba513747d1a9ba8c1b91b32bfabe88072e9519bf0f9', 49 | }, 50 | { 51 | private: 'efaa6048789fa0282302a5620a2fb0e2c60095a54c42b8312646bbbe1d2ec801', 52 | public: 53 | '04645a3995ff3309a36d1ec0991fd87ece2ee36e8887f0d5b304accb9152fe7a603aba24fefa904741e0fd67db24432a38153ecdc496ceec38eab1b7c2d8405de9', 54 | digest: '5be58c9bc87b284af73274dc6dc01e38faaa25dfac9cbeb8941ea90c177d2cd8', 55 | }, 56 | { 57 | private: 'ca7de577b3e6968da27088d22e918c039a96af3d4821b7e103560fb6ca1185c4', 58 | public: 59 | '04f3e03a4ac451a78254fa3d056448db6cbc29d2ef429228c8435141a126c0c07f2446c68270016322e93a6a14f2e7c557bfdcc74e122a013498b7f1ebe008cc30', 60 | digest: '0179e96ddeb567686e47f71794256ddbdbbfd5ca865b26d6751c66c84aa1ef4b', 61 | }, 62 | ]; 63 | -------------------------------------------------------------------------------- /src/__tests__/node.spec.ts: -------------------------------------------------------------------------------- 1 | import elliptic from 'elliptic'; 2 | import BN from 'bn.js'; 3 | import {pairs} from './keypairs.fixtures'; 4 | import * as util from '../util'; 5 | import Znode from '../node'; 6 | import jestFetch from 'jest-fetch-mock'; 7 | 8 | const secp256k1 = elliptic.ec('secp256k1'); 9 | const node = new Znode({url: 'http://localhost:4201'}); 10 | const fetchMock = fetch as typeof jestFetch; 11 | 12 | const code = '(* HelloWorld contract *)\n\n\n(***************************************************)\n(* Associated library *)\n(***************************************************)\nlibrary HelloWorld\n\nlet one_msg = \n fun (msg : Message) => \n let nil_msg = Nil {Message} in\n Cons {Message} msg nil_msg\n\nlet not_owner_code = Int32 1\nlet set_hello_code = Int32 2\n\n(***************************************************)\n(* The contract definition *)\n(***************************************************)\n\ncontract HelloWorld\n(owner: Address)\n\nfield welcome_msg : String = ""\n\ntransition setHello (msg : String)\n is_owner = builtin eq owner _sender;\n match is_owner with\n | False =>\n msg = {_tag : "Main"; _recipient : _sender; _amount : Uint128 0; code : not_owner_code};\n msgs = one_msg msg;\n send msgs\n | True =>\n welcome_msg := msg;\n msg = {_tag : "Main"; _recipient : _sender; _amount : Uint128 0; code : set_hello_code};\n msgs = one_msg msg;\n send msgs\n end\nend\n\n\ntransition getHello ()\n r <- welcome_msg;\n msg = {_tag : "Main"; _recipient : _sender; _amount : Uint128 0; msg : r};\n msgs = one_msg msg;\n send msgs\nend'; 13 | 14 | describe('node', () => { 15 | beforeEach(() => { 16 | fetchMock.resetMocks(); 17 | }); 18 | 19 | it('should be able to create transactions to 0x0', (done) => { 20 | const privateKey = pairs[1].private; 21 | const publicKey = secp256k1 22 | .keyFromPrivate(privateKey, 'hex') 23 | .getPublic(true, 'hex'); 24 | 25 | // the immutable initialisation variables 26 | const initParams = [ 27 | { 28 | vname: 'owner', 29 | type: 'Address', 30 | value: '0x1234567890123456789012345678901234567890', 31 | }, 32 | { 33 | vname: 'total_tokens', 34 | type: 'Uint128', 35 | value: '10000', 36 | }, 37 | ]; 38 | 39 | const tx = { 40 | version: 8, 41 | nonce: 8, 42 | to: '0000000000000000000000000000000000000000', 43 | from: pairs[1].digest.slice(0, 40), 44 | pubKey: publicKey, 45 | amount: new BN('888', 10), 46 | gasPrice: 8, 47 | gasLimit: 88, 48 | code: code, 49 | data: JSON.stringify(initParams).replace(/\\"/g, '"'), 50 | }; 51 | 52 | const signed = util.createTransactionJson(privateKey, tx); 53 | 54 | const response = JSON.stringify({some: 'random_data'}); 55 | fetchMock.mockResponseOnce(response); 56 | node.createTransaction(signed, (err, res) => { 57 | expect(err).toBeFalsy(); 58 | expect(JSON.stringify(res)).toEqual(response); 59 | done(); 60 | }); 61 | }); 62 | 63 | it('should be able to broadcast a well-formed transaction', (done) => { 64 | const privateKey = pairs[1].private; 65 | const publicKey = secp256k1 66 | .keyFromPrivate(privateKey, 'hex') 67 | .getPublic(true, 'hex'); 68 | 69 | const tx = { 70 | version: 8, 71 | nonce: 8, 72 | to: pairs[0].digest.slice(0, 40), 73 | from: pairs[1].digest.slice(0, 40), 74 | pubKey: publicKey, 75 | amount: new BN('888', 10), 76 | gasPrice: 8, 77 | gasLimit: 88, 78 | code: '', 79 | data: '', 80 | }; 81 | 82 | // setup mock response here 83 | const response = JSON.stringify({some: 'random_data'}); 84 | fetchMock.mockResponseOnce(response); 85 | 86 | node.createTransaction(tx, (err, res) => { 87 | expect(err).toBeFalsy(); 88 | expect(JSON.stringify(res)).toEqual(response); 89 | done(); 90 | }); 91 | }); 92 | }); 93 | -------------------------------------------------------------------------------- /src/__tests__/schnorr.fixtures.ts: -------------------------------------------------------------------------------- 1 | export default [ 2 | { 3 | msg: 4 | '89D68815DDB9E5F8D7FD53B6EC096616A773B9421F6704CED36EF4E484BA0C6C5A4855C71C33A54AC82BE803E5CFD175779FC444B7E6AA9001EEFABEBC0CF99754887C7B0A27AFDDC415F8A02C5AF1EFEA26AD1E5D92B1E2', 5 | priv: 'EDA7AFB6E3CEC979CC37BA87A09E63CAA864D0202A6BA7DF7966C012B1D92F7E', 6 | pub: '024C34E2D3921D05102BF3D4EE806E188395AFD033F39D090A46A369D709797FC3', 7 | k: '63C6C74C9FD5F31B5576E47873994BB6C8724FA31EEAB7669DB915EDFDB1A23C', 8 | r: '4B31EA76A9E890D533A753BEB0EE9DE1072CA5508B0DA5D45B1AA9487FA491FE', 9 | s: 'CC92A532CCB5172C1199178E832EA770B4BFA696034471BDC1CE23215276B109', 10 | }, 11 | { 12 | msg: 13 | 'EF9237CE5B615BC08677EE5ABFBD85F73F7F8868CB1B5FBA4C1309F16061AA133821FBE2A758D2BBE6AA040A940D41B7D3B869CEE945150AA4A40E6FF719EEC24B2681CD5CE06B50273436584066046656D5EFED73157591', 14 | priv: 'C7A5FCF7B927D652231C56CB8F007D2E4A392726620D6604B50F54BC32732A16', 15 | pub: '024F39C9B8DC1355E806F5C324A8D80B67FD0B1848A2A78F7C7E9E514ED9C51074', 16 | k: '015B931D9C7BF3A7A70E57868BF29712377E74355FC59032CD7547C80E179010', 17 | r: '611FAB2F8B1D0E48D2D535CD9A1DFD9F31AB834F8C34C20100FC93CBA61EEF72', 18 | s: '371DC25E061CF20F096AA2B1FE552A7C07D8B102B2F7F8865E984BA679CAF4AF', 19 | }, 20 | { 21 | msg: 22 | '4E0E67D2D03957F0CF6C87834BF328540588360BA7C7C5F88541634FB7BADE5F94FF671D1FEBDCBDA116D2DA779038ED7679896C29198B2657B58C50EA054F644F4129C8BA8D8D544B727633DD40754398046796E038626F', 23 | priv: '8608065C1B777CE7655311293995AA091C84C2B16B010985138936A6736EF0F6', 24 | pub: '03707675447CB9E50CDF2DDD4B3D0B2A5CFE2DE60AD377509E340E9D0B75F7458B', 25 | k: '8695F6766BA6D132E4EB547AFC9B65C0EE5F2AEC1D0F41E695ABCD161EAC9A52', 26 | r: '9CFB236E54868BE966A5104051EB9E1BB7F38B5BA30D2AA865E73F1BABE6C283', 27 | s: '4A213BC595BE4A6B91BDC2989041EFEACDD5E09EADEE21AEF6110A32C57C3317', 28 | }, 29 | { 30 | msg: 31 | 'D9D5BF144C08E9577ED0D1E5E560875109B340980580473DBC2E689A3BE838E77A0A3348FE960EC9BF81DA36F1868CA5D24788FA4C0C778BF0D12314285495636516CF40861B3D737FD35DBB591C5B5D25916EB1D86176B1', 32 | priv: '01310279230B5D9230AFAD6F72FD6AAB3584F0756833910278BCC54FDCFF2B45', 33 | pub: '03CB4F22931C82DE38780DEE9DB105CB7175287D65CF754D79165B2E50E4012E28', 34 | k: '6DF6E9E4A2CCCE53812CAA61477B93130F123782614BF61867653C966B03D689', 35 | r: '01F095B428B01F7243217C87839892E1EA44ABB22D3BC1FADBA774901218C1FD', 36 | s: '6A46F23B370EB837CBB8F52B99F4336FE4FE718C50270938B868314D9609D543', 37 | }, 38 | { 39 | msg: 40 | '1C1784B5484EECDB393F6A0ACA11B91DF0866B500B8DEE501FD7EB9BCE09A17D74124B4605ADFC0777BED9816D8D7E8488544A18D8045CB3283B0A752B881B5F500FADB59010E63D1B664F8BDA2DBF33CB6BE21C8EB3ECA9', 41 | priv: '8CEE0A6AEE8FB30A0AE7B6A5BFAFFA52E097E88F5388919F06D407520056503E', 42 | pub: '02D9CFD6CD6B4231BD6F1BDC5DAC502B4AF6144A9407FE37764CAB8CFC530566FA', 43 | k: '12C31321A6E3D10597C560DF6D4505ACF85E1531A56FC70EC65466BA79BAA7F7', 44 | r: 'AB561B9544923AA35F200AAF84206C4132E0F95629FD7CB7CBB211B4D88174F7', 45 | s: 'B65BAA2528FC5F3B195169EB6BFA2BD7B6D28B7B1323647105A7A733C0FEC4CE', 46 | }, 47 | { 48 | msg: 49 | 'B9103262CDB941F77376F5D3DBB7A3D5A387797FC4819A035ECA704CEDB37110ee7f206b0c8805aaebf4963e7c4708ce8d4e092366e71792a8a3b2bbcdee321b3e15380c541ef0930888969f7457afe18588826a419d5831', 50 | priv: '042E4F26C128D61B356C1C44DD8688945B9104CC064572137FF0C2238F3D1B26', 51 | pub: '02F898D30F7BE156B7AB89F92B5BE536D0BFADFF1343628DA68FAF24BBF8051F60', 52 | k: 'BC174CD51F7D19FF103CEA62AD9054387EFCBC9665991501C303549BACDF749B', 53 | r: '6E4CF5B29AE2F51645CB48FD0240B3D7A40F54FB87CD0CB6A81AE08086F87A9B', 54 | s: 'E68710FB6721EC077F7C57878CB7A79370CF7B4D056CE755C6761C166C39FB73', 55 | }, 56 | { 57 | msg: 58 | '3957166441B93515E8F03C95D8E8CE1E1864FAAD68DDFC5932130109390B0F1FE5CA716805F8362E98DCCAADC86ADBED25801A9A9DCFA6264319DDAFE83A89C51F3C6D199D38DE10E660C37BE872C3F2B31660DE8BC95902', 59 | priv: '1A0A27DC91FC16956F2C18A9D3024DE4B3CEE9F330D4955E0655741929181DDF', 60 | pub: '0299831A1D3ECEDAC359355059D9D8CA3829CE4788B6D52873BE6811EA7926C0CD', 61 | k: 'CD9F19178563B5EE012E603C0F977E94E1D22A1FA98992177550E453AAEC0257', 62 | r: '391FE228C29165EAA4D3062CF96E2AA7C07B4F0F8D720CEC5162A3F16F653679', 63 | s: '513E0537B56E5CFCBE2CFB06022A280DE5BC224021B3BB06EF2BC78721903731', 64 | }, 65 | { 66 | msg: 67 | '0687EF5309D108534F51F8658FB4F080B7CB19EE9AEBD718CC4FA27C8C37DFC1ADA5D133D13ABE03F021E9B1B78CCBD82F7FF2B38C6D48D01E481B2D4FAF7171805FD7F2D39EF4C4F19B9496E81DAB8193B3737E1B27D9C4', 68 | priv: '5E986AD51606AE69D9DA413B8FB503878BA607A31D12EA0B98B7930AC23662A7', 69 | pub: '031DFE3D937119F0DAC3BD4CD6DBF6E41FEB29C6B5C14EFB8E387AC4C4EFEB4036', 70 | k: '82BFDC4F8C897C46286109FA7B1B4ECCB724CE8823A27B01C0E857587587C71E', 71 | r: 'C200BC1708C1AEAFA624FB89ECB5FC8F92122D829ABB87FC8A14E27084FB7909', 72 | s: '48FDDFCD83AF62442380F3FF1E1A8F986196B56F2BE3F797EA991086F95CEDCE', 73 | }, 74 | { 75 | msg: 76 | '5BFA6CC351E220AE0CE106986D61FF34A11E19FD3650E9B7818FC33A1E0FC02C44557AC8AB50C9B2DEB2F6B5E24C4FDD9F8867BDCE1FF261008E7897970E346207D75E47A158298E5BA2F56246869CC42E362A02731264E6', 77 | priv: 'EF7AE484F4821E320D4104F5350B8A9B82121329CAF1596D1563B22595738536', 78 | pub: '0250E299F2A83E5E88C4B0A80D2CD5D6F4261E0E5B788F800AA332B4CE4CBC6AD0', 79 | k: '9B605C81169E65D8CABCC026834109027D07BC35DB4E60C094704CAD41436522', 80 | r: '3B5FC26609EC90B2CEC4A7D43BDC700D8BFA1A20E3AAB5C6A7DAFF4C9BB01C3B', 81 | s: '655568B30AFA1DFB60009F33DD9CBD8A4A44CC2A4A446FB7E0B2F84AE08828E5', 82 | }, 83 | { 84 | msg: 85 | 'A7F1D92A82C8D8FE434D98558CE2B347171198542F112D0558F56BD68807999248336241F30D23E55F30D1C8ED610C4B0235398184B814A29CB45A672ACAE548E9C5F1B0C4158AE59B4D39F6F7E8A105D3FEEDA5D5F3D9E4', 86 | priv: '0755EFB1BDCA8E28FD29CA57774D9DB7B07A65A48EF7F8762E52840D43FDD277', 87 | pub: '02076F5B8511A3AD45A4856681AB66C0B8A979F44640036E752231298ED75AD48E', 88 | k: 'BC59D8D973767EBB04AE5BCDAD61849985E800D148165FAFF3AD93004EFB42D6', 89 | r: '76697A7A7BA544C21FB4B7EB64EF9E1C7CEA22C9CB861C9BB565D99C55767B82', 90 | s: '53354ADB50D95DB0608D999214FEB6D6E60FAF2323275162E023C09FB3FE3A04', 91 | }, 92 | ]; 93 | -------------------------------------------------------------------------------- /src/__tests__/util.spec.ts: -------------------------------------------------------------------------------- 1 | import elliptic from 'elliptic'; 2 | import Signature from 'elliptic/lib/elliptic/ec/signature'; 3 | import BN from 'bn.js'; 4 | import {addresses} from './address.fixtures'; 5 | import {checksummedStore} from './checksum.fixtures'; 6 | import {pairs} from './keypairs.fixtures'; 7 | import schnorrVectors from './schnorr.fixtures'; 8 | import * as util from '../util'; 9 | import * as schnorr from '../schnorr'; 10 | 11 | const secp256k1 = elliptic.ec('secp256k1'); 12 | 13 | describe('utils', () => { 14 | it('should be able to generate a valid 32-byte private key', () => { 15 | const pk = util.generatePrivateKey(); 16 | 17 | expect(pk).toHaveLength(64); 18 | expect(util.verifyPrivateKey(pk)).toBeTruthy(); 19 | }); 20 | 21 | it('should recover a public key from a private key', () => { 22 | pairs.forEach(({private: priv, public: expected}) => { 23 | const actual = util.getPubKeyFromPrivateKey(priv); 24 | expect(actual).toEqual(util.compressPublicKey(expected)); 25 | }); 26 | }); 27 | 28 | it('should convert a public key to an address', () => { 29 | pairs.forEach(({public: pub, digest}) => { 30 | const expected = digest.slice(24); 31 | const actual = util.getAddressFromPublicKey(pub); 32 | 33 | expect(actual).toHaveLength(40); 34 | expect(actual).toEqual(expected); 35 | }); 36 | }); 37 | 38 | it('should be able to recover an address from a private key', () => { 39 | const [pair] = pairs; 40 | const expected = util.getAddressFromPublicKey( 41 | util.compressPublicKey(pair.public), 42 | ); 43 | const actual = util.getAddressFromPrivateKey(pair.private); 44 | 45 | expect(actual).toHaveLength(40); 46 | expect(actual).toEqual(expected); 47 | }); 48 | 49 | it('should give the same address for a given public or private key', () => { 50 | pairs.forEach(({private: priv, public: pub}) => { 51 | const fromPrivateKey = util.getAddressFromPrivateKey(priv); 52 | const fromPublicKey = util.getAddressFromPublicKey( 53 | util.compressPublicKey(pub), 54 | ); 55 | 56 | expect(fromPrivateKey).toHaveLength(40); 57 | expect(fromPublicKey).toHaveLength(40); 58 | expect(fromPublicKey).toEqual(fromPrivateKey); 59 | }); 60 | }); 61 | 62 | it('should be able to correctly create transaction json', () => { 63 | const privateKey = pairs[1].private; 64 | const publicKey = secp256k1 65 | .keyFromPrivate(privateKey, 'hex') 66 | .getPublic(true, 'hex'); 67 | 68 | const tx = { 69 | version: 8, 70 | nonce: 8, 71 | to: pairs[0].digest.slice(24), 72 | pubKey: publicKey, 73 | amount: new BN('888', 10), 74 | gasPrice: 8, 75 | gasLimit: 88, 76 | code: '', 77 | data: '', 78 | }; 79 | 80 | const {signature} = util.createTransactionJson(privateKey, tx); 81 | const res = schnorr.verify( 82 | util.encodeTransaction(tx), 83 | new Signature({ 84 | r: new BN((signature as string).slice(0, 64), 16), 85 | s: new BN((signature as string).slice(64), 16), 86 | }), 87 | Buffer.from(publicKey, 'hex'), 88 | ); 89 | 90 | expect(res).toBeTruthy(); 91 | }); 92 | 93 | it('should produce the same results as the C++ keygen util', () => { 94 | addresses.forEach(({public: pub, private: priv, address}) => { 95 | const generatedPub = util.getPubKeyFromPrivateKey(priv); 96 | const addressFromPriv = util.getAddressFromPrivateKey(priv); 97 | const addressFromPub = util.getAddressFromPrivateKey(priv); 98 | 99 | expect(generatedPub.toUpperCase()).toEqual(pub); 100 | expect(addressFromPriv.toUpperCase()).toEqual(address); 101 | expect(addressFromPub.toUpperCase()).toEqual(address); 102 | }); 103 | }); 104 | 105 | it('should sign messages correctly', () => { 106 | const privateKey = pairs[1].private; 107 | const publicKey = secp256k1 108 | .keyFromPrivate(privateKey, 'hex') 109 | .getPublic(false, 'hex'); 110 | 111 | const tx = { 112 | version: 8, 113 | nonce: 8, 114 | to: pairs[0].digest.slice(0, 40), 115 | pubKey: publicKey, 116 | amount: new BN('888', 10), 117 | gasPrice: 8, 118 | gasLimit: 88, 119 | code: '', 120 | data: '', 121 | }; 122 | 123 | const encodedTx = util.encodeTransaction(tx); 124 | const sig = schnorr.sign( 125 | encodedTx, 126 | Buffer.from(privateKey, 'hex'), 127 | Buffer.from(publicKey, 'hex'), 128 | ); 129 | const res = schnorr.verify(encodedTx, sig, Buffer.from(publicKey, 'hex')); 130 | 131 | expect(res).toBeTruthy(); 132 | }); 133 | 134 | it('should not verify a falsely signed transaction', () => { 135 | schnorrVectors.forEach(({priv, k}, idx) => { 136 | const pub = secp256k1.keyFromPrivate(priv, 'hex').getPublic(true, 'hex'); 137 | const badPrivateKey = pairs[0].private; 138 | 139 | const tx = { 140 | version: 8, 141 | nonce: 8, 142 | to: util.getAddressFromPublicKey(pub), 143 | pubKey: pub, 144 | amount: new BN('888', 10), 145 | gasPrice: 8, 146 | gasLimit: 88, 147 | code: '', 148 | data: '', 149 | }; 150 | 151 | const encodedTx = util.encodeTransaction(tx); 152 | 153 | let sig; 154 | while (!sig) { 155 | sig = schnorr.trySign( 156 | encodedTx, 157 | new BN(Buffer.from(badPrivateKey, 'hex')), 158 | new BN(k), 159 | Buffer.from(''), 160 | Buffer.from(pub, 'hex'), 161 | ); 162 | } 163 | 164 | const res = schnorr.verify(encodedTx, sig, Buffer.from(pub, 'hex')); 165 | expect(res).toBeFalsy(); 166 | }); 167 | }); 168 | 169 | it('should match the C++ Schnorr implementation', () => { 170 | schnorrVectors.forEach(({msg, priv, pub, k, r, s}) => { 171 | let sig: Signature | null = null; 172 | while (!sig) { 173 | sig = schnorr.trySign( 174 | Buffer.from(msg, 'hex'), 175 | new BN(Buffer.from(priv, 'hex')), 176 | new BN(k, 16), 177 | Buffer.from(''), 178 | Buffer.from(pub, 'hex'), 179 | ); 180 | } 181 | 182 | const res = schnorr.verify( 183 | Buffer.from(msg, 'hex'), 184 | sig, 185 | Buffer.from(pub, 'hex'), 186 | ); 187 | 188 | expect(sig.r.toString('hex', 64).toUpperCase()).toEqual(r); 189 | expect(sig.s.toString('hex', 64).toUpperCase()).toEqual(s); 190 | expect(res).toBeTruthy(); 191 | }); 192 | }); 193 | 194 | it('should return a valid 0x prefixed checksummed address', () => { 195 | checksummedStore.forEach(({original: address, good: expected}) => { 196 | const actual = util.toChecksumAddress(address); 197 | expect(actual).toEqual(expected); 198 | expect(actual.substr(0, 2)).toEqual("0x"); 199 | }); 200 | }); 201 | 202 | it('should return true when a valid checksummed address is tested', () => { 203 | checksummedStore.forEach(({good: checksummed}) => { 204 | const actual = util.isValidChecksumAddress(checksummed); 205 | expect(actual).toBeTruthy(); 206 | }); 207 | }); 208 | 209 | it('should return false when an invalid checksummed address is tested', () => { 210 | checksummedStore.forEach(({bad: badlychecksummed}) => { 211 | const actual = util.isValidChecksumAddress(badlychecksummed); 212 | expect(actual).toBeFalsy(); 213 | }); 214 | }); 215 | }); 216 | -------------------------------------------------------------------------------- /src/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.0.1", 3 | "defaultNodeUrl": "http://localhost:4201" 4 | } -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Zilliqa 2 | // This source code is being disclosed to you solely for the purpose of your participation in 3 | // testing Zilliqa. You may view, compile and run the code for that purpose and pursuant to 4 | // the protocols and algorithms that are programmed into, and intended by, the code. You may 5 | // not do anything else with the code without express permission from Zilliqa Research Pte. Ltd., 6 | // including modifying or publishing the code (or any part of it), and developing or forming 7 | // another public or private blockchain network. This source code is provided ‘as is’ and no 8 | // warranties are given as to title or non-infringement, merchantability or fitness for purpose 9 | // and, to the extent permitted by law, all liability for your use of the code is disclaimed. 10 | import Zilliqa from './zilliqa'; 11 | import * as schnorr from './schnorr'; 12 | import ZNode from './node'; 13 | import * as util from './util'; 14 | 15 | export { 16 | Zilliqa, 17 | ZNode, 18 | schnorr, 19 | util 20 | }; 21 | 22 | if (typeof window !== 'undefined' && typeof window.Zilliqa === 'undefined') { 23 | window.Zilliqa = Zilliqa; 24 | } 25 | -------------------------------------------------------------------------------- /src/node.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Zilliqa 2 | // This source code is being disclosed to you solely for the purpose of your participation in 3 | // testing Zilliqa. You may view, compile and run the code for that purpose and pursuant to 4 | // the protocols and algorithms that are programmed into, and intended by, the code. You may 5 | // not do anything else with the code without express permission from Zilliqa Research Pte. Ltd., 6 | // including modifying or publishing the code (or any part of it), and developing or forming 7 | // another public or private blockchain network. This source code is provided ‘as is’ and no 8 | // warranties are given as to title or non-infringement, merchantability or fitness for purpose 9 | // and, to the extent permitted by law, all liability for your use of the code is disclaimed. 10 | import BN from 'bn.js'; 11 | import {validateArgs} from './util'; 12 | import * as util from './util'; 13 | 14 | type callback = (error: any, data: any) => any; 15 | 16 | export default class ZNode { 17 | url: string; 18 | apiUrl: string; 19 | 20 | constructor(args: any) { 21 | validateArgs(args, { 22 | url: [util.isUrl], 23 | }); 24 | 25 | this.url = args.url; 26 | this.apiUrl = 'https://api.zilliqa.com'; 27 | } 28 | 29 | /** 30 | * isConnected 31 | * 32 | * returns network id 33 | * 34 | * @param {callback} cb 35 | */ 36 | isConnected = (cb: callback) => { 37 | rpcAjax(this.url, 'GetNetworkId', [], cb); 38 | }; 39 | 40 | /** 41 | * getNetworkId 42 | * 43 | * alias for isConnected 44 | * 45 | * @param {callback} cb 46 | */ 47 | getNetworkId = (cb: callback) => { 48 | this.isConnected(cb); 49 | }; 50 | 51 | getClientVersion = (cb: callback) => { 52 | rpcAjax(this.url, 'GetClientVersion', [], cb); 53 | }; 54 | 55 | getProtocolVersion = (cb: callback) => { 56 | rpcAjax(this.url, 'GetProtocolVersion', [], cb); 57 | }; 58 | 59 | createTransaction = (args, cb) => { 60 | try { 61 | validateArgs(args, { 62 | to: [util.isAddress], 63 | pubKey: [util.isPubKey], 64 | amount: [BN.isBN], 65 | gasPrice: [util.isNumber], 66 | gasLimit: [util.isNumber], 67 | }); 68 | } catch (e) { 69 | cb(e); 70 | return; 71 | } 72 | 73 | rpcAjax( 74 | this.url, 75 | 'CreateTransaction', 76 | // FIXME: core must be able to parse amount as string; it currently does 77 | // not. the issue is being tracked here: https://github.com/Zilliqa/Zilliqa/issues/524 78 | {...args, amount: args.amount.toNumber()}, 79 | cb, 80 | ); 81 | }; 82 | 83 | getTransaction = (args, cb) => { 84 | try { 85 | validateArgs(args, { 86 | txHash: [util.isHash], 87 | }); 88 | } catch (e) { 89 | cb(e); 90 | return; 91 | } 92 | 93 | rpcAjax(this.url, 'GetTransaction', args.txHash, cb); 94 | }; 95 | 96 | getDsBlock = (args, cb) => { 97 | rpcAjax(this.url, 'GetDsBlock', args.blockNumber, cb); 98 | }; 99 | 100 | getTxBlock = (args, cb) => { 101 | rpcAjax(this.url, 'GetTxBlock', args.blockNumber, cb); 102 | }; 103 | 104 | getLatestDsBlock = cb => { 105 | rpcAjax(this.url, 'GetLatestDsBlock', '', cb); 106 | }; 107 | 108 | getLatestTxBlock = cb => { 109 | rpcAjax(this.url, 'GetLatestTxBlock', '', cb); 110 | }; 111 | 112 | getBalance = (args, cb) => { 113 | try { 114 | validateArgs(args, { 115 | address: [util.isAddress], 116 | }); 117 | } catch (e) { 118 | cb(e); 119 | return; 120 | } 121 | 122 | rpcAjax(this.url, 'GetBalance', args.address, cb); 123 | }; 124 | 125 | getGasPrice = cb => { 126 | rpcAjax(this.url, 'GetGasPrice', '', cb); 127 | }; 128 | 129 | getSmartContractState = (args, cb) => { 130 | try { 131 | validateArgs(args, { 132 | address: [util.isAddress], 133 | }); 134 | } catch (e) { 135 | cb(e); 136 | return; 137 | } 138 | 139 | rpcAjax(this.url, 'GetSmartContractState', args.address, cb); 140 | }; 141 | 142 | getSmartContractCode = (args, cb) => { 143 | try { 144 | validateArgs(args, { 145 | address: [util.isAddress], 146 | }); 147 | } catch (e) { 148 | cb(e); 149 | return; 150 | } 151 | 152 | rpcAjax(this.url, 'GetSmartContractCode', args.address, cb); 153 | }; 154 | 155 | getSmartContractInit = (args, cb) => { 156 | try { 157 | validateArgs(args, { 158 | address: [util.isAddress], 159 | }); 160 | } catch (e) { 161 | cb(e); 162 | return; 163 | } 164 | 165 | rpcAjax(this.url, 'GetSmartContractInit', args.address, cb); 166 | }; 167 | 168 | getSmartContracts = (args, cb) => { 169 | try { 170 | validateArgs(args, { 171 | address: [util.isAddress], 172 | }); 173 | } catch (e) { 174 | cb(e); 175 | return; 176 | } 177 | 178 | rpcAjax(this.url, 'GetSmartContracts', args.address, cb); 179 | }; 180 | 181 | getTransactionHistory = (args, cb) => { 182 | try { 183 | validateArgs(args, { 184 | address: [util.isAddress], 185 | }); 186 | } catch (e) { 187 | cb(e); 188 | return; 189 | } 190 | 191 | rpcAjax(this.url, 'GetTransactionHistory', args.address, cb); 192 | }; 193 | 194 | getBlockTransactionCount = (args, cb) => { 195 | try { 196 | validateArgs(args, { 197 | blockNumber: [util.isNumber], 198 | }); 199 | } catch (e) { 200 | cb(e); 201 | return; 202 | } 203 | 204 | rpcAjax(this.url, 'GetBlockTransactionCount', args.blockNumber, cb); 205 | }; 206 | 207 | getCode = (args, cb) => { 208 | try { 209 | validateArgs(args, { 210 | address: [util.isAddress], 211 | }); 212 | } catch (e) { 213 | cb(e); 214 | return; 215 | } 216 | 217 | rpcAjax(this.url, 'GetCode', args.address, cb); 218 | }; 219 | 220 | createMessage = (args, cb) => { 221 | try { 222 | validateArgs( 223 | { 224 | to: [util.isAddress], 225 | }, 226 | { 227 | from: [util.isAddress], 228 | gas: [util.isNumber], 229 | gasPrice: [util.isNumber], 230 | }, 231 | ); 232 | } catch (e) { 233 | cb(e); 234 | return; 235 | } 236 | 237 | rpcAjax(this.url, 'CreateMessage', args, cb); 238 | }; 239 | 240 | getGasEstimate = (args, cb) => { 241 | try { 242 | validateArgs( 243 | {}, 244 | { 245 | to: [util.isAddress], 246 | from: [util.isAddress], 247 | gas: [util.isNumber], 248 | gasPrice: [util.isNumber], 249 | gasLimit: [util.isNumber], 250 | }, 251 | ); 252 | } catch (e) { 253 | cb(e); 254 | return; 255 | } 256 | 257 | rpcAjax(this.url, 'GetGasEstimate', args, cb); 258 | }; 259 | 260 | getTransactionReceipt = (args, cb) => { 261 | try { 262 | validateArgs(args, { 263 | txHash: [util.isHash], 264 | }); 265 | } catch (e) { 266 | cb(e); 267 | return; 268 | } 269 | 270 | rpcAjax(this.url, 'GetTransactionReceipt', args.txHash, cb); 271 | }; 272 | 273 | getHashrate = cb => { 274 | rpcAjax(this.url, 'GetHashrate', '', cb); 275 | }; 276 | 277 | isNodeMining = (args, cb) => { 278 | rpcAjax(this.url, 'isNodeMining', '', cb); 279 | }; 280 | 281 | compileCode = (args, cb) => { 282 | try { 283 | validateArgs(args, { 284 | code: [util.isString], 285 | }); 286 | } catch (e) { 287 | cb(e); 288 | return; 289 | } 290 | 291 | rpcAjax(this.url, 'CompileCode', args, cb); 292 | }; 293 | 294 | checkCode = (args, cb) => { 295 | try { 296 | validateArgs(args, { 297 | code: [util.isString], 298 | }); 299 | } catch (e) { 300 | cb(e); 301 | return; 302 | } 303 | 304 | serverAjax(this.apiUrl + '/v1/checker', args, cb); 305 | }; 306 | 307 | checkCodeTest = (args, cb) => { 308 | try { 309 | validateArgs(args, { 310 | code: [util.isString], 311 | }); 312 | } catch (e) { 313 | cb(e); 314 | return; 315 | } 316 | 317 | serverAjax(this.apiUrl + '/v1/runner', args, cb); 318 | }; 319 | 320 | // Explorer APIs 321 | getBlockchainInfo = (args, cb) => { 322 | rpcAjax(this.url, 'GetBlockchainInfo', '', cb); 323 | }; 324 | 325 | getDSBlockListing = (args, cb) => { 326 | try { 327 | validateArgs(args, { 328 | page: [util.isNumber], 329 | }); 330 | } catch (e) { 331 | cb(e); 332 | return; 333 | } 334 | 335 | rpcAjax(this.url, 'DSBlockListing', args.page, cb); 336 | }; 337 | 338 | getTxBlockListing = (args, cb) => { 339 | try { 340 | validateArgs(args, { 341 | page: [util.isNumber], 342 | }); 343 | } catch (e) { 344 | cb(e); 345 | return; 346 | } 347 | 348 | rpcAjax(this.url, 'TxBlockListing', args.page, cb); 349 | }; 350 | 351 | getNumTxnsTxEpoch = (args, cb) => { 352 | rpcAjax(this.url, 'GetNumTxnsTxEpoch', '', cb); 353 | }; 354 | 355 | getNumTxnsDSEpoch = (args, cb) => { 356 | rpcAjax(this.url, 'GetNumTxnsDSEpoch', '', cb); 357 | }; 358 | 359 | getTransactionListing = (args, cb) => { 360 | rpcAjax(this.url, 'GetRecentTransactions', '', cb); 361 | }; 362 | } 363 | 364 | function rpcAjax(url, method, params, cb) { 365 | postData(url, { 366 | jsonrpc: '2.0', 367 | method: method, 368 | params: [params], 369 | id: 1, 370 | }) 371 | .then(data => cb(null, data)) 372 | .catch(error => cb(error)); 373 | } 374 | 375 | function serverAjax(url, data, cb) { 376 | postData(url, data) 377 | .then(data => cb(null, data)) 378 | .catch(error => cb(error)); 379 | } 380 | 381 | function postData(url, data) { 382 | return fetch(url, { 383 | body: JSON.stringify(data), 384 | cache: 'no-cache', 385 | headers: { 386 | 'content-type': 'application/json', 387 | }, 388 | method: 'POST', 389 | mode: 'cors', 390 | redirect: 'follow', 391 | referrer: 'no-referrer', 392 | }).then(response => response.json()); 393 | } 394 | -------------------------------------------------------------------------------- /src/schnorr.ts: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2018 Zilliqa 3 | * This source code is being disclosed to you solely for the purpose of your participation in 4 | * testing Zilliqa. You may view, compile and run the code for that purpose and pursuant to 5 | * the protocols and algorithms that are programmed into, and intended by, the code. You may 6 | * not do anything else with the code without express permission from Zilliqa Research Pte. Ltd., 7 | * including modifying or publishing the code (or any part of it), and developing or forming 8 | * another public or private blockchain network. This source code is provided ‘as is’ and no 9 | * warranties are given as to title or non-infringement, merchantability or fitness for purpose 10 | * and, to the extent permitted by law, all liability for your use of the code is disclaimed. 11 | * Some programs in this code are governed by the GNU General Public License v3.0 (available at 12 | * https://www.gnu.org/licenses/gpl-3.0.en.html) (‘GPLv3’). The programs that are governed by 13 | * GPLv3.0 are those programs that are located in the folders src/depends and tests/depends 14 | * and which include a reference to GPLv3 in their program files. 15 | * 16 | * This implementation of Schnorr is modified from the following 17 | * schnorr.js - schnorr signatures for bcoin 18 | * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License). 19 | * https://github.com/bcoin-org/bcoin 20 | */ 21 | import assert from 'bsert'; 22 | import elliptic from 'elliptic'; 23 | import BN from 'bn.js'; 24 | import hashjs from 'hash.js'; 25 | import DRBG from 'hmac-drbg'; 26 | import Signature from 'elliptic/lib/elliptic/ec/signature'; 27 | 28 | const curve = elliptic.ec('secp256k1').curve; 29 | // Public key is a point (x, y) on the curve. 30 | // Each coordinate requires 32 bytes. 31 | // In its compressed form it suffices to store the x co-ordinate 32 | // and the sign for y. 33 | // Hence a total of 33 bytes. 34 | const PUBKEY_COMPRESSED_SIZE_BYTES = 33; 35 | 36 | /** 37 | * Hash (r | M). 38 | * @param {Buffer} msg 39 | * @param {BN} r 40 | * 41 | * @returns {Buffer} 42 | */ 43 | 44 | export const hash = (q: BN, pubkey: Buffer, msg: Buffer) => { 45 | const sha256 = hashjs.sha256(); 46 | const totalLength = PUBKEY_COMPRESSED_SIZE_BYTES * 2 + msg.byteLength; // 33 q + 33 pubkey + variable msgLen 47 | const Q = q.toArrayLike(Buffer, 'be', 33); 48 | const B = Buffer.allocUnsafe(totalLength); 49 | 50 | Q.copy(B, 0); 51 | pubkey.copy(B, 33); 52 | msg.copy(B, 66); 53 | 54 | return new BN(sha256.update(B).digest('hex'), 16); 55 | }; 56 | 57 | /** 58 | * sign 59 | * 60 | * @param {Buffer} msg 61 | * @param {Buffer} key 62 | * @param {Buffer} pubkey 63 | * @param {Buffer} pubNonce? 64 | * 65 | * @returns {Signature} 66 | */ 67 | export const sign = ( 68 | msg: Buffer, 69 | key: Buffer, 70 | pubkey: Buffer, 71 | pubNonce?: Buffer, 72 | ): Signature => { 73 | const prv = new BN(key); 74 | const drbg = getDRBG(msg, key, pubNonce); 75 | const len = curve.n.byteLength(); 76 | 77 | let pn; 78 | if (pubNonce) pn = curve.decodePoint(pubNonce); 79 | 80 | let sig; 81 | while (!sig) { 82 | const k = new BN(drbg.generate(len)); 83 | sig = trySign(msg, prv, k, pn, pubkey); 84 | } 85 | 86 | return sig; 87 | }; 88 | 89 | /** 90 | * trySign 91 | * 92 | * @param {Buffer} msg 93 | * @param {BN} prv - private key 94 | * @param {BN} k - DRBG-generated random number 95 | * @param {Buffer} pn - optional 96 | * @param {Buffer)} pubKey - public key 97 | * 98 | * @returns {Signature | null =>} 99 | */ 100 | export const trySign = ( 101 | msg: Buffer, 102 | prv: BN, 103 | k: BN, 104 | pn: Buffer, 105 | pubKey: Buffer, 106 | ): Signature | null => { 107 | if (prv.isZero()) throw new Error('Bad private key.'); 108 | 109 | if (prv.gte(curve.n)) throw new Error('Bad private key.'); 110 | 111 | // 1a. check that k is not 0 112 | if (k.isZero()) return null; 113 | // 1b. check that k is < the order of the group 114 | if (k.gte(curve.n)) return null; 115 | 116 | // 2. Compute commitment Q = kG, where g is the base point 117 | const Q = curve.g.mul(k); 118 | // convert the commitment to octets first 119 | const compressedQ = new BN(Q.encodeCompressed()); 120 | 121 | // 3. Compute the challenge r = H(Q || pubKey || msg) 122 | const r = hash(compressedQ, pubKey, msg); 123 | const h = r.clone(); 124 | 125 | if (h.isZero()) return null; 126 | 127 | if (h.eq(curve.n)) return null; 128 | 129 | // 4. Compute s = k - r * prv 130 | // 4a. Compute r * prv 131 | let s = h.imul(prv); 132 | // 4b. Compute s = k - r * prv mod n 133 | s = k.isub(s); 134 | s = s.umod(curve.n); 135 | 136 | if (s.isZero()) return null; 137 | 138 | return new Signature({r, s}); 139 | }; 140 | 141 | /** 142 | * Verify signature. 143 | * 144 | * @param {Buffer} msg 145 | * @param {Buffer} signature 146 | * @param {Buffer} key 147 | * 148 | * @returns {boolean} 149 | * 150 | * 1. Check if r,s is in [1, ..., order-1] 151 | * 2. Compute Q = sG + r*kpub 152 | * 3. If Q = O (the neutral point), return 0; 153 | * 4. r' = H(Q, kpub, m) 154 | * 5. return r' == r 155 | */ 156 | export const verify = (msg: Buffer, signature: Signature, key: Buffer) => { 157 | const sig = new Signature(signature); 158 | 159 | if (sig.s.gte(curve.n)) throw new Error('Invalid S value.'); 160 | 161 | if (sig.r.gt(curve.n)) throw new Error('Invalid R value.'); 162 | 163 | const kpub = curve.decodePoint(key); 164 | const l = kpub.mul(sig.r); 165 | const r = curve.g.mul(sig.s); 166 | 167 | const Q = l.add(r); 168 | const compressedQ = new BN(Q.encodeCompressed()); 169 | 170 | const r1 = hash(compressedQ, key, msg); 171 | 172 | if (r1.gte(curve.n)) throw new Error('Invalid hash.'); 173 | 174 | if (r1.isZero()) throw new Error('Invalid hash.'); 175 | 176 | return r1.eq(sig.r); 177 | }; 178 | 179 | /** 180 | * Schnorr personalization string. 181 | * @const {Buffer} 182 | */ 183 | export const alg = Buffer.from('Schnorr+SHA256 ', 'ascii'); 184 | 185 | /** 186 | * Instantiate an HMAC-DRBG. 187 | * 188 | * @param {Buffer} msg 189 | * @param {Buffer} priv - used as entropy input 190 | * @param {Buffer} data - used as nonce 191 | * 192 | * @returns {DRBG} 193 | */ 194 | export const getDRBG = (msg: Buffer, priv: Buffer, data?: Buffer) => { 195 | const pers = Buffer.allocUnsafe(48); 196 | 197 | pers.fill(0); 198 | 199 | if (data) { 200 | assert(data.length === 32); 201 | data.copy(pers, 0); 202 | } 203 | 204 | alg.copy(pers, 32); 205 | 206 | return new DRBG({ 207 | hash: hashjs.sha256, 208 | entropy: priv, 209 | nonce: msg, 210 | pers, 211 | }); 212 | }; 213 | 214 | /** 215 | * Generate pub+priv nonce pair. 216 | * 217 | * @param {Buffer} msg 218 | * @param {Buffer} priv 219 | * @param {Buffer} data 220 | * 221 | * @returns {Buffer} 222 | */ 223 | export const generateNoncePair = (msg: Buffer, priv: Buffer, data: Buffer) => { 224 | const drbg = getDRBG(msg, priv, data); 225 | const len = curve.n.byteLength(); 226 | 227 | let k = new BN(drbg.generate(len)); 228 | 229 | while (k.isZero() && k.gte(curve.n)) { 230 | k = new BN(drbg.generate(len)); 231 | } 232 | 233 | return Buffer.from(curve.g.mul(k).encode('array', true)); 234 | }; 235 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Zilliqa 2 | // This source code is being disclosed to you solely for the purpose of your participation in 3 | // testing Zilliqa. You may view, compile and run the code for that purpose and pursuant to 4 | // the protocols and algorithms that are programmed into, and intended by, the code. You may 5 | // not do anything else with the code without express permission from Zilliqa Research Pte. Ltd., 6 | // including modifying or publishing the code (or any part of it), and developing or forming 7 | // another public or private blockchain network. This source code is provided ‘as is’ and no 8 | // warranties are given as to title or non-infringement, merchantability or fitness for purpose 9 | // and, to the extent permitted by law, all liability for your use of the code is disclaimed. 10 | import BN from 'bn.js'; 11 | 12 | export interface TxDetails { 13 | version: number; 14 | nonce: number; 15 | to: string; 16 | amount: BN; 17 | pubKey: string; 18 | gasPrice: number; 19 | gasLimit: number; 20 | code: string; 21 | data: string; 22 | signature?: string; 23 | } 24 | -------------------------------------------------------------------------------- /src/util.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Zilliqa 2 | // This source code is being disclosed to you solely for the purpose of your participation in 3 | // testing Zilliqa. You may view, compile and run the code for that purpose and pursuant to 4 | // the protocols and algorithms that are programmed into, and intended by, the code. You may 5 | // not do anything else with the code without express permission from Zilliqa Research Pte. Ltd., 6 | // including modifying or publishing the code (or any part of it), and developing or forming 7 | // another public or private blockchain network. This source code is provided ‘as is’ and no 8 | // warranties are given as to title or non-infringement, merchantability or fitness for purpose 9 | // and, to the extent permitted by law, all liability for your use of the code is disclaimed. 10 | import randomBytes from 'randombytes'; 11 | import elliptic from 'elliptic'; 12 | import hashjs from 'hash.js'; 13 | import { isWebUri } from 'valid-url'; 14 | 15 | import * as schnorr from './schnorr'; 16 | import { TxDetails } from './types'; 17 | 18 | const NUM_BYTES = 32; 19 | //const HEX_PREFIX = '0x'; 20 | 21 | const secp256k1 = elliptic.ec('secp256k1'); 22 | 23 | /** 24 | * generatePrivateKey 25 | * 26 | * @returns {string} - the hex-encoded private key 27 | */ 28 | export const generatePrivateKey = (): string => { 29 | let priv = ''; 30 | const rand = randomBytes(NUM_BYTES); 31 | 32 | for (let i = 0; i < rand.byteLength; i++) { 33 | // add 00 in case we get an empty byte. 34 | const byte = rand[i]; 35 | const hexstr = '00'.concat(byte.toString(16)).slice(-2); 36 | priv += hexstr; 37 | } 38 | 39 | return priv; 40 | }; 41 | 42 | /** 43 | * getAddressFromPrivateKey 44 | * 45 | * takes a hex-encoded string (private key) and returns its corresponding 46 | * 20-byte hex-encoded address. 47 | * 48 | * @param {string} Key 49 | * @returns {string} 50 | */ 51 | export const getAddressFromPrivateKey = (privateKey: string) => { 52 | const keyPair = secp256k1.keyFromPrivate(privateKey, 'hex'); 53 | const pub = keyPair.getPublic(true, 'hex'); 54 | 55 | return hashjs 56 | .sha256() 57 | .update(pub, 'hex') 58 | .digest('hex') 59 | .slice(24); 60 | }; 61 | 62 | /** 63 | * getPubKeyFromPrivateKey 64 | * 65 | * takes a hex-encoded string (private key) and returns its corresponding 66 | * hex-encoded 33-byte public key. 67 | * 68 | * @param {string} privateKey 69 | * @returns {string} 70 | */ 71 | export const getPubKeyFromPrivateKey = (privateKey: string) => { 72 | const keyPair = secp256k1.keyFromPrivate(privateKey, 'hex'); 73 | return keyPair.getPublic(true, 'hex'); 74 | }; 75 | 76 | /** 77 | * compressPublicKey 78 | * 79 | * @param {string} publicKey - 65-byte public key, a point (x, y) 80 | * 81 | * @returns {string} 82 | */ 83 | export const compressPublicKey = (publicKey: string): string => { 84 | return secp256k1.keyFromPublic(publicKey, 'hex').getPublic(true, 'hex'); 85 | }; 86 | 87 | /** 88 | * getAddressFromPublicKey 89 | * 90 | * takes hex-encoded string and returns the corresponding address 91 | * 92 | * @param {string} pubKey 93 | * @returns {string} 94 | */ 95 | export const getAddressFromPublicKey = (pubKey: string) => { 96 | return hashjs 97 | .sha256() 98 | .update(pubKey, 'hex') 99 | .digest('hex') 100 | .slice(24); 101 | }; 102 | 103 | /** 104 | * verifyPrivateKey 105 | * 106 | * @param {string|Buffer} privateKey 107 | * @returns {boolean} 108 | */ 109 | export const verifyPrivateKey = (privateKey: string): boolean => { 110 | const keyPair = secp256k1.keyFromPrivate(privateKey, 'hex'); 111 | const { result } = keyPair.validate(); 112 | return result; 113 | }; 114 | 115 | /** 116 | * encodeTransaction 117 | * 118 | * @param {any} txn 119 | * @returns {Buffer} 120 | */ 121 | export const encodeTransaction = (txn: TxDetails) => { 122 | let codeHex = Buffer.from(txn.code).toString('hex'); 123 | let dataHex = Buffer.from(txn.data).toString('hex'); 124 | 125 | let encoded = 126 | intToByteArray(txn.version, 64).join('') + 127 | intToByteArray(txn.nonce, 64).join('') + 128 | txn.to + 129 | txn.pubKey + 130 | txn.amount.toString('hex', 64) + 131 | intToByteArray(txn.gasPrice, 64).join('') + 132 | intToByteArray(txn.gasLimit, 64).join('') + 133 | intToByteArray(txn.code.length, 8).join('') + // size of code 134 | codeHex + 135 | intToByteArray(txn.data.length, 8).join('') + // size of data 136 | dataHex; 137 | 138 | return Buffer.from(encoded, 'hex'); 139 | }; 140 | 141 | /** 142 | * createTransactionJson 143 | * 144 | * @param {string} privateKey 145 | * @param {TxDetails} txnDetails 146 | * @param {TxDetails} 147 | * 148 | * @returns {TxDetails} 149 | */ 150 | export const createTransactionJson = ( 151 | privateKey: string, 152 | txnDetails: TxDetails, 153 | ): TxDetails => { 154 | const pubKey = getPubKeyFromPrivateKey(privateKey); 155 | 156 | const txn = { 157 | version: txnDetails.version, 158 | nonce: txnDetails.nonce, 159 | to: txnDetails.to, 160 | amount: txnDetails.amount, 161 | pubKey, 162 | gasPrice: txnDetails.gasPrice, 163 | gasLimit: txnDetails.gasLimit, 164 | code: txnDetails.code || '', 165 | data: txnDetails.data || '', 166 | }; 167 | 168 | const encodedTx = encodeTransaction(txn); 169 | 170 | // sign using schnorr lib 171 | const sig = schnorr.sign( 172 | encodedTx, 173 | Buffer.from(privateKey, 'hex'), 174 | Buffer.from(pubKey, 'hex'), 175 | ); 176 | 177 | let r = sig.r.toString('hex'); 178 | let s = sig.s.toString('hex'); 179 | while (r.length < 64) { 180 | r = '0' + r; 181 | } 182 | while (s.length < 64) { 183 | s = '0' + s; 184 | } 185 | 186 | txn['signature'] = r + s; 187 | 188 | return txn; 189 | }; 190 | 191 | interface ValidatorDictionary { 192 | [key: string]: Array<(...args: any[]) => any>; 193 | } 194 | 195 | // make sure each of the keys in requiredArgs is present in args 196 | // and each of it's validator functions return true 197 | export const validateArgs = ( 198 | args: { [key: string]: any }, 199 | requiredArgs: ValidatorDictionary, 200 | optionalArgs?: ValidatorDictionary, 201 | ) => { 202 | for (var key in requiredArgs) { 203 | if (args[key] === undefined) throw new Error('Key not found: ' + key); 204 | 205 | for (var i = 0; i < requiredArgs[key].length; i++) { 206 | if (typeof requiredArgs[key][i] !== 'function') 207 | throw new Error('Validator is not a function'); 208 | 209 | if (!requiredArgs[key][i](args[key])) 210 | throw new Error('Validation failed for ' + key); 211 | } 212 | } 213 | 214 | if (optionalArgs) { 215 | for (var key in optionalArgs) { 216 | if (args[key]) { 217 | for (var i = 0; i < optionalArgs[key].length; i++) { 218 | if (typeof optionalArgs[key][i] !== 'function') 219 | throw new Error('Validator is not a function'); 220 | 221 | if (!optionalArgs[key][i](args[key])) 222 | throw new Error('Validation failed for ' + key); 223 | } 224 | } 225 | } 226 | } 227 | 228 | return true; 229 | }; 230 | 231 | export const isAddress = (address: string) => { 232 | return !!address.match(/^[0-9a-fA-F]{40}$/); 233 | }; 234 | 235 | export const isPrivateKey = (privateKey: string) => { 236 | return !!privateKey.match(/^[0-9a-fA-F]{64}$/); 237 | }; 238 | 239 | export const isPubKey = (pubKey: string) => { 240 | return !!pubKey.match(/^[0-9a-fA-F]{66}$/); 241 | }; 242 | 243 | export const isUrl = url => { 244 | return isWebUri(url); 245 | }; 246 | 247 | export const isHash = (txHash: string) => { 248 | return !!txHash.match(/^[0-9a-fA-F]{64}$/); 249 | }; 250 | 251 | export const isNumber = (number: any) => { 252 | return typeof number === 'number'; 253 | }; 254 | 255 | export const isString = (string: any) => { 256 | return typeof string === 'string'; 257 | }; 258 | 259 | // convert number to array representing the padded hex form 260 | export const intToByteArray = (val: number, paddedSize: number) => { 261 | const arr: string[] = []; 262 | 263 | let hexVal = val.toString(16); 264 | let hexRep: string[] = []; 265 | 266 | for (let i = 0; i < hexVal.length; i++) { 267 | hexRep[i] = hexVal[i].toString(); 268 | } 269 | 270 | for (let i = 0; i < paddedSize - hexVal.length; i++) { 271 | arr.push('0'); 272 | } 273 | 274 | for (let i = 0; i < hexVal.length; i++) { 275 | arr.push(hexRep[i]); 276 | } 277 | 278 | return arr; 279 | }; 280 | 281 | /** 282 | * toChecksumAddress 283 | * 284 | * takes hex-encoded string and returns the corresponding address 285 | * 286 | * @param {string} address 287 | * @returns {string} 288 | */ 289 | export const toChecksumAddress = (address: string): string => { 290 | 291 | address = address.toLowerCase().replace('0x', ''); 292 | const hash = hashjs.sha256().update(address, 'hex').digest('hex'); 293 | let ret = '0x'; 294 | for (let i = 0; i < address.length; i++) { 295 | if (parseInt(hash[i], 16) >= 8) { 296 | ret += address[i].toUpperCase(); 297 | } else { 298 | ret += address[i]; 299 | } 300 | } 301 | return ret; 302 | }; 303 | 304 | /** 305 | * isValidChecksumAddress 306 | * 307 | * takes hex-encoded string and returns boolean if address is checksumed 308 | * 309 | * @param {string} address 310 | * @returns {boolean} 311 | */ 312 | export const isValidChecksumAddress = (address: string): boolean => { 313 | return (isAddress(address.replace('0x', '')) && toChecksumAddress(address) === address); 314 | }; 315 | -------------------------------------------------------------------------------- /src/zilliqa.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Zilliqa 2 | // This source code is being disclosed to you solely for the purpose of your participation in 3 | // testing Zilliqa. You may view, compile and run the code for that purpose and pursuant to 4 | // the protocols and algorithms that are programmed into, and intended by, the code. You may 5 | // not do anything else with the code without express permission from Zilliqa Research Pte. Ltd., 6 | // including modifying or publishing the code (or any part of it), and developing or forming 7 | // another public or private blockchain network. This source code is provided ‘as is’ and no 8 | // warranties are given as to title or non-infringement, merchantability or fitness for purpose 9 | // and, to the extent permitted by law, all liability for your use of the code is disclaimed. 10 | import Znode from './node'; 11 | import {validateArgs} from './util'; 12 | import * as util from './util'; 13 | import config from './config.json'; 14 | 15 | interface Options { 16 | nodeUrl: string; 17 | } 18 | 19 | export default class Zilliqa { 20 | data: {[key: string]: any}; 21 | version: string; 22 | node: Znode; 23 | util: Partial; 24 | 25 | constructor(options: Options) { 26 | this.data = {}; 27 | this.node = new Znode({url: options.nodeUrl || config.defaultNodeUrl}); 28 | this.util = { 29 | generatePrivateKey: util.generatePrivateKey, 30 | verifyPrivateKey: util.verifyPrivateKey, 31 | getAddressFromPrivateKey: util.getAddressFromPrivateKey, 32 | getPubKeyFromPrivateKey: util.getPubKeyFromPrivateKey, 33 | createTransactionJson: util.createTransactionJson, 34 | getAddressFromPublicKey: util.getAddressFromPublicKey, 35 | isAddress: util.isAddress, 36 | isPubKey: util.isPubKey, 37 | intToByteArray: util.intToByteArray, 38 | compressPublicKey: util.compressPublicKey, 39 | isPrivateKey: util.isPrivateKey, 40 | toChecksumAddress: util.toChecksumAddress, 41 | isValidChecksumAddress: util.isValidChecksumAddress, 42 | 43 | }; 44 | 45 | this.version = config.version; 46 | } 47 | 48 | // library methods 49 | getLibraryVersion = () => { 50 | return this.version; 51 | }; 52 | 53 | getNode = () => { 54 | return this.node; 55 | }; 56 | 57 | setNode = (options: Options) => { 58 | validateArgs(options, { 59 | nodeUrl: [util.isUrl], 60 | }); 61 | 62 | this.node = new Znode({url: options.nodeUrl || config.defaultNodeUrl}); 63 | return null; 64 | }; 65 | } 66 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "esModuleInterop": true, 4 | "outDir": "dist", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "lib": ["es2015", "es2016", "es2017", "dom"], 8 | "sourceMap": true, 9 | "resolveJsonModule": true, 10 | "moduleResolution": "node", 11 | "declaration": true, 12 | "declarationDir": "dist", 13 | "rootDir": "src", 14 | "forceConsistentCasingInFileNames": false, 15 | "noImplicitReturns": true, 16 | "noImplicitThis": true, 17 | "noImplicitAny": false, 18 | "strictNullChecks": true, 19 | "suppressImplicitAnyIndexErrors": true, 20 | "noUnusedLocals": true 21 | }, 22 | "include": [ "src/**/*", "typings/**/*" ] 23 | } 24 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "tslint:latest", 4 | "tslint-config-prettier" 5 | ], 6 | "rules": { 7 | "interface-name": [ 8 | true, 9 | "never-prefix" 10 | ], 11 | "ordered-imports": [false], 12 | "member-access": false, 13 | "no-console": false, 14 | "no-empty-interface": false, 15 | "no-submodule-imports": false, 16 | "object-literal-sort-keys": false, 17 | "object-literal-key-quotes": [ 18 | true, 19 | "as-needed" 20 | ], 21 | "quotemark": [ 22 | true, 23 | "single" 24 | ], 25 | "semicolon": [ 26 | true, 27 | "always", 28 | "ignore-bound-class-methods" 29 | ], 30 | "jsx-boolean-value": false 31 | }, 32 | "linterOptions": { 33 | "exclude": [ 34 | "config/**/*.js", 35 | "node_modules/**/*.ts" 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /typings/bn.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for bn.js 4.11 2 | // Project: https://github.com/indutny/bn.js 3 | // Definitions by: Leonid Logvinov 4 | // Henry Nguyen 5 | // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped 6 | 7 | declare module 'bn.js' { 8 | type Endianness = 'le' | 'be'; 9 | type IPrimeName = 'k256' | 'p224' | 'p192' | 'p25519'; 10 | type ArrayCtor = typeof Array; 11 | type BufferCtor = typeof Buffer; 12 | type ArrayType = ArrayCtor | BufferCtor; 13 | 14 | class RedBN { 15 | redAdd(b: RedBN): RedBN; 16 | redIAdd(b: RedBN): RedBN; 17 | redSub(b: RedBN): RedBN; 18 | redISub(b: RedBN): RedBN; 19 | redShl(num: number): RedBN; 20 | redMul(b: RedBN): RedBN; 21 | redIMul(b: RedBN): RedBN; 22 | redSqr(): RedBN; 23 | redISqr(): RedBN; 24 | /** 25 | * @description square root modulo reduction context's prime 26 | */ 27 | redSqrt(): RedBN; 28 | /** 29 | * @description modular inverse of the number 30 | */ 31 | redInvm(): RedBN; 32 | redNeg(): RedBN; 33 | /** 34 | * @description modular exponentiation 35 | */ 36 | redPow(b: RedBN): RedBN; 37 | fromRed(): BN; 38 | } 39 | 40 | // FIXME: not sure how to specify the reduction context here 41 | interface ReductionContext { 42 | m: number; 43 | prime: any; 44 | [key: string]: any; 45 | } 46 | 47 | class BN { 48 | constructor( 49 | number: number | string | number[] | Buffer | BN, 50 | base?: number, 51 | endian?: Endianness, 52 | ); 53 | 54 | /** 55 | * @description create a reduction context 56 | */ 57 | static red(reductionContext: BN | IPrimeName): ReductionContext; 58 | 59 | /** 60 | * @description create a reduction context with the Montgomery trick. 61 | */ 62 | static mont(num: BN): ReductionContext; 63 | 64 | /** 65 | * @description returns true if the supplied object is a BN.js instance 66 | */ 67 | static isBN(b: any): b is BN; 68 | 69 | /** 70 | * @description Convert number to red 71 | */ 72 | toRed(reductionContext: ReductionContext): RedBN; 73 | 74 | /** 75 | * @description clone number 76 | */ 77 | clone(): BN; 78 | 79 | /** 80 | * @description convert to base-string and pad with zeroes 81 | */ 82 | toString(base?: number | 'hex', length?: number): string; 83 | 84 | /** 85 | * @description convert to Javascript Number (limited to 53 bits) 86 | */ 87 | toNumber(): number; 88 | 89 | /** 90 | * @description convert to JSON compatible hex string (alias of toString(16)) 91 | */ 92 | toJSON(): string; 93 | 94 | /** 95 | * @description convert to byte Array, and optionally zero pad to length, throwing if already exceeding 96 | */ 97 | toArray(endian?: Endianness, length?: number): number[]; 98 | 99 | /** 100 | * @description convert to an instance of `type`, which must behave like an Array 101 | */ 102 | toArrayLike( 103 | type: T, 104 | endian?: Endianness, 105 | length?: number, 106 | ): T extends BufferCtor ? Buffer : Array; 107 | 108 | /** 109 | * @description convert to Node.js Buffer (if available). For compatibility with browserify and similar tools, use this instead: a.toArrayLike(Buffer, endian, length) 110 | */ 111 | toBuffer(endian?: Endianness, length?: number): Buffer; 112 | 113 | /** 114 | * @description get number of bits occupied 115 | */ 116 | bitLength(): number; 117 | 118 | /** 119 | * @description return number of less-significant consequent zero bits (example: 1010000 has 4 zero bits) 120 | */ 121 | zeroBits(): number; 122 | 123 | /** 124 | * @description return number of bytes occupied 125 | */ 126 | byteLength(): number; 127 | 128 | /** 129 | * @description true if the number is negative 130 | */ 131 | isNeg(): boolean; 132 | 133 | /** 134 | * @description check if value is even 135 | */ 136 | isEven(): boolean; 137 | 138 | /** 139 | * @description check if value is odd 140 | */ 141 | isOdd(): boolean; 142 | 143 | /** 144 | * @description check if value is zero 145 | */ 146 | isZero(): boolean; 147 | 148 | /** 149 | * @description compare numbers and return `-1 (a < b)`, `0 (a == b)`, or `1 (a > b)` depending on the comparison result 150 | */ 151 | cmp(b: BN): -1 | 0 | 1; 152 | 153 | /** 154 | * @description compare numbers and return `-1 (a < b)`, `0 (a == b)`, or `1 (a > b)` depending on the comparison result 155 | */ 156 | ucmp(b: BN): -1 | 0 | 1; 157 | 158 | /** 159 | * @description compare numbers and return `-1 (a < b)`, `0 (a == b)`, or `1 (a > b)` depending on the comparison result 160 | */ 161 | cmpn(b: number): -1 | 0 | 1; 162 | 163 | /** 164 | * @description a less than b 165 | */ 166 | lt(b: BN): boolean; 167 | 168 | /** 169 | * @description a less than b 170 | */ 171 | ltn(b: number): boolean; 172 | 173 | /** 174 | * @description a less than or equals b 175 | */ 176 | lte(b: BN): boolean; 177 | 178 | /** 179 | * @description a less than or equals b 180 | */ 181 | lten(b: number): boolean; 182 | 183 | /** 184 | * @description a greater than b 185 | */ 186 | gt(b: BN): boolean; 187 | 188 | /** 189 | * @description a greater than b 190 | */ 191 | gtn(b: number): boolean; 192 | 193 | /** 194 | * @description a greater than or equals b 195 | */ 196 | gte(b: BN): boolean; 197 | 198 | /** 199 | * @description a greater than or equals b 200 | */ 201 | gten(b: number): boolean; 202 | 203 | /** 204 | * @description a equals b 205 | */ 206 | eq(b: BN): boolean; 207 | 208 | /** 209 | * @description a equals b 210 | */ 211 | eqn(b: number): boolean; 212 | 213 | /** 214 | * @description convert to two's complement representation, where width is bit width 215 | */ 216 | toTwos(width: number): BN; 217 | 218 | /** 219 | * @description convert from two's complement representation, where width is the bit width 220 | */ 221 | fromTwos(width: number): BN; 222 | 223 | /** 224 | * @description negate sign 225 | */ 226 | neg(): BN; 227 | 228 | /** 229 | * @description negate sign 230 | */ 231 | ineg(): BN; 232 | 233 | /** 234 | * @description absolute value 235 | */ 236 | abs(): BN; 237 | 238 | /** 239 | * @description absolute value 240 | */ 241 | iabs(): BN; 242 | 243 | /** 244 | * @description addition 245 | */ 246 | add(b: BN): BN; 247 | 248 | /** 249 | * @description addition 250 | */ 251 | iadd(b: BN): BN; 252 | 253 | /** 254 | * @description addition 255 | */ 256 | addn(b: number): BN; 257 | 258 | /** 259 | * @description addition 260 | */ 261 | iaddn(b: number): BN; 262 | 263 | /** 264 | * @description subtraction 265 | */ 266 | sub(b: BN): BN; 267 | 268 | /** 269 | * @description subtraction 270 | */ 271 | isub(b: BN): BN; 272 | 273 | /** 274 | * @description subtraction 275 | */ 276 | subn(b: number): BN; 277 | 278 | /** 279 | * @description subtraction 280 | */ 281 | isubn(b: number): BN; 282 | 283 | /** 284 | * @description multiply 285 | */ 286 | mul(b: BN): BN; 287 | 288 | /** 289 | * @description multiply 290 | */ 291 | imul(b: BN): BN; 292 | 293 | /** 294 | * @description multiply 295 | */ 296 | muln(b: number): BN; 297 | 298 | /** 299 | * @description multiply 300 | */ 301 | imuln(b: number): BN; 302 | 303 | /** 304 | * @description square 305 | */ 306 | sqr(): BN; 307 | 308 | /** 309 | * @description square 310 | */ 311 | isqr(): BN; 312 | 313 | /** 314 | * @description raise `a` to the power of `b` 315 | */ 316 | pow(b: BN): BN; 317 | 318 | /** 319 | * @description divide 320 | */ 321 | div(b: BN): BN; 322 | 323 | /** 324 | * @description divide 325 | */ 326 | divn(b: number): BN; 327 | 328 | /** 329 | * @description divide 330 | */ 331 | idivn(b: number): BN; 332 | 333 | /** 334 | * @description reduct 335 | */ 336 | mod(b: BN): BN; 337 | 338 | /** 339 | * @description reduct 340 | */ 341 | umod(b: BN): BN; 342 | 343 | /** 344 | * @see API consistency https://github.com/indutny/bn.js/pull/130 345 | * @description reduct 346 | */ 347 | modn(b: number): number; 348 | 349 | /** 350 | * @description rounded division 351 | */ 352 | divRound(b: BN): BN; 353 | 354 | /** 355 | * @description or 356 | */ 357 | or(b: BN): BN; 358 | 359 | /** 360 | * @description or 361 | */ 362 | ior(b: BN): BN; 363 | 364 | /** 365 | * @description or 366 | */ 367 | uor(b: BN): BN; 368 | 369 | /** 370 | * @description or 371 | */ 372 | iuor(b: BN): BN; 373 | 374 | /** 375 | * @description and 376 | */ 377 | and(b: BN): BN; 378 | 379 | /** 380 | * @description and 381 | */ 382 | iand(b: BN): BN; 383 | 384 | /** 385 | * @description and 386 | */ 387 | uand(b: BN): BN; 388 | 389 | /** 390 | * @description and 391 | */ 392 | iuand(b: BN): BN; 393 | 394 | /** 395 | * @description and (NOTE: `andln` is going to be replaced with `andn` in future) 396 | */ 397 | andln(b: number): BN; 398 | 399 | /** 400 | * @description xor 401 | */ 402 | xor(b: BN): BN; 403 | 404 | /** 405 | * @description xor 406 | */ 407 | ixor(b: BN): BN; 408 | 409 | /** 410 | * @description xor 411 | */ 412 | uxor(b: BN): BN; 413 | 414 | /** 415 | * @description xor 416 | */ 417 | iuxor(b: BN): BN; 418 | 419 | /** 420 | * @description set specified bit to 1 421 | */ 422 | setn(b: number): BN; 423 | 424 | /** 425 | * @description shift left 426 | */ 427 | shln(b: number): BN; 428 | 429 | /** 430 | * @description shift left 431 | */ 432 | ishln(b: number): BN; 433 | 434 | /** 435 | * @description shift left 436 | */ 437 | ushln(b: number): BN; 438 | 439 | /** 440 | * @description shift left 441 | */ 442 | iushln(b: number): BN; 443 | 444 | /** 445 | * @description shift right 446 | */ 447 | shrn(b: number): BN; 448 | 449 | /** 450 | * @description shift right (unimplemented https://github.com/indutny/bn.js/blob/master/lib/bn.js#L2086) 451 | */ 452 | ishrn(b: number): BN; 453 | 454 | /** 455 | * @description shift right 456 | */ 457 | ushrn(b: number): BN; 458 | /** 459 | * @description shift right 460 | */ 461 | 462 | iushrn(b: number): BN; 463 | /** 464 | * @description test if specified bit is set 465 | */ 466 | 467 | testn(b: number): boolean; 468 | /** 469 | * @description clear bits with indexes higher or equal to `b` 470 | */ 471 | 472 | maskn(b: number): BN; 473 | /** 474 | * @description clear bits with indexes higher or equal to `b` 475 | */ 476 | 477 | imaskn(b: number): BN; 478 | /** 479 | * @description add `1 << b` to the number 480 | */ 481 | bincn(b: number): BN; 482 | 483 | /** 484 | * @description not (for the width specified by `w`) 485 | */ 486 | notn(w: number): BN; 487 | 488 | /** 489 | * @description not (for the width specified by `w`) 490 | */ 491 | inotn(w: number): BN; 492 | 493 | /** 494 | * @description GCD 495 | */ 496 | gcd(b: BN): BN; 497 | 498 | /** 499 | * @description Extended GCD results `({ a: ..., b: ..., gcd: ... })` 500 | */ 501 | egcd(b: BN): {a: BN; b: BN; gcd: BN}; 502 | 503 | /** 504 | * @description inverse `a` modulo `b` 505 | */ 506 | invm(b: BN): BN; 507 | } 508 | 509 | export = BN; 510 | } 511 | -------------------------------------------------------------------------------- /typings/elliptic.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Zilliqa 2 | // This source code is being disclosed to you solely for the purpose of your participation in 3 | // testing Zilliqa. You may view, compile and run the code for that purpose and pursuant to 4 | // the protocols and algorithms that are programmed into, and intended by, the code. You may 5 | // not do anything else with the code without express permission from Zilliqa Research Pte. Ltd., 6 | // including modifying or publishing the code (or any part of it), and developing or forming 7 | // another public or private blockchain network. This source code is provided ‘as is’ and no 8 | // warranties are given as to title or non-infringement, merchantability or fitness for purpose 9 | // and, to the extent permitted by law, all liability for your use of the code is disclaimed. 10 | declare module 'elliptic' { 11 | import BN from 'bn.js'; 12 | 13 | namespace elliptic { 14 | type CurveTypes = 'short' | 'edwards' | 'mont'; 15 | type PrivateKey = 16 | | string 17 | | Buffer 18 | | {x: Buffer; y: Buffer} 19 | | {x: string; y: string}; 20 | 21 | interface Curve { 22 | type: CurveTypes; 23 | n: BN; 24 | g: Point; 25 | decodePoint(msg: Buffer | Array | string, enc?: string): Point; 26 | } 27 | 28 | interface Point { 29 | x: BN; 30 | y: BN; 31 | inf: boolean; 32 | encode(enc: string, compressed?: boolean): Array; 33 | encodeCompressed(enc?: string): Array; 34 | add(k: BN | Number | Point): Point; 35 | mul(k: BN | Number | Point): Point; 36 | } 37 | 38 | interface EC { 39 | curve: Curve; 40 | keyFromPrivate(priv: string, enc: string): KeyPair; 41 | keyFromPublic(pub: string, enc: string): KeyPair; 42 | } 43 | 44 | interface KeyPair { 45 | fromPublic(ec: Curve, pub: BN, enc: string): KeyPair; 46 | fromPrivate(ec: Curve, priv: BN, enc: string): KeyPair; 47 | // this is broken, but we can't fix it without changing the upstream 48 | // library; compact is optional, but optional parameters should always 49 | // _follow_ mandatory ones. 50 | getPublic(compact: boolean, enc: string): string; 51 | getPrivate(enc: string): Array; 52 | validate(): { result: boolean; reason: string | null }; 53 | } 54 | 55 | export function ec(curve: string): EC; 56 | } 57 | 58 | export = elliptic; 59 | } 60 | -------------------------------------------------------------------------------- /typings/json.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Zilliqa 2 | // This source code is being disclosed to you solely for the purpose of your participation in 3 | // testing Zilliqa. You may view, compile and run the code for that purpose and pursuant to 4 | // the protocols and algorithms that are programmed into, and intended by, the code. You may 5 | // not do anything else with the code without express permission from Zilliqa Research Pte. Ltd., 6 | // including modifying or publishing the code (or any part of it), and developing or forming 7 | // another public or private blockchain network. This source code is provided ‘as is’ and no 8 | // warranties are given as to title or non-infringement, merchantability or fitness for purpose 9 | // and, to the extent permitted by law, all liability for your use of the code is disclaimed. 10 | declare module '*.json' { 11 | var exported: any; 12 | export = exported; 13 | } 14 | -------------------------------------------------------------------------------- /typings/signature.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Zilliqa 2 | // This source code is being disclosed to you solely for the purpose of your participation in 3 | // testing Zilliqa. You may view, compile and run the code for that purpose and pursuant to 4 | // the protocols and algorithms that are programmed into, and intended by, the code. You may 5 | // not do anything else with the code without express permission from Zilliqa Research Pte. Ltd., 6 | // including modifying or publishing the code (or any part of it), and developing or forming 7 | // another public or private blockchain network. This source code is provided ‘as is’ and no 8 | // warranties are given as to title or non-infringement, merchantability or fitness for purpose 9 | // and, to the extent permitted by law, all liability for your use of the code is disclaimed. 10 | declare module 'elliptic/lib/elliptic/ec/signature' { 11 | import BN from 'bn.js'; 12 | 13 | interface Options { 14 | r: string | BN; 15 | s: string | BN; 16 | } 17 | 18 | interface Signature { 19 | r: BN; 20 | s: BN; 21 | } 22 | 23 | var Signature: { 24 | new(opt: Options): Signature; 25 | new(data: Buffer): Signature; 26 | }; 27 | 28 | export = Signature; 29 | } 30 | -------------------------------------------------------------------------------- /typings/window.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Zilliqa 2 | // This source code is being disclosed to you solely for the purpose of your participation in 3 | // testing Zilliqa. You may view, compile and run the code for that purpose and pursuant to 4 | // the protocols and algorithms that are programmed into, and intended by, the code. You may 5 | // not do anything else with the code without express permission from Zilliqa Research Pte. Ltd., 6 | // including modifying or publishing the code (or any part of it), and developing or forming 7 | // another public or private blockchain network. This source code is provided ‘as is’ and no 8 | // warranties are given as to title or non-infringement, merchantability or fitness for purpose 9 | // and, to the extent permitted by law, all liability for your use of the code is disclaimed. 10 | import Zilliqa from '../src/zilliqa'; 11 | 12 | declare global { 13 | interface Window { 14 | Zilliqa: typeof Zilliqa; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Zilliqa 2 | // This source code is being disclosed to you solely for the purpose of your participation in 3 | // testing Zilliqa. You may view, compile and run the code for that purpose and pursuant to 4 | // the protocols and algorithms that are programmed into, and intended by, the code. You may 5 | // not do anything else with the code without express permission from Zilliqa Research Pte. Ltd., 6 | // including modifying or publishing the code (or any part of it), and developing or forming 7 | // another public or private blockchain network. This source code is provided ‘as is’ and no 8 | // warranties are given as to title or non-infringement, merchantability or fitness for purpose 9 | // and, to the extent permitted by law, all liability for your use of the code is disclaimed. 10 | // Base webpack configuration - to be used in ALL environments. 11 | /* eslint import/no-extraneous-dependencies: ["error", { devDependencies: true }] */ 12 | const path = require('path'); 13 | const webpack = require('webpack'); 14 | const UglifyJs = require('uglifyjs-webpack-plugin'); 15 | 16 | const baseConfig = { 17 | entry: { 18 | zilliqa: [ 19 | 'whatwg-fetch', 20 | './src/index.ts' 21 | ], 22 | }, 23 | mode: 'production', 24 | module: { 25 | rules: [ 26 | { 27 | test: /\.ts$/, 28 | use: { 29 | loader: 'babel-loader', 30 | options: { 31 | babelrc: true, 32 | cacheDirectory: true, 33 | }, 34 | }, 35 | }, 36 | ], 37 | }, 38 | devtool: 'source-map', 39 | resolve: { 40 | extensions: ['.ts', '.js'], 41 | }, 42 | }; 43 | 44 | const clientConfig = { 45 | ...baseConfig, 46 | optimization: { 47 | minimizer: [ 48 | new UglifyJs({ 49 | uglifyOptions: { 50 | compress: true, 51 | mangle: true, 52 | toplevel: false, 53 | output: { 54 | beautify: false, 55 | comments: false, 56 | }, 57 | }, 58 | include: /zilliqa\.js$/, 59 | parallel: true, 60 | sourceMap: true, 61 | }), 62 | ], 63 | }, 64 | output: { 65 | libraryTarget: 'umd', 66 | library: 'zilliqa.js', 67 | filename: '[name].browser.js', 68 | path: path.join(__dirname, 'dist'), 69 | }, 70 | } 71 | 72 | const serverConfig = { 73 | ...baseConfig, 74 | mode: 'development', 75 | target: 'node', 76 | plugins: [ 77 | new webpack.ProvidePlugin({ 78 | fetch: ['node-fetch-polyfill', 'default'], 79 | }), 80 | ], 81 | output: { 82 | filename: '[name].server.js', 83 | library: 'zilliqa.js', 84 | libraryTarget: 'commonjs2', 85 | path: path.join(__dirname, 'dist'), 86 | } 87 | } 88 | 89 | module.exports = [baseConfig, serverConfig]; 90 | --------------------------------------------------------------------------------