├── .circleci └── config.yml ├── .gitignore ├── .npmignore ├── API.md ├── COPYRIGHT ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── package-lock.json ├── package.json ├── src ├── cmd │ ├── actor │ │ └── ls.js │ ├── address │ │ ├── default.js │ │ ├── lookup.js │ │ ├── ls.js │ │ └── new.js │ ├── bootstrap │ │ └── ls.js │ ├── chain │ │ ├── head.js │ │ └── ls.js │ ├── client │ │ ├── cat.js │ │ ├── import.js │ │ ├── list-asks.js │ │ ├── payments.js │ │ ├── propose-storage-deal.js │ │ └── query-storage-deal.js │ ├── config │ │ ├── get.js │ │ └── set.js │ ├── dag │ │ └── get.js │ ├── dht │ │ ├── find-peer.js │ │ └── find-provs.js │ ├── id.js │ ├── log │ │ ├── level.js │ │ ├── ls.js │ │ └── tail.js │ ├── message │ │ └── wait.js │ ├── miner │ │ └── create.js │ ├── mining │ │ └── stop.js │ ├── ping.js │ ├── retrieval-client │ │ └── retrieve-piece.js │ ├── show │ │ └── block.js │ ├── stats │ │ └── bandwidth.js │ ├── swarm │ │ ├── connect.js │ │ └── peers.js │ ├── version.js │ └── wallet │ │ ├── balance.js │ │ ├── export.js │ │ └── import.js ├── index.js └── lib │ ├── fetch.js │ ├── form-data.browser.js │ ├── form-data.js │ ├── multiaddr-to-uri.js │ └── to-camel.js ├── test ├── e2e │ ├── _warn.js │ ├── actor │ │ └── ls.test.js │ ├── address │ │ ├── default.test.js │ │ ├── lookup.test.js │ │ ├── ls.test.js │ │ └── new.test.js │ ├── bootstrap │ │ └── ls.test.js │ ├── chain │ │ ├── head.test.js │ │ └── ls.test.js │ ├── client │ │ ├── import.test.js │ │ └── list-asks.test.js │ ├── config │ │ ├── get.test.js │ │ └── set.test.js │ ├── dag │ │ └── get.test.js │ ├── dht │ │ └── find-provs.test.js │ ├── helpers │ │ ├── faucet.js │ │ └── filecoin.js │ ├── id.test.js │ ├── log │ │ ├── level.test.js │ │ ├── ls.test.js │ │ └── tail.test.js │ ├── miner │ │ └── create.test.js │ ├── mining │ │ └── stop.test.js │ ├── ping.test.js │ ├── show │ │ └── block.test.js │ ├── stats │ │ └── bandwidth.test.js │ ├── swarm │ │ └── peers.test.js │ ├── version.test.js │ └── wallet │ │ ├── balance.test.js │ │ ├── export.test.js │ │ └── import.test.js ├── helpers │ └── iterable.js └── unit │ ├── cmd │ ├── actor │ │ └── ls.test.js │ ├── address │ │ ├── default.test.js │ │ ├── lookup.test.js │ │ ├── ls.test.js │ │ └── new.test.js │ ├── bootstrap │ │ └── ls.test.js │ ├── chain │ │ ├── head.test.js │ │ └── ls.test.js │ ├── client │ │ ├── cat.test.js │ │ ├── import.test.js │ │ ├── list-asks.fixtures.json │ │ ├── list-asks.test.js │ │ ├── payments.test.js │ │ ├── propose-storage-deal.fixtures.json │ │ ├── propose-storage-deal.test.js │ │ ├── query-storage-deal.fixtures.json │ │ └── query-storage-deal.test.js │ ├── config │ │ ├── get.test.js │ │ └── set.test.js │ ├── dag │ │ ├── get.fixtures.json │ │ └── get.test.js │ ├── dht │ │ ├── find-peer.fixtures.json │ │ ├── find-peer.test.js │ │ ├── find-provs.fixtures.json │ │ └── find-provs.test.js │ ├── id.test.js │ ├── log │ │ ├── level.test.js │ │ ├── ls.fixtures.json │ │ ├── ls.test.js │ │ ├── tail.fixtures.json │ │ └── tail.test.js │ ├── mining │ │ └── stop.test.js │ ├── ping.test.js │ ├── retrieval-client │ │ └── retrieve-piece.test.js │ ├── show │ │ ├── block.fixtures.json │ │ └── block.test.js │ ├── stats │ │ ├── bandwidth.fixtures.json │ │ └── bandwidth.test.js │ ├── swarm │ │ ├── connect.test.js │ │ └── peers.test.js │ ├── version.test.js │ └── wallet │ │ ├── balance.test.js │ │ ├── export.fixtures.json │ │ └── export.test.js │ └── lib │ └── fetch.test.js ├── webpack.config.js └── webpack.dev.config.js /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # Javascript Node CircleCI 2.0 configuration file 2 | # 3 | # Check https://circleci.com/docs/2.0/language-javascript/ for more details 4 | # 5 | version: 2 6 | jobs: 7 | build: 8 | docker: 9 | # specify the version you desire here 10 | - image: circleci/node:10 11 | 12 | # Specify service dependencies here if necessary 13 | # CircleCI maintains a library of pre-built images 14 | # documented at https://circleci.com/docs/2.0/circleci-images/ 15 | # - image: circleci/mongo:3.4.4 16 | 17 | working_directory: ~/repo 18 | 19 | steps: 20 | - checkout 21 | 22 | # Download and cache dependencies 23 | - restore_cache: 24 | keys: 25 | - v1-dependencies-{{ checksum "package.json" }} 26 | # fallback to using the latest cache if no exact match is found 27 | - v1-dependencies- 28 | 29 | - run: npm install 30 | 31 | - save_cache: 32 | paths: 33 | - node_modules 34 | key: v1-dependencies-{{ checksum "package.json" }} 35 | 36 | # run tests! 37 | - run: 38 | command: | 39 | npm run lint 40 | npm test 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .nyc_output 3 | coverage 4 | dist 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .nyc_output 3 | coverage 4 | -------------------------------------------------------------------------------- /API.md: -------------------------------------------------------------------------------- 1 | # API 2 | 3 | * [actor.ls](#actorls) 4 | * [address.default](#addressdefault) 5 | * [address.lookup](#addresslookup) 6 | * [address.ls](#addressls) 7 | * [address.new](#addressnew) 8 | * [bootstrap.ls](#bootstrapls) 9 | * [chain.head](#chainhead) 10 | * [chain.ls](#chainls) 11 | * [client.cat](#clientcat) 12 | * [client.import](#clientimport) 13 | * [client.listAsks](#clientlistasks) 14 | * [client.payments](#clientpayments) 15 | * [client.proposeStorageDeal](#clientproposestoragedeal) 16 | * [client.queryStorageDeal](#clientquerystoragedeal) 17 | * [config.get](#configget) 18 | * [config.set](#configset) 19 | * [dag.get](#dagget) 20 | * [dht.findPeer](#dhtfindpeer) 21 | * [dht.findProvs](#dhtfindprovs) 22 | * dht.query 23 | * [id](#id) 24 | * [log.level](#loglevel) 25 | * [log.ls](#logls) 26 | * [log.tail](#logtail) 27 | * message.send 28 | * message.status 29 | * [message.wait](#messagewait) 30 | * miner.addAsk 31 | * [miner.create](#minercreate) 32 | * miner.owner 33 | * miner.pledge 34 | * miner.power 35 | * miner.setPrice 36 | * miner.updatePeerId 37 | * mining.once 38 | * mining.start 39 | * [mining.stop](#miningstop) 40 | * mpool.ls 41 | * mpool.rm 42 | * mpool.show 43 | * paych.close 44 | * paych.create 45 | * paych.extend 46 | * paych.ls 47 | * paych.reclaim 48 | * paych.redeem 49 | * paych.voucher 50 | * [ping](#ping) 51 | * [retrievalClient.retrievePiece](#retrievalclientretrievepiece) 52 | * [show.block](#showblock) 53 | * [stats.bandwidth](#statsbandwidth) 54 | * [swarm.connect](#swarmconnect) 55 | * [swarm.peers](#swarmpeers) 56 | * [version](#version) 57 | * [wallet.balance](#walletbalance) 58 | * [wallet.export](#walletexport) 59 | * [wallet.import](#walletimport) 60 | 61 | ## `actor.ls` 62 | 63 | > TODO describe actor.ls 64 | 65 | ### `actor.ls([options])` 66 | 67 | #### Parameters 68 | 69 | | Name | Type | Description | 70 | |------|------|-------------| 71 | | options | `Object` | Optional options | 72 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 73 | 74 | #### Returns 75 | 76 | | Type | Description | 77 | |------|-------------| 78 | | `AsyncIterable` | TODO describe return value | 79 | 80 | #### Example 81 | 82 | ```js 83 | for await (const actor of fc.actor.ls()) 84 | console.log(actor) 85 | 86 | /* 87 | After first iteration: 88 | { actorType: 'MinerActor', 89 | address: 'fcqpdd3end3j5hhu7lacxg4vnluu9rxfd3nteezw6', 90 | code: 'zb2rhmciMRS4PBXYBBHssphYKQrbFujVjj1SMyUyN2bU2SKFx', 91 | nonce: 0, 92 | balance: '100', 93 | exports: 94 | { addAsk: { Params: [Array], Return: [Array] }, 95 | commitSector: { Params: [Array], Return: [] }, 96 | getKey: { Params: [], Return: [Array] }, 97 | getLastUsedSectorID: { Params: [], Return: [Array] }, 98 | getOwner: { Params: [], Return: [Array] }, 99 | getPeerID: { Params: [], Return: [Array] }, 100 | getPower: { Params: [], Return: [Array] }, 101 | getProvingPeriodStart: { Params: [], Return: [Array] }, 102 | submitPoSt: { Params: [Array], Return: [] }, 103 | updatePeerID: { Params: [Array], Return: [] } }, 104 | head: 'zDPWYqFD5LSWY8NQR7hWtLU8arYBw6W9eXZ1VvWjzh8YUJfAshx4' 105 | */ 106 | ``` 107 | 108 | ## `address.default` 109 | 110 | > Fetch the default address 111 | 112 | ### `address.default([options])` 113 | 114 | #### Parameters 115 | 116 | | Name | Type | Description | 117 | |------|------|-------------| 118 | | options | `Object` | Optional options | 119 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 120 | 121 | #### Returns 122 | 123 | | Type | Description | 124 | |------|-------------| 125 | | `Promise` | The default address | 126 | 127 | #### Example 128 | 129 | ```js 130 | const addr = await fc.address.default() 131 | console.log(addr) // t1gwlbykvhfrkhrtll43ceiyzgggk7omnololcwpy 132 | ``` 133 | 134 | ## `address.lookup` 135 | 136 | > TODO describe address.lookup 137 | 138 | ### `address.lookup(addr, [options])` 139 | 140 | #### Parameters 141 | 142 | | Name | Type | Description | 143 | |------|------|-------------| 144 | | addr | `String` | Address to lookup peer ID for | 145 | | options | `Object` | Optional options | 146 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 147 | 148 | #### Returns 149 | 150 | | Type | Description | 151 | |------|-------------| 152 | | `Promise` | Peer ID for address | 153 | 154 | ## `address.ls` 155 | 156 | > List address(es) 157 | 158 | ### `address.ls([options])` 159 | 160 | #### Parameters 161 | 162 | | Name | Type | Description | 163 | |------|------|-------------| 164 | | options | `Object` | Optional options | 165 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 166 | 167 | #### Returns 168 | 169 | | Type | Description | 170 | |------|-------------| 171 | | `Promise` | Addresses | 172 | 173 | #### Example 174 | 175 | ```js 176 | const addresses = await fc.address.ls() 177 | console.log(addresses) // [fcqyz3pgq7qpg0nekps597zth57x7xmh4sad7euk0] 178 | ``` 179 | 180 | ## `address.new` 181 | 182 | > TODO describe address.new 183 | 184 | ### `address.new([options])` 185 | 186 | #### Parameters 187 | 188 | | Name | Type | Description | 189 | |------|------|-------------| 190 | | options | `Object` | Optional options | 191 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 192 | 193 | #### Returns 194 | 195 | | Type | Description | 196 | |------|-------------| 197 | | `Promise` | A newly created address | 198 | 199 | #### Example 200 | 201 | ```js 202 | const addr = await fc.address.new() 203 | console.log(addr) // fcq7kwnm7mqaynhngfl6qtp03p6jxmyda62zagfek 204 | ``` 205 | 206 | ## `bootstrap.ls` 207 | 208 | > TODO describe bootstrap.ls 209 | 210 | ### `bootstrap.ls([options])` 211 | 212 | #### Parameters 213 | 214 | | Name | Type | Description | 215 | |------|------|-------------| 216 | | options | `Object` | Optional options | 217 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 218 | 219 | #### Returns 220 | 221 | | Type | Description | 222 | |------|-------------| 223 | | `Promise` | List of bootstrap [multiaddrs](https://github.com/multiformats/js-multiaddr) | 224 | 225 | #### Example 226 | 227 | ```js 228 | const addrs = await fc.boostrap.ls() 229 | console.log(addrs) 230 | 231 | /* 232 | [ '/dns4/test.kittyhawk.wtf/tcp/9001/ipfs/QmXq6XEYeEmUzBFuuKbVEGgxEpVD4xbSkG2Rhek6zkFMp4', 233 | '/dns4/test.kittyhawk.wtf/tcp/9002/ipfs/QmXhxqTKzBKHA5FcMuiKZv8YaMPwpbKGXHRVZcFB2DX9XY', 234 | '/dns4/test.kittyhawk.wtf/tcp/9003/ipfs/QmZGDLdQLUTi7uYTNavKwCd7SBc5KMfxzWxAyvqRQvwuiV', 235 | '/dns4/test.kittyhawk.wtf/tcp/9004/ipfs/QmZRnwmCjyNHgeNDiyT8mXRtGhP6uSzgHtrozc42crmVbg' ] 236 | */ 237 | ``` 238 | 239 | ## `chain.head` 240 | 241 | > Get heaviest tipset CIDs 242 | 243 | ### `chain.head([options])` 244 | 245 | #### Parameters 246 | 247 | | Name | Type | Description | 248 | |------|------|-------------| 249 | | options | `Object` | Optional options | 250 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 251 | 252 | #### Returns 253 | 254 | | Type | Description | 255 | |------|-------------| 256 | | `Promise` | Array of String CIDs | 257 | 258 | #### Example 259 | 260 | ```js 261 | const block = await fc.chain.head() 262 | console.log(block) 263 | // [ 'zDPWYqFCrhCRdGa1Z84DBpSQ5rrHphwjs7qHe5uS2LFurdnE6vvF' ] 264 | ``` 265 | 266 | ## `chain.ls` 267 | 268 | > Dump full block chain 269 | 270 | ### `chain.ls([options])` 271 | 272 | #### Parameters 273 | 274 | | Name | Type | Description | 275 | |------|------|-------------| 276 | | options | `Object` | Optional options | 277 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 278 | 279 | #### Returns 280 | 281 | | Type | Description | 282 | |------|-------------| 283 | | `AsyncIterable` | Iterable of blocks in the blockchain | 284 | 285 | #### Example 286 | 287 | ```js 288 | for await (const block of fc.chain.ls()) 289 | console.log(block) 290 | 291 | /* 292 | After first iteration: 293 | [ { miner: 'fcq5y65n23xdkcx2ymakflxpxqhkvewnwswp0me52', 294 | ticket: 'BNdhwXA6ty/KdYJ3YY/gZ1CexKRXsDYOpBq0wbK+/kA=', 295 | parents: [ [String] ], 296 | parentWeightNumerator: 'y8q87bOQCQ==', 297 | parentWeightDenominator: 'xpSakwY=', 298 | height: '6hU=', 299 | nonce: 'AA==', 300 | messages: [ [Object] ], 301 | stateRoot: 'zDPWYqFD5LSWY8NQR7hWtLU8arYBw6W9eXZ1VvWjzh8YUJfAshx4', 302 | messageReceipts: [ [Object] ] } ] 303 | */ 304 | ``` 305 | 306 | ## `client.cat` 307 | 308 | > Read out data stored on the network 309 | 310 | ### `client.cat(cid, [options])` 311 | 312 | #### Parameters 313 | 314 | | Name | Type | Description | 315 | |------|------|-------------| 316 | | cid | `CID`\|`String` | CID of the content to read | 317 | | options | `Object` | Optional options | 318 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 319 | 320 | #### Returns 321 | 322 | | Type | Description | 323 | |------|-------------| 324 | | `AsyncIterable` | Content of the file, yields `Buffer` objects in Node.js and `UInt8Array` objects in the browser | 325 | 326 | #### Example 327 | 328 | ```js 329 | let data = Buffer.alloc(0) 330 | for await (const chunk of fc.client.cat('QmZPUUg1QVMciR1yYnC2HSFrXyAUwRvpnbx4haYefB2KY3')) 331 | data = Buffer.concat([data, chunk]) 332 | ``` 333 | 334 | ## `client.import` 335 | 336 | > Import data into the local node 337 | 338 | ### `client.import(input, [options])` 339 | 340 | #### Parameters 341 | 342 | | Name | Type | Description | 343 | |------|------|-------------| 344 | | input | `Buffer`\|`String`\|`AsyncIterable`\|`TypedArray`\|`Blob` | Data to import. Note, `TypedArray` and `Blob` supported in browser only. | 345 | | options | `Object` | Optional options | 346 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 347 | 348 | #### Returns 349 | 350 | | Type | Description | 351 | |------|-------------| 352 | | `Promise` | CID of the imported content | 353 | 354 | #### Example 355 | 356 | From a buffer: 357 | 358 | ```js 359 | const data = Buffer.from('Hello World!') 360 | const cid = await fc.client.import(data) 361 | ``` 362 | 363 | From a Node.js stream (or async iterable): 364 | 365 | ```js 366 | const data = fs.createReadStream('/path/to/file') 367 | const cid = await fc.client.import(data) 368 | ``` 369 | 370 | ## `client.listAsks` 371 | 372 | > List all asks in the storage market 373 | 374 | ### `client.listAsks([options])` 375 | 376 | #### Parameters 377 | 378 | | Name | Type | Description | 379 | |------|------|-------------| 380 | | options | `Object` | Optional options | 381 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 382 | 383 | #### Returns 384 | 385 | | Type | Description | 386 | |------|-------------| 387 | | `AsyncIterable` | Storage market asks | 388 | 389 | #### Example 390 | 391 | ```js 392 | for await (const ask of fc.client.listAsks()) 393 | console.log(ask) 394 | 395 | /* 396 | After first iteration: 397 | { miner: 't2zup5a5rytwissvm6zq74amp4chrnazrl4ev4yii', 398 | price: '0.00000000000001', 399 | expiry: 33329, 400 | id: 4 } 401 | */ 402 | ``` 403 | 404 | ## `client.payments` 405 | 406 | > List payments for a given deal 407 | 408 | ### `client.payments(dealCid, [options])` 409 | 410 | #### Parameters 411 | 412 | | Name | Type | Description | 413 | |------|------|-------------| 414 | | dealCid | `CID`\|`String` | Channel id from which to list vouchers | 415 | | options | `Object` | Optional options | 416 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 417 | 418 | #### Returns 419 | 420 | | Type | Description | 421 | |------|-------------| 422 | | `Promise` | List of payments | 423 | 424 | #### Example 425 | 426 | ```js 427 | const cid = 'zDPWYqFCuTNxiwRkt1iDJWEy6qKPGCunMGHrP1ojsMrZDWKYsgzF' 428 | const payments = await fc.client.payments(cid) 429 | console.log(payments) 430 | 431 | /* 432 | [ 433 | { 434 | "channel": 0, 435 | "payer": "t1bcvxo4ztdkukjmrsjvc5d4w24cl55vvbrssspyy", 436 | "target": "t1uo4nzu44apoclkbjbbvc4f3irbptg3ctjq44wiq", 437 | "amount": "25000", 438 | "validAt": 8, 439 | "condition": null, 440 | "signature": "1My76149fPIulbdO/DKlkUBMMSLwGYSw2XmVKXq3HrxMG5kkmBgsaPZ/DzdxiOWX5kdnXJ++AFQqsmWHd5dtOwE=" 441 | } 442 | ] 443 | */ 444 | ``` 445 | 446 | 447 | ## `client.proposeStorageDeal` 448 | 449 | > Propose a storage deal with a storage miner 450 | 451 | ### `client.proposeStorageDeal(miner, cid, askId, time, [options])` 452 | 453 | #### Parameters 454 | 455 | | Name | Type | Description | 456 | |------|------|-------------| 457 | | miner | `String` | Address of miner to send storage proposal | 458 | | cid | `String` | CID of the data to be stored | 459 | | askId | `String` | ID of ask for which to propose a deal | 460 | | time | `Number`\|`String` | Time in blocks (about 30 seconds per block) to store data. For example, storing for 1 day (2 blocks/min * 60 min/hr * 24 hr/day) = 2880 blocks. | 461 | | options | `Object` | Optional options | 462 | | options.allowDuplicates | `Boolean` | Allows duplicate proposals to be created. Unless this flag is set, you will not be able to make more than one deal per piece per miner. This protection exists to prevent erroneous duplicate deals. This parameter is not required. | 463 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 464 | 465 | #### Returns 466 | 467 | | Type | Description | 468 | |------|-------------| 469 | | `Promise` | Storage deal | 470 | 471 | #### Example 472 | 473 | ```js 474 | const miner = 't2u2r6nyaxdspozci5t2i2xtfw23lxa35rvkul7di' 475 | const cid = 'QmV9mkND7mvWim77R669UCLg1DgYzqiX1NsXtj7GSydzD6' 476 | const askId = '0' 477 | const time = 2800 // 1 day 478 | 479 | const storageDealProposal = await fc.client.proposeStorageDeal(miner, cid, askId, time) 480 | 481 | // with optional flag to allow duplicates 482 | const storageDealProposal = await fc.client.proposeStorageDeal(miner, cid, askId, time, { allowDuplicates: true }) 483 | 484 | /* 485 | { 486 | "state": 3, 487 | "message": "", 488 | "proposalCid": "zDPWYqFCz8vQRUnFVsbdXPAWTRuRBLaPncKLLSqd7cNF3Bd2NQT5", 489 | "proofInfo": null, 490 | "signature": "c2lnbmF0dXJycmVlZQ==" 491 | } 492 | */ 493 | ``` 494 | 495 | ## `client.queryStorageDeal` 496 | 497 | > Query a storage deal's status 498 | 499 | ### `client.queryStorageDeal(dealCid, [options])` 500 | 501 | #### Parameters 502 | 503 | | Name | Type | Description | 504 | |------|------|-------------| 505 | | dealCid | `String` | CID of deal to query | 506 | | options | `Object` | Optional options | 507 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 508 | 509 | #### Returns 510 | 511 | | Type | Description | 512 | |------|-------------| 513 | | `Promise` | Storage deal | 514 | 515 | #### Example 516 | 517 | ```js 518 | const dealCid = 'zDPWYqFD8CNXu7Mo9qPSUANbTK2vi9vJBnvavF9S1pVGPHafVHpT' 519 | const storageDeal = await fc.client.queryStorageDeal(dealCid) 520 | console.log(storageDeal) 521 | 522 | /* 523 | { 524 | "state": 7, 525 | "message": "", 526 | "proposalCid": "zDPWYqFD8CNXu7Mo9qPSUANbTK2vi9vJBnvavF9S1pVGPHafVHpT", 527 | "proofInfo": 528 | { 529 | "sectorID": 1, 530 | "commD":"mkgOa7RCAYNHgUqsWmNR0MjAkzNMZM46ZPPuLonPsDk=", 531 | "commR":"gMGjsTgYFeXSFq3Vaqf2Nm2rhMV/nJ17nmZEPMeCs1I=", 532 | "commRStar":"87+U6/0jhvfBtauei+LG//bDpsNqlRa9Yguv+VSPHAE=", 533 | "commitmentMessage": "zDPWYqFCtHkWNkE2p6t6TeV1sPP5kbnKc5ajUhMVV8xvrw1u5F1R", 534 | "pieceInclusionProof": "EiAbbOy4pChsCYqFYA6qJaUJYStlnwYMdQPHZX7YBkVXDD6vgmGTPnWrcdA9M0oAXQCzOq735YKySLUoTI6pAw==" 535 | }, 536 | "signature": "c2lnbmF0dXJycmVlZQ==" 537 | } 538 | */ 539 | ``` 540 | 541 | 542 | ## `config.get` 543 | 544 | > Get config values 545 | 546 | ### `config.get(key, [options])` 547 | 548 | #### Parameters 549 | 550 | | Name | Type | Description | 551 | |------|------|-------------| 552 | | key | `String` | Dot separated key to config value to retrieve | 553 | | options | `Object` | Optional options | 554 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 555 | 556 | #### Returns 557 | 558 | | Type | Description | 559 | |------|-------------| 560 | | `Promise` | The current config value | 561 | 562 | #### Example 563 | 564 | ```js 565 | const value = await fc.config.get('bootstrap.addresses') 566 | console.log(value) 567 | 568 | /* 569 | ["/dns4/nightly.kittyhawk.wtf/tcp/9000/ipfs/Qmd6xrWYHsxivfakYRy6MszTpuAiEoFbgE1LWw4EvwBpp4", 570 | "/dns4/nightly.kittyhawk.wtf/tcp/9001/ipfs/QmXq6XEYeEmUzBFuuKbVEGgxEpVD4xbSkG2Rhek6zkFMp4", 571 | "/dns4/nightly.kittyhawk.wtf/tcp/9002/ipfs/QmXhxqTKzBKHA5FcMuiKZv8YaMPwpbKGXHRVZcFB2DX9XY", 572 | "/dns4/nightly.kittyhawk.wtf/tcp/9003/ipfs/QmZGDLdQLUTi7uYTNavKwCd7SBc5KMfxzWxAyvqRQvwuiV", 573 | "/dns4/nightly.kittyhawk.wtf/tcp/9004/ipfs/QmZRnwmCjyNHgeNDiyT8mXRtGhP6uSzgHtrozc42crmVbg'] 574 | */ 575 | ``` 576 | 577 | ## `config.set` 578 | 579 | > Set a config value 580 | 581 | ### `config.set(key, value, [options])` 582 | 583 | #### Parameters 584 | 585 | | Name | Type | Description | 586 | |------|------|-------------| 587 | | key | `String` | Dot separated key to config property name | 588 | | value | `?` | Value to set for the config value (must be JSON stringifyable) | 589 | | options | `Object` | Optional options | 590 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 591 | 592 | #### Returns 593 | 594 | | Type | Description | 595 | |------|-------------| 596 | | `Promise` | The set config value | 597 | 598 | #### Example 599 | 600 | ```js 601 | const value = await fc.config.set('api.address', '/ip4/127.0.0.1/tcp/3453') 602 | console.log(value) 603 | 604 | /* 605 | /ip4/127.0.0.1/tcp/3453 606 | */ 607 | ``` 608 | 609 | ## `dag.get` 610 | 611 | > Get a DAG node by its CID 612 | 613 | ### `dag.get(cid, [options])` 614 | 615 | #### Parameters 616 | 617 | | Name | Type | Description | 618 | |------|------|-------------| 619 | | cid | `CID`\|`String` | CID of the DAG node to get | 620 | | options | `Object` | Optional options | 621 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 622 | 623 | #### Returns 624 | 625 | | Type | Description | 626 | |------|-------------| 627 | | `Promise` | The DAG node. If the server returns `Content-Type: 'application/json'` then the response is parsed into a JS object. Otherwise the raw `Buffer` (in Node.js) or `Blob` (in the browser) are returned. | 628 | 629 | #### Example 630 | 631 | ```js 632 | const UnixFs = require('ipfs-unixfs') 633 | const input = Buffer.from('Hello World!') 634 | const cid = await fc.client.import(input) 635 | const node = await fc.dag.get(cid) 636 | // Extract the raw data from the UnixFs DAG node 637 | const output = UnixFs.unmarshal(Buffer.from(output.data, 'base64')).data 638 | console.log(output.toString()) // Hello World! 639 | ``` 640 | 641 | ## `dht.findPeer` 642 | 643 | > Find a peer given a peerId. 644 | 645 | ### `dht.findPeer(peerId, [options])` 646 | 647 | #### Parameters 648 | 649 | | Name | Type | Description | 650 | |------|------|-------------| 651 | | peerId | `String` | ID of peer to find | 652 | | options | `Object` | Optional options | 653 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 654 | 655 | #### Returns 656 | 657 | | Type | Description | 658 | |------|-------------| 659 | | `AsyncIterable` | Multiaddresses of a given peer. | 660 | 661 | #### Example 662 | 663 | ```js 664 | const peers = await fc.swarm.peers() 665 | const peerId = peers[0].addr.getPeerId() 666 | 667 | for await (const addr of fc.dht.findPeer(peerId)) 668 | console.log(addr) 669 | 670 | /* 671 | [ '/ip4/3.90.230.176/tcp/49996', 672 | '/ip4/3.90.230.176/tcp/49917', 673 | '/ip4/3.90.230.176/tcp/58302', 674 | '/ip4/3.90.230.176/tcp/9004', 675 | '/ip4/3.90.230.176/tcp/49889', 676 | '/ip4/3.90.230.176/tcp/49872', 677 | '/ip4/3.90.230.176/tcp/57292', 678 | '/ip4/172.19.0.14/tcp/9000', 679 | '/ip4/3.90.230.176/tcp/46177', 680 | '/ip4/127.0.0.1/tcp/9000' 681 | */ 682 | ``` 683 | 684 | ## `dht.findProvs` 685 | 686 | > Find peers that can provide a given key's value. 687 | 688 | ### `dht.findProvs(key, [options])` 689 | 690 | #### Parameters 691 | 692 | | Name | Type | Description | 693 | |------|------|-------------| 694 | | key | `String` | The key whose provider Peer IDs are output | 695 | | options | `Object` | Optional options | 696 | | options.numProviders | `Boolean` | The max number of providers to find. Default: 20 | 697 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 698 | 699 | #### Returns 700 | 701 | | Type | Description | 702 | |------|-------------| 703 | | `AsyncIterable` | Responses from peers documenting the providers that provide the value. | 704 | 705 | #### Example 706 | 707 | ```js 708 | for await (const res of fc.dht.findProvs('QmbFMke1KXqnYyBBWxB74N4c5SBnJMVAiMNRcGu6x1AwQH')) 709 | console.log(res) 710 | 711 | /* 712 | Example iteration output: 713 | { type: 1, 714 | responses: 715 | [ { id: [String], addrs: [Array] }, 716 | { id: [String], addrs: [Array] }, 717 | { id: [String], addrs: [Array] }, 718 | { id: [String], addrs: [Array] }, 719 | { id: [String], addrs: [Array] }, 720 | { id: [String], addrs: [Array] }, 721 | { id: [String], addrs: [Array] }, 722 | { id: [String], addrs: [Array] }, 723 | { id: [String], addrs: [Array] }, 724 | { id: [String], addrs: [Array] }, 725 | { id: [String], addrs: [Array] }, 726 | { id: [String], addrs: [Array] }, 727 | { id: [String], addrs: [Array] }, 728 | { id: [String], addrs: [Array] }, 729 | { id: [String], addrs: [Array] }, 730 | { id: [String], addrs: [Array] }, 731 | { id: [String], addrs: [Array] }, 732 | { id: [String], addrs: [Array] }, 733 | { id: [String], addrs: [Array] }, 734 | { id: [String], addrs: [Array] } ], 735 | id: 'QmRCrwBopruk3dihfu9njyZ2J88VvCJG4JEnmhNku47RCR' 736 | */ 737 | ``` 738 | 739 | ## `id` 740 | 741 | > Get the identity of the Filecoin node 742 | 743 | ### `id([options])` 744 | 745 | #### Parameters 746 | 747 | | Name | Type | Description | 748 | |------|------|-------------| 749 | | options | `Object` | Optional options | 750 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 751 | 752 | #### Returns 753 | 754 | | Type | Description | 755 | |------|-------------| 756 | | `Promise<{ id, addresses }>` | TODO describe return value | 757 | 758 | #### Example 759 | 760 | ```js 761 | const { id, addresses } = await fc.id() 762 | console.log({ id, addresses }) 763 | 764 | /* 765 | { id: 'QmVESp5X5EtRXGrDBqHzZ1Hd22nSh5QLtw8BozGNu9dWef', 766 | addresses: 767 | [ '/ip4/127.0.0.1/tcp/6000/ipfs/QmVESp5X5EtRXGrDBqHzZ1Hd22nSh5QLtw8BozGNu9dWef', 768 | '/ip4/192.168.1.132/tcp/6000/ipfs/QmVESp5X5EtRXGrDBqHzZ1Hd22nSh5QLtw8BozGNu9dWef' ] } 769 | */ 770 | ``` 771 | 772 | ## `log.level` 773 | 774 | > Set the logging level for a subsystem or all subsystems 775 | 776 | ### `log.level(level, [options])` 777 | 778 | #### Parameters 779 | 780 | | Name | Type | Description | 781 | |------|------|-------------| 782 | | level | `String` | Log level to set. Available levels: debug, info, warning, error, fatal | 783 | | options | `Object` | Optional options | 784 | | options.subsystem | `String` | Subsystem to set the log level for. See [`log.ls`](#logls) for available subsystems | 785 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 786 | 787 | #### Returns 788 | 789 | | Type | Description | 790 | |------|-------------| 791 | | `Promise` | Confirmation message | 792 | 793 | #### Example 794 | 795 | Set log level for all subsystems: 796 | 797 | ```js 798 | const msg = await fc.log.level('debug') 799 | console.log(msg) // "Changed log level of all subsystems to: debug" 800 | ``` 801 | 802 | Set log level for "ping" subsystem: 803 | 804 | ```js 805 | const msg = await fc.log.level('debug', { subsystem: 'ping' }) 806 | console.log(msg) // "Changed log level of 'ping' to 'debug'" 807 | ``` 808 | 809 | ## `log.ls` 810 | 811 | > List the logging subsystems 812 | 813 | ### `log.ls([options])` 814 | 815 | #### Parameters 816 | 817 | | Name | Type | Description | 818 | |------|------|-------------| 819 | | options | `Object` | Optional options | 820 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 821 | 822 | #### Returns 823 | 824 | | Type | Description | 825 | |------|-------------| 826 | | `Promise` | The available subsystems | 827 | 828 | #### Example 829 | 830 | ```js 831 | const subsystems = await fc.log.ls() 832 | console.log(subsystems) 833 | 834 | /* 835 | [ 'commands/log', 836 | 'fps', 837 | 'net.bootstrap', 838 | 'messageimpl', 839 | 'peerstore', 840 | 'swarm2', 841 | 'dht.pb', 842 | 'autorelay', 843 | 'engine', 844 | 'eventlog', 845 | 'blockstore', 846 | 'keystore', 847 | 'transport', 848 | 'types', 849 | 'nat', 850 | 'bstestnet', 851 | 'sectorbuilder', 852 | '/fil/hello', 853 | 'mplex', 854 | 'addrutil', 855 | 'cmds/http', 856 | 'cmds/cli', 857 | 'autonat-svc', 858 | 'node', 859 | 'metrics', 860 | 'pubsub', 861 | 'chain.store', 862 | 'p2p-config', 863 | 'basichost', 864 | 'boguskey', 865 | 'mocknet', 866 | 'mockrouter', 867 | 'routing/record', 868 | 'providers', 869 | 'reuseport-transport', 870 | 'net/identify', 871 | 'secio', 872 | 'repo', 873 | 'ping', 874 | 'peerqueue', 875 | 'pathresolv', 876 | 'chain.syncer', 877 | 'chunk', 878 | 'bitswap_network', 879 | 'lock', 880 | 'stream-upgrader', 881 | 'tcp-tpt', 882 | 'relay', 883 | '/fil/retrieval', 884 | '/fil/storage', 885 | 'cmds', 886 | 'porcelain', 887 | 'discovery', 888 | 'table', 889 | 'dht', 890 | 'autonat', 891 | 'routedhost', 892 | 'bitswap', 893 | 'blockservice', 894 | 'consensus.expected', 895 | 'mqueue', 896 | 'mining' ] 897 | */ 898 | ``` 899 | 900 | ## `log.tail` 901 | 902 | > Tail the logs 903 | 904 | ### `log.tail([options])` 905 | 906 | #### Parameters 907 | 908 | | Name | Type | Description | 909 | |------|------|-------------| 910 | | options | `Object` | Optional options | 911 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 912 | 913 | #### Returns 914 | 915 | | Type | Description | 916 | |------|-------------| 917 | | `AsyncIterable` | Log entries | 918 | 919 | #### Example 920 | 921 | ```js 922 | for await (const entry of fc.log.tail()) 923 | console.log(entry) 924 | ``` 925 | 926 | ## `message.wait` 927 | 928 | > Wait for a message to appear in a mined block 929 | 930 | ### `message.wait(messageCid, [options])` 931 | 932 | #### Parameters 933 | 934 | | Name | Type | Description | 935 | |------|------|-------------| 936 | | messageCid | `CID`\|`String` | CID of the message to wait for | 937 | | options | `Object` | Optional options | 938 | | options.message | `Boolean` | Print the whole message. Default: true. | 939 | | options.receipt | `Boolean` | Print the whole message receipt. Default: true. | 940 | | options.return | `Boolean` | Print the return value from the receipt. Default: false. | 941 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 942 | | options.timeout | `String` | Maximum time to wait for message. e.g., 300ms, 1.5h, 2h45m. Default: 10m. | 943 | 944 | #### Returns 945 | 946 | | Type | Description | 947 | |------|-------------| 948 | | `Promise` | Message contents | 949 | 950 | #### Example 951 | 952 | ```js 953 | const msg = await fc.message.wait('zdpuAm8mTU17dB5mckEDSNXFtvuxVESUhKivSLCWw1kMZjdK9') 954 | ``` 955 | 956 | ## `miner.create` 957 | 958 | > Create a new file miner with FIL 959 | > 960 | > Issues a new message to the network to create the miner, then waits for the message to be mined as this is required to return the address of the new miner. 961 | > 962 | > Collateral will be committed at the rate of 0.001FIL per sector. When the miner's collateral drops below 0.001FIL, the miner will not be able to commit additional sectors. 963 | 964 | ### `miner.create(collateral, [options])` 965 | 966 | #### Parameters 967 | 968 | | Name | Type | Description | 969 | |------|------|-------------| 970 | | collateral | `Number`\|`String` | The amount of collateral, in FIL. | 971 | | options | `Object` | Optional options | 972 | | options.sectorSize | `String` | Size of the sectors which this miner will commit, in bytes. | 973 | | options.from | `String` | Address to send from | 974 | | options.peerId | `String` | Base58-encoded libp2p peer ID that the miner will operate. | 975 | | options.gasPrice | `Number`\|`String` | Price (FIL e.g. 0.00013) to pay for each GasUnits consumed mining this message. | 976 | | options.gasLimit | `Number`\|`String` | Maximum number of GasUnits this message is allowed to consume. | 977 | | options.preview | `Boolean` | Preview the Gas cost of this command without actually executing it. | 978 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 979 | 980 | #### Returns 981 | 982 | | Type | Description | 983 | |------|-------------| 984 | | `Promise` | TODO | 985 | 986 | #### Example 987 | 988 | ```js 989 | const res = await fc.miner.create(100, { 990 | gasPrice: 0.1, 991 | gasLimit: 300, 992 | from: 't1afotrik6r7s4mcm5oeay6vc7qombbxjqplkw4ka' 993 | }) 994 | 995 | console.log(res) 996 | ``` 997 | 998 | ## `mining.stop` 999 | 1000 | > Stop mining operations 1001 | 1002 | ### `mining.stop([options])` 1003 | 1004 | #### Parameters 1005 | 1006 | | Name | Type | Description | 1007 | |------|------|-------------| 1008 | | options | `Object` | Optional options | 1009 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 1010 | 1011 | #### Returns 1012 | 1013 | | Type | Description | 1014 | |------|-------------| 1015 | | `Promise` | Confirmation message | 1016 | 1017 | #### Example 1018 | 1019 | ```js 1020 | const msg = await fc.mining.stop() 1021 | console.log(msg) // Stopped mining 1022 | ``` 1023 | 1024 | ## `ping` 1025 | 1026 | > Send echo request packets to p2p network members 1027 | 1028 | ### `ping(peerId, [options])` 1029 | 1030 | #### Parameters 1031 | 1032 | | Name | Type | Description | 1033 | |------|------|-------------| 1034 | | peerId | `CID`\|`String` | ID of peer to be pinged | 1035 | | options | `Object` | Optional options | 1036 | | options.count | `Number` | Number of ping messages to send. Default: 10 | 1037 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 1038 | 1039 | #### Returns 1040 | 1041 | | Type | Description | 1042 | |------|-------------| 1043 | | `AsyncIterable<{ success, text, time }>` | Async iterable of pong messages received by the node | 1044 | 1045 | #### Example 1046 | 1047 | ```js 1048 | const peers = await fc.swarm.peers() 1049 | const peerId = peers[0].addr.getPeerId() 1050 | 1051 | for await (const pong of fc.ping(peerId)) 1052 | console.log(pong) 1053 | 1054 | /* 1055 | After first iteration: 1056 | { success: true, text: '', time: 187.54 } 1057 | */ 1058 | ``` 1059 | 1060 | ## `retrievalClient.retrievePiece` 1061 | 1062 | > Read out piece data stored by a miner on the network 1063 | 1064 | ### `retrievalClient.retrievePiece(miner, cid, [options])` 1065 | 1066 | #### Parameters 1067 | 1068 | | Name | Type | Description | 1069 | |------|------|-------------| 1070 | | miner | `String` | Retrieval miner actor address | 1071 | | cid | `CID`\|`String` | Content identifier of piece to read | 1072 | | options | `Object` | Optional options | 1073 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 1074 | 1075 | #### Returns 1076 | 1077 | | Type | Description | 1078 | |------|-------------| 1079 | | `AsyncIterable` | Content of the file, yields `Buffer` objects in Node.js and `UInt8Array` objects in the browser | 1080 | 1081 | #### Example 1082 | 1083 | ```js 1084 | const pieceData = fc.retrievalClient.retrievePiece( 1085 | 't2u2r6nyaxdspozci5t2i2xtfw23lxa35rvkul7di', 1086 | 'QmSB6t4fVfE4fZ46EFBodtK89RJaCRTtPRaEYFx8EQxh8a' 1087 | ) 1088 | 1089 | let data = Buffer.alloc(0) 1090 | for await (const chunk of pieceData) 1091 | data = Buffer.concat([data, chunk]) 1092 | ``` 1093 | 1094 | ## `show.block` 1095 | 1096 | > Show a filecoin block by its CID 1097 | 1098 | ### `show.block(cid, [options])` 1099 | 1100 | #### Parameters 1101 | 1102 | | Name | Type | Description | 1103 | |------|------|-------------| 1104 | | cid | `CID`\|`String` | CID of block to show | 1105 | | options | `Object` | Optional options | 1106 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 1107 | 1108 | #### Returns 1109 | 1110 | | Type | Description | 1111 | |------|-------------| 1112 | | `Promise` | The blockchain block | 1113 | 1114 | #### Example 1115 | 1116 | ```js 1117 | const block = await fc.show.block('zDPWYqFCutuHwRZhGXzji9L4eHeoFxxNCxCruGjWje36aAvbK2XV') 1118 | console.log(block) 1119 | 1120 | /* 1121 | { miner: '', 1122 | ticket: null, 1123 | parents: 'zDPWYqFCtf5awkxnZbpurnQFvsrafnv4nJbP8UkAHD8GCf8T2Sz4', 1124 | parentWeight: 'AA==', 1125 | height: 'AA==', 1126 | nonce: 'AA==', 1127 | messages: null, 1128 | stateRoot: 'zdpuAm8mTU17dB5mckEDSNXFtvuxVESUhKivSLCWw1kMZjdK9', 1129 | messageReceipts: null, 1130 | proof: 1131 | [ 0, 1132 | 0, 1133 | 0, 1134 | 0, 1135 | 0, 1136 | 0, 1137 | ... 92 more items ] } 1138 | */ 1139 | ``` 1140 | 1141 | ## `stats.bandwidth` 1142 | 1143 | > Get bandwidth usage statistics 1144 | 1145 | ### `stats.bandwidth([options])` 1146 | 1147 | #### Parameters 1148 | 1149 | | Name | Type | Description | 1150 | |------|------|-------------| 1151 | | options | `Object` | Optional options | 1152 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 1153 | 1154 | #### Returns 1155 | 1156 | | Type | Description | 1157 | |------|-------------| 1158 | | `Promise` | Current bandwidth usage stats | 1159 | 1160 | #### Example 1161 | 1162 | ```js 1163 | const stats = await fc.stats.bandwidth() 1164 | console.log(stats) 1165 | 1166 | /* 1167 | { totalIn: 7962607306, 1168 | totalOut: 5437567180, 1169 | rateIn: 1757169.0307054976, 1170 | rateOut: 1066315.9253809578 } 1171 | */ 1172 | ``` 1173 | 1174 | ## `swarm.connect` 1175 | 1176 | > Open a connection to a given address 1177 | 1178 | ### `swarm.connect(addr, [options])` 1179 | 1180 | #### Parameters 1181 | 1182 | | Name | Type | Description | 1183 | |------|------|-------------| 1184 | | addr | `String`\|`Multiaddr`\|`String[]`\|`Multiaddr[]` | Address(es) to connect to | 1185 | | options | `Object` | Optional options | 1186 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 1187 | 1188 | #### Returns 1189 | 1190 | | Type | Description | 1191 | |------|-------------| 1192 | | `Promise` | List of connection results | 1193 | 1194 | #### Example 1195 | 1196 | ```js 1197 | const res = await fc.swarm.connect('/ip4/192.168.1.1/tcp/6000/ipfs/QmQbd6WxZ3pwcwWn21MvgH1zH4m8hk148kTfoB6BNFa5hK') 1198 | console.log(res) 1199 | 1200 | /* 1201 | [ { peer: 'QmQbd6WxZ3pwcwWn21MvgH1zH4m8hk148kTfoB6BNFa5hK', 1202 | success: true } ] 1203 | */ 1204 | ``` 1205 | 1206 | ## `swarm.peers` 1207 | 1208 | > List peers with open connections 1209 | 1210 | ### `swarm.peers([options])` 1211 | 1212 | #### Parameters 1213 | 1214 | | Name | Type | Description | 1215 | |------|------|-------------| 1216 | | options | `Object` | Optional options | 1217 | | options.latency | `Boolean` | Return information about latency for each peer | 1218 | | options.streams | `Boolean` | Return information about open streams for each peer | 1219 | | options.verbose | `Boolean` | Return all extra information | 1220 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 1221 | 1222 | #### Returns 1223 | 1224 | | Type | Description | 1225 | |------|-------------| 1226 | | `Promise` | List of peer info | 1227 | 1228 | #### Example 1229 | 1230 | ```js 1231 | const peers = await fc.swarm.peers({ verbose: true }) 1232 | console.log(peers.map(p => ({ ...p, addr: p.addr.toString() }))) 1233 | 1234 | /* 1235 | { addr: 1236 | '/ip4/67.180.60.249/tcp/35645/ipfs/QmNTS7MeGJYu4StMn1EmnV6XyX4JhxZPNrHrdcApLNk1YA', 1237 | streams: [ { protocol: '/fil/hello/1.0.0' }, 1238 | { protocol: '/fil/hello/1.0.0' }, 1239 | { protocol: '/fil/kad/1.0.0' }, 1240 | { protocol: '/floodsub/1.0.0' }, 1241 | { protocol: '/floodsub/1.0.0' } ], 1242 | latency: 'n/a', 1243 | muxer: '' } ] 1244 | */ 1245 | ``` 1246 | 1247 | ## `version` 1248 | 1249 | > Get the version of the Filecoin node 1250 | 1251 | ### `version([options])` 1252 | 1253 | #### Parameters 1254 | 1255 | | Name | Type | Description | 1256 | |------|------|-------------| 1257 | | options | `Object` | Optional options | 1258 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 1259 | 1260 | #### Returns 1261 | 1262 | | Type | Description | 1263 | |------|-------------| 1264 | | `Promise` | TODO describe return value | 1265 | 1266 | #### Example 1267 | 1268 | ```js 1269 | const version = await fc.version() 1270 | console.log(version) 1271 | 1272 | /* 1273 | { commit: '4e75ee9b601525c45eb255d80ccb73de35102c6d' } 1274 | */ 1275 | ``` 1276 | 1277 | ## `wallet.addrs.ls` 1278 | 1279 | > Get the wallet address(es) 1280 | 1281 | ### `wallet.addrs.ls([options])` 1282 | 1283 | #### Parameters 1284 | 1285 | | Name | Type | Description | 1286 | |------|------|-------------| 1287 | | options | `Object` | Optional options | 1288 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 1289 | 1290 | #### Returns 1291 | 1292 | | Type | Description | 1293 | |------|-------------| 1294 | | `Promise` | TODO describe return value | 1295 | 1296 | #### Example 1297 | 1298 | ```js 1299 | const addresses = await fc.wallet.addrs.ls() 1300 | console.log(addresses) 1301 | 1302 | /* 1303 | ['fcqu4uhfnuvwu4yf647lgatjftht5pyn44yxxfc5k'] 1304 | */ 1305 | ``` 1306 | 1307 | ## `wallet.balance` 1308 | 1309 | > Lookup the balance of a given wallet 1310 | 1311 | ### `wallet.balance(addr, [options])` 1312 | 1313 | #### Parameters 1314 | 1315 | | Name | Type | Description | 1316 | |------|------|-------------| 1317 | | addr | `String` | Address of wallet to lookup balance of | 1318 | | options | `Object` | Optional options | 1319 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 1320 | 1321 | #### Returns 1322 | 1323 | | Type | Description | 1324 | |------|-------------| 1325 | | `Promise` | Balance of the wallet | 1326 | 1327 | #### Example 1328 | 1329 | ```js 1330 | const balance = await fc.wallet.balance('fcqqr00e38ge3vr90xx7x46gj7hq3dxcl09us08e') 1331 | console.log(balance) // 6900 1332 | ``` 1333 | 1334 | ## `wallet.export` 1335 | 1336 | > Export key information for wallets 1337 | 1338 | ### `wallet.export(addr, [options])` 1339 | 1340 | #### Parameters 1341 | 1342 | | Name | Type | Description | 1343 | |------|------|-------------| 1344 | | addr | `String`\|`String[]` | Address(es) of wallet(s) to export | 1345 | | options | `Object` | Optional options | 1346 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 1347 | 1348 | #### Returns 1349 | 1350 | | Type | Description | 1351 | |------|-------------| 1352 | | `Promise` | Exported key info | 1353 | 1354 | #### Example 1355 | 1356 | Single: 1357 | 1358 | ```js 1359 | const info = await fc.wallet.export('fcqqr00e38ge3vr90xx7x46gj7hq3dxcl09us08e') 1360 | console.log(info) 1361 | 1362 | /* 1363 | { 1364 | keyInfo: [ 1365 | { 1366 | privateKey: 'RxOfKlALxw8+XCaHQGaJfpXRWweYl+/xdIxVQfJTaTU=', 1367 | curve: 'secp256k1' 1368 | } 1369 | ] 1370 | } 1371 | */ 1372 | ``` 1373 | 1374 | Multiple: 1375 | 1376 | ```js 1377 | const info = await fc.wallet.export([ 1378 | 'fcqqr00e38ge3vr90xx7x46gj7hq3dxcl09us08e', 1379 | 'fcq5y65n23xdkcx2ymakflxpxqhkvewnwswp0me52' 1380 | ]) 1381 | console.log(info) 1382 | 1383 | /* 1384 | { 1385 | keyInfo: [ 1386 | { 1387 | privateKey: 'RxOfKlALxw8+XCaHQGaJfpXRWweYl+/xdIxVQfJTaTU=', 1388 | curve: 'secp256k1' 1389 | }, 1390 | { 1391 | privateKey: 'rZ7hdys60Rk5+kab9ZuUJ87o6zLgyYgOqP1lHEAYgwo=', 1392 | curve: 'secp256k1' 1393 | } 1394 | ] 1395 | } 1396 | */ 1397 | ``` 1398 | 1399 | ## `wallet.import` 1400 | 1401 | > import a wallet with KeyInfo 1402 | 1403 | 1404 | ### `wallet.import(keyInfo, [options])` 1405 | 1406 | #### Parameters 1407 | 1408 | | Name | Type | Description | 1409 | |------|------|-------------| 1410 | | addr | `KeyInfo`\|`KeyInfo[]` | KeyInfo(s) to import | 1411 | | options | `Object` | Optional options | 1412 | | options.signal | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | A signal that can be used to abort the request | 1413 | 1414 | #### Returns 1415 | 1416 | | Type | Description | 1417 | |------|-------------| 1418 | | `Promise` | imported address(es) | 1419 | 1420 | #### Example 1421 | 1422 | Single: 1423 | 1424 | ```js 1425 | const keyInfo = {"privateKey":"pdHwTOrJXnAGvQ0861k66xRsiT7N3Ms8IGte3nT837E=","curve":"secp256k1"} 1426 | const res = await fc.wallet.import(keyInfo) 1427 | console.log(res.addresses) 1428 | // [ 't1b3keswmeuk4tipp5egjbk3aoag56g5zd3cle2va' ] 1429 | ``` 1430 | 1431 | Multiple: 1432 | 1433 | ```js 1434 | const keyInfo = [ 1435 | {"privateKey":"pdHwTOrJXnAGvQ0861k66xRsiT7N3Ms8IGte3nT837E=","curve":"secp256k1"}, 1436 | {"privateKey":"Wxvp929XNPFVPPefsYJqpOuAnoXceh+P6tNq5pEmqcc=","curve":"secp256k1"} 1437 | ] 1438 | const res = await fc.wallet.import(keyInfo) 1439 | console.log(res.addresses) 1440 | // [ 't1b3keswmeuk4tipp5egjbk3aoag56g5zd3cle2va', 't1dktsc463xl3e3fq7bgjg6h2zcmhftvqfw7juqea' ] 1441 | ``` 1442 | 1443 | 1444 | 1445 | 1446 | -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | This library is dual-licensed under Apache 2.0 and MIT terms. 2 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Copyright 2019 by the Filecoin contributors. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # filecoin-api-client 2 | 3 | ## Status 4 | 5 | This repository is in a **frozen** state. It is not being maintained or kept in sync with the libraries it depends on. This library was designed for an early version of _go-filecoin_, which is now known as [Venus](https://venus.filecoin.io/). An API client for Lotus can be found at https://github.com/filecoin-shipyard/js-lotus-client-rpc. Even though work on this repository has been **shelved**, anyone interested in updating or maintaining this library should express their interest on one Filecoin community conversation mediums: . 6 | 7 | --- 8 | 9 | [![CircleCI branch](https://img.shields.io/circleci/project/github/filecoin-shipyard/js-filecoin-api-client/master.svg)](https://circleci.com/gh/filecoin-shipyard/js-filecoin-api-client) 10 | [![dependencies Status](https://david-dm.org/filecoin-shipyard/js-filecoin-api-client/status.svg)](https://david-dm.org/filecoin-shipyard/js-filecoin-api-client) 11 | [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) 12 | 13 | > An API client for Filecoin 14 | 15 | ⚠️ WARNING: Filecoin is under heavy development and breaking changes are highly likely between versions. This library is **experimental**, **incomplete** and **unsupported** by the Filecoin team. It may be broken in part or in entirety. 16 | 17 | 🧩 Currently compatible with **Filecoin 0.3.2** 18 | 19 | ## Install 20 | 21 | ```sh 22 | npm i filecoin-api-client 23 | ``` 24 | 25 | ## Usage 26 | 27 | ### Node.js 28 | 29 | ```js 30 | const Filecoin = require('filecoin-api-client') 31 | 32 | const fc = Filecoin({ 33 | apiAddr: '/ip4/127.0.0.1/tcp/3453/http' // (optional, default) 34 | }) 35 | 36 | // see API below for usage 37 | ``` 38 | 39 | ### Browser 40 | 41 | ```html 42 | 43 | 50 | ``` 51 | 52 | #### CORS 53 | 54 | In a web browser, the Filecoin API client might encounter an error saying that the origin is not allowed. This is a CORS ("Cross Origin Resource Sharing") failure: Filecoin servers send HTTP headers allowing access to only certain origins by default. You can whitelist the origins that you are calling from by changing your Filecoin config like this: 55 | 56 | ```sh 57 | $ filecoin config api.accessControlAllowOrigin '["http://example.com"]' 58 | ``` 59 | 60 | ## API 61 | 62 | * [actor.ls](API.md#actorls) 63 | * [address.default](API.md#addressdefault) 64 | * [address.lookup](API.md#addresslookup) 65 | * [address.ls](API.md#addressls) 66 | * [address.new](API.md#addressnew) 67 | * [bootstrap.ls](API.md#bootstrapls) 68 | * [chain.head](API.md#chainhead) 69 | * [chain.ls](API.md#chainls) 70 | * [client.cat](API.md#clientcat) 71 | * [client.import](API.md#clientimport) 72 | * [client.listAsks](API.md#clientlistasks) 73 | * [client.payments](API.md#clientpayments) 74 | * [client.proposeStorageDeal](API.md#clientproposestoragedeal) 75 | * [client.queryStorageDeal](API.md#clientquerystoragedeal) 76 | * [config.get](API.md#configget) 77 | * [config.set](API.md#configset) 78 | * [dag.get](API.md#dagget) 79 | * [dht.findPeer](API.md#dhtfindpeer) 80 | * [dht.findProvs](API.md#dhtfindprovs) 81 | * dht.query 82 | * [id](API.md#id) 83 | * [log.level](API.md#loglevel) 84 | * [log.ls](API.md#logls) 85 | * [log.tail](API.md#logtail) 86 | * message.send 87 | * message.status 88 | * [message.wait](API.md#messagewait) 89 | * miner.addAsk 90 | * [miner.create](API.md#minercreate) 91 | * miner.owner 92 | * miner.pledge 93 | * miner.power 94 | * miner.setPrice 95 | * miner.updatePeerId 96 | * mining.once 97 | * mining.start 98 | * [mining.stop](API.md#miningstop) 99 | * mpool.ls 100 | * mpool.rm 101 | * mpool.show 102 | * paych.close 103 | * paych.create 104 | * paych.extend 105 | * paych.ls 106 | * paych.reclaim 107 | * paych.redeem 108 | * paych.voucher 109 | * [ping](API.md#ping) 110 | * [retrievalClient.retrievePiece](API.md#retrievalclientretrievepiece) 111 | * [show.block](API.md#showblock) 112 | * [stats.bandwidth](API.md#statsbandwidth) 113 | * [swarm.connect](API.md#swarmconnect) 114 | * [swarm.peers](API.md#swarmpeers) 115 | * [version](API.md#version) 116 | * [wallet.balance](API.md#walletbalance) 117 | * [wallet.export](API.md#walletexport) 118 | * [wallet.import](API.md#walletimport) 119 | 120 | Status: 35/57 **61%** 121 | 122 | ## Contribute 123 | 124 | Feel free to dive in! [Open an issue](https://github.com/filecoin-shipyard/js-filecoin-api-client/issues/new) or submit PRs. 125 | 126 | ## License 127 | 128 | The Filecoin Project is dual-licensed under Apache 2.0 and MIT terms: 129 | - Apache License, Version 2.0, ([LICENSE-APACHE](https://github.com/filecoin-shipyard/js-filecoin-api-client/blob/master/LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 130 | - MIT license ([LICENSE-MIT](https://github.com/filecoin-shipyard/js-filecoin-api-client/blob/master/LICENSE-MIT) or http://opensource.org/licenses/MIT) 131 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "filecoin-api-client", 3 | "version": "0.5.2", 4 | "description": "API client for Filecoin", 5 | "main": "src/index.js", 6 | "browser": { 7 | "./src/lib/form-data.js": "./src/lib/form-data.browser.js" 8 | }, 9 | "scripts": { 10 | "build": "webpack", 11 | "test": "npm run test:unit", 12 | "test:unit": "ava --verbose test/unit/**/*.test.js test/unit/**/**/*.test.js", 13 | "test:e2e": "node test/e2e/_warn.js && ava --verbose test/e2e/**/*.test.js", 14 | "coverage": "nyc --reporter=lcov --reporter=text npm run test:unit", 15 | "lint": "standard" 16 | }, 17 | "author": "Alan Shaw", 18 | "license": "(Apache-2.0 OR MIT)", 19 | "dependencies": { 20 | "explain-error": "^1.0.4", 21 | "form-data": "^2.5.0", 22 | "is-buffer": "^2.0.3", 23 | "it-to-stream": "^0.1.1", 24 | "iterable-ndjson": "^1.1.0", 25 | "node-fetch": "^2.6.0" 26 | }, 27 | "devDependencies": { 28 | "abort-controller": "^3.0.0", 29 | "ava": "^2.2.0", 30 | "cids": "^0.7.1", 31 | "ipfs-unixfs": "^0.1.16", 32 | "multiaddr": "^7.1.0", 33 | "nyc": "^14.1.1", 34 | "standard": "^14.1.0", 35 | "webpack": "^4.39.1", 36 | "webpack-cli": "^3.3.6" 37 | }, 38 | "ava": { 39 | "babel": false, 40 | "compileEnhancements": false, 41 | "failWithoutAssertions": false 42 | }, 43 | "files": [ 44 | "src", 45 | "dist" 46 | ], 47 | "directories": { 48 | "test": "test" 49 | }, 50 | "repository": { 51 | "type": "git", 52 | "url": "git+https://github.com/filecoin-shipyard/js-filecoin-api-client.git" 53 | }, 54 | "keywords": [ 55 | "Filecoin", 56 | "FIL", 57 | "API", 58 | "HTTP", 59 | "REST" 60 | ], 61 | "bugs": { 62 | "url": "https://github.com/filecoin-shipyard/js-filecoin-api-client/issues" 63 | }, 64 | "homepage": "https://github.com/filecoin-shipyard/js-filecoin-api-client#readme" 65 | } 66 | -------------------------------------------------------------------------------- /src/cmd/actor/ls.js: -------------------------------------------------------------------------------- 1 | const ndjson = require('iterable-ndjson') 2 | const toUri = require('../../lib/multiaddr-to-uri') 3 | const { ok, toIterable } = require('../../lib/fetch') 4 | 5 | module.exports = (fetch, config) => { 6 | return options => (async function * () { 7 | options = options || {} 8 | 9 | const url = toUri(config.apiAddr) + '/api/actor/ls' 10 | const res = await ok(fetch(url, { signal: options.signal })) 11 | 12 | for await (const actor of ndjson(toIterable(res.body))) { 13 | if (actor.code) { 14 | actor.code = actor.code['/'] 15 | } 16 | 17 | if (actor.head) { 18 | actor.head = actor.head['/'] 19 | } 20 | 21 | yield actor 22 | } 23 | })() 24 | } 25 | -------------------------------------------------------------------------------- /src/cmd/address/default.js: -------------------------------------------------------------------------------- 1 | const toUri = require('../../lib/multiaddr-to-uri') 2 | const { ok } = require('../../lib/fetch') 3 | 4 | module.exports = (fetch, config) => { 5 | return async options => { 6 | options = options || {} 7 | const url = `${toUri(config.apiAddr)}/api/address/default` 8 | const res = await ok(fetch(url, { signal: options.signal })) 9 | const { Address } = await res.json() 10 | return Address 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/cmd/address/lookup.js: -------------------------------------------------------------------------------- 1 | const toUri = require('../../lib/multiaddr-to-uri') 2 | const { ok } = require('../../lib/fetch') 3 | 4 | module.exports = (fetch, config) => { 5 | return async (minerAddr, options) => { 6 | options = options || {} 7 | minerAddr = encodeURIComponent(minerAddr) 8 | const url = `${toUri(config.apiAddr)}/api/address/lookup?arg=${minerAddr}` 9 | const res = await ok(fetch(url, { signal: options.signal })) 10 | return res.json() 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/cmd/address/ls.js: -------------------------------------------------------------------------------- 1 | const toUri = require('../../lib/multiaddr-to-uri') 2 | const { ok } = require('../../lib/fetch') 3 | 4 | module.exports = (fetch, config) => { 5 | return async options => { 6 | options = options || {} 7 | const url = `${toUri(config.apiAddr)}/api/address/ls` 8 | const res = await ok(fetch(url, { signal: options.signal })) 9 | const data = await res.json() 10 | return data.Addresses 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/cmd/address/new.js: -------------------------------------------------------------------------------- 1 | const toUri = require('../../lib/multiaddr-to-uri') 2 | const { ok } = require('../../lib/fetch') 3 | 4 | module.exports = (fetch, config) => { 5 | return async options => { 6 | options = options || {} 7 | const url = `${toUri(config.apiAddr)}/api/address/new` 8 | const res = await ok(fetch(url, { signal: options.signal })) 9 | const { Address } = await res.json() 10 | return Address 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/cmd/bootstrap/ls.js: -------------------------------------------------------------------------------- 1 | const toUri = require('../../lib/multiaddr-to-uri') 2 | const { ok } = require('../../lib/fetch') 3 | 4 | module.exports = (fetch, config) => { 5 | return async options => { 6 | options = options || {} 7 | const url = `${toUri(config.apiAddr)}/api/bootstrap/ls` 8 | const res = await ok(fetch(url, { signal: options.signal })) 9 | const data = await res.json() 10 | return data.Peers || [] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/cmd/chain/head.js: -------------------------------------------------------------------------------- 1 | const toUri = require('../../lib/multiaddr-to-uri') 2 | const { ok } = require('../../lib/fetch') 3 | 4 | module.exports = (fetch, config) => { 5 | return async options => { 6 | options = options || {} 7 | const url = `${toUri(config.apiAddr)}/api/chain/head` 8 | const res = await ok(fetch(url, { signal: options.signal })) 9 | const heads = await res.json() 10 | return heads.map(h => h['/']) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/cmd/chain/ls.js: -------------------------------------------------------------------------------- 1 | const ndjson = require('iterable-ndjson') 2 | const toUri = require('../../lib/multiaddr-to-uri') 3 | const { ok, toIterable } = require('../../lib/fetch') 4 | 5 | module.exports = (fetch, config) => { 6 | return options => (async function * () { 7 | options = options || {} 8 | 9 | const url = toUri(config.apiAddr) + '/api/chain/ls' 10 | const res = await ok(fetch(url, { signal: options.signal })) 11 | 12 | for await (const block of ndjson(toIterable(res.body))) { 13 | yield block.map(b => { 14 | if (Array.isArray(b.parents)) { 15 | b.parents = b.parents.map(p => p['/']) 16 | } 17 | 18 | if (b.stateRoot) { 19 | b.stateRoot = b.stateRoot['/'] 20 | } 21 | 22 | return b 23 | }) 24 | } 25 | })() 26 | } 27 | -------------------------------------------------------------------------------- /src/cmd/client/cat.js: -------------------------------------------------------------------------------- 1 | const toUri = require('../../lib/multiaddr-to-uri') 2 | const { ok, toIterable } = require('../../lib/fetch') 3 | 4 | module.exports = (fetch, config) => { 5 | return (cid, options) => (async function * () { 6 | options = options || {} 7 | 8 | const url = `${toUri(config.apiAddr)}/api/client/cat?arg=${encodeURIComponent(cid)}` 9 | const res = await ok(fetch(url, { signal: options.signal })) 10 | 11 | for await (const chunk of toIterable(res.body)) { 12 | yield chunk 13 | } 14 | })() 15 | } 16 | -------------------------------------------------------------------------------- /src/cmd/client/import.js: -------------------------------------------------------------------------------- 1 | const toUri = require('../../lib/multiaddr-to-uri') 2 | const { ok } = require('../../lib/fetch') 3 | const { toFormData } = require('../../lib/form-data') 4 | 5 | module.exports = (fetch, config) => { 6 | return async (input, options) => { 7 | options = options || {} 8 | 9 | const url = `${toUri(config.apiAddr)}/api/client/import` 10 | const res = await ok(fetch(url, { 11 | method: 'POST', 12 | signal: options.signal, 13 | body: await toFormData(input) 14 | })) 15 | 16 | const data = await res.json() 17 | return data['/'] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/cmd/client/list-asks.js: -------------------------------------------------------------------------------- 1 | const ndjson = require('iterable-ndjson') 2 | const toUri = require('../../lib/multiaddr-to-uri') 3 | const { ok, toIterable } = require('../../lib/fetch') 4 | const toCamel = require('../../lib/to-camel') 5 | 6 | module.exports = (fetch, config) => { 7 | return options => (async function * () { 8 | options = options || {} 9 | 10 | const url = toUri(config.apiAddr) + '/api/client/list-asks' 11 | const res = await ok(fetch(url, { signal: options.signal })) 12 | 13 | for await (const ask of ndjson(toIterable(res.body))) { 14 | yield toCamel(ask) 15 | } 16 | })() 17 | } 18 | -------------------------------------------------------------------------------- /src/cmd/client/payments.js: -------------------------------------------------------------------------------- 1 | const toUri = require('../../lib/multiaddr-to-uri') 2 | const { ok } = require('../../lib/fetch') 3 | 4 | module.exports = (fetch, config) => { 5 | return async (cid, options) => { 6 | options = options || {} 7 | cid = encodeURIComponent(cid) 8 | 9 | const url = `${toUri(config.apiAddr)}/api/client/payments?arg=${cid}` 10 | const res = await ok(fetch(url, { signal: options.signal })) 11 | 12 | const paymentsData = await res.json() 13 | 14 | return (paymentsData || []).map(d => { 15 | const { valid_at: validAt, ...rest } = d 16 | if (validAt != null) { 17 | rest.validAt = validAt 18 | } 19 | return rest 20 | }) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/cmd/client/propose-storage-deal.js: -------------------------------------------------------------------------------- 1 | const toUri = require('../../lib/multiaddr-to-uri') 2 | const { ok } = require('../../lib/fetch') 3 | const toCamel = require('../../lib/to-camel') 4 | 5 | module.exports = (fetch, config) => { 6 | return async (miner, cid, askId, time, options) => { 7 | options = options || {} 8 | 9 | const qs = new URLSearchParams(options.qs) 10 | ;[miner, cid.toString(), askId, time].forEach(arg => qs.append('arg', arg)) 11 | if (options.allowDuplicates != null) qs.set('allow-duplicates', options.allowDuplicates) 12 | 13 | const url = `${toUri(config.apiAddr)}/api/client/propose-storage-deal?${qs}` 14 | const res = await ok(fetch(url, { signal: options.signal })) 15 | 16 | const newDeal = toCamel(await res.json()) 17 | 18 | if (newDeal.proposalCid) { 19 | newDeal.proposalCid = newDeal.proposalCid['/'] 20 | } 21 | 22 | newDeal.proofInfo = toCamel(newDeal.proofInfo) 23 | 24 | return newDeal 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/cmd/client/query-storage-deal.js: -------------------------------------------------------------------------------- 1 | const toUri = require('../../lib/multiaddr-to-uri') 2 | const { ok } = require('../../lib/fetch') 3 | const toCamel = require('../../lib/to-camel') 4 | 5 | module.exports = (fetch, config) => { 6 | return async (cid, options) => { 7 | options = options || {} 8 | 9 | const url = `${toUri(config.apiAddr)}/api/client/query-storage-deal?arg=${encodeURIComponent(cid)}` 10 | const res = await ok(fetch(url, { signal: options.signal })) 11 | 12 | const storageDeal = toCamel(await res.json()) 13 | 14 | if (storageDeal.proposalCid) { 15 | storageDeal.proposalCid = storageDeal.proposalCid['/'] 16 | } 17 | 18 | if (storageDeal.proofInfo) { 19 | storageDeal.proofInfo = toCamel(storageDeal.proofInfo) 20 | } 21 | 22 | if (storageDeal.proofInfo && storageDeal.proofInfo.commitmentMessage) { 23 | storageDeal.proofInfo.commitmentMessage = storageDeal.proofInfo.commitmentMessage['/'] 24 | } 25 | 26 | return storageDeal 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/cmd/config/get.js: -------------------------------------------------------------------------------- 1 | const toUri = require('../../lib/multiaddr-to-uri') 2 | const { ok } = require('../../lib/fetch') 3 | 4 | module.exports = (fetch, config) => { 5 | return async (key, options) => { 6 | options = options || {} 7 | const url = `${toUri(config.apiAddr)}/api/config?arg=${encodeURIComponent(key)}` 8 | const res = await ok(fetch(url, { signal: options.signal })) 9 | const data = await res.json() 10 | return data 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/cmd/config/set.js: -------------------------------------------------------------------------------- 1 | const toUri = require('../../lib/multiaddr-to-uri') 2 | const explain = require('explain-error') 3 | const { ok } = require('../../lib/fetch') 4 | 5 | module.exports = (fetch, config) => { 6 | return async (key, value, options) => { 7 | options = options || {} 8 | 9 | try { 10 | value = JSON.stringify(value) 11 | } catch (err) { 12 | throw explain(err, 'failed to stringify config value') 13 | } 14 | 15 | const qs = new URLSearchParams(options.qs) 16 | ;[key, value].forEach(arg => qs.append('arg', arg)) 17 | 18 | const url = `${toUri(config.apiAddr)}/api/config?${qs}` 19 | const res = await ok(fetch(url, { signal: options.signal })) 20 | const data = await res.json() 21 | return data 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/cmd/dag/get.js: -------------------------------------------------------------------------------- 1 | const toUri = require('../../lib/multiaddr-to-uri') 2 | const { ok } = require('../../lib/fetch') 3 | 4 | module.exports = (fetch, config) => { 5 | return async (cid, options) => { 6 | options = options || {} 7 | 8 | const url = `${toUri(config.apiAddr)}/api/dag/get?arg=${encodeURIComponent(cid)}` 9 | const res = await ok(fetch(url, { signal: options.signal })) 10 | 11 | if (res.headers.get('Content-Type') === 'application/json') { 12 | return res.json() 13 | } 14 | 15 | // Buffer for Node.js, blob otherwise 16 | return res.buffer ? res.buffer() : res.blob() 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/cmd/dht/find-peer.js: -------------------------------------------------------------------------------- 1 | const ndjson = require('iterable-ndjson') 2 | const toUri = require('../../lib/multiaddr-to-uri') 3 | const { ok, toIterable } = require('../../lib/fetch') 4 | 5 | module.exports = (fetch, config) => { 6 | return (peerId, options) => (async function * () { 7 | options = options || {} 8 | 9 | const qs = new URLSearchParams(options.qs) 10 | qs.set('arg', peerId.toString()) 11 | 12 | const url = `${toUri(config.apiAddr)}/api/dht/findpeer?${qs}` 13 | const res = await ok(fetch(url, { signal: options.signal })) 14 | 15 | for await (const addr of ndjson(toIterable(res.body))) { 16 | yield addr 17 | } 18 | })() 19 | } 20 | -------------------------------------------------------------------------------- /src/cmd/dht/find-provs.js: -------------------------------------------------------------------------------- 1 | const ndjson = require('iterable-ndjson') 2 | const toUri = require('../../lib/multiaddr-to-uri') 3 | const { ok, toIterable } = require('../../lib/fetch') 4 | 5 | module.exports = (fetch, config) => { 6 | return (key, options) => (async function * () { 7 | options = options || {} 8 | 9 | const qs = new URLSearchParams(options.qs) 10 | qs.set('arg', key.toString()) 11 | if (options.numProviders) qs.set('num-providers', options.numProviders) 12 | 13 | const url = `${toUri(config.apiAddr)}/api/dht/findprovs?${qs}` 14 | const res = await ok(fetch(url, { signal: options.signal })) 15 | 16 | for await (const peer of ndjson(toIterable(res.body))) { 17 | const prov = { 18 | type: peer.Type, 19 | responses: (peer.Responses || []).map(r => ({ 20 | id: r.ID, 21 | addrs: r.Addrs || [] 22 | })) 23 | } 24 | 25 | if (peer.ID) { 26 | prov.id = peer.ID 27 | } 28 | 29 | if (peer.Extra) { 30 | prov.extra = peer.Extra 31 | } 32 | 33 | yield prov 34 | } 35 | })() 36 | } 37 | -------------------------------------------------------------------------------- /src/cmd/id.js: -------------------------------------------------------------------------------- 1 | const toUri = require('../lib/multiaddr-to-uri') 2 | const { ok } = require('../lib/fetch') 3 | 4 | module.exports = (fetch, config) => { 5 | return async options => { 6 | options = options || {} 7 | const url = `${toUri(config.apiAddr)}/api/id` 8 | const res = await ok(fetch(url, { signal: options.signal })) 9 | const data = await res.json() 10 | return { id: data.ID, addresses: data.Addresses || [] } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/cmd/log/level.js: -------------------------------------------------------------------------------- 1 | const toUri = require('../../lib/multiaddr-to-uri') 2 | const { ok } = require('../../lib/fetch') 3 | 4 | module.exports = (fetch, config) => { 5 | return async (level, options) => { 6 | options = options || {} 7 | 8 | const qs = new URLSearchParams(options.qs) 9 | qs.set('arg', level) 10 | if (options.subsystem) qs.set('subsystem', options.subsystem) 11 | 12 | const url = `${toUri(config.apiAddr)}/api/log/level?${qs}` 13 | const res = await ok(fetch(url, { signal: options.signal })) 14 | return res.json() 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/cmd/log/ls.js: -------------------------------------------------------------------------------- 1 | const toUri = require('../../lib/multiaddr-to-uri') 2 | const { ok } = require('../../lib/fetch') 3 | 4 | module.exports = (fetch, config) => { 5 | return async options => { 6 | options = options || {} 7 | const url = `${toUri(config.apiAddr)}/api/log/ls` 8 | const res = await ok(fetch(url, { signal: options.signal })) 9 | return res.json() 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/cmd/log/tail.js: -------------------------------------------------------------------------------- 1 | const toUri = require('../../lib/multiaddr-to-uri') 2 | const { ok, toIterable } = require('../../lib/fetch') 3 | const ndjson = require('iterable-ndjson') 4 | 5 | module.exports = (fetch, config) => { 6 | return options => (async function * () { 7 | options = options || {} 8 | 9 | const url = `${toUri(config.apiAddr)}/api/log/tail` 10 | const res = await ok(fetch(url, { signal: options.signal })) 11 | 12 | for await (const entry of ndjson(toIterable(res.body))) { 13 | yield entry 14 | } 15 | })() 16 | } 17 | -------------------------------------------------------------------------------- /src/cmd/message/wait.js: -------------------------------------------------------------------------------- 1 | const toUri = require('../../lib/multiaddr-to-uri') 2 | const { ok } = require('../../lib/fetch') 3 | const toCamel = require('../../lib/to-camel') 4 | 5 | module.exports = (fetch, config) => { 6 | return async (messageCid, options) => { 7 | options = options || {} 8 | 9 | const qs = new URLSearchParams(options.qs) 10 | qs.set('arg', messageCid.toString()) 11 | if (options.message != null) qs.set('message', options.message) 12 | if (options.receipt != null) qs.set('receipt', options.receipt) 13 | if (options.return != null) qs.set('return', options.return) 14 | if (options.timeout) qs.set('timeout', options.timeout) 15 | 16 | const url = `${toUri(config.apiAddr)}/api/message/wait?${qs}` 17 | const res = await ok(fetch(url, { signal: options.signal })) 18 | 19 | return toCamel(await res.json()) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/cmd/miner/create.js: -------------------------------------------------------------------------------- 1 | const toUri = require('../../lib/multiaddr-to-uri') 2 | const { ok } = require('../../lib/fetch') 3 | 4 | module.exports = (fetch, config) => { 5 | return async (collateral, options) => { 6 | options = options || {} 7 | 8 | const qs = new URLSearchParams(options.qs) 9 | qs.set('arg', collateral) 10 | 11 | if (options.from != null) { 12 | qs.set('from', options.from) 13 | } 14 | 15 | if (options.gasLimit != null) { 16 | qs.set('gas-limit', options.gasLimit) 17 | } 18 | 19 | if (options.gasPrice != null) { 20 | qs.set('gas-price', options.gasPrice) 21 | } 22 | 23 | if (options.peerId != null) { 24 | qs.set('peerid', options.peerId) 25 | } 26 | 27 | if (options.preview != null) { 28 | qs.set('preview', options.preview) 29 | } 30 | 31 | if (options.sectorSize != null) { 32 | qs.set('sectorsize', options.sectorSize) 33 | } 34 | 35 | const url = `${toUri(config.apiAddr)}/api/miner/create?${qs}` 36 | const res = await ok(fetch(url, { signal: options.signal })) 37 | return res.json() 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/cmd/mining/stop.js: -------------------------------------------------------------------------------- 1 | const toUri = require('../../lib/multiaddr-to-uri') 2 | const { ok } = require('../../lib/fetch') 3 | 4 | module.exports = (fetch, config) => { 5 | return async options => { 6 | options = options || {} 7 | const url = `${toUri(config.apiAddr)}/api/mining/stop` 8 | const res = await ok(fetch(url, { signal: options.signal })) 9 | return res.json() 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/cmd/ping.js: -------------------------------------------------------------------------------- 1 | const toUri = require('../lib/multiaddr-to-uri') 2 | const ndjson = require('iterable-ndjson') 3 | const { ok, toIterable } = require('../lib/fetch') 4 | const toCamel = require('../lib/to-camel') 5 | 6 | module.exports = (fetch, config) => { 7 | return (peerId, options) => (async function * () { 8 | options = options || {} 9 | 10 | const qs = new URLSearchParams(options.qs) 11 | qs.set('arg', peerId.toString()) 12 | 13 | if (options.count != null) { 14 | qs.set('count', options.count) 15 | } 16 | 17 | const url = `${toUri(config.apiAddr)}/api/ping?${qs}` 18 | const res = await ok(fetch(url, { signal: options.signal })) 19 | 20 | for await (const pong of ndjson(toIterable(res.body))) { 21 | yield toCamel(pong) 22 | } 23 | })() 24 | } 25 | -------------------------------------------------------------------------------- /src/cmd/retrieval-client/retrieve-piece.js: -------------------------------------------------------------------------------- 1 | const toUri = require('../../lib/multiaddr-to-uri') 2 | const { ok, toIterable } = require('../../lib/fetch') 3 | 4 | module.exports = (fetch, config) => { 5 | return (minerAddr, cid, options) => (async function * () { 6 | options = options || {} 7 | 8 | minerAddr = encodeURIComponent(minerAddr) 9 | cid = encodeURIComponent(cid) 10 | 11 | const url = `${toUri(config.apiAddr)}/api/retrieval-client/retrieve-piece?arg=${minerAddr}&arg=${cid}` 12 | const res = await ok(fetch(url, { signal: options.signal })) 13 | 14 | yield * toIterable(res.body) 15 | })() 16 | } 17 | -------------------------------------------------------------------------------- /src/cmd/show/block.js: -------------------------------------------------------------------------------- 1 | const toUri = require('../../lib/multiaddr-to-uri') 2 | const { ok } = require('../../lib/fetch') 3 | 4 | module.exports = (fetch, config) => { 5 | return async (cid, options) => { 6 | options = options || {} 7 | 8 | const url = `${toUri(config.apiAddr)}/api/show/block?arg=${encodeURIComponent(cid)}` 9 | const res = await ok(fetch(url, { signal: options.signal })) 10 | const block = await res.json() 11 | 12 | if (Array.isArray(block.parents)) { 13 | block.parents = block.parents.map(p => p['/']) 14 | } 15 | 16 | if (block.stateRoot) { 17 | block.stateRoot = block.stateRoot['/'] 18 | } 19 | 20 | return block 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/cmd/stats/bandwidth.js: -------------------------------------------------------------------------------- 1 | const toUri = require('../../lib/multiaddr-to-uri') 2 | const { ok } = require('../../lib/fetch') 3 | const toCamel = require('../../lib/to-camel') 4 | 5 | module.exports = (fetch, config) => { 6 | return async options => { 7 | options = options || {} 8 | const url = `${toUri(config.apiAddr)}/api/stats/bandwidth` 9 | const res = await ok(fetch(url, { signal: options.signal })) 10 | return toCamel(await res.json()) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/cmd/swarm/connect.js: -------------------------------------------------------------------------------- 1 | const toUri = require('../../lib/multiaddr-to-uri') 2 | const { ok } = require('../../lib/fetch') 3 | const toCamel = require('../../lib/to-camel') 4 | 5 | module.exports = (fetch, config) => { 6 | return async (addrs, options) => { 7 | addrs = Array.isArray(addrs) ? addrs : [addrs] 8 | options = options || {} 9 | 10 | const qs = new URLSearchParams(options.qs) 11 | addrs.forEach(a => qs.append('arg', a.toString())) 12 | 13 | const url = `${toUri(config.apiAddr)}/api/swarm/connect?${qs}` 14 | const res = await ok(fetch(url, { signal: options.signal })) 15 | const data = await res.json() 16 | 17 | return (data || []).map(toCamel) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/cmd/swarm/peers.js: -------------------------------------------------------------------------------- 1 | const toUri = require('../../lib/multiaddr-to-uri') 2 | const { ok } = require('../../lib/fetch') 3 | const toCamel = require('../../lib/to-camel') 4 | 5 | module.exports = (fetch, config) => { 6 | return async options => { 7 | options = options || {} 8 | 9 | const qs = new URLSearchParams(options.qs) 10 | 11 | if (options.verbose) { 12 | qs.set('verbose', true) 13 | } else { 14 | if (options.streams) { 15 | qs.set('streams', true) 16 | } 17 | if (options.latency) { 18 | qs.set('latency', true) 19 | } 20 | } 21 | 22 | const url = `${toUri(config.apiAddr)}/api/swarm/peers?${qs}` 23 | const res = await ok(fetch(url, { signal: options.signal })) 24 | const data = await res.json() 25 | 26 | return (data.Peers || []).map(p => { 27 | const peerInfo = { addr: p.Addr, peer: p.Peer } 28 | 29 | if (options.verbose || options.streams) { 30 | peerInfo.streams = (p.Streams || []).map(toCamel) 31 | } 32 | 33 | if (options.verbose || options.latency) { 34 | peerInfo.latency = p.Latency 35 | } 36 | 37 | if (options.verbose) { 38 | peerInfo.muxer = p.Muxer 39 | } 40 | 41 | return peerInfo 42 | }) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/cmd/version.js: -------------------------------------------------------------------------------- 1 | const toUri = require('../lib/multiaddr-to-uri') 2 | const { ok } = require('../lib/fetch') 3 | const toCamel = require('../lib/to-camel') 4 | 5 | module.exports = (fetch, config) => { 6 | return async options => { 7 | options = options || {} 8 | const url = `${toUri(config.apiAddr)}/api/version` 9 | const res = await ok(fetch(url, { signal: options.signal })) 10 | return toCamel(await res.json()) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/cmd/wallet/balance.js: -------------------------------------------------------------------------------- 1 | const toUri = require('../../lib/multiaddr-to-uri') 2 | const { ok } = require('../../lib/fetch') 3 | 4 | module.exports = (fetch, config) => { 5 | return async (minerAddr, options) => { 6 | options = options || {} 7 | minerAddr = encodeURIComponent(minerAddr) 8 | const url = `${toUri(config.apiAddr)}/api/wallet/balance?arg=${minerAddr}` 9 | const res = await ok(fetch(url, { signal: options.signal })) 10 | return res.json() 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/cmd/wallet/export.js: -------------------------------------------------------------------------------- 1 | const toUri = require('../../lib/multiaddr-to-uri') 2 | const { ok } = require('../../lib/fetch') 3 | const toCamel = require('../../lib/to-camel') 4 | 5 | module.exports = (fetch, config) => { 6 | return async (minerAddr, options) => { 7 | minerAddr = Array.isArray(minerAddr) ? minerAddr : [minerAddr] 8 | options = options || {} 9 | 10 | const qs = new URLSearchParams(options.qs) 11 | minerAddr.forEach(a => qs.append('arg', a)) 12 | 13 | const url = `${toUri(config.apiAddr)}/api/wallet/export?${qs}` 14 | const res = await ok(fetch(url, { signal: options.signal })) 15 | 16 | return toCamel(await res.json()) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/cmd/wallet/import.js: -------------------------------------------------------------------------------- 1 | const toUri = require('../../lib/multiaddr-to-uri') 2 | const { ok } = require('../../lib/fetch') 3 | const toCamel = require('../../lib/to-camel') 4 | const FormData = require('form-data') 5 | 6 | module.exports = (fetch, config) => { 7 | return async (keyInfo, options) => { 8 | keyInfo = Array.isArray(keyInfo) ? keyInfo : [keyInfo] 9 | options = options || {} 10 | 11 | const form = new FormData() 12 | form.append('walletFile', JSON.stringify({ KeyInfo: keyInfo })) 13 | 14 | const url = `${toUri(config.apiAddr)}/api/wallet/import` 15 | const res = await ok(fetch(url, { 16 | signal: options.signal, 17 | method: 'POST', 18 | body: form 19 | })) 20 | 21 | return toCamel(await res.json()) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | module.exports = (fetch, config) => { 2 | if (typeof fetch !== 'function') { 3 | config = fetch 4 | fetch = null 5 | } 6 | 7 | fetch = fetch || require('./lib/fetch').fetch 8 | config = config || {} 9 | if (typeof config === 'string') config = { apiAddr: config } 10 | 11 | config.apiAddr = config.apiAddr || '/ip4/127.0.0.1/tcp/3453/http' 12 | 13 | return { 14 | actor: { 15 | ls: require('./cmd/actor/ls')(fetch, config) 16 | }, 17 | address: { 18 | default: require('./cmd/address/default')(fetch, config), 19 | lookup: require('./cmd/address/lookup')(fetch, config), 20 | ls: require('./cmd/address/ls')(fetch, config), 21 | new: require('./cmd/address/new')(fetch, config) 22 | }, 23 | bootstrap: { 24 | ls: require('./cmd/bootstrap/ls')(fetch, config) 25 | }, 26 | chain: { 27 | head: require('./cmd/chain/head')(fetch, config), 28 | ls: require('./cmd/chain/ls')(fetch, config) 29 | }, 30 | client: { 31 | cat: require('./cmd/client/cat')(fetch, config), 32 | import: require('./cmd/client/import')(fetch, config), 33 | listAsks: require('./cmd/client/list-asks')(fetch, config), 34 | payments: require('./cmd/client/payments')(fetch, config), 35 | proposeStorageDeal: require('./cmd/client/propose-storage-deal')(fetch, config), 36 | queryStorageDeal: require('./cmd/client/query-storage-deal')(fetch, config) 37 | }, 38 | config: { 39 | get: require('./cmd/config/get')(fetch, config), 40 | set: require('./cmd/config/set')(fetch, config) 41 | }, 42 | dag: { 43 | get: require('./cmd/dag/get')(fetch, config) 44 | }, 45 | dht: { 46 | findProvs: require('./cmd/dht/find-provs')(fetch, config), 47 | findPeer: require('./cmd/dht/find-peer')(fetch, config) 48 | }, 49 | id: require('./cmd/id')(fetch, config), 50 | log: { 51 | level: require('./cmd/log/level')(fetch, config), 52 | ls: require('./cmd/log/ls')(fetch, config), 53 | tail: require('./cmd/log/tail')(fetch, config) 54 | }, 55 | message: { 56 | wait: require('./cmd/message/wait')(fetch, config) 57 | }, 58 | miner: { 59 | create: require('./cmd/miner/create')(fetch, config) 60 | }, 61 | mining: { 62 | stop: require('./cmd/mining/stop')(fetch, config) 63 | }, 64 | ping: require('./cmd/ping')(fetch, config), 65 | retrievalClient: { 66 | retrievePiece: require('./cmd/retrieval-client/retrieve-piece')(fetch, config) 67 | }, 68 | show: { 69 | block: require('./cmd/show/block')(fetch, config) 70 | }, 71 | stats: { 72 | bandwidth: require('./cmd/stats/bandwidth')(fetch, config) 73 | }, 74 | swarm: { 75 | connect: require('./cmd/swarm/connect')(fetch, config), 76 | peers: require('./cmd/swarm/peers')(fetch, config) 77 | }, 78 | version: require('./cmd/version')(fetch, config), 79 | wallet: { 80 | balance: require('./cmd/wallet/balance')(fetch, config), 81 | export: require('./cmd/wallet/export')(fetch, config), 82 | import: require('./cmd/wallet/import')(fetch, config) 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/lib/fetch.js: -------------------------------------------------------------------------------- 1 | const explain = require('explain-error') 2 | 3 | exports.fetch = require('node-fetch') 4 | 5 | // Ensure fetch response is ok (200) 6 | // and if not, attempt to JSON parse body, extract error message and throw 7 | exports.ok = async res => { 8 | res = await res 9 | 10 | if (!res.ok) { 11 | const { status } = res 12 | const defaultMsg = `unexpected status ${status}` 13 | let msg 14 | try { 15 | let data = await res.text() 16 | try { 17 | data = JSON.parse(data) 18 | msg = data.message || data.Message 19 | } catch (err) { 20 | msg = data 21 | } 22 | } catch (err) { 23 | throw Object.assign(explain(err, defaultMsg), { status }) 24 | } 25 | throw Object.assign(new Error(msg || defaultMsg), { status }) 26 | } 27 | 28 | return res 29 | } 30 | 31 | exports.toIterable = body => { 32 | if (body[Symbol.asyncIterator]) return body 33 | 34 | if (body.getReader) { 35 | return (async function * () { 36 | const reader = body.getReader() 37 | 38 | try { 39 | while (true) { 40 | const { done, value } = await reader.read() 41 | if (done) return 42 | yield value 43 | } 44 | } finally { 45 | reader.releaseLock() 46 | } 47 | })() 48 | } 49 | 50 | throw new Error('unknown stream') 51 | } 52 | -------------------------------------------------------------------------------- /src/lib/form-data.browser.js: -------------------------------------------------------------------------------- 1 | /* eslint-env browser */ 2 | 3 | const isBuffer = require('is-buffer') 4 | 5 | exports.toFormData = async function toFormData (input) { 6 | // If not an async iterator, this must conform to whatever FormData allows 7 | if (!input[Symbol.asyncIterator]) { 8 | const formData = new FormData() 9 | formData.append('file', input) 10 | return formData 11 | } 12 | 13 | // In the browser there's _currently_ no streaming upload, buffer up our 14 | // async iterator chunks and append a big Blob :( 15 | 16 | // One day, this will be browser streams 17 | const formData = new FormData() 18 | const bufs = [] 19 | for await (const chunk of input) { 20 | bufs.push(isBuffer(chunk) ? chunk.buffer : chunk) 21 | } 22 | formData.append('file', new Blob(bufs)) 23 | return formData 24 | } 25 | -------------------------------------------------------------------------------- /src/lib/form-data.js: -------------------------------------------------------------------------------- 1 | const toStream = require('it-to-stream') 2 | const FormData = require('form-data') 3 | 4 | exports.toFormData = async function toFormData (input) { 5 | // If not an async iterator, this must conform to whatever FormData allows 6 | if (!input[Symbol.asyncIterator]) { 7 | const formData = new FormData() 8 | formData.append('file', input) 9 | return formData 10 | } 11 | 12 | // In Node.js, FormData can be passed a stream so no need to buffer 13 | const formData = new FormData() 14 | 15 | formData.append( 16 | 'file', 17 | // FIXME: add a `path` property to the stream so `form-data` doesn't set 18 | // a Content-Length header that is only the sum of the size of the 19 | // header/footer when knownLength option (below) is null. 20 | Object.assign( 21 | toStream(input), 22 | { path: input.path || 'file' } 23 | ), 24 | { 25 | filepath: input.path, 26 | contentType: 'application/octet-stream', 27 | knownLength: input.length // Send Content-Length header if known 28 | } 29 | ) 30 | 31 | return formData 32 | } 33 | -------------------------------------------------------------------------------- /src/lib/multiaddr-to-uri.js: -------------------------------------------------------------------------------- 1 | module.exports = ma => { 2 | const parts = `${ma}`.split('/') 3 | const port = getPort(parts) 4 | return `${getProtocol(parts)}://${parts[2]}${port == null ? '' : ':' + port}` 5 | } 6 | 7 | function getProtocol (maParts) { 8 | return maParts.indexOf('https') === -1 ? 'http' : 'https' 9 | } 10 | 11 | function getPort (maParts) { 12 | const tcpIndex = maParts.indexOf('tcp') 13 | return tcpIndex === -1 ? null : maParts[tcpIndex + 1] 14 | } 15 | -------------------------------------------------------------------------------- /src/lib/to-camel.js: -------------------------------------------------------------------------------- 1 | // Convert object properties to camel case. 2 | // NOT recursive! 3 | // e.g. 4 | // AgentVersion => agentVersion 5 | // ID => id 6 | module.exports = obj => { 7 | if (obj == null) return obj 8 | const caps = /^[A-Z]+$/ 9 | return Object.keys(obj).reduce((camelObj, k) => { 10 | if (caps.test(k)) { // all caps 11 | camelObj[k.toLowerCase()] = obj[k] 12 | } else if (caps.test(k[0])) { // pascal 13 | camelObj[k[0].toLowerCase() + k.slice(1)] = obj[k] 14 | } else { 15 | camelObj[k] = obj[k] 16 | } 17 | return camelObj 18 | }, {}) 19 | } 20 | -------------------------------------------------------------------------------- /test/e2e/_warn.js: -------------------------------------------------------------------------------- 1 | if (!process.env.FILECOIN_API_ADDR) { 2 | console.warn('WARNING: using default API address for testing, use FILECOIN_API_ADDR environment variable to override.') 3 | } 4 | -------------------------------------------------------------------------------- /test/e2e/actor/ls.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../helpers/filecoin') 3 | 4 | test('should list actors', async t => { 5 | const fc = Filecoin() 6 | 7 | let actor 8 | for await (actor of fc.actor.ls()) break 9 | t.truthy(actor) 10 | }) 11 | -------------------------------------------------------------------------------- /test/e2e/address/default.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../helpers/filecoin') 3 | 4 | test('should fetch default address', async t => { 5 | const fc = Filecoin() 6 | 7 | const addr = await fc.address.default() 8 | t.true(typeof addr === 'string') 9 | }) 10 | -------------------------------------------------------------------------------- /test/e2e/address/lookup.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../helpers/filecoin') 3 | 4 | // TODO: why can't we lookup ourself? 5 | test.skip('should lookup own address', async t => { 6 | const fc = Filecoin() 7 | const { addresses } = await fc.address.ls() 8 | const res = await fc.address.lookup(addresses[0]) 9 | t.truthy(res) 10 | }) 11 | -------------------------------------------------------------------------------- /test/e2e/address/ls.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../helpers/filecoin') 3 | 4 | test('should list addresses', async t => { 5 | const fc = Filecoin() 6 | const addresses = await fc.address.ls() 7 | t.true(Array.isArray(addresses)) 8 | addresses.forEach(a => t.true(typeof a === 'string')) 9 | }) 10 | -------------------------------------------------------------------------------- /test/e2e/address/new.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../helpers/filecoin') 3 | 4 | test('should create new address', async t => { 5 | const fc = Filecoin() 6 | 7 | const addr = await fc.address.new() 8 | t.true(typeof addr === 'string') 9 | }) 10 | -------------------------------------------------------------------------------- /test/e2e/bootstrap/ls.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Multiaddr = require('multiaddr') 3 | const Filecoin = require('../helpers/filecoin') 4 | 5 | test('should list bootstrap node addresses', async t => { 6 | const fc = Filecoin() 7 | 8 | const addrs = await fc.bootstrap.ls() 9 | t.true(Array.isArray(addrs)) 10 | addrs.forEach(a => t.notThrows(() => Multiaddr(a))) 11 | }) 12 | -------------------------------------------------------------------------------- /test/e2e/chain/head.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const CID = require('cids') 3 | const Filecoin = require('../helpers/filecoin') 4 | 5 | test('should get chain heads', async t => { 6 | const fc = Filecoin() 7 | 8 | const heads = await fc.chain.head('fcqqr00e38ge3vr90xx7x46gj7hq3dxcl09us08e') 9 | t.true(Array.isArray(heads)) 10 | heads.forEach(h => t.notThrows(() => new CID(h))) 11 | }) 12 | -------------------------------------------------------------------------------- /test/e2e/chain/ls.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../helpers/filecoin') 3 | 4 | test('should get blockchain', async t => { 5 | const fc = Filecoin() 6 | 7 | let block 8 | for await (block of fc.chain.ls()) break 9 | t.true(Array.isArray(block)) 10 | block.forEach(b => t.true(typeof block[0].miner === 'string')) 11 | }) 12 | -------------------------------------------------------------------------------- /test/e2e/client/import.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const { randomBytes } = require('crypto') 3 | const CID = require('cids') 4 | const Filecoin = require('../helpers/filecoin') 5 | const { toAsyncIterable } = require('../../helpers/iterable') 6 | 7 | test('should import a buffer', async t => { 8 | const fc = Filecoin() 9 | const input = randomBytes(256) 10 | 11 | const cid = await fc.client.import(input) 12 | t.notThrows(() => new CID(cid)) 13 | 14 | let output = Buffer.alloc(0) 15 | for await (const chunk of fc.client.cat(cid)) { 16 | output = Buffer.concat([output, chunk]) 17 | } 18 | 19 | t.deepEqual(output, input) 20 | }) 21 | 22 | test('should import an async iterable', async t => { 23 | const fc = Filecoin() 24 | const input = [randomBytes(256), randomBytes(32), randomBytes(512)] 25 | 26 | const cid = await fc.client.import(toAsyncIterable(input)) 27 | t.notThrows(() => new CID(cid)) 28 | 29 | let output = Buffer.alloc(0) 30 | for await (const chunk of fc.client.cat(cid)) { 31 | output = Buffer.concat([output, chunk]) 32 | } 33 | 34 | t.deepEqual(output, Buffer.concat(input)) 35 | }) 36 | -------------------------------------------------------------------------------- /test/e2e/client/list-asks.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../helpers/filecoin') 3 | 4 | test('should list asks', async t => { 5 | const fc = Filecoin() 6 | 7 | let i = 0 8 | for await (const ask of fc.client.listAsks()) { 9 | if (!ask.error) { 10 | t.true(typeof ask.id === 'number') 11 | t.true(typeof ask.miner === 'string') 12 | t.true(typeof ask.price === 'string') 13 | t.true(typeof ask.expiry === 'number') 14 | } 15 | if (i++ >= 5) break 16 | } 17 | }) 18 | -------------------------------------------------------------------------------- /test/e2e/config/get.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Multiaddr = require('multiaddr') 3 | const Filecoin = require('../helpers/filecoin') 4 | 5 | test('should get config value', async t => { 6 | const fc = Filecoin() 7 | const res = await fc.config.get('bootstrap.addresses') 8 | 9 | t.true(Array.isArray(res)) 10 | res.forEach(addr => t.notThrows(() => Multiaddr(addr))) 11 | }) 12 | -------------------------------------------------------------------------------- /test/e2e/config/set.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../helpers/filecoin') 3 | 4 | test('should set config value', async t => { 5 | const fc = Filecoin() 6 | 7 | const methods = await fc.config.get('api.accessControlAllowMethods') 8 | const nextMethods = methods.concat(`TEST${Date.now()}`) 9 | 10 | const res = await fc.config.set('api.accessControlAllowMethods', nextMethods) 11 | 12 | t.deepEqual(res, nextMethods) 13 | t.deepEqual(await fc.config.get('api.accessControlAllowMethods'), nextMethods) 14 | 15 | // Clean up! 16 | await fc.config.set('api.accessControlAllowMethods', methods) 17 | }) 18 | -------------------------------------------------------------------------------- /test/e2e/dag/get.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const { randomBytes } = require('crypto') 3 | const CID = require('cids') 4 | const UnixFs = require('ipfs-unixfs') 5 | const Filecoin = require('../helpers/filecoin') 6 | 7 | test('should get a DAG node', async t => { 8 | const fc = Filecoin() 9 | const input = randomBytes(256) 10 | 11 | const cid = await fc.client.import(input) 12 | t.notThrows(() => new CID(cid)) 13 | 14 | const node = await fc.dag.get(cid) 15 | const meta = UnixFs.unmarshal(Buffer.from(node.data, 'base64')) 16 | 17 | t.deepEqual(meta.data, input) 18 | }) 19 | -------------------------------------------------------------------------------- /test/e2e/dht/find-provs.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const CID = require('cids') 3 | const Multiaddr = require('multiaddr') 4 | const { randomBytes } = require('crypto') 5 | const Filecoin = require('../helpers/filecoin') 6 | 7 | test('should find providers', async t => { 8 | const fc = Filecoin() 9 | 10 | const input = randomBytes(256) 11 | const cid = await fc.client.import(input) 12 | 13 | for await (const peer of fc.dht.findProvs(cid, { numProviders: 1 })) { 14 | if (peer.id) { 15 | t.notThrows(() => new CID(peer.id)) 16 | } 17 | 18 | t.true(typeof peer.type === 'number') 19 | 20 | peer.responses.forEach((r, j) => { 21 | t.notThrows(() => new CID(r.id)) 22 | 23 | r.addrs.forEach((a, k) => { 24 | t.notThrows(() => Multiaddr(a)) 25 | }) 26 | }) 27 | 28 | if (peer.extra) { 29 | t.true(typeof peer.extra === 'string') 30 | } 31 | } 32 | }) 33 | -------------------------------------------------------------------------------- /test/e2e/helpers/faucet.js: -------------------------------------------------------------------------------- 1 | const toUri = require('../../../src/lib/multiaddr-to-uri') 2 | const fetch = require('node-fetch') 3 | const FormData = require('form-data') 4 | const CID = require('cids') 5 | 6 | const TAP_ADDR = '/dns4/user.kittyhawk.wtf/tcp/9797/http' 7 | 8 | module.exports = async (walletAddr, options) => { 9 | options = options || {} 10 | 11 | const body = new FormData() 12 | body.append('target', walletAddr) 13 | 14 | const res = await fetch(`${toUri(options.tapAddr || TAP_ADDR)}/tap`, { 15 | method: 'POST', 16 | body, 17 | signal: options.signal 18 | }) 19 | 20 | if (!res.ok) { 21 | throw new Error(`Unexpected status: ${res.status}`) 22 | } 23 | 24 | const text = await res.text() 25 | 26 | if (!text.includes('Success! Message CID: ')) { 27 | throw new Error('Unexpected response: ' + text) 28 | } 29 | 30 | return new CID(text.trim().replace('Success! Message CID: ', '')) 31 | } 32 | -------------------------------------------------------------------------------- /test/e2e/helpers/filecoin.js: -------------------------------------------------------------------------------- 1 | const Filecoin = require('../../../src') 2 | 3 | module.exports = () => Filecoin({ apiAddr: process.env.FILECOIN_API_ADDR }) 4 | -------------------------------------------------------------------------------- /test/e2e/id.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const CID = require('cids') 3 | const Filecoin = require('./helpers/filecoin') 4 | 5 | test('should get id', async t => { 6 | const fc = Filecoin() 7 | const res = await fc.id() 8 | 9 | t.notThrows(() => new CID(res.id)) 10 | t.true(Array.isArray(res.addresses)) 11 | }) 12 | -------------------------------------------------------------------------------- /test/e2e/log/level.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../helpers/filecoin') 3 | 4 | test('should set the log level for all subsystems', async t => { 5 | const fc = Filecoin() 6 | 7 | let res 8 | res = await fc.log.level('error') 9 | t.is(res, 'Changed log level of all subsystems to: error') 10 | 11 | res = await fc.log.level('warning') 12 | t.is(res, 'Changed log level of all subsystems to: warning') 13 | 14 | res = await fc.log.level('info') 15 | t.is(res, 'Changed log level of all subsystems to: info') 16 | }) 17 | 18 | test('should set the log level for a specific subsystem', async t => { 19 | const fc = Filecoin() 20 | 21 | let res 22 | res = await fc.log.level('error', { subsystem: 'ping' }) 23 | t.is(res, 'Changed log level of \'ping\' to \'error\'') 24 | 25 | res = await fc.log.level('warning', { subsystem: 'ping' }) 26 | t.is(res, 'Changed log level of \'ping\' to \'warning\'') 27 | 28 | res = await fc.log.level('info', { subsystem: 'ping' }) 29 | t.is(res, 'Changed log level of \'ping\' to \'info\'') 30 | }) 31 | 32 | test('should error for unknown log level', async t => { 33 | const fc = Filecoin() 34 | const err = await t.throwsAsync(fc.log.level('foo')) 35 | t.is(err.message, 'unknown log level: foo. Available levels: debug, info, warning, error, fatal, panic') 36 | }) 37 | 38 | test('should error for unknown subsystem', async t => { 39 | const fc = Filecoin() 40 | const err = await t.throwsAsync(fc.log.level('info', { subsystem: 'foo' })) 41 | t.is(err.message, 'Error: No such logger') 42 | }) 43 | -------------------------------------------------------------------------------- /test/e2e/log/ls.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../helpers/filecoin') 3 | 4 | test('should list logging subsystems', async t => { 5 | const fc = Filecoin() 6 | const subsystems = await fc.log.ls() 7 | t.true(Array.isArray(subsystems)) 8 | subsystems.forEach(a => t.true(typeof a === 'string')) 9 | }) 10 | -------------------------------------------------------------------------------- /test/e2e/log/tail.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../helpers/filecoin') 3 | 4 | test('should tail the log', async t => { 5 | const fc = Filecoin() 6 | 7 | let i = 0 8 | for await (const entry of fc.log.tail()) { 9 | t.truthy(entry) 10 | i++ 11 | if (i > 2) break // Stream 3 log entries 12 | } 13 | }) 14 | -------------------------------------------------------------------------------- /test/e2e/miner/create.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const AbortController = require('abort-controller') 3 | const Filecoin = require('../helpers/filecoin') 4 | const faucet = require('../helpers/faucet') 5 | 6 | // FIXME: miner.create can only be called once, so e2e tests need to be changed 7 | // to spin up a new filecoin node for this test 8 | // https://github.com/filecoin-shipyard/js-filecoin-api-client/issues/69 9 | test.skip('should create a miner', async t => { 10 | const fc = Filecoin() 11 | 12 | const controller = new AbortController() 13 | const abortTimeout = setTimeout(() => controller.abort(), 5 * 60 * 1000) 14 | 15 | try { 16 | const walletAddr = await fc.address.new() 17 | const messageCid = await faucet(walletAddr) 18 | 19 | console.log('waiting for message ' + messageCid) 20 | 21 | await fc.message.wait(messageCid, { signal: controller.signal }) 22 | 23 | console.log('creating miner') 24 | 25 | const collateral = 100 26 | const res = await fc.miner.create(collateral, { 27 | gasPrice: 0.1, 28 | gasLimit: 300, 29 | from: walletAddr, 30 | signal: controller.signal 31 | }) 32 | console.log(JSON.stringify(res, null, 2)) 33 | clearTimeout(abortTimeout) 34 | } catch (err) { 35 | if (err.name !== 'AbortError') throw err 36 | console.warn('skipping "should create a miner" due to timeout') 37 | t.pass() 38 | } 39 | }) 40 | -------------------------------------------------------------------------------- /test/e2e/mining/stop.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../helpers/filecoin') 3 | 4 | test('should stop the mining', async t => { 5 | const fc = Filecoin() 6 | const msg = await fc.mining.stop() 7 | t.is(msg, 'Stopped mining') 8 | }) 9 | -------------------------------------------------------------------------------- /test/e2e/ping.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('./helpers/filecoin') 3 | 4 | test('should ping a peer', async t => { 5 | const fc = Filecoin() 6 | 7 | let peers 8 | while (true) { 9 | peers = await fc.swarm.peers() 10 | if (peers.length) break 11 | } 12 | 13 | const peerId = peers[0].addr.getPeerId() 14 | 15 | let i = 0 16 | for await (const pong of fc.ping(peerId, { count: 2 })) { 17 | t.false(Number.isNaN(pong.time)) 18 | t.is(pong.count, i) 19 | i++ 20 | } 21 | }) 22 | -------------------------------------------------------------------------------- /test/e2e/show/block.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const CID = require('cids') 3 | const Filecoin = require('../helpers/filecoin') 4 | 5 | test('should show block info', async t => { 6 | const fc = Filecoin() 7 | const [cid] = await fc.chain.head() 8 | const block = await fc.show.block(cid) 9 | 10 | t.truthy(block) 11 | t.notThrows(() => new CID(block.stateRoot)) 12 | }) 13 | -------------------------------------------------------------------------------- /test/e2e/stats/bandwidth.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../helpers/filecoin') 3 | 4 | test('should get bandwidth stats', async t => { 5 | const fc = Filecoin() 6 | 7 | const stats = await fc.stats.bandwidth() 8 | 9 | t.true(typeof stats.totalIn === 'number') 10 | t.true(typeof stats.totalOut === 'number') 11 | t.true(typeof stats.rateIn === 'number') 12 | t.true(typeof stats.rateOut === 'number') 13 | }) 14 | -------------------------------------------------------------------------------- /test/e2e/swarm/peers.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Multiaddr = require('multiaddr') 3 | const Filecoin = require('../helpers/filecoin') 4 | 5 | test('should list swarm peers', async t => { 6 | const fc = Filecoin() 7 | const peers = await fc.swarm.peers() 8 | 9 | t.true(Array.isArray(peers)) 10 | peers.forEach(p => t.notThrows(() => Multiaddr(p.addr))) 11 | }) 12 | -------------------------------------------------------------------------------- /test/e2e/version.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('./helpers/filecoin') 3 | 4 | test('should get version', async t => { 5 | const fc = Filecoin() 6 | const res = await fc.version() 7 | 8 | t.true(typeof res.commit === 'string') 9 | }) 10 | -------------------------------------------------------------------------------- /test/e2e/wallet/balance.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../helpers/filecoin') 3 | 4 | test('should get wallet balance', async t => { 5 | const fc = Filecoin() 6 | const addresses = await fc.address.ls() 7 | const balance = await fc.wallet.balance(addresses[0]) 8 | t.false(isNaN(parseInt(balance))) 9 | }) 10 | -------------------------------------------------------------------------------- /test/e2e/wallet/export.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../helpers/filecoin') 3 | 4 | test('should export a wallet', async t => { 5 | const fc = Filecoin() 6 | const addresses = await fc.address.ls() 7 | const data = await fc.wallet.export(addresses[0]) 8 | 9 | t.truthy(data.keyInfo) 10 | t.true(Array.isArray(data.keyInfo)) 11 | t.is(data.keyInfo.length, 1) 12 | 13 | data.keyInfo.forEach(k => { 14 | t.true(typeof k.privateKey === 'string') 15 | t.true(typeof k.curve === 'string') 16 | }) 17 | }) 18 | 19 | test('should export multiple wallets', async t => { 20 | const fc = Filecoin() 21 | 22 | // Ensure more than one 23 | await fc.address.new() 24 | const addresses = await fc.address.ls() 25 | const data = await fc.wallet.export(addresses) 26 | 27 | t.truthy(data.keyInfo) 28 | t.true(Array.isArray(data.keyInfo)) 29 | t.is(data.keyInfo.length, addresses.length) 30 | 31 | data.keyInfo.forEach(k => { 32 | t.true(typeof k.privateKey === 'string') 33 | t.true(typeof k.curve === 'string') 34 | }) 35 | }) 36 | -------------------------------------------------------------------------------- /test/e2e/wallet/import.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../helpers/filecoin') 3 | 4 | test('should import a wallet', async t => { 5 | const fc = Filecoin() 6 | const addresses = await fc.address.ls() 7 | const data = await fc.wallet.export(addresses[0]) 8 | 9 | t.truthy(data.keyInfo) 10 | t.true(Array.isArray(data.keyInfo)) 11 | 12 | const res = await fc.wallet.import(data.keyInfo) 13 | console.log(res.addresses) 14 | t.true(Array.isArray(res.addresses)) 15 | }) 16 | 17 | test('should import multiple wallets', async t => { 18 | const fc = Filecoin() 19 | 20 | // Ensure more than one 21 | await fc.address.new() 22 | const addresses = await fc.address.ls() 23 | const data = await fc.wallet.export(addresses) 24 | 25 | const res = await fc.wallet.import(data.keyInfo) 26 | t.truthy(res.addresses) 27 | t.true(Array.isArray(res.addresses)) 28 | t.is(res.addresses.length, data.keyInfo.length) 29 | }) 30 | -------------------------------------------------------------------------------- /test/helpers/iterable.js: -------------------------------------------------------------------------------- 1 | exports.toAsyncIterable = array => { 2 | array = Array.from(array) 3 | return { 4 | [Symbol.asyncIterator] () { 5 | return this 6 | }, 7 | async next () { 8 | await new Promise(resolve => setTimeout(resolve)) 9 | return array.length 10 | ? { done: false, value: array.shift() } 11 | : { done: true } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/unit/cmd/actor/ls.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const CID = require('cids') 3 | const Filecoin = require('../../../../src') 4 | const { toAsyncIterable } = require('../../../helpers/iterable') 5 | 6 | test('should list actors', async t => { 7 | const fetch = () => ({ ok: true, body: toAsyncIterable(['{}\n{}']) }) 8 | const fc = Filecoin(fetch) 9 | 10 | for await (const actor of fc.actor.ls()) { 11 | t.truthy(actor) 12 | } 13 | }) 14 | 15 | test('should throw on invalid actor', async t => { 16 | const fetch = () => ({ ok: true, body: toAsyncIterable(['{}\n{']) }) 17 | const fc = Filecoin(fetch) 18 | 19 | try { 20 | for await (const actor of fc.actor.ls()) { 21 | t.truthy(actor) 22 | } 23 | } catch (err) { 24 | return t.pass() 25 | } 26 | t.fail() 27 | }) 28 | 29 | test('should deserialize actor head CID', async t => { 30 | const expectedActors = [{ 31 | head: { '/': 'zDPWYqFD8NrAiH9oxT3PT53TEMeZdkURTrHJXS6ymqqR1z9fCaVe' } 32 | }] 33 | const fetch = () => ({ 34 | ok: true, 35 | body: toAsyncIterable([expectedActors.map(a => JSON.stringify(a)).join('\n')]) 36 | }) 37 | const fc = Filecoin(fetch) 38 | 39 | const actors = [] 40 | for await (const actor of fc.actor.ls()) actors.push(actor) 41 | 42 | expectedActors.forEach((expectedActor, i) => { 43 | t.notThrows(() => new CID(actors[i].head)) 44 | t.is(actors[i].head.toString(), expectedActor.head['/']) 45 | }) 46 | }) 47 | 48 | test('should deserialize actor code CID', async t => { 49 | const expectedActors = [{ 50 | code: { '/': 'zb2rhe71ud5XjA2RaFk2esBaQcD51EjKRLFP2yrB7Yq2WoiZ3' } 51 | }] 52 | const fetch = () => ({ 53 | ok: true, 54 | body: toAsyncIterable([expectedActors.map(a => JSON.stringify(a)).join('\n')]) 55 | }) 56 | const fc = Filecoin(fetch) 57 | 58 | const actors = [] 59 | for await (const actor of fc.actor.ls()) actors.push(actor) 60 | 61 | expectedActors.forEach((expectedActor, i) => { 62 | t.notThrows(() => new CID(actors[i].code)) 63 | t.is(actors[i].code.toString(), expectedActor.code['/']) 64 | }) 65 | }) 66 | 67 | test('should throw on request error', async t => { 68 | const message = `BOOM${Date.now()}` 69 | const fetch = () => ({ ok: false, text: () => JSON.stringify({ message }) }) 70 | const fc = Filecoin(fetch) 71 | 72 | try { 73 | for await (const _ of fc.actor.ls()) { // eslint-disable-line 74 | t.fail() 75 | } 76 | } catch (err) { 77 | return t.is(err.message, message) 78 | } 79 | t.fail() 80 | }) 81 | -------------------------------------------------------------------------------- /test/unit/cmd/address/default.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../../../../src') 3 | 4 | test('should fetch default miner address', async t => { 5 | const expectedAddr = 't1gwlbykvhfrkhrtll43ceiyzgggk7omnololcwpy' 6 | const fetch = () => ({ ok: true, json: () => ({ Address: expectedAddr }) }) 7 | const fc = Filecoin(fetch) 8 | 9 | const addr = await fc.address.default() 10 | t.is(addr, expectedAddr) 11 | }) 12 | 13 | test('should throw on request error', async t => { 14 | const message = `BOOM${Date.now()}` 15 | const fetch = () => ({ ok: false, text: () => JSON.stringify({ message }) }) 16 | const fc = Filecoin(fetch) 17 | 18 | try { 19 | await fc.address.default() 20 | } catch (err) { 21 | return t.is(err.message, message) 22 | } 23 | t.fail() 24 | }) 25 | -------------------------------------------------------------------------------- /test/unit/cmd/address/lookup.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../../../../src') 3 | 4 | test('should throw on request error', async t => { 5 | const message = `BOOM${Date.now()}` 6 | const fetch = () => ({ ok: false, text: () => JSON.stringify({ message }) }) 7 | const fc = Filecoin(fetch) 8 | 9 | try { 10 | await fc.address.lookup('fcq6qjh02udcv4yv7astq6t9npamq2t5jh8lpa533') 11 | } catch (err) { 12 | return t.is(err.message, message) 13 | } 14 | t.fail() 15 | }) 16 | -------------------------------------------------------------------------------- /test/unit/cmd/address/ls.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../../../../src') 3 | 4 | test('should list miner addresses', async t => { 5 | const expectedAddrs = [ 6 | 'fcqqr00e38ge3vr90xx7x46gj7hq3dxcl09us08e', 7 | 'fcq6pg4anvwxrz27c5zxkm3n2qf6yqmxqfnny0jqk', 8 | 'fcqntxtj4786kfcv0ncfpndr5tucxjnpwt8qda8rd', 9 | 'fcq6qjh02udcv4yv7astq6t9npamq2t5jh8lpa533' 10 | ] 11 | const fetch = () => ({ 12 | ok: true, 13 | json: () => ({ Addresses: expectedAddrs }) 14 | }) 15 | const fc = Filecoin(fetch) 16 | 17 | const addresses = await fc.address.ls() 18 | t.deepEqual(addresses, expectedAddrs) 19 | }) 20 | 21 | test('should throw on request error', async t => { 22 | const message = `BOOM${Date.now()}` 23 | const fetch = () => ({ ok: false, text: () => JSON.stringify({ message }) }) 24 | const fc = Filecoin(fetch) 25 | 26 | try { 27 | await fc.address.ls() 28 | } catch (err) { 29 | return t.is(err.message, message) 30 | } 31 | t.fail() 32 | }) 33 | -------------------------------------------------------------------------------- /test/unit/cmd/address/new.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../../../../src') 3 | 4 | test('should create new miner address', async t => { 5 | const expectedAddr = 'fcq6pg4anvwxrz27c5zxkm3n2qf6yqmxqfnny0jqk' 6 | const fetch = () => ({ ok: true, json: () => ({ Address: expectedAddr }) }) 7 | const fc = Filecoin(fetch) 8 | 9 | const addr = await fc.address.new() 10 | t.is(addr, expectedAddr) 11 | }) 12 | 13 | test('should throw on request error', async t => { 14 | const message = `BOOM${Date.now()}` 15 | const fetch = () => ({ ok: false, text: () => JSON.stringify({ message }) }) 16 | const fc = Filecoin(fetch) 17 | 18 | try { 19 | await fc.address.new() 20 | } catch (err) { 21 | return t.is(err.message, message) 22 | } 23 | t.fail() 24 | }) 25 | -------------------------------------------------------------------------------- /test/unit/cmd/bootstrap/ls.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../../../../src') 3 | 4 | test('should list bootstrap node addresses', async t => { 5 | const expectedAddrs = [ 6 | '/dns4/test.kittyhawk.wtf/tcp/9001/ipfs/QmXq6XEYeEmUzBFuuKbVEGgxEpVD4xbSkG2Rhek6zkFMp4', 7 | '/dns4/test.kittyhawk.wtf/tcp/9002/ipfs/QmXhxqTKzBKHA5FcMuiKZv8YaMPwpbKGXHRVZcFB2DX9XY', 8 | '/dns4/test.kittyhawk.wtf/tcp/9003/ipfs/QmZGDLdQLUTi7uYTNavKwCd7SBc5KMfxzWxAyvqRQvwuiV', 9 | '/dns4/test.kittyhawk.wtf/tcp/9004/ipfs/QmZRnwmCjyNHgeNDiyT8mXRtGhP6uSzgHtrozc42crmVbg' 10 | ] 11 | const fetch = () => ({ ok: true, json: () => ({ Peers: expectedAddrs }) }) 12 | const fc = Filecoin(fetch) 13 | 14 | const addrs = await fc.bootstrap.ls() 15 | t.deepEqual(addrs.map(a => a.toString()), expectedAddrs) 16 | }) 17 | 18 | test('should throw on request error', async t => { 19 | const message = `BOOM${Date.now()}` 20 | const fetch = () => ({ ok: false, text: () => JSON.stringify({ message }) }) 21 | const fc = Filecoin(fetch) 22 | 23 | try { 24 | await fc.bootstrap.ls() 25 | } catch (err) { 26 | return t.is(err.message, message) 27 | } 28 | t.fail() 29 | }) 30 | -------------------------------------------------------------------------------- /test/unit/cmd/chain/head.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../../../../src') 3 | 4 | test('should get chain heads', async t => { 5 | const expectedCids = ['zDPWYqFCrhCRdGa1Z84DBpSQ5rrHphwjs7qHe5uS2LFurdnE6vvF'] 6 | const fetch = () => ({ 7 | ok: true, 8 | json: () => expectedCids.map(cid => ({ '/': cid })) 9 | }) 10 | const fc = Filecoin(fetch) 11 | 12 | const heads = await fc.chain.head('fcqqr00e38ge3vr90xx7x46gj7hq3dxcl09us08e') 13 | t.deepEqual(heads.map(cid => cid.toString()), expectedCids) 14 | }) 15 | 16 | test('should throw on request error', async t => { 17 | const message = `BOOM${Date.now()}` 18 | const fetch = () => ({ ok: false, text: () => JSON.stringify({ message }) }) 19 | const fc = Filecoin(fetch) 20 | 21 | try { 22 | await fc.chain.head() 23 | } catch (err) { 24 | return t.is(err.message, message) 25 | } 26 | t.fail() 27 | }) 28 | -------------------------------------------------------------------------------- /test/unit/cmd/chain/ls.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const CID = require('cids') 3 | const Filecoin = require('../../../../src') 4 | const { toAsyncIterable } = require('../../../helpers/iterable') 5 | 6 | test('should get blockchain', async t => { 7 | const expectedBlocks = [ 8 | [{ miner: 'fcq5y65n23xdkcx2ymakflxpxqhkvewnwswp0me52' }], 9 | [{ miner: 'fcq9vwjadr749mnnndadqwxedrpuewnx09qe23atk' }] 10 | ] 11 | const fetch = () => ({ 12 | ok: true, 13 | body: toAsyncIterable([expectedBlocks.map(b => JSON.stringify(b)).join('\n')]) 14 | }) 15 | const fc = Filecoin(fetch) 16 | 17 | const blocks = [] 18 | for await (const block of fc.chain.ls()) blocks.push(block) 19 | t.deepEqual(blocks, expectedBlocks) 20 | }) 21 | 22 | test('should deserialize parent CIDs', async t => { 23 | const expectedBlocks = [ 24 | [{ 25 | miner: 'fcq5y65n23xdkcx2ymakflxpxqhkvewnwswp0me52', 26 | parents: [{ '/': 'zDPWYqFD2UfFjGbkQcfVX5BM75Wr1xQTBoKpwMBKgYZcBCdPw7Au' }] 27 | }] 28 | ] 29 | const fetch = () => ({ 30 | ok: true, 31 | body: toAsyncIterable([expectedBlocks.map(b => JSON.stringify(b)).join('\n')]) 32 | }) 33 | const fc = Filecoin(fetch) 34 | 35 | const blocks = [] 36 | for await (const block of fc.chain.ls()) blocks.push(block) 37 | 38 | expectedBlocks.forEach((expectedBlock, i) => { 39 | expectedBlock.forEach((expectedHead, j) => { 40 | expectedHead.parents.forEach((expectedParent, k) => { 41 | t.notThrows(() => new CID(blocks[i][j].parents[k])) 42 | t.is(blocks[i][j].parents[k].toString(), expectedParent['/']) 43 | }) 44 | }) 45 | }) 46 | }) 47 | 48 | test('should deserialize state root CID', async t => { 49 | const expectedBlocks = [ 50 | [{ 51 | miner: 'fcq5y65n23xdkcx2ymakflxpxqhkvewnwswp0me52', 52 | stateRoot: { '/': 'zdpuAvER9XYSRZFk8HJxmAp8qTTiaqPDk3ZtBg8bPmmTE8HBV' } 53 | }] 54 | ] 55 | const fetch = () => ({ 56 | ok: true, 57 | body: toAsyncIterable([expectedBlocks.map(b => JSON.stringify(b)).join('\n')]) 58 | }) 59 | const fc = Filecoin(fetch) 60 | 61 | const blocks = [] 62 | for await (const block of fc.chain.ls()) blocks.push(block) 63 | 64 | expectedBlocks.forEach((expectedBlock, i) => { 65 | expectedBlock.forEach((expectedHead, j) => { 66 | t.notThrows(() => new CID(blocks[i][j].stateRoot)) 67 | t.is(blocks[i][j].stateRoot.toString(), expectedHead.stateRoot['/']) 68 | }) 69 | }) 70 | }) 71 | 72 | test('should throw on request error', async t => { 73 | const message = `BOOM${Date.now()}` 74 | const fetch = () => ({ ok: false, text: () => JSON.stringify({ message }) }) 75 | const fc = Filecoin(fetch) 76 | 77 | try { 78 | for await (const _ of fc.chain.ls()) { // eslint-disable-line 79 | t.fail() 80 | } 81 | } catch (err) { 82 | return t.is(err.message, message) 83 | } 84 | t.fail() 85 | }) 86 | -------------------------------------------------------------------------------- /test/unit/cmd/client/cat.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const { randomBytes } = require('crypto') 3 | const CID = require('cids') 4 | const Filecoin = require('../../../../src') 5 | const { toAsyncIterable } = require('../../../helpers/iterable') 6 | 7 | test('should cat a file with CID string', async t => { 8 | const cid = 'QmZPUUg1QVMciR1yYnC2HSFrXyAUwRvpnbx4haYefB2KY3' 9 | const chunks = [randomBytes(2048), randomBytes(512), randomBytes(256)] 10 | const fetch = () => ({ ok: true, body: toAsyncIterable(chunks) }) 11 | const fc = Filecoin(fetch) 12 | 13 | let data = Buffer.alloc(0) 14 | for await (const chunk of fc.client.cat(cid)) { 15 | data = Buffer.concat([data, chunk]) 16 | } 17 | 18 | t.deepEqual(data, Buffer.concat(chunks)) 19 | }) 20 | 21 | test('should cat a file with CID instance', async t => { 22 | const cid = new CID('QmZPUUg1QVMciR1yYnC2HSFrXyAUwRvpnbx4haYefB2KY3') 23 | const chunks = [randomBytes(2048), randomBytes(512), randomBytes(256)] 24 | const fetch = url => { 25 | url = new URL(url) 26 | // Ensure the CID was encoded properly 27 | t.is(url.searchParams.get('arg'), cid.toString()) 28 | return { ok: true, body: toAsyncIterable(chunks) } 29 | } 30 | const fc = Filecoin(fetch) 31 | 32 | let data = Buffer.alloc(0) 33 | for await (const chunk of fc.client.cat(cid)) { 34 | data = Buffer.concat([data, chunk]) 35 | } 36 | 37 | t.deepEqual(data, Buffer.concat(chunks)) 38 | }) 39 | -------------------------------------------------------------------------------- /test/unit/cmd/client/import.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const { randomBytes } = require('crypto') 3 | const Filecoin = require('../../../../src') 4 | const { toAsyncIterable } = require('../../../helpers/iterable') 5 | 6 | test('should import a buffer', async t => { 7 | const input = randomBytes(256) 8 | 9 | const res = { '/': 'QmPrUbJdyPsLxkwENZNFm6Xn95oXSiUbHvaBBRVSn2PrJV' } 10 | const fetch = () => ({ ok: true, json: () => res }) 11 | const fc = Filecoin(fetch) 12 | 13 | const cid = await fc.client.import(input) 14 | 15 | t.is(cid, res['/']) 16 | }) 17 | 18 | test('should import a string', async t => { 19 | const input = randomBytes(256).toString('hex') 20 | 21 | const res = { '/': 'QmPrUbJdyPsLxkwENZNFm6Xn95oXSiUbHvaBBRVSn2PrJV' } 22 | const fetch = () => ({ ok: true, json: () => res }) 23 | const fc = Filecoin(fetch) 24 | 25 | const cid = await fc.client.import(input) 26 | 27 | t.is(cid, res['/']) 28 | }) 29 | 30 | test('should import an async iterable', async t => { 31 | const input = [randomBytes(256), randomBytes(32), randomBytes(512)] 32 | 33 | const res = { '/': 'QmPrUbJdyPsLxkwENZNFm6Xn95oXSiUbHvaBBRVSn2PrJV' } 34 | const fetch = () => ({ ok: true, json: () => res }) 35 | const fc = Filecoin(fetch) 36 | 37 | const cid = await fc.client.import(toAsyncIterable(input)) 38 | t.is(cid, res['/']) 39 | }) 40 | -------------------------------------------------------------------------------- /test/unit/cmd/client/list-asks.fixtures.json: -------------------------------------------------------------------------------- 1 | { 2 | "sample0": [ 3 | {"Miner":"t2umjj4tjijibvgdctfmmqprj2jvqdogbqu4qeglq","Price":"0.000000000000000001","Expiry":10456,"ID":0,"Error":null}, 4 | {"Miner":"t2xcclowx2fftuy4jrijgepjrotm4bez72uczkcqq","Price":"0.0000001","Expiry":10127,"ID":0,"Error":null}, 5 | {"Miner":"t26caihlqus7w2hn27ohujtebn4tvr53uu2qghlwq","Price":"0.000000001","Expiry":4344,"ID":0,"Error":null}, 6 | {"Miner":"t275gl4iadq4t77w3qjkx42mj2lzmue2eas7zsela","Price":"0.000000001","Expiry":10014,"ID":0,"Error":null}, 7 | {"Miner":"t275gl4iadq4t77w3qjkx42mj2lzmue2eas7zsela","Price":"0.0000001","Expiry":10019,"ID":1,"Error":null}, 8 | {"Miner":"t275gl4iadq4t77w3qjkx42mj2lzmue2eas7zsela","Price":"0.0001","Expiry":8163,"ID":2,"Error":null}, 9 | {"Miner":"t275gl4iadq4t77w3qjkx42mj2lzmue2eas7zsela","Price":"0.000000001","Expiry":10402,"ID":3,"Error":null}, 10 | {"Miner":"t2c626jtlocodvdfef35dz5i3uqohjhgowntst2qa","Price":"0.000000001","Expiry":33281,"ID":1,"Error":null}, 11 | {"Miner":"t2k2zn42ypc7w55ivm5ksmuxsqfzvks5f6e3cfyvy","Price":"0.000000001","Expiry":6707,"ID":0,"Error":null}, 12 | {"Miner":"t2o2e27gzupfnqpupretbfrs5rzf7zrqzblk2msna","Price":"0.0000001","Expiry":4373,"ID":1,"Error":null}, 13 | {"Miner":"t2o2e27gzupfnqpupretbfrs5rzf7zrqzblk2msna","Price":"0.000000001","Expiry":7169,"ID":2,"Error":null}, 14 | {"Miner":"t2dtrlpkcyjocxjhf23qi2ma7t3oxr75xqr6mjppq","Price":"0.00000000001234","Expiry":292385,"ID":0,"Error":null}, 15 | {"Miner":"t2dtrlpkcyjocxjhf23qi2ma7t3oxr75xqr6mjppq","Price":"0.00000004321","Expiry":104395,"ID":1,"Error":null}, 16 | {"Miner":"t2dtrlpkcyjocxjhf23qi2ma7t3oxr75xqr6mjppq","Price":"0.00000004321","Expiry":107295,"ID":2,"Error":null}, 17 | {"Miner":"t2dtrlpkcyjocxjhf23qi2ma7t3oxr75xqr6mjppq","Price":"0.000000000000111","Expiry":107296,"ID":3,"Error":null}, 18 | {"Miner":"t2vta3drlwuj2tgt4ybraymjk6fs76tcgujhwuwey","Price":"0.0000000001","Expiry":4637,"ID":0,"Error":null}, 19 | {"Miner":"t27myexirun24em73x5spo6bodixftttkjbd3ny2y","Price":"0.0000001","Expiry":10047,"ID":0,"Error":null}, 20 | {"Miner":"t2j2tznoeykqvwklcituymc6c5b34gcazdzsqc76y","Price":"0.000000001","Expiry":4845,"ID":0,"Error":null}, 21 | {"Miner":"t2ip46i55o35zkrm3n3fxn4u7m5fqk2mwviwgdzti","Price":"0.000000001","Expiry":5997,"ID":0,"Error":null}, 22 | {"Miner":"t2ip46i55o35zkrm3n3fxn4u7m5fqk2mwviwgdzti","Price":"0","Expiry":6014,"ID":1,"Error":null}, 23 | {"Miner":"t2tnbpzcmtmq5bktcf35zu6sla5mjoniwbaxkxxta","Price":"0.0000001","Expiry":10111,"ID":0,"Error":null}, 24 | {"Miner":"t26qmpijwi74frsev3lrltxoinmz3qjmhqhz5iv2y","Price":"0.0000000000001","Expiry":3995,"ID":0,"Error":null}, 25 | {"Miner":"t26qmpijwi74frsev3lrltxoinmz3qjmhqhz5iv2y","Price":"0.000000000000000001","Expiry":4163,"ID":1,"Error":null}, 26 | {"Miner":"t2sibmgdzesxsdpmxdk76d343ntnpkb5fwi4kqqei","Price":"0.0001","Expiry":2218,"ID":0,"Error":null}, 27 | {"Miner":"t2zzt3vxeox6xsggzbnzc6lu3vbuulbio7e7c7e5q","Price":"0.000000001","Expiry":3785,"ID":0,"Error":null}, 28 | {"Miner":"t2k7nq2csa4tb6sjedzy5rhwlqmfbiwg6rytlq7ra","Price":"0.000000000000001","Expiry":90356,"ID":0,"Error":null}, 29 | {"Miner":"t2s4u4pbgpoqhbhgh55jwtep7h2fpdirynrg7hp2q","Price":"0.000000001","Expiry":11328,"ID":2,"Error":null}, 30 | {"Miner":"t225vgix2kesbp4pb2xfurg332q73onkvmqa5g2va","Price":"0.000000001","Expiry":6686,"ID":0,"Error":null}, 31 | {"Miner":"t225vgix2kesbp4pb2xfurg332q73onkvmqa5g2va","Price":"0.0000000000001","Expiry":98759,"ID":1,"Error":null}, 32 | {"Miner":"t225vgix2kesbp4pb2xfurg332q73onkvmqa5g2va","Price":"0.0000000000001","Expiry":98944,"ID":2,"Error":null}, 33 | {"Miner":"t24biygquyhz3sufipryihdogmlorpra2ugm7pb7q","Price":"0.0000001","Expiry":10033,"ID":0,"Error":null}, 34 | {"Miner":"t2pg7xs2o5d7wmeqpuogfjlzfkozcuh3chm27hegq","Price":"0.000000000000000001","Expiry":33281,"ID":0,"Error":null}, 35 | {"Miner":"t2c5ghf37z7fuj7fmq2b4pb23i4peedwv4zrunwci","Price":"0.000000001","Expiry":3575,"ID":0,"Error":null}, 36 | {"Miner":"t2dimevimdscubm2ii5escpu5d6jm6vifyqz62zsi","Price":"0","Expiry":30084,"ID":0,"Error":null}, 37 | {"Miner":"t2dimevimdscubm2ii5escpu5d6jm6vifyqz62zsi","Price":"0.00000000000001","Expiry":30790,"ID":1,"Error":null}, 38 | {"Miner":"t2pqolz2fl4owvllhgggit32bnu5c3fpv4kstejly","Price":"0.000000000001","Expiry":289132,"ID":0,"Error":null}, 39 | {"Miner":"t2puqz44klyacujki34gdjzg2fry6w6hd52jotw5a","Price":"0.000000001","Expiry":3802,"ID":0,"Error":null}, 40 | {"Miner":"t27or2ipxcjgfdnrwd6iotwn6gxd4m573dzurjxbq","Price":"0.000000001","Expiry":86511,"ID":0,"Error":null}, 41 | {"Miner":"t2o4tjqm5gal2dgku546cee3x5kha7kl3jvpmqglq","Price":"0.00000000001","Expiry":3771,"ID":0,"Error":null}, 42 | {"Miner":"t2cjlmqurszatufgeapupsey3feeejqbxkyqwsj5q","Price":"0.000000001","Expiry":6822,"ID":0,"Error":null}, 43 | {"Miner":"t2x2ncgr6pj5mdwhl6dwcgcb7sa6awmpx6gcttlqq","Price":"0.000000000000000001","Expiry":10441,"ID":0,"Error":null}, 44 | {"Miner":"t2wqluw4qg4jb33tjgat4ceygfjetcvgjt67a5jza","Price":"0.000000001","Expiry":101006,"ID":0,"Error":null}, 45 | {"Miner":"t2wqluw4qg4jb33tjgat4ceygfjetcvgjt67a5jza","Price":"0.00000000000001","Expiry":101006,"ID":1,"Error":null}, 46 | {"Miner":"t2ay7zjf45dlz7tyffsse6beqk7hvaozh4oc72vsq","Price":"0.000000000000000001","Expiry":523467,"ID":0,"Error":null}, 47 | {"Miner":"t2puwthlc4jwl5j4pd7e33w7u4tmb2oqz33h2toei","Price":"0.000000001","Expiry":92751,"ID":0,"Error":null}, 48 | {"Miner":"t2puwthlc4jwl5j4pd7e33w7u4tmb2oqz33h2toei","Price":"0.0000000001","Expiry":92925,"ID":1,"Error":null}, 49 | {"Miner":"t2puwthlc4jwl5j4pd7e33w7u4tmb2oqz33h2toei","Price":"0.00000000001","Expiry":93915,"ID":2,"Error":null}, 50 | {"Miner":"t2nah4boij7zefk7slzr7wjkuezebonecqxiwkuwi","Price":"0","Expiry":1059116,"ID":0,"Error":null}, 51 | {"Miner":"t2r2z2qse3desm3piczbttlhlyswkhvdyeyjyacqy","Price":"0.0000000000001","Expiry":3997,"ID":0,"Error":null}, 52 | {"Miner":"t2r2z2qse3desm3piczbttlhlyswkhvdyeyjyacqy","Price":"0.000000000000000001","Expiry":4163,"ID":1,"Error":null}, 53 | {"Miner":"t2p5os4jyx22btpourqjqy2kvwccpphfvwzb5f2xi","Price":"0.000000001","Expiry":10908,"ID":0,"Error":null}, 54 | {"Miner":"t2ovnitn4v2z75uhzfj6wbqlavdsgehukogw5inny","Price":"0.000000000000000001","Expiry":7068,"ID":0,"Error":null}, 55 | {"Miner":"t2wejow677gwup3kx5w6hoyttjfjmfpsa6pnufzhy","Price":"0.000000001","Expiry":86503,"ID":0,"Error":null}, 56 | {"Miner":"t2gaavyd6pj2vblr7qgvzvz3sv724x5576xa4nhea","Price":"0.000000001","Expiry":8283,"ID":0,"Error":null}, 57 | {"Miner":"t2gaavyd6pj2vblr7qgvzvz3sv724x5576xa4nhea","Price":"0.000000000000000001","Expiry":8284,"ID":1,"Error":null}, 58 | {"Miner":"t2bjknxfk23s6wdbdib4kwhrumv7kyzo2wdcjpnca","Price":"0.000000000000000001","Expiry":3993,"ID":0,"Error":null}, 59 | {"Miner":"t2bjknxfk23s6wdbdib4kwhrumv7kyzo2wdcjpnca","Price":"0.000000000000000001","Expiry":519560,"ID":1,"Error":null}, 60 | {"Miner":"t2bvgcbfspjpygeywlzax4xtiiafakvkqax2nbqgi","Price":"0","Expiry":4526,"ID":0,"Error":null}, 61 | {"Miner":"t27kwemg5xu5xvuc6egygi5cf7b6ferqbco2zvhma","Price":"0.00000000001","Expiry":3912,"ID":0,"Error":null}, 62 | {"Miner":"t27kwemg5xu5xvuc6egygi5cf7b6ferqbco2zvhma","Price":"0.000000000000000001","Expiry":4163,"ID":1,"Error":null}, 63 | {"Miner":"t2av7lmuuuoome7uceagnughs2yt43hkxy3gde5kq","Price":"0.000000000000000001","Expiry":520651,"ID":0,"Error":null}, 64 | {"Miner":"t2av7lmuuuoome7uceagnughs2yt43hkxy3gde5kq","Price":"0.000000000000000001","Expiry":520656,"ID":1,"Error":null}, 65 | {"Miner":"t2rtuxdlqyv32ew3rncwhn2lhpo7m32u3idlrvqey","Price":"0.00000000001","Expiry":3314,"ID":0,"Error":null}, 66 | {"Miner":"t2bjxrnja3a4wbu3itucqqzzxp3b3livspl6e7w2a","Price":"0.000000001","Expiry":3807,"ID":0,"Error":null}, 67 | {"Miner":"t2yjawzei66rir4rpuedvn4x6dtt4g5ipqldho4kq","Price":"0","Expiry":12388,"ID":0,"Error":null}, 68 | {"Miner":"t23pginoiyeu4rfe2ureufnueklwh62iayaj3ak3a","Price":"0.0000001","Expiry":7429,"ID":1,"Error":null}, 69 | {"Miner":"t2kaeor6tmb7mgwgfhn77isoxzjpqi5446q5kmzqy","Price":"0.0000000001","Expiry":4630,"ID":0,"Error":null}, 70 | {"Miner":"t2u3v3dgpukzgxaf3clv74tygh5tkzejqfeiuouyq","Price":"0.00000000001","Expiry":5118,"ID":0,"Error":null}, 71 | {"Miner":"t23f4srgitg7t6tusxoxfbpazksiwo7jslrt3hqui","Price":"0.0000000000001","Expiry":7609,"ID":0,"Error":null}, 72 | {"Miner":"t23f4srgitg7t6tusxoxfbpazksiwo7jslrt3hqui","Price":"0.0000000000001","Expiry":98759,"ID":1,"Error":null}, 73 | {"Miner":"t2dqagdc3tudvfhvce7cj5ep6scfmvtuyhfjc3vra","Price":"0.000000000000000001","Expiry":10620,"ID":0,"Error":null}, 74 | {"Miner":"t2y4mlipvvoopr4vfrxxkez4hdycfumv5i2mifdsq","Price":"0.000000001","Expiry":4381,"ID":0,"Error":null}, 75 | {"Miner":"t226ep6pdpjbhglhwecoa7c267end3oxrqjjpa4zy","Price":"0.0000001","Expiry":289166,"ID":0,"Error":null}, 76 | {"Miner":"t226ep6pdpjbhglhwecoa7c267end3oxrqjjpa4zy","Price":"0.00001","Expiry":101230,"ID":1,"Error":null}, 77 | {"Miner":"t226ep6pdpjbhglhwecoa7c267end3oxrqjjpa4zy","Price":"0.00000001","Expiry":101738,"ID":2,"Error":null}, 78 | {"Miner":"t2lhkobdsduq2garvytgdwko2tkzi5s3eujwhnvwy","Price":"0.000000000000001","Expiry":89841,"ID":0,"Error":null}, 79 | {"Miner":"t22haz6mphqwfkd3vd5t2macpbxarl3jbo2alfngq","Price":"0.00000000001","Expiry":4707,"ID":0,"Error":null}, 80 | {"Miner":"t22haz6mphqwfkd3vd5t2macpbxarl3jbo2alfngq","Price":"0.00000000001","Expiry":4717,"ID":1,"Error":null}, 81 | {"Miner":"t2a3ahcwq4dw7vbwhv7fwxnq3x34sua6dcvlj4nnq","Price":"0.000000000000000001","Expiry":523725,"ID":0,"Error":null}, 82 | {"Miner":"t2a3ahcwq4dw7vbwhv7fwxnq3x34sua6dcvlj4nnq","Price":"0.000000000000000001","Expiry":523834,"ID":1,"Error":null}, 83 | {"Miner":"t2aeqsus3r233pqk7lqplxgqkfezns4ylbrcuigvi","Price":"0","Expiry":289287,"ID":0,"Error":null}, 84 | {"Miner":"t26yh4kjczqnaakvn3hwi3ahtyid62xy2kmymobua","Price":"0","Expiry":2881389,"ID":0,"Error":null}, 85 | {"Miner":"t2b5gaw2qe47565jwhuq6i2fymttjmfsi2gie52kq","Price":"0.000000001","Expiry":36174,"ID":0,"Error":null}, 86 | {"Miner":"t2mlozfivcc4buvjzjvgdil46crpg7f2aylvnp6ui","Price":"0.000000001","Expiry":86515,"ID":0,"Error":null}, 87 | {"Miner":"t2qqsnhceuzq7rtcjeafy7amwfbuae5nokgfaf4ja","Price":"10000000","Expiry":589,"ID":0,"Error":null}, 88 | {"Miner":"t2qqsnhceuzq7rtcjeafy7amwfbuae5nokgfaf4ja","Price":"100","Expiry":590,"ID":1,"Error":null}, 89 | {"Miner":"t2qqsnhceuzq7rtcjeafy7amwfbuae5nokgfaf4ja","Price":"10","Expiry":592,"ID":2,"Error":null}, 90 | {"Miner":"t2ltih4riwicspobkl4ffnktiivlwxdqfnd34w5pq","Price":"0.000000001","Expiry":6792,"ID":0,"Error":null}, 91 | {"Miner":"t2op5elh2743dvo6nqbkauevqbsagheujzsmzjq6a","Price":"0","Expiry":1052306,"ID":0,"Error":null}, 92 | {"Miner":"t25yrhyjwec7gb2ggrrzri2chju72v3s6t3sf4hsy","Price":"0.000000000000000001","Expiry":33328,"ID":0,"Error":null}, 93 | {"Miner":"t2ocybv2kas5loe7xnfxzslursdqxjekk53qm47la","Price":"0.0000000001","Expiry":8200,"ID":0,"Error":null}, 94 | {"Miner":"t2dqgosptgxxwp3bhldyb472xcl7fwox5ehygsi5q","Price":"0.0000001","Expiry":36691,"ID":0,"Error":null}, 95 | {"Miner":"t23v7cl66gfrcsbom5ygofkfhxktdoujca7pfp42y","Price":"0","Expiry":12358,"ID":0,"Error":null}, 96 | {"Miner":"t2sgvkpfcuqkmuzmmdyi7g63aqeqt4txder6b744q","Price":"0.00000000001","Expiry":295303,"ID":0,"Error":null}, 97 | {"Miner":"t2sjwfvonf2ludfnrxxeb6c7crnwldlmopnjggqjq","Price":"0.000000000000000001","Expiry":36605,"ID":0,"Error":null}, 98 | {"Miner":"t257fseyp2p5evzzjklyieq6rsnklm7mi4n22a6di","Price":"0.000000001","Expiry":6563,"ID":0,"Error":null}, 99 | {"Miner":"t2w3e2dd57oxlimvoisdgcxe7uewqdefy6poi6rhi","Price":"0.00000001","Expiry":4234,"ID":0,"Error":null}, 100 | {"Miner":"t2dwdiauodg2xektvehi2wqiiywj4vmezpeay4lsy","Price":"0.000000001","Expiry":4487,"ID":0,"Error":null}, 101 | {"Miner":"t2dwdiauodg2xektvehi2wqiiywj4vmezpeay4lsy","Price":"0.000000000000000001","Expiry":7141,"ID":1,"Error":null}, 102 | {"Miner":"t23esmk6hh2sg3b5wqy5pizepc2cil6ebczzri7fq","Price":"0.000000001","Expiry":15947,"ID":0,"Error":null}, 103 | {"Miner":"t26pbmqgkkgdgfooujreonqogea6uwp4bczzlefbq","Price":"0","Expiry":289574,"ID":0,"Error":null}, 104 | {"Miner":"t2r5h6scftl5j6gnpei66uzrjxgani2dlxj2iux3y","Price":"0.0001","Expiry":5277,"ID":0,"Error":null}, 105 | {"Miner":"t2r5h6scftl5j6gnpei66uzrjxgani2dlxj2iux3y","Price":"0.000001","Expiry":5530,"ID":1,"Error":null}, 106 | {"Miner":"t2uqspqkb2inf52toimwldqzb7fgyeuk7kvceeyui","Price":"0.0000000000001","Expiry":4025,"ID":0,"Error":null}, 107 | {"Miner":"t2uqspqkb2inf52toimwldqzb7fgyeuk7kvceeyui","Price":"0.000000000000000001","Expiry":4163,"ID":1,"Error":null}, 108 | {"Miner":"t2vt3c6gokzi42wbtkyab3apxg6xcyggrblrcz4ua","Price":"0.00000000001","Expiry":3903,"ID":0,"Error":null}, 109 | {"Miner":"t2vt3c6gokzi42wbtkyab3apxg6xcyggrblrcz4ua","Price":"0.000000000000000001","Expiry":4163,"ID":1,"Error":null}, 110 | {"Miner":"t2xcprtj7j4ips6rm3ezsecq2eatfv5e5h243aswa","Price":"0.000000001","Expiry":32619,"ID":0,"Error":null}, 111 | {"Miner":"t2xcprtj7j4ips6rm3ezsecq2eatfv5e5h243aswa","Price":"0.0000000000001","Expiry":98932,"ID":1,"Error":null}, 112 | {"Miner":"t2sh66t6qwkqsma46rbiuhtjme6x6kuwboupu6y3a","Price":"0.000000001","Expiry":10985,"ID":0,"Error":null}, 113 | {"Miner":"t2sh66t6qwkqsma46rbiuhtjme6x6kuwboupu6y3a","Price":"0.000000001","Expiry":10986,"ID":1,"Error":null}, 114 | {"Miner":"t2pwqfepvcq7qk2ptdhvhxxsodml3c6vowqre5cey","Price":"0.000005801","Expiry":10234,"ID":0,"Error":null}, 115 | {"Miner":"t2pwqfepvcq7qk2ptdhvhxxsodml3c6vowqre5cey","Price":"6.6666666","Expiry":10255,"ID":1,"Error":null}, 116 | {"Miner":"t2pwqfepvcq7qk2ptdhvhxxsodml3c6vowqre5cey","Price":"0.111111111","Expiry":10353,"ID":2,"Error":null}, 117 | {"Miner":"t2pwqfepvcq7qk2ptdhvhxxsodml3c6vowqre5cey","Price":"0.333333333","Expiry":10357,"ID":3,"Error":null}, 118 | {"Miner":"t2pwqfepvcq7qk2ptdhvhxxsodml3c6vowqre5cey","Price":"0.000000001","Expiry":10739,"ID":4,"Error":null}, 119 | {"Miner":"t2auxymibgbxb3s5g3756zgfgonrq5pcqbdicp4ky","Price":"0.0001","Expiry":5179,"ID":0,"Error":null}, 120 | {"Miner":"t23lj7npikhi43oz724kwwexzlr3gzdc5wefsrfhq","Price":"0.000000000000000001","Expiry":33217,"ID":0,"Error":null}, 121 | {"Miner":"t24hhlivv5ge4lsoq36ko622hrg6ucvdd7ppfhqly","Price":"0.000000001","Expiry":9020,"ID":0,"Error":null}, 122 | {"Miner":"t2ilrstbljcsncb7vq5epbitos53cbknzt5gefabi","Price":"0.0000000000001","Expiry":4027,"ID":0,"Error":null}, 123 | {"Miner":"t2ilrstbljcsncb7vq5epbitos53cbknzt5gefabi","Price":"0.000000000000000001","Expiry":4163,"ID":1,"Error":null}, 124 | {"Miner":"t2g552gdmq55t3iekf77rtsgmklg6wv6wknys26ny","Price":"0.000000001","Expiry":9020,"ID":0,"Error":null}, 125 | {"Miner":"t2ld2t7mxhxt3cge77yt7rptnxqypyeepm64btsfa","Price":"0.000000000000001","Expiry":5002,"ID":0,"Error":null}, 126 | {"Miner":"t2bpnpyhumrkp5rtja5qnsmiklyo3wyibtnapcw5y","Price":"0.00000000001","Expiry":7595,"ID":0,"Error":null}, 127 | {"Miner":"t2bpnpyhumrkp5rtja5qnsmiklyo3wyibtnapcw5y","Price":"0.00000000001","Expiry":7608,"ID":1,"Error":null}, 128 | {"Miner":"t2bpnpyhumrkp5rtja5qnsmiklyo3wyibtnapcw5y","Price":"0.00000000001","Expiry":7609,"ID":2,"Error":null}, 129 | {"Miner":"t2eeovr7roal3qvhirwrrqearhxmtu5kyp3gdg2si","Price":"0.000000001","Expiry":29483,"ID":0,"Error":null}, 130 | {"Miner":"t2eeovr7roal3qvhirwrrqearhxmtu5kyp3gdg2si","Price":"0.000000001","Expiry":33342,"ID":1,"Error":null}, 131 | {"Miner":"t2edwt2245lfhn4u5smycniof4zvz7owvh7mkl7xa","Price":"0.000000000000000001","Expiry":10369,"ID":0,"Error":null}, 132 | {"Miner":"t2kyebutmmcajt6oafdy2ozkyg3kbt5derylmubra","Price":"0.00000000001","Expiry":4050,"ID":0,"Error":null}, 133 | {"Miner":"t2qa3egrafwil6rhe4io2yoafzvfktpbjc5fqyq5q","Price":"0.000000000000000001","Expiry":11368,"ID":0,"Error":null}, 134 | {"Miner":"t2jlwg2eo7h4mvhwlhihnt3aud6cnd734injh3pqq","Price":"0.000000001","Expiry":86507,"ID":0,"Error":null}, 135 | {"Miner":"t2sylmuoc36yu3v7gzufwdmrgqdly6cgnszejbnsq","Price":"0.000000000000000001","Expiry":7040,"ID":0,"Error":null}, 136 | {"Miner":"t26wylqi3kpklsoolihn6gmc7u562rdzpitvcfu7q","Price":"0.00061","Expiry":30046,"ID":0,"Error":null}, 137 | {"Miner":"t26wylqi3kpklsoolihn6gmc7u562rdzpitvcfu7q","Price":"0","Expiry":32665,"ID":1,"Error":null}, 138 | {"Miner":"t26wylqi3kpklsoolihn6gmc7u562rdzpitvcfu7q","Price":"0.0000000000013","Expiry":32673,"ID":2,"Error":null}, 139 | {"Miner":"t26wylqi3kpklsoolihn6gmc7u562rdzpitvcfu7q","Price":"0.000000000004321","Expiry":33754,"ID":3,"Error":null}, 140 | {"Miner":"t26wylqi3kpklsoolihn6gmc7u562rdzpitvcfu7q","Price":"0.00000000000111","Expiry":36053,"ID":4,"Error":null}, 141 | {"Miner":"t2fdsj43ehkylubr7jinoy3t7br4bsreykbvwddiq","Price":"0.999999999","Expiry":10708,"ID":0,"Error":null}, 142 | {"Miner":"t2fdsj43ehkylubr7jinoy3t7br4bsreykbvwddiq","Price":"0.000000001","Expiry":10904,"ID":1,"Error":null}, 143 | {"Miner":"t2t42mpb5x7ludiqbpmxmmvesfktbsuupbpe3xsqq","Price":"0.000000000000000001","Expiry":10353,"ID":0,"Error":null}, 144 | {"Miner":"t2v67l4l67blk3ncjn576p3ax6rcbep7bnxelrvdy","Price":"0.000000000000000001","Expiry":4007,"ID":0,"Error":null}, 145 | {"Miner":"t2xd4o2ncairmvj2gowbriuvfov2ydyq4fijrbdni","Price":"0.000000001","Expiry":6940,"ID":0,"Error":null}, 146 | {"Miner":"t2xd4o2ncairmvj2gowbriuvfov2ydyq4fijrbdni","Price":"0.000000001","Expiry":6940,"ID":1,"Error":null}, 147 | {"Miner":"t2wcmxu7zistgzpqv7erpdj7zkwoclgkp7j27nmfa","Price":"0.000000001","Expiry":3835,"ID":0,"Error":null}, 148 | {"Miner":"t2wcmxu7zistgzpqv7erpdj7zkwoclgkp7j27nmfa","Price":"0.000000000000000001","Expiry":3841,"ID":1,"Error":null}, 149 | {"Miner":"t2yxxuetnru2vvn6fykslxarghxmjvhj5om3mlrry","Price":"0","Expiry":1052137,"ID":0,"Error":null}, 150 | {"Miner":"t2z6x3mb2wnb3niehk5dhnzz2wtaq4i7n3c2ajw4q","Price":"0.1","Expiry":4802,"ID":0,"Error":null}, 151 | {"Miner":"t2a5kc5zp4doge377tlq5prp437icwf7bykaotlny","Price":"0.0000000000001","Expiry":4015,"ID":0,"Error":null}, 152 | {"Miner":"t2a5kc5zp4doge377tlq5prp437icwf7bykaotlny","Price":"0.000000000000000001","Expiry":4163,"ID":1,"Error":null}, 153 | {"Miner":"t2a42kampeon6nxdg263hnu3oocvn4mvg5644bpkq","Price":"0.0000000001","Expiry":95999,"ID":0,"Error":null}, 154 | {"Miner":"t2wpb7s76ylq37dxfq3pj6hdgd2t2heq2aicicgfy","Price":"0.000000001","Expiry":5500,"ID":0,"Error":null}, 155 | {"Miner":"t2lmhfwk2g5sfg5h66umgcs4yvdxyr4obtfzmh3la","Price":"0.000000000000000001","Expiry":3993,"ID":0,"Error":null}, 156 | {"Miner":"t2zup5a5rytwissvm6zq74amp4chrnazrl4ev4yii","Price":"0.00000000000000001","Expiry":33111,"ID":0,"Error":null}, 157 | {"Miner":"t2zup5a5rytwissvm6zq74amp4chrnazrl4ev4yii","Price":"0.00000000000000001","Expiry":33133,"ID":1,"Error":null}, 158 | {"Miner":"t2zup5a5rytwissvm6zq74amp4chrnazrl4ev4yii","Price":"0.00000000000000001","Expiry":33160,"ID":2,"Error":null}, 159 | {"Miner":"t2zup5a5rytwissvm6zq74amp4chrnazrl4ev4yii","Price":"0.000000001","Expiry":7263,"ID":3,"Error":null}, 160 | {"Miner":"t2zup5a5rytwissvm6zq74amp4chrnazrl4ev4yii","Price":"0.00000000000001","Expiry":33329,"ID":4,"Error":null}, 161 | {"Miner":"t2tovnxt5rulcef4twu5dlyqlt7vsthwhv6enolmi","Price":"0.000001","Expiry":9618,"ID":0,"Error":null}, 162 | {"Miner":"t2zvbuxrttgp5ebjraep2cfycfvy7r47wdymig3sy","Price":"0","Expiry":4796,"ID":0,"Error":null}, 163 | {"Miner":"t2awzntgkkuezahigokyj5fzijudu25ucqfgqg4lq","Price":"0.00000001","Expiry":4217,"ID":0,"Error":null}, 164 | {"Miner":"t2xxptuxcnvzpskkg4rhhgatra4jp2glcvkub33dq","Price":"0.000000001","Expiry":12204,"ID":0,"Error":null} 165 | ] 166 | } 167 | -------------------------------------------------------------------------------- /test/unit/cmd/client/list-asks.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../../../../src') 3 | const { toAsyncIterable } = require('../../../helpers/iterable') 4 | const Fixtures = require('./list-asks.fixtures.json') 5 | 6 | test('should list asks', async t => { 7 | const fetch = () => ({ 8 | ok: true, 9 | body: toAsyncIterable(Fixtures.sample0.map(ask => JSON.stringify(ask) + '\n')) 10 | }) 11 | const fc = Filecoin(fetch) 12 | 13 | let i = 0 14 | for await (const ask of fc.client.listAsks()) { 15 | t.is(ask.id, Fixtures.sample0[i].ID) 16 | t.is(ask.miner, Fixtures.sample0[i].Miner) 17 | t.is(ask.price, Fixtures.sample0[i].Price) 18 | t.is(ask.expiry, Fixtures.sample0[i].Expiry) 19 | i++ 20 | } 21 | }) 22 | -------------------------------------------------------------------------------- /test/unit/cmd/client/payments.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../../../../src') 3 | 4 | test('should list payments for a given deal', async t => { 5 | const cid = 'zDPWYqFCuTNxiwRkt1iDJWEy6qKPGCunMGHrP1ojsMrZDWKYsgzF' 6 | const payments = [ 7 | { 8 | channel: 0, 9 | payer: 't1bcvxo4ztdkukjmrsjvc5d4w24cl55vvbrssspyy', 10 | target: 't1uo4nzu44apoclkbjbbvc4f3irbptg3ctjq44wiq', 11 | amount: 25000, 12 | valid_at: 8, 13 | condition: null, 14 | signature: '1My76149fPIulbdO/DKlkUBMMSLwGYSw2XmVKXq3HrxMG5kkmBgsaPZ/DzdxiOWX5kdnXJ++AFQqsmWHd5dtOwE=' 15 | } 16 | ] 17 | 18 | const fetch = () => ({ ok: true, json: () => payments }) 19 | const fc = Filecoin(fetch) 20 | 21 | const res = await fc.client.payments(cid) 22 | 23 | t.true(Array.isArray(res)) 24 | t.is(res.length, payments.length) 25 | 26 | res.forEach((p, i) => { 27 | t.is(p.channel, payments[i].channel) 28 | t.is(p.payer, payments[i].payer) 29 | t.is(p.target, payments[i].target) 30 | t.is(p.amount, payments[i].amount) 31 | t.is(p.validAt, payments[i].valid_at) 32 | t.is(p.condition, payments[i].condition) 33 | t.is(p.signature, payments[i].signature) 34 | }) 35 | }) 36 | -------------------------------------------------------------------------------- /test/unit/cmd/client/propose-storage-deal.fixtures.json: -------------------------------------------------------------------------------- 1 | { 2 | "sample0": { 3 | "State": 3, 4 | "Message": "", 5 | "ProposalCid": 6 | { 7 | "/": "zDPWYqFCz8vQRUnFVsbdXPAWTRuRBLaPncKLLSqd7cNF3Bd2NQT5" 8 | }, 9 | "ProofInfo": null, 10 | "Signature": "c2lnbmF0dXJycmVlZQ==" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/unit/cmd/client/propose-storage-deal.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../../../../src') 3 | const Fixtures = require('./propose-storage-deal.fixtures.json') 4 | 5 | test('should propose a storage deal', async t => { 6 | const minerAddr = 't2u2r6nyaxdspozci5t2i2xtfw23lxa35rvkul7di' 7 | const cid = 'QmV9mkND7mvWim77R669UCLg1DgYzqiX1NsXtj7GSydzD6' 8 | const askId = '0' 9 | const time = '2880' 10 | 11 | const fetch = () => ({ ok: true, json: () => Fixtures.sample0 }) 12 | const fc = Filecoin(fetch) 13 | 14 | const res = await fc.client.proposeStorageDeal(minerAddr, cid, askId, time) 15 | 16 | t.deepEqual(res, { 17 | state: 3, 18 | message: '', 19 | proposalCid: 'zDPWYqFCz8vQRUnFVsbdXPAWTRuRBLaPncKLLSqd7cNF3Bd2NQT5', 20 | proofInfo: null, 21 | signature: 'c2lnbmF0dXJycmVlZQ==' 22 | }) 23 | }) 24 | 25 | test('should allow proposal of a storage deal with allowDuplicates flag', async t => { 26 | const minerAddr = 't2u2r6nyaxdspozci5t2i2xtfw23lxa35rvkul7di' 27 | const cid = 'QmV9mkND7mvWim77R669UCLg1DgYzqiX1NsXtj7GSydzD6' 28 | const askId = '0' 29 | const time = '2880' 30 | const options = { allowDuplicates: true } 31 | 32 | const fetch = () => ({ ok: true, json: () => Fixtures.sample0 }) 33 | const fc = Filecoin(fetch) 34 | 35 | const res = await fc.client.proposeStorageDeal(minerAddr, cid, askId, time, options) 36 | 37 | t.deepEqual(res, { 38 | state: 3, 39 | message: '', 40 | proposalCid: 'zDPWYqFCz8vQRUnFVsbdXPAWTRuRBLaPncKLLSqd7cNF3Bd2NQT5', 41 | proofInfo: null, 42 | signature: 'c2lnbmF0dXJycmVlZQ==' 43 | }) 44 | }) 45 | -------------------------------------------------------------------------------- /test/unit/cmd/client/query-storage-deal.fixtures.json: -------------------------------------------------------------------------------- 1 | { 2 | "State":7, 3 | "Message":"", 4 | "ProposalCid": 5 | { 6 | "/":"bafy2bzaceargn5lm5l6imiact6sktr5xl3fkgdga3lamchl6x6rdj36aeeaiq" 7 | }, 8 | "ProofInfo": 9 | { 10 | "SectorID":1, 11 | "CommD":"mkgOa7RCAYNHgUqsWmNR0MjAkzNMZM46ZPPuLonPsDk=", 12 | "CommR":"gMGjsTgYFeXSFq3Vaqf2Nm2rhMV/nJ17nmZEPMeCs1I=", 13 | "CommRStar":"87+U6/0jhvfBtauei+LG//bDpsNqlRa9Yguv+VSPHAE=", 14 | "CommitmentMessage": 15 | { 16 | "/":"bafy2bzaceaueo3rf4dzvc3fxjdio3zc3vedb2phcidk5c3rp3wsnm7jxfrgfg" 17 | }, 18 | "PieceInclusionProof":"EAAAAAAAAADmCRBjqxNVP7Z0RG7pdnulR4TrA6M8BbnqV9dn35ojaw==" 19 | }, 20 | "Signature":"c2lnbmF0dXJycmVlZQ==" 21 | } 22 | -------------------------------------------------------------------------------- /test/unit/cmd/client/query-storage-deal.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../../../../src') 3 | const Fixtures = require('./query-storage-deal.fixtures.json') 4 | 5 | test('should list the storage deal info for a particular cid', async t => { 6 | const cid = 'zDPWYqFCuTNxiwRkt1iDJWEy6qKPGCunMGHrP1ojsMrZDWKYsgzF' 7 | 8 | const fetch = () => ({ ok: true, json: () => Fixtures }) 9 | const fc = Filecoin(fetch) 10 | 11 | const res = await fc.client.queryStorageDeal(cid) 12 | 13 | const responseProofInfo = Fixtures.ProofInfo 14 | 15 | const proofInfo = { 16 | sectorID: responseProofInfo.SectorID, 17 | commitmentMessage: responseProofInfo.CommitmentMessage['/'], 18 | commD: responseProofInfo.CommD, 19 | commR: responseProofInfo.CommR, 20 | commRStar: responseProofInfo.CommRStar, 21 | pieceInclusionProof: responseProofInfo.PieceInclusionProof 22 | } 23 | 24 | t.deepEqual(res, { 25 | state: 7, 26 | message: '', 27 | proposalCid: Fixtures.ProposalCid['/'], 28 | proofInfo: proofInfo, 29 | signature: Fixtures.Signature 30 | }) 31 | }) 32 | -------------------------------------------------------------------------------- /test/unit/cmd/config/get.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../../../../src') 3 | 4 | test('should get config value', async t => { 5 | const data = { 6 | address: '/ip4/127.0.0.1/tcp/3453', 7 | accessControlAllowOrigin: ['*'], 8 | accessControlAllowCredentials: false, 9 | accessControlAllowMethods: ['GET', 'POST', 'PUT'] 10 | } 11 | const fetch = () => ({ ok: true, json: () => data }) 12 | const fc = Filecoin(fetch) 13 | const res = await fc.config.get('api') 14 | 15 | t.deepEqual(res, data) 16 | }) 17 | -------------------------------------------------------------------------------- /test/unit/cmd/config/set.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../../../../src') 3 | 4 | test('should set config value', async t => { 5 | const data = '/ip4/127.0.0.1/tcp/' + Date.now() 6 | const fetch = () => ({ ok: true, json: () => data }) 7 | const fc = Filecoin(fetch) 8 | const res = await fc.config.set('api.address', data) 9 | 10 | t.deepEqual(res, data) 11 | }) 12 | 13 | test('should throw for non stringifyable value', async t => { 14 | const fc = Filecoin() 15 | 16 | // Create object with circular reference 17 | const a = {} 18 | const b = {} 19 | a.toB = b 20 | b.toA = a 21 | 22 | const err = await t.throwsAsync(fc.config.set('api.address', a)) 23 | 24 | t.is(err.message, 'failed to stringify config value') 25 | }) 26 | -------------------------------------------------------------------------------- /test/unit/cmd/dag/get.fixtures.json: -------------------------------------------------------------------------------- 1 | { 2 | "sample0": { 3 | "cid": "QmVqyYSPsY77iWdSMMBBEqYaTH1YTHhuPvvMtFugQgfg2f", 4 | "node": { 5 | "data": "CAISgALjOf6VibzIIJBjbXNuzsKa80hC30Rm5Z4UXDvVpMvEbsfT+4uc5yxAf+KdwCw4CZgWd9iv5uyrApZ63pB3Lq12v7rlRZ1S3SctLkY0QJuLqXjJPaIiQ3u79+/BuLksyV4KOiUDOlsuv53MGzFC2urJvaC2NCCS+16yrwsEAUg/Pby213AH9HK/rtykyrccu8dI9F/zTddD1pVPq4zs37i8lBRCL/mAquxaGOUvbYc/Jrn1HthHjoxGZcmzYmtCNHcVM1F1suVkHzCMKjY5QWCDJWXytLEqODqvzO32f3HFCCh/mfF67GJva1cZ1IYJZR5dcyrTTN5VflxD8VQh4qHwGIAC", 6 | "links": [] 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/unit/cmd/dag/get.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../../../../src') 3 | const Fixtures = require('./get.fixtures.json') 4 | 5 | test('should get a DAG node', async t => { 6 | const fetch = url => { 7 | url = new URL(url) 8 | t.is(url.searchParams.get('arg'), Fixtures.sample0.cid) 9 | 10 | return { 11 | ok: true, 12 | headers: { 13 | get (key) { return this[key] }, 14 | 'Content-Type': 'application/json' 15 | }, 16 | json: () => Fixtures.sample0.node 17 | } 18 | } 19 | 20 | const fc = Filecoin(fetch) 21 | const node = await fc.dag.get(Fixtures.sample0.cid) 22 | 23 | t.deepEqual(node, Fixtures.sample0.node) 24 | }) 25 | -------------------------------------------------------------------------------- /test/unit/cmd/dht/find-peer.fixtures.json: -------------------------------------------------------------------------------- 1 | { 2 | "sample0": [ 3 | "/ip4/3.90.230.176/tcp/40510/ipfs/QmXq6XEYeEmUzBFuuKbVEGgxEpVD4xbSkG2Rhek6zkFMp4/p2p-circuit", 4 | "/ip4/184.72.199.74/tcp/59174/ipfs/QmXhxqTKzBKHA5FcMuiKZv8YaMPwpbKGXHRVZcFB2DX9XY/p2p-circuit", 5 | "/ip4/3.90.230.176/tcp/9002/ipfs/QmXhxqTKzBKHA5FcMuiKZv8YaMPwpbKGXHRVZcFB2DX9XY/p2p-circuit/ipfs/QmezicWuZn9r4LvkVrtriGUbkTa4Z4V5TW8aS9qoPXegCi/p2p-circuit", 6 | "/ip4/3.90.230.176/tcp/31725/ipfs/QmXhxqTKzBKHA5FcMuiKZv8YaMPwpbKGXHRVZcFB2DX9XY/p2p-circuit/ipfs/QmezicWuZn9r4LvkVrtriGUbkTa4Z4V5TW8aS9qoPXegCi/p2p-circuit", 7 | "/ip4/3.90.230.176/tcp/61943/ipfs/QmXq6XEYeEmUzBFuuKbVEGgxEpVD4xbSkG2Rhek6zkFMp4/p2p-circuit", 8 | "/ip4/64.46.28.178/tcp/44680", 9 | "/ip4/64.46.28.178/tcp/49501", 10 | "/ip4/3.90.230.176/tcp/11871/ipfs/QmXq6XEYeEmUzBFuuKbVEGgxEpVD4xbSkG2Rhek6zkFMp4/p2p-circuit", 11 | "/ip4/3.90.230.176/tcp/54214/ipfs/QmZRnwmCjyNHgeNDiyT8mXRtGhP6uSzgHtrozc42crmVbg/p2p-circuit", 12 | "/ip4/3.90.230.176/tcp/45302/ipfs/QmZRnwmCjyNHgeNDiyT8mXRtGhP6uSzgHtrozc42crmVbg/p2p-circuit", 13 | "/ip4/184.72.199.74/tcp/24612/ipfs/Qmd6xrWYHsxivfakYRy6MszTpuAiEoFbgE1LWw4EvwBpp4/p2p-circuit", 14 | "/ip4/52.54.103.140/tcp/11610/ipfs/Qmd6xrWYHsxivfakYRy6MszTpuAiEoFbgE1LWw4EvwBpp4/p2p-circuit", 15 | "/ip4/3.90.230.176/tcp/58266/ipfs/QmXhxqTKzBKHA5FcMuiKZv8YaMPwpbKGXHRVZcFB2DX9XY/p2p-circuit", 16 | "/ip4/3.90.230.176/tcp/34750/ipfs/QmXq6XEYeEmUzBFuuKbVEGgxEpVD4xbSkG2Rhek6zkFMp4/p2p-circuit", 17 | "/ip4/64.46.28.178/tcp/43002", 18 | "/ip4/3.90.230.176/tcp/9004/ipfs/QmZRnwmCjyNHgeNDiyT8mXRtGhP6uSzgHtrozc42crmVbg/p2p-circuit", 19 | "/ip4/64.46.28.178/tcp/64272", 20 | "/ip4/64.46.28.178/tcp/49556", 21 | "/ip4/3.90.230.176/tcp/48381/ipfs/QmXq6XEYeEmUzBFuuKbVEGgxEpVD4xbSkG2Rhek6zkFMp4/p2p-circuit", 22 | "/ip4/3.90.230.176/tcp/48725/ipfs/QmXhxqTKzBKHA5FcMuiKZv8YaMPwpbKGXHRVZcFB2DX9XY/p2p-circuit", 23 | "/ip4/127.0.0.1/tcp/6000", 24 | "/ip4/3.90.230.176/tcp/35550/ipfs/QmXhxqTKzBKHA5FcMuiKZv8YaMPwpbKGXHRVZcFB2DX9XY/p2p-circuit", 25 | "/ip4/64.46.28.178/tcp/43325", 26 | "/ip4/64.46.28.178/tcp/43764", 27 | "/ip4/64.46.28.178/tcp/43710", 28 | "/ip4/3.90.230.176/tcp/46177/ipfs/QmZRnwmCjyNHgeNDiyT8mXRtGhP6uSzgHtrozc42crmVbg/p2p-circuit", 29 | "/ip4/24.122.108.38/tcp/6908/ipfs/QmaJhzM4oBsfHGkd71q1ECgDQYQtjQ3n4o1MaGcfLHXopQ/p2p-circuit", 30 | "/ip4/3.90.230.176/tcp/54616/ipfs/QmXq6XEYeEmUzBFuuKbVEGgxEpVD4xbSkG2Rhek6zkFMp4/p2p-circuit", 31 | "/ip4/3.90.230.176/tcp/49532/ipfs/Qmd6xrWYHsxivfakYRy6MszTpuAiEoFbgE1LWw4EvwBpp4/p2p-circuit", 32 | "/ip4/64.46.28.178/tcp/49507", 33 | "/ip4/3.90.230.176/tcp/62469/ipfs/QmXq6XEYeEmUzBFuuKbVEGgxEpVD4xbSkG2Rhek6zkFMp4/p2p-circuit", 34 | "/ip4/64.46.28.178/tcp/49541", 35 | "/ip4/184.72.199.74/tcp/23738/ipfs/QmXhxqTKzBKHA5FcMuiKZv8YaMPwpbKGXHRVZcFB2DX9XY/p2p-circuit", 36 | "/ip4/3.90.230.176/tcp/9002/ipfs/QmXhxqTKzBKHA5FcMuiKZv8YaMPwpbKGXHRVZcFB2DX9XY/p2p-circuit", 37 | "/ip4/114.248.135.105/tcp/6000/ipfs/QmezicWuZn9r4LvkVrtriGUbkTa4Z4V5TW8aS9qoPXegCi/p2p-circuit", 38 | "/ip4/114.248.135.105/tcp/19785/ipfs/QmVWSEJ5mTwxu7dkDrJ9WWLfXYLaMrgBhkJr9fRSECo5h4/p2p-circuit/ipfs/QmezicWuZn9r4LvkVrtriGUbkTa4Z4V5TW8aS9qoPXegCi/p2p-circuit", 39 | "/ip4/3.90.230.176/tcp/42594/ipfs/QmXq6XEYeEmUzBFuuKbVEGgxEpVD4xbSkG2Rhek6zkFMp4/p2p-circuit", 40 | "/ip4/3.90.230.176/tcp/43726/ipfs/QmXhxqTKzBKHA5FcMuiKZv8YaMPwpbKGXHRVZcFB2DX9XY/p2p-circuit", 41 | "/ip4/64.46.28.178/tcp/49532", 42 | "/ip4/64.46.28.178/tcp/44128", 43 | "/ip4/3.90.230.176/tcp/62047/ipfs/QmXq6XEYeEmUzBFuuKbVEGgxEpVD4xbSkG2Rhek6zkFMp4/p2p-circuit", 44 | "/ip4/184.72.199.74/tcp/9034/ipfs/QmXhxqTKzBKHA5FcMuiKZv8YaMPwpbKGXHRVZcFB2DX9XY/p2p-circuit", 45 | "/ip4/3.90.230.176/tcp/38570/ipfs/QmXq6XEYeEmUzBFuuKbVEGgxEpVD4xbSkG2Rhek6zkFMp4/p2p-circuit", 46 | "/ip4/3.90.230.176/tcp/29234/ipfs/QmZGDLdQLUTi7uYTNavKwCd7SBc5KMfxzWxAyvqRQvwuiV/p2p-circuit", 47 | "/ip4/64.46.28.178/tcp/49520", 48 | "/ip4/3.90.230.176/tcp/33670/ipfs/QmXhxqTKzBKHA5FcMuiKZv8YaMPwpbKGXHRVZcFB2DX9XY/p2p-circuit", 49 | "/ip4/3.90.230.176/tcp/49474/ipfs/Qmd6xrWYHsxivfakYRy6MszTpuAiEoFbgE1LWw4EvwBpp4/p2p-circuit", 50 | "/ip4/184.72.199.74/tcp/48058/ipfs/QmXhxqTKzBKHA5FcMuiKZv8YaMPwpbKGXHRVZcFB2DX9XY/p2p-circuit", 51 | "/ip4/184.72.199.74/tcp/56758/ipfs/QmXhxqTKzBKHA5FcMuiKZv8YaMPwpbKGXHRVZcFB2DX9XY/p2p-circuit", 52 | "/ip4/3.90.230.176/tcp/49137/ipfs/QmXq6XEYeEmUzBFuuKbVEGgxEpVD4xbSkG2Rhek6zkFMp4/p2p-circuit", 53 | "/ip4/64.46.28.178/tcp/49499", 54 | "/ip4/3.90.230.176/tcp/34660/ipfs/QmXhxqTKzBKHA5FcMuiKZv8YaMPwpbKGXHRVZcFB2DX9XY/p2p-circuit", 55 | "/ip4/184.72.199.74/tcp/46054/ipfs/QmXhxqTKzBKHA5FcMuiKZv8YaMPwpbKGXHRVZcFB2DX9XY/p2p-circuit", 56 | "/ip4/64.46.28.178/tcp/44026", 57 | "/ip4/64.46.28.178/tcp/49505", 58 | "/ip4/184.72.199.74/tcp/9019/ipfs/QmXhxqTKzBKHA5FcMuiKZv8YaMPwpbKGXHRVZcFB2DX9XY/p2p-circuit", 59 | "/ip4/64.46.28.178/tcp/43285", 60 | "/ip4/3.90.230.176/tcp/62075/ipfs/QmXq6XEYeEmUzBFuuKbVEGgxEpVD4xbSkG2Rhek6zkFMp4/p2p-circuit", 61 | "/ip4/184.72.199.74/tcp/9004/ipfs/QmZRnwmCjyNHgeNDiyT8mXRtGhP6uSzgHtrozc42crmVbg/p2p-circuit", 62 | "/ip4/64.46.28.178/tcp/49521", 63 | "/ip4/64.46.28.178/tcp/44413", 64 | "/ip4/64.46.28.178/tcp/44494", 65 | "/ip4/3.90.230.176/tcp/35632/ipfs/QmZRnwmCjyNHgeNDiyT8mXRtGhP6uSzgHtrozc42crmVbg/p2p-circuit", 66 | "/ip4/3.90.230.176/tcp/56636/ipfs/QmZRnwmCjyNHgeNDiyT8mXRtGhP6uSzgHtrozc42crmVbg/p2p-circuit", 67 | "/ip4/64.46.28.178/tcp/49548", 68 | "/ip4/64.46.28.178/tcp/44652", 69 | "/ip4/52.54.103.140/tcp/20050/ipfs/QmXhxqTKzBKHA5FcMuiKZv8YaMPwpbKGXHRVZcFB2DX9XY/p2p-circuit", 70 | "/ip4/3.90.230.176/tcp/43298/ipfs/QmXq6XEYeEmUzBFuuKbVEGgxEpVD4xbSkG2Rhek6zkFMp4/p2p-circuit", 71 | "/ip4/64.46.28.178/tcp/42845", 72 | "/ip4/64.46.28.178/tcp/42690", 73 | "/ip4/3.90.230.176/tcp/60226/ipfs/QmXq6XEYeEmUzBFuuKbVEGgxEpVD4xbSkG2Rhek6zkFMp4/p2p-circuit", 74 | "/ip4/3.90.230.176/tcp/48380/ipfs/QmXq6XEYeEmUzBFuuKbVEGgxEpVD4xbSkG2Rhek6zkFMp4/p2p-circuit", 75 | "/ip4/3.90.230.176/tcp/47941/ipfs/QmZRnwmCjyNHgeNDiyT8mXRtGhP6uSzgHtrozc42crmVbg/p2p-circuit", 76 | "/ip4/64.46.28.178/tcp/43566", 77 | "/ip4/3.90.230.176/tcp/39046/ipfs/QmXq6XEYeEmUzBFuuKbVEGgxEpVD4xbSkG2Rhek6zkFMp4/p2p-circuit", 78 | "/ip4/64.46.28.178/tcp/49534", 79 | "/ip4/3.90.230.176/tcp/47929/ipfs/QmZRnwmCjyNHgeNDiyT8mXRtGhP6uSzgHtrozc42crmVbg/p2p-circuit", 80 | "/ip4/3.90.230.176/tcp/9001/ipfs/QmXq6XEYeEmUzBFuuKbVEGgxEpVD4xbSkG2Rhek6zkFMp4/p2p-circuit", 81 | "/ip4/64.46.28.178/tcp/43855", 82 | "/ip4/3.90.230.176/tcp/47260/ipfs/Qmd6xrWYHsxivfakYRy6MszTpuAiEoFbgE1LWw4EvwBpp4/p2p-circuit", 83 | "/ip4/52.54.103.140/tcp/6488/ipfs/QmZRnwmCjyNHgeNDiyT8mXRtGhP6uSzgHtrozc42crmVbg/p2p-circuit", 84 | "/ip4/3.90.230.176/tcp/31725/ipfs/QmXhxqTKzBKHA5FcMuiKZv8YaMPwpbKGXHRVZcFB2DX9XY/p2p-circuit", 85 | "/ipfs/QmezicWuZn9r4LvkVrtriGUbkTa4Z4V5TW8aS9qoPXegCi/p2p-circuit", 86 | "/ip4/64.46.28.178/tcp/43190", 87 | "/ip4/64.46.28.178/tcp/42979", 88 | "/ip4/10.0.1.19/tcp/6000", 89 | "/ip4/3.90.230.176/tcp/37030/ipfs/QmZRnwmCjyNHgeNDiyT8mXRtGhP6uSzgHtrozc42crmVbg/p2p-circuit", 90 | "/ip4/64.46.28.178/tcp/43073", 91 | "/ip4/64.46.28.178/tcp/49549", 92 | "/ip4/64.46.28.178/tcp/43129", 93 | "/ip4/3.90.230.176/tcp/16877/ipfs/QmZRnwmCjyNHgeNDiyT8mXRtGhP6uSzgHtrozc42crmVbg/p2p-circuit", 94 | "/ip4/3.90.230.176/tcp/45364/ipfs/QmXq6XEYeEmUzBFuuKbVEGgxEpVD4xbSkG2Rhek6zkFMp4/p2p-circuit", 95 | "/ip4/3.90.230.176/tcp/43419/ipfs/QmXhxqTKzBKHA5FcMuiKZv8YaMPwpbKGXHRVZcFB2DX9XY/p2p-circuit", 96 | "/ip4/3.90.230.176/tcp/33074/ipfs/QmXq6XEYeEmUzBFuuKbVEGgxEpVD4xbSkG2Rhek6zkFMp4/p2p-circuit", 97 | "/ip4/64.46.28.178/tcp/44620", 98 | "/ip4/64.46.28.178/tcp/44544", 99 | "/ip4/3.90.230.176/tcp/41312/ipfs/QmZRnwmCjyNHgeNDiyT8mXRtGhP6uSzgHtrozc42crmVbg/p2p-circuit", 100 | "/ip4/3.90.230.176/tcp/35740/ipfs/QmXq6XEYeEmUzBFuuKbVEGgxEpVD4xbSkG2Rhek6zkFMp4/p2p-circuit", 101 | "/ip4/114.248.135.105/tcp/19784/ipfs/QmVWSEJ5mTwxu7dkDrJ9WWLfXYLaMrgBhkJr9fRSECo5h4/p2p-circuit", 102 | "/ip4/3.90.230.176/tcp/55094/ipfs/QmZRnwmCjyNHgeNDiyT8mXRtGhP6uSzgHtrozc42crmVbg/p2p-circuit", 103 | "/ip4/3.90.230.176/tcp/9000/ipfs/Qmd6xrWYHsxivfakYRy6MszTpuAiEoFbgE1LWw4EvwBpp4/p2p-circuit", 104 | "/ip4/64.46.28.178/tcp/43609", 105 | "/ip4/3.90.230.176/tcp/9003/ipfs/QmZGDLdQLUTi7uYTNavKwCd7SBc5KMfxzWxAyvqRQvwuiV/p2p-circuit", 106 | "/ip4/3.90.230.176/tcp/47937/ipfs/QmZRnwmCjyNHgeNDiyT8mXRtGhP6uSzgHtrozc42crmVbg/p2p-circuit", 107 | "/ip4/3.90.230.176/tcp/38994/ipfs/QmXq6XEYeEmUzBFuuKbVEGgxEpVD4xbSkG2Rhek6zkFMp4/p2p-circuit", 108 | "/ip4/114.248.135.105/tcp/19784/ipfs/QmW7JjsrY282ouBRV4y2RpA7fWAeeMiqmCLL4LaFSw3USD/p2p-circuit/ipfs/QmezicWuZn9r4LvkVrtriGUbkTa4Z4V5TW8aS9qoPXegCi/p2p-circuit", 109 | "/ip4/3.90.230.176/tcp/49689/ipfs/Qmd6xrWYHsxivfakYRy6MszTpuAiEoFbgE1LWw4EvwBpp4/p2p-circuit", 110 | "/ip4/184.72.199.74/tcp/34424/ipfs/Qmd6xrWYHsxivfakYRy6MszTpuAiEoFbgE1LWw4EvwBpp4/p2p-circuit" 111 | ] 112 | } 113 | -------------------------------------------------------------------------------- /test/unit/cmd/dht/find-peer.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Multiaddr = require('multiaddr') 3 | const Filecoin = require('../../../../src') 4 | const { toAsyncIterable } = require('../../../helpers/iterable') 5 | const Fixtures = require('./find-peer.fixtures.json') 6 | 7 | test('should find multiaddrs of peer', async t => { 8 | const fetch = () => ({ 9 | ok: true, 10 | body: toAsyncIterable(Fixtures.sample0.map(p => `${JSON.stringify(p)}\n`)) 11 | }) 12 | const fc = Filecoin(fetch) 13 | 14 | let i = 0 15 | for await (const addr of fc.dht.findPeer('QmWLtQBDSFpfeD3k23rYhsQ8cS7a4WCRNHWz9UvrsaT2UE')) { 16 | t.notThrows(() => Multiaddr(addr)) 17 | t.is(addr.toString(), Fixtures.sample0[i]) 18 | 19 | i++ 20 | } 21 | }) 22 | -------------------------------------------------------------------------------- /test/unit/cmd/dht/find-provs.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Multiaddr = require('multiaddr') 3 | const Filecoin = require('../../../../src') 4 | const { toAsyncIterable } = require('../../../helpers/iterable') 5 | const Fixtures = require('./find-provs.fixtures.json') 6 | 7 | test('should find providers', async t => { 8 | const fetch = () => ({ 9 | ok: true, 10 | body: toAsyncIterable(Fixtures.sample0.map(p => `${JSON.stringify(p)}\n`)) 11 | }) 12 | const fc = Filecoin(fetch) 13 | 14 | let i = 0 15 | for await (const peer of fc.dht.findProvs('QmbFMke1KXqnYyBBWxB74N4c5SBnJMVAiMNRcGu6x1AwQH')) { 16 | if (peer.id) { 17 | t.is(peer.id, Fixtures.sample0[i].ID) 18 | } 19 | 20 | t.true(typeof peer.type === 'number') 21 | t.is(peer.type, Fixtures.sample0[i].Type) 22 | 23 | peer.responses.forEach((r, j) => { 24 | t.is(r.id, Fixtures.sample0[i].Responses[j].ID) 25 | r.addrs.forEach((a, k) => { 26 | t.notThrows(() => Multiaddr(a)) 27 | t.is(a.toString(), Fixtures.sample0[i].Responses[j].Addrs[k]) 28 | }) 29 | }) 30 | 31 | if (peer.extra) { 32 | t.true(typeof peer.extra === 'string') 33 | t.is(peer.extra, Fixtures.sample0[i].Extra) 34 | } 35 | 36 | i++ 37 | } 38 | }) 39 | -------------------------------------------------------------------------------- /test/unit/cmd/id.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../../../src') 3 | 4 | test('should get id', async t => { 5 | const jsonData = { 6 | Addresses: [ 7 | '/ip4/127.0.0.1/tcp/6000/ipfs/QmVESp5X5EtRXGrDBqHzZ1Hd22nSh5QLtw8BozGNu9dWef', 8 | '/ip4/192.168.1.132/tcp/6000/ipfs/QmVESp5X5EtRXGrDBqHzZ1Hd22nSh5QLtw8BozGNu9dWef' 9 | ], 10 | ID: 'QmVESp5X5EtRXGrDBqHzZ1Hd22nSh5QLtw8BozGNu9dWef' 11 | } 12 | 13 | const fetch = () => ({ ok: true, json: () => jsonData }) 14 | const fc = Filecoin(fetch) 15 | const res = await fc.id() 16 | 17 | t.is(res.id, jsonData.ID) 18 | t.true(Array.isArray(res.addresses)) 19 | t.deepEqual(res.addresses.map(a => a.toString()), jsonData.Addresses) 20 | }) 21 | -------------------------------------------------------------------------------- /test/unit/cmd/log/level.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../../../../src') 3 | 4 | test('should set the log level for all subsystems', async t => { 5 | const level = 'error' 6 | const expectedMessage = `Changed log level of all subsystems to: ${level}` 7 | const fetch = url => { 8 | url = new URL(url) 9 | t.is(url.searchParams.get('arg'), level) 10 | return { ok: true, json: () => expectedMessage } 11 | } 12 | const fc = Filecoin(fetch) 13 | 14 | const msg = await fc.log.level(level) 15 | t.is(msg, expectedMessage) 16 | }) 17 | 18 | test('should set the log level for a specific subsystem', async t => { 19 | const level = 'error' 20 | const subsystem = 'ping' 21 | const expectedMessage = `Changed log level of '${subsystem}' to '${level}'` 22 | const fetch = url => { 23 | url = new URL(url) 24 | t.is(url.searchParams.get('arg'), level) 25 | t.is(url.searchParams.get('subsystem'), subsystem) 26 | return { ok: true, json: () => expectedMessage } 27 | } 28 | const fc = Filecoin(fetch) 29 | 30 | const msg = await fc.log.level(level, { subsystem }) 31 | t.is(msg, expectedMessage) 32 | }) 33 | 34 | test('should error for unknown log level', async t => { 35 | const level = 'foo' 36 | const expectedMessage = `'unknown log level: ${level}. Available levels: debug, info, warning, error, fatal, panic'` 37 | const fetch = url => { 38 | return { ok: false, text: () => JSON.stringify({ Message: expectedMessage }) } 39 | } 40 | const fc = Filecoin(fetch) 41 | 42 | const err = await t.throwsAsync(fc.log.level(level)) 43 | t.is(err.message, expectedMessage) 44 | }) 45 | 46 | test('should error for unknown subsystem', async t => { 47 | const level = 'error' 48 | const subsystem = 'foo' 49 | const expectedMessage = 'Error: No such logger' 50 | const fetch = url => { 51 | return { ok: false, text: () => JSON.stringify({ Message: expectedMessage }) } 52 | } 53 | const fc = Filecoin(fetch) 54 | 55 | const err = await t.throwsAsync(fc.log.level(level, { subsystem })) 56 | t.is(err.message, expectedMessage) 57 | }) 58 | -------------------------------------------------------------------------------- /test/unit/cmd/log/ls.fixtures.json: -------------------------------------------------------------------------------- 1 | { 2 | "sample0": [ 3 | "commands/log", 4 | "fps", 5 | "net.bootstrap", 6 | "messageimpl", 7 | "peerstore", 8 | "swarm2", 9 | "dht.pb", 10 | "autorelay", 11 | "engine", 12 | "eventlog", 13 | "blockstore", 14 | "keystore", 15 | "transport", 16 | "types", 17 | "nat", 18 | "bstestnet", 19 | "sectorbuilder", 20 | "/fil/hello", 21 | "mplex", 22 | "addrutil", 23 | "cmds/http", 24 | "cmds/cli", 25 | "autonat-svc", 26 | "node", 27 | "metrics", 28 | "pubsub", 29 | "chain.store", 30 | "p2p-config", 31 | "basichost", 32 | "boguskey", 33 | "mocknet", 34 | "mockrouter", 35 | "routing/record", 36 | "providers", 37 | "reuseport-transport", 38 | "net/identify", 39 | "secio", 40 | "repo", 41 | "ping", 42 | "peerqueue", 43 | "pathresolv", 44 | "chain.syncer", 45 | "chunk", 46 | "bitswap_network", 47 | "lock", 48 | "stream-upgrader", 49 | "tcp-tpt", 50 | "relay", 51 | "/fil/retrieval", 52 | "/fil/storage", 53 | "cmds", 54 | "porcelain", 55 | "discovery", 56 | "table", 57 | "dht", 58 | "autonat", 59 | "routedhost", 60 | "bitswap", 61 | "blockservice", 62 | "consensus.expected", 63 | "mqueue", 64 | "mining" 65 | ] 66 | } 67 | -------------------------------------------------------------------------------- /test/unit/cmd/log/ls.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../../../../src') 3 | const Fixtures = require('./ls.fixtures.json') 4 | 5 | test('should list logging subsystems', async t => { 6 | const fetch = () => ({ ok: true, json: () => Fixtures.sample0 }) 7 | const fc = Filecoin(fetch) 8 | 9 | const subsystems = await fc.log.ls() 10 | t.deepEqual(subsystems, Fixtures.sample0) 11 | }) 12 | -------------------------------------------------------------------------------- /test/unit/cmd/log/tail.fixtures.json: -------------------------------------------------------------------------------- 1 | { 2 | "sample0": [ 3 | { 4 | "event": "Bitswap.Rebroadcast.idle", 5 | "system": "bitswap", 6 | "time": "2019-02-20T20:06:38.950367Z" 7 | }, 8 | { 9 | "addresses": [ 10 | "/p2p-circuit", 11 | "/ip4/127.0.0.1/tcp/6000", 12 | "/ip4/192.168.0.17/tcp/6000" 13 | ], 14 | "event": "interfaceListenAddresses", 15 | "system": "addrutil", 16 | "time": "2019-02-20T20:06:39.190146Z" 17 | }, 18 | { 19 | "TraceID": 3408245272008122928, 20 | "SpanID": 5014653491894053896, 21 | "ParentSpanID": 0, 22 | "Operation": "secureHandshake", 23 | "Start": "2019-02-20T20:06:39.450455Z", 24 | "Duration": 101526455, 25 | "Tags": { "system": "secio" }, 26 | "Logs": [ 27 | { 28 | "Timestamp": "2019-02-20T20:06:39.450481Z", 29 | "Fields": [ 30 | { 31 | "Key": "remotePeer", 32 | "Value": "QmXhxqTKzBKHA5FcMuiKZv8YaMPwpbKGXHRVZcFB2DX9XY" 33 | } 34 | ] 35 | }, 36 | { 37 | "Timestamp": "2019-02-20T20:06:39.450483Z", 38 | "Fields": [{ "Key": "established", "Value": "false" }] 39 | }, 40 | { 41 | "Timestamp": "2019-02-20T20:06:39.450485Z", 42 | "Fields": [ 43 | { 44 | "Key": "localPeer", 45 | "Value": "QmQbd6WxZ3pwcwWn21MvgH1zH4m8hk148kTfoB6BNFa5hK" 46 | } 47 | ] 48 | } 49 | ] 50 | }, 51 | { 52 | "TraceID": 8787725752423871427, 53 | "SpanID": 3617326162124794397, 54 | "ParentSpanID": 0, 55 | "Operation": "swarmDialDo", 56 | "Start": "2019-02-20T20:06:39.189831Z", 57 | "Duration": 524165660, 58 | "Tags": { "system": "swarm2" }, 59 | "Logs": [ 60 | { 61 | "Timestamp": "2019-02-20T20:06:39.189843Z", 62 | "Fields": [ 63 | { 64 | "Key": "localPeer", 65 | "Value": "QmQbd6WxZ3pwcwWn21MvgH1zH4m8hk148kTfoB6BNFa5hK" 66 | } 67 | ] 68 | }, 69 | { 70 | "Timestamp": "2019-02-20T20:06:39.189844Z", 71 | "Fields": [ 72 | { 73 | "Key": "remotePeer", 74 | "Value": "QmXhxqTKzBKHA5FcMuiKZv8YaMPwpbKGXHRVZcFB2DX9XY" 75 | } 76 | ] 77 | }, 78 | { 79 | "Timestamp": "2019-02-20T20:06:39.189846Z", 80 | "Fields": [{ "Key": "subsystem", "Value": "swarm" }] 81 | } 82 | ] 83 | }, 84 | { 85 | "TraceID": 7182434419962293870, 86 | "SpanID": 3549414091921882411, 87 | "ParentSpanID": 0, 88 | "Operation": "swarmDialAttemptStart", 89 | "Start": "2019-02-20T20:06:39.189792Z", 90 | "Duration": 524365035, 91 | "Tags": { "system": "swarm2" }, 92 | "Logs": [ 93 | { 94 | "Timestamp": "2019-02-20T20:06:39.189816Z", 95 | "Fields": [{ "Key": "subsystem", "Value": "swarm" }] 96 | }, 97 | { 98 | "Timestamp": "2019-02-20T20:06:39.189818Z", 99 | "Fields": [ 100 | { 101 | "Key": "localPeer", 102 | "Value": "QmQbd6WxZ3pwcwWn21MvgH1zH4m8hk148kTfoB6BNFa5hK" 103 | } 104 | ] 105 | }, 106 | { 107 | "Timestamp": "2019-02-20T20:06:39.18982Z", 108 | "Fields": [ 109 | { 110 | "Key": "remotePeer", 111 | "Value": "QmXhxqTKzBKHA5FcMuiKZv8YaMPwpbKGXHRVZcFB2DX9XY" 112 | } 113 | ] 114 | } 115 | ] 116 | }, 117 | { 118 | "TraceID": 325907608848630265, 119 | "SpanID": 5938876069602130660, 120 | "ParentSpanID": 0, 121 | "Operation": "swarmDialAttemptSync", 122 | "Start": "2019-02-20T20:06:39.189623Z", 123 | "Duration": 524595106, 124 | "Tags": { "system": "swarm2" }, 125 | "Logs": [ 126 | { 127 | "Timestamp": "2019-02-20T20:06:39.189668Z", 128 | "Fields": [ 129 | { 130 | "Key": "peerID", 131 | "Value": "QmXhxqTKzBKHA5FcMuiKZv8YaMPwpbKGXHRVZcFB2DX9XY" 132 | } 133 | ] 134 | } 135 | ] 136 | }, 137 | { 138 | "cid": { "/": "zDPWYqFD3j8fr9NcPXtnDp9LcVH4mx9ncr8R2YVMisSoAYj3duRU" }, 139 | "event": "Bitswap.GetBlockRequest.Start", 140 | "system": "bitswap", 141 | "time": "2019-02-20T20:06:39.715203Z" 142 | } 143 | ] 144 | } 145 | -------------------------------------------------------------------------------- /test/unit/cmd/log/tail.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../../../../src') 3 | const { toAsyncIterable } = require('../../../helpers/iterable') 4 | const Fixtures = require('./tail.fixtures.json') 5 | 6 | test('should tail the log', async t => { 7 | const fetch = () => ({ 8 | ok: true, 9 | body: toAsyncIterable(Fixtures.sample0.map(l => JSON.stringify(l) + '\n')) 10 | }) 11 | const fc = Filecoin(fetch) 12 | 13 | let i = 0 14 | for await (const entry of fc.log.tail()) { 15 | t.deepEqual(entry, Fixtures.sample0[i]) 16 | i++ 17 | } 18 | }) 19 | -------------------------------------------------------------------------------- /test/unit/cmd/mining/stop.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../../../../src') 3 | 4 | test('should stop the mining', async t => { 5 | const expectedMessage = 'Stopped mining' 6 | const fetch = () => ({ ok: true, json: () => expectedMessage }) 7 | const fc = Filecoin(fetch) 8 | 9 | const msg = await fc.mining.stop() 10 | t.is(msg, expectedMessage) 11 | }) 12 | -------------------------------------------------------------------------------- /test/unit/cmd/ping.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../../../src') 3 | const { toAsyncIterable } = require('../../helpers/iterable') 4 | 5 | test('should ping a peer', async t => { 6 | const pingResponses = [ 7 | { Count: 0, Time: 187.54 }, 8 | { Count: 1, Time: 173.06 }, 9 | { Count: 2, Time: 182.41 } 10 | ] 11 | 12 | const fetch = () => ({ 13 | ok: true, 14 | body: toAsyncIterable(pingResponses.map(r => JSON.stringify(r) + '\n')) 15 | }) 16 | const fc = Filecoin(fetch) 17 | const peerId = 'QmYWJ4Ft1Rd6RctWjgPJFVwd9QGs5J2Gi3LiXp3C8Kp81C' 18 | 19 | let i = 0 20 | for await (const pong of fc.ping(peerId)) { 21 | t.is(pong.count, pingResponses[i].Count) 22 | t.is(pong.time, pingResponses[i].Time) 23 | i++ 24 | } 25 | }) 26 | 27 | test('should ping a peer with count option', async t => { 28 | const pingResponses = [ 29 | { Count: 0, Time: 187.54 }, 30 | { Count: 1, Time: 173.06 }, 31 | { Count: 2, Time: 182.41 } 32 | ] 33 | 34 | const fetch = url => { 35 | const count = parseInt(new URL(url).searchParams.get('count')) 36 | const responses = pingResponses.slice(0, count).map(r => JSON.stringify(r) + '\n') 37 | return { 38 | ok: true, 39 | body: toAsyncIterable(responses) 40 | } 41 | } 42 | const fc = Filecoin(fetch) 43 | const peerId = 'QmYWJ4Ft1Rd6RctWjgPJFVwd9QGs5J2Gi3LiXp3C8Kp81C' 44 | const count = 2 45 | 46 | let i = 0 47 | for await (const pong of fc.ping(peerId, { count })) { 48 | t.is(pong.count, pingResponses[i].Count) 49 | t.is(pong.time, pingResponses[i].Time) 50 | i++ 51 | } 52 | 53 | t.is(i, count) 54 | }) 55 | -------------------------------------------------------------------------------- /test/unit/cmd/retrieval-client/retrieve-piece.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const { randomBytes } = require('crypto') 3 | const Filecoin = require('../../../../src') 4 | const { toAsyncIterable } = require('../../../helpers/iterable') 5 | 6 | test('should read out piece data stored by a miner on the network', async t => { 7 | const cid = 'QmZPUUg1QVMciR1yYnC2HSFrXyAUwRvpnbx4haYefB2KY3' 8 | const miner = 'fcq5y65n23xdkcx2ymakflxpxqhkvewnwswp0me52' 9 | const chunks = [randomBytes(2048), randomBytes(512), randomBytes(256)] 10 | const fetch = () => ({ ok: true, body: toAsyncIterable(chunks) }) 11 | const fc = Filecoin(fetch) 12 | 13 | const data = [] 14 | for await (const chunk of fc.retrievalClient.retrievePiece(miner, cid)) { 15 | data.push(chunk) 16 | } 17 | 18 | t.deepEqual(Buffer.concat(data), Buffer.concat(chunks)) 19 | }) 20 | -------------------------------------------------------------------------------- /test/unit/cmd/show/block.fixtures.json: -------------------------------------------------------------------------------- 1 | { 2 | "sample0": { 3 | "miner": "", 4 | "ticket": null, 5 | "parents": [ 6 | { 7 | "/": "zDPWYqFCtf5awkxnZbpurnQFvsrafnv4nJbP8UkAHD8GCf8T2Sz4" 8 | } 9 | ], 10 | "height": "AQ==", 11 | "nonce": "AQ==", 12 | "parentWeight": "Mg==", 13 | "messages": [], 14 | "stateRoot": { 15 | "/": "zdpuAm8mTU17dB5mckEDSNXFtvuxVESUhKivSLCWw1kMZjdK9" 16 | }, 17 | "messageReceipts": [] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/unit/cmd/show/block.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../../../../src') 3 | const Fixtures = require('./block.fixtures.json') 4 | 5 | test('should show block info', async t => { 6 | const fetch = () => ({ ok: true, json: () => Fixtures.sample0 }) 7 | const fc = Filecoin(fetch) 8 | const block = await fc.show.block('zDPWYqFCutuHwRZhGXzji9L4eHeoFxxNCxCruGjWje36aAvbK2XV') 9 | 10 | t.deepEqual(block, Fixtures.sample0) 11 | }) 12 | -------------------------------------------------------------------------------- /test/unit/cmd/stats/bandwidth.fixtures.json: -------------------------------------------------------------------------------- 1 | { 2 | "sample0": { 3 | "TotalIn": 7962607306, 4 | "TotalOut": 5437567180, 5 | "RateIn": 1757169.0307054976, 6 | "RateOut": 1066315.9253809578 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/unit/cmd/stats/bandwidth.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../../../../src') 3 | const Fixtures = require('./bandwidth.fixtures.json') 4 | 5 | test('should get bandwidth stats', async t => { 6 | const fetch = () => ({ ok: true, json: () => Fixtures.sample0 }) 7 | const fc = Filecoin(fetch) 8 | 9 | const stats = await fc.stats.bandwidth() 10 | 11 | t.is(stats.totalIn, Fixtures.sample0.TotalIn) 12 | t.is(stats.totalOut, Fixtures.sample0.TotalOut) 13 | t.is(stats.rateIn, Fixtures.sample0.RateIn) 14 | t.is(stats.rateOut, Fixtures.sample0.RateOut) 15 | }) 16 | -------------------------------------------------------------------------------- /test/unit/cmd/swarm/connect.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../../../../src') 3 | 4 | test('should connect to an address', async t => { 5 | const addr = '/ip4/192.168.1.1/tcp/6000/ipfs/QmQbd6WxZ3pwcwWn21MvgH1zH4m8hk148kTfoB6BNFa5hK' 6 | const data = [{ 7 | Peer: 'QmQbd6WxZ3pwcwWn21MvgH1zH4m8hk148kTfoB6BNFa5hK', 8 | Success: true 9 | }] 10 | 11 | const fetch = () => ({ ok: true, json: () => data }) 12 | const fc = Filecoin(fetch) 13 | 14 | const res = await fc.swarm.connect(addr) 15 | 16 | t.true(Array.isArray(res)) 17 | t.is(res.length, 1) 18 | 19 | res.forEach((p, i) => { 20 | t.is(Object.keys(p).length, 2) 21 | t.is(p.peer, data[i].Peer) 22 | t.is(p.success, data[i].Success) 23 | }) 24 | }) 25 | 26 | test('should connect to multiple addresses', async t => { 27 | const addrs = [ 28 | '/ip4/192.168.1.1/tcp/6000/ipfs/QmQbd6WxZ3pwcwWn21MvgH1zH4m8hk148kTfoB6BNFa5hK', 29 | '/ip4/192.168.1.2/tcp/6000/ipfs/QmZUWJ1Uhwjf5ytfTD1ZEh2jJGrp78gFyx9F6sZ9WnqFVR' 30 | ] 31 | 32 | const data = [{ 33 | Peer: 'QmQbd6WxZ3pwcwWn21MvgH1zH4m8hk148kTfoB6BNFa5hK', 34 | Success: true 35 | }, { 36 | Peer: 'QmZUWJ1Uhwjf5ytfTD1ZEh2jJGrp78gFyx9F6sZ9WnqFVR', 37 | Success: false 38 | }] 39 | 40 | const fetch = () => ({ ok: true, json: () => data }) 41 | const fc = Filecoin(fetch) 42 | 43 | const res = await fc.swarm.connect(addrs) 44 | 45 | t.true(Array.isArray(res)) 46 | t.is(res.length, 2) 47 | 48 | res.forEach((p, i) => { 49 | t.is(Object.keys(p).length, 2) 50 | t.is(p.peer, data[i].Peer) 51 | t.is(p.success, data[i].Success) 52 | }) 53 | }) 54 | -------------------------------------------------------------------------------- /test/unit/cmd/swarm/peers.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../../../../src') 3 | 4 | test('should list swarm peers', async t => { 5 | const data = { 6 | Peers: [{ 7 | Addr: '/ip4/103.233.252.158/tcp/6000', 8 | Peer: 'QmZUWJ1Uhwjf5ytfTD1ZEh2jJGrp78gFyx9F6sZ9WnqFVR', 9 | Latency: '', 10 | Muxer: '', 11 | Streams: null 12 | }] 13 | } 14 | 15 | const fetch = () => ({ ok: true, json: () => data }) 16 | const fc = Filecoin(fetch) 17 | 18 | const peers = await fc.swarm.peers() 19 | 20 | t.true(Array.isArray(peers)) 21 | t.is(peers.length, 1) 22 | 23 | peers.forEach((p, i) => { 24 | t.is(Object.keys(p).length, 2) 25 | t.is(p.addr, data.Peers[i].Addr) 26 | t.is(p.peer, data.Peers[i].Peer) 27 | }) 28 | }) 29 | 30 | test('should list swarm peers with verbose option', async t => { 31 | const data = { 32 | Peers: [{ 33 | Addr: '/ip4/103.233.252.158/tcp/6000', 34 | Peer: 'QmZUWJ1Uhwjf5ytfTD1ZEh2jJGrp78gFyx9F6sZ9WnqFVR', 35 | Latency: '213.287947ms', 36 | Muxer: '', 37 | Streams: [ 38 | { Protocol: '/fil/hello/1.0.0' }, 39 | { Protocol: '/fil/hello/1.0.0' }, 40 | { Protocol: '/fil/kad/1.0.0' }, 41 | { Protocol: '/floodsub/1.0.0' }, 42 | { Protocol: '/floodsub/1.0.0' }, 43 | { Protocol: '/ipfs/bitswap/1.1.0' } 44 | ] 45 | }] 46 | } 47 | 48 | const fetch = () => ({ ok: true, json: () => data }) 49 | const fc = Filecoin(fetch) 50 | 51 | const peers = await fc.swarm.peers({ verbose: true }) 52 | 53 | t.true(Array.isArray(peers)) 54 | t.is(peers.length, 1) 55 | 56 | peers.forEach((p, i) => { 57 | t.is(Object.keys(p).length, 5) 58 | t.is(p.addr, data.Peers[i].Addr) 59 | t.is(p.peer, data.Peers[i].Peer) 60 | t.is(p.latency, data.Peers[i].Latency) 61 | t.is(p.muxer, data.Peers[i].Muxer) 62 | t.true(Array.isArray(p.streams)) 63 | t.true(p.streams.every((s, j) => s.protocol === data.Peers[i].Streams[j].Protocol)) 64 | }) 65 | }) 66 | 67 | test('should list swarm peers with streams option', async t => { 68 | const data = { 69 | Peers: [{ 70 | Addr: '/ip4/103.233.252.158/tcp/6000', 71 | Peer: 'QmZUWJ1Uhwjf5ytfTD1ZEh2jJGrp78gFyx9F6sZ9WnqFVR', 72 | Latency: '', 73 | Muxer: '', 74 | Streams: [ 75 | { Protocol: '/fil/hello/1.0.0' }, 76 | { Protocol: '/fil/hello/1.0.0' }, 77 | { Protocol: '/fil/kad/1.0.0' }, 78 | { Protocol: '/floodsub/1.0.0' }, 79 | { Protocol: '/floodsub/1.0.0' }, 80 | { Protocol: '/ipfs/bitswap/1.1.0' } 81 | ] 82 | }] 83 | } 84 | 85 | const fetch = () => ({ ok: true, json: () => data }) 86 | const fc = Filecoin(fetch) 87 | 88 | const peers = await fc.swarm.peers({ streams: true }) 89 | 90 | t.true(Array.isArray(peers)) 91 | t.is(peers.length, 1) 92 | 93 | peers.forEach((p, i) => { 94 | t.is(Object.keys(p).length, 3) 95 | t.is(p.addr, data.Peers[i].Addr) 96 | t.is(p.peer, data.Peers[i].Peer) 97 | t.true(Array.isArray(p.streams)) 98 | t.true(p.streams.every((s, j) => s.protocol === data.Peers[i].Streams[j].Protocol)) 99 | }) 100 | }) 101 | 102 | test('should list swarm peers with latency option', async t => { 103 | const data = { 104 | Peers: [{ 105 | Addr: '/ip4/103.233.252.158/tcp/6000', 106 | Peer: 'QmZUWJ1Uhwjf5ytfTD1ZEh2jJGrp78gFyx9F6sZ9WnqFVR', 107 | Latency: '213.287947ms', 108 | Muxer: '', 109 | Streams: null 110 | }] 111 | } 112 | 113 | const fetch = () => ({ ok: true, json: () => data }) 114 | const fc = Filecoin(fetch) 115 | 116 | const peers = await fc.swarm.peers({ latency: true }) 117 | 118 | t.true(Array.isArray(peers)) 119 | t.is(peers.length, 1) 120 | 121 | peers.forEach((p, i) => { 122 | t.is(Object.keys(p).length, 3) 123 | t.is(p.addr, data.Peers[i].Addr) 124 | t.is(p.peer, data.Peers[i].Peer) 125 | t.is(p.latency, data.Peers[i].Latency) 126 | }) 127 | }) 128 | -------------------------------------------------------------------------------- /test/unit/cmd/version.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../../../src') 3 | 4 | test('should get version', async t => { 5 | const commit = '4e75ee9b601525c45eb255d80ccb73de35102c6d' 6 | const fetch = () => ({ ok: true, json: () => ({ Commit: commit }) }) 7 | const fc = Filecoin(fetch) 8 | const res = await fc.version() 9 | 10 | t.is(res.commit, commit) 11 | }) 12 | -------------------------------------------------------------------------------- /test/unit/cmd/wallet/balance.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../../../../src') 3 | 4 | test('should get wallet balance', async t => { 5 | const expectedBalance = '6900' 6 | const fetch = () => ({ ok: true, json: () => expectedBalance }) 7 | const fc = Filecoin(fetch) 8 | 9 | const balance = await fc.wallet.balance('fcqqr00e38ge3vr90xx7x46gj7hq3dxcl09us08e') 10 | t.is(balance, expectedBalance) 11 | }) 12 | 13 | test('should throw on request error', async t => { 14 | const message = `BOOM${Date.now()}` 15 | const fetch = () => ({ ok: false, text: () => JSON.stringify({ message }) }) 16 | const fc = Filecoin(fetch) 17 | 18 | try { 19 | await fc.wallet.balance('fcqqr00e38ge3vr90xx7x46gj7hq3dxcl09us08e') 20 | } catch (err) { 21 | return t.is(err.message, message) 22 | } 23 | t.fail() 24 | }) 25 | -------------------------------------------------------------------------------- /test/unit/cmd/wallet/export.fixtures.json: -------------------------------------------------------------------------------- 1 | { 2 | "single": { 3 | "KeyInfo": [ 4 | { 5 | "privateKey": "RxOfKlALxw8+XCaHQGaJfpXRWweYl+/xdIxVQfJTaTU=", 6 | "curve": "secp256k1" 7 | } 8 | ] 9 | }, 10 | "multiple": { 11 | "KeyInfo": [ 12 | { 13 | "privateKey": "RxOfKlALxw8+XCaHQGaJfpXRWweYl+/xdIxVQfJTaTU=", 14 | "curve": "secp256k1" 15 | }, 16 | { 17 | "privateKey": "yGZieo9zCXIaQmpqjhhkqHdIy9N7zHJVbE34WJs1aFI=", 18 | "curve": "secp256k1" 19 | }, 20 | { 21 | "privateKey": "wtmOLFQl7HOPCN73GQkMzBMemxk/IJYPcRHkFf6aiWo=", 22 | "curve": "secp256k1" 23 | } 24 | ] 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/unit/cmd/wallet/export.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const Filecoin = require('../../../../src') 3 | const Fixtures = require('./export.fixtures.json') 4 | 5 | test('should export a wallet', async t => { 6 | const fetch = () => ({ ok: true, json: () => Fixtures.single }) 7 | const fc = Filecoin(fetch) 8 | const data = await fc.wallet.export('fcqqr00e38ge3vr90xx7x46gj7hq3dxcl09us08e') 9 | 10 | t.deepEqual(data.keyInfo, Fixtures.single.KeyInfo) 11 | }) 12 | 13 | test('should export multiple wallets', async t => { 14 | const fetch = () => ({ ok: true, json: () => Fixtures.multiple }) 15 | const fc = Filecoin(fetch) 16 | const data = await fc.wallet.export([ 17 | 'fcqqr00e38ge3vr90xx7x46gj7hq3dxcl09us08e', 18 | 't1birbw25eb545u6sty7j3562a753asg6woufhogq', 19 | 't1cybcewm7emhrrcu6gbp63yoehotrjdt4xhvu37y' 20 | ]) 21 | 22 | t.deepEqual(data.keyInfo, Fixtures.multiple.KeyInfo) 23 | }) 24 | -------------------------------------------------------------------------------- /test/unit/lib/fetch.test.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const { ok } = require('../../../src/lib/fetch') 3 | 4 | test('should parse json error response', async t => { 5 | const res = { 6 | ok: false, 7 | text: () => Promise.resolve(JSON.stringify({ 8 | Message: 'boom', 9 | Code: 0, 10 | Type: 'error' 11 | })), 12 | status: 500 13 | } 14 | 15 | const err = await t.throwsAsync(ok(res)) 16 | 17 | t.is(err.message, 'boom') 18 | t.is(err.status, 500) 19 | }) 20 | 21 | test('should fallback to text error response', async t => { 22 | const res = { 23 | ok: false, 24 | json: () => Promise.reject(new Error('failed to parse json')), 25 | text: () => 'boom', 26 | status: 500 27 | } 28 | 29 | const err = await t.throwsAsync(ok(res)) 30 | 31 | t.is(err.message, 'boom') 32 | t.is(err.status, 500) 33 | }) 34 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | mode: 'production', 3 | output: { 4 | filename: 'Filecoin.js', 5 | library: 'Filecoin' 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /webpack.dev.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack') 2 | 3 | module.exports = { 4 | mode: 'development', 5 | output: { 6 | filename: 'Filecoin.js', 7 | library: 'Filecoin' 8 | }, 9 | devtool: false, 10 | plugins: [ 11 | new webpack.SourceMapDevToolPlugin({}) 12 | ] 13 | } 14 | --------------------------------------------------------------------------------