Compare commits

..
187 Commits
Author SHA1 Message Date
Chris Troutner 2ff46c1f76 Merge pull request #82 from Permissionless-Software-Foundation/ct-unstable
fix(axios): Updating axios
2021-01-04 14:49:11 -08:00
Chris Troutner 6926bbe113 fix(axios): Updating axios 2021-01-04 14:44:48 -08:00
Chris Troutner 360f1509dd Merge pull request #81 from Permissionless-Software-Foundation/ct-unstable
Changes to Linting
2021-01-02 16:47:15 -08:00
Chris Troutner d5d2e43ad0 fix(husky): Adding husky for auto linting 2021-01-02 16:44:53 -08:00
Chris Troutner 1012f4c1bf Wrapping up linting 2021-01-02 16:39:44 -08:00
Chris Troutner 3cedd251e5 fix(linting): Adding standard linting rules 2021-01-02 15:41:12 -08:00
Chris Troutner bdb4de0353 Merge pull request #80 from Permissionless-Software-Foundation/ct-unstable
Converting dependencies targeting GitHub repos to npm libraries.
2021-01-01 17:15:43 -08:00
Chris Troutner 1de0bdcf14 Updating bitcoincashjs-lib 2021-01-01 17:12:35 -08:00
Chris Troutner 3a9e4f64b5 Updating bitcoincashjs-lib 2021-01-01 16:50:02 -08:00
Chris Troutner ea57f52b20 fixing dependency in test 2021-01-01 16:39:03 -08:00
Chris Troutner 903aae1091 Fixing references to npm libs 2021-01-01 16:36:12 -08:00
Chris Troutner 1af766cbda fix(coininfo): Switching to forked npm library 2021-01-01 16:29:50 -08:00
Chris Troutner 60ee10ef4d fix(bip21): Switching to npm lib 2021-01-01 16:14:55 -08:00
Chris Troutner 2d4bc6127e fix(bitcoincashjs-lib): Using npm package rather than github repo 2021-01-01 14:30:57 -08:00
Chris Troutner a2c2d41833 fix(bitcoincash-ops): Switching to PSF fork of library 2021-01-01 12:51:54 -08:00
Chris Troutner 0e7db7bf39 fix(bip32-utils): Replacing bip32-utils with PSF maintained fork 2021-01-01 12:39:19 -08:00
Chris Troutner 46de4f6a25 feat(BITBOX Shim): Removing Shim support for BITBOX 2021-01-01 11:56:09 -08:00
Chris Troutner 2acf47a550 feat(wallet): Removing wallet library 2021-01-01 11:45:34 -08:00
Chris Troutner 7fea5c2630 Merge pull request #79 from Permissionless-Software-Foundation/ct-test-joey-slp
Testing Joey's Updates to SLP Handling
2020-12-30 08:52:52 -08:00
Chris Troutner b297743521 feat(SLP): Improved SLP calculation to fix small burns 2020-12-30 08:24:18 -08:00
Chris Troutner 6c33222172 Merge pull request #60 from josephroyking/slp-utils-patch
Resolving correct decimal precision for slp token qty
2020-12-28 05:01:59 -08:00
Chris Troutner 9a36a8261a Merge pull request #54 from josephroyking/generateSendOpReturn-rounding-patch
Generate send op return rounding patch
2020-12-28 04:57:53 -08:00
Chris Troutner 1433c77fcc Merge pull request #78 from Permissionless-Software-Foundation/ct-unstable
feat(Blockbook): Removing support for Blockbook indexer
2020-12-24 10:18:55 -08:00
Chris Troutner b1c3311d50 feat(Blockbook): Removing support for Blockbook indexer 2020-12-24 10:16:41 -08:00
Chris Troutner b3e224e481 Cleaned up integration tests 2020-12-24 10:06:39 -08:00
Chris Troutner 06e2dad45c Ran npm audit fix 2020-12-24 09:26:36 -08:00
Chris Troutner d475f2220f feat(SLPDB status): Created bchjs.SLP.Utils.getStatus() to get health status of SLPDB 2020-12-24 09:25:35 -08:00
Chris Troutner 10520a2e08 Merge pull request #75 from Permissionless-Software-Foundation/ct-unstable
fix(tokenUtxoDetails): Renabling local caching of tx validation
2020-12-13 09:16:17 -08:00
Chris Troutner 05b654d54a fix(tokenUtxoDetails): Renabling local caching of tx validation 2020-12-13 09:14:06 -08:00
Chris Troutner 3c4051c3a5 Merge pull request #74 from Permissionless-Software-Foundation/ct-unstable
fix(tokenUtxoDetails): Updating to handle alternative output from SLPDB
2020-12-13 09:00:48 -08:00
Chris Troutner 0f3cc1e9e8 Merge branch 'master' into ct-unstable 2020-12-13 08:56:28 -08:00
Chris Troutner b9873f7ed8 Added additional corner case unit test for tokenUtxoDetails() 2020-12-13 08:56:09 -08:00
Chris Troutner 82cd9270fa fix(tokenUtxoDetails): Updating to handle alternative output from SLPDB 2020-12-13 08:51:58 -08:00
Chris Troutner ac6b45b162 Merge pull request #73 from Permissionless-Software-Foundation/ct-unstable
fix(debugging): Additional debugging
2020-12-13 07:26:07 -08:00
Chris Troutner 66a99c0560 Merge branch 'master' into ct-unstable 2020-12-13 07:20:08 -08:00
Chris Troutner 17e4a32ff4 fix(debugging): Additional debugging 2020-12-13 07:19:24 -08:00
Chris Troutner 6a430b4da6 Merge pull request #72 from Permissionless-Software-Foundation/ct-unstable
fix(debugging): Debugging problem with hydrateUtxos()
2020-12-13 06:55:48 -08:00
Chris Troutner 77ab090bc2 fix(debugging): Debugging problem with hydrateUtxos() 2020-12-13 06:51:07 -08:00
Chris Troutner fdff4a1afb Merge pull request #71 from Permissionless-Software-Foundation/ct-unstable
fix(tokenUtxoDetails): Fixing bug with fallback validators
2020-12-13 06:25:10 -08:00
Chris Troutner 12701cf3dc fix(tokenUtxoDetails): Fixing bug with fallback validators 2020-12-13 06:20:51 -08:00
Chris Troutner 1032625ac8 Merge pull request #70 from Permissionless-Software-Foundation/ct-unstable
blockbook: Removing blockbook support from testnet
2020-12-11 15:19:36 -08:00
Chris Troutner 586c2972da feat(blockbook): Removing blockbook support from testnet 2020-12-11 15:15:03 -08:00
Chris Troutner 3d41e41192 fix(testnet): Updating integration tests 2020-12-11 14:59:46 -08:00
Chris Troutner af8e0cdf45 Merge pull request #69 from Permissionless-Software-Foundation/ct-unstable
fix(testnet): Fixing testnet integration tests
2020-12-08 18:36:54 -08:00
Chris Troutner 10f6f58ec5 fix(testnet): Fixing testnet integration tests 2020-12-08 18:28:30 -08:00
Chris Troutner fd9f399f41 Merge pull request #68 from Permissionless-Software-Foundation/ct-unstable
Added test/integration/implementations/
2020-12-08 17:59:49 -08:00
Chris Troutner 98582edd0b Merge branch 'master' into ct-unstable 2020-12-08 17:56:03 -08:00
Chris Troutner 07b7cb0afd Added test/integration/implementations/ for customized integration tests for different implementations 2020-12-08 17:55:47 -08:00
Chris Troutner dda9658375 Merge pull request #67 from Permissionless-Software-Foundation/ct-unstable
Refactoring integration tests
2020-12-08 17:45:22 -08:00
Chris Troutner 358dad533d Removing old bchn integration tests 2020-12-08 17:42:31 -08:00
Chris Troutner 7a63573143 fix(integration): Refactored abc and bchn integration tests 2020-12-08 17:23:41 -08:00
Chris Troutner 333ced5c79 updating gitignore 2020-12-07 15:54:56 -08:00
Chris Troutner c6ceae1283 Merge pull request #65 from Permissionless-Software-Foundation/ct-unstable
fix(semantic-release): Updating to 17.3.0
2020-12-06 19:59:16 -08:00
Chris Troutner 4e8a376720 fix(semantic-release): Updating to 17.3.0 2020-12-06 19:54:44 -08:00
Chris Troutner cee348cb3e Merge pull request #64 from Permissionless-Software-Foundation/ct-unstable
fix(tests): Cleaning up integration tests
2020-12-06 19:44:35 -08:00
Chris Troutner 75e56e7aa7 Merge branch 'master' into ct-unstable 2020-12-06 19:39:35 -08:00
Chris Troutner d6ae6ffb6b fix(tests): Cleaning up integration tests 2020-12-06 19:39:23 -08:00
Chris Troutner 12f6547167 Merge pull request #63 from Permissionless-Software-Foundation/ct-unstable
feat(tokenUtxoDetails()): Using fallback SLP validators
2020-12-06 19:21:34 -08:00
Chris Troutner d1847d2eca feat(tokenUtxoDetails()): Using fallback SLP validators 2020-12-06 19:18:47 -08:00
Chris Troutner 1f01e6ae47 fix(tokenUtxoDetails): Catching and invalidating malformed SLP OP_RETURNs 2020-12-06 18:40:14 -08:00
Chris Troutner 1375601a81 Restored all unit tests 2020-12-06 17:41:43 -08:00
Chris Troutner e97a8e7cf5 fix(slp utils): refactoring unit tests 2020-12-06 15:41:39 -08:00
Chris Troutner 3df211301c fix(unit tests): Refactored a lot of code flow 2020-12-06 14:51:48 -08:00
Chris Troutner a81dec068c fix(address unit tests): Fixed to prevent network call 2020-12-06 13:48:06 -08:00
Chris Troutner 4af6716631 Editing slp-util unit tests 2020-12-06 13:07:35 -08:00
Chris Troutner 98f7cb8f3a encapsulating and mocking axios in the slp-utils lib and unit tests 2020-12-06 09:59:01 -08:00
Chris Troutner 348a67a79b tokenUtxoDetails: prototyped different validation methods 2020-12-06 09:49:30 -08:00
Chris Troutner a9c128f96b Merge pull request #62 from Permissionless-Software-Foundation/ct-unstable
fix(unit test): Fixing changing test
2020-12-05 21:49:27 -08:00
Chris Troutner bdf1c50c9d fix(unit test): Fixing changing test 2020-12-05 21:47:26 -08:00
Chris Troutner ccc545b1be Bumping to v4.0 2020-12-05 20:51:50 -08:00
Chris Troutner c6301055fa Merge pull request #61 from Permissionless-Software-Foundation/ct-unstable
perf(v4): Switching to bch-api v4 routes
2020-12-05 20:48:23 -08:00
Chris Troutner 13d9f89a82 Commenting out test that still needs to be mocked 2020-12-05 20:44:53 -08:00
Chris Troutner f5de593f89 fix(tests): Getting all tests passing 2020-12-05 20:42:07 -08:00
Chris Troutner 3b0ec95fba perf(v4): Switching to bch-api v4 routes 2020-12-05 19:28:33 -08:00
Chris Troutner 0a328090ea saving confused progress 2020-12-05 19:06:11 -08:00
Chris Troutner 315cb4f254 feat(whitelist): Added method for getting SLPDB whitelist 2020-12-05 14:02:39 -08:00
Chris Troutner 28f08f02ac fix(ABC): fixed integration tests that broke 2020-12-05 12:23:41 -08:00
Joey King ad5fabf2e6 Remove stub test 2020-12-03 06:57:44 -08:00
Joey King f8f6db069b Implementing BigNumber for all tokenQty calcs 2020-12-03 06:56:05 -08:00
Joey King df620e0302 stub test method 2020-12-02 16:06:10 -08:00
Joey King 19f2e87528 Resolving correct decimal precision for slp token qty 2020-12-02 16:02:07 -08:00
Chris Troutner 5949e0f6f8 Changing free-tier to bchn 2020-11-23 07:51:19 -08:00
Chris Troutner 617bb16ddb Merge pull request #59 from Permissionless-Software-Foundation/ct-unstable
fix(price): Removing documentation for deprecated endpoint
2020-11-17 17:12:45 -08:00
Chris Troutner 83f14f5522 fix(price): Removing documentation for deprecated endpoint 2020-11-17 17:09:23 -08:00
Chris Troutner b8e22e1c99 Merge pull request #58 from Permissionless-Software-Foundation/ct-unstable
fix(price): Adding BCHA price
2020-11-17 14:47:47 -08:00
Chris Troutner 72d560e407 fix(price): Adding BCHA price 2020-11-17 14:41:04 -08:00
Chris Troutner 248b2fa2a6 Merge pull request #57 from Permissionless-Software-Foundation/ct-unstable
fix(basic auth): Fixing some bugs around basic auth
2020-11-12 09:52:29 -08:00
Chris Troutner 563cb297fe fix(basic auth): Fixing some bugs around basic auth 2020-11-12 09:48:54 -08:00
Chris Troutner 4c020240e1 fix(rate limits): Updated e2e tests for post-fork servers 2020-11-11 18:39:57 -08:00
Chris Troutner e070409a95 Merge pull request #56 from Permissionless-Software-Foundation/ct-unstable
Basic Authentication
2020-11-11 18:20:09 -08:00
Chris Troutner fbbd855145 feat(Basic Authentication): Adding authPass for auth token to all libraries 2020-11-11 17:47:46 -08:00
Chris Troutner 731987b35b fix(Basic Authentication): Adding back in 2020-11-11 14:56:53 -08:00
Chris Troutner 1e8e7b79f2 Updating comments in e2e rate limit tests 2020-11-11 14:11:13 -08:00
Joey King b512b222dd Adding large test tx 2020-11-10 14:28:10 -08:00
Joey King 650e3b53fc Adding tests and checks 2020-11-10 13:38:41 -08:00
Chris Troutner 099eb25e88 Merge pull request #53 from Permissionless-Software-Foundation/ct-unstable
fix(blockbook): Removing documentation as a step towards deprecation
2020-11-10 08:44:32 -08:00
Chris Troutner 12a7c666c6 fix(blockbook): Removing documentation as a step towards deprecation 2020-11-10 08:39:26 -08:00
Chris Troutner e482e09e77 Merge pull request #52 from Permissionless-Software-Foundation/ninsight-tx-details
Add Ninsight TX Details
2020-11-10 08:27:12 -08:00
Chris Troutner 7ca6498ca0 feat(Ninsight): Adding TX Details endpoint 2020-11-10 08:24:19 -08:00
Chris Troutner f89b52ac86 Merge branch 'master' into ninsight-tx-details 2020-11-10 08:21:07 -08:00
Joey King 905658ca28 format changes take two 2020-11-10 06:19:36 -08:00
Joey King b0c91c407d matching original formatting 2020-11-10 06:13:53 -08:00
Joey King d2c68efc0c Use BigNumber to eliminate rounding error token burns 2020-11-10 06:10:38 -08:00
Stoyan Zhekov 7990d0bffd Add Ninsight TX Details 2020-11-10 19:04:16 +09:00
Chris Troutner c0eaaf77c8 fix(integration tests): Updating scripts in package.json 2020-11-09 18:17:44 -08:00
Chris Troutner f424047a69 Merge pull request #51 from Permissionless-Software-Foundation/ninsight-tx-history
Add Ninsight TX History to bch-js
2020-11-09 16:14:39 -08:00
Chris Troutner fc0d8b7f8c fix(ninsight): Adding tx history endpoint 2020-11-09 16:12:10 -08:00
Chris Troutner 4551d1ca99 Merge pull request #50 from Permissionless-Software-Foundation/ninsight-unconfirmed-utxos
Add Ninsight Unconfirmed UTXOs
2020-11-09 15:47:11 -08:00
Chris Troutner b8083c6b88 fix(ninsight): Adding unconfirmed UTXOs endpoint 2020-11-09 15:45:11 -08:00
Stoyan Zhekov 0ef8555837 Add Ninsight TX History to bch-js 2020-11-09 19:49:41 +09:00
Stoyan Zhekov a7564ce611 Add Ninsight Unconfirmed UTXOs 2020-11-09 17:44:09 +09:00
Chris Troutner 601b87cb4a Updating README 2020-11-08 19:14:43 -08:00
Chris Troutner edfcc92b7b Merge pull request #48 from Permissionless-Software-Foundation/ct-unstable
Updating README
2020-11-08 19:04:29 -08:00
Chris Troutner a32e0da9be Updating README 2020-11-08 19:02:30 -08:00
Chris Troutner a1bf617d91 Updating README 2020-11-08 18:56:48 -08:00
Chris Troutner 33d2da503d Updating READMe 2020-11-08 18:49:45 -08:00
Chris Troutner c2ff1e2d68 Updating npm lib 2020-11-08 17:46:40 -08:00
Chris Troutner cc9e8c0319 Fixing links in README 2020-11-08 17:38:11 -08:00
Chris Troutner 83389129d6 Merge pull request #47 from Permissionless-Software-Foundation/ct-unstable
fix(network): Updates for fork
2020-11-08 14:07:01 -08:00
Chris Troutner 360d56e283 fix(network): Updates for fork 2020-11-08 14:05:10 -08:00
Chris Troutner 53a0da4ef1 Merge branch 'master' into ct-unstable 2020-11-08 09:36:41 -08:00
Chris Troutner 6d4534f177 Removing test 2020-11-08 09:36:31 -08:00
Chris Troutner 90ec06adaa Merge pull request #46 from Permissionless-Software-Foundation/ct-unstable
Updating e2e rate limit tests
2020-11-08 09:33:29 -08:00
Chris Troutner a6759cdae5 Testing CI 2020-11-08 09:26:24 -08:00
Chris Troutner 078f157e4e fix(rate limits): Updating e2e rate limit tests for new bch-api rate limits 2020-11-08 09:15:53 -08:00
Chris Troutner 98029f74f8 Merge pull request #45 from Permissionless-Software-Foundation/ct-unstable
fix(integration tests): slowing down integration tests for BVT
2020-11-03 09:40:53 -08:00
Chris Troutner 9348ccb7de fix(integration tests): slowing down integration tests for BVT 2020-11-03 08:14:55 -08:00
Chris Troutner 6a6f5fa5fa Merge pull request #44 from Permissionless-Software-Foundation/ct-unstable
Updates to Integration Tests
2020-11-02 15:45:20 -08:00
Chris Troutner 9863fad6a6 fix(testnet): Updating testnet integration tests to pass BVT 2020-11-02 14:49:28 -08:00
Chris Troutner 3a2f38bcf0 fix(integration): Removed all non-integration tests from integration tests 2020-11-02 14:27:31 -08:00
Chris Troutner bc5c7052a1 Merge pull request #43 from Permissionless-Software-Foundation/ct-unstable
Ct unstable
2020-10-31 11:07:41 -07:00
Chris Troutner 89d5171e92 Merge branch 'master' into ct-unstable 2020-10-31 11:04:33 -07:00
Chris Troutner c80a0dcde4 fix(bchn): Starting separate integration tests for bchn 2020-10-30 16:05:26 -07:00
Chris Troutner a2f7ae7fb4 fix(electrumx): Updates for new abc v0.22.4 2020-10-30 15:10:55 -07:00
Chris Troutner 4c2c7a4f6f Merge pull request #42 from Permissionless-Software-Foundation/ct-unstable
fix(hydrateUtxos): Fixing integration test
2020-10-30 07:45:06 -07:00
Chris Troutner 6efb08565a fix(hydrateUtxos): Fixing integration test 2020-10-29 21:46:53 -07:00
Chris Troutner 8a8dcbe593 Merge pull request #41 from Permissionless-Software-Foundation/ct-unstable
fix(integration tests): Updating testnet integration tests
2020-10-29 08:08:17 -07:00
Chris Troutner ae58895d71 fix(integration tests): Updating testnet integration tests 2020-10-29 07:18:59 -07:00
Chris Troutner a50ace320b Merge pull request #40 from Permissionless-Software-Foundation/ct-unstable
fix(rawtransactions): Updating integration test for latest version of…
2020-10-27 19:16:41 -07:00
Chris Troutner b1d583cfe4 fix(rawtransactions): Updating integration test for latest version of ABC 2020-10-27 18:03:32 -07:00
Chris Troutner 0b86a19726 Merge pull request #39 from Permissionless-Software-Foundation/ct-unstable
fix(price): Fixing broken integration test
2020-10-20 18:34:13 -07:00
Chris Troutner eb3bc7bcff fix(price): Fixing broken integration test 2020-10-20 18:18:18 -07:00
Chris Troutner c5361e0516 Merge pull request #38 from Permissionless-Software-Foundation/ct-unstable
fix(docs): Update to price documentation
2020-10-19 19:55:57 -07:00
Chris Troutner 54d9233f41 fix(docs): Update to price documentation 2020-10-19 19:46:27 -07:00
Chris Troutner 37a5f0e6fa Merge pull request #37 from Permissionless-Software-Foundation/ct-unstable
feat(price): Added additional endpoints for retrieving market price o…
2020-10-19 19:40:51 -07:00
Chris Troutner 2180b14e1f feat(price): Added additional endpoints for retrieving market price of BCH 2020-10-19 19:36:55 -07:00
Chris Troutner 40e1704572 Merge pull request #36 from Permissionless-Software-Foundation/ct-unstable
Added testnet SLP integration tests
2020-10-16 22:25:59 -07:00
Chris Troutner 9539119c57 fix(testnet): Added additional integration tests for testnet SLP 2020-10-16 22:22:18 -07:00
Chris Troutner b397381c7d fix(hydrateUtxos): Improving documentation 2020-10-13 21:49:22 -07:00
Chris Troutner 6cdb9a0867 fix(documentation): Fixing documentation conflict on slp addrs 2020-10-13 15:58:45 -07:00
Chris Troutner 01f45d7103 Merge pull request #34 from Permissionless-Software-Foundation/ct-unstable
fix(tokenUtxoDetails): handling dust attack transactions better
2020-10-11 17:59:04 -07:00
Chris Troutner ba38d3e107 fix(tokenUtxoDetails): handling dust attack transactions better 2020-10-11 17:46:27 -07:00
Chris Troutner cbb0d0a8ca Merge pull request #33 from Permissionless-Software-Foundation/ct-unstable
validateTxid2
2020-10-11 16:51:40 -07:00
Chris Troutner 7ec8442540 fix(Electrumx.blockHeader): Mocking negative test-case unit tests 2020-10-11 15:39:17 -07:00
Chris Troutner be3094fc77 feat(validateTxid2): slp-validate based validation of SLP txids 2020-10-11 15:23:50 -07:00
Chris Troutner d35f0e5473 Merge pull request #30 from Permissionless-Software-Foundation/broacast-tx
Add Electrumx Broadcast TX method
2020-10-09 11:35:12 -07:00
Chris Troutner 79088fc68d linting 2020-10-09 11:30:07 -07:00
Chris Troutner fe84729737 Merge branch 'master' into broacast-tx 2020-10-09 11:21:29 -07:00
Chris Troutner 2ec72e73c1 Merge pull request #32 from Permissionless-Software-Foundation/ct-unstable
fix(bchn): Adding bchn free tier to integration tests
2020-10-09 11:21:05 -07:00
Chris Troutner a2c121bf3b fix(bchn): Adding bchn free tier to integration tests 2020-10-09 11:17:40 -07:00
Chris Troutner fd6f58fd45 Merge pull request #31 from Permissionless-Software-Foundation/ct-unstable
fix(decodeOpReturn): Added additional comments
2020-10-07 10:53:01 -07:00
Chris Troutner e8b2f88ff5 fix(decodeOpReturn): Added additional comments 2020-10-07 08:07:06 -07:00
Chris Troutner 4a11db7c45 Merge pull request #29 from kaellis/master
add internal caching for slp.tokenUtxoDetails to reduce duplicate calls
2020-10-07 08:02:08 -07:00
Stoyan Zhekov af118f8a62 Add Electrumx Broadcast TX method 2020-10-07 17:14:30 +09:00
Ken Ellis 1f41b67e3b add internal caching for slp.tokenUtxoDetails to reduce duplicate calls 2020-10-01 09:33:06 -04:00
Chris Troutner 054fb9c14e Merge pull request #28 from Permissionless-Software-Foundation/ct-unstable
Improvements to hydrateUtxos()
2020-09-28 19:33:20 -07:00
Chris Troutner 1fd4095dcb fix(hydateUtxos): Refined integration test 2020-09-28 19:30:06 -07:00
Chris Troutner 0eb1f74ba1 fix(hydrateUtxos): fixing documentation for the function 2020-09-28 19:18:27 -07:00
Chris Troutner 1a13c41c22 Merge pull request #27 from Permissionless-Software-Foundation/ct-unstable
fix(tokenUtxoDetails): returning isValid:null when 429 error encounte…
2020-09-28 18:00:27 -07:00
Chris Troutner 8b6952b1d4 Updating docs 2020-09-28 17:52:37 -07:00
Chris Troutner 73dd2c010d fix(tokenUtxoDetails): returning isValid:null when 429 error encountered with decodeOpReturn() 2020-09-28 17:39:26 -07:00
Chris Troutner 70743876d2 Merge pull request #25 from Permissionless-Software-Foundation/ct-unstable
fix(hydrateUtxos): Adapted to accept Electrumx.utxo() output
2020-09-27 17:56:36 -07:00
Chris Troutner ab51afb2a8 fix(hydrateUtxos): Adapted to accept Electrumx.utxo() output 2020-09-27 17:52:31 -07:00
Chris Troutner 8a59374831 Merge pull request #24 from Permissionless-Software-Foundation/ct-unstable
feat(SLP.Utils.hydrateUtxos): Added hydrateUtxos to match new bch-api…
2020-09-27 01:51:53 -07:00
Chris Troutner 32b8efa7a2 feat(SLP.Utils.hydrateUtxos): Added hydrateUtxos to match new bch-api endpoint 2020-09-27 01:47:46 -07:00
Chris Troutner b0bdc50193 Merge pull request #22 from Permissionless-Software-Foundation/add-electrumx-raw-tx-data
Add ElectrumX Raw Transaction Details method and tests
2020-09-12 06:58:33 -07:00
Stoyan Zhekov 0a897f19bb code, unit and integration tests and api-doc added 2020-09-11 23:46:01 +09:00
Chris Troutner d8e746acd9 Merge pull request #21 from Permissionless-Software-Foundation/add-electrumx-get-block-header
Add ElectrumX get block headers method and tests
2020-09-11 07:17:47 -07:00
Stoyan Zhekov 47bd0d66bc Add ElectrumX get block headers method and tests 2020-09-01 23:52:50 +09:00
Chris Troutner 6a4a861c07 Merge pull request #20 from Permissionless-Software-Foundation/ct-unstable
fix(ninsight): fixing testnet integration test
2020-08-13 16:45:45 -07:00
Chris Troutner caee2db99e fix(ninsight): fixing testnet integration test 2020-08-13 16:41:49 -07:00
Chris Troutner 392f51b166 Merge pull request #19 from Permissionless-Software-Foundation/ct-unstable
fix(ninsight): Fixing failing ninsight integration test
2020-08-13 16:19:06 -07:00
Chris Troutner 8facfd69ac fix(ninsight): Fixing failing ninsight integration test 2020-08-13 16:07:08 -07:00
Chris Troutner 7f1b87215c Merge branch 'master' into ct-unstable 2020-08-13 15:44:37 -07:00
Chris Troutner 662e53aaa2 debugging ninsight test 2020-08-13 15:44:26 -07:00
Chris Troutner 98fc4b9530 Merge pull request #18 from Permissionless-Software-Foundation/update/cleanUp-docs
Clean up documentation
2020-08-13 15:43:57 -07:00
nicocappabianca de8c8e6284 clean up documentation 2020-08-12 21:34:50 -03:00
121 changed files with 15646 additions and 9473 deletions
+30
View File
@@ -0,0 +1,30 @@
# http://editorconfig.org
# A special property that should be specified at the top of the file outside of
# any sections. Set to true to stop .editor config file search on current file
root = true
[*]
# Indentation style
# Possible values - tab, space
indent_style = space
# Indentation size in single-spaced characters
# Possible values - an integer, tab
indent_size = 2
# Line ending file format
# Possible values - lf, crlf, cr
end_of_line = lf
# File character encoding
# Possible values - latin1, utf-8, utf-16be, utf-16le
charset = utf-8
# Denotes whether to trim whitespace at the end of lines
# Possible values - true, false
trim_trailing_whitespace = true
# Denotes whether file should end with a newline
# Possible values - true, false
insert_final_newline = true
+6 -51
View File
@@ -1,55 +1,10 @@
{
"root": true,
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module"
"extends": "standard",
"env": {
"node": true,
"mocha": true
},
"plugins": ["prettier"],
"rules": {
"no-debugger": ["warn"],
"no-regex-spaces": ["error"],
"no-unsafe-negation": ["error"],
"curly": ["error", "multi-or-nest", "consistent"],
"dot-location": ["error", "property"],
"dot-notation": ["error"],
"eqeqeq": ["error", "smart"],
"no-else-return": ["error"],
"no-extra-bind": ["error"],
"no-extra-label": ["error"],
"no-floating-decimal": ["error"],
"no-implicit-coercion": ["error", { "allow": ["!!"] }],
"wrap-iife": ["error", "inside"],
"strict": ["error", "global"],
"func-call-spacing": ["error", "never"],
"comma-style": ["error", "last"],
"keyword-spacing": ["error"],
"linebreak-style": ["error", "unix"],
"new-parens": ["error"],
"no-lonely-if": ["error"],
"no-multiple-empty-lines": ["error", { "max": 2, "maxEOF": 1 }],
"no-whitespace-before-property": ["error"],
"semi": ["error", "never"],
"arrow-body-style": ["error", "as-needed"],
"arrow-parens": ["error", "as-needed"],
"arrow-spacing": ["error"],
"no-useless-computed-key": ["error"],
"no-useless-rename": ["error"],
"no-var": ["off"],
"prefer-spread": ["off"],
"prefer-template": ["error"],
"rest-spread-spacing": ["error", "never"],
"prefer-const": ["warn", { "destructuring": "all" }],
"no-unreachable": ["warn"],
"no-unused-vars": ["warn", { "args": "none" }],
"prettier/prettier": [
"warn",
{
"printWidth": 80,
"trailingComma": "none",
"singleQuote": false,
"semi": false
}
]
"parserOptions": {
"ecmaVersion": 8
}
}
+1
View File
@@ -2,6 +2,7 @@ node_modules/*
.nyc_output/*
wallet-info.txt
wallet.json
integration-test-sweet.sh
docs/
coverage/
+42 -52
View File
@@ -1,68 +1,71 @@
# bch-js
[![Build Status](https://travis-ci.org/christroutner/bch-js.svg?branch=master)](https://travis-ci.org/christroutner/bch-js)
[![Version](https://img.shields.io/npm/v/@chris.troutner/bch-js)](https://www.npmjs.com/package/@chris.troutner/bch-js)
[![Downloads/week](https://img.shields.io/npm/dw/@chris.troutner/bch-js)](https://npmjs.org/package/@chris.troutner/bch-js)
[![License](https://img.shields.io/npm/l/@chris.troutner/bch-js)](https://github.com/christroutner/bch-js/blob/master/LICENSE.md)
[![Build Status](https://travis-ci.org/Permissionless-Software-Foundation/bch-js.svg?branch=master)](https://travis-ci.org/Permissionless-Software-Foundation/bch-js)
[![Version](https://img.shields.io/npm/v/@psf/bch-js)](https://www.npmjs.com/package/@psf/bch-js)
[![Downloads/week](https://img.shields.io/npm/dw/@psf/bch-js)](https://npmjs.org/package/@psf/bch-js)
[![License](https://img.shields.io/npm/l/@psf/bch-js)](https://github.com/Permissionless-Software-Foundation/bch-js/blob/master/LICENSE.md)
[bch-js](https://www.npmjs.com/package/@chris.troutner/bch-js) is a JavaScript npm library for creating web and mobile apps for interacting with the Bitcoin Cash (BCH) blockchain. It can be used for free, but requires an account on [FullStack.cash](https://fullstack.cash) for increased rate limits. Find out more from [this article](https://troutsblog.com/research/bitcoin-cash/how-to-bch-full-stack-developer).
[bch-js](https://www.npmjs.com/package/@psf/bch-js) is a JavaScript npm library for creating web and mobile apps that can interact with the Bitcoin Cash (BCH) blockchains. It can be used for free, but requires an account on [FullStack.cash](https://fullstack.cash) for increased rate limits. Learn more from [this article](https://troutsblog.com/research/bitcoin-cash/how-to-bch-full-stack-developer) about Full Stack Bitcoin Cash development.
### Quick Start Videos:
Here are two YouTube walk-through videos to help you get started:
- [Introduction to bch-js and the bch-js-examples repository](https://youtu.be/GD2i1ZUiyrk)
- [Working with the FullStack.cash JWT token](https://youtu.be/GD2i1ZUiyrk)
### Quick Links
- [npm Library](https://www.npmjs.com/package/@chris.troutner/bch-js)
- [npm Library](https://www.npmjs.com/package/@psf/bch-js)
- [Documentation](https://bchjs.fullstack.cash/)
- [Examples](https://github.com/Permissionless-Software-Foundation/bch-js-examples)
- [api.fullstack.cash](https://api.fullstack.cash) - The REST API this library talks to by default.
- [bchn.fullstack.cash](https://bchn.fullstack.cash) - The REST API this library talks to by default.
- [FullStack.cash](https://fullstack.cash) - cloud-based infrastructure for application developers.
- [FullStack.cash Account](https://fullstack.cash/login) - Get your API key to unlock increased rate limits.
- [FullStack.cash](https://fullstack.cash) - cloud-based infrastructure for application
developers.
- [Permissionless Software Foundation](https://psfoundation.cash) - The organization that maintains this library.
### Quick Notes
- Install library: `npm install @chris.troutner/bch-js`
- Install library: `npm install @psf/bch-js`
- Instantiate the library in your code:
```
const BCHJS = require("@chris.troutner/bch-js")
let bchjs = new BCHJS()
const BCHJS = require("@psf/bch-js")
let bchjs = new BCHJS() // Defaults to BCHN network.
// testnet
bchjs = new BCHJS({ restURL: 'https://tapi.fullstack.cash/v3/' })
bchjs = new BCHJS({ restURL: 'https://testnet3.fullstack.cash/v3/' })
```
This is a fork of the [BITBOX SDK](https://github.com/Bitcoin-com/bitbox-sdk) (which is maintained by Bitcoin.com). This library is intended to be paired with
the [bch-api](https://github.com/christroutner/bch-api) REST API.
This library is intended to be paired with
the [bch-api](https://github.com/Permissionless-Software-Foundation/bch-api) REST API, and the infrastructure provided by [FullStack.cash](https://fullstack.cash). The `restURL` property can be changed to work with different Bitcoin Cash networks:
If you need a backward-compatible instance of this library, you can use a
'shim'. Do it like this:
```
const BCHJS = require("@chris.troutner/bch-js")
const bitbox = BCHJS.BitboxShim({ restURL: 'https://api.fullstack.cash/v3/' })
```
- BCHN Mainnet REST API server: https://bchn.fullstack.cash/v3/
- ABC Mainnet REST API server: https://abc.fullstack.cash/v3/
- Testnet3 REST API server: https://testnet3.fullstack.cash/v3/
- Check server status: https://metrics.fullstack.cash
### API Key
The [bch-api](https://github.com/christroutner/bch-api) REST API hosted by [FullStack.cash](https://fullstack.cash) uses JWT tokens to pay for increased
rate limits when interacting with the back end server. See [this article](https://troutsblog.com/research/bitcoin-cash/how-to-bch-full-stack-developer) if you want to understand the system-as-a-whole. The JWT token can be fed to bch-js *implicitly* or *explicitly*.
- Implicitly: bch-js will detect your JWT token by setting the `BCHJSTOKEN` environment variable.
The [bch-api](https://github.com/Permissionless-Software-Foundation/bch-api) REST API hosted by [FullStack.cash](https://fullstack.cash) uses JWT tokens to pay for increased
rate limits when interacting with the back end server. See [this article](https://troutsblog.com/research/bitcoin-cash/how-to-bch-full-stack-developer) if you want to understand the system-as-a-whole. The JWT token can be fed to bch-js _implicitly_ or _explicitly_.
- Implicitly: bch-js will detect your JWT token if you set the `BCHJSTOKEN` environment variable.
- Explicitly: You can directly feed in the JWT token with the `apiToken` property when instantiating the library. Here is an example:
```
const BCHJS = require("@chris.troutner/bch-js")
const BCHJS = require("@psf/bch-js")
let bchjs = new BCHJS({
restURL: 'https://api.fullstack.cash/v3/',
restURL: 'https://bchn.fullstack.cash/v3/',
apiToken: 'eyJhbGciO...' // Your JWT token here.
})
```
### Gatsby
bch-js is included in this [gatsby-ipfs-template](https://github.com/Permissionless-Software-Foundation/gatsby-ipfs-template) for building uncensorable web apps that can interact with the blockchain. When building a Gatsby (or other front-end app that uses Webpack), you'll need to add these lines to your `gatsby-node.js` file, as per [this issue](https://github.com/gatsbyjs/gatsby/issues/564):
```
exports.onCreateWebpackConfig = ({ actions }) => {
actions.setWebpackConfig({
@@ -75,60 +78,47 @@ exports.onCreateWebpackConfig = ({ actions }) => {
This is because the new IPFS class in bch-js uses the fs library for uploading files, which is not supported by Gatsby.
We also provide [minimal-slp-wallet-web](https://www.npmjs.com/package/minimal-slp-wallet-web) as a basic Bitcoin Cash wallet with SLP support, for front end projects. bch-js is encapsulated inside the instantiation of the library Class.
## Features
This library sets itself apart from BITBOX with the following features:
- [ECMAScript 2017 standard JavaScript](https://en.wikipedia.org/wiki/ECMAScript#8th_Edition_-_ECMAScript_2017) used instead of TypeScript. Works
natively with node.js v10 or higher.
natively with node.js v10 or higher.
- Full SLP tokens support: bch-js has full support for all SLP token functionality, including send, mint, and genesis transactions. It also fully support all aspects of [non-fugible tokans (NFTs)](https://www.youtube.com/watch?v=vvlpYUx6HRs).
- [Semantic Release](https://github.com/semantic-release/semantic-release) for
continuous delivery using semantic versioning.
continuous delivery using semantic versioning.
- [Greenkeeper](https://greenkeeper.io/) automatic dependency management for
automatically maintaining the latest, most secure dependencies.
automatically maintaining the latest, most secure dependencies.
- [IPFS uploads](https://ipfs.io) of all files and dependencies, to backup
dependencies in case they are ever inaccessible from GitHub or npm.
dependencies in case they are ever inaccessible from GitHub or npm.
## Documentation:
Full documentation for this library can be found here:
- [Documentation](https://bchjs.fullstack.cash/)
Original documentation on BITBOX is available at:
- [General docs](https://developer.bitcoin.com)
- [BITBOX Introduction](https://developer.bitcoin.com/bitbox)
- [BITBOX API Reference](https://developer.bitcoin.com/bitbox/docs/getting-started)
bch-js uses [APIDOC](http://apidocjs.com/) so that documentation and working code
live in the same repository. To generate the documentation:
- `npm run docs`
- Open the generated `docs/index.html` file in a web browser.
## Support
Have questions? Need help? Join our community support
[Telegram channel](https://t.me/bch_js_toolkit)
## IPFS Releases
I will periodically publish IPFS releases of this repository, including all
dependencies in the `node_modules` folder. This ensures working copies of this
repository can be retrieved in case there is any drift in dependency files, or
if dependencies are pulled from npm or GitHub.
Copies of this repository are also published on [IPFS](https://ipfs.io).
- Initial fork on 5/9/2019:
- without node_modules folder: QmQFHfbBQdEHfhtiRLbXtX1NcgnfL45hZb7TbQimTXAuzG (4 MB)
- with node_modules folder: QmXq9Ds6Qdkg9xbRhcF8pay9KabA6QN2y7bx3wvSqiXifk (107 MB)
- v1.0.0 - refactored to pure JavaScript:
- without node_modules folder: QmNjFsiTZRMAUa9rZpXqZqivv9JLaNicwLSPHjyLB7PVDk (1 MB)
- with node_modules folder: Qma9ScApwBtuL7dpdSk7jpBFTxbqRdiR921WjyP75SU7bT (100 MB)
- v3.8.10: QmauhggzKDo9A9je5y2K6WRAp32JmGRFCw2ZFTiSnW8yot
## License
[MIT](LICENSE.md)
+3351 -1291
View File
File diff suppressed because it is too large Load Diff
+33 -23
View File
@@ -1,6 +1,6 @@
{
"name": "@psf/bch-js",
"version": "3.4.0",
"version": "4.0.0",
"description": "The FullStack.cash JavaScript library for Bitcoin Cash and SLP Tokens",
"author": "Chris Troutner <chris.troutner@gmail.com>",
"contributors": [
@@ -8,18 +8,20 @@
],
"main": "src/bch-js",
"scripts": {
"test": "nyc mocha --timeout 30000 test/unit/",
"test:integration": "mocha --timeout 30000 test/integration/",
"test:integration:testnet": "mocha --timeout 30000 test/integration/testnet/",
"test:integration:local": "RESTURL=http://localhost:3000/v3/ mocha --timeout 30000 test/integration",
"test:integration:testnet:local": "RESTURL=http://localhost:4000/v3/ mocha --timeout 30000 test/integration/testnet",
"test:integration:free": "bash test/integration/test-free-tier.sh",
"test:integration:free:testnet": "bash test/integration/testnet/test-free-tier.sh",
"test:temp": "mocha --timeout 30000 test/integration/testnet/ninsight.js",
"test:integration:api": "RESTURL=https://api.fullstack.cash/v3/ mocha --timeout 30000 test/integration",
"test": "nyc mocha --trace-warnings --unhandled-rejections=strict --timeout 30000 test/unit/",
"test:integration": "npm run test:integration:bchn",
"test:integration:abc": "export RESTURL=https://abc.fullstack.cash/v4/ && export IS_USING_FREE_TIER=true && mocha --timeout 30000 test/integration/ && mocha --timeout 30000 test/integration/chains/abc/",
"test:integration:bchn": "export RESTURL=https://bchn.fullstack.cash/v4/ && export IS_USING_FREE_TIER=true && mocha --timeout 30000 test/integration/ && mocha --timeout 30000 test/integration/chains/bchn/",
"test:integration:testnet": "IS_USING_FREE_TIER=true mocha --timeout 30000 test/integration/chains/testnet/",
"test:integration:local": "RESTURL=http://localhost:3000/v4/ mocha --timeout 30000 test/integration",
"test:integration:local:bchn": "RESTURL=http://localhost:3000/v4/ bash test/integration/test-bchn-integration.sh",
"test:integration:local:testnet": "RESTURL=http://localhost:4000/v4/ mocha --timeout 30000 test/integration/testnet",
"test:temp": "export RESTURL=https://bchn.fullstack.cash/v4/ && mocha --timeout 30000 -g '#getStatus' test/integration/",
"test:temp2": "mocha --timeout 30000 -g '#getStatus' test/unit/",
"coverage": "nyc report --reporter=text-lcov | coveralls",
"coverage:report": "nyc --reporter=html mocha --timeout 25000 test/unit/",
"docs": "./node_modules/.bin/apidoc -i src/ -o docs"
"docs": "./node_modules/.bin/apidoc -i src/ -o docs",
"lint": "standard --env mocha --fix"
},
"license": "MIT",
"homepage": "https://github.com/Permissionless-Software-Foundation/bch-js",
@@ -30,35 +32,34 @@
"dependencies": {
"@uppy/core": "^1.10.4",
"@uppy/tus": "^1.5.12",
"apidoc": "^0.17.7",
"apidoc": "^0.25.0",
"assert": "^2.0.0",
"axios": "^0.19.0",
"axios": "^0.21.1",
"bc-bip68": "^1.0.5",
"bch-wallet-bridge.js": "github:web3bch/bch-wallet-bridge.js#master",
"bchaddrjs-slp": "^0.2.5",
"bigi": "^1.4.2",
"bignumber.js": "^9.0.0",
"bip-schnorr": "^0.3.0",
"bip21": "Bitcoin-com/bip21",
"bip32-utils": "Bitcoin-com/bip32-utils#0.13.1",
"@psf/bip21": "^2.0.1",
"@psf/bip32-utils": "^0.13.1",
"bip38": "^2.0.2",
"bip39": "^3.0.2",
"bip66": "^1.1.5",
"bitcoincash-ops": "christroutner/bitcoincash-ops",
"bitcoincashjs-lib": "christroutner/bitcoincashjs-lib#master",
"@psf/bitcoincash-ops": "^2.0.0",
"@psf/bitcoincashjs-lib": "^4.0.2",
"bitcoinjs-message": "^2.0.0",
"bs58": "^4.0.1",
"buffer": "^5.1.0",
"cashaddrjs": "^0.3.3",
"chalk": "^2.3.0",
"clear": "0.1.0",
"coininfo": "Bitcoin-com/coininfo",
"@psf/coininfo": "^4.0.0",
"commander": "^3.0.0",
"cp-file": "^7.0.0",
"ecurve": "^1.0.6",
"figlet": "^1.2.0",
"git-clone": "^0.1.0",
"ini": "^1.3.5",
"ini": "^1.3.8",
"mkdirp": "^0.5.1",
"node-cmd": "^3.0.0",
"node-emoji": "^1.8.1",
@@ -79,18 +80,27 @@
"coveralls": "^3.0.2",
"eslint": "5.16.0",
"eslint-config-prettier": "^6.0.0",
"eslint-config-standard": "^14.1.0",
"eslint-plugin-node": "^9.1.0",
"eslint-plugin-prettier": "^3.1.0",
"eslint-plugin-standard": "^4.0.0",
"husky": "^4.3.6",
"lodash.clonedeep": "^4.5.0",
"mocha": "^6.1.4",
"nock": "^10.0.6",
"node-mocks-http": "^1.7.0",
"nyc": "^14.1.0",
"prettier": "^1.18.2",
"semantic-release": "^15.13.19",
"sinon": "^7.3.2"
"semantic-release": "^17.3.1",
"sinon": "^7.3.2",
"standard": "^16.0.3"
},
"apidoc": {
"title": "bch-js",
"url": "bchjs."
},
"husky": {
"hooks": {
"pre-commit": "npm run lint"
}
}
}
+113 -95
View File
@@ -1,20 +1,37 @@
//const axios = require("axios")
const Bitcoin = require("bitcoincashjs-lib")
const cashaddr = require("cashaddrjs")
const coininfo = require("coininfo")
// const axios = require("axios")
const Bitcoin = require('@psf/bitcoincashjs-lib')
const cashaddr = require('cashaddrjs')
const coininfo = require('@psf/coininfo')
class Address {
constructor(config) {
constructor (config) {
const tmp = {}
if (!config || !config.restURL) tmp.restURL = `https://api.bchjs.cash/v3/`
if (!config || !config.restURL) tmp.restURL = 'https://api.bchjs.cash/v4/'
else tmp.restURL = config.restURL
this.restURL = tmp.restURL
this.apiToken = tmp.apiToken
this.authToken = config.authToken
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
}
}
}
/**
* @api Address.toLegacyAddress() toLegacyAddress() - Convert to Legacy Address
* @api Address.toLegacyAddress() toLegacyAddress()
* @apiName toLegacyAddress
* @apiGroup Address
* @apiDescription Convert cashaddr to legacy address format
@@ -37,34 +54,34 @@ class Address {
* // mqc1tmwY2368LLGktnePzEyPAsgADxbksi
*/
// Translate address from any address format into a specific format.
toLegacyAddress(address) {
toLegacyAddress (address) {
const { prefix, type, hash } = this._decode(address)
let bitcoincash
switch (prefix) {
case "bitcoincash":
case 'bitcoincash':
bitcoincash = coininfo.bitcoincash.main
break
case "bchtest":
case 'bchtest':
bitcoincash = coininfo.bitcoincash.test
break
case "bchreg":
case 'bchreg':
bitcoincash = coininfo.bitcoincash.regtest
break
default:
throw `unsupported prefix : ${prefix}`
throw new Error(`unsupported prefix : ${prefix}`)
}
let version
switch (type) {
case "P2PKH":
case 'P2PKH':
version = bitcoincash.versions.public
break
case "P2SH":
case 'P2SH':
version = bitcoincash.versions.scripthash
break
default:
throw `unsupported address type : ${type}`
throw new Error(`unsupported address type : ${type}`)
}
const hashBuf = Buffer.from(hash)
@@ -73,7 +90,7 @@ class Address {
}
/**
* @api Address.toCashAddress() toCashAddress() - Convert to bitcoincash: format
* @api Address.toCashAddress() toCashAddress()
* @apiName toCashAddress
* @apiGroup Address
* @apiDescription Convert legacy to cashAddress format
@@ -95,11 +112,11 @@ class Address {
* bchjs.Address.toCashAddress('msDbtTj7kWXPpYaR7PQmMK84i66fJqQMLx', false)
* // qzq9je6pntpva3wf6scr7mlnycr54sjgeqxgrr9ku3
*/
toCashAddress(address, prefix = true, regtest = false) {
toCashAddress (address, prefix = true, regtest = false) {
const decoded = this._decode(address)
let prefixString
if (regtest) prefixString = "bchreg"
if (regtest) prefixString = 'bchreg'
else prefixString = decoded.prefix
const cashAddress = cashaddr.encode(
@@ -109,18 +126,18 @@ class Address {
)
if (prefix) return cashAddress
return cashAddress.split(":")[1]
return cashAddress.split(':')[1]
}
// Converts any address format to hash160
toHash160(address) {
toHash160 (address) {
const legacyAddress = this.toLegacyAddress(address)
const bytes = Bitcoin.address.fromBase58Check(legacyAddress)
return bytes.hash.toString("hex")
return bytes.hash.toString('hex')
}
/**
* @api Address.hash160ToLegacy() hash160ToLegacy() - Convert hash160 to legacy address.
* @api Address.hash160ToLegacy() hash160ToLegacy()
* @apiName hash160ToLegacy
* @apiGroup Address
* @apiDescription Convert hash160 to legacy address.
@@ -139,14 +156,14 @@ class Address {
* // mhTg9sgNgvAGfmJs192oUzQWqAXHH5nqLE
*/
// Converts hash160 to Legacy Address
hash160ToLegacy(hash160, network = Bitcoin.networks.bitcoin.pubKeyHash) {
const buffer = Buffer.from(hash160, "hex")
hash160ToLegacy (hash160, network = Bitcoin.networks.bitcoin.pubKeyHash) {
const buffer = Buffer.from(hash160, 'hex')
const legacyAddress = Bitcoin.address.toBase58Check(buffer, network)
return legacyAddress
}
/**
* @api Address.hash160ToCash() hash160ToCash() - Convert hash160 to cash address.
* @api Address.hash160ToCash() hash160ToCash()
* @apiName hash160ToCash
* @apiGroup Address
* @apiDescription Convert hash160 to cash address.
@@ -160,7 +177,7 @@ class Address {
* 'bchtest:qq24rpar9qas3vc9r8d4p0prhwaf7jmx2u22nzt946'
*/
// Converts hash160 to Cash Address
hash160ToCash(
hash160ToCash (
hash160,
network = Bitcoin.networks.bitcoin.pubKeyHash,
regtest = false
@@ -169,7 +186,7 @@ class Address {
return this.toCashAddress(legacyAddress, true, regtest)
}
_decode(address) {
_decode (address) {
try {
return this._decodeLegacyAddress(address)
} catch (error) {}
@@ -185,56 +202,56 @@ class Address {
throw new Error(`Unsupported address format : ${address}`)
}
_decodeLegacyAddress(address) {
_decodeLegacyAddress (address) {
const { version, hash } = Bitcoin.address.fromBase58Check(address)
const info = coininfo.bitcoincash
switch (version) {
case info.main.versions.public:
return {
prefix: "bitcoincash",
type: "P2PKH",
prefix: 'bitcoincash',
type: 'P2PKH',
hash: hash,
format: "legacy"
format: 'legacy'
}
case info.main.versions.scripthash:
return {
prefix: "bitcoincash",
type: "P2SH",
prefix: 'bitcoincash',
type: 'P2SH',
hash: hash,
format: "legacy"
format: 'legacy'
}
case info.test.versions.public:
return {
prefix: "bchtest",
type: "P2PKH",
prefix: 'bchtest',
type: 'P2PKH',
hash: hash,
format: "legacy"
format: 'legacy'
}
case info.test.versions.scripthash:
return {
prefix: "bchtest",
type: "P2SH",
prefix: 'bchtest',
type: 'P2SH',
hash: hash,
format: "legacy"
format: 'legacy'
}
default:
throw new Error(`Invalid format : ${address}`)
}
}
_decodeCashAddress(address) {
if (address.indexOf(":") !== -1) {
_decodeCashAddress (address) {
if (address.indexOf(':') !== -1) {
const decoded = cashaddr.decode(address)
decoded.format = "cashaddr"
decoded.format = 'cashaddr'
return decoded
}
const prefixes = ["bitcoincash", "bchtest", "bchreg"]
const prefixes = ['bitcoincash', 'bchtest', 'bchreg']
for (let i = 0; i < prefixes.length; ++i) {
try {
const decoded = cashaddr.decode(`${prefixes[i]}:${address}`)
decoded.format = "cashaddr"
decoded.format = 'cashaddr'
return decoded
} catch (error) {}
}
@@ -242,12 +259,12 @@ class Address {
throw new Error(`Invalid format : ${address}`)
}
_encodeAddressFromHash160(address) {
_encodeAddressFromHash160 (address) {
try {
return {
legacyAddress: this.hash160ToLegacy(address),
cashAddress: this.hash160ToCash(address),
format: "hash160"
format: 'hash160'
}
} catch (error) {}
@@ -255,7 +272,7 @@ class Address {
}
/**
* @api Address.isLegacyAddress() isLegacyAddress() - Detect if legacy address.
* @api Address.isLegacyAddress() isLegacyAddress()
* @apiName isLegacyAddress
* @apiGroup Address
* @apiDescription Detect if legacy base58check encoded address.
@@ -286,12 +303,12 @@ class Address {
* // true
*/
// Test for address format.
isLegacyAddress(address) {
return this.detectAddressFormat(address) === "legacy"
isLegacyAddress (address) {
return this.detectAddressFormat(address) === 'legacy'
}
/**
* @api Address.isCashAddress() isCashAddress() - Detect if cashAddr address.
* @api Address.isCashAddress() isCashAddress()
* @apiName isCashAddress
* @apiGroup Address
* @apiDescription Detect if cashAddr encoded address.
@@ -321,12 +338,12 @@ class Address {
* bchjs.Address.isCashAddress('mqc1tmwY2368LLGktnePzEyPAsgADxbksi')
* // false
*/
isCashAddress(address) {
return this.detectAddressFormat(address) === "cashaddr"
isCashAddress (address) {
return this.detectAddressFormat(address) === 'cashaddr'
}
/**
* @api Address.isHash160() isHash160() - Detect if an addess is a hash160.
* @api Address.isHash160() isHash160()
* @apiName isHash160
* @apiGroup Address
* @apiDescription Detect if an addess is a hash160.
@@ -340,12 +357,12 @@ class Address {
* bchjs.Address.isHash160(notHash160Address);
* // false
*/
isHash160(address) {
return this.detectAddressFormat(address) === "hash160"
isHash160 (address) {
return this.detectAddressFormat(address) === 'hash160'
}
/**
* @api Address.isMainnetAddress() isMainnetAddress() - Detect if mainnet address.
* @api Address.isMainnetAddress() isMainnetAddress()
* @apiName isMainnetAddress
* @apiGroup Address
* @apiDescription Detect if mainnet address .
@@ -376,15 +393,15 @@ class Address {
* // false
*/
// Test for address network.
isMainnetAddress(address) {
if (address[0] === "x") return true
else if (address[0] === "t") return false
isMainnetAddress (address) {
if (address[0] === 'x') return true
else if (address[0] === 't') return false
return this.detectAddressNetwork(address) === "mainnet"
return this.detectAddressNetwork(address) === 'mainnet'
}
/**
* @api Address.isTestnetAddress() isTestnetAddress() - Detect if testnet address.
* @api Address.isTestnetAddress() isTestnetAddress()
* @apiName isTestnetAddress
* @apiGroup Address
* @apiDescription Detect if testnet address.
@@ -414,15 +431,15 @@ class Address {
* bchjs.Address.isTestnetAddress('mqc1tmwY2368LLGktnePzEyPAsgADxbksi')
* // true
*/
isTestnetAddress(address) {
if (address[0] === "x") return false
else if (address[0] === "t") return true
isTestnetAddress (address) {
if (address[0] === 'x') return false
else if (address[0] === 't') return true
return this.detectAddressNetwork(address) === "testnet"
return this.detectAddressNetwork(address) === 'testnet'
}
/**
* @api Address.isRegTestAddress() isRegTestAddress() - Detect if regtest address.
* @api Address.isRegTestAddress() isRegTestAddress()
* @apiName isRegTestAddress
* @apiGroup Address
* @apiDescription Detect if regtest address.
@@ -456,12 +473,12 @@ class Address {
* bchjs.Address.isRegTestAddress('qph2v4mkxjgdqgmlyjx6njmey0ftrxlnggt9t0a6zy')
* // false
*/
isRegTestAddress(address) {
return this.detectAddressNetwork(address) === "regtest"
isRegTestAddress (address) {
return this.detectAddressNetwork(address) === 'regtest'
}
/**
* @api Address.isP2PKHAddress() isP2PKHAddress() - Detect if p2pkh address.
* @api Address.isP2PKHAddress() isP2PKHAddress()
* @apiName isP2PKHAddress
* @apiGroup Address
* @apiDescription Detect if p2pkh address.
@@ -493,12 +510,12 @@ class Address {
*/
// Test for address type.
isP2PKHAddress(address) {
return this.detectAddressType(address) === "p2pkh"
isP2PKHAddress (address) {
return this.detectAddressType(address) === 'p2pkh'
}
/**
* @api Address.isP2SHAddress() isP2SHAddress() - Detect if p2sh address.
* @api Address.isP2SHAddress() isP2SHAddress()
* @apiName isP2SHAddress
* @apiGroup Address
* @apiDescription Detect if p2sh address.
@@ -529,12 +546,12 @@ class Address {
* // false
*/
isP2SHAddress(address) {
return this.detectAddressType(address) === "p2sh"
isP2SHAddress (address) {
return this.detectAddressType(address) === 'p2sh'
}
/**
* @api Address.detectAddressFormat() detectAddressFormat() - Detect address format.
* @api Address.detectAddressFormat() detectAddressFormat()
* @apiName detectAddressFormat
* @apiGroup Address
* @apiDescription Detect address format.
@@ -565,14 +582,14 @@ class Address {
* // legacy
*/
// Detect address format.
detectAddressFormat(address) {
detectAddressFormat (address) {
const decoded = this._decode(address)
return decoded.format
}
/**
* @api Address.detectAddressNetwork() detectAddressNetwork() - Detect address network.
* @api Address.detectAddressNetwork() detectAddressNetwork()
* @apiName detectAddressNetwork
* @apiGroup Address
* @apiDescription Detect address network.
@@ -603,26 +620,26 @@ class Address {
* // testnet
*/
// Detect address network.
detectAddressNetwork(address) {
if (address[0] === "x") return "mainnet"
else if (address[0] === "t") return "testnet"
detectAddressNetwork (address) {
if (address[0] === 'x') return 'mainnet'
else if (address[0] === 't') return 'testnet'
const decoded = this._decode(address)
switch (decoded.prefix) {
case "bitcoincash":
return "mainnet"
case "bchtest":
return "testnet"
case "bchreg":
return "regtest"
case 'bitcoincash':
return 'mainnet'
case 'bchtest':
return 'testnet'
case 'bchreg':
return 'regtest'
default:
throw new Error(`Invalid prefix : ${decoded.prefix}`)
}
}
/**
* @api Address.detectAddressType() detectAddressType() - Detect address type.
* @api Address.detectAddressType() detectAddressType()
* @apiName detectAddressType
* @apiGroup Address
* @apiDescription Detect address type.
@@ -653,14 +670,14 @@ class Address {
* // p2pkh
*/
// Detect address type.
detectAddressType(address) {
detectAddressType (address) {
const decoded = this._decode(address)
return decoded.type.toLowerCase()
}
/**
* @api Address.fromXPub() fromXPub() - Generates an address (xpub).
* @api Address.fromXPub() fromXPub()
* @apiName fromXPub
* @apiGroup Address
* @apiDescription Generates an address for an extended public key (xpub).
@@ -688,7 +705,7 @@ class Address {
* // bchtest:qzd7dvlnfukggjqsf5ju0qqwwltakfumjsck33js6m
* // bchtest:qq322ataqeas4n0pdn4gz2sdereh5ae43ylk4qdvus
*/
fromXPub(xpub, path = "0/0") {
fromXPub (xpub, path = '0/0') {
const HDNode = Bitcoin.HDNode.fromBase58(
xpub,
Bitcoin.networks[this.detectAddressNetwork(xpub)]
@@ -698,7 +715,7 @@ class Address {
}
/**
* @api Address.fromOutputScript() fromOutputScript() - Detect an addess from an OutputScript..
* @api Address.fromOutputScript() fromOutputScript()
* @apiName fromOutputScript
* @apiGroup Address
* @apiDescription Detect an addess from an OutputScript..
@@ -721,12 +738,13 @@ class Address {
* bchjs.Address.fromOutputScript(scriptPubKey, 'testnet');
* // bchtest:pz0qcslrqn7hr44hsszwl4lw5r6udkg6zqh2hmtpyr
*/
fromOutputScript(scriptPubKey, network = "mainnet") {
fromOutputScript (scriptPubKey, network = 'mainnet') {
let netParam
if (network !== "bitcoincash" && network !== "mainnet")
if (network !== 'bitcoincash' && network !== 'mainnet') {
netParam = Bitcoin.networks.testnet
}
const regtest = network === "bchreg"
const regtest = network === 'bchreg'
return this.toCashAddress(
Bitcoin.address.fromOutputScript(scriptPubKey, netParam),
+46 -126
View File
@@ -7,64 +7,67 @@
*/
// bch-api mainnet.
// const DEFAULT_REST_API = "https://api.bchjs.cash/v3/"
const DEFAULT_REST_API = "https://api.fullstack.cash/v3/"
const DEFAULT_REST_API = 'https://api.fullstack.cash/v4/'
// const DEFAULT_REST_API = "http://localhost:3000/v4/"
// local deps
const BitcoinCash = require("./bitcoincash")
const Crypto = require("./crypto")
const Util = require("./util")
const Blockchain = require("./blockchain")
const Control = require("./control")
const Generating = require("./generating")
const Mining = require("./mining")
const RawTransactions = require("./raw-transactions")
const Mnemonic = require("./mnemonic")
const Address = require("./address")
const HDNode = require("./hdnode")
const TransactionBuilder = require("./transaction-builder")
const ECPair = require("./ecpair")
const Script = require("./script")
const Price = require("./price")
const Socket = require("./socket")
const Wallet = require("./wallet")
const Schnorr = require("./schnorr")
const SLP = require("./slp/slp")
const IPFS = require("./ipfs")
const Encryption = require("./encryption")
const BitcoinCash = require('./bitcoincash')
const Crypto = require('./crypto')
const Util = require('./util')
const Blockchain = require('./blockchain')
const Control = require('./control')
const Generating = require('./generating')
const Mining = require('./mining')
const RawTransactions = require('./raw-transactions')
const Mnemonic = require('./mnemonic')
const Address = require('./address')
const HDNode = require('./hdnode')
const TransactionBuilder = require('./transaction-builder')
const ECPair = require('./ecpair')
const Script = require('./script')
const Price = require('./price')
const Socket = require('./socket')
const Schnorr = require('./schnorr')
const SLP = require('./slp/slp')
const IPFS = require('./ipfs')
const Encryption = require('./encryption')
// Indexers
const Blockbook = require("./blockbook")
const OpenBazaar = require("./openbazaar")
const Ninsight = require("./ninsight")
const Electrumx = require("./electrumx")
const OpenBazaar = require('./openbazaar')
const Ninsight = require('./ninsight')
const Electrumx = require('./electrumx')
class BCHJS {
constructor(config) {
constructor (config) {
// Try to retrieve the REST API URL from different sources.
if (config && config.restURL && config.restURL !== "")
this.restURL = config.restURL
else if (process.env.RESTURL && process.env.RESTURL !== "")
this.restURL = process.env.RESTURL
else this.restURL = DEFAULT_REST_API
if (config && config.restURL && config.restURL !== '') { this.restURL = config.restURL } else if (process.env.RESTURL && process.env.RESTURL !== '') { this.restURL = process.env.RESTURL } else this.restURL = DEFAULT_REST_API
// Retrieve the apiToken
this.apiToken = "" // default value.
if (config && config.apiToken && config.apiToken !== "")
this.apiToken = config.apiToken
else if (process.env.BCHJSTOKEN && process.env.BCHJSTOKEN !== "")
this.apiToken = process.env.BCHJSTOKEN
this.apiToken = '' // default value.
if (config && config.apiToken && config.apiToken !== '') { this.apiToken = config.apiToken } else if (process.env.BCHJSTOKEN && process.env.BCHJSTOKEN !== '') { this.apiToken = process.env.BCHJSTOKEN }
// Retrieve the Basic Authentication password.
this.authPass = '' // default value.
if (config && config.authPass && config.authPass !== '') { this.authPass = config.authPass } else if (process.env.BCHJSAUTHPASS && process.env.BCHJSAUTHPASS !== '') { this.authPass = process.env.BCHJSAUTHPASS }
// Generate a Basic Authentication token from an auth password
this.authToken = ''
if (this.authPass) {
// console.log(`bch-js initialized with authPass: ${this.authPass}`)
// Generate the header for Basic Authentication.
const combined = `fullstackcash:${this.authPass}`
const base64Credential = Buffer.from(combined).toString('base64')
this.authToken = `Basic ${base64Credential}`
}
const libConfig = {
restURL: this.restURL,
apiToken: this.apiToken
apiToken: this.apiToken,
authToken: this.authToken
}
// console.log(`apiToken: ${this.apiToken}`)
// Populate Blockbook endpoints.
this.Blockbook = new Blockbook(libConfig)
// Populate OpenBazaar endpoints
this.OpenBazaar = new OpenBazaar(libConfig)
@@ -90,13 +93,12 @@ class BCHJS {
this.Generating = new Generating(libConfig)
this.HDNode = new HDNode(this.Address)
this.Mnemonic = new Mnemonic(this.Address)
this.Price = new Price()
this.Price = new Price(libConfig)
this.Script = new Script()
this.TransactionBuilder = TransactionBuilder
this.TransactionBuilder.setAddress(this.Address)
this.Util = new Util(libConfig)
this.Socket = Socket
this.Wallet = Wallet
this.Schnorr = new Schnorr(libConfig)
this.SLP = new SLP(libConfig)
@@ -104,88 +106,6 @@ class BCHJS {
this.IPFS = new IPFS()
}
static BitboxShim() {
return BitboxShim
}
}
// Creat a shim so that all the endpoints match BITBOX SDK and this library
// can be used as a drop-in replacement for BITBOX.
class BitboxShim {
constructor(config) {
// Try to retrieve the REST API URL from different sources.
if (config && config.restURL && config.restURL !== "")
this.restURL = config.restURL
else if (process.env.RESTURL && process.env.RESTURL !== "")
this.restURL = process.env.RESTURL
else this.restURL = DEFAULT_REST_API
// Retrieve the apiToken
this.apiToken = "" // default value.
if (config && config.apiToken && config.apiToken !== "")
this.apiToken = config.apiToken
else if (process.env.BCHJSTOKEN && process.env.BCHJSTOKEN !== "")
this.apiToken = process.env.BCHJSTOKEN
const libConfig = {
restURL: this.restURL,
apiToken: this.apiToken
}
// Populate utility functions
this.Address = new Address(libConfig)
this.BitcoinCash = new BitcoinCash(this.Address)
this.Blockchain = new Blockchain(libConfig)
this.Crypto = Crypto
this.ECPair = ECPair
this.ECPair.setAddress(this.Address)
this.Generating = new Generating(libConfig)
this.HDNode = new HDNode(this.Address)
this.Mnemonic = new Mnemonic(this.Address)
this.Price = new Price()
this.Script = new Script()
this.TransactionBuilder = TransactionBuilder
this.TransactionBuilder.setAddress(this.Address)
this.Util = new Util(libConfig)
this.Socket = Socket
this.Wallet = Wallet
this.Schnorr = new Schnorr(libConfig)
// Populate the SLP endpoints.
this.SLP = new SLP(libConfig)
this.Address = this.SLP.Address
this.ECPair.toSLPAddress = this.SLP.ECPair.toSLPAddress
this.Util.list = this.SLP.Utils.list
this.Util.balancesForAddress = this.SLP.Utils.balancesForAddress
this.Util.balancesForToken = this.SLP.Utils.balancesForToken
this.Util.balance = this.SLP.Utils.balance
this.Util.validateTxid = this.SLP.Utils.validateTxid
this.Util.tokenStats = this.SLP.Utils.tokenStats
this.Util.transactions = this.SLP.Utils.transactions
this.Util.burnTotal = this.SLP.Utils.burnTotal
this.Util.decodeOpReturn = this.SLP.Utils.decodeOpReturn
this.Util.isTokenUtxo = this.SLP.Utils.isTokenUtxo
this.Util.tokenUtxoDetails = this.SLP.Utils.tokenUtxoDetails
this.Util.txDetails = this.SLP.Utils.txDetails
// Populate Full Node
this.Control = new Control(libConfig)
this.Mining = new Mining(libConfig)
this.RawTransactions = new RawTransactions(libConfig)
// Populate Blockbook endpoints.
this.Blockbook = new Blockbook(libConfig)
// Populate OpenBazaar endpoints
this.OpenBazaar = new OpenBazaar(libConfig)
// Bitcoin.com Ninsight indexer
this.Ninsight = new Ninsight()
this.Electrumx = new Electrumx(libConfig)
}
}
module.exports = BCHJS
+52 -52
View File
@@ -1,21 +1,21 @@
const Bitcoin = require("bitcoincashjs-lib")
const sb = require("satoshi-bitcoin")
const bitcoinMessage = require("bitcoinjs-message")
const bs58 = require("bs58")
const bip21 = require("bip21")
const coininfo = require("coininfo")
const bip38 = require("bip38")
const wif = require("wif")
const Bitcoin = require('@psf/bitcoincashjs-lib')
const sb = require('satoshi-bitcoin')
const bitcoinMessage = require('bitcoinjs-message')
const bs58 = require('bs58')
const bip21 = require('@psf/bip21')
const coininfo = require('@psf/coininfo')
const bip38 = require('bip38')
const wif = require('wif')
const Buffer = require("safe-buffer").Buffer
const Buffer = require('safe-buffer').Buffer
class BitcoinCash {
constructor(address) {
constructor (address) {
this._address = address
}
/**
* @api BitcoinCash.toSatoshi() toSatoshi() - Converting Bitcoin Cash units to satoshi units.
* @api BitcoinCash.toSatoshi() toSatoshi()
* @apiName toSatoshi
* @apiGroup BitcoinCash
* @apiDescription
@@ -43,12 +43,12 @@ class BitcoinCash {
* // 50700000000
*/
// Translate coins to satoshi value
toSatoshi(coins) {
toSatoshi (coins) {
return sb.toSatoshi(coins)
}
/**
* @api BitcoinCash.toBitcoinCash() toBitcoinCash() - Converting satoshi units to Bitcoin Cash units.
* @api BitcoinCash.toBitcoinCash() toBitcoinCash()
* @apiName toBitcoinCash
* @apiGroup BitcoinCash
* @apiDescription
@@ -76,12 +76,12 @@ class BitcoinCash {
* // 507
*/
// Translate satoshi to coin value
toBitcoinCash(satoshis) {
toBitcoinCash (satoshis) {
return sb.toBitcoin(satoshis)
}
/**
* @api BitcoinCash.toBits() toBits() - Converting satoshi units to Bits denomination.
* @api BitcoinCash.toBits() toBits()
* @apiName toBits
* @apiGroup BitcoinCash
* @apiDescription
@@ -105,13 +105,13 @@ class BitcoinCash {
* // 0.123
*/
// Translate satoshi to bits denomination
toBits(satoshis) {
toBits (satoshis) {
return parseFloat(satoshis) / 100
}
// Translate satoshi to bits denomination
// TODO remove in 2.0
satsToBits(satoshis) {
satsToBits (satoshis) {
return parseFloat(satoshis) / 100
}
@@ -133,7 +133,7 @@ class BitcoinCash {
// }
/**
* @api BitcoinCash.signMessageWithPrivKey() signMessageWithPrivKey() - Sign message with private key.
* @api BitcoinCash.signMessageWithPrivKey() signMessageWithPrivKey()
* @apiName signMessageWithPrivKey
* @apiGroup BitcoinCash
* @apiDescription
@@ -147,10 +147,10 @@ class BitcoinCash {
* // IIYVhlo2Z6TWFjYX1+YM+7vQKz0m+zYdSe4eYpFLuAQDEZXqll7lZC8Au22VI2LLP5x+IerZckVk3QQPsA3e8/8=
*/
// sign message
signMessageWithPrivKey(privateKeyWIF, message) {
const network = privateKeyWIF.charAt(0) === "c" ? "testnet" : "mainnet"
signMessageWithPrivKey (privateKeyWIF, message) {
const network = privateKeyWIF.charAt(0) === 'c' ? 'testnet' : 'mainnet'
let bitcoincash
if (network === "mainnet") bitcoincash = coininfo.bitcoincash.main
if (network === 'mainnet') bitcoincash = coininfo.bitcoincash.main
else bitcoincash = coininfo.bitcoincash.test
const bitcoincashBitcoinJSLib = bitcoincash.toBitcoinJS()
@@ -161,11 +161,11 @@ class BitcoinCash {
const privateKey = keyPair.d.toBuffer(32)
return bitcoinMessage
.sign(message, privateKey, keyPair.compressed)
.toString("base64")
.toString('base64')
}
/**
* @api BitcoinCash.verifyMessage() verifyMessage() - Verify message.
* @api BitcoinCash.verifyMessage() verifyMessage()
* @apiName verifyMessage
* @apiGroup BitcoinCash
* @apiDescription
@@ -180,7 +180,7 @@ class BitcoinCash {
* // true
*/
// verify message
verifyMessage(address, signature, message) {
verifyMessage (address, signature, message) {
return bitcoinMessage.verify(
message,
this._address.toLegacyAddress(address),
@@ -189,7 +189,7 @@ class BitcoinCash {
}
/**
* @api BitcoinCash.encodeBase58Check() encodeBase58Check() - Encodes hex string as base58Check.
* @api BitcoinCash.encodeBase58Check() encodeBase58Check()
* @apiName encodeBase58Check
* @apiGroup BitcoinCash
* @apiDescription
@@ -222,12 +222,12 @@ class BitcoinCash {
* // 1Ly4gqPddveYHMNkfjoXHanVszXpD3duKg
*/
// encode base58Check
encodeBase58Check(hex) {
return bs58.encode(Buffer.from(hex, "hex"))
encodeBase58Check (hex) {
return bs58.encode(Buffer.from(hex, 'hex'))
}
/**
* @api BitcoinCash.decodeBase58Check() decodeBase58Check() - Decodes base58Check encoded string to hex.
* @api BitcoinCash.decodeBase58Check() decodeBase58Check()
* @apiName decodeBase58Check
* @apiGroup BitcoinCash
* @apiDescription
@@ -260,12 +260,12 @@ class BitcoinCash {
* // 00db04c2e6f104997cb04c956bf25da6078e559d303127f08b
*/
// decode base58Check
decodeBase58Check(address) {
return bs58.decode(address).toString("hex")
decodeBase58Check (address) {
return bs58.decode(address).toString('hex')
}
/**
* @api BitcoinCash.encodeBIP21() encodeBIP21() - Encodes address and options as BIP21 uri.
* @api BitcoinCash.encodeBIP21() encodeBIP21()
* @apiName encodeBIP21
* @apiGroup BitcoinCash
* @apiDescription
@@ -298,7 +298,7 @@ class BitcoinCash {
* // bitcoincash:qzw6tfrh8p0jh834uf9rhg77pjg5rgnt3qw0e54u03?amount=42&label=no%20prefix
*/
// encode bip21 url
encodeBIP21(address, options, regtest = false) {
encodeBIP21 (address, options, regtest = false) {
return bip21.encode(
this._address.toCashAddress(address, true, regtest),
options
@@ -306,7 +306,7 @@ class BitcoinCash {
}
/**
* @api BitcoinCash.decodeBIP21() decodeBIP21() - Decodes BIP21 uri.
* @api BitcoinCash.decodeBIP21() decodeBIP21()
* @apiName decodeBIP21
* @apiGroup BitcoinCash
* @apiDescription
@@ -335,12 +335,12 @@ class BitcoinCash {
* // { address: 'qzw6tfrh8p0jh834uf9rhg77pjg5rgnt3qw0e54u03', options: { amount: 42, label: 'no prefix' } }
*/
// decode bip21 url
decodeBIP21(url) {
decodeBIP21 (url) {
return bip21.decode(url)
}
/**
* @api BitcoinCash.getByteCount() getByteCount() - Get byte count of transaction.
* @api BitcoinCash.getByteCount() getByteCount()
* @apiName getByteCount
* @apiGroup BitcoinCash
* @apiDescription
@@ -405,19 +405,19 @@ class BitcoinCash {
* bchjs.BitcoinCash.getByteCount(inputs, outputs)
* // 1780
*/
getByteCount(inputs, outputs) {
getByteCount (inputs, outputs) {
// from https://github.com/bitcoinjs/bitcoinjs-lib/issues/921#issuecomment-354394004
let totalWeight = 0
let hasWitness = false
// assumes compressed pubkeys in all cases.
const types = {
inputs: {
"MULTISIG-P2SH": 49 * 4,
"MULTISIG-P2WSH": 6 + 41 * 4,
"MULTISIG-P2SH-P2WSH": 6 + 76 * 4,
'MULTISIG-P2SH': 49 * 4,
'MULTISIG-P2WSH': 6 + 41 * 4,
'MULTISIG-P2SH-P2WSH': 6 + 76 * 4,
P2PKH: 148 * 4,
P2WPKH: 108 + 41 * 4,
"P2SH-P2WPKH": 108 + 64 * 4
'P2SH-P2WPKH': 108 + 64 * 4
},
outputs: {
P2SH: 32 * 4,
@@ -427,26 +427,26 @@ class BitcoinCash {
}
}
Object.keys(inputs).forEach(function(key) {
if (key.slice(0, 8) === "MULTISIG") {
Object.keys(inputs).forEach(function (key) {
if (key.slice(0, 8) === 'MULTISIG') {
// ex. "MULTISIG-P2SH:2-3" would mean 2 of 3 P2SH MULTISIG
const keyParts = key.split(":")
const keyParts = key.split(':')
if (keyParts.length !== 2) throw new Error(`invalid input: ${key}`)
const newKey = keyParts[0]
const mAndN = keyParts[1].split("-").map(function(item) {
const mAndN = keyParts[1].split('-').map(function (item) {
return parseInt(item)
})
totalWeight += types.inputs[newKey] * inputs[key]
const multiplyer = newKey === "MULTISIG-P2SH" ? 4 : 1
const multiplyer = newKey === 'MULTISIG-P2SH' ? 4 : 1
totalWeight += (73 * mAndN[0] + 34 * mAndN[1]) * multiplyer
} else {
totalWeight += types.inputs[key] * inputs[key]
}
if (key.indexOf("W") >= 0) hasWitness = true
if (key.indexOf('W') >= 0) hasWitness = true
})
Object.keys(outputs).forEach(function(key) {
Object.keys(outputs).forEach(function (key) {
totalWeight += types.outputs[key] * outputs[key]
})
@@ -458,7 +458,7 @@ class BitcoinCash {
}
/**
* @api BitcoinCash.encryptBIP38() encryptBIP38() - BIP38 encrypt privkey WIFs.
* @api BitcoinCash.encryptBIP38() encryptBIP38()
* @apiName encryptBIP38
* @apiGroup BitcoinCash
* @apiDescription
@@ -479,14 +479,14 @@ class BitcoinCash {
* )
* // 6PYUAPLwLSEjWSAfoe9NTSPkMZXnJA8j8EFJtKaeSnP18RCouutBrS2735
*/
encryptBIP38(privKeyWIF, passphrase) {
encryptBIP38 (privKeyWIF, passphrase) {
const decoded = wif.decode(privKeyWIF)
return bip38.encrypt(decoded.privateKey, decoded.compressed, passphrase)
}
/**
* @api BitcoinCash.decryptBIP38() decryptBIP38() - BIP38 encrypt privkey WIFs.
* @api BitcoinCash.decryptBIP38() decryptBIP38()
* @apiName decryptBIP38
* @apiGroup BitcoinCash
* @apiDescription
@@ -509,10 +509,10 @@ class BitcoinCash {
* )
* // cSx7KzdH9EcvDEireu2WYpGnXdFYpta7sJUNt5kVCJgA7kcAU8Gm
*/
decryptBIP38(encryptedKey, passphrase, network = "mainnet") {
decryptBIP38 (encryptedKey, passphrase, network = 'mainnet') {
const decryptedKey = bip38.decrypt(encryptedKey, passphrase)
let prefix
if (network === "testnet") prefix = 0xef
if (network === 'testnet') prefix = 0xef
else prefix = 0x80
return wif.encode(prefix, decryptedKey.privateKey, decryptedKey.compressed)
-357
View File
@@ -1,357 +0,0 @@
/*
This library interacts with the REST API endpoints in bch-api that communicate
with the Blockbook API.
*/
const axios = require("axios")
let _this
class Blockbook {
constructor(config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
// console.log(`Blockbook apiToken: ${this.apiToken}`)
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
}
_this = this
}
/**
* @api Blockbook.balance() balance() - Balance about an address.
* @apiName Blockbook Balance
* @apiGroup Blockbook
* @apiDescription Return Balance about an address.
*
* @apiExample Example usage:
* (async () => {
* try {
* let balance = await bchjs.Blockbook.balance('bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c');
* console.log(balance)
* } catch(error) {
* console.error(error)
* }
* })()
*
* //{
* // "page": 1,
* // "totalPages": 1,
* // "itemsOnPage": 1000,
* // "address": "bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c",
* // "balance": "6000000",
* // "totalReceived": "10185868",
* // "totalSent": "4185868",
* // "unconfirmedBalance": "0",
* // "unconfirmedTxs": 0,
* // "txs": 41,
* // "txids": [
* // "d31dc2cf66fe4d3d3ae18e1065def58a64920746b1702b52f060e5edeea9883b",
* // "41e9a118765ecf7a1ba4487c0863e23dba343cc5880381a72f0365ac2546c5fa",
* // "2f902dec880568511cefa87b9dd761563edeba9c8ba784dc9fca2f7c8c4e6f97",
* // "eea57285462dd70dadcd431fc814857b3f81fe4d0a059a8c02c12fd7d33c02d1",
* // "282b3b296b6aed7122586ed69f7a57d35584eaf94a4d1b1ad7d1b05d36cb79d1",
* // "ac444896b3e32d17824fa6573eed3b89768c5c9085b7a71f3ba88e9d5ba67355",
* // "a5f972572ee1753e2fd2457dd61ce5f40fa2f8a30173d417e49feef7542c96a1",
* // "5165dc531aad05d1149bb0f0d9b7bda99c73e2f05e314bcfb5b4bb9ca5e1af5e",
* // "54edaa42ff3d6559884a84ebb9bf5ef255635902f5f23b4854245d6b093d41d4",
* // "2b0825188e909410a20a6fbdc58ff5ccf368844273f93f551222c91e6d0fa888",
* // "7a12ea2c83d0c8a5d0f643974b0f04bc19be185c9011ed8fc33255a61d3198bb",
* // "bd6aeeb0748251bb5dba7252ac766fb208c9909d7663c099568225d3bc998a7f",
* // "7898bb1a8c5d933f9c2b24270522e8705b897c2f8d5b1c3477a6b952f2fe22ae",
* // "8d35668a6838de8faa8dff5d8dedeb114bd8ffe6ae73d926264bc8328b2c46b5",
* // "741b4692a14088438ab142cf0865fcbf3977aa7dbd2aafa9bf5f45e75e5e199a",
* // "15f6a584080b04911121fbaca7bfcf3dd64ef2bfa5a01daf31e05a296c3e5e9e",
* // "376de807f63253584c3edb80f92832ea90e8fdd7d8e68b2602e230d1b015e311",
* // "eb5d0902e4a303f38223ecebb06bbf14da8a07d1ebb2d77a89dfb9e00e286c10",
* // "11205c557af139f382c43f1f09f223cf28c64d939951fd569e5a30eee6178ccd",
* // "ae05a78086b8d64db26d3047de3d6959a68f2a1ed3017ddf927e2c3b20a80b31",
* // "7e0fc3cac7504d45b0f2ce68e807e592f0edf17914ab618a4cb4d93403d11c98",
* // "1cafaacdfb85b0c33f496bf2c03c4f2ede508479bbad56ae99164dfd823a823f",
* // "788add6a5cd961bdf7ca6145a3112462e0e51523d84a4a48047407a795433947",
* // "49f09b616824a05eb14ae50c9fbc5d6a0c414d66a7d0b217aa75340c00ed8b85",
* // "00f075805adf2a34563ecca33071d660a4c1e91d7d7045282c54554ee4844739",
* // "8d048fd00cf375ba9bbea43730da1ce86fc3cb4026e1dd0e751c07fa50a652c6",
* // "ac0e82ea84f93444602a99199dd80793f79a8ece5ac86156d2fff34f0bad44b2",
* // "342f6815845797e0748f4716c923a0dc9b87de649b69925b36422f6d2dc23b7f",
* // "0839a16b2411a1220c64c4d32a4c9b1e77ac5f47558921cf7c0a2adf25e0eb41",
* // "62f42995711cb0308dac4203c5deaa2985f120559131e66aebc5164426fb6cee",
* // "2ada093fe13c9c04da9582bb304923ce08312eaec92560b9128cdb9e93c5f52f",
* // "e0aadd861a06993e39af932bb0b9ad69e7b37ef5843a13c6724789e1c94f3513",
* // "925490ce60334aca204d82a61b634d89fe4cc9de429c7b6cb5ec420df3e3be5e",
* // "60cb69f29c150378abe21d157858713f82c4e2122867597a2573474763a9e94e",
* // "369a589173969c1c882cfb2d82b1e0ec90076ec827ff9d0f32ffc115690c93c3",
* // "43324ef3f5fdd55b645ba14de8c0667be9b223d60b3d1dcd76cf8fdeb0fd32e4",
* // "d2985c9b1c5c18fc2f6a963b7cb850606c4a18fcb85619057211ce3c8bcec696",
* // "dded59fe377517e52918deae8912a096658ebf5ae61992d39953c8bc3932a11b",
* // "2dc053f55a666a3d2a08b1c680b704d62a55506d14ad884add87edcc56b9277d",
* // "544c15ce35c0f2e808d28f29d6587f1ec9276233e29856b7f2938cf0daef0026",
* // "81039b1d7b855b133f359f9dc65f776bd105650153a941675fedc504228ddbd3"
* // ]
* //}
*
*(async () => {
* try {
* let balance = await bchjs.Blockbook.balance(['bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c','1BFHGm4HzqgXXyNX8n7DsQno5DAC4iLMRA']);
* console.log(balance)
* } catch(error) {
* console.error(error)
* }
* })()
*
* //[
* // {
* // "page": 1,
* // "totalPages": 1,
* // "itemsOnPage": 1000,
* // "address": "bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c",
* // "balance": "6000000",
* // "totalReceived": "10185868",
* // "totalSent": "4185868",
* // "unconfirmedBalance": "0",
* // "unconfirmedTxs": 0,
* // "txs": 41,
* // "txids": [
* // "d31dc2cf66fe4d3d3ae18e1065def58a64920746b1702b52f060e5edeea9883b",
* // "41e9a118765ecf7a1ba4487c0863e23dba343cc5880381a72f0365ac2546c5fa",
* // "2f902dec880568511cefa87b9dd761563edeba9c8ba784dc9fca2f7c8c4e6f97",
* // "eea57285462dd70dadcd431fc814857b3f81fe4d0a059a8c02c12fd7d33c02d1",
* // "282b3b296b6aed7122586ed69f7a57d35584eaf94a4d1b1ad7d1b05d36cb79d1",
* // "ac444896b3e32d17824fa6573eed3b89768c5c9085b7a71f3ba88e9d5ba67355",
* // "a5f972572ee1753e2fd2457dd61ce5f40fa2f8a30173d417e49feef7542c96a1",
* // "5165dc531aad05d1149bb0f0d9b7bda99c73e2f05e314bcfb5b4bb9ca5e1af5e",
* // "54edaa42ff3d6559884a84ebb9bf5ef255635902f5f23b4854245d6b093d41d4",
* // "2b0825188e909410a20a6fbdc58ff5ccf368844273f93f551222c91e6d0fa888",
* // "7a12ea2c83d0c8a5d0f643974b0f04bc19be185c9011ed8fc33255a61d3198bb",
* // "bd6aeeb0748251bb5dba7252ac766fb208c9909d7663c099568225d3bc998a7f",
* // "7898bb1a8c5d933f9c2b24270522e8705b897c2f8d5b1c3477a6b952f2fe22ae",
* // "8d35668a6838de8faa8dff5d8dedeb114bd8ffe6ae73d926264bc8328b2c46b5",
* // "741b4692a14088438ab142cf0865fcbf3977aa7dbd2aafa9bf5f45e75e5e199a",
* // "15f6a584080b04911121fbaca7bfcf3dd64ef2bfa5a01daf31e05a296c3e5e9e",
* // "376de807f63253584c3edb80f92832ea90e8fdd7d8e68b2602e230d1b015e311",
* // "eb5d0902e4a303f38223ecebb06bbf14da8a07d1ebb2d77a89dfb9e00e286c10",
* // "11205c557af139f382c43f1f09f223cf28c64d939951fd569e5a30eee6178ccd",
* // "ae05a78086b8d64db26d3047de3d6959a68f2a1ed3017ddf927e2c3b20a80b31",
* // "7e0fc3cac7504d45b0f2ce68e807e592f0edf17914ab618a4cb4d93403d11c98",
* // "1cafaacdfb85b0c33f496bf2c03c4f2ede508479bbad56ae99164dfd823a823f",
* // "788add6a5cd961bdf7ca6145a3112462e0e51523d84a4a48047407a795433947",
* // "49f09b616824a05eb14ae50c9fbc5d6a0c414d66a7d0b217aa75340c00ed8b85",
* // "00f075805adf2a34563ecca33071d660a4c1e91d7d7045282c54554ee4844739",
* // "8d048fd00cf375ba9bbea43730da1ce86fc3cb4026e1dd0e751c07fa50a652c6",
* // "ac0e82ea84f93444602a99199dd80793f79a8ece5ac86156d2fff34f0bad44b2",
* // "342f6815845797e0748f4716c923a0dc9b87de649b69925b36422f6d2dc23b7f",
* // "0839a16b2411a1220c64c4d32a4c9b1e77ac5f47558921cf7c0a2adf25e0eb41",
* // "62f42995711cb0308dac4203c5deaa2985f120559131e66aebc5164426fb6cee",
* // "2ada093fe13c9c04da9582bb304923ce08312eaec92560b9128cdb9e93c5f52f",
* // "e0aadd861a06993e39af932bb0b9ad69e7b37ef5843a13c6724789e1c94f3513",
* // "925490ce60334aca204d82a61b634d89fe4cc9de429c7b6cb5ec420df3e3be5e",
* // "60cb69f29c150378abe21d157858713f82c4e2122867597a2573474763a9e94e",
* // "369a589173969c1c882cfb2d82b1e0ec90076ec827ff9d0f32ffc115690c93c3",
* // "43324ef3f5fdd55b645ba14de8c0667be9b223d60b3d1dcd76cf8fdeb0fd32e4",
* // "d2985c9b1c5c18fc2f6a963b7cb850606c4a18fcb85619057211ce3c8bcec696",
* // "dded59fe377517e52918deae8912a096658ebf5ae61992d39953c8bc3932a11b",
* // "2dc053f55a666a3d2a08b1c680b704d62a55506d14ad884add87edcc56b9277d",
* // "544c15ce35c0f2e808d28f29d6587f1ec9276233e29856b7f2938cf0daef0026",
* // "81039b1d7b855b133f359f9dc65f776bd105650153a941675fedc504228ddbd3"
* // ]
* // },
* // {
* // "page": 1,
* // "totalPages": 1,
* // "itemsOnPage": 1000,
* // "address": "bitcoincash:qpcxf2sv9hjw08nvpgffpamfus9nmksm3chv5zqtnz",
* // "balance": "0",
* // "totalReceived": "36781097",
* // "totalSent": "36781097",
* // "unconfirmedBalance": "0",
* // "unconfirmedTxs": 0,
* // "txs": 11,
* // "txids": [
* // "11205c557af139f382c43f1f09f223cf28c64d939951fd569e5a30eee6178ccd",
* // "ae05a78086b8d64db26d3047de3d6959a68f2a1ed3017ddf927e2c3b20a80b31",
* // "7e0fc3cac7504d45b0f2ce68e807e592f0edf17914ab618a4cb4d93403d11c98",
* // "60cb69f29c150378abe21d157858713f82c4e2122867597a2573474763a9e94e",
* // "f737485aaee3c10b13013fa109bb6294b099246134ca9885f4cc332dbc6c9bb4",
* // "decd5b9c0c959e4e543182093e8f7f8bc7a6ecd96a8a062daaeff3667f8feca7",
* // "94e69a627a34ae27fca81d15fff4323a7ce1f7c275c7485762ce018221017632",
* // "e67c70787af7f3506263c9eda007f3d2d24bd750ff95b5c50a120d9118dfd807",
* // "8e5e00704a147d54028f94d52df7730e821b9c6cd4bd29494e5636f49c199d6a",
* // "15102827c108566ea5daf725c09079c1a3f42ef99d1eb68ea8c584f7b16ab87a",
* // "cc27be8846276612dfce5924b7be96556212f0f0e62bd17641732175edb9911e"
* // ]
* // }
* //
*
*/
async balance(address) {
try {
// Handle single address.
if (typeof address === "string") {
const response = await axios.get(
`${this.restURL}blockbook/balance/${address}`,
_this.axiosOptions
)
return response.data
// Handle array of addresses.
} else if (Array.isArray(address)) {
const response = await axios.post(
`${this.restURL}blockbook/balance`,
{
addresses: address
},
_this.axiosOptions
)
return response.data
}
throw new Error(`Input address must be a string or array of strings.`)
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
}
}
/**
* @api Blockbook.utxo() utxo() - Get list of uxto for address.
* @apiName Blockbook Utxo
* @apiGroup Blockbook
* @apiDescription Return list of uxto for address.
*
* @apiExample Example usage:
* (async () => {
* try {
* let utxo = await bchjs.Blockbook.utxo('bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf');
* console.log(utxo);
* } catch(error) {
* console.error(error)
* }
* })()
*
* [{
* "txid": "7774e449c5a3065144cefbc4c0c21e6b69c987f095856778ef9f45ddd8ae1a41",
* "vout": 0,
* "value": "1000",
* "height": 604392,
* "confirmations": 25530,
* "satoshis": 1000
* }]
*
*
* (async () => {
* try {
* let utxo = await bchjs.Blockbook.utxo([
* "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
* "bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c"
* ]);
* console.log(utxo);
* } catch(error) {
* console.error(error)
* }
* })()
*
* [
* [{
* "txid": "7774e449c5a3065144cefbc4c0c21e6b69c987f095856778ef9f45ddd8ae1a41",
* "vout": 0,
* "value": "1000",
* "height": 604392,
* "confirmations": 25530,
* "satoshis": 1000
* }],
* [{
* "txid": "d5228d2cdc77fbe5a9aa79f19b0933b6802f9f0067f42847fc4fe343664723e5",
* "vout": 0,
* "value": "6000",
* "confirmations": 0,
* "satoshis": 6000
* }]
* ]
*/
async utxo(address) {
try {
// Handle single address.
if (typeof address === "string") {
const response = await axios.get(
`${this.restURL}blockbook/utxos/${address}`,
_this.axiosOptions
)
return response.data
// Handle array of addresses.
} else if (Array.isArray(address)) {
const response = await axios.post(
`${this.restURL}blockbook/utxos`,
{
addresses: address
},
_this.axiosOptions
)
return response.data
}
throw new Error(`Input address must be a string or array of strings.`)
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
}
}
/**
* @api Blockbook.tx() tx() - Get details on a transaction.
* @apiName Blockbook Tx
* @apiGroup Blockbook
* @apiDescription Get details on a transaction.
*
* @apiExample Example usage:
* (async () => {
* try {
* let txDetails = await bchjs.Blockbook.tx(`5fe9b74056319a8c87f45cc745030715a6180758b94938dbf90d639d55652392`);
* console.log(txDetails);
* } catch(error) {
* console.error(error)
* }
* })()
*
*/
async tx(txid) {
try {
// Handle single txid.
if (typeof txid === "string") {
const response = await axios.get(
`${this.restURL}blockbook/tx/${txid}`,
_this.axiosOptions
)
return response.data
// Handle array of addresses.
} else if (Array.isArray(txid)) {
const response = await axios.post(
`${this.restURL}blockbook/tx`,
{
txids: txid
},
_this.axiosOptions
)
return response.data
}
throw new Error(`Input txid must be a string or array of strings.`)
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
}
}
}
module.exports = Blockbook
+71 -59
View File
@@ -3,19 +3,29 @@
- Add blockhash functionality back into getTxOutProof
*/
const axios = require("axios")
const axios = require('axios')
let _this
class Blockchain {
constructor(config) {
constructor (config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
}
}
@@ -23,7 +33,7 @@ class Blockchain {
}
/**
* @api Blockchain.getBestBlockHash() getBestBlockHash() - Returns the hash of the best (tip) block in the longest blockchain.
* @api Blockchain.getBestBlockHash() getBestBlockHash()
* @apiName getBestBlockHash
* @apiGroup Blockchain
* @apiDescription
@@ -40,7 +50,7 @@ class Blockchain {
* })()
* // 241decef88889efac8e6ce428a8ac696fdde5972eceed97e1fb58d6106af31d5
*/
async getBestBlockHash() {
async getBestBlockHash () {
try {
const response = await axios.get(
`${this.restURL}blockchain/getBestBlockHash`,
@@ -54,7 +64,7 @@ class Blockchain {
}
/**
* @api Blockchain.getBlock() getBlock() - Return information about block hash.
* @api Blockchain.getBlock() getBlock()
* @apiName getBlock
* @apiGroup Blockchain
* @apiDescription
@@ -88,7 +98,7 @@ class Blockchain {
* // previousblockhash: '0000000008e647742775a230787d66fdf92c46a48c896bfbc85cdc8acc67e87d',
* // nextblockhash: '00000000a2887344f8db859e372e7e4bc26b23b9de340f725afbf2edb265b4c6' }
*/
async getBlock(blockhash, verbose = true) {
async getBlock (blockhash, verbose = true) {
try {
const response = await axios.get(
`${this.restURL}blockchain/getBlock/${blockhash}?verbose=${verbose}`,
@@ -102,7 +112,7 @@ class Blockchain {
}
/**
* @api Blockchain.getBlockchainInfo() getBlockchainInfo() - Returns an object containing various state info regarding blockchain processing.
* @api Blockchain.getBlockchainInfo() getBlockchainInfo()
* @apiName getBlockchainInfo
* @apiGroup Blockchain
* @apiDescription
@@ -138,7 +148,7 @@ class Blockchain {
* // timeout: 1493596800,
* // since: 419328 } } }
*/
async getBlockchainInfo() {
async getBlockchainInfo () {
try {
const response = await axios.get(
`${this.restURL}blockchain/getBlockchainInfo`,
@@ -152,7 +162,7 @@ class Blockchain {
}
/**
* @api Blockchain.getBlockCount() getBlockCount() - Returns the number of blocks in the longest blockchain.
* @api Blockchain.getBlockCount() getBlockCount()
* @apiName getBlockCount
* @apiGroup Blockchain
* @apiDescription
@@ -169,7 +179,7 @@ class Blockchain {
* })()
* // 529235
*/
async getBlockCount() {
async getBlockCount () {
try {
const response = await axios.get(
`${this.restURL}blockchain/getBlockCount`,
@@ -183,7 +193,7 @@ class Blockchain {
}
/**
* @api Blockchain.getBlockHash() getBlockHash() - Returns hash of block in best-block-chain at height provided.
* @api Blockchain.getBlockHash() getBlockHash()
* @apiName getBlockHash
* @apiGroup Blockchain
* @apiDescription
@@ -200,8 +210,8 @@ class Blockchain {
* })()
* // [ '000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f' ]
*/
async getBlockHash(height = 1) {
if (typeof height !== "string") height = JSON.stringify(height)
async getBlockHash (height = 1) {
if (typeof height !== 'string') height = JSON.stringify(height)
try {
const response = await axios.get(
@@ -216,7 +226,7 @@ class Blockchain {
}
/**
* @api Blockchain.getBlockHeader() getBlockHeader() - Return information about blockheader hash.
* @api Blockchain.getBlockHeader() getBlockHeader()
* @apiName getBlockHeader
* @apiGroup Blockchain
* @apiDescription
@@ -247,10 +257,10 @@ class Blockchain {
* // previousblockhash: '0000000008e647742775a230787d66fdf92c46a48c896bfbc85cdc8acc67e87d',
* // nextblockhash: '00000000a2887344f8db859e372e7e4bc26b23b9de340f725afbf2edb265b4c6' }]
*/
async getBlockHeader(hash, verbose = true) {
async getBlockHeader (hash, verbose = true) {
try {
// Handle single hash.
if (typeof hash === "string") {
if (typeof hash === 'string') {
const response = await axios.get(
`${this.restURL}blockchain/getBlockHeader/${hash}?verbose=${verbose}`,
_this.axiosOptions
@@ -273,7 +283,7 @@ class Blockchain {
return response.data
}
throw new Error(`Input hash must be a string or array of strings.`)
throw new Error('Input hash must be a string or array of strings.')
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
@@ -281,7 +291,7 @@ class Blockchain {
}
/**
* @api Blockchain.getChainTips() getChainTips() - Return information about all known tips in the block tree.
* @api Blockchain.getChainTips() getChainTips()
* @apiName getChainTips
* @apiGroup Blockchain
* @apiDescription
@@ -310,7 +320,7 @@ class Blockchain {
* // branchlen: 1,
* // status: 'valid-headers' } ]
*/
async getChainTips() {
async getChainTips () {
try {
const response = await axios.get(
`${this.restURL}blockchain/getChainTips`,
@@ -324,7 +334,7 @@ class Blockchain {
}
/**
* @api Blockchain.getDifficulty() getDifficulty() - Returns the proof-of-work difficulty as a multiple of the minimum difficulty.
* @api Blockchain.getDifficulty() getDifficulty()
* @apiName getDifficulty
* @apiGroup Blockchain
* @apiDescription
@@ -342,7 +352,7 @@ class Blockchain {
*
* // 702784497476.8376
*/
async getDifficulty() {
async getDifficulty () {
try {
const response = await axios.get(
`${this.restURL}blockchain/getDifficulty`,
@@ -356,8 +366,8 @@ class Blockchain {
}
// getMempoolAncestors
async getMempoolAncestors(txid, verbose = false) {
if (typeof txid !== "string") txid = JSON.stringify(txid)
async getMempoolAncestors (txid, verbose = false) {
if (typeof txid !== 'string') txid = JSON.stringify(txid)
try {
const response = await axios.get(
@@ -371,8 +381,8 @@ class Blockchain {
}
}
async getMempoolDescendants(txid, verbose = false) {
if (typeof txid !== "string") txid = JSON.stringify(txid)
async getMempoolDescendants (txid, verbose = false) {
if (typeof txid !== 'string') txid = JSON.stringify(txid)
try {
const response = await axios.get(
@@ -387,7 +397,7 @@ class Blockchain {
}
/**
* @api Blockchain.getMempoolEntry() getMempoolEntry() - Returns mempool data for given transaction.
* @api Blockchain.getMempoolEntry() getMempoolEntry()
* @apiName getMempoolEntry
* @apiGroup Blockchain
* @apiDescription
@@ -467,11 +477,11 @@ class Blockchain {
* // }
* // ]
*/
async getMempoolEntry(txid) {
//if (typeof txid !== "string") txid = JSON.stringify(txid)
async getMempoolEntry (txid) {
// if (typeof txid !== "string") txid = JSON.stringify(txid)
try {
if (typeof txid === "string") {
if (typeof txid === 'string') {
const response = await axios.get(
`${this.restURL}blockchain/getMempoolEntry/${txid}`,
_this.axiosOptions
@@ -491,7 +501,7 @@ class Blockchain {
return response.data
}
throw new Error(`Input must be a string or array of strings.`)
throw new Error('Input must be a string or array of strings.')
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
@@ -499,7 +509,7 @@ class Blockchain {
}
/**
* @api Blockchain.getMempoolInfo() getMempoolInfo() - Returns details on the active state of the TX memory pool.
* @api Blockchain.getMempoolInfo() getMempoolInfo()
* @apiName getMempoolInfo
* @apiGroup Blockchain
* @apiDescription
@@ -521,7 +531,7 @@ class Blockchain {
* // maxmempool: 300000000,
* // mempoolminfee: 0 }
*/
async getMempoolInfo() {
async getMempoolInfo () {
try {
const response = await axios.get(
`${this.restURL}blockchain/getMempoolInfo`,
@@ -535,7 +545,7 @@ class Blockchain {
}
/**
* @api Blockchain.getRawMempool() getRawMempool() - Returns all transaction ids in memory pool as a json array of string transaction ids.
* @api Blockchain.getRawMempool() getRawMempool()
* @apiName getRawMempool
* @apiGroup Blockchain
* @apiDescription
@@ -568,7 +578,7 @@ class Blockchain {
* // depends:
* // [ 'e25682caafc7000645d59f4c11d8d594b2943979b9d8fafb9f946e2b35c21b7e' ] },]
*/
async getRawMempool(verbose = false) {
async getRawMempool (verbose = false) {
try {
const response = await axios.get(
`${this.restURL}blockchain/getRawMempool?vebose=${verbose}`,
@@ -582,7 +592,7 @@ class Blockchain {
}
/**
* @api Blockchain.getTxOut() getTxOut() - Returns details about an unspent transaction output.
* @api Blockchain.getTxOut() getTxOut()
* @apiName getTxOut
* @apiGroup Blockchain
* @apiDescription
@@ -600,20 +610,22 @@ class Blockchain {
*
* // null
*/
async getTxOut(txid, n, include_mempool = true) {
async getTxOut (txid, n, includeMempool = true) {
try {
// Input validation
if (typeof txid !== "string" || txid.length !== 64)
throw new Error(`txid needs to be a proper transaction ID`)
if (typeof txid !== 'string' || txid.length !== 64) {
throw new Error('txid needs to be a proper transaction ID')
}
if (isNaN(n)) throw new Error(`n must be an integer`)
if (isNaN(n)) throw new Error('n must be an integer')
if (typeof include_mempool !== "boolean")
throw new Error(`include_mempool input must be of type boolean`)
if (typeof includeMempool !== 'boolean') {
throw new Error('includeMempool input must be of type boolean')
}
// Send the request to the REST API.
// const response = await axios.get(
// `${this.restURL}blockchain/getTxOut/${txid}/${n}?include_mempool=${include_mempool}`,
// `${this.restURL}blockchain/getTxOut/${txid}/${n}?includeMempool=${includeMempool}`,
// _this.axiosOptions
// )
const response = await axios.post(
@@ -621,7 +633,7 @@ class Blockchain {
{
txid: txid,
vout: n,
mempool: include_mempool
mempool: includeMempool
},
_this.axiosOptions
)
@@ -634,7 +646,7 @@ class Blockchain {
}
/**
* @api Blockchain.getTxOutProof() getTxOutProof() - Returns a hex-encoded proof that "txid" was included in a block.
* @api Blockchain.getTxOutProof() getTxOutProof()
* @apiName getTxOutProof
* @apiGroup Blockchain
* @apiDescription
@@ -669,12 +681,12 @@ class Blockchain {
* // "010000007de867cc8adc5cc8fb6b898ca4462cf9fd667d7830a275277447e60800000000338f121232e169d3100edd82004dc2a1f0e1f030c6c488fa61eafa930b0528fe021f7449ffff001d36b4af9a0100000001338f121232e169d3100edd82004dc2a1f0e1f030c6c488fa61eafa930b0528fe0101"
* // ]
*/
async getTxOutProof(txids) {
async getTxOutProof (txids) {
try {
// Single txid.
if (typeof txids === "string") {
if (typeof txids === 'string') {
const path = `${this.restURL}blockchain/getTxOutProof/${txids}`
//if (blockhash) path = `${path}?blockhash=${blockhash}`
// if (blockhash) path = `${path}?blockhash=${blockhash}`
const response = await axios.get(path, _this.axiosOptions)
return response.data
@@ -693,14 +705,14 @@ class Blockchain {
return response.data
}
throw new Error(`Input must be a string or array of strings.`)
throw new Error('Input must be a string or array of strings.')
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
}
}
async preciousBlock(blockhash) {
async preciousBlock (blockhash) {
try {
const response = await axios.get(
`${this.restURL}blockchain/preciousBlock/${blockhash}`,
@@ -713,7 +725,7 @@ class Blockchain {
}
}
async pruneBlockchain(height) {
async pruneBlockchain (height) {
try {
const response = await axios.post(
`${this.restURL}blockchain/pruneBlockchain/${height}`,
@@ -726,7 +738,7 @@ class Blockchain {
}
}
async verifyChain(checklevel = 3, nblocks = 6) {
async verifyChain (checklevel = 3, nblocks = 6) {
try {
const response = await axios.get(
`${this.restURL}blockchain/verifyChain?checklevel=${checklevel}&nblocks=${nblocks}`,
@@ -740,7 +752,7 @@ class Blockchain {
}
/**
* @api Blockchain.verifyTxOutProof() verifyTxOutProof() - Verifies that a proof points to a transaction in a block.
* @api Blockchain.verifyTxOutProof() verifyTxOutProof()
* @apiName verifyTxOutProof
* @apiGroup Blockchain
* @apiDescription
@@ -776,10 +788,10 @@ class Blockchain {
* // "03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7"
* // ]
*/
async verifyTxOutProof(proof) {
async verifyTxOutProof (proof) {
try {
// Single block
if (typeof proof === "string") {
if (typeof proof === 'string') {
const response = await axios.get(
`${this.restURL}blockchain/verifyTxOutProof/${proof}`,
_this.axiosOptions
@@ -800,7 +812,7 @@ class Blockchain {
return response.data
}
throw new Error(`Input must be a string or array of strings.`)
throw new Error('Input must be a string or array of strings.')
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
+19 -9
View File
@@ -2,19 +2,29 @@
API endpoints for basic control and information of the full node.
*/
const axios = require("axios")
const axios = require('axios')
let _this // Global reference to the instance of this class.
class Control {
constructor(config) {
constructor (config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
}
}
@@ -22,7 +32,7 @@ class Control {
}
/**
* @api Control.getNetworkInfo() getNetworkInfo() - Get Network info
* @api Control.getNetworkInfo() getNetworkInfo()
* @apiName getNetworkInfo
* @apiGroup Control
* @apiDescription Returns an object containing various network info.
@@ -67,7 +77,7 @@ class Control {
* warnings:
* 'Warning: Unknown block versions being mined! It\'s possible unknown rules are in effect' }}
*/
async getNetworkInfo() {
async getNetworkInfo () {
try {
const response = await axios.get(
`${this.restURL}control/getNetworkInfo`,
@@ -80,7 +90,7 @@ class Control {
}
}
async getMemoryInfo() {
async getMemoryInfo () {
try {
const response = await axios.get(
`${this.restURL}control/getMemoryInfo`,
+12 -12
View File
@@ -1,9 +1,9 @@
const randomBytes = require("randombytes")
const Bitcoin = require("bitcoincashjs-lib")
const randomBytes = require('randombytes')
const Bitcoin = require('@psf/bitcoincashjs-lib')
class Crypto {
/**
* @api Crypto.sha256() sha256() - Utility for creating sha256 hash.
* @api Crypto.sha256() sha256()
* @apiName sha256
* @apiGroup Crypto
* @apiDescription Utility for creating sha256 hash digests of data
@@ -26,12 +26,12 @@ class Crypto {
*
* */
// Translate address from any address format into a specific format.
static sha256(buffer) {
static sha256 (buffer) {
return Bitcoin.crypto.sha256(buffer)
}
/**
* @api Crypto.ripemd160() ripemd160()-Utility for creating ripemd160 hash.
* @api Crypto.ripemd160() ripemd160()
* @apiName ripemd160
* @apiGroup Crypto
* @apiDescription Utility for creating ripemd160 hash digests of data
@@ -52,12 +52,12 @@ class Crypto {
* bchjs.Crypto.ripemd160(buffer)
* // <Buffer 5f 95 6a 88 86 30 51 ea 52 15 d8 97 0c ed 8e 21 8e b6 15 cf>
* */
static ripemd160(buffer) {
static ripemd160 (buffer) {
return Bitcoin.crypto.ripemd160(buffer)
}
/**
* @api Crypto.hash256() hash256() - Utility for creating double sha256 hash.
* @api Crypto.hash256() hash256()
* @apiName hash256
* @apiGroup Crypto
* @apiDescription Utility for creating double sha256 hash digests of data.
@@ -78,12 +78,12 @@ class Crypto {
* bchjs.Crypto.hash256(buffer)
* // <Buffer 68 8f 1d 02 9e d5 4c 34 d0 32 0b 83 8b f6 fc 64 f6 2f 38 a6 e9 30 a0 af 5b db 4e 27 d1 a6 84 cd>
* */
static hash256(buffer) {
static hash256 (buffer) {
return Bitcoin.crypto.hash256(buffer)
}
/**
* @api Crypto.hash160() hash160() - Utility for creating ripemd160(sha256()) hash.
* @api Crypto.hash160() hash160()
* @apiName hash160
* @apiGroup Crypto
* @apiDescription Utility for creating ripemd160(sha256()) hash digests of data.
@@ -104,12 +104,12 @@ class Crypto {
* bchjs.Crypto.hash160(buffer)
*
* */
static hash160(buffer) {
static hash160 (buffer) {
return Bitcoin.crypto.hash160(buffer)
}
/**
* @api Crypto.randomBytes() randomBytes() - Generates cryptographically strong pseudo-random data.
* @api Crypto.randomBytes() randomBytes()
* @apiName randomBytes
* @apiGroup Crypto
* @apiDescription Generates cryptographically strong pseudo-random data. The size argument is a number indicating the number of bytes to generate.
@@ -130,7 +130,7 @@ class Crypto {
* bchjs.Crypto.randomBytes(32)
* // <Buffer ec 44 73 72 ea 48 3e 08 a5 0a 62 b8 40 0f 69 64 a7 75 35 af 20 3d e1 6d ce 3b f9 37 11 19 2b c6>
* */
static randomBytes(size = 16) {
static randomBytes (size = 16) {
return randomBytes(size)
}
}
+25 -21
View File
@@ -1,12 +1,13 @@
const Bitcoin = require("bitcoincashjs-lib")
const coininfo = require("coininfo")
const Bitcoin = require('@psf/bitcoincashjs-lib')
const coininfo = require('@psf/coininfo')
class ECPair {
static setAddress(address) {
static setAddress (address) {
ECPair._address = address
}
/**
* @api Ecpair.fromWIF() fromWIF() - Generates an ECPair from a private key in wallet import format (WIF).
* @api Ecpair.fromWIF() fromWIF()
* @apiName fromWIF
* @apiGroup ECPair
* @apiDescription Generates an ECPair from a private key in wallet import format (WIF). Follow these steps to go from a private key to a WIF. This method only works with a compressed private key.
@@ -20,22 +21,21 @@ class ECPair {
* let wif = 'cSNLj6xeg3Yg2rfcgKoWNx4MiAgn9ugCUUro37UDEhn6CzeYqjWW'
* bchjs.ECPair.fromWIF(wif)
* */
static fromWIF(privateKeyWIF) {
static fromWIF (privateKeyWIF) {
let network
if (privateKeyWIF[0] === "L" || privateKeyWIF[0] === "K")
network = "mainnet"
else if (privateKeyWIF[0] === "c") network = "testnet"
if (privateKeyWIF[0] === 'L' || privateKeyWIF[0] === 'K') { network = 'mainnet' } else if (privateKeyWIF[0] === 'c') network = 'testnet'
let bitcoincash
if (network === "mainnet") bitcoincash = coininfo.bitcoincash.main
if (network === 'mainnet') bitcoincash = coininfo.bitcoincash.main
else bitcoincash = coininfo.bitcoincash.test
const bitcoincashBitcoinJSLib = bitcoincash.toBitcoinJS()
return Bitcoin.ECPair.fromWIF(privateKeyWIF, bitcoincashBitcoinJSLib)
}
/**
* @api Ecpair.toWIF() toWIF() - Gets a private key in wallet import format from an ECPair.
* @api Ecpair.toWIF() toWIF()
* @apiName toWIF
* @apiGroup ECPair
* @apiDescription Gets a private key in wallet import format from an ECPair.
@@ -57,19 +57,20 @@ class ECPair {
* bchjs.ECPair.toWIF(ecpair);
* // cT3tJP7BnjFJSAHbooMXrY8E9t2AFj37amSBAYFMeHfqPqPgD4ZA
* */
static toWIF(ecpair) {
static toWIF (ecpair) {
return ecpair.toWIF()
}
static sign(ecpair, buffer) {
static sign (ecpair, buffer) {
return ecpair.sign(buffer)
}
static verify(ecpair, buffer, signature) {
static verify (ecpair, buffer, signature) {
return ecpair.verify(buffer, signature)
}
/**
* @api Ecpair.fromPublicKey() fromPublicKey() - Generates an ECPair from a public key buffer.
* @api Ecpair.fromPublicKey() fromPublicKey()
* @apiName fromPublicKey
* @apiGroup ECPair
* @apiDescription Generates an ECPair from a public key buffer.
@@ -83,11 +84,12 @@ class ECPair {
* let pubkeyBuffer = Buffer.from("024a6d0737a23c472d078d78c1cbc3c2bbf8767b48e72684ff03a911b463da7fa6", 'hex');
* bchjs.ECPair.fromPublicKey(pubkeyBuffer);
* */
static fromPublicKey(pubkeyBuffer) {
static fromPublicKey (pubkeyBuffer) {
return Bitcoin.ECPair.fromPublicKeyBuffer(pubkeyBuffer)
}
/**
* @api Ecpair.toPublicKey() toPublicKey() - Get the public key of an ECPair as a buffer.
* @api Ecpair.toPublicKey() toPublicKey()
* @apiName toPublicKey
* @apiGroup ECPair
* @apiDescription Get the public key of an ECPair as a buffer.
@@ -105,11 +107,12 @@ class ECPair {
* bchjs.ECPair.toPublicKey(ecpair);
* //
* */
static toPublicKey(ecpair) {
static toPublicKey (ecpair) {
return ecpair.getPublicKeyBuffer()
}
/**
* @api Ecpair.toLegacyAddress() toLegacyAddress() - Get legacy address of ECPair.
* @api Ecpair.toLegacyAddress() toLegacyAddress()
* @apiName toLegacyAddress
* @apiGroup ECPair
* @apiDescription Get legacy address of ECPair.
@@ -131,11 +134,12 @@ class ECPair {
* bchjs.ECPair.toLegacyAddress(ecpair);
* // mg4PygFcXoyNJGJkM2Dcpe25av9wXzz1My
* */
static toLegacyAddress(ecpair) {
static toLegacyAddress (ecpair) {
return ecpair.getAddress()
}
/**
* @api Ecpair.toCashAddress() toCashAddress() - Get cash address of ECPair.
* @api Ecpair.toCashAddress() toCashAddress()
* @apiName toCashAddress
* @apiGroup ECPair
* @apiDescription Get cash address of ECPair.
@@ -157,7 +161,7 @@ class ECPair {
* bchjs.ECPair.toCashAddress(ecpair);
* // bchtest:qqzly4vrcxcjw62u4yq4nv86ltk2mc9v0yvq8mvj6m
* */
static toCashAddress(ecpair, regtest = false) {
static toCashAddress (ecpair, regtest = false) {
return ECPair._address.toCashAddress(ecpair.getAddress(), true, regtest)
}
}
+224 -19
View File
@@ -3,20 +3,29 @@
by FullStack.cash
*/
const axios = require("axios")
const axios = require('axios')
let _this
class ElectrumX {
constructor(config) {
constructor (config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`,
timeout: 15000
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
}
}
@@ -88,10 +97,10 @@ class ElectrumX {
* }
*
*/
async utxo(address) {
async utxo (address) {
try {
// Handle single address.
if (typeof address === "string") {
if (typeof address === 'string') {
const response = await axios.get(
`${this.restURL}electrumx/utxos/${address}`,
_this.axiosOptions
@@ -111,7 +120,7 @@ class ElectrumX {
return response.data
}
throw new Error(`Input address must be a string or array of strings.`)
throw new Error('Input address must be a string or array of strings.')
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
@@ -172,10 +181,10 @@ class ElectrumX {
* }
*
*/
async balance(address) {
async balance (address) {
try {
// Handle single address.
if (typeof address === "string") {
if (typeof address === 'string') {
const response = await axios.get(
`${this.restURL}electrumx/balance/${address}`,
_this.axiosOptions
@@ -195,7 +204,7 @@ class ElectrumX {
return response.data
}
throw new Error(`Input address must be a string or array of strings.`)
throw new Error('Input address must be a string or array of strings.')
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
@@ -270,10 +279,10 @@ class ElectrumX {
* }
*
*/
async transactions(address) {
async transactions (address) {
try {
// Handle single address.
if (typeof address === "string") {
if (typeof address === 'string') {
const response = await axios.get(
`${this.restURL}electrumx/transactions/${address}`,
_this.axiosOptions
@@ -293,7 +302,7 @@ class ElectrumX {
return response.data
}
throw new Error(`Input address must be a string or array of strings.`)
throw new Error('Input address must be a string or array of strings.')
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
@@ -362,10 +371,10 @@ class ElectrumX {
* }
*
*/
async unconfirmed(address) {
async unconfirmed (address) {
try {
// Handle single address.
if (typeof address === "string") {
if (typeof address === 'string') {
const response = await axios.get(
`${this.restURL}electrumx/unconfirmed/${address}`,
_this.axiosOptions
@@ -385,7 +394,203 @@ class ElectrumX {
return response.data
}
throw new Error(`Input address must be a string or array of strings.`)
throw new Error('Input address must be a string or array of strings.')
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
}
}
/**
* @api Electrumx.blockHeader() blockHeader()
* @apiName ElectrumX Block headers
* @apiGroup ElectrumX
* @apiDescription Return block headers for a given height
*
* @apiExample Example usage:
* (async () => {
* try {
* let headers = await bchjs.Electrumx.blockHeaders(42);
* console.log(headers);
* } catch(error) {
* console.error(error)
* }
* })()
*
* headers = {
* "success": true,
* "headers": [
* "010000008b52bbd72c2f49569059f559c1b1794de5192e4f7d6d2b03c7482bad0000000083e4f8a9d502ed0c419075c1abb5d56f878a2e9079e5612bfb76a2dc37d9c42741dd6849ffff001d2b909dd6",
* "01000000f528fac1bcb685d0cd6c792320af0300a5ce15d687c7149548904e31000000004e8985a786d864f21e9cbb7cbdf4bc9265fe681b7a0893ac55a8e919ce035c2f85de6849ffff001d385ccb7c"
* ]
* }
*
* (async () => {
* try {
* let headers = await bchjs.Electrumx.blockHeaders(42, 1);
* console.log(headers);
* } catch(error) {
* console.error(error)
* }
* })()
*
* headers = {
* "success": true,
* "headers": [
* "010000008b52bbd72c2f49569059f559c1b1794de5192e4f7d6d2b03c7482bad0000000083e4f8a9d502ed0c419075c1abb5d56f878a2e9079e5612bfb76a2dc37d9c42741dd6849ffff001d2b909dd6"
* ]
* }
*
*/
async blockHeader (height, count = 1) {
try {
const response = await axios.get(
`${this.restURL}electrumx/block/headers/${height}?count=${count}`,
_this.axiosOptions
)
return response.data
} catch (error) {
// console.log("error: ", error)
if (error.response && error.response.data) {
if (error.response && error.response.data) { throw new Error(error.response.data.error) } else throw error.response.data
} else {
throw error
}
}
}
/**
* @api Electrumx.txData() txData()
* @apiName ElectrumX txData
* @apiGroup ElectrumX
* @apiDescription Returns an object with transaction details of the TXID
*
* @apiExample Example usage:
* (async () => {
* try {
* let result = await bchjs.Electrumx.txData('4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251')
* console.log(result);
* } catch(error) {
* console.error(error)
* }
* })()
*
* result = {
* "success": true,
* "details": {
* "blockhash": "0000000000000000002aaf94953da3b487317508ebd1003a1d75d6d6ec2e75cc",
* "blocktime": 1578327094,
* "confirmations": 31861,
* "hash": "4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251",
* ...
* "vin": [
* {
* "scriptSig": {
* ...
* "vout": [
* {
* "n": 0,
* "scriptPubKey": {
* "addresses": [
* "bitcoincash: pqvfecpwxvj53ayqfwkxtjaxsgpvnklcyg8xewk9hl"
* ],
* }
* ...
* }
*
* (async () => {
* try {
* let result = await bchjs.Electrumx.txData(['4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251', '4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251'])
* console.log(result);
* } catch(error) {
* console.error(error)
* }
* })()
*
* result = {
* "transactions": [
* {
* "txid": "4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251",
* "details": {
* "blockhash": "0000000000000000002aaf94953da3b487317508ebd1003a1d75d6d6ec2e75cc",
* "blocktime": 1578327094,
* "confirmations": 31861,
* "hash": "4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251",
* ...
* }
* },
* {
* "txid": "4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251",
* "details": {
* "blockhash": "0000000000000000002aaf94953da3b487317508ebd1003a1d75d6d6ec2e75cc",
* "blocktime": 1578327094,
* ...
* }
* ]
* }
*/
async txData (txid) {
try {
// Handle single transaction.
if (typeof txid === 'string') {
const response = await axios.get(
`${this.restURL}electrumx/tx/data/${txid}`,
_this.axiosOptions
)
return response.data
} else if (Array.isArray(txid)) {
const response = await axios.post(
`${this.restURL}electrumx/tx/data`,
{
txids: txid
},
_this.axiosOptions
)
return response.data
}
throw new Error('Input txId must be a string or array of strings.')
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
}
}
/**
* @api Electrumx.broadcast() broadcast()
* @apiName ElectrumX Broadcast
* @apiGroup ElectrumX
* @apiDescription Broadcast a raw transaction and return the transaction ID on success or error on failure.
*
* (async () => {
* try {
* const txHex = "020000000265d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667010000006441dd1dd72770cadede1a7fd0363574846c48468a398ddfa41a9677c74cac8d2652b682743725a3b08c6c2021a629011e11a264d9036e9d5311e35b5f4937ca7b4e4121020797d8fd4d2fa6fd7cdeabe2526bfea2b90525d6e8ad506ec4ee3c53885aa309ffffffff65d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667000000006441347d7f218c11c04487c1ad8baac28928fb10e5054cd4494b94d078cfa04ccf68e064fb188127ff656c0b98e9ce87f036d183925d0d0860605877d61e90375f774121028a53f95eb631b460854fc836b2e5d31cad16364b4dc3d970babfbdcc3f2e4954ffffffff035ac355000000000017a914189ce02e332548f4804bac65cba68202c9dbf822878dfd0800000000001976a914285bb350881b21ac89724c6fb6dc914d096cd53b88acf9ef3100000000001976a91445f1f1c4a9b9419a5088a3e9c24a293d7a150e6488ac00000000"
* let result = await bchjs.Electrumx.broadcast(txHex)
* console.log(result);
* } catch(error) {
* console.error(error)
* }
* })()
*
* result = {
* "success": true,
* "txid": "..."
* }
*/
async broadcast (txHex) {
try {
if (typeof txHex === 'string') {
const response = await axios.post(
`${this.restURL}electrumx/tx/broadcast`,
{ txHex },
_this.axiosOptions
)
return response.data
}
throw new Error('Input txHex must be a string.')
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
+18 -10
View File
@@ -2,21 +2,30 @@
This library contains useful functions that deal with encryption.
*/
const axios = require("axios")
const axios = require('axios')
let _this
class Encryption {
constructor(config) {
constructor (config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.axios = axios
// console.log(`Blockbook apiToken: ${this.apiToken}`)
this.authToken = config.authToken
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
}
}
@@ -24,10 +33,9 @@ class Encryption {
}
// Search the blockchain for a public key associated with a BCH address.
async getPubKey(addr) {
async getPubKey (addr) {
try {
if (!addr || typeof addr !== "string")
throw new Error(`Input must be a valid Bitcoin Cash address.`)
if (!addr || typeof addr !== 'string') { throw new Error('Input must be a valid Bitcoin Cash address.') }
const response = await _this.axios.get(
`${this.restURL}encryption/publickey/${addr}`,
+17 -7
View File
@@ -1,23 +1,33 @@
const axios = require("axios")
const axios = require('axios')
let _this
class Generating {
constructor(config) {
constructor (config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
}
}
_this = this
}
async generateToAddress(blocks, address, maxtries = 1000000) {
async generateToAddress (blocks, address, maxtries = 1000000) {
try {
const response = await axios.post(
`${this.restURL}generating/generateToAddress/${blocks}/${address}?maxtries=${maxtries}`,
+53 -55
View File
@@ -1,15 +1,15 @@
const Bitcoin = require("bitcoincashjs-lib")
const coininfo = require("coininfo")
const bip32utils = require("bip32-utils")
const bchaddrjs = require("bchaddrjs-slp")
const Bitcoin = require('@psf/bitcoincashjs-lib')
const coininfo = require('@psf/coininfo')
const bip32utils = require('@psf/bip32-utils')
const bchaddrjs = require('bchaddrjs-slp')
class HDNode {
constructor(address) {
constructor (address) {
this._address = address
}
/**
* @api HDNode.fromSeed() fromSeed() - Create HDNode from Seed Buffer.
* @api HDNode.fromSeed() fromSeed()
* @apiName fromSeed
* @apiGroup HDNode
* @apiDescription
@@ -32,11 +32,9 @@ class HDNode {
* // create HDNode from seed buffer
* bchjs.HDNode.fromSeed(seedBuffer);
*/
fromSeed(rootSeedBuffer, network = "mainnet") {
fromSeed (rootSeedBuffer, network = 'mainnet') {
let bitcoincash
if (network === "bitcoincash" || network === "mainnet")
bitcoincash = coininfo.bitcoincash.main
else bitcoincash = coininfo.bitcoincash.test
if (network === 'bitcoincash' || network === 'mainnet') { bitcoincash = coininfo.bitcoincash.main } else bitcoincash = coininfo.bitcoincash.test
const bitcoincashBitcoinJSLib = bitcoincash.toBitcoinJS()
return Bitcoin.HDNode.fromSeedBuffer(
@@ -46,7 +44,7 @@ class HDNode {
}
/**
* @api HDNode.toLegacyAddress() toLegacyAddress() - Get legacy address of HDNode.
* @api HDNode.toLegacyAddress() toLegacyAddress()
* @apiName toLegacyAddress
* @apiGroup HDNode
* @apiDescription
@@ -75,12 +73,12 @@ class HDNode {
* bchjs.HDNode.toLegacyAddress(hdNode);
* // 14mVsq3H5Ep2Jb6AqoKsmY1BFHKCBGPDLi
*/
toLegacyAddress(hdNode) {
toLegacyAddress (hdNode) {
return hdNode.getAddress()
}
/**
* @api HDNode.toCashAddress() toCashAddress() - Get cash address of HDNode
* @api HDNode.toCashAddress() toCashAddress()
* @apiName toCashAddress
* @apiGroup HDNode
* @apiDescription
@@ -109,14 +107,14 @@ class HDNode {
* bchjs.HDNode.toCashAddress(hdNode);
* // bitcoincash:qq549jxsjv66kw0smdju4es2axnk7hhe9cquhjg4gt
*/
toCashAddress(hdNode, regtest = false) {
toCashAddress (hdNode, regtest = false) {
return this._address.toCashAddress(hdNode.getAddress(), true, regtest)
}
/**
* @api SLP.HDNode.toSLPAddress() toSLPAddress() - Get slp address of HDNode.
* @api SLP.HDNode.toSLPAddress() toSLPAddress()
* @apiName toSLPAddress
* @apiGroup SLP
* @apiGroup HDNode
* @apiDescription Get slp address of HDNode.
*
* @apiExample Example usage:
@@ -142,13 +140,13 @@ class HDNode {
* bchjs.SLP.HDNode.toSLPAddress(hdNode);
* // simpleledger:qqxh2z2z397m4c6u9s5x6wjtku742q8rpvm6al2nrf
*/
toSLPAddress(hdNode) {
toSLPAddress (hdNode) {
const cashAddr = this.toCashAddress(hdNode)
return bchaddrjs.toSlpAddress(cashAddr)
}
/**
* @api HDNode.toWIF() toWIF() - Get private key in wallet import format (WIF) of HDNode.
* @api HDNode.toWIF() toWIF()
* @apiName toWIF
* @apiGroup HDNode
* @apiDescription
@@ -177,12 +175,12 @@ class HDNode {
* bchjs.HDNode.toWIF(hdNode);
* // KwobPFhv3AuXc3ps6YtWfMVRpLBDBA7jnJddurfELTyTNcFhZYpJ
*/
toWIF(hdNode) {
toWIF (hdNode) {
return hdNode.keyPair.toWIF()
}
/**
* @api HDNode.toXPub() toXPub() - Get extended public key of HDNode.
* @api HDNode.toXPub() toXPub()
* @apiName toXPub
* @apiGroup HDNode
* @apiDescription
@@ -211,12 +209,12 @@ class HDNode {
* bchjs.HDNode.toXPub(hdNode);
* // xpub661MyMwAqRbcFuMLeHkSbTNwNHG9MQyrAZqV1Q4MEAsmj9MYa5sxg8WC2LKqW6EHviHVucBjWi1n38juZpDDeX3U6YrsMeACdcNSTHkM8BQ
*/
toXPub(hdNode) {
toXPub (hdNode) {
return hdNode.neutered().toBase58()
}
/**
* @api HDNode.toXPriv() toXPriv() - Get extended private key of HDNode.
* @api HDNode.toXPriv() toXPriv()
* @apiName toXPriv
* @apiGroup HDNode
* @apiDescription
@@ -245,12 +243,12 @@ class HDNode {
* bchjs.HDNode.toXPriv(hdNode);
* // xprv9s21ZrQH143K2b5GPP6zHz22E6LeCgQXJtwNbC3MA3Kz7Se7tveKo96EhqwFtSkYWkyenVcMqM7uq35PcUNG8cUdpsJEgwKG3dvfP7TmL3v
*/
toXPriv(hdNode) {
toXPriv (hdNode) {
return hdNode.toBase58()
}
/**
* @api HDNode.toKeyPair() toKeyPair() - Get the ECPair of an HDNode.
* @api HDNode.toKeyPair() toKeyPair()
* @apiName toKeyPair
* @apiGroup HDNode
* @apiDescription
@@ -277,12 +275,12 @@ class HDNode {
* // create public key buffer from HDNode
* bchjs.HDNode.toKeyPair(hdNode);
*/
toKeyPair(hdNode) {
toKeyPair (hdNode) {
return hdNode.keyPair
}
/**
* @api HDNode.toPublicKey() toPublicKey() - Get the public key of an HDNode as a buffer.
* @api HDNode.toPublicKey() toPublicKey()
* @apiName toPublicKey
* @apiGroup HDNode
* @apiDescription
@@ -311,12 +309,12 @@ class HDNode {
* bchjs.HDNode.toPublicKey(hdNode);
* // <Buffer 02 d2 26 74 6e 78 03 ac 11 e0 96 c6 24 de e8 dd 62 52 e7 8e 51 56 8a c1 18 62 aa 2a 72 50 1d ea 7d>
*/
toPublicKey(hdNode) {
toPublicKey (hdNode) {
return hdNode.getPublicKeyBuffer()
}
/**
* @api HDNode.fromXPriv() fromXPriv() - Generate HDNode from extended private key.
* @api HDNode.fromXPriv() fromXPriv()
* @apiName fromXPriv
* @apiGroup HDNode
* @apiDescription
@@ -329,17 +327,17 @@ class HDNode {
* // testnet xpriv
* bchjs.HDNode.fromXPriv('tprv8gQ3zr1F5pRHMebqqhorrorYNvUG3XkcZjSWVs2cEtRwwJy1TRhgRx4XcF8dYHM2eyTbTCcdKYNhqgyBQphxwRoVyVKr9zuyoA8WxNDRvom');
*/
fromXPriv(xpriv) {
fromXPriv (xpriv) {
let bitcoincash
if (xpriv[0] === "x") bitcoincash = coininfo.bitcoincash.main
else if (xpriv[0] === "t") bitcoincash = coininfo.bitcoincash.test
if (xpriv[0] === 'x') bitcoincash = coininfo.bitcoincash.main
else if (xpriv[0] === 't') bitcoincash = coininfo.bitcoincash.test
const bitcoincashBitcoinJSLib = bitcoincash.toBitcoinJS()
return Bitcoin.HDNode.fromBase58(xpriv, bitcoincashBitcoinJSLib)
}
/**
* @api HDNode.fromXPub() fromXPub() - Generate HDNode from extended public key.
* @api HDNode.fromXPub() fromXPub()
* @apiName fromXPub
* @apiGroup HDNode
* @apiDescription
@@ -352,17 +350,17 @@ class HDNode {
* // testnet xpub
* bchjs.HDNode.fromXPub('tpubDD669G3VEC6xF7ddjMUTGDWewwzCCrwX933HnP4ufAELmoDn5pXGcSgPnLodjFvWQwRXkG94f77BatEDA8dfQ99yy97kRYynUpNLENEqTBo');
*/
fromXPub(xpub) {
fromXPub (xpub) {
let bitcoincash
if (xpub[0] === "x") bitcoincash = coininfo.bitcoincash.main
else if (xpub[0] === "t") bitcoincash = coininfo.bitcoincash.test
if (xpub[0] === 'x') bitcoincash = coininfo.bitcoincash.main
else if (xpub[0] === 't') bitcoincash = coininfo.bitcoincash.test
const bitcoincashBitcoinJSLib = bitcoincash.toBitcoinJS()
return Bitcoin.HDNode.fromBase58(xpub, bitcoincashBitcoinJSLib)
}
/**
* @api HDNode.derivePath() derivePath() - Derive child HDNode from path.
* @api HDNode.derivePath() derivePath()
* @apiName derivePath
* @apiGroup HDNode
* @apiDescription
@@ -378,12 +376,12 @@ class HDNode {
* // derive hardened child HDNode
* bchjs.HDNode.derivePath(hdNode, "m/44'/145'/0'");
*/
derivePath(hdnode, path) {
derivePath (hdnode, path) {
return hdnode.derivePath(path)
}
/**
* @api HDNode.derive() derive() - Derive non hardened child HDNode.
* @api HDNode.derive() derive()
* @apiName derive
* @apiGroup HDNode
* @apiDescription
@@ -399,12 +397,12 @@ class HDNode {
* // derive unhardened child HDNode
* bchjs.HDNode.derive(hdNode, 0);
*/
derive(hdnode, path) {
derive (hdnode, path) {
return hdnode.derive(path)
}
/**
* @api HDNode.deriveHardened() deriveHardened() - Derive hardened child HDNode.
* @api HDNode.deriveHardened() deriveHardened()
* @apiName deriveHardened
* @apiGroup HDNode
* @apiDescription
@@ -420,12 +418,12 @@ class HDNode {
* // derive hardened child HDNode
* bchjs.HDNode.deriveHardened(hdNode, 0);
*/
deriveHardened(hdnode, path) {
deriveHardened (hdnode, path) {
return hdnode.deriveHardened(path)
}
/**
* @api HDNode.sign() sign() - Sign 32 byte hash encoded as a buffer.
* @api HDNode.sign() sign()
* @apiName sign
* @apiGroup HDNode
* @apiDescription
@@ -450,12 +448,12 @@ class HDNode {
* // sign
* bchjs.HDNode.sign(hdnode, buf);
*/
sign(hdnode, buffer) {
sign (hdnode, buffer) {
return hdnode.sign(buffer)
}
/**
* @api HDNode.verify() verify() - Verify signed 32 byte hash encoded as a buffer.
* @api HDNode.verify() verify()
* @apiName verify
* @apiGroup HDNode
* @apiDescription
@@ -494,12 +492,12 @@ class HDNode {
* bchjs.HDNode.verify(hdnode2, buf, signature);
* // false
*/
verify(hdnode, buffer, signature) {
verify (hdnode, buffer, signature) {
return hdnode.verify(buffer, signature)
}
/**
* @api HDNode.isPublic() isPublic() - Check if an HDNode can only derive public keys and children.
* @api HDNode.isPublic() isPublic()
* @apiName isPublic
* @apiGroup HDNode
* @apiDescription
@@ -530,12 +528,12 @@ class HDNode {
* bchjs.HDNode.isPublic(node);
* // false
*/
isPublic(hdnode) {
isPublic (hdnode) {
return hdnode.isNeutered()
}
/**
* @api HDNode.isPrivate() isPrivate() - Check if an HDNode can derive both public and private keys and children.
* @api HDNode.isPrivate() isPrivate()
* @apiName isPrivate
* @apiGroup HDNode
* @apiDescription
@@ -566,12 +564,12 @@ class HDNode {
* bchjs.HDNode.isPrivate(node);
* // true
*/
isPrivate(hdnode) {
isPrivate (hdnode) {
return !hdnode.isNeutered()
}
/**
* @api HDNode.toIdentifier() toIdentifier() - hash160 of Nodes public key.
* @api HDNode.toIdentifier() toIdentifier()
* @apiName toIdentifier
* @apiGroup HDNode
* @apiDescription
@@ -598,16 +596,16 @@ class HDNode {
* bchjs.Crypto.hash160(publicKeyBuffer);
* // <Buffer e1 8e 20 e3 f8 f1 c0 53 e6 1f 9e 3a 58 8e 71 f5 0b 8d 2d c4>
*/
toIdentifier(hdnode) {
toIdentifier (hdnode) {
return hdnode.getIdentifier()
}
fromBase58(base58, network) {
fromBase58 (base58, network) {
return Bitcoin.HDNode.fromBase58(base58, network)
}
/**
* @api HDNode.createAccount() createAccount() - Create BIP32 account.
* @api HDNode.createAccount() createAccount()
* @apiName createAccount
* @apiGroup HDNode
* @apiDescription
@@ -625,14 +623,14 @@ class HDNode {
* // create account
* let account = bchjs.HDNode.createAccount([childNode]);
*/
createAccount(hdNodes) {
createAccount (hdNodes) {
const arr = hdNodes.map(
(item, index) => new bip32utils.Chain(item.neutered())
)
return new bip32utils.Account(arr)
}
createChain(hdNode) {
createChain (hdNode) {
return new bip32utils.Chain(hdNode)
}
}
+62 -52
View File
@@ -3,19 +3,19 @@
and downloading data from the IPFS network.
*/
const axios = require("axios")
const Uppy = require("@uppy/core")
const Tus = require("@uppy/tus")
const fs = require("fs")
const axios = require('axios')
const Uppy = require('@uppy/core')
const Tus = require('@uppy/tus')
const fs = require('fs')
let _this
class IPFS {
constructor(config) {
constructor (config) {
this.IPFS_API = process.env.IPFS_API
? process.env.IPFS_API
: // : `http://localhost:5001`
`https://ipfs-api.fullstack.cash`
: 'https://ipfs-api.fullstack.cash'
// : `http://localhost:5001`
// Default options when calling axios.
this.axiosOptions = {
@@ -35,16 +35,16 @@ class IPFS {
}
// Initializes Uppy, which is used for file uploads.
initUppy() {
initUppy () {
const uppy = Uppy({
allowMultipleUploads: false,
meta: { test: "avatar" },
meta: { test: 'avatar' },
debug: false,
restrictions: {
maxFileSize: null,
maxNumberOfFiles: 1,
minNumberOfFiles: 1,
allowedFileTypes: null //type of files allowed to load
allowedFileTypes: null // type of files allowed to load
}
})
uppy.use(Tus, { endpoint: `${_this.IPFS_API}/uppy-files` })
@@ -53,7 +53,7 @@ class IPFS {
}
/**
* @api IPFS.createFileModelServer() createFileModelServer() - Create a file model
* @api IPFS.createFileModelServer() createFileModelServer()
* @apiName createFileModelServer()
* @apiGroup IPFS
* @apiDescription Creates a new model on the server. If successful, will
@@ -90,11 +90,12 @@ class IPFS {
* "__v": 0
* }
*/
async createFileModelServer(path) {
async createFileModelServer (path) {
try {
// Ensure the file exists.
if (!_this.fs.existsSync(path))
if (!_this.fs.existsSync(path)) {
throw new Error(`Could not find this file: ${path}`)
}
// Read in the file.
const fileBuf = _this.fs.readFileSync(path)
@@ -103,11 +104,11 @@ class IPFS {
// console.log(`Buffer length: ${fileBuf.length}`)
// Get the file name from the path.
const splitPath = path.split("/")
const splitPath = path.split('/')
const fileName = splitPath[splitPath.length - 1]
// Get the file extension.
const splitExt = fileName.split(".")
const splitExt = fileName.split('.')
const fileExt = splitExt[splitExt.length - 1]
const fileObj = {
@@ -125,13 +126,13 @@ class IPFS {
return fileData.data
} catch (err) {
console.error(`Error in createFileModel()`)
console.error('Error in createFileModel()')
throw err
}
}
/**
* @api IPFS.uploadFileServer() uploadFileServer() - Upload a file to IPFS
* @api IPFS.uploadFileServer() uploadFileServer()
* @apiName uploadFile()
* @apiGroup IPFS
* @apiDescription Upload a file to the FullStack.cash IPFS server. If
@@ -157,15 +158,16 @@ class IPFS {
* "fileExtension": "js"
* }
*/
async uploadFileServer(path, modelId) {
async uploadFileServer (path, modelId) {
try {
// Ensure the file exists.
if (!_this.fs.existsSync(path))
if (!_this.fs.existsSync(path)) {
throw new Error(`Could not find this file: ${path}`)
}
if (!modelId) {
throw new Error(
`Must include a file model ID in order to upload a file.`
'Must include a file model ID in order to upload a file.'
)
}
@@ -173,14 +175,14 @@ class IPFS {
const fileBuf = _this.fs.readFileSync(path)
// Get the file name from the path.
const splitPath = path.split("/")
const splitPath = path.split('/')
const fileName = splitPath[splitPath.length - 1]
// Prepare the upload object. Get a file ID from Uppy.
const id = _this.uppy.addFile({
name: fileName,
data: fileBuf,
source: "Local",
source: 'Local',
isRemote: false
})
// console.log(`id: ${JSON.stringify(id, null, 2)}`)
@@ -191,8 +193,9 @@ class IPFS {
// Upload the file to the server.
const upData = await _this.uppy.upload()
if (upData.failed.length)
throw new Error("The file could not be uploaded")
if (upData.failed.length) {
throw new Error('The file could not be uploaded')
}
if (upData.successful.length) {
delete upData.successful[0].data
@@ -213,13 +216,13 @@ class IPFS {
return false
} catch (err) {
console.error(`Error in bch-js/src/ipfs.js/upload(): `)
console.error('Error in bch-js/src/ipfs.js/upload(): ')
throw err
}
}
/**
* @api IPFS.getStatus() getStatus() - Check status of file upload
* @api IPFS.getStatus() getStatus()
* @apiName getStatus()
* @apiGroup IPFS
* @apiDescription Gets the status of the uploaded file. Will return an object
@@ -246,9 +249,9 @@ class IPFS {
* "fileName": "ipfs-e2e.js"
* }
*/
async getStatus(modelId) {
async getStatus (modelId) {
try {
if (!modelId) throw new Error(`Must include a file model ID.`)
if (!modelId) throw new Error('Must include a file model ID.')
const fileData = await _this.axios.get(
`${this.IPFS_API}/files/${modelId}`
@@ -266,12 +269,13 @@ class IPFS {
return fileObj
} catch (err) {
console.error(`Error in getStatus()`)
console.error('Error in getStatus()')
throw err
}
}
/**
* @api IPFS.createFileModelWeb() createFileModelWeb() - Create a file model
* @api IPFS.createFileModelWeb() createFileModelWeb()
* @apiName createFileModelWeb()
* @apiGroup IPFS
* @apiDescription Creates a new model on the server. If successful, will
@@ -311,20 +315,22 @@ class IPFS {
* "__v": 0
* }
*/
async createFileModelWeb(file) {
async createFileModelWeb (file) {
try {
if (!file) throw new Error(`File is required`)
if (!file) throw new Error('File is required')
const { name, size } = file
if (!name || typeof name !== "string")
throw new Error(`File should have the property 'name' of string type`)
if (!name || typeof name !== 'string') {
throw new Error("File should have the property 'name' of string type")
}
if (!size || typeof size !== "number")
throw new Error(`File should have the property 'size' of number type`)
if (!size || typeof size !== 'number') {
throw new Error("File should have the property 'size' of number type")
}
// Get the file extension.
const splitExt = name.split(".")
const splitExt = name.split('.')
const fileExt = splitExt[splitExt.length - 1]
const fileObj = {
@@ -342,13 +348,13 @@ class IPFS {
return fileData.data
} catch (err) {
console.error(`Error in createFileModelWeb()`)
console.error('Error in createFileModelWeb()')
throw err
}
}
/**
* @api IPFS.uploadFileWeb() uploadFileWeb() - Upload a file to IPFS
* @api IPFS.uploadFileWeb() uploadFileWeb()
* @apiName uploadFileWeb()
* @apiGroup IPFS
* @apiDescription Upload a file to the FullStack.cash IPFS server. If
@@ -377,24 +383,27 @@ class IPFS {
* "fileExtension": "js"
* }
*/
async uploadFileWeb(file, modelId) {
async uploadFileWeb (file, modelId) {
try {
if (!file) throw new Error(`File is required`)
if (!file) throw new Error('File is required')
const { name, type, size } = file
if (!name || typeof name !== "string")
throw new Error(`File should have the property 'name' of string type`)
if (!name || typeof name !== 'string') {
throw new Error("File should have the property 'name' of string type")
}
if (!type || typeof type !== "string")
throw new Error(`File should have the property 'type' of string type`)
if (!type || typeof type !== 'string') {
throw new Error("File should have the property 'type' of string type")
}
if (!size || typeof size !== "number")
throw new Error(`File should have the property 'size' of number type`)
if (!size || typeof size !== 'number') {
throw new Error("File should have the property 'size' of number type")
}
if (!modelId) {
throw new Error(
`Must include a file model ID in order to upload a file.`
'Must include a file model ID in order to upload a file.'
)
}
@@ -402,7 +411,7 @@ class IPFS {
const id = _this.uppy.addFile({
name: name,
data: file,
source: "Local",
source: 'Local',
isRemote: false
})
// console.log(`id: ${JSON.stringify(id, null, 2)}`)
@@ -413,8 +422,9 @@ class IPFS {
// Upload the file to the server.
const upData = await _this.uppy.upload()
if (upData.failed.length)
throw new Error("The file could not be uploaded")
if (upData.failed.length) {
throw new Error('The file could not be uploaded')
}
if (upData.successful.length) {
delete upData.successful[0].data
@@ -435,7 +445,7 @@ class IPFS {
return false
} catch (err) {
console.error(`Error in bch-js/src/ipfs.js/uploadFileWeb(): `)
console.error('Error in bch-js/src/ipfs.js/uploadFileWeb(): ')
throw err
}
}
+21 -11
View File
@@ -1,26 +1,36 @@
const axios = require("axios")
const axios = require('axios')
let _this
class Mining {
constructor(config) {
constructor (config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
}
}
_this = this
}
async getBlockTemplate(template_request) {
async getBlockTemplate (templateRequest) {
try {
const response = await axios.get(
`${this.restURL}mining/getBlockTemplate/${template_request}`,
`${this.restURL}mining/getBlockTemplate/${templateRequest}`,
_this.axiosOptions
)
return response.data
@@ -30,7 +40,7 @@ class Mining {
}
}
async getMiningInfo() {
async getMiningInfo () {
try {
const response = await axios.get(
`${this.restURL}mining/getMiningInfo`,
@@ -43,7 +53,7 @@ class Mining {
}
}
async getNetworkHashps(nblocks = 120, height = 1) {
async getNetworkHashps (nblocks = 120, height = 1) {
try {
const response = await axios.get(
`${this.restURL}mining/getNetworkHashps?nblocks=${nblocks}&height=${height}`,
@@ -56,7 +66,7 @@ class Mining {
}
}
async submitBlock(hex, parameters) {
async submitBlock (hex, parameters) {
let path = `${this.restURL}mining/submitBlock/${hex}`
if (parameters) path = `${path}?parameters=${parameters}`
+41 -41
View File
@@ -1,16 +1,19 @@
const BIP39 = require("bip39")
const randomBytes = require("randombytes")
const Bitcoin = require("bitcoincashjs-lib")
const Buffer = require("safe-buffer").Buffer
const wif = require("wif")
/* eslint no-prototype-builtins: "off" */
/* eslint node/no-callback-literal: "off" */
const BIP39 = require('bip39')
const randomBytes = require('randombytes')
const Bitcoin = require('@psf/bitcoincashjs-lib')
const Buffer = require('safe-buffer').Buffer
const wif = require('wif')
class Mnemonic {
constructor(address) {
constructor (address) {
this._address = address
}
/**
* @api Mnemonic.generate() generate() - Generate BIP39 mnemonic from entropy.
* @api Mnemonic.generate() generate()
* @apiName generate
* @apiGroup Mnemonic
* @apiDescription
@@ -45,12 +48,12 @@ class Mnemonic {
* bchjs.Mnemonic.generate(256, bitbox.Mnemonic.wordLists().korean)
* // 기능 단추 교육 비난 시집 근육 운동 코미디 숟가락 과목 한동안 유적 시리즈 삼월 앞날 유난히 흰색 사실 논문 장사 어른 논문 의논 장차
*/
generate(bits = 128, wordlist) {
generate (bits = 128, wordlist) {
return BIP39.generateMnemonic(bits, randomBytes, wordlist)
}
/**
* @api Mnemonic.fromEntropy() fromEntropy() - Create mnemonic from entropy.
* @api Mnemonic.fromEntropy() fromEntropy()
* @apiName fromEntropy
* @apiGroup Mnemonic
* @apiDescription
@@ -95,16 +98,13 @@ class Mnemonic {
* // generate 16 bytes of entropy
* let entropy = bchjs.Crypto.randomBytes(16);
* //
* // turn entropy to 12 japanese word mnemonic
* bchjs.Mnemonic.fromEntropy(entropy.toString('hex'), bchjs.Mnemonic.wordLists().japanese)
* // ぱそこん にあう にんめい きどく ちそう せんきょ かいが きおく いれる いねむり しいく きかんしゃ
*/
fromEntropy(bytes, wordlist) {
fromEntropy (bytes, wordlist) {
return BIP39.entropyToMnemonic(bytes, wordlist)
}
/**
* @api Mnemonic.toEntropy() toEntropy() - Turn mnemonic to entropy.
* @api Mnemonic.toEntropy() toEntropy()
* @apiName toEntropy
* @apiGroup Mnemonic
* @apiDescription
@@ -136,12 +136,12 @@ class Mnemonic {
* bchjs.Mnemonic.toEntropy(mnemonic)
* // <Buffer f3 79 da 02 cc 42 6e 6e 26 43 0d 25 e6 cc 37 2d fd 0a 1a 2e 4a 33 ac 4d c6 ae 6d 56 01 7f 64 2d>
*/
toEntropy(mnemonic, wordlist) {
return Buffer.from(BIP39.mnemonicToEntropy(mnemonic, wordlist), "hex")
toEntropy (mnemonic, wordlist) {
return Buffer.from(BIP39.mnemonicToEntropy(mnemonic, wordlist), 'hex')
}
/**
* @api Mnemonic.validate() validate() - Validate mnemonic.
* @api Mnemonic.validate() validate()
* @apiName validate
* @apiGroup Mnemonic
* @apiDescription
@@ -157,11 +157,11 @@ class Mnemonic {
* bchjs.Mnemonic.validate('boil lonely casino manage habit where total glory muffin name limit mansion boil lonely casino manage habit where total glory muffin name limit mansion', bitbox.Mnemonic.wordLists().english)
* // Invalid mnemonic
*/
validate(mnemonic, wordlist) {
validate (mnemonic, wordlist) {
// Preprocess the words
const words = mnemonic.split(" ")
const words = mnemonic.split(' ')
// Detect blank phrase
if (words.length === 0) return "Blank mnemonic"
if (words.length === 0) return 'Blank mnemonic'
// Check each word
for (let i = 0; i < words.length; i++) {
@@ -173,15 +173,15 @@ class Mnemonic {
}
}
// Check the words are valid
//const properPhrase = words.join()
// const properPhrase = words.join()
const isValid = BIP39.validateMnemonic(mnemonic, wordlist)
if (!isValid) return "Invalid mnemonic"
if (!isValid) return 'Invalid mnemonic'
return "Valid mnemonic"
return 'Valid mnemonic'
}
/**
* @api Mnemonic.toSeed() toSeed() - Create root seed from mnemonic
* @api Mnemonic.toSeed() toSeed()
* @apiName toSeed
* @apiGroup Mnemonic
* @apiDescription
@@ -203,12 +203,12 @@ class Mnemonic {
* await bchjs.Mnemonic.toSeed('frost deliver coin clutch upon round scene wonder various wise luggage country', 'yayayayay');
* // <Buffer 1d 00 9f a3 a8 86 51 a4 04 d5 03 3d eb 6d b1 01 e2 f1 3b c3 c8 6d 1f b9 93 b4 d1 33 dc 84 21 12 2c 9b 52 10 ba d8 96 15 e0 b0 9a 34 33 52 f8 07 c8 c4 ... >
*/
toSeed(mnemonic, password = "") {
toSeed (mnemonic, password = '') {
return BIP39.mnemonicToSeed(mnemonic, password)
}
/**
* @api Mnemonic.wordLists() wordLists() - Return mnemonic word lists.
* @api Mnemonic.wordLists() wordLists()
* @apiName wordLists
* @apiGroup Mnemonic
* @apiDescription
@@ -229,12 +229,12 @@ class Mnemonic {
* // spanish: []
* // }
*/
wordLists() {
wordLists () {
return BIP39.wordlists
}
/**
* @api Mnemonic.toKeypairs() toKeypairs() - Returns an array of privateKeyWIF/publicAddress pairs.
* @api Mnemonic.toKeypairs() toKeypairs()
* @apiName toKeypairs
* @apiGroup Mnemonic
* @apiDescription
@@ -260,10 +260,10 @@ class Mnemonic {
* // { privateKeyWIF: 'L5gB66JqhfouEtZG5aRMQ9JaVS2ggkK3YozGfzZegBupaPXqdfaz',
* // address: 'bitcoincash:qphwlpu2wzjxrjts94pn4wh778fwsu2afg2aj5her9' } ]
*/
async toKeypairs(mnemonic, numberOfKeypairs = 1, regtest = false) {
const rootSeedBuffer = await this.toSeed(mnemonic, "")
async toKeypairs (mnemonic, numberOfKeypairs = 1, regtest = false) {
const rootSeedBuffer = await this.toSeed(mnemonic, '')
const hdNode = Bitcoin.HDNode.fromSeedBuffer(rootSeedBuffer)
const HDPath = `44'/145'/0'/0/`
const HDPath = "44'/145'/0'/0/"
const accounts = []
@@ -290,7 +290,7 @@ class Mnemonic {
}
/**
* @api Mnemonic.findNearestWord() findNearestWord() - Returns nearest matching word from provided word list.
* @api Mnemonic.findNearestWord() findNearestWord()
* @apiName findNearestWord
* @apiGroup Mnemonic
* @apiDescription
@@ -321,7 +321,7 @@ class Mnemonic {
* bchjs.Mnemonic.findNearestWord(word, wordlist);
* // neve
*/
findNearestWord(word, wordlist) {
findNearestWord (word, wordlist) {
let minDistance = 99
let closestWord = wordlist[0]
for (let i = 0; i < wordlist.length; i++) {
@@ -352,7 +352,7 @@ module.exports = Mnemonic
* @return Object the final object.
*/
const _extend = function(dst) {
const _extend = function (dst) {
const sources = Array.prototype.slice.call(arguments, 1)
for (let i = 0; i < sources.length; ++i) {
const src = sources[i]
@@ -365,8 +365,8 @@ const _extend = function(dst) {
* Defer execution of given function.
* @param {Function} func
*/
const _defer = function(func) {
if (typeof setImmediate === "function") return setImmediate(func)
const _defer = function (func) {
if (typeof setImmediate === 'function') return setImmediate(func)
return setTimeout(func, 0)
}
@@ -374,7 +374,7 @@ const _defer = function(func) {
/**
* Based on the algorithm at http://en.wikipedia.org/wiki/Levenshtein_distance.
*/
var Levenshtein = {
const Levenshtein = {
/**
* Calculate levenshtein distance of the two strings.
*
@@ -382,7 +382,7 @@ var Levenshtein = {
* @param str2 String the second string.
* @return Integer the levenshtein distance (0 and above).
*/
get: function(str1, str2) {
get: function (str1, str2) {
// base cases
if (str1 === str2) return 0
if (str1.length === 0) return str2.length
@@ -432,7 +432,7 @@ var Levenshtein = {
* @param [options] Object additional options.
* @param [options.progress] Function progress callback with signature: function(percentComplete)
*/
getAsync: function(str1, str2, cb, options) {
getAsync: function (str1, str2, cb, options) {
options = _extend(
{},
{
@@ -457,7 +457,7 @@ var Levenshtein = {
i = 0
j = -1
var __calculate = function() {
const __calculate = function () {
// reset timer
startTime = new Date().valueOf()
currentTime = startTime
@@ -499,7 +499,7 @@ var Levenshtein = {
}
// send a progress update?
if (null !== options.progress) {
if (options.progress !== null) {
try {
options.progress.call(null, (i * 100.0) / str1.length)
} catch (err) {
+228 -10
View File
@@ -3,12 +3,12 @@
Bitcoin.com
*/
const axios = require("axios")
const axios = require('axios')
let _this
class Ninsight {
constructor(config) {
constructor (config) {
// this.restURL = config.restURL
// this.apiToken = config.apiToken
@@ -16,7 +16,7 @@ class Ninsight {
if (config) {
this.ninsightURL = config.ninsightURL
? config.ninsightURL
: `https://rest.bitcoin.com/v2`
: 'https://rest.bitcoin.com/v2'
}
// Add JWT token to the authorization header.
@@ -31,7 +31,7 @@ class Ninsight {
}
/**
* @api Ninsight.utxo() utxo() - Get list of uxto for address.
* @api Ninsight.utxo() utxo()
* @apiName Ninsight Utxo
* @apiGroup Ninsight
* @apiDescription Return list of uxto for address.
@@ -50,26 +50,28 @@ class Ninsight {
* // {
* // "txid": "d31dc2cf66fe4d3d3ae18e1065def58a64920746b1702b52f060e5edeea9883b",
* // "vout": 1,
* // "value": "1000000",
* // "amount": 0.03608203,
* // "satoshis": 3608203,
* // "height": 585570,
* // "confirmations": 10392
* // },
* // {
* // "txid": "41e9a118765ecf7a1ba4487c0863e23dba343cc5880381a72f0365ac2546c5fa",
* // "vout": 0,
* // "value": "1000000",
* // "amount": 0.03608203,
* // "satoshis": 3608203,
* // "height": 577125,
* // "confirmations": 18837
* // }
* // ]
*
*/
async utxo(address) {
async utxo (address) {
try {
// Handle single address.
if (typeof address === "string") {
if (typeof address === 'string') {
const response = await axios.post(
`${this.ninsightURL}/address/utxo/${address}`,
`${this.ninsightURL}/address/utxo`,
{
addresses: [address]
},
@@ -90,7 +92,223 @@ class Ninsight {
return response.data
}
throw new Error(`Input address must be a string or array of strings.`)
throw new Error('Input address must be a string or array of strings.')
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
}
}
/**
* @api Ninsight.unconfirmed() unconfirmed()
* @apiName Ninsight Unconfirmed Utxo
* @apiGroup Ninsight
* @apiDescription Returns a list of unconfirmed UTXOs for an address.
*
* @apiExample Example usage:
* (async () => {
* try {
* let utxo = await bchjs.Ninsight.unconfirmed('bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c');
* console.log(utxo);
* } catch(error) {
* console.error(error)
* }
* })()
*
* // [
* // {
* // "txid": "d31dc2cf66fe4d3d3ae18e1065def58a64920746b1702b52f060e5edeea9883b",
* // "vout": 1,
* // "amount": 0.03608203,
* // "satoshis": 3608203,
* // "confirmations": 0
* // "ts": 1559670801
* // },
* // {
* // "txid": "41e9a118765ecf7a1ba4487c0863e23dba343cc5880381a72f0365ac2546c5fa",
* // "vout": 0,
* // "amount": 0.03608203,
* // "satoshis": 3608203,
* // "confirmations": 0
* // "ts": 1559670902
* // }
* // ]
*
*/
async unconfirmed (address) {
try {
if (typeof address === 'string') {
const response = await axios.post(
`${this.ninsightURL}/address/unconfirmed`,
{
addresses: [address]
},
_this.axiosOptions
)
return response.data
} else if (Array.isArray(address)) {
const response = await axios.post(
`${this.ninsightURL}/address/unconfirmed`,
{
addresses: address
},
_this.axiosOptions
)
return response.data
}
throw new Error('Input address must be a string or array of strings.')
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
}
}
/**
* @api Ninsight.transactions() transactions()
* @apiName Ninsight TX History
* @apiGroup Ninsight
* @apiDescription Return transactions history for address.
*
* @apiExample Example usage:
* (async () => {
* try {
* let txs = await bchjs.Ninsight.transactions('bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c');
* console.log(txs);
* } catch(error) {
* console.error(error)
* }
* })()
*
* // [
* // {
* // "pagesTotal": 1,
* // "txs": [
* // {
* // "txid": "ec7bc8349386e3e1939bbdc4f8092fdbdd6a380734e68486b558cd594c451d5b",
* // "version": 2,
* // "locktime": 0,
* // "vin": [
* // {
* // "txid": "4f1fc57c33659628938db740449bf92fb75799e1d5750a4aeef80eb52d6df1e0",
* // "vout": 0,
* // "sequence": 4294967295,
* // "n": 0,
* // ...
* // }
* // ...
* // ]
* // ...
* // }
* // ],
* // "legacyAddress": "1LpbYkEM5cryfhs58tH8c93p4SGzit7UrP",
* // "cashAddress": "bitcoincash:qrvk436u4r0ew2wj0rd9pnxhx4w90p2yfc29ta0d2n",
* // "currentPage": 0
* // }
* // ]
* //
*
*/
async transactions (address) {
try {
if (typeof address === 'string') {
const response = await axios.post(
`${this.ninsightURL}/address/transactions`,
{
addresses: [address]
},
_this.axiosOptions
)
return response.data
} else if (Array.isArray(address)) {
const response = await axios.post(
`${this.ninsightURL}/address/transactions`,
{
addresses: address
},
_this.axiosOptions
)
return response.data
}
throw new Error('Input address must be a string or array of strings.')
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
}
}
/**
* @api Ninsight.txDetails() txDetails()
* @apiName Ninsight TX Details
* @apiGroup Ninsight
* @apiDescription Return transactions details for address(es).
*
* @apiExample Example usage:
* (async () => {
* try {
* let result = await bchjs.Ninsight.txDetails('fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33');
* console.log(result);
* } catch(error) {
* console.error(error)
* }
* })()
*
* // [
* // {
* // "txid": "fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33",
* // "version": 1,
* // "locktime": 0,
* // "vin": [
* // {
* // "sequence": 4294967295,
* // "n": 0
* // }
* // ],
* // "vout": [
* // ...
* // ],
* // "blockhash": "00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09",
* // "blockheight": 1000,
* // "confirmations": 659909,
* // "time": 1232346882,
* // "blocktime": 1232346882,
* // "firstSeenTime": null,
* // "valueOut": 50,
* // "size": 135
* // }
* // ]
*
*/
async txDetails (txid) {
try {
if (typeof txid === 'string') {
const response = await axios.post(
`${this.ninsightURL}/transaction/details`,
{
txids: [txid]
},
_this.axiosOptions
)
return response.data
} else if (Array.isArray(txid)) {
const response = await axios.post(
`${this.ninsightURL}/transaction/details`,
{
txids: txid
},
_this.axiosOptions
)
return response.data
}
throw new Error('Transaction ID must be a string or array of strings.')
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
+17 -17
View File
@@ -3,12 +3,12 @@
provides for their application.
*/
const axios = require("axios")
const axios = require('axios')
let _this
class OpenBazaar {
constructor(config) {
constructor (config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
@@ -23,7 +23,7 @@ class OpenBazaar {
}
/**
* @api OpenBazaar.balance() balance() - Balance about an address.
* @api OpenBazaar.balance() balance()
* @apiName OpenBazaar Balance
* @apiGroup OpenBazaar
* @apiDescription Return Balance about an address.
@@ -55,12 +55,12 @@ class OpenBazaar {
* }
*
*/
async balance(address) {
async balance (address) {
try {
// Handle single address.
if (typeof address === "string") {
if (typeof address === 'string') {
let response
if (process.env.NETWORK === "testnet") {
if (process.env.NETWORK === 'testnet') {
response = await axios.get(
`https://tbch.blockbook.api.openbazaar.org/api/address/${address}`,
_this.axiosOptions
@@ -75,7 +75,7 @@ class OpenBazaar {
return response.data
}
throw new Error(`Input address must be a string.`)
throw new Error('Input address must be a string.')
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
@@ -83,7 +83,7 @@ class OpenBazaar {
}
/**
* @api OpenBazaar.utxo() utxo() - Get list of uxto for address.
* @api OpenBazaar.utxo() utxo()
* @apiName OpenBazaar Utxo
* @apiGroup OpenBazaar
* @apiDescription Return list of uxto for address.
@@ -109,12 +109,12 @@ class OpenBazaar {
* }
* ]
*/
async utxo(address) {
async utxo (address) {
try {
// Handle single address.
if (typeof address === "string") {
if (typeof address === 'string') {
let response
if (process.env.NETWORK === "testnet") {
if (process.env.NETWORK === 'testnet') {
response = await axios.get(
`https://tbch.blockbook.api.openbazaar.org/api/utxo/${address}`,
_this.axiosOptions
@@ -127,7 +127,7 @@ class OpenBazaar {
}
return response.data
}
throw new Error(`Input address must be a string.`)
throw new Error('Input address must be a string.')
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
@@ -135,7 +135,7 @@ class OpenBazaar {
}
/**
* @api OpenBazaar.tx() tx() - Get details on a transaction.
* @api OpenBazaar.tx() tx()
* @apiName OpenBazaar Tx
* @apiGroup OpenBazaar
* @apiDescription Get details on a transaction.
@@ -199,12 +199,12 @@ class OpenBazaar {
* }
*
*/
async tx(txid) {
async tx (txid) {
try {
// Handle single txid.
if (typeof txid === "string") {
if (typeof txid === 'string') {
let response
if (process.env.NETWORK === "testnet") {
if (process.env.NETWORK === 'testnet') {
response = await axios.get(
`https://tbch.blockbook.api.openbazaar.org/api/tx/${txid}`,
_this.axiosOptions
@@ -218,7 +218,7 @@ class OpenBazaar {
return response.data
}
throw new Error(`Input txid must be a string.`)
throw new Error('Input txid must be a string.')
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
+151 -24
View File
@@ -1,32 +1,159 @@
const axios = require("axios")
/**
* @api price.current() current() - Get current price.
* @apiName Price.
* @apiGroup Price
* @apiDescription Return current price of BCH in multiple currencies.
*
* @apiExample Example usage:
*(async () => {
* try {
* let current = await bchjs.Price.current('usd');
* console.log(current);
* } catch(error) {
* console.error(error)
* }
*})()
*
* // 26681
*/
const axios = require('axios')
let _this
class Price {
async current(currency = "usd") {
constructor (config) {
_this = this
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
}
}
this.axios = axios
}
// This endpoint is deprecated. Documentation removed.
async current (currency = 'usd') {
try {
const response = await axios.get(
const response = await this.axios.get(
`https://index-api.bitcoin.com/api/v0/cash/price/${currency.toLowerCase()}`
)
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
return response.data.price
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
} catch (err) {
if (err.response && err.response.data) throw err.response.data
else throw err
}
}
/**
* @api price.getUsd() getUsd()
* @apiName Price getUsd()
* @apiGroup Price
* @apiDescription Return current price of BCH in USD.
* This endpoint gets the USD price of BCH from the Coinbase API. The price
* comes from bch-api, so it has a better chance of working in Tor.
*
* @apiExample Example usage:
*(async () => {
* try {
* let current = await bchjs.Price.getUsd();
* console.log(current);
* } catch(err) {
* console.err(err)
* }
*})()
*
* // 266.81
*/
async getUsd () {
try {
const response = await this.axios.get(
`${this.restURL}price/usd`,
_this.axiosOptions
)
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
return response.data.usd
} catch (err) {
if (err.response && err.response.data) throw err.response.data
else throw err
}
}
/**
* @api price.rates() rates()
* @apiName Price rates()
* @apiGroup Price
* @apiDescription Return current price of BCH in several different currencies.
* This endpoint gets the price of BCH from the Coinbase API in many different
* currencies. The price
* comes from bch-api, so it has a better chance of working in Tor.
*
* @apiExample Example usage:
*(async () => {
* try {
* let current = await bchjs.Price.rates();
* console.log(current);
* } catch(err) {
* console.err(err)
* }
*})()
*
* {
* AED: "915.049218",
* AFN: "19144.48874646",
* ALGO: "826.6633482661356600405",
* ...
* ZRX: "644.844402797695193656",
* ZWL: "80215.03"
* }
*/
async rates () {
try {
const response = await this.axios.get(
`${this.restURL}price/rates`,
_this.axiosOptions
)
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
return response.data
} catch (err) {
if (err.response && err.response.data) throw err.response.data
else throw err
}
}
/**
* @api price.getBchaUsd() getBchaUsd()
* @apiName Price getBchaUsd()
* @apiGroup Price
* @apiDescription Return current price of BCHA in USD.
* This endpoint gets the USD price of BCHA from the Coinex API. The price
* comes from bch-api, so it has a better chance of working in Tor.
*
* @apiExample Example usage:
*(async () => {
* try {
* let current = await bchjs.Price.getBchaUsd();
* console.log(current);
* } catch(err) {
* console.err(err)
* }
*})()
*
* // 18.81
*/
async getBchaUsd () {
try {
const response = await this.axios.get(
`${this.restURL}price/bchausd`,
_this.axiosOptions
)
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
return response.data.usd
} catch (err) {
if (err.response && err.response.data) throw err.response.data
else throw err
}
}
}
+45 -36
View File
@@ -1,24 +1,37 @@
const axios = require("axios")
const axios = require('axios')
let _this
class RawTransactions {
constructor(config) {
constructor (config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
}
}
// Encapsulate dependencies
this.axios = axios
_this = this
}
/**
* @api RawTransactions.decodeRawTransaction() decodeRawTransaction() - Return an Array of JSON objects representing the serialized, hex-encoded transactions.
* @api RawTransactions.decodeRawTransaction() decodeRawTransaction()
* @apiName decodeRawTransaction
* @apiGroup RawTransactions
* @apiDescription
@@ -79,10 +92,10 @@ class RawTransactions {
* // vin: [ [Object] ],
* // vout: [ [Object] ] } ]
*/
async decodeRawTransaction(hex) {
async decodeRawTransaction (hex) {
try {
// Single hex
if (typeof hex === "string") {
if (typeof hex === 'string') {
const response = await axios.get(
`${this.restURL}rawtransactions/decodeRawTransaction/${hex}`,
_this.axiosOptions
@@ -93,7 +106,7 @@ class RawTransactions {
// Array of hexes
} else if (Array.isArray(hex)) {
const options = {
method: "POST",
method: 'POST',
url: `${this.restURL}rawtransactions/decodeRawTransaction`,
data: {
hexes: hex
@@ -107,7 +120,7 @@ class RawTransactions {
return response.data
}
throw new Error(`Input must be a string or array of strings.`)
throw new Error('Input must be a string or array of strings.')
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
@@ -115,7 +128,7 @@ class RawTransactions {
}
/**
* @api RawTransactions.decodeScript() decodeScript() - Decode hex-encoded scripts.
* @api RawTransactions.decodeScript() decodeScript()
* @apiName decodeScript
* @apiGroup RawTransactions
* @apiDescription
@@ -147,11 +160,11 @@ class RawTransactions {
* // type: 'nonstandard',
* // p2sh: 'bitcoincash:pqwndulzwft8dlmqrteqyc9hf823xr3lcc7ypt74ts' }]
*/
async decodeScript(script) {
//if (typeof script !== "string") script = JSON.stringify(script)
async decodeScript (script) {
// if (typeof script !== "string") script = JSON.stringify(script)
try {
if (typeof script === "string") {
if (typeof script === 'string') {
const response = await axios.get(
`${this.restURL}rawtransactions/decodeScript/${script}`,
_this.axiosOptions
@@ -160,7 +173,7 @@ class RawTransactions {
return response.data
} else if (Array.isArray(script)) {
const options = {
method: "POST",
method: 'POST',
url: `${this.restURL}rawtransactions/decodeScript`,
data: {
hexes: script
@@ -174,7 +187,7 @@ class RawTransactions {
return response.data
}
throw new Error(`Input must be a string or array of strings.`)
throw new Error('Input must be a string or array of strings.')
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
@@ -182,7 +195,7 @@ class RawTransactions {
}
/**
* @api RawTransactions.getRawTransaction() getRawTransaction() - Return the raw transaction data.
* @api RawTransactions.getRawTransaction() getRawTransaction()
* @apiName getRawTransaction
* @apiGroup RawTransactions
* @apiDescription
@@ -245,9 +258,9 @@ class RawTransactions {
* // time: 1547752564,
* // blocktime: 1547752564 } ]
*/
async getRawTransaction(txid, verbose = false) {
async getRawTransaction (txid, verbose = false) {
try {
if (typeof txid === "string") {
if (typeof txid === 'string') {
const response = await axios.get(
`${this.restURL}rawtransactions/getRawTransaction/${txid}?verbose=${verbose}`,
_this.axiosOptions
@@ -256,22 +269,20 @@ class RawTransactions {
return response.data
} else if (Array.isArray(txid)) {
const options = {
method: "POST",
method: 'POST',
url: `${this.restURL}rawtransactions/getRawTransaction`,
data: {
txids: txid,
verbose: verbose
},
headers: {
authorization: `Token ${this.apiToken}`
}
headers: _this.axiosOptions.headers
}
const response = await axios(options)
return response.data
}
throw new Error(`Input must be a string or array of strings.`)
throw new Error('Input must be a string or array of strings.')
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
@@ -279,7 +290,7 @@ class RawTransactions {
}
/**
* @api RawTransactions.sendRawTransaction() sendRawTransaction() - Submits raw transaction (serialized, hex-encoded) to local node and network.
* @api RawTransactions.sendRawTransaction() sendRawTransaction()
* @apiName sendRawTransaction
* @apiGroup RawTransactions
* @apiDescription
@@ -310,16 +321,16 @@ class RawTransactions {
* })()
* // ['0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098']
*/
async sendRawTransaction(hex, allowhighfees = false) {
async sendRawTransaction (hex, allowhighfees = false) {
try {
// Single tx hex.
if (typeof hex === "string") {
const response = await axios.get(
if (typeof hex === 'string') {
const response = await this.axios.get(
`${this.restURL}rawtransactions/sendRawTransaction/${hex}`,
_this.axiosOptions
)
if (response.data === "66: insufficient priority") {
if (response.data === '66: insufficient priority') {
console.warn(
`WARN: Insufficient Priority! This is likely due to a fee that is too low, or insufficient funds.
Please ensure that there is BCH in the given wallet. If you are running on the testnet, get some
@@ -332,21 +343,19 @@ class RawTransactions {
// Array input
} else if (Array.isArray(hex)) {
const options = {
method: "POST",
method: 'POST',
url: `${this.restURL}rawtransactions/sendRawTransaction`,
data: {
hexes: hex
},
headers: {
authorization: `Token ${this.apiToken}`
}
headers: _this.axiosOptions.headers
}
const response = await axios(options)
const response = await _this.axios(options)
return response.data
}
throw new Error(`Input hex must be a string or array of strings.`)
throw new Error('Input hex must be a string or array of strings.')
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
+43 -33
View File
@@ -1,20 +1,30 @@
const schnorr = require("bip-schnorr")
const schnorr = require('bip-schnorr')
class Schnorr {
constructor(config) {
constructor (config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
}
}
}
/**
* @api Schnorr.sign() sign() - Sign a 32-byte message with the private key, returning a 64-byte signature.
* @api Schnorr.sign() sign()
* @apiName sign
* @apiGroup Schnorr
* @apiDescription
@@ -36,12 +46,12 @@ class Schnorr {
* console.log("The signature is: " + createdSignature.toString("hex"))
* // The signature is: 2a298dacae57395a15d0795ddbfd1dcb564da82b0f269bc70a74f8220429ba1d1e51a22ccec35599b8f266912281f8365ffc2d035a230434a1a64dc59f7013fd
*/
sign(privateKey, message) {
sign (privateKey, message) {
return schnorr.sign(privateKey, message)
}
/**
* @api Schnorr.verify() verify() - Verify a 64-byte signature of a 32-byte message against the public key.
* @api Schnorr.verify() verify()
* @apiName verify
* @apiGroup Schnorr
* @apiDescription
@@ -68,12 +78,12 @@ class Schnorr {
* console.error("The signature verification failed: " + e)
* }
*/
verify(publicKey, message, signatureToVerify) {
verify (publicKey, message, signatureToVerify) {
return schnorr.verify(publicKey, message, signatureToVerify)
}
/**
* @api Schnorr.batchVerify() batchVerify() - Verify a list of 64-byte signatures as a batch operation.
* @api Schnorr.batchVerify() batchVerify()
* @apiName batchVerify
* @apiGroup Schnorr
* @apiDescription
@@ -130,12 +140,12 @@ class Schnorr {
* console.error("The signature verification failed: " + e)
* }
*/
batchVerify(publicKeys, messages, signaturesToVerify) {
batchVerify (publicKeys, messages, signaturesToVerify) {
return schnorr.batchVerify(publicKeys, messages, signaturesToVerify)
}
/**
* @api Schnorr.nonInteractive() nonInteractive() - Aggregates multiple signatures of different private keys
* @api Schnorr.nonInteractive() nonInteractive()
* @apiName nonInteractive
* @apiGroup Schnorr
* @apiDescription
@@ -179,12 +189,12 @@ class Schnorr {
* console.error("The signature verification failed: " + e)
* }
*/
nonInteractive(privateKeys, message) {
nonInteractive (privateKeys, message) {
return schnorr.muSig.nonInteractive(privateKeys, message)
}
/**
* @api Schnorr.computeEll() computeEll() - Generate ell which is the hash over all public keys participating in a session.
* @api Schnorr.computeEll() computeEll()
* @apiName computeEll
* @apiGroup Schnorr
* @apiDescription
@@ -253,12 +263,12 @@ class Schnorr {
* // -----------------------------------------------------------------------
* publicData.pubKeyHash = bchjs.Schnorr.computeEll(publicData.pubKeys)
*/
computeEll(publicKeys) {
computeEll (publicKeys) {
return schnorr.muSig.computeEll(publicKeys)
}
/**
* @api Schnorr.publicKeyCombine() publicKeyCombine() - Creates a special rogue-key-resistant.
* @api Schnorr.publicKeyCombine() publicKeyCombine()
* @apiName publicKeyCombine
* @apiGroup Schnorr
* @apiDescription
@@ -271,12 +281,12 @@ class Schnorr {
* publicData.pubKeyHash
* )
*/
publicKeyCombine(publicKeys, publicKeyHash) {
publicKeyCombine (publicKeys, publicKeyHash) {
return schnorr.muSig.pubKeyCombine(publicKeys, publicKeyHash)
}
/**
* @api Schnorr.sessionInitialize() sessionInitialize() - Creates a signing session.
* @api Schnorr.sessionInitialize() sessionInitialize()
* @apiName sessionInitialize
* @apiGroup Schnorr
* @apiDescription
@@ -303,7 +313,7 @@ class Schnorr {
* })
* const signerSession = signerPrivateData[0].session
*/
sessionInitialize(sessionId, privateKey, message, pubKeyCombined, ell, idx) {
sessionInitialize (sessionId, privateKey, message, pubKeyCombined, ell, idx) {
return schnorr.muSig.sessionInitialize(
sessionId,
privateKey,
@@ -315,7 +325,7 @@ class Schnorr {
}
/**
* @api Schnorr.sessionNonceCombine() sessionNonceCombine() - Combines multiple nonces R_i into the combined nonce R.
* @api Schnorr.sessionNonceCombine() sessionNonceCombine()
* @apiName sessionNonceCombine
* @apiGroup Schnorr
* @apiDescription
@@ -355,12 +365,12 @@ class Schnorr {
* data => (data.session.nonceIsNegated = signerSession.nonceIsNegated)
* )
*/
sessionNonceCombine(session, nonces) {
sessionNonceCombine (session, nonces) {
return schnorr.muSig.sessionNonceCombine(session, nonces)
}
/**
* @api Schnorr.partialSign() partialSign() - Creates a partial signature s_i for a participant.
* @api Schnorr.partialSign() partialSign()
* @apiName partialSign
* @apiGroup Schnorr
* @apiDescription
@@ -382,7 +392,7 @@ class Schnorr {
* )
* })
*/
partialSign(session, message, nonceCombined, pubKeyCombined) {
partialSign (session, message, nonceCombined, pubKeyCombined) {
return schnorr.muSig.partialSign(
session,
message,
@@ -392,7 +402,7 @@ class Schnorr {
}
/**
* @api Schnorr.partialSignatureVerify() partialSignatureVerify() - Verifies a partial signature s_i against the participant's public key P_i.
* @api Schnorr.partialSignatureVerify() partialSignatureVerify()
* @apiName partialSignatureVerify
* @apiGroup Schnorr
* @apiDescription
@@ -426,7 +436,7 @@ class Schnorr {
* )
* }
*/
partialSignatureVerify(
partialSignatureVerify (
session,
partialSignature,
nonceCombined,
@@ -445,7 +455,7 @@ class Schnorr {
}
/**
* @api Schnorr.partialSignaturesCombine() partialSignaturesCombine() - Combines multiple partial signatures into a Schnorr signature.
* @api Schnorr.partialSignaturesCombine() partialSignaturesCombine()
* @apiName partialSignaturesCombine
* @apiGroup Schnorr
* @apiDescription
@@ -474,27 +484,27 @@ class Schnorr {
* publicData.signature
* )
*/
partialSignaturesCombine(nonceCombined, partialSignatures) {
partialSignaturesCombine (nonceCombined, partialSignatures) {
return schnorr.muSig.partialSigCombine(nonceCombined, partialSignatures)
}
bufferToInt(buffer) {
bufferToInt (buffer) {
return schnorr.convert.bufferToInt(buffer)
}
intToBuffer(bigInteger) {
intToBuffer (bigInteger) {
return schnorr.convert.intToBuffer(bigInteger)
}
hash(buffer) {
hash (buffer) {
return schnorr.convert.hash(buffer)
}
pointToBuffer(point) {
pointToBuffer (point) {
return schnorr.convert.pointToBuffer(point)
}
pubKeyToPoint(publicKey) {
pubKeyToPoint (publicKey) {
return schnorr.convert.pubKeyToPoint(publicKey)
}
}
+10 -10
View File
@@ -1,8 +1,8 @@
const Bitcoin = require("bitcoincashjs-lib")
const opcodes = require("bitcoincash-ops")
const Bitcoin = require('@psf/bitcoincashjs-lib')
const opcodes = require('@psf/bitcoincash-ops')
class Script {
constructor() {
constructor () {
this.opcodes = opcodes
this.nullData = Bitcoin.script.nullData
this.multisig = {
@@ -58,7 +58,7 @@ class Script {
* bchjs.Script.classifyInput(bchjs.Script.fromASM(scripthashInput));
* // scripthash
*/
classifyInput(script) {
classifyInput (script) {
return Bitcoin.script.classifyInput(script)
}
@@ -90,7 +90,7 @@ class Script {
* bchjs.Script.classifyOutput(bchjs.Script.fromASM(scripthashOutput));
* // scripthash
*/
classifyOutput(script) {
classifyOutput (script) {
return Bitcoin.script.classifyOutput(script)
}
@@ -116,7 +116,7 @@ class Script {
* // 136,
* // 172 ]
*/
decode(scriptBuffer) {
decode (scriptBuffer) {
return Bitcoin.script.decompile(scriptBuffer)
}
@@ -150,7 +150,7 @@ class Script {
* bchjs.Script.encode(scriptPubKey);
* // <Buffer 76 a9 14 24 e9 c0 78 04 d0 ee 7e 5b da 93 4e 0a 3a e8 71 0f c0 07 dd 88 ac>
*/
encode(scriptChunks) {
encode (scriptChunks) {
const arr = []
scriptChunks.forEach(chunk => {
arr.push(chunk)
@@ -187,7 +187,7 @@ class Script {
* bchjs.Script.encode2(scriptPubKey);
* // <Buffer 76 a9 14 24 e9 c0 78 04 d0 ee 7e 5b da 93 4e 0a 3a e8 71 0f c0 07 dd 88 ac>
*/
encode2(scriptChunks) {
encode2 (scriptChunks) {
const arr = []
scriptChunks.forEach(chunk => {
arr.push(chunk)
@@ -213,7 +213,7 @@ class Script {
* bchjs.Script.toASM(scriptBuffer);
* // OP_DUP OP_HASH160 bee4182d9fbc8931a728410a0cd3e0f340f2995a OP_EQUALVERIFY OP_CHECKSIG
*/
toASM(buffer) {
toASM (buffer) {
return Bitcoin.script.toASM(buffer)
}
@@ -235,7 +235,7 @@ class Script {
* bchjs.Script.fromASM(scriptPubKeyASM);
* // <Buffer 76 a9 14 be e4 18 2d 9f bc 89 31 a7 28 41 0a 0c d3 e0 f3 40 f2 99 5a 88 ac>
*/
fromASM(asm) {
fromASM (asm) {
return Bitcoin.script.fromASM(asm)
}
}
+37 -31
View File
@@ -1,11 +1,11 @@
const BCHJSAddress = require("../address")
const BCHJSAddress = require('../address')
// const bchAddress = new BCHJSAddress()
let bchAddress
const bchaddrjs = require("bchaddrjs-slp")
const bchaddrjs = require('bchaddrjs-slp')
class Address extends BCHJSAddress {
constructor(config) {
constructor (config) {
super(config)
this.restURL = config.restURL
@@ -14,7 +14,7 @@ class Address extends BCHJSAddress {
}
/**
* @api SLP.Address.toSLPAddress() toSLPAddress() - Converting to slpAddress format.
* @api SLP.Address.toSLPAddress() toSLPAddress()
* @apiName toSLPAddress
* @apiGroup SLP
* @apiDescription Converting legacy or cashaddr to slpAddress format.
@@ -52,15 +52,15 @@ class Address extends BCHJSAddress {
* bchjs.SLP.Address.toSLPAddress('msDbtTj7kWXPpYaR7PQmMK84i66fJqQMLx', false)
* // qzq9je6pntpva3wf6scr7mlnycr54sjgeqauyclpwv
*/
toSLPAddress(address, prefix = true, regtest = false) {
toSLPAddress (address, prefix = true, regtest = false) {
this._ensureValidAddress(address)
const slpAddress = bchaddrjs.toSlpAddress(address)
if (prefix) return slpAddress
return slpAddress.split(":")[1]
return slpAddress.split(':')[1]
}
/**
* @api SLP.Address.toCashAddress() toCashAddress() - Converting to cashAddress format.
* @api SLP.Address.toCashAddress() toCashAddress()
* @apiName toCashAddress
* @apiGroup SLP
* @apiDescription Converting legacy or slpaddr to cashAddress format.
@@ -98,15 +98,15 @@ class Address extends BCHJSAddress {
* bchjs.SLP.Address.toCashAddress('msDbtTj7kWXPpYaR7PQmMK84i66fJqQMLx', false)
* // qzq9je6pntpva3wf6scr7mlnycr54sjgeqxgrr9ku3
*/
toCashAddress(address, prefix = true, regtest = false) {
toCashAddress (address, prefix = true, regtest = false) {
this._ensureValidAddress(address)
const cashAddress = bchaddrjs.toCashAddress(address)
if (prefix) return cashAddress
return cashAddress.split(":")[1]
return cashAddress.split(':')[1]
}
/**
* @api SLP.Address.toLegacyAddress() toLegacyAddress() - Converting to legacy address format.
* @api SLP.Address.toLegacyAddress() toLegacyAddress()
* @apiName toLegacyAddress
* @apiGroup SLP
* @apiDescription Converting cashaddr or slpaddr to legacy address format.
@@ -145,18 +145,18 @@ class Address extends BCHJSAddress {
* bchjs.SLP.Address.toLegacyAddress('qph2v4mkxjgdqgmlyjx6njmey0ftrxlnggs3v58dse')
* // mqc1tmwY2368LLGktnePzEyPAsgADxbksi
*/
toLegacyAddress(address) {
toLegacyAddress (address) {
this._ensureValidAddress(address)
const cashAddr = bchaddrjs.toCashAddress(address)
return bchAddress.toLegacyAddress(cashAddr)
}
isLegacyAddress(address) {
isLegacyAddress (address) {
this._ensureValidAddress(address)
return bchAddress.isLegacyAddress(address)
}
isCashAddress(address) {
isCashAddress (address) {
this._ensureValidAddress(address)
if (bchaddrjs.isSlpAddress(address)) return false
@@ -164,7 +164,7 @@ class Address extends BCHJSAddress {
}
/**
* @api SLP.Address.isSLPAddress() isSLPAddress() - Detect if slpAddr encoded address.
* @api SLP.Address.isSLPAddress() isSLPAddress()
* @apiName isSLPAddress
* @apiGroup SLP
* @apiDescription Detect if slpAddr encoded address.
@@ -195,13 +195,13 @@ class Address extends BCHJSAddress {
* bchjs.SLP.Address.isSLPAddress('mqc1tmwY2368LLGktnePzEyPAsgADxbksi')
* // false
*/
isSLPAddress(address) {
isSLPAddress (address) {
this._ensureValidAddress(address)
return bchaddrjs.isSlpAddress(address)
}
/**
* @api SLP.Address.isMainnetAddress() isMainnetAddress() - Detect if mainnet address.
* @api SLP.Address.isMainnetAddress() isMainnetAddress()
* @apiName isMainnetAddress
* @apiGroup SLP
* @apiDescription Detect if mainnet address.
@@ -248,14 +248,14 @@ class Address extends BCHJSAddress {
* bchjs.SLP.Address.isMainnetAddress('mqc1tmwY2368LLGktnePzEyPAsgADxbksi')
* // false
*/
isMainnetAddress(address) {
isMainnetAddress (address) {
this._ensureValidAddress(address)
const cashaddr = bchaddrjs.toCashAddress(address)
return bchAddress.isMainnetAddress(cashaddr)
}
/**
* @api SLP.Address.isTestnetAddress() isTestnetAddress() - Detect if testnet address.
* @api SLP.Address.isTestnetAddress() isTestnetAddress()
* @apiName isTestnetAddress
* @apiGroup SLP
* @apiDescription Detect if testnet address.
@@ -301,13 +301,14 @@ class Address extends BCHJSAddress {
* bchjs.SLP.Address.isTestnetAddress('mqc1tmwY2368LLGktnePzEyPAsgADxbksi')
* // true
*/
isTestnetAddress(address) {
isTestnetAddress (address) {
this._ensureValidAddress(address)
const cashAddr = bchaddrjs.toCashAddress(address)
return bchAddress.isTestnetAddress(cashAddr)
}
/**
* @api SLP.Address.isP2PKHAddress() isP2PKHAddress() - Detect if p2pkh address.
* @api SLP.Address.isP2PKHAddress() isP2PKHAddress()
* @apiName isP2PKHAddress
* @apiGroup SLP
* @apiDescription Detect if p2pkh address.
@@ -353,13 +354,14 @@ class Address extends BCHJSAddress {
* bchjs.SLP.Address.isP2PKHAddress('mqc1tmwY2368LLGktnePzEyPAsgADxbksi')
* // true
*/
isP2PKHAddress(address) {
isP2PKHAddress (address) {
this._ensureValidAddress(address)
const cashAddr = bchaddrjs.toCashAddress(address)
return bchAddress.isP2PKHAddress(cashAddr)
}
/**
* @api SLP.Address.isP2SHAddress() isP2SHAddress() - Detect if p2sh address.
* @api SLP.Address.isP2SHAddress() isP2SHAddress()
* @apiName isP2SHAddress
* @apiGroup SLP
* @apiDescription Detect if p2sh address.
@@ -405,13 +407,14 @@ class Address extends BCHJSAddress {
* bchjs.SLP.Address.isP2SHAddress('mqc1tmwY2368LLGktnePzEyPAsgADxbksi')
* // false
*/
isP2SHAddress(address) {
isP2SHAddress (address) {
this._ensureValidAddress(address)
const cashAddr = bchaddrjs.toCashAddress(address)
return bchAddress.isP2SHAddress(cashAddr)
}
/**
* @api SLP.Address.detectAddressFormat() detectAddressFormat() - Detect address format.
* @api SLP.Address.detectAddressFormat() detectAddressFormat()
* @apiName detectAddressFormat
* @apiGroup SLP
* @apiDescription Detect address format.
@@ -457,14 +460,15 @@ class Address extends BCHJSAddress {
* bchjs.SLP.Address.detectAddressFormat('mqc1tmwY2368LLGktnePzEyPAsgADxbksi')
* // legacy
*/
detectAddressFormat(address) {
detectAddressFormat (address) {
this._ensureValidAddress(address)
if (bchaddrjs.isSlpAddress(address)) return "slpaddr"
if (bchaddrjs.isSlpAddress(address)) return 'slpaddr'
return bchAddress.detectAddressFormat(address)
}
/**
* @api SLP.Address.detectAddressNetwork() detectAddressNetwork() - Detect address network.
* @api SLP.Address.detectAddressNetwork() detectAddressNetwork()
* @apiName detectAddressNetwork
* @apiGroup SLP
* @apiDescription Detect address network.
@@ -510,13 +514,14 @@ class Address extends BCHJSAddress {
* bchjs.SLP.Address.detectAddressNetwork('mqc1tmwY2368LLGktnePzEyPAsgADxbksi')
* // testnet
*/
detectAddressNetwork(address) {
detectAddressNetwork (address) {
this._ensureValidAddress(address)
const cashAddr = bchaddrjs.toCashAddress(address)
return bchAddress.detectAddressNetwork(cashAddr)
}
/**
* @api SLP.Address.detectAddressType() detectAddressType() - Detect address type.
* @api SLP.Address.detectAddressType() detectAddressType()
* @apiName detectAddressType
* @apiGroup SLP
* @apiDescription Detect address type.
@@ -562,11 +567,12 @@ class Address extends BCHJSAddress {
* bchjs.SLP.Address.detectAddressType('mqc1tmwY2368LLGktnePzEyPAsgADxbksi');
* // p2pkh
*/
detectAddressType(address) {
detectAddressType (address) {
this._ensureValidAddress(address)
const cashAddr = bchaddrjs.toCashAddress(address)
return bchAddress.detectAddressType(cashAddr)
}
/*
async details(address) {
let tmpBITBOX
@@ -644,7 +650,7 @@ class Address extends BCHJSAddress {
return tmpBITBOX.Address.transactions(address)
}
*/
_ensureValidAddress(address) {
_ensureValidAddress (address) {
try {
bchaddrjs.toCashAddress(address)
} catch (err) {
+6 -6
View File
@@ -1,9 +1,9 @@
//const BCHJS = require("../bch-js")
//const bchjs = new BCHJS()
// const BCHJS = require("../bch-js")
// const bchjs = new BCHJS()
const BCHJSECPair = require("../ecpair")
const BCHJSECPair = require('../ecpair')
const bchaddrjs = require("bchaddrjs-slp")
const bchaddrjs = require('bchaddrjs-slp')
class ECPair extends BCHJSECPair {
/*
@@ -13,7 +13,7 @@ class ECPair extends BCHJSECPair {
}
*/
/**
* @api SLP.ECPair.toSLPAddress() toSLPAddress() - Get slp address of ECPair.
* @api SLP.ECPair.toSLPAddress() toSLPAddress()
* @apiName toSLPAddress
* @apiGroup SLP
* @apiDescription Get slp address of ECPair.
@@ -25,7 +25,7 @@ class ECPair extends BCHJSECPair {
* bchjs.SLP.ECPair.toSLPAddress(ecpair);
* // slptest:qq835u5srlcqwrtwt6xm4efwan30fxg9hcqag6fk03
*/
static toSLPAddress(ecpair) {
static toSLPAddress (ecpair) {
const slpAddress = bchaddrjs.toSlpAddress(this.toCashAddress(ecpair))
return slpAddress
}
+60 -54
View File
@@ -8,17 +8,17 @@
(Parent) token.
*/
const Address = require("./address")
const Address = require('./address')
const BigNumber = require("bignumber.js")
const slpMdm = require("slp-mdm")
// const BigNumber = require('bignumber.js')
const slpMdm = require('slp-mdm')
// const addy = new Address()
let addy
const TransactionBuilder = require("../transaction-builder")
const TransactionBuilder = require('../transaction-builder')
class TokenType1 {
constructor(config) {
constructor (config) {
this.restURL = config.restURL
addy = new Address(config)
@@ -59,12 +59,12 @@ class TokenType1 {
* // https://github.com/Permissionless-Software-Foundation/bch-js-examples/tree/master/applications/slp/nft
*
*/
newNFTGroupOpReturn(configObj) {
newNFTGroupOpReturn (configObj) {
try {
// TODO: Add input validation.
// Prevent error if user fails to add the document hash.
if (!configObj.documentHash) configObj.documentHash = ""
if (!configObj.documentHash) configObj.documentHash = ''
// If mint baton is not specified, then replace it with null.
if (!configObj.mintBatonVout) configObj.mintBatonVout = null
@@ -81,7 +81,7 @@ class TokenType1 {
return script
} catch (err) {
console.log(`Error in generateNFTParentOpReturn()`)
console.log('Error in generateNFTParentOpReturn()')
throw err
}
}
@@ -130,43 +130,47 @@ class TokenType1 {
* // See additional code here:
* // https://github.com/Permissionless-Software-Foundation/bch-js-examples/tree/master/applications/slp/nft
*/
mintNFTGroupOpReturn(tokenUtxos, mintQty, destroyBaton = false) {
try {
// Throw error if input is not an array.
if (!Array.isArray(tokenUtxos))
throw new Error(`tokenUtxos must be an array.`)
// Loop through the tokenUtxos array and find the minting baton.
let mintBatonUtxo
for (let i = 0; i < tokenUtxos.length; i++) {
if (tokenUtxos[i].utxoType === "minting-baton")
mintBatonUtxo = tokenUtxos[i]
}
// Throw an error if the minting baton could not be found.
if (!mintBatonUtxo)
throw new Error(`Minting baton could not be found in tokenUtxos array.`)
const tokenId = mintBatonUtxo.tokenId
if (!tokenId)
throw new Error(`tokenId property not found in mint-baton UTXO.`)
// Signal that the baton should be passed or detroyed.
let batonVout = 2
if (destroyBaton) batonVout = null
const script = slpMdm.NFT1.Group.mint(
tokenId,
batonVout,
new slpMdm.BN(mintQty)
)
return script
} catch (err) {
// console.log(`Error in generateMintOpReturn()`)
throw err
mintNFTGroupOpReturn (tokenUtxos, mintQty, destroyBaton = false) {
// try {
// Throw error if input is not an array.
if (!Array.isArray(tokenUtxos)) {
throw new Error('tokenUtxos must be an array.')
}
// Loop through the tokenUtxos array and find the minting baton.
let mintBatonUtxo
for (let i = 0; i < tokenUtxos.length; i++) {
if (tokenUtxos[i].utxoType === 'minting-baton') {
mintBatonUtxo = tokenUtxos[i]
}
}
// Throw an error if the minting baton could not be found.
if (!mintBatonUtxo) {
throw new Error('Minting baton could not be found in tokenUtxos array.')
}
const tokenId = mintBatonUtxo.tokenId
if (!tokenId) {
throw new Error('tokenId property not found in mint-baton UTXO.')
}
// Signal that the baton should be passed or detroyed.
let batonVout = 2
if (destroyBaton) batonVout = null
const script = slpMdm.NFT1.Group.mint(
tokenId,
batonVout,
new slpMdm.BN(mintQty)
)
return script
// } catch (err) {
// // console.log(`Error in generateMintOpReturn()`)
// throw err
// }
}
/**
@@ -200,12 +204,12 @@ class TokenType1 {
* // https://github.com/Permissionless-Software-Foundation/bch-js-examples/tree/master/applications/slp/nft
*
*/
generateNFTChildGenesisOpReturn(configObj) {
generateNFTChildGenesisOpReturn (configObj) {
try {
// TODO: Add input validation.
// Prevent error if user fails to add the document hash.
if (!configObj.documentHash) configObj.documentHash = ""
if (!configObj.documentHash) configObj.documentHash = ''
// If mint baton is not specified, then replace it with null.
if (!configObj.mintBatonVout) configObj.mintBatonVout = null
@@ -217,12 +221,12 @@ class TokenType1 {
configObj.documentHash,
0,
configObj.mintBatonVout,
new slpMdm.BN("1")
new slpMdm.BN('1')
)
return script
} catch (err) {
console.log(`Error in generateNFTChildGenesisOpReturn()`)
console.log('Error in generateNFTChildGenesisOpReturn()')
throw err
}
}
@@ -270,7 +274,7 @@ class TokenType1 {
* // See additional code here:
* // https://github.com/Permissionless-Software-Foundation/bch-js-examples/tree/master/applications/slp/nft
*/
generateNFTChildSendOpReturn(tokenUtxos, sendQty) {
generateNFTChildSendOpReturn (tokenUtxos, sendQty) {
try {
// TODO: Add input validation.
@@ -278,8 +282,9 @@ class TokenType1 {
// Calculate the total amount of tokens owned by the wallet.
let totalTokens = 0
for (let i = 0; i < tokenUtxos.length; i++)
for (let i = 0; i < tokenUtxos.length; i++) {
totalTokens += tokenUtxos[i].tokenQty
}
const change = totalTokens - sendQty
@@ -312,7 +317,7 @@ class TokenType1 {
return { script, outputs }
} catch (err) {
console.log(`Error in generateNFTChildSendOpReturn()`)
console.log('Error in generateNFTChildSendOpReturn()')
throw err
}
}
@@ -360,7 +365,7 @@ class TokenType1 {
* // See additional code here:
* // https://github.com/Permissionless-Software-Foundation/bch-js-examples/tree/master/applications/slp/nft
*/
generateNFTGroupSendOpReturn(tokenUtxos, sendQty) {
generateNFTGroupSendOpReturn (tokenUtxos, sendQty) {
try {
// TODO: Add input validation.
@@ -368,8 +373,9 @@ class TokenType1 {
// Calculate the total amount of tokens owned by the wallet.
let totalTokens = 0
for (let i = 0; i < tokenUtxos.length; i++)
for (let i = 0; i < tokenUtxos.length; i++) {
totalTokens += tokenUtxos[i].tokenQty
}
const change = totalTokens - sendQty
@@ -402,7 +408,7 @@ class TokenType1 {
return { script, outputs }
} catch (err) {
console.log(`Error in generateNFTGroupSendOpReturn()`)
console.log('Error in generateNFTGroupSendOpReturn()')
throw err
}
}
+27 -18
View File
@@ -7,33 +7,42 @@
// imports
// require deps
//const BCHJS = require("../bch-js")
const Address = require("./address")
const ECPair = require("./ecpair")
// const BCHJS = require("../bch-js")
const Address = require('./address')
const ECPair = require('./ecpair')
// const HDNode = require("./hdnode")
const TokenType1 = require("./tokentype1")
const NFT1 = require("./nft1")
const Utils = require("./utils")
const TokenType1 = require('./tokentype1')
const NFT1 = require('./nft1')
const Utils = require('./utils')
// SLP is a superset of BITBOX
class SLP {
constructor(config) {
const tmp = {}
if (!config || !config.restURL) {
tmp.restURL = `https://api.fullstack.cash/v3/`
constructor (config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
tmp.restURL = config.restURL
tmp.apiToken = config.apiToken
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
}
}
this.restURL = tmp.restURL
this.apiToken = tmp.apiToken
this.Address = new Address(tmp)
this.Address = new Address(config)
this.ECPair = ECPair
this.TokenType1 = new TokenType1(tmp)
this.TokenType1 = new TokenType1(config)
this.NFT1 = new NFT1(this.restURL)
this.Utils = new Utils(tmp)
this.Utils = new Utils(config)
}
}
+89 -54
View File
@@ -1,34 +1,49 @@
//const BCHJS = require("../bch-js")
//const bchjs = new BCHJS()
/*
This library handles the OP_RETURN of SLP TokenType1 transactions.
*/
const Address = require("./address")
const Script = require("../script")
// const BCHJS = require("../bch-js")
// const bchjs = new BCHJS()
const BigNumber = require("bignumber.js")
const slpMdm = require("slp-mdm")
const axios = require("axios")
const Address = require('./address')
const Script = require('../script')
const BigNumber = require('bignumber.js')
const slpMdm = require('slp-mdm')
const axios = require('axios')
// const addy = new Address()
let addy
const TransactionBuilder = require("../transaction-builder")
const TransactionBuilder = require('../transaction-builder')
let _this // local global
class TokenType1 {
constructor(config) {
constructor (config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
}
}
addy = new Address(config)
this.Script = new Script()
this.axios = axios
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
}
// Instantiate the transaction builder.
TransactionBuilder.setAddress(addy)
@@ -77,17 +92,21 @@ class TokenType1 {
* // See additional code here:
* // https://github.com/Permissionless-Software-Foundation/bch-js-examples/blob/master/applications/slp/send-token/send-token.js
*/
generateSendOpReturn(tokenUtxos, sendQty) {
generateSendOpReturn (tokenUtxos, sendQty) {
try {
const tokenId = tokenUtxos[0].tokenId
const decimals = tokenUtxos[0].decimals
// Calculate the total amount of tokens owned by the wallet.
let totalTokens = 0
for (let i = 0; i < tokenUtxos.length; i++)
totalTokens += tokenUtxos[i].tokenQty
const sendQtyBig = new BigNumber(sendQty).times(10 ** decimals)
const change = totalTokens - sendQty
// Calculate the total amount of tokens owned by the wallet.
const totalTokens = tokenUtxos.reduce(
(tot, txo) =>
tot.plus(new BigNumber(txo.tokenQty).times(10 ** decimals)),
new BigNumber(0)
)
const change = totalTokens.minus(sendQtyBig)
// console.log(`change: ${change}`)
let script
@@ -98,19 +117,23 @@ class TokenType1 {
outputs = 2
// Convert the send quantity to the format expected by slp-mdm.
let baseQty = new BigNumber(sendQty).times(10 ** decimals)
baseQty = baseQty.absoluteValue()
baseQty = Math.floor(baseQty)
baseQty = baseQty.toString()
const baseQty = sendQtyBig.toString()
// console.log(`baseQty: `, baseQty)
// Convert the change quantity to the format expected by slp-mdm.
let baseChange = new BigNumber(change).times(10 ** decimals)
baseChange = baseChange.absoluteValue()
baseChange = Math.floor(baseChange)
baseChange = baseChange.toString()
const baseChange = change.toString()
// console.log(`baseChange: `, baseChange)
// Check for potential burns
const outputQty = new BigNumber(baseChange).plus(
new BigNumber(baseQty)
)
const inputQty = new BigNumber(totalTokens)
const tokenOutputDelta = outputQty.minus(inputQty).toString() !== '0'
if (tokenOutputDelta) {
throw new Error('Token transaction inputs do not match outputs, cannot send transaction')
}
// Generate the OP_RETURN as a Buffer.
script = slpMdm.TokenType1.send(tokenId, [
new slpMdm.BN(baseQty),
@@ -120,13 +143,17 @@ class TokenType1 {
// Corner case, when there is no token change to send back.
} else {
let baseQty = new BigNumber(sendQty).times(10 ** decimals)
baseQty = baseQty.absoluteValue()
baseQty = Math.floor(baseQty)
baseQty = baseQty.toString()
const baseQty = sendQtyBig.toString()
// console.log(`baseQty: `, baseQty)
// console.log(`baseQty: ${baseQty.toString()}`)
// Check for potential burns
const noChangeOutputQty = new BigNumber(baseQty)
const noChangeInputQty = new BigNumber(totalTokens)
const tokenSingleOutputError =
noChangeOutputQty.minus(noChangeInputQty).toString() !== '0'
if (tokenSingleOutputError) {
throw new Error('Token transaction inputs do not match outputs, cannot send transaction')
}
// Generate the OP_RETURN as a Buffer.
script = slpMdm.TokenType1.send(tokenId, [new slpMdm.BN(baseQty)])
@@ -134,7 +161,7 @@ class TokenType1 {
return { script, outputs }
} catch (err) {
console.log(`Error in generateSendOpReturn()`)
console.log('Error in generateSendOpReturn()')
throw err
}
}
@@ -185,15 +212,16 @@ class TokenType1 {
* // https://github.com/Permissionless-Software-Foundation/bch-js-examples/blob/master/applications/slp/burn-tokens/burn-tokens.js
*
*/
generateBurnOpReturn(tokenUtxos, burnQty) {
generateBurnOpReturn (tokenUtxos, burnQty) {
try {
const tokenId = tokenUtxos[0].tokenId
const decimals = tokenUtxos[0].decimals
// Calculate the total amount of tokens owned by the wallet.
let totalTokens = 0
for (let i = 0; i < tokenUtxos.length; i++)
for (let i = 0; i < tokenUtxos.length; i++) {
totalTokens += tokenUtxos[i].tokenQty
}
const remainder = totalTokens - burnQty
@@ -209,7 +237,7 @@ class TokenType1 {
return script
} catch (err) {
console.log(`Error in generateBurnOpReturn()`)
console.log('Error in generateBurnOpReturn()')
throw err
}
}
@@ -248,7 +276,7 @@ class TokenType1 {
* // https://github.com/Permissionless-Software-Foundation/bch-js-examples/blob/master/applications/slp/create-token/create-token.js
*
*/
generateGenesisOpReturn(configObj) {
generateGenesisOpReturn (configObj) {
try {
// TODO: Add input validation.
@@ -260,7 +288,7 @@ class TokenType1 {
baseQty = baseQty.toString()
// Prevent error if user fails to add the document hash.
if (!configObj.documentHash) configObj.documentHash = ""
if (!configObj.documentHash) configObj.documentHash = ''
// If mint baton is not specified, then replace it with null.
if (!configObj.mintBatonVout) configObj.mintBatonVout = null
@@ -277,7 +305,7 @@ class TokenType1 {
return script
} catch (err) {
console.log(`Error in generateGenesisOpReturn()`)
console.log('Error in generateGenesisOpReturn()')
throw err
}
}
@@ -328,30 +356,37 @@ class TokenType1 {
* // See additional code here:
* // https://github.com/Permissionless-Software-Foundation/bch-js-examples/blob/master/applications/slp/mint-token/mint-token.js
*/
generateMintOpReturn(tokenUtxos, mintQty, destroyBaton = false) {
generateMintOpReturn (tokenUtxos, mintQty, destroyBaton = false) {
try {
// Throw error if input is not an array.
if (!Array.isArray(tokenUtxos))
throw new Error(`tokenUtxos must be an array.`)
if (!Array.isArray(tokenUtxos)) {
throw new Error('tokenUtxos must be an array.')
}
// Loop through the tokenUtxos array and find the minting baton.
let mintBatonUtxo
for (let i = 0; i < tokenUtxos.length; i++) {
if (tokenUtxos[i].utxoType === "minting-baton")
if (tokenUtxos[i].utxoType === 'minting-baton') {
mintBatonUtxo = tokenUtxos[i]
}
}
// Throw an error if the minting baton could not be found.
if (!mintBatonUtxo)
throw new Error(`Minting baton could not be found in tokenUtxos array.`)
if (!mintBatonUtxo) {
throw new Error(
'Minting baton could not be found in tokenUtxos array.'
)
}
const tokenId = mintBatonUtxo.tokenId
const decimals = mintBatonUtxo.decimals
if (!tokenId)
throw new Error(`tokenId property not found in mint-baton UTXO.`)
if (!decimals)
throw new Error(`decimals property not found in mint-baton UTXO.`)
if (!tokenId) {
throw new Error('tokenId property not found in mint-baton UTXO.')
}
if (!decimals) {
throw new Error('decimals property not found in mint-baton UTXO.')
}
let baseQty = new BigNumber(mintQty).times(10 ** decimals)
baseQty = baseQty.absoluteValue()
@@ -370,7 +405,7 @@ class TokenType1 {
return script
} catch (err) {
// console.log(`Error in generateMintOpReturn()`)
console.log('Error in generateMintOpReturn()')
throw err
}
}
@@ -402,7 +437,7 @@ class TokenType1 {
* "outputs": 2
* }
*/
async getHexOpReturn(tokenUtxos, sendQty) {
async getHexOpReturn (tokenUtxos, sendQty) {
try {
// TODO: Add input filtering.
@@ -426,7 +461,7 @@ class TokenType1 {
return slpSendObj
} catch (err) {
console.log(err)
console.log('Error in getHexOpReturn()')
throw err
}
}
+753 -122
View File
File diff suppressed because it is too large Load Diff
+7 -8
View File
@@ -1,15 +1,15 @@
const io = require("socket.io-client")
const io = require('socket.io-client')
class Socket {
constructor(config = {}) {
if (typeof config === "string") {
constructor (config = {}) {
if (typeof config === 'string') {
// TODO remove this check in v2.0
this.socket = io(`${config}`)
} else {
if (config.restURL) {
this.socket = io(`${config.restURL}`)
} else {
const restURL = "https://rest.bitcoin.com"
const restURL = 'https://rest.bitcoin.com'
this.socket = io(`${restURL}`)
}
@@ -17,12 +17,11 @@ class Socket {
}
}
listen(endpoint, cb) {
listen (endpoint, cb) {
this.socket.emit(endpoint)
if (endpoint === "blocks") this.socket.on("blocks", msg => cb(msg))
else if (endpoint === "transactions")
this.socket.on("transactions", msg => cb(msg))
if (endpoint === 'blocks') this.socket.on('blocks', msg => cb(msg))
else if (endpoint === 'transactions') { this.socket.on('transactions', msg => cb(msg)) }
}
}
+24 -22
View File
@@ -1,18 +1,16 @@
const Bitcoin = require("bitcoincashjs-lib")
const coininfo = require("coininfo")
const bip66 = require("bip66")
const bip68 = require("bc-bip68")
const Bitcoin = require('@psf/bitcoincashjs-lib')
const coininfo = require('@psf/coininfo')
const bip66 = require('bip66')
const bip68 = require('bc-bip68')
class TransactionBuilder {
static setAddress(address) {
static setAddress (address) {
TransactionBuilder._address = address
}
constructor(network = "mainnet") {
constructor (network = 'mainnet') {
let bitcoincash
if (network === "bitcoincash" || network === "mainnet")
bitcoincash = coininfo.bitcoincash.main
else bitcoincash = coininfo.bitcoincash.test
if (network === 'bitcoincash' || network === 'mainnet') { bitcoincash = coininfo.bitcoincash.main } else bitcoincash = coininfo.bitcoincash.test
const bitcoincashBitcoinJSLib = bitcoincash.toBitcoinJS()
this.transaction = new Bitcoin.TransactionBuilder(bitcoincashBitcoinJSLib)
@@ -33,11 +31,11 @@ class TransactionBuilder {
this.bip66 = bip66
this.bip68 = bip68
this.p2shInput = false
this.tx
// this.tx
}
/**
* @api Transaction-Builder.addInput() addInput() - Add input to transaction.
* @api Transaction-Builder.addInput() addInput()
* @apiName AddInput
* @apiGroup TransactionBuilder
* @apiDescription Add input to transaction.
@@ -48,25 +46,26 @@ class TransactionBuilder {
* // add input with txid and index of vout
* transactionBuilder.addInput(txid, 0);
*/
addInput(txHash, vout, sequence = this.DEFAULT_SEQUENCE, prevOutScript) {
addInput (txHash, vout, sequence = this.DEFAULT_SEQUENCE, prevOutScript) {
this.transaction.addInput(txHash, vout, sequence, prevOutScript)
}
addInputScript(vout, script) {
addInputScript (vout, script) {
this.tx = this.transaction.buildIncomplete()
this.tx.setInputScript(vout, script)
this.p2shInput = true
}
addInputScripts(scripts) {
addInputScripts (scripts) {
this.tx = this.transaction.buildIncomplete()
scripts.forEach(script => {
this.tx.setInputScript(script.vout, script.script)
})
this.p2shInput = true
}
/**
* @api Transaction-Builder.addOutput() addOutput() - Add output to transaction.
* @api Transaction-Builder.addOutput() addOutput()
* @apiName AddOutput
* @apiGroup TransactionBuilder
* @apiDescription Add output to transaction.
@@ -79,7 +78,7 @@ class TransactionBuilder {
* // add output w/ address and amount to send
* transactionBuilder.addOutput('bitcoincash:qpuax2tarq33f86wccwlx8ge7tad2wgvqgjqlwshpw', sendAmount);
*/
addOutput(scriptPubKey, amount) {
addOutput (scriptPubKey, amount) {
try {
this.transaction.addOutput(
TransactionBuilder._address.toLegacyAddress(scriptPubKey),
@@ -89,8 +88,9 @@ class TransactionBuilder {
this.transaction.addOutput(scriptPubKey, amount)
}
}
/**
* @api Transaction-Builder.setLockTime() setLockTime() - Set locktime.
* @api Transaction-Builder.setLockTime() setLockTime()
* @apiName SetLockTime
* @apiGroup TransactionBuilder
* @apiDescription Set locktime.
@@ -104,11 +104,12 @@ class TransactionBuilder {
* transactionBuilder.addOutput('bitcoincash:qpuax2tarq33f86wccwlx8ge7tad2wgvqgjqlwshpw', sendAmount);
* transactionBuilder.setLockTime(50000)
*/
setLockTime(locktime) {
setLockTime (locktime) {
this.transaction.setLockTime(locktime)
}
/**
* @api Transaction-Builder.sign() sign() - Sign transaction..
* @api Transaction-Builder.sign() sign()
* @apiName Sign.
* @apiGroup TransactionBuilder
* @apiDescription Sign transaction. It creates the unlocking script needed to spend an input. Each input has its own script and thus 'sign' must be called for each input even if the keyPair is the same..
@@ -124,7 +125,7 @@ class TransactionBuilder {
* // sign w/ keyPair
* transactionBuilder.sign(0, keyPair, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount, transactionBuilder.signatureAlgorithms.SCHNORR);
*/
sign(
sign (
vin,
keyPair,
redeemScript,
@@ -144,8 +145,9 @@ class TransactionBuilder {
signatureAlgorithm
)
}
/**
* @api Transaction-Builder.build() build() - Build transaction.
* @api Transaction-Builder.build() build()
* @apiName Build.
* @apiGroup TransactionBuilder
* @apiDescription Build transaction.
@@ -154,7 +156,7 @@ class TransactionBuilder {
* // build tx
* let tx = bchjs.transactionBuilder.build();
*/
build() {
build () {
if (this.p2shInput === true) return this.tx
return this.transaction.build()
+21 -11
View File
@@ -1,16 +1,26 @@
const axios = require("axios")
const axios = require('axios')
let _this
class Util {
constructor(config) {
constructor (config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
}
}
@@ -18,7 +28,7 @@ class Util {
}
/**
* @api util.validateAddress() validateAddress() - Get information about the given bitcoin address.
* @api util.validateAddress() validateAddress()
* @apiName Validate Address.
* @apiGroup Util
* @apiDescription Return information about the given bitcoin address.
@@ -62,10 +72,10 @@ class Util {
* // iscompressed: true,
* // account: 'Test' }]
*/
async validateAddress(address) {
async validateAddress (address) {
try {
// Single block
if (typeof address === "string") {
if (typeof address === 'string') {
const response = await axios.get(
`${this.restURL}util/validateAddress/${address}`,
_this.axiosOptions
@@ -75,7 +85,7 @@ class Util {
// Array of blocks.
} else if (Array.isArray(address)) {
const options = {
method: "POST",
method: 'POST',
url: `${this.restURL}util/validateAddress`,
data: {
addresses: address
@@ -89,7 +99,7 @@ class Util {
return response.data
}
throw new Error(`Input must be a string or array of strings.`)
throw new Error('Input must be a string or array of strings.')
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
-77
View File
@@ -1,77 +0,0 @@
// import BCHWalletBridge from "bch-wallet-bridge.js"
class Wallet {
constructor(walletProvider) {
// this.bchWalletBridge = new BCHWalletBridge(walletProvider)
}
setWalletProvider(walletProvider) {
this.bchWalletBridge.walletProvider = walletProvider
}
getAddress(changeType, index, dAppId) {
return this.bchWalletBridge.getAddress(changeType, index, dAppId)
}
getAddressIndex(changeType, dAppId) {
return this.bchWalletBridge.getAddressIndex(changeType, dAppId)
}
getAddresses(changeType, startIndex, size, dAppId) {
return this.bchWalletBridge.getAddresses(
changeType,
startIndex,
size,
dAppId
)
}
getRedeemScript(p2shAddress, dAppId) {
return this.bchWalletBridge.getRedeemScript(p2shAddress, dAppId)
}
getRedeemScripts(dAppId) {
return this.bchWalletBridge.getRedeemScripts(dAppId)
}
addRedeemScript(redeemScript, dAppId) {
return this.bchWalletBridge.addRedeemScript(redeemScript, dAppId)
}
getUtxos(dAppId) {
return this.bchWalletBridge.getUtxos(dAppId)
}
getBalance(dAppId) {
return this.bchWalletBridge.getBalance(dAppId)
}
sign(address, dataToSign) {
return this.bchWalletBridge.sign(address, dataToSign)
}
buildTransaction(outputs, dAppId) {
return this.bchWalletBridge.buildTransaction(outputs, dAppId)
}
getProtocolVersion() {
return this.bchWalletBridge.getProtocolVersion()
}
getNetwork() {
return this.bchWalletBridge.getNetwork()
}
getFeePerByte() {
return this.bchWalletBridge.getFeePerByte()
}
getDefaultDAppId() {
return this.bchWalletBridge.getDefaultDAppId()
}
setDefaultDAppId(dAppId) {
return this.bchWalletBridge.setDefaultDAppId(dAppId)
}
}
module.exports = Wallet
+7 -7
View File
@@ -2,17 +2,17 @@
A Mocha test file for running end-to-end (e2e) tests.
*/
//const mocha = require("mocha")
const assert = require("chai").assert
// const mocha = require("mocha")
const assert = require('chai').assert
const sendToken = require("./send-token/send-token")
const sendToken = require('./send-token/send-token')
describe("#end-to-end tests", () => {
describe("#send-tokens", () => {
it("SLPDB should update balances in less than 10 seconds", async () => {
describe('#end-to-end tests', () => {
describe('#send-tokens', () => {
it('SLPDB should update balances in less than 10 seconds', async () => {
const result = await sendToken.sendTokenTest()
assert(result, true, "True expected if test passed successfully.")
assert(result, true, 'True expected if test passed successfully.')
})
})
})
+5 -5
View File
@@ -3,15 +3,15 @@
IPFS is working.
*/
process.env.IPFS_API = `http://localhost:5001`
process.env.IPFS_API = 'http://localhost:5001'
// process.env.IPFS_API = `https://ipfs-api.fullstack.cash`
const BCHJS = require("../../../src/bch-js")
const BCHJS = require('../../../src/bch-js')
const bchjs = new BCHJS()
describe(`#IPFS`, () => {
it("should upload a file to the server", async () => {
const path = `${__dirname}/ipfs-e2e.js`
describe('#IPFS', () => {
it('should upload a file to the server', async () => {
const path = `${__dirname.toString()}/ipfs-e2e.js`
const fileModel = await bchjs.IPFS.createFileModel(path)
console.log(`fileModel: ${JSON.stringify(fileModel, null, 2)}`)
+23 -16
View File
@@ -4,38 +4,45 @@
To Run Test:
- Update the RESTURL for bch-api you want to test against.
- Ensure the BCHJSTOKEN environment variable is set to an empty string.
- If working with bch-api locally, eliminate the local IP address from the
whitelist in bch-api/src/middleware/route-ratelimit.js
Run this test with this command:
mocha --timeout=30000 anonymous-rate-limits.js
*/
const assert = require("chai").assert
const assert = require('chai').assert
const RESTURL = `https://api.fullstack.cash/v3/`
// const RESTURL = `http://localhost:3000/v3/`
// const RESTURL = `https://abc.fullstack.cash/v4/`
const RESTURL = 'https://bchn.fullstack.cash/v4/'
// const RESTURL = `http://localhost:3000/v4/`
const BCHJS = require("../../../src/bch-js")
const BCHJS = require('../../../src/bch-js')
const bchjs = new BCHJS({ restURL: RESTURL })
describe("#anonymous rate limits", () => {
it("should allow an anonymous call to a full node endpoint", async () => {
describe('#anonymous rate limits', () => {
it('should allow an anonymous call to a full node endpoint', async () => {
const result = await bchjs.Control.getNetworkInfo()
assert.property(result, "version")
assert.property(result, 'version')
}).timeout(5000)
it("should allow an anonymous call to an indexer", async () => {
const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
const result = await bchjs.Blockbook.balance(addr)
it('should allow an anonymous call to an indexer', async () => {
const addr = 'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf'
const result = await bchjs.Electrumx.balance(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "balance")
assert.property(result, 'balance')
}).timeout(5000)
it("should throw error when rate limit exceeded", async () => {
it('should throw error when rate limit exceeded', async () => {
try {
for (let i = 0; i < 5; i++) await bchjs.Control.getNetworkInfo()
for (let i = 0; i < 35; i++) await bchjs.Control.getNetworkInfo()
assert.equal(true, false, "unexpected result")
assert.fail('Unexpected result')
} catch (err) {
assert.include(err.error, "Too many requests")
assert.include(err.error, 'Too many requests')
}
}).timeout(5000)
}).timeout(20000)
})
@@ -0,0 +1,56 @@
/*
Mocha test that verifies that the bch-api server is enforcing its
access rules for Basic Authentication.
To Run Test:
- Update the restURL for bch-api you want to test against.
- Update the PRO_PASS value with a current PRO_PASSES string used by bch-api.
*/
const assert = require('chai').assert
const PRO_PASS = 'testpassword'
const BCHJS = require('../../../src/bch-js')
const bchjs = new BCHJS({
// restURL: `https://bchn.fullstack.cash/v4/`,
restURL: 'https://abc.fullstack.cash/v4/',
// restURL: `http://localhost:3000/v4/`,
authPass: PRO_PASS
})
describe('#Basic Authentication rate limits', () => {
it('should allow more than 20 RPM to full node', async () => {
for (let i = 0; i < 22; i++) {
const result = await bchjs.Control.getNetworkInfo()
if (i === 5) {
// console.log(`validating 5th call: ${i}`)
assert.property(result, 'version', 'more than 3 calls allowed')
}
if (i === 15) {
// console.log(`validating 5th call: ${i}`)
assert.property(result, 'version', 'more than 10 calls allowed')
}
}
}).timeout(45000)
it('should allow more than 20 RPM to an indexer', async () => {
const addr = 'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf'
for (let i = 0; i < 22; i++) {
const result = await bchjs.Blockbook.balance(addr)
if (i === 5) {
// console.log(`validating 5th call: ${i}`)
assert.property(result, 'balance', 'more than 3 calls allowed')
}
if (i === 15) {
// console.log(`validating 5th call: ${i}`)
assert.property(result, 'balance', 'more than 10 calls allowed')
}
}
}).timeout(45000)
})
+33 -31
View File
@@ -1,4 +1,8 @@
/*
CT 11/11/2020:
There is no longer a free tier. These tests have been deprecated.
--------
Mocha test that verifies that the bch-api server is enforcing its
FREE access rules
@@ -7,72 +11,59 @@
- Update the JWT_TOKEN value with a current free-level JWT token.
*/
const assert = require("chai").assert
const assert = require('chai').assert
const JWT_TOKEN =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlODhhY2YyMDIyMWMxMDAxMmFkOTQwMSIsImVtYWlsIjoiZGVtb0BkZW1vLmNvbSIsImFwaUxldmVsIjoxMCwicmF0ZUxpbWl0IjozLCJpYXQiOjE1OTA1Mjk2NzgsImV4cCI6MTU5MzEyMTY3OH0.4q5MFDCcVx0FusivJPiEIj3w8nhFG7ZV5IhJS7faUlc"
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlODhhY2YyMDIyMWMxMDAxMmFkOTQwMSIsImVtYWlsIjoiZGVtb0BkZW1vLmNvbSIsImFwaUxldmVsIjoxMCwicmF0ZUxpbWl0IjozLCJpYXQiOjE2MDQ4NTQ2OTEsImV4cCI6MTYwNzQ0NjY5MX0.iwse0z0KDKHx9graCxcOwj6lSlfKQAb1zLhmjvygvts'
const BCHJS = require("../../../src/bch-js")
const BCHJS = require('../../../src/bch-js')
const bchjs = new BCHJS({
restURL: `https://api.fullstack.cash/v3/`,
// restURL: `http://localhost:3000/v3/`,
restURL: 'https://api.fullstack.cash/v4/',
// restURL: `http://localhost:3000/v4/`,
apiToken: JWT_TOKEN
})
describe("#free rate limits", () => {
it("should allow an free call to an indexer", async () => {
const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
describe('#free rate limits', () => {
it('should allow an free call to an indexer', async () => {
const addr = 'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf'
const result = await bchjs.Blockbook.balance(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "balance")
assert.property(result, 'balance')
}).timeout(5000)
// it("should throw error when rate limit exceeded 3 RPM for indexer endpoints", async () => {
// const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
//
// try {
// for (let i = 0; i < 5; i++) await bchjs.Blockbook.balance(addr)
//
// assert.equal(true, false, "unexpected result")
// } catch (err) {
// // console.log(`err: `, err)
// assert.include(err.error, "Too many requests")
// }
// }).timeout(10000)
it("should allow up to 10 RPM to indexer, then throw error", async () => {
it('should allow up to 10 RPM to indexer, then throw error', async () => {
try {
const addr = "bitcoincash:qrehqueqhw629p6e57994436w730t4rzasnly00ht0"
const addr = 'bitcoincash:qrehqueqhw629p6e57994436w730t4rzasnly00ht0'
for (let i = 0; i < 15; i++) {
const result = await await bchjs.Blockbook.balance(addr)
if (i === 5) {
// console.log(`validating 5th call: ${i}`)
assert.property(result, "address", "more than 3 calls allowed")
assert.property(result, 'address', 'more than 3 calls allowed')
}
}
} catch (err) {
// console.log(`err: `, err)
assert.include(
err.error,
"currently 10 requests",
"more than 10 not allowed"
'currently 10 requests',
'more than 10 not allowed'
)
assert.include(err.error, 10)
assert.notInclude(err.error, 3)
}
}).timeout(20000)
it("should allow up to 10 RPM to full node, then throw error", async () => {
it('should allow up to 10 RPM to full node, then throw error', async () => {
try {
for (let i = 0; i < 15; i++) {
const result = await bchjs.Control.getNetworkInfo()
if (i === 5) {
// console.log(`validating 5th call: ${i}`)
assert.property(result, "version", "more than 3 calls allowed")
assert.property(result, 'version', 'more than 3 calls allowed')
}
}
} catch (err) {
@@ -80,11 +71,22 @@ describe("#free rate limits", () => {
// console.log(`err: `, err)
assert.include(
err.error,
"currently 10 requests",
"more than 10 not allowed"
'currently 10 requests',
'more than 10 not allowed'
)
assert.include(err.error, 10)
assert.notInclude(err.error, 3)
}
}).timeout(20000)
it('should throw error when rate limit exceeded 20 RPM for indexer endpoints', async () => {
try {
for (let i = 0; i < 22; i++) await bchjs.Control.getNetworkInfo()
assert.fail('unexpected result')
} catch (err) {
// console.log(`err: `, err)
assert.include(err.error, 'Too many requests')
}
}).timeout(20000)
})
+38 -31
View File
@@ -1,70 +1,77 @@
/*
CT 11/11/2020:
There is no longer a free tier. These tests have been deprecated.
----
Mocha test that verifies that the bch-api server is enforcing its
full-node access rules
To Run Test:
- Update the restURL for bch-api you want to test against.
- Update the JWT_TOKEN value with a current full-node-level JWT token.
- Update the JWT_TOKEN value with a paid tier JWT token.
*/
const assert = require("chai").assert
const assert = require('chai').assert
const JWT_TOKEN =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVkYmY4MjA1YTYwODliMjliYTlhZjc1OSIsImlhdCI6MTU3MjgzMTgzOSwiZXhwIjoxNTc1NDIzODM5fQ.sFFS4AF04U2aUwmKkBIfnMQIUoygzV9UMVzzQuwctpY"
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlODhhY2JmMDIyMWMxMDAxMmFkOTNmZiIsImVtYWlsIjoiY2hyaXMudHJvdXRuZXJAZ21haWwuY29tIiwiYXBpTGV2ZWwiOjQwLCJyYXRlTGltaXQiOjMsImlhdCI6MTYwMzIyNzEwNCwiZXhwIjoxNjA1ODE5MTA0fQ.CV36grzdD36Ht3BwZGHG4XU40CVDzMRw9Ars1x1r27M'
const BCHJS = require("../../../src/bch-js")
const BCHJS = require('../../../src/bch-js')
const bchjs = new BCHJS({
restURL: `https://api.bchjs.cash/v3/`,
// restURL: `http://localhost:3000/v3/`,
// restURL: `https://bchn.fullstack.cash/v4/`,
restURL: 'https:/abc.fullstack.cash/v4/',
// restURL: `http://localhost:3000/v4/`,
apiToken: JWT_TOKEN
})
describe("#full node rate limits", () => {
it("should allow an free call to an indexer", async () => {
const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
const result = await bchjs.Blockbook.balance(addr)
describe('#full node rate limits', () => {
it('should allow an free call to an indexer', async () => {
const addr = 'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf'
const result = await bchjs.Electrumx.balance(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "balance")
assert.property(result, 'balance')
}).timeout(5000)
it("should throw error when rate limit exceeded 3 RPM for indexer endpoints", async () => {
const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
// CT 11/8/20: New rate limits make this test invalid.
// it("should throw error when rate limit exceeded 20 RPM for indexer endpoints", async () => {
// const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
//
// try {
// for (let i = 0; i < 22; i++) await bchjs.Electrumx.balance(addr)
//
// assert.fail("unexpected result")
// } catch (err) {
// // console.log(`err: `, err)
// assert.include(err.error, "Too many requests")
// }
// }).timeout(10000)
try {
for (let i = 0; i < 5; i++) await bchjs.Blockbook.balance(addr)
assert.equal(true, false, "unexpected result")
} catch (err) {
// console.log(`err: `, err)
assert.include(err.error, "Too many requests")
}
}).timeout(10000)
it("should allow more than 10 RPM to full node", async () => {
for (let i = 0; i < 20; i++) {
it('should allow more than 20 RPM to full node', async () => {
for (let i = 0; i < 22; i++) {
const result = await bchjs.Control.getNetworkInfo()
if (i === 5) {
// console.log(`validating 5th call: ${i}`)
assert.property(result, "version", "more than 3 calls allowed")
assert.property(result, 'version', 'more than 3 calls allowed')
}
if (i === 15) {
// console.log(`validating 5th call: ${i}`)
assert.property(result, "version", "more than 10 calls allowed")
assert.property(result, 'version', 'more than 10 calls allowed')
}
}
}).timeout(10000)
}).timeout(20000)
it("should throw error for more than 100 RPM to fullnode", async () => {
it('should throw error for more than 100 RPM to fullnode', async () => {
try {
console.log('This test usually doesn\'t pass, because of latency.')
for (let i = 0; i < 100; i++) await bchjs.Control.getNetworkInfo()
} catch (err) {
// console.log(`validating after 10th call`)
// console.log(`err: `, err)
assert.include(err.error, "Too many requests")
assert.include(err.error, 'Too many requests')
assert.include(err.error, 100)
}
}).timeout(30000)
}).timeout(45000)
})
+19 -18
View File
@@ -7,50 +7,51 @@
- Update the JWT_TOKEN value with a current indexer-level JWT token.
*/
const assert = require("chai").assert
const assert = require('chai').assert
const JWT_TOKEN =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlODhhY2JmMDIyMWMxMDAxMmFkOTNmZiIsImVtYWlsIjoiY2hyaXMudHJvdXRuZXJAZ21haWwuY29tIiwiYXBpTGV2ZWwiOjQwLCJyYXRlTGltaXQiOjMsImlhdCI6MTU5MDQzMjIxNywiZXhwIjoxNTkzMDI0MjE3fQ.R0Euhutd5FHCxLlSzjq1TYsGjI6iua_AguWIeLK2xCU"
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlODhhY2JmMDIyMWMxMDAxMmFkOTNmZiIsImVtYWlsIjoiY2hyaXMudHJvdXRuZXJAZ21haWwuY29tIiwiYXBpTGV2ZWwiOjQwLCJyYXRlTGltaXQiOjMsImlhdCI6MTYwMzIyNzEwNCwiZXhwIjoxNjA1ODE5MTA0fQ.CV36grzdD36Ht3BwZGHG4XU40CVDzMRw9Ars1x1r27M'
const BCHJS = require("../../../src/bch-js")
const BCHJS = require('../../../src/bch-js')
const bchjs = new BCHJS({
restURL: `https://api.fullstack.cash/v3/`,
// restURL: `http://localhost:3000/v3/`,
// restURL: `https://bchn.fullstack.cash/v4/`,
restURL: 'https://abc.fullstack.cash/v4/',
// restURL: `http://localhost:3000/v4/`,
apiToken: JWT_TOKEN
})
describe("#full node rate limits", () => {
it("should allow more than 10 RPM to full node", async () => {
for (let i = 0; i < 20; i++) {
describe('#Indexer rate limits', () => {
it('should allow more than 20 RPM to full node', async () => {
for (let i = 0; i < 22; i++) {
const result = await bchjs.Control.getNetworkInfo()
if (i === 5) {
// console.log(`validating 5th call: ${i}`)
assert.property(result, "version", "more than 3 calls allowed")
assert.property(result, 'version', 'more than 3 calls allowed')
}
if (i === 15) {
// console.log(`validating 5th call: ${i}`)
assert.property(result, "version", "more than 10 calls allowed")
assert.property(result, 'version', 'more than 10 calls allowed')
}
}
}).timeout(30000)
}).timeout(45000)
it("should allow more than 10 RPM to an indexer", async () => {
const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
it('should allow more than 20 RPM to an indexer', async () => {
const addr = 'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf'
for (let i = 0; i < 20; i++) {
const result = await bchjs.Blockbook.balance(addr)
for (let i = 0; i < 22; i++) {
const result = await bchjs.Electrumx.balance(addr)
if (i === 5) {
// console.log(`validating 5th call: ${i}`)
assert.property(result, "balance", "more than 3 calls allowed")
assert.property(result, 'balance', 'more than 3 calls allowed')
}
if (i === 15) {
// console.log(`validating 5th call: ${i}`)
assert.property(result, "balance", "more than 10 calls allowed")
assert.property(result, 'balance', 'more than 10 calls allowed')
}
}
}).timeout(30000)
}).timeout(45000)
})
@@ -13,24 +13,25 @@
*/
// Replace the address below with the address you want to send the BCH to.
const RECV_ADDR1 = `bchtest:qzfn2mly05t6fjsh5kjj0dqq0jjtct27ng089dgg05`
const RECV_ADDR2 = `bchtest:qz6yw0kqgfkknfy6jh2jvlfnkzmre3lt2u0pgcckdk`
const RECV_ADDR1 = 'bchtest:qzfn2mly05t6fjsh5kjj0dqq0jjtct27ng089dgg05'
const RECV_ADDR2 = 'bchtest:qz6yw0kqgfkknfy6jh2jvlfnkzmre3lt2u0pgcckdk'
const SATOSHIS_TO_SEND = 1000
// Instantiate BITBOX.
const bitboxLib = "../../../lib/BITBOX"
const bitboxLib = '../../../lib/BITBOX'
const BITBOXSDK = require(bitboxLib)
const BITBOX = new BITBOXSDK({ restURL: "https://trest.bitcoin.com/v2/" })
//const BITBOX = new BITBOXSDK({ restURL: "http://localhost:3000/v2/" })
const BITBOX = new BITBOXSDK({ restURL: 'https://trest.bitcoin.com/v2/' })
// const BITBOX = new BITBOXSDK({ restURL: "http://localhost:3000/v2/" })
const util = require("util")
// const util = require('util')
// Open the wallet generated with create-wallet.
let walletInfo = {}
try {
var walletInfo = require(`./wallet.json`)
walletInfo = require('./wallet.json')
} catch (err) {
console.log(
`Could not open wallet.json. Generate a wallet with create-wallet first.`
'Could not open wallet.json. Generate a wallet with create-wallet first.'
)
process.exit(0)
}
@@ -38,7 +39,7 @@ try {
const SEND_ADDR = walletInfo.cashAddress
const SEND_MNEMONIC = walletInfo.mnemonic
async function testSend() {
async function testSend () {
try {
const hex1 = await buildTx1(RECV_ADDR1)
const hex2 = await buildTx2(RECV_ADDR2)
@@ -51,15 +52,15 @@ async function testSend() {
hex2
])
console.log(`Transaction IDs: ${JSON.stringify(broadcast, null, 2)}`)
console.log(`Should return an array of TXID strings.`)
console.log('Should return an array of TXID strings.')
} catch (err) {
console.log(`Error in testSend: `, err)
console.log('Error in testSend: ', err)
}
}
testSend()
// Build a TX hex with the largest UTXO.
async function buildTx1(recAddr) {
async function buildTx1 (recAddr) {
try {
// Get the balance of the sending address.
const balance = await getBCHBalance(SEND_ADDR, false)
@@ -68,7 +69,7 @@ async function buildTx1(recAddr) {
// Exit if the balance is zero.
if (balance <= 0.0) {
console.log(`Balance of sending address is zero. Exiting.`)
console.log('Balance of sending address is zero. Exiting.')
process.exit(0)
}
@@ -77,16 +78,17 @@ async function buildTx1(recAddr) {
console.log(`Sender Legacy Address: ${SEND_ADDR_LEGACY}`)
console.log(`Receiver Legacy Address: ${RECV_ADDR_LEGACY}`)
const balance2 = await getBCHBalance(recAddr, false)
//console.log(`Balance of recieving address ${recAddr} is ${balance2} BCH.`)
// const balance2 = await getBCHBalance(recAddr, false)
// console.log(`Balance of recieving address ${recAddr} is ${balance2} BCH.`)
await getBCHBalance(recAddr, false)
const u = await BITBOX.Address.utxo(SEND_ADDR)
//console.log(`u: ${JSON.stringify(u, null, 2)}`)
// console.log(`u: ${JSON.stringify(u, null, 2)}`)
const utxo = findBiggestUtxo(u.utxos)
console.log(`utxo: ${JSON.stringify(utxo, null, 2)}`)
// instance of transaction builder
const transactionBuilder = new BITBOX.TransactionBuilder("testnet")
const transactionBuilder = new BITBOX.TransactionBuilder('testnet')
const satoshisToSend = SATOSHIS_TO_SEND
const originalAmount = utxo.satoshis
@@ -137,13 +139,13 @@ async function buildTx1(recAddr) {
return hex
} catch (err) {
console.log(`Error in buildTx().`)
console.log('Error in buildTx().')
throw err
}
}
// Build a TX hex with the SECOND largest UTXO.
async function buildTx2(recAddr) {
async function buildTx2 (recAddr) {
try {
// Get the balance of the sending address.
const balance = await getBCHBalance(SEND_ADDR, false)
@@ -152,7 +154,7 @@ async function buildTx2(recAddr) {
// Exit if the balance is zero.
if (balance <= 0.0) {
console.log(`Balance of sending address is zero. Exiting.`)
console.log('Balance of sending address is zero. Exiting.')
process.exit(0)
}
@@ -161,16 +163,17 @@ async function buildTx2(recAddr) {
console.log(`Sender Legacy Address: ${SEND_ADDR_LEGACY}`)
console.log(`Receiver Legacy Address: ${RECV_ADDR_LEGACY}`)
const balance2 = await getBCHBalance(recAddr, false)
//console.log(`Balance of recieving address ${recAddr} is ${balance2} BCH.`)
// const balance2 = await getBCHBalance(recAddr, false)
// console.log(`Balance of recieving address ${recAddr} is ${balance2} BCH.`)
await getBCHBalance(recAddr, false)
const u = await BITBOX.Address.utxo(SEND_ADDR)
//console.log(`u: ${JSON.stringify(u, null, 2)}`)
// console.log(`u: ${JSON.stringify(u, null, 2)}`)
const utxo = findNextBiggestUtxo(u.utxos)
console.log(`utxo: ${JSON.stringify(utxo, null, 2)}`)
// instance of transaction builder
const transactionBuilder = new BITBOX.TransactionBuilder("testnet")
const transactionBuilder = new BITBOX.TransactionBuilder('testnet')
const satoshisToSend = SATOSHIS_TO_SEND
const originalAmount = utxo.satoshis
@@ -221,30 +224,30 @@ async function buildTx2(recAddr) {
return hex
} catch (err) {
console.log(`Error in buildTx().`)
console.log('Error in buildTx().')
throw err
}
}
// Generate a change address from a Mnemonic of a private key.
function changeAddrFromMnemonic(mnemonic) {
function changeAddrFromMnemonic (mnemonic) {
// root seed buffer
const rootSeed = BITBOX.Mnemonic.toSeed(mnemonic)
// master HDNode
const masterHDNode = BITBOX.HDNode.fromSeed(rootSeed, "testnet")
const masterHDNode = BITBOX.HDNode.fromSeed(rootSeed, 'testnet')
// HDNode of BIP44 account
const account = BITBOX.HDNode.derivePath(masterHDNode, "m/44'/145'/0'")
// derive the first external change address HDNode which is going to spend utxo
const change = BITBOX.HDNode.derivePath(account, "0/0")
const change = BITBOX.HDNode.derivePath(account, '0/0')
return change
}
// Get the balance in BCH of a BCH address.
async function getBCHBalance(addr, verbose) {
async function getBCHBalance (addr, verbose) {
try {
const result = await BITBOX.Address.details(addr)
@@ -254,16 +257,16 @@ async function getBCHBalance(addr, verbose) {
return bchBalance.balance
} catch (err) {
console.error(`Error in getBCHBalance: `, err)
console.error('Error in getBCHBalance: ', err)
console.log(`addr: ${addr}`)
throw err
}
}
// Returns the utxo with the biggest balance from an array of utxos.
function findBiggestUtxo(utxos) {
function findBiggestUtxo (utxos) {
// Sort the utxos by the amount of satoshis, largest first.
utxos.sort(function(a, b) {
utxos.sort(function (a, b) {
return b.satoshis - a.satoshis
})
@@ -271,9 +274,9 @@ function findBiggestUtxo(utxos) {
}
// Returns the utxo with the 2nd biggest balance from an array of utxos.
function findNextBiggestUtxo(utxos) {
function findNextBiggestUtxo (utxos) {
// Sort the utxos by the amount of satoshis, largest first.
utxos.sort(function(a, b) {
utxos.sort(function (a, b) {
return b.satoshis - a.satoshis
})
@@ -13,23 +13,24 @@
*/
// Replace the address below with the address you want to send the BCH to.
const RECV_ADDR1 = `bchtest:qzfn2mly05t6fjsh5kjj0dqq0jjtct27ng089dgg05`
const RECV_ADDR1 = 'bchtest:qzfn2mly05t6fjsh5kjj0dqq0jjtct27ng089dgg05'
const SATOSHIS_TO_SEND = 1000
// Instantiate BITBOX.
const bitboxLib = "../../../lib/BITBOX"
const bitboxLib = '../../../lib/BITBOX'
const BITBOXSDK = require(bitboxLib)
const BITBOX = new BITBOXSDK({ restURL: "https://trest.bitcoin.com/v2/" })
//const BITBOX = new BITBOXSDK({ restURL: "http://localhost:3000/v2/" })
const BITBOX = new BITBOXSDK({ restURL: 'https://trest.bitcoin.com/v2/' })
// const BITBOX = new BITBOXSDK({ restURL: "http://localhost:3000/v2/" })
const util = require("util")
// const util = require('util')
// Open the wallet generated with create-wallet.
let walletInfo = {}
try {
var walletInfo = require(`./wallet.json`)
walletInfo = require('./wallet.json')
} catch (err) {
console.log(
`Could not open wallet.json. Generate a wallet with create-wallet first.`
'Could not open wallet.json. Generate a wallet with create-wallet first.'
)
process.exit(0)
}
@@ -37,26 +38,26 @@ try {
const SEND_ADDR = walletInfo.cashAddress
const SEND_MNEMONIC = walletInfo.mnemonic
async function testSend() {
async function testSend () {
try {
const hex1 = await buildTx1(RECV_ADDR1)
//const hex2 = await buildTx2(RECV_ADDR2)
// const hex2 = await buildTx2(RECV_ADDR2)
console.log(`hex1: ${hex1}\n\n`)
//console.log(`hex2: ${hex2}\n\n`)
// console.log(`hex2: ${hex2}\n\n`)
const broadcast = await BITBOX.RawTransactions.sendRawTransaction(hex1)
console.log(`Transaction IDs: ${JSON.stringify(broadcast, null, 2)}`)
console.log(`Should return a TXID string.`)
console.log('Should return a TXID string.')
} catch (err) {
console.log(`Error in testSend: `, err)
console.log('Error in testSend: ', err)
}
}
testSend()
// Build a TX hex with the largest UTXO.
async function buildTx1(recAddr) {
async function buildTx1 (recAddr) {
try {
// Get the balance of the sending address.
const balance = await getBCHBalance(SEND_ADDR, false)
@@ -65,7 +66,7 @@ async function buildTx1(recAddr) {
// Exit if the balance is zero.
if (balance <= 0.0) {
console.log(`Balance of sending address is zero. Exiting.`)
console.log('Balance of sending address is zero. Exiting.')
process.exit(0)
}
@@ -74,16 +75,17 @@ async function buildTx1(recAddr) {
console.log(`Sender Legacy Address: ${SEND_ADDR_LEGACY}`)
console.log(`Receiver Legacy Address: ${RECV_ADDR_LEGACY}`)
const balance2 = await getBCHBalance(recAddr, false)
//console.log(`Balance of recieving address ${recAddr} is ${balance2} BCH.`)
// const balance2 = await getBCHBalance(recAddr, false)
// console.log(`Balance of recieving address ${recAddr} is ${balance2} BCH.`)
await getBCHBalance(recAddr, false)
const u = await BITBOX.Address.utxo(SEND_ADDR)
//console.log(`u: ${JSON.stringify(u, null, 2)}`)
// console.log(`u: ${JSON.stringify(u, null, 2)}`)
const utxo = findBiggestUtxo(u.utxos)
console.log(`utxo: ${JSON.stringify(utxo, null, 2)}`)
// instance of transaction builder
const transactionBuilder = new BITBOX.TransactionBuilder("testnet")
const transactionBuilder = new BITBOX.TransactionBuilder('testnet')
const satoshisToSend = SATOSHIS_TO_SEND
const originalAmount = utxo.satoshis
@@ -134,30 +136,30 @@ async function buildTx1(recAddr) {
return hex
} catch (err) {
console.log(`Error in buildTx().`)
console.log('Error in buildTx().')
throw err
}
}
// Generate a change address from a Mnemonic of a private key.
function changeAddrFromMnemonic(mnemonic) {
function changeAddrFromMnemonic (mnemonic) {
// root seed buffer
const rootSeed = BITBOX.Mnemonic.toSeed(mnemonic)
// master HDNode
const masterHDNode = BITBOX.HDNode.fromSeed(rootSeed, "testnet")
const masterHDNode = BITBOX.HDNode.fromSeed(rootSeed, 'testnet')
// HDNode of BIP44 account
const account = BITBOX.HDNode.derivePath(masterHDNode, "m/44'/145'/0'")
// derive the first external change address HDNode which is going to spend utxo
const change = BITBOX.HDNode.derivePath(account, "0/0")
const change = BITBOX.HDNode.derivePath(account, '0/0')
return change
}
// Get the balance in BCH of a BCH address.
async function getBCHBalance(addr, verbose) {
async function getBCHBalance (addr, verbose) {
try {
const result = await BITBOX.Address.details(addr)
@@ -167,16 +169,16 @@ async function getBCHBalance(addr, verbose) {
return bchBalance.balance
} catch (err) {
console.error(`Error in getBCHBalance: `, err)
console.error('Error in getBCHBalance: ', err)
console.log(`addr: ${addr}`)
throw err
}
}
// Returns the utxo with the biggest balance from an array of utxos.
function findBiggestUtxo(utxos) {
function findBiggestUtxo (utxos) {
// Sort the utxos by the amount of satoshis, largest first.
utxos.sort(function(a, b) {
utxos.sort(function (a, b) {
return b.satoshis - a.satoshis
})
+14 -14
View File
@@ -8,7 +8,7 @@
*/
// Inspect utility used for debugging.
const util = require("util")
const util = require('util')
util.inspect.defaultOptions = {
showHidden: true,
colors: true,
@@ -18,22 +18,22 @@ util.inspect.defaultOptions = {
// const SLPSDK = require("../../../lib/SLP")
// const slpsdk = new SLPSDK()
const WALLET1 = `../wallet1.json`
const WALLET2 = `../wallet2.json`
const WALLET1 = '../wallet1.json'
const WALLET2 = '../wallet2.json'
const lib = require("../util/e2e-util")
const lib = require('../util/e2e-util')
// The main test function.
// Sends a token and reports on how long it takes to show up in SLPDB production.
async function sendTokenTest() {
async function sendTokenTest () {
try {
// Open the sending wallet.
const sendWallet = await lib.openWallet(WALLET1)
//console.log(`sendWallet: ${JSON.stringify(walletInfo, null, 2)}`)
// console.log(`sendWallet: ${JSON.stringify(walletInfo, null, 2)}`)
// Open the recieving wallet.
const recvWallet = await lib.openWallet(WALLET2)
//console.log(`recvWallet: ${JSON.stringify(walletInfo, null, 2)}`)
// console.log(`recvWallet: ${JSON.stringify(walletInfo, null, 2)}`)
// Get the balance of the recieving wallet.
// const testTokens = recvWallet.tokenBalance.filter(
@@ -46,7 +46,7 @@ async function sendTokenTest() {
// Send a token to the recieving wallet.
await lib.sendToken(sendWallet, recvWallet)
console.log(`Sent test token.`)
console.log('Sent test token.')
// Track the time until the balance for the recieving wallet has been updated.
const startTime = new Date()
@@ -56,7 +56,7 @@ async function sendTokenTest() {
for (let i = 0; i < 50; i++) {
await sleep(waitTime) // Wait for a while before checking
console.log(`Checking token balance...`)
console.log('Checking token balance...')
newBalance = await lib.getTestTokenBalance(recvWallet)
// Break out of the loop once a new balance is detected.
@@ -65,12 +65,12 @@ async function sendTokenTest() {
// Provide high-level warnings.
const secondsPassed = (i * waitTime) / 1000
if (secondsPassed > 60 * 10) {
console.log(`More than 10 minutes passed.`)
console.log('More than 10 minutes passed.')
return false // Fail the test.
} else if (secondsPassed > 60 * 5) {
console.log(`More than 5 minutes passed.`)
console.log('More than 5 minutes passed.')
} else if (secondsPassed > 60) {
console.log(`More than 1 minute passed.`)
console.log('More than 1 minute passed.')
}
}
@@ -85,13 +85,13 @@ async function sendTokenTest() {
return deltaTime // Return the time in minutes it took for SLPDB to update.
} catch (err) {
console.log(`Error in e2e/send-token.js/sendTokenTest(): `, err)
console.log('Error in e2e/send-token.js/sendTokenTest(): ', err)
return false
}
}
// Promise based sleep function.
function sleep(ms) {
function sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
+19 -18
View File
@@ -10,19 +10,19 @@ module.exports = {
threeDecimals
}
const SLPSDK = require("../../../lib/SLP")
const SLPSDK = require('../../../lib/SLP')
const slpsdk = new SLPSDK()
const testTokenId =
"cc1b2084a9c43bb5a633df7f38201adde5c5f5cef2fed945d12f8dcd4e505c67"
'cc1b2084a9c43bb5a633df7f38201adde5c5f5cef2fed945d12f8dcd4e505c67'
// Open a wallet and return an object with its address, BCH balance, and SLP
// token balance.
async function openWallet(filename) {
async function openWallet (filename) {
try {
walletInfo = require(filename)
const walletInfo = require(filename)
//const walletBalance = await getBalance(walletInfo)
// const walletBalance = await getBalance(walletInfo)
// const walletBalance = await slpsdk.Utils.balancesForAddress(
// walletInfo.slpAddress
// )
@@ -40,7 +40,7 @@ async function openWallet(filename) {
}
// Send a token from wallet1 to wallet2.
async function sendToken(wallet1, wallet2) {
async function sendToken (wallet1, wallet2) {
try {
const mnemonic = wallet1.mnemonic
@@ -53,11 +53,11 @@ async function sendToken(wallet1, wallet2) {
// HDNode of BIP44 account
const account = slpsdk.HDNode.derivePath(masterHDNode, "m/44'/145'/0'")
const change = slpsdk.HDNode.derivePath(account, "0/0")
const change = slpsdk.HDNode.derivePath(account, '0/0')
// get the cash address
//const cashAddress = slpsdk.HDNode.toCashAddress(change)
//const slpAddress = slpsdk.HDNode.toSLPAddress(change)
// const cashAddress = slpsdk.HDNode.toCashAddress(change)
// const slpAddress = slpsdk.HDNode.toSLPAddress(change)
const fundingAddress = wallet1.slpAddress
const fundingWif = slpsdk.HDNode.toWIF(change) // <-- compressed WIF format
@@ -71,25 +71,26 @@ async function sendToken(wallet1, wallet2) {
tokenReceiverAddress,
bchChangeReceiverAddress,
tokenId:
"cc1b2084a9c43bb5a633df7f38201adde5c5f5cef2fed945d12f8dcd4e505c67",
'cc1b2084a9c43bb5a633df7f38201adde5c5f5cef2fed945d12f8dcd4e505c67',
amount: 1
}
//console.log(`createConfig: ${util.inspect(createConfig)}`)
// console.log(`createConfig: ${util.inspect(createConfig)}`)
// Generate, sign, and broadcast a hex-encoded transaction for sending
// the tokens.
const sendTxId = await slpsdk.TokenType1.send(sendConfig)
// const sendTxId = await slpsdk.TokenType1.send(sendConfig)
await slpsdk.TokenType1.send(sendConfig)
//console.log(`sendTxId: ${sendTxId}`)
// console.log(`sendTxId: ${sendTxId}`)
} catch (err) {
console.log(`Error in e2e-util.js/sendToken()`)
console.log('Error in e2e-util.js/sendToken()')
throw err
}
}
// Returns just the test token balance for a wallet.
async function getTestTokenBalance(walletData) {
async function getTestTokenBalance (walletData) {
try {
const tokenBalance = await slpsdk.Util.balancesForAddress(
walletData.slpAddress
@@ -100,20 +101,20 @@ async function getTestTokenBalance(walletData) {
return testTokens[0].balance
} catch (err) {
console.log(`Error in e2e-util.js/getTestTokenBalance()`)
console.log('Error in e2e-util.js/getTestTokenBalance()')
throw err
}
}
// Round a number to three decimal places.
function threeDecimals(inNum) {
function threeDecimals (inNum) {
try {
let tempNum = inNum * 1000
tempNum = Math.round(tempNum)
tempNum = tempNum / 1000
return tempNum
} catch (err) {
console.log(`Error in e2e-util.js/threeDecimals()`)
console.log('Error in e2e-util.js/threeDecimals()')
throw err
}
}
-170
View File
@@ -1,170 +0,0 @@
/*
Integration tests for the Blockbook library.
*/
const chai = require("chai")
const assert = chai.assert
const BCHJS = require("../../src/bch-js")
const bchjs = new BCHJS()
//const axios = require("axios")
// Inspect utility used for debugging.
const util = require("util")
util.inspect.defaultOptions = {
showHidden: true,
colors: true,
depth: 3
}
describe(`#Blockbook`, () => {
describe(`#Balance`, () => {
it(`should GET balance for a single address`, async () => {
const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
const result = await bchjs.Blockbook.balance(addr)
//console.log(`result: ${util.inspect(result)}`)
assert.hasAnyKeys(result, [
"page",
"totalPages",
"itemsOnPage",
"address",
"balance",
"totalReceived",
"totalSent",
"unconfirmedBalance",
"unconfirmedTxs",
"txs",
"txids"
])
assert.isArray(result.txids)
})
it(`should POST request balances for an array of addresses`, async () => {
const addr = [
"bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
"bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
]
const result = await bchjs.Blockbook.balance(addr)
//console.log(`result: ${util.inspect(result)}`)
assert.isArray(result)
assert.hasAnyKeys(result[0], [
"page",
"totalPages",
"itemsOnPage",
"address",
"balance",
"totalReceived",
"totalSent",
"unconfirmedBalance",
"unconfirmedTxs",
"txs",
"txids"
])
assert.isArray(result[0].txids)
})
it(`should throw an error for improper input`, async () => {
try {
const addr = 12345
await bchjs.Blockbook.balance(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(
err.message,
`Input address must be a string or array of strings`
)
}
})
it(`should throw error on array size rate limit`, async () => {
try {
const addr = []
for (let i = 0; i < 25; i++)
addr.push("bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf")
const result = await bchjs.Blockbook.balance(addr)
console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
}
})
})
describe(`#utxo`, () => {
it(`should GET utxos for a single address`, async () => {
const addr = "bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7"
const result = await bchjs.Blockbook.utxo(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.hasAnyKeys(result[0], [
"txid",
"vout",
"value",
"height",
"confirmations"
])
})
it(`should POST utxo details for an array of addresses`, async () => {
const addr = [
"bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7",
"bitcoincash:qz0us0z6ucpqt07jgpad0shgh7xmwxyr3ynlcsq0wr"
]
const result = await bchjs.Blockbook.utxo(addr)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.isArray(result[0])
assert.hasAnyKeys(result[0][0], [
"txid",
"vout",
"value",
"height",
"confirmations"
])
})
it(`should throw an error for improper input`, async () => {
try {
const addr = 12345
await bchjs.Blockbook.utxo(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(
err.message,
`Input address must be a string or array of strings`
)
}
})
it(`should throw error on array size rate limit`, async () => {
try {
const addr = []
for (let i = 0; i < 25; i++)
addr.push("bitcoincash:qz0us0z6ucpqt07jgpad0shgh7xmwxyr3ynlcsq0wr")
const result = await bchjs.Blockbook.utxo(addr)
//console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
}
})
})
})
+94 -142
View File
@@ -7,119 +7,109 @@
of an e2e test to be properly tested.
*/
const chai = require("chai")
const chai = require('chai')
const assert = chai.assert
const BCHJS = require("../../src/bch-js")
const BCHJS = require('../../src/bch-js')
const bchjs = new BCHJS()
// Inspect utility used for debugging.
const util = require("util")
const util = require('util')
util.inspect.defaultOptions = {
showHidden: true,
colors: true,
depth: 3
}
describe(`#blockchain`, () => {
describe(`#getBestBlockHash`, () => {
it(`should GET best block hash`, async () => {
describe('#blockchain', () => {
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
describe('#getBestBlockHash', () => {
it('should GET best block hash', async () => {
const result = await bchjs.Blockchain.getBestBlockHash()
//console.log(`result: ${util.inspect(result)}`)
// console.log(`result: ${util.inspect(result)}`)
assert.isString(result)
assert.equal(result.length, 64, "Specific hash length")
assert.equal(result.length, 64, 'Specific hash length')
})
})
describe("#getBlockHeader", () => {
it(`should GET block header for a single hash`, async () => {
describe('#getBlockHeader', () => {
it('should GET block header for a single hash', async () => {
const hash =
"000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201"
'000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201'
const result = await bchjs.Blockchain.getBlockHeader(hash)
assert.hasAllKeys(result, [
"hash",
"confirmations",
"height",
"version",
"versionHex",
"merkleroot",
"time",
"mediantime",
"nonce",
"bits",
"difficulty",
"chainwork",
"previousblockhash",
"nextblockhash",
"nTx"
'hash',
'confirmations',
'height',
'version',
'versionHex',
'merkleroot',
'time',
'mediantime',
'nonce',
'bits',
'difficulty',
'chainwork',
'previousblockhash',
'nextblockhash',
'nTx'
])
})
it(`should GET block headers for an array of hashes`, async () => {
it('should GET block headers for an array of hashes', async () => {
const hash = [
"000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201",
"00000000000000000568f0a96bf4348847bc84e455cbfec389f27311037a20f3"
'000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201',
'00000000000000000568f0a96bf4348847bc84e455cbfec389f27311037a20f3'
]
const result = await bchjs.Blockchain.getBlockHeader(hash)
assert.isArray(result)
assert.hasAllKeys(result[0], [
"hash",
"confirmations",
"height",
"version",
"versionHex",
"merkleroot",
"time",
"mediantime",
"nonce",
"bits",
"difficulty",
"chainwork",
"previousblockhash",
"nextblockhash",
"nTx"
'hash',
'confirmations',
'height',
'version',
'versionHex',
'merkleroot',
'time',
'mediantime',
'nonce',
'bits',
'difficulty',
'chainwork',
'previousblockhash',
'nextblockhash',
'nTx'
])
})
it(`should throw an error for improper input`, async () => {
try {
const hash = 12345
await bchjs.Blockchain.getBlockHeader(hash)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.include(
err.message,
`Input hash must be a string or array of strings`
)
}
})
it(`should throw error on array size rate limit`, async () => {
it('should throw error on array size rate limit', async () => {
try {
const data = []
for (let i = 0; i < 25; i++) {
data.push(
"000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201"
'000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201'
)
}
const result = await bchjs.Blockchain.getBlockHeader(data)
console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
assert.hasAnyKeys(err, ['error'])
assert.include(err.error, 'Array too large')
}
})
})
describe("#getMempoolEntry", () => {
describe('#getMempoolEntry', () => {
/*
// To run this test, the txid must be unconfirmed.
const txid =
@@ -171,119 +161,77 @@ describe(`#blockchain`, () => {
})
*/
it(`should throw an error if txid is not in mempool`, async () => {
it('should throw an error if txid is not in mempool', async () => {
try {
const txid =
"03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7"
'03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7'
await bchjs.Blockchain.getMempoolEntry(txid)
assert.equal(true, false, "Unexpected result!")
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
//console.log(`err: ${util.inspect(err)}`)
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, `Transaction not in mempool`)
}
})
it(`should throw an error for improper single input`, async () => {
try {
const txid = 12345
await bchjs.Blockchain.getMempoolEntry(txid)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.include(
err.message,
`Input must be a string or array of strings`
)
// console.log(`err: ${util.inspect(err)}`)
assert.hasAnyKeys(err, ['error'])
assert.include(err.error, 'Transaction not in mempool')
}
})
})
describe(`#getTxOutProof`, () => {
it(`should get single tx out proof`, async () => {
describe('#getTxOutProof', () => {
it('should get single tx out proof', async () => {
const txid =
"03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7"
'03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7'
const result = await bchjs.Blockchain.getTxOutProof(txid)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isString(result)
})
it(`should get an array of tx out proofs`, async () => {
it('should get an array of tx out proofs', async () => {
const txid = [
"03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7",
"fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33"
'03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7',
'fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33'
]
const result = await bchjs.Blockchain.getTxOutProof(txid)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.isString(result[0])
})
it(`should throw an error for improper single input`, async () => {
try {
const txid = 12345
await bchjs.Blockchain.getTxOutProof(txid)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.include(
err.message,
`Input must be a string or array of strings`
)
}
})
})
describe(`#verifyTxOutProof`, () => {
describe('#verifyTxOutProof', () => {
const mockTxOutProof =
"0000002086a4a3161f9ba2174883ec0b93acceac3b2f37b36ed1f90000000000000000009cb02406d1094ecf3e0b4c0ca7c585125e721147c39daf6b48c90b512741e13a12333e5cb38705180f441d8c7100000008fee9b60f1edb57e5712839186277ed39e0a004a32be9096ee47472efde8eae62f789f9d7a9f59d0ea7093dea1e0c65ff0b953f1d8cf3d47f92e732ca0295f603c272d5f4a63509f7a887f2549d78af7444aa0ecbb4f66d9cbe13bc6a89f59e05a199df8325d490818ffefe6b6321d32d7496a68580459836c0183f89082fc1b491cc91b23ecdcaa4c347bf599a62904d61f1c15b400ebbd5c90149010c139d9c1e31b774b796977393a238080ab477e1d240d0c4f155d36f519668f49bae6bd8cd5b8e40522edf76faa09cca6188d83ff13af6967cc6a569d1a5e9aeb1fdb7f531ddd2d0cbb81879741d5f38166ac1932136264366a4065cc96a42e41f96294f02df01"
'0000002086a4a3161f9ba2174883ec0b93acceac3b2f37b36ed1f90000000000000000009cb02406d1094ecf3e0b4c0ca7c585125e721147c39daf6b48c90b512741e13a12333e5cb38705180f441d8c7100000008fee9b60f1edb57e5712839186277ed39e0a004a32be9096ee47472efde8eae62f789f9d7a9f59d0ea7093dea1e0c65ff0b953f1d8cf3d47f92e732ca0295f603c272d5f4a63509f7a887f2549d78af7444aa0ecbb4f66d9cbe13bc6a89f59e05a199df8325d490818ffefe6b6321d32d7496a68580459836c0183f89082fc1b491cc91b23ecdcaa4c347bf599a62904d61f1c15b400ebbd5c90149010c139d9c1e31b774b796977393a238080ab477e1d240d0c4f155d36f519668f49bae6bd8cd5b8e40522edf76faa09cca6188d83ff13af6967cc6a569d1a5e9aeb1fdb7f531ddd2d0cbb81879741d5f38166ac1932136264366a4065cc96a42e41f96294f02df01'
it(`should verify a single proof`, async () => {
it('should verify a single proof', async () => {
const result = await bchjs.Blockchain.verifyTxOutProof(mockTxOutProof)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.isString(result[0])
assert.equal(
result[0],
"03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7"
'03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7'
)
})
it(`should verify an array of proofs`, async () => {
it('should verify an array of proofs', async () => {
const proofs = [mockTxOutProof, mockTxOutProof]
const result = await bchjs.Blockchain.verifyTxOutProof(proofs)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.isString(result[0])
assert.equal(
result[0],
"03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7"
'03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7'
)
})
it(`should throw an error for improper single input`, async () => {
try {
const txid = 12345
await bchjs.Blockchain.verifyTxOutProof(txid)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.include(
err.message,
`Input must be a string or array of strings`
)
}
})
it(`should throw error on array size rate limit`, async () => {
it('should throw error on array size rate limit', async () => {
try {
const data = []
for (let i = 0; i < 25; i++) data.push(mockTxOutProof)
@@ -291,35 +239,35 @@ describe(`#blockchain`, () => {
const result = await bchjs.Blockchain.verifyTxOutProof(data)
console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
assert.hasAnyKeys(err, ['error'])
assert.include(err.error, 'Array too large')
}
})
})
describe("#getTxOut", () => {
it("should get information on an unspent tx", async () => {
describe('#getTxOut', () => {
it('should get information on an unspent tx', async () => {
const result = await bchjs.Blockchain.getTxOut(
"62a3ea958a463a372bc0caf2c374a7f60be9c624be63a0db8db78f05809df6d8",
'62a3ea958a463a372bc0caf2c374a7f60be9c624be63a0db8db78f05809df6d8',
0,
true
)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAllKeys(result, [
"bestblock",
"confirmations",
"value",
"scriptPubKey",
"coinbase"
'bestblock',
'confirmations',
'value',
'scriptPubKey',
'coinbase'
])
})
it("should get information on a spent tx", async () => {
it('should get information on a spent tx', async () => {
const result = await bchjs.Blockchain.getTxOut(
"87380e52d151856b23173d6d8a3db01b984c6b50f77ea045a5a1cf4f54497871",
'87380e52d151856b23173d6d8a3db01b984c6b50f77ea045a5a1cf4f54497871',
0,
true
)
@@ -329,3 +277,7 @@ describe(`#blockchain`, () => {
})
})
})
function sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
@@ -0,0 +1,71 @@
/*
Integration tests for the bchjs. Only covers calls made to
rest.bitcoin.com.
TODO
*/
const chai = require('chai')
const assert = chai.assert
const BCHJS = require('../../../../src/bch-js')
const bchjs = new BCHJS()
// Inspect utility used for debugging.
const util = require('util')
util.inspect.defaultOptions = {
showHidden: true,
colors: true,
depth: 3
}
describe('#rawtransaction', () => {
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
/*
Testing sentRawTransaction isn't really possible with an integration test,
as the endpoint really needs an e2e test to be properly tested. The tests
below expect error messages returned from the server, but at least test
that the server is responding on those endpoints, and responds consistently.
*/
describe('sendRawTransaction', () => {
it('should send a single transaction hex', async () => {
try {
const hex =
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000'
await bchjs.RawTransactions.sendRawTransaction(hex)
// console.log(`result ${JSON.stringify(result, null, 2)}`)
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
// console.log(`err: ${util.inspect(err)}`)
assert.hasAllKeys(err, ['error'])
assert.include(err.error, 'bad-txns-inputs-missingorspent')
}
})
it('should send an array of tx hexes', async () => {
try {
const hexes = [
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000',
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000'
]
const result = await bchjs.RawTransactions.sendRawTransaction(hexes)
console.log(`result ${JSON.stringify(result, null, 2)}`)
} catch (err) {
// console.log(`err: ${util.inspect(err)}`)
assert.hasAllKeys(err, ['error'])
assert.include(err.error, 'bad-txns-inputs-missingorspent')
}
})
})
})
function sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
+223
View File
@@ -0,0 +1,223 @@
/*
Integration tests for the bchjs covering SLP tokens.
These tests are specific to the ABC chain.
*/
const chai = require('chai')
const assert = chai.assert
const BCHJS = require('../../../../src/bch-js')
let bchjs
// Inspect utility used for debugging.
const util = require('util')
util.inspect.defaultOptions = {
showHidden: true,
colors: true,
depth: 1
}
describe('#SLP', () => {
// before(() => {
// console.log(`bchjs.SLP.restURL: ${bchjs.SLP.restURL}`)
// console.log(`bchjs.SLP.apiToken: ${bchjs.SLP.apiToken}`)
// })
beforeEach(async () => {
// Introduce a delay so that the BVT doesn't trip the rate limits.
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
bchjs = new BCHJS()
})
describe('#util', () => {
describe('#tokenUtxoDetails', () => {
it('should handle a range of UTXO types', async () => {
const utxos = [
// Malformed SLP tx
{
note: 'Malformed SLP tx',
tx_hash:
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a',
tx_pos: 1,
value: 546
},
// Normal TX (non-SLP)
{
note: 'Normal TX (non-SLP)',
tx_hash:
'01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0',
tx_pos: 0,
value: 400000
},
// Valid PSF SLP tx
{
note: 'Valid PSF SLP tx',
tx_hash:
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd',
tx_pos: 1,
value: 546
},
// Valid SLP token not in whitelist
{
note: 'Valid SLP token not in whitelist',
tx_hash:
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488',
tx_pos: 1,
value: 546
},
// Token send on BCHN network.
{
note: 'Token send on BCHN network',
tx_hash:
'402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019',
tx_pos: 1,
value: 546
},
// Token send on ABC network.
{
note: 'Token send on ABC network',
tx_hash:
'336bfe2168aac4c3303508a9e8548a0d33797a83b85b76a12d845c8d6674f79d',
tx_pos: 1,
value: 546
},
// Known invalid SLP token send of PSF tokens.
{
note: 'Known invalid SLP token send of PSF tokens',
tx_hash:
'2bf691ad3679d928fef880b8a45b93b233f8fa0d0a92cf792313dbe77b1deb74',
tx_pos: 1,
value: 546
}
]
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
// Malformed SLP tx
assert.equal(data[0].tx_hash, utxos[0].tx_hash)
assert.equal(data[0].isValid, false)
// Normal TX (non-SLP)
assert.equal(data[1].tx_hash, utxos[1].tx_hash)
assert.equal(data[1].isValid, false)
// Valid PSF SLP tx
assert.equal(data[2].tx_hash, utxos[2].tx_hash)
assert.equal(data[2].isValid, true)
// Valid SLP token not in whitelist
assert.equal(data[3].tx_hash, utxos[3].tx_hash)
assert.equal(data[3].isValid, true)
// Token send on BCHN network
assert.equal(data[4].tx_hash, utxos[4].tx_hash)
assert.equal(data[4].isValid, null)
// Token send on ABC network
assert.equal(data[5].tx_hash, utxos[5].tx_hash)
assert.equal(data[5].isValid, true)
// Known invalid SLP token send of PSF tokens
assert.equal(data[6].tx_hash, utxos[6].tx_hash)
assert.equal(data[6].isValid, false)
})
})
describe('#validateTxid3', () => {
it('should invalidate a known invalid TXID', async () => {
const txid =
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a'
const result = await bchjs.SLP.Utils.validateTxid3(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], 'txid')
assert.equal(result[0].txid, txid)
assert.property(result[0], 'valid')
assert.equal(result[0].valid, null)
})
it('should validate a known valid TXID', async () => {
const txid =
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd'
const result = await bchjs.SLP.Utils.validateTxid3(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], 'txid')
assert.equal(result[0].txid, txid)
assert.property(result[0], 'valid')
assert.equal(result[0].valid, true)
})
it('should handle a mix of valid, invalid, and non-SLP txs', async () => {
const txids = [
// Malformed SLP tx
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a',
// Normal TX (non-SLP)
'01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0',
// Valid PSF SLP tx
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd',
// Valid SLP token not in whitelist
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488',
// Unprocessed SLP TX
// "a0d6406eecfd8634158efa9314ff15b4cbf451938e9dc7b5678c46b41eabc6ed" // Mint baton
'402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019'
]
const result = await bchjs.SLP.Utils.validateTxid3(txids)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.equal(result[0].valid, null)
assert.equal(result[1].valid, null)
assert.equal(result[2].valid, true)
assert.equal(result[3].valid, true)
assert.equal(result[4].valid, null)
})
})
describe('#validateTxid', () => {
it('should handle a mix of valid, invalid, and non-SLP txs', async () => {
const txids = [
// Malformed SLP tx
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a',
// Normal TX (non-SLP)
'01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0',
// Valid PSF SLP tx
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd',
// Valid SLP token not in whitelist
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488',
// Token send on BCHN network.
'402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019',
// Token send on ABC network.
'336bfe2168aac4c3303508a9e8548a0d33797a83b85b76a12d845c8d6674f79d'
]
const result = await bchjs.SLP.Utils.validateTxid(txids)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.equal(result[0].valid, null)
assert.equal(result[1].valid, null)
assert.equal(result[2].valid, true)
assert.equal(result[3].valid, true)
assert.equal(result[4].valid, null)
assert.equal(result[5].valid, true)
})
})
})
})
// Promise-based sleep function
function sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
@@ -0,0 +1,71 @@
/*
Integration tests for the bchjs. Only covers calls made to
rest.bitcoin.com.
TODO
*/
const chai = require('chai')
const assert = chai.assert
const BCHJS = require('../../../../src/bch-js')
const bchjs = new BCHJS()
// Inspect utility used for debugging.
const util = require('util')
util.inspect.defaultOptions = {
showHidden: true,
colors: true,
depth: 3
}
describe('#rawtransaction', () => {
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
/*
Testing sentRawTransaction isn't really possible with an integration test,
as the endpoint really needs an e2e test to be properly tested. The tests
below expect error messages returned from the server, but at least test
that the server is responding on those endpoints, and responds consistently.
*/
describe('sendRawTransaction', () => {
it('should send a single transaction hex', async () => {
try {
const hex =
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000'
await bchjs.RawTransactions.sendRawTransaction(hex)
// console.log(`result ${JSON.stringify(result, null, 2)}`)
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
// console.log(`err: ${util.inspect(err)}`)
assert.hasAllKeys(err, ['error'])
assert.include(err.error, 'Missing inputs')
}
})
it('should send an array of tx hexes', async () => {
try {
const hexes = [
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000',
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000'
]
const result = await bchjs.RawTransactions.sendRawTransaction(hexes)
console.log(`result ${JSON.stringify(result, null, 2)}`)
} catch (err) {
// console.log(`err: ${util.inspect(err)}`)
assert.hasAllKeys(err, ['error'])
assert.include(err.error, 'Missing inputs')
}
})
})
})
function sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
+247
View File
@@ -0,0 +1,247 @@
/*
Integration tests for the bchjs covering SLP tokens.
These tests are specific to the ABC chain.
*/
const chai = require('chai')
const assert = chai.assert
const BCHJS = require('../../../../src/bch-js')
let bchjs
// Inspect utility used for debugging.
const util = require('util')
util.inspect.defaultOptions = {
showHidden: true,
colors: true,
depth: 1
}
describe('#SLP', () => {
// before(() => {
// console.log(`bchjs.SLP.restURL: ${bchjs.SLP.restURL}`)
// console.log(`bchjs.SLP.apiToken: ${bchjs.SLP.apiToken}`)
// })
beforeEach(async () => {
// Introduce a delay so that the BVT doesn't trip the rate limits.
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
bchjs = new BCHJS()
})
describe('#util', () => {
describe('#tokenUtxoDetails', () => {
it('should handle a range of UTXO types', async () => {
const utxos = [
// Malformed SLP tx
{
note: 'Malformed SLP tx',
tx_hash:
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a',
tx_pos: 1,
value: 546
},
// Normal TX (non-SLP)
{
note: 'Normal TX (non-SLP)',
tx_hash:
'01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0',
tx_pos: 0,
value: 400000
},
// Valid PSF SLP tx
{
note: 'Valid PSF SLP tx',
tx_hash:
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd',
tx_pos: 1,
value: 546
},
// Valid SLP token not in whitelist
{
note: 'Valid SLP token not in whitelist',
tx_hash:
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488',
tx_pos: 1,
value: 546
},
// Token send on BCHN network.
{
note: 'Token send on BCHN network',
tx_hash:
'402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019',
tx_pos: 1,
value: 546
},
// Token send on ABC network.
{
note: 'Token send on ABC network',
tx_hash:
'336bfe2168aac4c3303508a9e8548a0d33797a83b85b76a12d845c8d6674f79d',
tx_pos: 1,
value: 546
},
// Known invalid SLP token send of PSF tokens.
{
note: 'Known invalid SLP token send of PSF tokens',
tx_hash:
'2bf691ad3679d928fef880b8a45b93b233f8fa0d0a92cf792313dbe77b1deb74',
tx_pos: 1,
value: 546
}
]
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
// Malformed SLP tx
assert.equal(data[0].tx_hash, utxos[0].tx_hash)
assert.equal(data[0].isValid, false)
// Normal TX (non-SLP)
assert.equal(data[1].tx_hash, utxos[1].tx_hash)
assert.equal(data[1].isValid, false)
// Valid PSF SLP tx
assert.equal(data[2].tx_hash, utxos[2].tx_hash)
assert.equal(data[2].isValid, true)
// Valid SLP token not in whitelist
assert.equal(data[3].tx_hash, utxos[3].tx_hash)
assert.equal(data[3].isValid, true)
// Token send on BCHN network
assert.equal(data[4].tx_hash, utxos[4].tx_hash)
assert.equal(data[4].isValid, true)
// Token send on ABC network
assert.equal(data[5].tx_hash, utxos[5].tx_hash)
assert.equal(data[5].isValid, null)
// Known invalid SLP token send of PSF tokens
assert.equal(data[6].tx_hash, utxos[6].tx_hash)
assert.equal(data[6].isValid, false)
})
})
describe('#validateTxid3', () => {
it('should invalidate a known invalid TXID', async () => {
const txid =
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a'
const result = await bchjs.SLP.Utils.validateTxid3(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], 'txid')
assert.equal(result[0].txid, txid)
assert.property(result[0], 'valid')
assert.equal(result[0].valid, null)
})
it('should validate a known valid TXID', async () => {
const txid =
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd'
const result = await bchjs.SLP.Utils.validateTxid3(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], 'txid')
assert.equal(result[0].txid, txid)
assert.property(result[0], 'valid')
assert.equal(result[0].valid, true)
})
it('should handle a mix of valid, invalid, and non-SLP txs', async () => {
const txids = [
// Malformed SLP tx
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a',
// Normal TX (non-SLP)
'01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0',
// Valid PSF SLP tx
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd',
// Valid SLP token not in whitelist
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488',
// Unprocessed SLP TX
'402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019'
]
const result = await bchjs.SLP.Utils.validateTxid3(txids)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.equal(result[0].txid, txids[0])
assert.equal(result[0].valid, null)
assert.equal(result[1].txid, txids[1])
assert.equal(result[1].valid, null)
assert.equal(result[2].txid, txids[2])
assert.equal(result[2].valid, true)
// True in validateTxid() but null in validateTxid3()
assert.equal(result[3].txid, txids[3])
assert.equal(result[3].valid, null)
// Note: This should change from null to true once SLPDB finishes indexing.
assert.equal(result[4].txid, txids[4])
assert.equal(result[4].valid, null)
})
})
describe('#validateTxid', () => {
it('should handle a mix of valid, invalid, and non-SLP txs', async () => {
const txids = [
// Malformed SLP tx
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a',
// Normal TX (non-SLP)
'01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0',
// Valid PSF SLP tx
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd',
// Valid SLP token not in whitelist
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488',
// Token send on BCHN network.
'402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019',
// Token send on ABC network.
'336bfe2168aac4c3303508a9e8548a0d33797a83b85b76a12d845c8d6674f79d'
]
const result = await bchjs.SLP.Utils.validateTxid(txids)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.equal(result[0].txid, txids[0])
assert.equal(result[0].valid, null)
assert.equal(result[1].txid, txids[1])
assert.equal(result[1].valid, null)
assert.equal(result[2].txid, txids[2])
assert.equal(result[2].valid, true)
// True in validateTxid() but null in validateTxid3()
assert.equal(result[3].txid, txids[3])
assert.equal(result[3].valid, true)
assert.equal(result[4].txid, txids[4])
assert.equal(result[4].valid, true)
assert.equal(result[5].txid, txids[5])
assert.equal(result[5].valid, null)
})
})
})
})
// Promise-based sleep function
function sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
@@ -0,0 +1,260 @@
/*
Integration tests for the bchjs. Only covers calls made to
rest.bitcoin.com.
TODO
- getMempoolEntry() only works on TXs in the mempool, so it needs to be part
of an e2e test to be properly tested.
*/
const chai = require('chai')
const assert = chai.assert
const RESTURL = process.env.RESTURL
? process.env.RESTURL
: 'https://testnet3.fullstack.cash/v4/'
// if (process.env.RESTURL) RESTURL = process.env.RESTURL
const BCHJS = require('../../../../src/bch-js')
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v4/` })
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
// Inspect utility used for debugging.
const util = require('util')
util.inspect.defaultOptions = {
showHidden: true,
colors: true,
depth: 3
}
describe('#blockchain', () => {
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
describe('#getBestBlockHash', () => {
it('should GET best block hash', async () => {
const result = await bchjs.Blockchain.getBestBlockHash()
// console.log(`result: ${util.inspect(result)}`)
assert.isString(result)
assert.equal(result.length, 64, 'Specific hash length')
})
})
describe('#getBlockHeader', () => {
it('should GET block header for a single hash', async () => {
const hash =
'000000000000c57178ace90210289e6b5383134c5b5306e1cdd8395176e10aaf'
const result = await bchjs.Blockchain.getBlockHeader(hash)
assert.hasAllKeys(result, [
'hash',
'confirmations',
'height',
'version',
'versionHex',
'merkleroot',
'time',
'mediantime',
'nonce',
'bits',
'difficulty',
'chainwork',
'previousblockhash',
'nextblockhash',
'nTx'
])
})
it('should GET block headers for an array of hashes', async () => {
const hash = [
'000000000000c57178ace90210289e6b5383134c5b5306e1cdd8395176e10aaf',
'00000000000b7db4cbae48d852fcbef32f728014582094ad613fe12af6600ff2'
]
const result = await bchjs.Blockchain.getBlockHeader(hash)
assert.isArray(result)
assert.hasAllKeys(result[0], [
'hash',
'confirmations',
'height',
'version',
'versionHex',
'merkleroot',
'time',
'mediantime',
'nonce',
'bits',
'difficulty',
'chainwork',
'previousblockhash',
'nextblockhash',
'nTx'
])
})
it('should throw error on array size rate limit', async () => {
try {
const data = []
for (let i = 0; i < 25; i++) {
data.push(
'00000000000b7db4cbae48d852fcbef32f728014582094ad613fe12af6600ff2'
)
}
await bchjs.Blockchain.getBlockHeader(data)
// console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
assert.hasAnyKeys(err, ['error'])
assert.include(err.error, 'Array too large')
}
})
})
describe('#getMempoolEntry', () => {
/*
// To run this test, the txid must be unconfirmed.
const txid =
"defea04c38ee00cf73ad402984714ed22dc0dd99b2ae5cb50d791d94343ba79b"
it(`should GET single mempool entry`, async () => {
const result = await bchjs.Blockchain.getMempoolEntry(txid)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAnyKeys(result, [
"size",
"fee",
"modifiedfee",
"time",
"height",
"startingpriority",
"currentpriority",
"descendantcount",
"descendantsize",
"descendantfees",
"ancestorcount",
"ancestorsize",
"ancestorfees",
"depends"
])
})
it(`should get an array of mempool entries`, async () => {
const result = await bchjs.Blockchain.getMempoolEntry([txid, txid])
console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.hasAnyKeys(result[0], [
"size",
"fee",
"modifiedfee",
"time",
"height",
"startingpriority",
"currentpriority",
"descendantcount",
"descendantsize",
"descendantfees",
"ancestorcount",
"ancestorsize",
"ancestorfees",
"depends"
])
})
*/
it('should throw an error if txid is not in mempool', async () => {
try {
const txid =
'1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04'
await bchjs.Blockchain.getMempoolEntry(txid)
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
// console.log(`err: ${util.inspect(err)}`)
assert.hasAnyKeys(err, ['error'])
assert.include(err.error, 'Transaction not in mempool')
}
})
})
describe('#getTxOutProof', () => {
it('should get single tx out proof', async () => {
const txid =
'1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04'
const result = await bchjs.Blockchain.getTxOutProof(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isString(result)
})
it('should get an array of tx out proofs', async () => {
const txid = [
'1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04',
'fc4f696c0ebb3d0994b3975f57d85be75ef752b9fd52c17e361ec3be2fa3e752'
]
const result = await bchjs.Blockchain.getTxOutProof(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.isString(result[0])
})
})
describe('#verifyTxOutProof', () => {
const mockTxOutProof =
'00000020ac86ce8f2bda235c0dc135d18f6a777c44b121e8f41db8a51ca65000000000000cd4de3c49337712f3a1092c47c3bf73ec2f9b1cfd289ee991ede0b6eab4df229d5b8c5dffff001d82ce005b0700000003ec55d9142eac2c1d2229e5af24898b2590c111b62e2787fa1998d3d713fd432fd557124ed758fa156a6cdc6d317d5575aec2b86dfb159c62ecb4743f28bef1cb52e7a32fbec31e367ec152fdb952f75ee75bd8575f97b394093dbb0e6c694ffc0135'
it('should verify a single proof', async () => {
const result = await bchjs.Blockchain.verifyTxOutProof(mockTxOutProof)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.isString(result[0])
assert.equal(
result[0],
'fc4f696c0ebb3d0994b3975f57d85be75ef752b9fd52c17e361ec3be2fa3e752'
)
})
it('should verify an array of proofs', async () => {
const proofs = [mockTxOutProof, mockTxOutProof]
const result = await bchjs.Blockchain.verifyTxOutProof(proofs)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.isString(result[0])
assert.equal(
result[0],
'fc4f696c0ebb3d0994b3975f57d85be75ef752b9fd52c17e361ec3be2fa3e752'
)
})
it('should throw error on array size rate limit', async () => {
try {
const data = []
for (let i = 0; i < 25; i++) data.push(mockTxOutProof)
const result = await bchjs.Blockchain.verifyTxOutProof(data)
console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
assert.hasAnyKeys(err, ['error'])
assert.include(err.error, 'Array too large')
}
})
})
})
function sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
@@ -0,0 +1,32 @@
/*
Integration tests for bchjs control library.
*/
const chai = require('chai')
const assert = chai.assert
const RESTURL = process.env.RESTURL
? process.env.RESTURL
: 'https://testnet3.fullstack.cash/v4/'
const BCHJS = require('../../../../src/bch-js')
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
describe('#control', () => {
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
describe('#getNetworkInfo', () => {
it('should get info on the full node', async () => {
const result = await bchjs.Control.getNetworkInfo()
console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'version')
})
})
})
function sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
@@ -0,0 +1,368 @@
const chai = require('chai')
const assert = chai.assert
const sinon = require('sinon')
const util = require('util')
const RESTURL = process.env.RESTURL
? process.env.RESTURL
: 'https://testnet3.fullstack.cash/v4/'
const BCHJS = require('../../../../src/bch-js')
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
describe('#ElectrumX', () => {
let sandbox
beforeEach(async () => {
sandbox = sinon.createSandbox()
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
afterEach(() => sandbox.restore())
describe('#utxo', () => {
it('should GET utxos for a single address', async () => {
const addr = 'bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2'
const result = await bchjs.Electrumx.utxo(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, 'utxos')
assert.isArray(result.utxos)
assert.property(result.utxos[0], 'height')
assert.property(result.utxos[0], 'tx_hash')
assert.property(result.utxos[0], 'tx_pos')
assert.property(result.utxos[0], 'value')
})
it('should POST utxo details for an array of addresses', async () => {
const addr = [
'bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2',
'bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2'
]
const result = await bchjs.Electrumx.utxo(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, 'utxos')
assert.isArray(result.utxos)
assert.property(result.utxos[0], 'utxos')
assert.isArray(result.utxos[0].utxos)
assert.property(result.utxos[0], 'address')
assert.property(result.utxos[0].utxos[0], 'height')
assert.property(result.utxos[0].utxos[0], 'tx_hash')
assert.property(result.utxos[0].utxos[0], 'tx_pos')
assert.property(result.utxos[0].utxos[0], 'value')
})
it('should throw error on array size rate limit', async () => {
try {
const addr = []
for (let i = 0; i < 25; i++) { addr.push('bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2') }
// const result = await bchjs.Electrumx.utxo(addr)
// console.log(`result: ${util.inspect(result)}`)
await bchjs.Electrumx.utxo(addr)
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
assert.hasAnyKeys(err, ['error'])
assert.include(err.error, 'Array too large')
}
})
})
describe('#balance', () => {
it('should GET balance for a single address', async () => {
const addr = 'bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2'
const result = await bchjs.Electrumx.balance(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, 'balance')
assert.property(result.balance, 'confirmed')
assert.property(result.balance, 'unconfirmed')
})
it('should POST request for balances for an array of addresses', async () => {
const addr = [
'bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2',
'bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2'
]
const result = await bchjs.Electrumx.balance(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, 'balances')
assert.isArray(result.balances)
assert.property(result.balances[0], 'address')
assert.property(result.balances[0], 'balance')
assert.property(result.balances[0].balance, 'confirmed')
assert.property(result.balances[0].balance, 'unconfirmed')
})
it('should throw error on array size rate limit', async () => {
try {
const addr = []
for (let i = 0; i < 25; i++) { addr.push('bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2') }
const result = await bchjs.Electrumx.balance(addr)
console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
assert.hasAnyKeys(err, ['error'])
assert.include(err.error, 'Array too large')
}
})
})
describe('#transactions', () => {
it('should GET transaction history for a single address', async () => {
const addr = 'bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2'
const result = await bchjs.Electrumx.transactions(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, 'transactions')
assert.isArray(result.transactions)
assert.property(result.transactions[0], 'height')
assert.property(result.transactions[0], 'tx_hash')
})
it('should POST request for transaction history for an array of addresses', async () => {
const addr = [
'bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2',
'bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2'
]
const result = await bchjs.Electrumx.transactions(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, 'transactions')
assert.isArray(result.transactions)
assert.property(result.transactions[0], 'address')
assert.property(result.transactions[0], 'transactions')
assert.isArray(result.transactions[0].transactions)
assert.property(result.transactions[0].transactions[0], 'height')
assert.property(result.transactions[0].transactions[0], 'tx_hash')
})
it('should throw error on array size rate limit', async () => {
try {
const addr = []
for (let i = 0; i < 25; i++) { addr.push('bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2') }
const result = await bchjs.Electrumx.transactions(addr)
console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
assert.hasAnyKeys(err, ['error'])
assert.include(err.error, 'Array too large')
}
})
})
describe('#unconfirmed', () => {
// These tests won't work because unconfirmed transactions are transient in nature.
/*
it(`should GET unconfirmed UTXOs (mempool) for a single address`, async () => {
const addr = "bchtest:qp25k20dgcljrz4hkdz43partam3j5httyprjp23qd"
const result = await bchjs.Electrumx.unconfirmed(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.equal(result.success, true)
assert.property(result, "utxos")
assert.isArray(result.utxos)
assert.property(result.utxos[0], "height")
assert.property(result.utxos[0], "tx_hash")
assert.property(result.utxos[0], "fee")
})
it(`should POST unconfirmed UTXO details for an array of addresses`, async () => {
const addr = [
"bchtest:qp25k20dgcljrz4hkdz43partam3j5httyprjp23qd",
"bchtest:qpkl3xylrjx4jup6m66e7zg7whlaucsxeudxeqawdj"
]
const result = await bchjs.Electrumx.unconfirmed(addr)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.equal(result.success, true)
assert.property(result, "utxos")
assert.isArray(result.utxos)
assert.property(result.utxos[0], "utxos")
assert.isArray(result.utxos[0].utxos)
assert.property(result.utxos[0], "address")
assert.property(result.utxos[0].utxos[0], "height")
assert.property(result.utxos[0].utxos[0], "tx_hash")
assert.property(result.utxos[0].utxos[0], "fee")
})
*/
it('should throw error on array size rate limit', async () => {
try {
const addr = []
for (let i = 0; i < 25; i++) { addr.push('bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2') }
await bchjs.Electrumx.unconfirmed(addr)
// console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
assert.hasAnyKeys(err, ['error'])
assert.include(err.error, 'Array too large')
}
})
})
describe('#blockHeader', () => {
it('should GET block headers for given height and count', async () => {
const height = 42
const count = 2
const result = await bchjs.Electrumx.blockHeader(height, count)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, 'headers')
assert.isArray(result.headers)
assert.equal(result.headers.length, 2)
})
it('should GET block headers for given height with default count = 1', async () => {
const height = 42
const result = await bchjs.Electrumx.blockHeader(height)
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, 'headers')
assert.isArray(result.headers)
assert.equal(result.headers.length, 1)
})
})
describe('#txData', () => {
it('should GET details for a single transaction', async () => {
const txid =
'76d2ee0ebd8b978742f6478ff9a12f478c34e4cee0a2b919059101d961bd01ee'
const result = await bchjs.Electrumx.txData(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, 'details')
assert.isObject(result.details)
assert.property(result.details, 'blockhash')
assert.property(result.details, 'hash')
assert.property(result.details, 'hex')
assert.property(result.details, 'vin')
assert.property(result.details, 'vout')
assert.equal(result.details.hash, txid)
})
it('should POST details for an array of transactions', async () => {
const txids = [
'76d2ee0ebd8b978742f6478ff9a12f478c34e4cee0a2b919059101d961bd01ee',
'76d2ee0ebd8b978742f6478ff9a12f478c34e4cee0a2b919059101d961bd01ee'
]
const result = await bchjs.Electrumx.txData(txids)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, 'transactions')
assert.isArray(result.transactions)
assert.property(result.transactions[0], 'txid')
assert.property(result.transactions[0], 'details')
assert.property(result.transactions[0].details, 'blockhash')
assert.property(result.transactions[0].details, 'hash')
assert.property(result.transactions[0].details, 'hex')
assert.property(result.transactions[0].details, 'vin')
assert.property(result.transactions[0].details, 'vout')
})
it('should throw error on array size rate limit', async () => {
try {
const txids = []
for (let i = 0; i < 25; i++) {
txids.push(
'76d2ee0ebd8b978742f6478ff9a12f478c34e4cee0a2b919059101d961bd01ee'
)
}
await bchjs.Electrumx.txData(txids)
// console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
assert.hasAnyKeys(err, ['error'])
assert.include(err.error, 'Array too large')
}
})
})
describe('#broadcast', () => {
it('should broadcast a single transaction', async () => {
const txHex =
'020000000265d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667010000006441dd1dd72770cadede1a7fd0363574846c48468a398ddfa41a9677c74cac8d2652b682743725a3b08c6c2021a629011e11a264d9036e9d5311e35b5f4937ca7b4e4121020797d8fd4d2fa6fd7cdeabe2526bfea2b90525d6e8ad506ec4ee3c53885aa309ffffffff65d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667000000006441347d7f218c11c04487c1ad8baac28928fb10e5054cd4494b94d078cfa04ccf68e064fb188127ff656c0b98e9ce87f036d183925d0d0860605877d61e90375f774121028a53f95eb631b460854fc836b2e5d31cad16364b4dc3d970babfbdcc3f2e4954ffffffff035ac355000000000017a914189ce02e332548f4804bac65cba68202c9dbf822878dfd0800000000001976a914285bb350881b21ac89724c6fb6dc914d096cd53b88acf9ef3100000000001976a91445f1f1c4a9b9419a5088a3e9c24a293d7a150e6488ac00000000'
try {
await bchjs.Electrumx.broadcast(txHex)
} catch (err) {
assert.property(err, 'success')
assert.equal(err.success, false)
assert.include(
err.error,
'the transaction was rejected by network rules'
)
}
})
})
})
function sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
+147
View File
@@ -0,0 +1,147 @@
const chai = require('chai')
const assert = chai.assert
const sinon = require('sinon')
const BCHJS = require('../../../../src/bch-js')
const bchjs = new BCHJS({ ninsightURL: 'https://trest.bitcoin.com/v2' })
describe('#Ninsight', () => {
let sandbox
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
sandbox = sinon.createSandbox()
})
afterEach(() => sandbox.restore())
describe('#utxo', () => {
it('should GET utxos for a single address', async () => {
const addr = 'bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr'
const result = await bchjs.Ninsight.utxo(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result[0], 'utxos')
assert.property(result[0], 'legacyAddress')
assert.property(result[0], 'cashAddress')
assert.property(result[0], 'slpAddress')
assert.property(result[0], 'scriptPubKey')
assert.property(result[0], 'asm')
assert.isArray(result[0].utxos)
assert.property(result[0].utxos[0], 'txid')
assert.property(result[0].utxos[0], 'vout')
assert.property(result[0].utxos[0], 'amount')
assert.property(result[0].utxos[0], 'satoshis')
assert.property(result[0].utxos[0], 'height')
assert.property(result[0].utxos[0], 'confirmations')
})
it('should POST utxo details for an array of addresses', async () => {
const addr = [
'bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr',
'bchtest:qp6hgvevf4gzz6l7pgcte3gaaud9km0l459fa23dul'
]
const result = await bchjs.Ninsight.utxo(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.isArray(result[0].utxos)
assert.property(result[0], 'utxos')
assert.property(result[0], 'legacyAddress')
assert.property(result[0], 'cashAddress')
assert.property(result[0], 'slpAddress')
assert.property(result[0], 'scriptPubKey')
assert.property(result[0], 'asm')
// assert.hasAnyKeys(result[0][0], [
// "txid",
// "vout",
// "value",
// "height",
// "confirmations"
// ])
})
})
describe('#transactions', () => {
it('should POST transactions history for a single address', async () => {
const addr = 'bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr'
const result = await bchjs.Ninsight.transactions(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], 'cashAddress')
assert.property(result[0], 'legacyAddress')
assert.property(result[0], 'txs')
assert.isArray(result[0].txs)
assert.property(result[0].txs[0], 'txid')
assert.property(result[0].txs[0], 'vin')
assert.property(result[0].txs[0], 'vout')
})
it('should POST transactions history for an array of addresses', async () => {
const addr = [
'bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr',
'bchtest:qp6hgvevf4gzz6l7pgcte3gaaud9km0l459fa23dul'
]
const result = await bchjs.Ninsight.transactions(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], 'cashAddress')
assert.property(result[0], 'legacyAddress')
assert.property(result[0], 'txs')
assert.isArray(result[0].txs)
assert.property(result[0].txs[0], 'txid')
assert.property(result[0].txs[0], 'vin')
assert.property(result[0].txs[0], 'vout')
})
})
describe('#txDetails', () => {
it('should POST transactions details for a single address', async () => {
const txid =
'76856d82e00b2696acd8d989e1fa6c46b431005046a285ce905814cac0ff8fea'
const result = await bchjs.Ninsight.txDetails(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], 'txid')
assert.property(result[0], 'version')
assert.property(result[0], 'locktime')
assert.property(result[0], 'vin')
assert.property(result[0], 'vout')
assert.property(result[0], 'blockhash')
assert.property(result[0], 'blockheight')
assert.property(result[0], 'confirmations')
assert.property(result[0], 'time')
assert.property(result[0], 'blocktime')
assert.property(result[0], 'valueOut')
assert.property(result[0], 'size')
})
it('should POST transactions details for an array of addresses', async () => {
const txid = [
'f191d1062789d7071da6f2168ba306869a829294f6b1c09d03492db4ca3a8e77',
'76856d82e00b2696acd8d989e1fa6c46b431005046a285ce905814cac0ff8fea'
]
const result = await bchjs.Ninsight.txDetails(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], 'txid')
assert.property(result[0], 'vin')
assert.property(result[0], 'vout')
})
})
})
function sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
@@ -5,154 +5,143 @@
TODO
*/
const chai = require("chai")
const chai = require('chai')
const assert = chai.assert
const RESTURL = process.env.RESTURL
? process.env.RESTURL
: `https://tapi.fullstack.cash/v3/`
: 'https://testnet3.fullstack.cash/v4/'
// if (process.env.RESTURL) RESTURL = process.env.RESTURL
const BCHJS = require("../../../src/bch-js")
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v3/` })
const BCHJS = require('../../../../src/bch-js')
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v4/` })
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
// Inspect utility used for debugging.
const util = require("util")
const util = require('util')
util.inspect.defaultOptions = {
showHidden: true,
colors: true,
depth: 3
}
describe("#rawtransaction", () => {
describe("#decodeRawTransaction", () => {
it("should decode tx for a single hex", async () => {
describe('#rawtransaction', () => {
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
describe('#decodeRawTransaction', () => {
it('should decode tx for a single hex', async () => {
const hex =
"0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
'0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000'
const result = await bchjs.RawTransactions.decodeRawTransaction(hex)
//console.log(`result ${JSON.stringify(result, null, 2)}`)
// console.log(`result ${JSON.stringify(result, null, 2)}`)
assert.hasAnyKeys(result, [
"txid",
"hash",
"size",
"version",
"locktime",
"vin",
"vout"
'txid',
'hash',
'size',
'version',
'locktime',
'vin',
'vout'
])
assert.isArray(result.vin)
assert.isArray(result.vout)
})
it("should decode an array of tx hexes", async () => {
it('should decode an array of tx hexes', async () => {
const hexes = [
"0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000",
"0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
'0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000',
'0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000'
]
const result = await bchjs.RawTransactions.decodeRawTransaction(hexes)
//console.log(`result ${JSON.stringify(result, null, 2)}`)
// console.log(`result ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.hasAnyKeys(result[0], [
"txid",
"hash",
"size",
"version",
"locktime",
"vin",
"vout"
'txid',
'hash',
'size',
'version',
'locktime',
'vin',
'vout'
])
assert.isArray(result[0].vin)
assert.isArray(result[0].vout)
})
it(`should throw an error for improper single input`, async () => {
try {
const addr = 12345
await bchjs.RawTransactions.decodeRawTransaction(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(
err.message,
`Input must be a string or array of strings.`
)
}
})
it(`should throw error on array size rate limit`, async () => {
it('should throw error on array size rate limit', async () => {
try {
const data = []
for (let i = 0; i < 25; i++) {
data.push(
"0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
'0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000'
)
}
const result = await bchjs.RawTransactions.decodeRawTransaction(data)
console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
assert.hasAnyKeys(err, ['error'])
assert.include(err.error, 'Array too large')
}
})
})
describe("#getRawTransaction", () => {
it("should decode a single txid, with concise output", async () => {
describe('#getRawTransaction', () => {
it('should decode a single txid, with concise output', async () => {
const txid =
"1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04"
'1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04'
const verbose = false
const result = await bchjs.RawTransactions.getRawTransaction(
txid,
verbose
)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isString(result)
})
it("should decode a single txid, with verbose output", async () => {
it('should decode a single txid, with verbose output', async () => {
const txid =
"1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04"
'1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04'
const verbose = true
const result = await bchjs.RawTransactions.getRawTransaction(
txid,
verbose
)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAnyKeys(result, [
"hex",
"txid",
"hash",
"size",
"version",
"locktime",
"vin",
"vout",
"blockhash",
"confirmations",
"time",
"blocktime"
'hex',
'txid',
'hash',
'size',
'version',
'locktime',
'vin',
'vout',
'blockhash',
'confirmations',
'time',
'blocktime'
])
assert.isArray(result.vin)
assert.isArray(result.vout)
})
it("should decode an array of txids, with a concise output", async () => {
it('should decode an array of txids, with a concise output', async () => {
const txid = [
"1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04",
"1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04"
'1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04',
'1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04'
]
const verbose = false
@@ -160,16 +149,16 @@ describe("#rawtransaction", () => {
txid,
verbose
)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.isString(result[0])
})
it("should decode an array of txids, with a verbose output", async () => {
it('should decode an array of txids, with a verbose output', async () => {
const txid = [
"1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04",
"1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04"
'1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04',
'1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04'
]
const verbose = true
@@ -177,54 +166,54 @@ describe("#rawtransaction", () => {
txid,
verbose
)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.hasAnyKeys(result[0], [
"hex",
"txid",
"hash",
"size",
"version",
"locktime",
"vin",
"vout",
"blockhash",
"confirmations",
"time",
"blocktime"
'hex',
'txid',
'hash',
'size',
'version',
'locktime',
'vin',
'vout',
'blockhash',
'confirmations',
'time',
'blocktime'
])
assert.isArray(result[0].vin)
assert.isArray(result[0].vout)
})
it(`should throw error on array size limit`, async () => {
it('should throw error on array size limit', async () => {
try {
const dataMock =
"1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04"
'1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04'
const data = []
for (let i = 0; i < 25; i++) data.push(dataMock)
const result = await bchjs.RawTransactions.getRawTransaction(data)
console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
assert.hasAnyKeys(err, ['error'])
assert.include(err.error, 'Array too large')
}
})
})
describe("#decodeScript", () => {
it("should decode script for a single hex", async () => {
describe('#decodeScript', () => {
it('should decode script for a single hex', async () => {
const hex =
"4830450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed592012102e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16"
'4830450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed592012102e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16'
const result = await bchjs.RawTransactions.decodeScript(hex)
//console.log(`result ${JSON.stringify(result, null, 2)}`)
// console.log(`result ${JSON.stringify(result, null, 2)}`)
assert.hasAllKeys(result, ["asm", "type", "p2sh"])
assert.hasAllKeys(result, ['asm', 'type', 'p2sh'])
})
// CT 2/20/19 - Waiting for this PR to be merged complete the test:
@@ -239,22 +228,6 @@ describe("#rawtransaction", () => {
const result = await bchjs.RawTransactions.decodeScript(hexes)
console.log(`result ${JSON.stringify(result, null, 2)}`)
})
*/
/*
it(`should throw an error for improper single input`, async () => {
try {
const addr = 12345
await bchjs.RawTransactions.decodeRawTransaction(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(
err.message,
`Input must be a string or array of strings.`
)
}
})
*/
})
@@ -264,29 +237,29 @@ describe("#rawtransaction", () => {
below expect error messages returned from the server, but at least test
that the server is responding on those endpoints, and responds consistently.
*/
describe("sendRawTransaction", () => {
it("should send a single transaction hex", async () => {
describe('sendRawTransaction', () => {
it('should send a single transaction hex', async () => {
try {
const hex =
"01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000"
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000'
await bchjs.RawTransactions.sendRawTransaction(hex)
//console.log(`result ${JSON.stringify(result, null, 2)}`)
// console.log(`result ${JSON.stringify(result, null, 2)}`)
assert.equal(true, false, "Unexpected result!")
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
//console.log(`err: ${util.inspect(err)}`)
// console.log(`err: ${util.inspect(err)}`)
assert.hasAllKeys(err, ["error"])
assert.include(err.error, "Missing inputs")
assert.hasAllKeys(err, ['error'])
assert.include(err.error, 'Missing inputs')
}
})
it("should send an array of tx hexes", async () => {
it('should send an array of tx hexes', async () => {
try {
const hexes = [
"01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000",
"01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000"
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000',
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000'
]
const result = await bchjs.RawTransactions.sendRawTransaction(hexes)
@@ -294,41 +267,30 @@ describe("#rawtransaction", () => {
} catch (err) {
// console.log(`err: ${util.inspect(err)}`)
assert.hasAllKeys(err, ["error"])
assert.include(err.error, "Missing inputs")
assert.hasAllKeys(err, ['error'])
assert.include(err.error, 'Missing inputs')
}
})
it(`should throw an error for improper single input`, async () => {
try {
const addr = 12345
await bchjs.RawTransactions.sendRawTransaction(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(
err.message,
`Input hex must be a string or array of strings`
)
}
})
it(`should throw error on array size rate limit`, async () => {
it('should throw error on array size rate limit', async () => {
try {
const dataMock =
"01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000"
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000'
const data = []
for (let i = 0; i < 25; i++) data.push(dataMock)
const result = await bchjs.RawTransactions.sendRawTransaction(data)
console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
assert.hasAnyKeys(err, ['error'])
assert.include(err.error, 'Array too large')
}
})
})
})
function sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
+172
View File
@@ -0,0 +1,172 @@
/*
Integration tests for the bchjs covering SLP tokens.
*/
const chai = require('chai')
const assert = chai.assert
const RESTURL = process.env.RESTURL
? process.env.RESTURL
: 'https://testnet3.fullstack.cash/v4/'
// if (process.env.RESTURL) RESTURL = process.env.RESTURL
const BCHJS = require('../../../../src/bch-js')
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v4/` })
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
// Inspect utility used for debugging.
const util = require('util')
util.inspect.defaultOptions = {
showHidden: true,
colors: true,
depth: 1
}
describe('#SLP', () => {
beforeEach(async () => {
// Introduce a delay so that the BVT doesn't trip the rate limits.
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
describe('#util', () => {
it('should get information on the Oasis token', async () => {
const tokenId =
'a371e9934c7695d08a5eb7f31d3bceb4f3644860cc67520cda1e149423b9ec39'
const result = await bchjs.SLP.Utils.list(tokenId)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAnyKeys(result, [
'decimals',
'timestamp',
'timestamp_unix',
'versionType',
'documentUri',
'symbol',
'name',
'containsBaton',
'id',
'documentHash',
'initialTokenQty',
'blockCreated',
'blockLastActiveSend',
'blockLastActiveMint',
'txnsSinceGenesis',
'validAddress',
'totalMinted',
'totalBurned',
'circulatingSupply',
'mintingBatonStatus'
])
})
})
describe('#decodeOpReturn', () => {
it('should decode the OP_RETURN for a SEND txid', async () => {
const txid =
'ad28116e0818339342dddfc5f58ca8a5379ceb9679b4e4cbd72f4de905415ec1'
const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAllKeys(result, ['amounts', 'tokenType', 'tokenId', 'txType'])
})
})
describe('#balancesForAddress', () => {
it('should fetch all balances for address: slptest:qz0kc67pm4emjyr3gaaa2wstdaykg9m4yqwlzpj3w9', async () => {
const balances = await bchjs.SLP.Utils.balancesForAddress(
'slptest:qz0kc67pm4emjyr3gaaa2wstdaykg9m4yqwlzpj3w9'
)
// console.log(`balances: ${JSON.stringify(balances, null, 2)}`)
assert.isArray(balances)
assert.hasAllKeys(balances[0], [
'tokenId',
'balanceString',
'balance',
'decimalCount',
'slpAddress'
])
})
it('should fetch balances for multiple addresses', async () => {
const addresses = [
'slptest:qz0kc67pm4emjyr3gaaa2wstdaykg9m4yqwlzpj3w9',
'slptest:qr5uy4h8ysyhwkp9s245scckdnc7teyjqc5ft2z43h'
]
const balances = await bchjs.SLP.Utils.balancesForAddress(addresses)
// console.log(`balances: ${JSON.stringify(balances, null, 2)}`)
assert.isArray(balances)
assert.isArray(balances[0])
assert.hasAllKeys(balances[0][0], [
'tokenId',
'balanceString',
'balance',
'decimalCount',
'slpAddress'
])
})
})
describe('#tokenUtxoDetails', () => {
it('should hydrate UTXOs', async () => {
const bchAddr = bchjs.SLP.Address.toCashAddress(
'slptest:qz0kc67pm4emjyr3gaaa2wstdaykg9m4yqwlzpj3w9'
)
const utxos = await bchjs.Electrumx.utxo([bchAddr])
// console.log(`utxos: ${JSON.stringify(utxos, null, 2)}`)
const utxoInfo = await bchjs.SLP.Utils.tokenUtxoDetails(
utxos.utxos[0].utxos
)
// console.log(`utxoInfo: ${JSON.stringify(utxoInfo, null, 2)}`)
assert.isArray(utxoInfo)
// first UTXO should be a PSF test token.
assert.equal(utxoInfo[0].isValid, true)
})
})
describe('#hydrateUtxos', () => {
// This test will error out if the LOCAL_RESTURL settings is not set properly
// in bch-api.
it('should hydrate UTXOs', async () => {
const bchAddr = bchjs.SLP.Address.toCashAddress(
'slptest:qz0kc67pm4emjyr3gaaa2wstdaykg9m4yqwlzpj3w9'
)
const utxos = await bchjs.Electrumx.utxo([bchAddr])
// console.log(`utxos: ${JSON.stringify(utxos, null, 2)}`)
const utxoInfo = await bchjs.SLP.Utils.hydrateUtxos(utxos.utxos)
// console.log(`utxoInfo: ${JSON.stringify(utxoInfo, null, 2)}`)
assert.isArray(utxoInfo.slpUtxos[0].utxos)
// first UTXO should be a PSF test token.
assert.equal(utxoInfo.slpUtxos[0].utxos[0].isValid, true)
})
})
describe('#validateTxid2', () => {
it('should validate a token txid', async () => {
const txid =
'ad28116e0818339342dddfc5f58ca8a5379ceb9679b4e4cbd72f4de905415ec1'
const validated = await bchjs.SLP.Utils.validateTxid(txid)
// console.log(validated)
assert.equal(validated[0].valid, true)
})
})
})
// Promise-based sleep function
function sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
+9
View File
@@ -0,0 +1,9 @@
#!/bin/bash
export RESTURL=https://free-test.fullstack.cash/v4/
export NETWORK=testnet
export IS_USING_FREE_TIER=true
cd test/integration/testnet/
mocha --timeout 30000 blockchain.js control.js electrumx.js rawtransaction.js slp.js util.js
#mocha --timeout 30000 blockchain.js
+109
View File
@@ -0,0 +1,109 @@
/*
Integration tests for the bchjs. Only covers calls made to
rest.bitcoin.com.
*/
const chai = require('chai')
const assert = chai.assert
const RESTURL = process.env.RESTURL
? process.env.RESTURL
: 'https://testnet3.fullstack.cash/v4/'
// if (process.env.RESTURL) RESTURL = process.env.RESTURL
const BCHJS = require('../../../../src/bch-js')
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v4/` })
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
// Inspect utility used for debugging.
const util = require('util')
util.inspect.defaultOptions = {
showHidden: true,
colors: true,
depth: 3
}
describe('#util', () => {
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
describe('#validateAddress', () => {
it('should return false for testnet addr on mainnet', async () => {
const address = 'bitcoincash:qp4k8fjtgunhdr7yq30ha4peu'
const result = await bchjs.Util.validateAddress(address)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAllKeys(result, ['isvalid'])
assert.equal(result.isvalid, false)
})
it('should return false for bad address', async () => {
const address = 'bchtest:qqqk4y6lsl5da64sg53xezmplyu5kmpyz2ysaa5y'
const result = await bchjs.Util.validateAddress(address)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAllKeys(result, ['isvalid'])
assert.equal(result.isvalid, false)
})
it('should validate valid address', async () => {
const address = 'bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y'
const result = await bchjs.Util.validateAddress(address)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAnyKeys(result, [
'isvalid',
'address',
'scriptPubKey',
// "ismine",
// "iswatchonly",
'isscript'
])
assert.equal(result.isvalid, true)
})
it('should validate an array of addresses', async () => {
const address = [
'bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y',
'bchtest:pq6k9969f6v6sg7a75jkru4n7wn9sknv5cztcp0dnh'
]
const result = await bchjs.Util.validateAddress(address)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.hasAnyKeys(result[0], [
'isvalid',
'address',
'scriptPubKey',
// "ismine",
// "iswatchonly",
'isscript'
])
})
it('should throw error on array size rate limit', async () => {
try {
const dataMock = 'bchtest:pq6k9969f6v6sg7a75jkru4n7wn9sknv5cztcp0dnh'
const data = []
for (let i = 0; i < 25; i++) data.push(dataMock)
const result = await bchjs.Util.validateAddress(data)
console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
assert.hasAnyKeys(err, ['error'])
assert.include(err.error, 'Array too large')
}
})
})
})
function sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
+14 -6
View File
@@ -2,18 +2,26 @@
Integration tests for bchjs control library.
*/
const chai = require("chai")
const chai = require('chai')
const assert = chai.assert
const BCHJS = require("../../src/bch-js")
const BCHJS = require('../../src/bch-js')
const bchjs = new BCHJS()
describe(`#control`, () => {
describe(`#getNetworkInfo`, () => {
it("should get info on the full node", async () => {
describe('#control', () => {
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
describe('#getNetworkInfo', () => {
it('should get info on the full node', async () => {
const result = await bchjs.Control.getNetworkInfo()
console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "version")
assert.property(result, 'version')
})
})
})
function sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
+212 -88
View File
@@ -1,185 +1,193 @@
const chai = require("chai")
const chai = require('chai')
const assert = chai.assert
const sinon = require("sinon")
const sinon = require('sinon')
const BCHJS = require("../../src/bch-js")
const BCHJS = require('../../src/bch-js')
const bchjs = new BCHJS()
describe(`#ElectrumX`, () => {
describe('#ElectrumX', () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
beforeEach(async () => {
sandbox = sinon.createSandbox()
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
afterEach(() => sandbox.restore())
describe(`#utxo`, () => {
it(`should GET utxos for a single address`, async () => {
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
describe('#utxo', () => {
it('should GET utxos for a single address', async () => {
const addr = 'bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9'
const result = await bchjs.Electrumx.utxo(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, "utxos")
assert.property(result, 'utxos')
assert.isArray(result.utxos)
assert.property(result.utxos[0], "height")
assert.property(result.utxos[0], "tx_hash")
assert.property(result.utxos[0], "tx_pos")
assert.property(result.utxos[0], "value")
assert.property(result.utxos[0], 'height')
assert.property(result.utxos[0], 'tx_hash')
assert.property(result.utxos[0], 'tx_pos')
assert.property(result.utxos[0], 'value')
})
it(`should POST request for UTXOs for an array of addresses`, async () => {
it('should POST request for UTXOs for an array of addresses', async () => {
const addr = [
"bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
"bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf',
'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v'
]
const result = await bchjs.Electrumx.utxo(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, "utxos")
assert.property(result, 'utxos')
assert.isArray(result.utxos)
assert.property(result.utxos[0], "utxos")
assert.property(result.utxos[0], 'utxos')
assert.isArray(result.utxos[0].utxos)
assert.property(result.utxos[0], "address")
assert.property(result.utxos[0], 'address')
assert.property(result.utxos[0].utxos[0], "height")
assert.property(result.utxos[0].utxos[0], "tx_hash")
assert.property(result.utxos[0].utxos[0], "tx_pos")
assert.property(result.utxos[0].utxos[0], "value")
assert.property(result.utxos[0].utxos[0], 'height')
assert.property(result.utxos[0].utxos[0], 'tx_hash')
assert.property(result.utxos[0].utxos[0], 'tx_pos')
assert.property(result.utxos[0].utxos[0], 'value')
})
it(`should throw error on array size rate limit`, async () => {
it('should throw error on array size rate limit', async () => {
try {
const addr = []
for (let i = 0; i < 25; i++)
addr.push("bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf")
for (let i = 0; i < 25; i++) { addr.push('bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf') }
const result = await bchjs.Electrumx.utxo(addr)
// const result = await bchjs.Electrumx.utxo(addr)
await bchjs.Electrumx.utxo(addr)
console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
// console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
assert.hasAnyKeys(err, ['error'])
assert.include(err.error, 'Array too large')
}
})
})
describe(`#balance`, () => {
it(`should GET balance for a single address`, async () => {
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
describe('#balance', () => {
it('should GET balance for a single address', async () => {
const addr = 'bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9'
const result = await bchjs.Electrumx.balance(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, "balance")
assert.property(result.balance, "confirmed")
assert.property(result.balance, "unconfirmed")
assert.property(result, 'balance')
assert.property(result.balance, 'confirmed')
assert.property(result.balance, 'unconfirmed')
})
it(`should POST request for balances for an array of addresses`, async () => {
it('should POST request for balances for an array of addresses', async () => {
const addr = [
"bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
"bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf',
'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v'
]
const result = await bchjs.Electrumx.balance(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, "balances")
assert.property(result, 'balances')
assert.isArray(result.balances)
assert.property(result.balances[0], "address")
assert.property(result.balances[0], "balance")
assert.property(result.balances[0].balance, "confirmed")
assert.property(result.balances[0].balance, "unconfirmed")
assert.property(result.balances[0], 'address')
assert.property(result.balances[0], 'balance')
assert.property(result.balances[0].balance, 'confirmed')
assert.property(result.balances[0].balance, 'unconfirmed')
})
it(`should throw error on array size rate limit`, async () => {
it('should throw error on array size rate limit', async () => {
try {
const addr = []
for (let i = 0; i < 25; i++)
addr.push("bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf")
for (let i = 0; i < 25; i++) { addr.push('bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf') }
const result = await bchjs.Electrumx.balance(addr)
// const result = await bchjs.Electrumx.balance(addr)
// console.log(`result: ${util.inspect(result)}`)
console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
await bchjs.Electrumx.balance(addr)
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
assert.hasAnyKeys(err, ['error'])
assert.include(err.error, 'Array too large')
}
})
})
describe(`#transactions`, () => {
it(`should GET transaction history for a single address`, async () => {
const addr = "bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
describe('#transactions', () => {
it('should GET transaction history for a single address', async () => {
const addr = 'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v'
const result = await bchjs.Electrumx.transactions(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, "transactions")
assert.property(result, 'transactions')
assert.isArray(result.transactions)
assert.property(result.transactions[0], "height")
assert.property(result.transactions[0], "tx_hash")
assert.property(result.transactions[0], 'height')
assert.property(result.transactions[0], 'tx_hash')
})
it(`should POST request for transaction history for an array of addresses`, async () => {
it('should POST request for transaction history for an array of addresses', async () => {
const addr = [
"bitcoincash:qrl2nlsaayk6ekxn80pq0ks32dya8xfclyktem2mqj",
"bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
'bitcoincash:qrl2nlsaayk6ekxn80pq0ks32dya8xfclyktem2mqj',
'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v'
]
const result = await bchjs.Electrumx.transactions(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, "transactions")
assert.property(result, 'transactions')
assert.isArray(result.transactions)
assert.property(result.transactions[0], "address")
assert.property(result.transactions[0], "transactions")
assert.property(result.transactions[0], 'address')
assert.property(result.transactions[0], 'transactions')
assert.isArray(result.transactions[0].transactions)
assert.property(result.transactions[0].transactions[0], "height")
assert.property(result.transactions[0].transactions[0], "tx_hash")
assert.property(result.transactions[0].transactions[0], 'height')
assert.property(result.transactions[0].transactions[0], 'tx_hash')
})
it(`should throw error on array size rate limit`, async () => {
it('should throw error on array size rate limit', async () => {
try {
const addr = []
for (let i = 0; i < 25; i++)
addr.push("bitcoincash:qrehqueqhw629p6e57994436w730t4rzasnly00ht0")
for (let i = 0; i < 25; i++) { addr.push('bitcoincash:qrehqueqhw629p6e57994436w730t4rzasnly00ht0') }
const result = await bchjs.Electrumx.transactions(addr)
// const result = await bchjs.Electrumx.transactions(addr)
// console.log(`result: ${util.inspect(result)}`)
console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
await bchjs.Electrumx.transactions(addr)
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
assert.hasAnyKeys(err, ['error'])
assert.include(err.error, 'Array too large')
}
})
})
describe(`#unconfirmed`, () => {
describe('#unconfirmed', () => {
// These tests won't work because unconfirmed transactions are transient in nature.
/*
it(`should GET unconfirmed UTXOs (mempool) for a single address`, async () => {
@@ -224,20 +232,136 @@ describe(`#ElectrumX`, () => {
})
*/
it(`should throw error on array size rate limit`, async () => {
it('should throw error on array size rate limit', async () => {
try {
const addr = []
for (let i = 0; i < 25; i++)
addr.push("bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf")
for (let i = 0; i < 25; i++) { addr.push('bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf') }
await bchjs.Electrumx.unconfirmed(addr)
// console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
assert.hasAnyKeys(err, ['error'])
assert.include(err.error, 'Array too large')
}
})
})
describe('#blockHeader', () => {
it('should GET block headers for given height and count', async () => {
const height = 42
const count = 2
const result = await bchjs.Electrumx.blockHeader(height, count)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, 'headers')
assert.isArray(result.headers)
assert.equal(result.headers.length, 2)
})
it('should GET block headers for given height with default count = 1', async () => {
const height = 42
const result = await bchjs.Electrumx.blockHeader(height)
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, 'headers')
assert.isArray(result.headers)
assert.equal(result.headers.length, 1)
})
})
describe('#txData', () => {
it('should GET details for a single transaction', async () => {
const txid =
'4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251'
const result = await bchjs.Electrumx.txData(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, 'details')
assert.isObject(result.details)
assert.property(result.details, 'blockhash')
assert.property(result.details, 'hash')
assert.property(result.details, 'hex')
assert.property(result.details, 'vin')
assert.property(result.details, 'vout')
assert.equal(result.details.hash, txid)
})
it('should POST details for an array of transactions', async () => {
const txids = [
'4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251',
'4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251'
]
const result = await bchjs.Electrumx.txData(txids)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, 'transactions')
assert.isArray(result.transactions)
assert.property(result.transactions[0], 'txid')
assert.property(result.transactions[0], 'details')
assert.property(result.transactions[0].details, 'blockhash')
assert.property(result.transactions[0].details, 'hash')
assert.property(result.transactions[0].details, 'hex')
assert.property(result.transactions[0].details, 'vin')
assert.property(result.transactions[0].details, 'vout')
})
it('should throw error on array size rate limit', async () => {
try {
const txids = []
for (let i = 0; i < 25; i++) {
txids.push(
'4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251'
)
}
await bchjs.Electrumx.txData(txids)
// console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
assert.hasAnyKeys(err, ['error'])
assert.include(err.error, 'Array too large')
}
})
})
describe('#broadcast', () => {
it('should broadcast a single transaction', async () => {
const txHex =
'020000000265d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667010000006441dd1dd72770cadede1a7fd0363574846c48468a398ddfa41a9677c74cac8d2652b682743725a3b08c6c2021a629011e11a264d9036e9d5311e35b5f4937ca7b4e4121020797d8fd4d2fa6fd7cdeabe2526bfea2b90525d6e8ad506ec4ee3c53885aa309ffffffff65d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667000000006441347d7f218c11c04487c1ad8baac28928fb10e5054cd4494b94d078cfa04ccf68e064fb188127ff656c0b98e9ce87f036d183925d0d0860605877d61e90375f774121028a53f95eb631b460854fc836b2e5d31cad16364b4dc3d970babfbdcc3f2e4954ffffffff035ac355000000000017a914189ce02e332548f4804bac65cba68202c9dbf822878dfd0800000000001976a914285bb350881b21ac89724c6fb6dc914d096cd53b88acf9ef3100000000001976a91445f1f1c4a9b9419a5088a3e9c24a293d7a150e6488ac00000000'
try {
await bchjs.Electrumx.broadcast(txHex)
} catch (err) {
assert.property(err, 'success')
assert.equal(err.success, false)
assert.include(
err.error,
'the transaction was rejected by network rules'
)
}
})
})
})
function sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
+21 -13
View File
@@ -1,31 +1,39 @@
const assert = require("chai").assert
const assert = require('chai').assert
const BCHJS = require("../../src/bch-js")
const BCHJS = require('../../src/bch-js')
const bchjs = new BCHJS()
describe("#Encryption", () => {
describe("#getPubKey", () => {
it("should get a public key", async () => {
const addr = "bitcoincash:qpf8jv9hmqcda0502gjp7nm3g24y5h5s4unutghsxq"
describe('#Encryption', () => {
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
describe('#getPubKey', () => {
it('should get a public key', async () => {
const addr = 'bitcoincash:qpf8jv9hmqcda0502gjp7nm3g24y5h5s4unutghsxq'
const result = await bchjs.encryption.getPubKey(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, "publicKey")
assert.property(result, 'publicKey')
})
it("should report when public key can not be found", async () => {
const addr = "bitcoincash:qrgqqkky28jdkv3w0ctrah0mz3jcsnsklc34gtukrh"
it('should report when public key can not be found', async () => {
const addr = 'bitcoincash:qrgqqkky28jdkv3w0ctrah0mz3jcsnsklc34gtukrh'
const result = await bchjs.encryption.getPubKey(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.property(result, 'success')
assert.equal(result.success, false)
assert.property(result, "publicKey")
assert.equal(result.publicKey, "not found")
assert.property(result, 'publicKey')
assert.equal(result.publicKey, 'not found')
})
})
})
function sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
@@ -0,0 +1,71 @@
/*
Integration tests for the bchjs. Only covers calls made to
rest.bitcoin.com.
TODO
*/
const chai = require('chai')
const assert = chai.assert
const BCHJS = require('../../../../src/bch-js')
const bchjs = new BCHJS()
// Inspect utility used for debugging.
const util = require('util')
util.inspect.defaultOptions = {
showHidden: true,
colors: true,
depth: 3
}
describe('#rawtransaction', () => {
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
/*
Testing sentRawTransaction isn't really possible with an integration test,
as the endpoint really needs an e2e test to be properly tested. The tests
below expect error messages returned from the server, but at least test
that the server is responding on those endpoints, and responds consistently.
*/
describe('sendRawTransaction', () => {
it('should send a single transaction hex', async () => {
try {
const hex =
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000'
await bchjs.RawTransactions.sendRawTransaction(hex)
// console.log(`result ${JSON.stringify(result, null, 2)}`)
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
// console.log(`err: ${util.inspect(err)}`)
assert.hasAllKeys(err, ['error'])
assert.include(err.error, 'Missing inputs')
}
})
it('should send an array of tx hexes', async () => {
try {
const hexes = [
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000',
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000'
]
const result = await bchjs.RawTransactions.sendRawTransaction(hexes)
console.log(`result ${JSON.stringify(result, null, 2)}`)
} catch (err) {
// console.log(`err: ${util.inspect(err)}`)
assert.hasAllKeys(err, ['error'])
assert.include(err.error, 'Missing inputs')
}
})
})
})
function sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
@@ -0,0 +1,246 @@
/*
Integration tests for the bchjs covering SLP tokens.
These tests are specific to the ABC chain.
*/
const chai = require('chai')
const assert = chai.assert
const BCHJS = require('../../../../src/bch-js')
let bchjs
// Inspect utility used for debugging.
const util = require('util')
util.inspect.defaultOptions = {
showHidden: true,
colors: true,
depth: 1
}
describe('#SLP', () => {
// before(() => {
// console.log(`bchjs.SLP.restURL: ${bchjs.SLP.restURL}`)
// console.log(`bchjs.SLP.apiToken: ${bchjs.SLP.apiToken}`)
// })
beforeEach(async () => {
// Introduce a delay so that the BVT doesn't trip the rate limits.
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
bchjs = new BCHJS()
})
describe('#util', () => {
describe('#tokenUtxoDetails', () => {
it('should handle a range of UTXO types', async () => {
const utxos = [
// Malformed SLP tx
{
note: 'Malformed SLP tx',
tx_hash:
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a',
tx_pos: 1,
value: 546
},
// Normal TX (non-SLP)
{
note: 'Normal TX (non-SLP)',
tx_hash:
'01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0',
tx_pos: 0,
value: 400000
},
// Valid PSF SLP tx
{
note: 'Valid PSF SLP tx',
tx_hash:
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd',
tx_pos: 1,
value: 546
},
// Valid SLP token not in whitelist
{
note: 'Valid SLP token not in whitelist',
tx_hash:
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488',
tx_pos: 1,
value: 546
},
// Token send on BCHN network.
{
note: 'Token send on BCHN network',
tx_hash:
'402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019',
tx_pos: 1,
value: 546
},
// Token send on ABC network.
{
note: 'Token send on ABC network',
tx_hash:
'336bfe2168aac4c3303508a9e8548a0d33797a83b85b76a12d845c8d6674f79d',
tx_pos: 1,
value: 546
},
// Known invalid SLP token send of PSF tokens.
{
note: 'Known invalid SLP token send of PSF tokens',
tx_hash:
'2bf691ad3679d928fef880b8a45b93b233f8fa0d0a92cf792313dbe77b1deb74',
tx_pos: 1,
value: 546
}
]
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
// Malformed SLP tx
assert.equal(data[0].tx_hash, utxos[0].tx_hash)
assert.equal(data[0].isValid, false)
// Normal TX (non-SLP)
assert.equal(data[1].tx_hash, utxos[1].tx_hash)
assert.equal(data[1].isValid, false)
// Valid PSF SLP tx
assert.equal(data[2].tx_hash, utxos[2].tx_hash)
assert.equal(data[2].isValid, true)
// Valid SLP token not in whitelist
assert.equal(data[3].tx_hash, utxos[3].tx_hash)
assert.equal(data[3].isValid, true)
// Token send on BCHN network
assert.equal(data[4].tx_hash, utxos[4].tx_hash)
assert.equal(data[4].isValid, true)
// Token send on ABC network
assert.equal(data[5].tx_hash, utxos[5].tx_hash)
assert.equal(data[5].isValid, null)
// Known invalid SLP token send of PSF tokens
assert.equal(data[6].tx_hash, utxos[6].tx_hash)
assert.equal(data[6].isValid, false)
})
})
describe('#validateTxid3', () => {
it('should invalidate a known invalid TXID', async () => {
const txid =
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a'
const result = await bchjs.SLP.Utils.validateTxid3(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], 'txid')
assert.equal(result[0].txid, txid)
assert.property(result[0], 'valid')
assert.equal(result[0].valid, null)
})
it('should validate a known valid TXID', async () => {
const txid =
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd'
const result = await bchjs.SLP.Utils.validateTxid3(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], 'txid')
assert.equal(result[0].txid, txid)
assert.property(result[0], 'valid')
assert.equal(result[0].valid, true)
})
it('should handle a mix of valid, invalid, and non-SLP txs', async () => {
const txids = [
// Malformed SLP tx
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a',
// Normal TX (non-SLP)
'01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0',
// Valid PSF SLP tx
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd',
// Valid SLP token not in whitelist
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488',
// Unprocessed SLP TX
'402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019'
]
const result = await bchjs.SLP.Utils.validateTxid3(txids)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.equal(result[0].txid, txids[0])
assert.equal(result[0].valid, null)
assert.equal(result[1].txid, txids[1])
assert.equal(result[1].valid, null)
assert.equal(result[2].txid, txids[2])
assert.equal(result[2].valid, true)
// True in validateTxid()
assert.equal(result[3].txid, txids[3])
assert.equal(result[3].valid, true)
assert.equal(result[4].txid, txids[4])
assert.equal(result[4].valid, true)
})
})
describe('#validateTxid', () => {
it('should handle a mix of valid, invalid, and non-SLP txs', async () => {
const txids = [
// Malformed SLP tx
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a',
// Normal TX (non-SLP)
'01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0',
// Valid PSF SLP tx
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd',
// Valid SLP token not in whitelist
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488',
// Token send on BCHN network.
'402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019',
// Token send on ABC network.
'336bfe2168aac4c3303508a9e8548a0d33797a83b85b76a12d845c8d6674f79d'
]
const result = await bchjs.SLP.Utils.validateTxid(txids)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.equal(result[0].txid, txids[0])
assert.equal(result[0].valid, null)
assert.equal(result[1].txid, txids[1])
assert.equal(result[1].valid, null)
assert.equal(result[2].txid, txids[2])
assert.equal(result[2].valid, true)
// True in validateTxid() but null in validateTxid3()
assert.equal(result[3].txid, txids[3])
assert.equal(result[3].valid, true)
assert.equal(result[4].txid, txids[4])
assert.equal(result[4].valid, true)
assert.equal(result[5].txid, txids[5])
assert.equal(result[5].valid, null)
})
})
})
})
// Promise-based sleep function
function sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
+112 -31
View File
@@ -1,43 +1,49 @@
const chai = require("chai")
const chai = require('chai')
const assert = chai.assert
const sinon = require("sinon")
const sinon = require('sinon')
const BCHJS = require("../../src/bch-js")
const bchjs = new BCHJS({ ninsightURL: "https://rest.bitcoin.com/v2" })
const BCHJS = require('../../src/bch-js')
const bchjs = new BCHJS({ ninsightURL: 'https://rest.bitcoin.com/v2' })
describe(`#Ninsight`, () => {
describe('#Ninsight', () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
beforeEach(async () => {
sandbox = sinon.createSandbox()
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
afterEach(() => sandbox.restore())
describe(`#utxo`, () => {
it(`should GET utxos for a single address`, async () => {
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
describe('#utxo', () => {
it('should GET utxos for a single address', async () => {
const addr = 'bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9'
const result = await bchjs.Ninsight.utxo(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "utxos")
assert.property(result, "legacyAddress")
assert.property(result, "cashAddress")
assert.property(result, "slpAddress")
assert.property(result, "scriptPubKey")
assert.property(result, "asm")
assert.property(result[0], 'utxos')
assert.property(result[0], 'legacyAddress')
assert.property(result[0], 'cashAddress')
assert.property(result[0], 'slpAddress')
assert.property(result[0], 'scriptPubKey')
assert.property(result[0], 'asm')
assert.isArray(result.utxos)
assert.isArray(result[0].utxos)
assert.property(result.utxos[0], "txid")
assert.property(result.utxos[0], "vout")
assert.property(result.utxos[0], "amount")
assert.property(result.utxos[0], "satoshis")
assert.property(result.utxos[0], "height")
assert.property(result.utxos[0], "confirmations")
assert.property(result[0].utxos[0], 'txid')
assert.property(result[0].utxos[0], 'vout')
assert.property(result[0].utxos[0], 'amount')
assert.property(result[0].utxos[0], 'satoshis')
assert.property(result[0].utxos[0], 'height')
assert.property(result[0].utxos[0], 'confirmations')
})
it(`should POST utxo details for an array of addresses`, async () => {
it('should POST utxo details for an array of addresses', async () => {
const addr = [
"bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7",
"bitcoincash:qz0us0z6ucpqt07jgpad0shgh7xmwxyr3ynlcsq0wr"
'bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7',
'bitcoincash:qz0us0z6ucpqt07jgpad0shgh7xmwxyr3ynlcsq0wr'
]
const result = await bchjs.Ninsight.utxo(addr)
@@ -46,12 +52,87 @@ describe(`#Ninsight`, () => {
assert.isArray(result)
assert.isArray(result[0].utxos)
assert.property(result[0], "utxos")
assert.property(result[0], "legacyAddress")
assert.property(result[0], "cashAddress")
assert.property(result[0], "slpAddress")
assert.property(result[0], "scriptPubKey")
assert.property(result[0], "asm")
assert.property(result[0], 'utxos')
assert.property(result[0], 'legacyAddress')
assert.property(result[0], 'cashAddress')
assert.property(result[0], 'slpAddress')
assert.property(result[0], 'scriptPubKey')
assert.property(result[0], 'asm')
})
})
describe('#transactions', () => {
it('should POST transactions history for a single address', async () => {
const addr = 'bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9'
const result = await bchjs.Ninsight.transactions(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], 'cashAddress')
assert.property(result[0], 'legacyAddress')
assert.property(result[0], 'txs')
assert.isArray(result[0].txs)
assert.property(result[0].txs[0], 'txid')
assert.property(result[0].txs[0], 'vin')
assert.property(result[0].txs[0], 'vout')
})
it('should POST transactions history for an array of addresses', async () => {
const addr = [
'bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7',
'bitcoincash:qz0us0z6ucpqt07jgpad0shgh7xmwxyr3ynlcsq0wr'
]
const result = await bchjs.Ninsight.transactions(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], 'cashAddress')
assert.property(result[0], 'legacyAddress')
assert.property(result[0], 'txs')
assert.isArray(result[0].txs)
assert.property(result[0].txs[0], 'txid')
assert.property(result[0].txs[0], 'vin')
assert.property(result[0].txs[0], 'vout')
})
})
describe('#txDetails', () => {
it('should POST transactions details for a single address', async () => {
const txid = 'fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33'
const result = await bchjs.Ninsight.txDetails(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], 'txid')
assert.property(result[0], 'version')
assert.property(result[0], 'locktime')
assert.property(result[0], 'vin')
assert.property(result[0], 'vout')
assert.property(result[0], 'blockhash')
assert.property(result[0], 'blockheight')
assert.property(result[0], 'confirmations')
assert.property(result[0], 'time')
assert.property(result[0], 'blocktime')
assert.property(result[0], 'valueOut')
assert.property(result[0], 'size')
})
it('should POST transactions details for an array of addresses', async () => {
const txid = [
'fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33',
'4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251'
]
const result = await bchjs.Ninsight.txDetails(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], 'txid')
assert.property(result[0], 'vin')
assert.property(result[0], 'vout')
})
})
})
function sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
+49 -77
View File
@@ -2,116 +2,88 @@
tests for OpenBazaar library.
*/
const chai = require("chai")
const chai = require('chai')
const assert = chai.assert
const BCHJS = require("../../src/bch-js")
const BCHJS = require('../../src/bch-js')
const bchjs = new BCHJS()
describe(`#OpenBazaar`, () => {
describe(`#Balance`, () => {
it(`should throw an error for improper input`, async () => {
try {
const addr = 12345
describe('#OpenBazaar', () => {
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
await bchjs.OpenBazaar.balance(addr)
// assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(err.message, `Input address must be a string`)
}
})
it(`should GET balance for a single address`, async () => {
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
describe('#Balance', () => {
it('should GET balance for a single address', async () => {
const addr = 'bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9'
const result = await bchjs.OpenBazaar.balance(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAllKeys(result, [
"page",
"totalPages",
"itemsOnPage",
"addrStr",
"balance",
"totalReceived",
"totalSent",
"unconfirmedBalance",
"unconfirmedTxApperances",
"txApperances",
"transactions"
'page',
'totalPages',
'itemsOnPage',
'addrStr',
'balance',
'totalReceived',
'totalSent',
'unconfirmedBalance',
'unconfirmedTxApperances',
'txApperances',
'transactions'
])
assert.isArray(result.transactions)
})
})
describe(`#utxo`, () => {
it(`should throw an error for improper input`, async () => {
try {
const addr = 12345
await bchjs.OpenBazaar.utxo(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(err.message, `Input address must be a string`)
}
})
it(`should GET utxos for a single address`, async () => {
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
describe('#utxo', () => {
it('should GET utxos for a single address', async () => {
const addr = 'bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9'
const result = await bchjs.OpenBazaar.utxo(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.hasAllKeys(result[0], [
"txid",
"vout",
"amount",
"height",
"confirmations",
"satoshis"
'txid',
'vout',
'amount',
'height',
'confirmations',
'satoshis'
])
})
})
describe(`#tx`, () => {
it(`should throw an error for improper input`, async () => {
try {
const addr = 12345
await bchjs.OpenBazaar.tx(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(err.message, `Input txid must be a string`)
}
})
it(`should GET transactions for a single address`, async () => {
describe('#tx', () => {
it('should GET transactions for a single address', async () => {
const addr =
"2b37bdb3b63dd0bca720437754a36671431a950e684b64c44ea910ea9d5297c7"
'2b37bdb3b63dd0bca720437754a36671431a950e684b64c44ea910ea9d5297c7'
const result = await bchjs.OpenBazaar.tx(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAllKeys(result, [
"txid",
"version",
"vin",
"vout",
"blockhash",
"blockheight",
"confirmations",
"blocktime",
"valueOut",
"valueIn",
"fees",
"hex",
"time"
'txid',
'version',
'vin',
'vout',
'blockhash',
'blockheight',
'confirmations',
'blocktime',
'valueOut',
'valueIn',
'fees',
'hex',
'time'
])
assert.isArray(result.vin)
assert.isArray(result.vout)
})
})
})
function sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
+43 -7
View File
@@ -1,14 +1,50 @@
const assert = require("assert")
const BCHJS = require("../../src/bch-js")
const assert = require('chai').assert
const BCHJS = require('../../src/bch-js')
const bchjs = new BCHJS()
describe("#price", () => {
describe("#current", () => {
describe("#single currency", () => {
it("should get current price for single currency", async () => {
const result = await bchjs.Price.current("usd")
describe('#price', () => {
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
describe('#current', () => {
describe('#single currency', () => {
it('should get current price for single currency', async () => {
const result = await bchjs.Price.current('usd')
assert.notEqual(0, result)
})
})
})
describe('#getUsd', () => {
it('should get the USD price of BCH', async () => {
const result = await bchjs.Price.getUsd()
// console.log(result)
assert.isNumber(result)
})
})
describe('#getBchaUsd', () => {
it('should get the USD price of BCHA', async () => {
const result = await bchjs.Price.getBchaUsd()
console.log(result)
assert.isNumber(result)
})
})
describe('#rates', () => {
it('should get the price of BCH in several currencies', async () => {
const result = await bchjs.Price.rates()
// console.log(result)
assert.property(result, 'USD')
assert.property(result, 'CAD')
})
})
})
function sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
+94 -166
View File
@@ -5,147 +5,136 @@
TODO
*/
const chai = require("chai")
const chai = require('chai')
const assert = chai.assert
const BCHJS = require("../../src/bch-js")
const BCHJS = require('../../src/bch-js')
const bchjs = new BCHJS()
// Inspect utility used for debugging.
const util = require("util")
const util = require('util')
util.inspect.defaultOptions = {
showHidden: true,
colors: true,
depth: 3
}
describe("#rawtransaction", () => {
describe("#decodeRawTransaction", () => {
it("should decode tx for a single hex", async () => {
describe('#rawtransaction', () => {
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
describe('#decodeRawTransaction', () => {
it('should decode tx for a single hex', async () => {
const hex =
"0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
'0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000'
const result = await bchjs.RawTransactions.decodeRawTransaction(hex)
//console.log(`result ${JSON.stringify(result, null, 2)}`)
// console.log(`result ${JSON.stringify(result, null, 2)}`)
assert.hasAnyKeys(result, [
"txid",
"hash",
"size",
"version",
"locktime",
"vin",
"vout"
'txid',
'hash',
'size',
'version',
'locktime',
'vin',
'vout'
])
assert.isArray(result.vin)
assert.isArray(result.vout)
})
it("should decode an array of tx hexes", async () => {
it('should decode an array of tx hexes', async () => {
const hexes = [
"0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000",
"0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
'0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000',
'0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000'
]
const result = await bchjs.RawTransactions.decodeRawTransaction(hexes)
//console.log(`result ${JSON.stringify(result, null, 2)}`)
// console.log(`result ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.hasAnyKeys(result[0], [
"txid",
"hash",
"size",
"version",
"locktime",
"vin",
"vout"
'txid',
'hash',
'size',
'version',
'locktime',
'vin',
'vout'
])
assert.isArray(result[0].vin)
assert.isArray(result[0].vout)
})
it(`should throw an error for improper single input`, async () => {
try {
const addr = 12345
await bchjs.RawTransactions.decodeRawTransaction(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(
err.message,
`Input must be a string or array of strings.`
)
}
})
it(`should throw error on array size rate limit`, async () => {
it('should throw error on array size rate limit', async () => {
try {
const data = []
for (let i = 0; i < 25; i++) {
data.push(
"0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
'0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000'
)
}
const result = await bchjs.RawTransactions.decodeRawTransaction(data)
console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
assert.hasAnyKeys(err, ['error'])
assert.include(err.error, 'Array too large')
}
})
})
describe("#getRawTransaction", () => {
it("should decode a single txid, with concise output", async () => {
describe('#getRawTransaction', () => {
it('should decode a single txid, with concise output', async () => {
const txid =
"23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1"
'23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1'
const verbose = false
const result = await bchjs.RawTransactions.getRawTransaction(
txid,
verbose
)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isString(result)
})
it("should decode a single txid, with verbose output", async () => {
it('should decode a single txid, with verbose output', async () => {
const txid =
"23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1"
'23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1'
const verbose = true
const result = await bchjs.RawTransactions.getRawTransaction(
txid,
verbose
)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAnyKeys(result, [
"hex",
"txid",
"hash",
"size",
"version",
"locktime",
"vin",
"vout",
"blockhash",
"confirmations",
"time",
"blocktime"
'hex',
'txid',
'hash',
'size',
'version',
'locktime',
'vin',
'vout',
'blockhash',
'confirmations',
'time',
'blocktime'
])
assert.isArray(result.vin)
assert.isArray(result.vout)
})
it("should decode an array of txids, with a concise output", async () => {
it('should decode an array of txids, with a concise output', async () => {
const txid = [
"23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1",
"b25d24fbb42d84812ed2cb55797f10fdec41afc7906ab563d1ec8c8676a2037f"
'23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1',
'b25d24fbb42d84812ed2cb55797f10fdec41afc7906ab563d1ec8c8676a2037f'
]
const verbose = false
@@ -153,16 +142,16 @@ describe("#rawtransaction", () => {
txid,
verbose
)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.isString(result[0])
})
it("should decode an array of txids, with a verbose output", async () => {
it('should decode an array of txids, with a verbose output', async () => {
const txid = [
"23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1",
"b25d24fbb42d84812ed2cb55797f10fdec41afc7906ab563d1ec8c8676a2037f"
'23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1',
'b25d24fbb42d84812ed2cb55797f10fdec41afc7906ab563d1ec8c8676a2037f'
]
const verbose = true
@@ -170,54 +159,54 @@ describe("#rawtransaction", () => {
txid,
verbose
)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.hasAnyKeys(result[0], [
"hex",
"txid",
"hash",
"size",
"version",
"locktime",
"vin",
"vout",
"blockhash",
"confirmations",
"time",
"blocktime"
'hex',
'txid',
'hash',
'size',
'version',
'locktime',
'vin',
'vout',
'blockhash',
'confirmations',
'time',
'blocktime'
])
assert.isArray(result[0].vin)
assert.isArray(result[0].vout)
})
it(`should throw error on array size rate limit`, async () => {
it('should throw error on array size rate limit', async () => {
try {
const dataMock =
"23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1"
'23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1'
const data = []
for (let i = 0; i < 25; i++) data.push(dataMock)
const result = await bchjs.RawTransactions.getRawTransaction(data)
console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
assert.hasAnyKeys(err, ['error'])
assert.include(err.error, 'Array too large')
}
})
})
describe("#decodeScript", () => {
it("should decode script for a single hex", async () => {
describe('#decodeScript', () => {
it('should decode script for a single hex', async () => {
const hex =
"4830450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed592012102e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16"
'4830450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed592012102e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16'
const result = await bchjs.RawTransactions.decodeScript(hex)
//console.log(`result ${JSON.stringify(result, null, 2)}`)
// console.log(`result ${JSON.stringify(result, null, 2)}`)
assert.hasAllKeys(result, ["asm", "type", "p2sh"])
assert.hasAllKeys(result, ['asm', 'type', 'p2sh'])
})
// CT 2/20/19 - Waiting for this PR to be merged complete the test:
@@ -232,22 +221,6 @@ describe("#rawtransaction", () => {
const result = await bchjs.RawTransactions.decodeScript(hexes)
console.log(`result ${JSON.stringify(result, null, 2)}`)
})
*/
/*
it(`should throw an error for improper single input`, async () => {
try {
const addr = 12345
await bchjs.RawTransactions.decodeRawTransaction(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(
err.message,
`Input must be a string or array of strings.`
)
}
})
*/
})
@@ -257,71 +230,26 @@ describe("#rawtransaction", () => {
below expect error messages returned from the server, but at least test
that the server is responding on those endpoints, and responds consistently.
*/
describe("sendRawTransaction", () => {
it("should send a single transaction hex", async () => {
try {
const hex =
"01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000"
await bchjs.RawTransactions.sendRawTransaction(hex)
//console.log(`result ${JSON.stringify(result, null, 2)}`)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: ${util.inspect(err)}`)
assert.hasAllKeys(err, ["error"])
assert.include(err.error, "Missing inputs")
}
})
it("should send an array of tx hexes", async () => {
try {
const hexes = [
"01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000",
"01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000"
]
const result = await bchjs.RawTransactions.sendRawTransaction(hexes)
console.log(`result ${JSON.stringify(result, null, 2)}`)
} catch (err) {
// console.log(`err: ${util.inspect(err)}`)
assert.hasAllKeys(err, ["error"])
assert.include(err.error, "Missing inputs")
}
})
it(`should throw an error for improper single input`, async () => {
try {
const addr = 12345
await bchjs.RawTransactions.sendRawTransaction(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(
err.message,
`Input hex must be a string or array of strings`
)
}
})
it(`should throw error on array size rate limit`, async () => {
describe('sendRawTransaction', () => {
it('should throw error on array size rate limit', async () => {
try {
const dataMock =
"01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000"
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000'
const data = []
for (let i = 0; i < 25; i++) data.push(dataMock)
const result = await bchjs.RawTransactions.sendRawTransaction(data)
console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
assert.hasAnyKeys(err, ['error'])
assert.include(err.error, 'Array too large')
}
})
})
})
function sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
+413 -170
View File
@@ -2,21 +2,21 @@
Integration tests for the bchjs covering SLP tokens.
*/
const chai = require("chai")
const chai = require('chai')
const assert = chai.assert
const BCHJS = require("../../src/bch-js")
const bchjs = new BCHJS()
const BCHJS = require('../../src/bch-js')
let bchjs
// Inspect utility used for debugging.
const util = require("util")
const util = require('util')
util.inspect.defaultOptions = {
showHidden: true,
colors: true,
depth: 1
}
describe(`#SLP`, () => {
describe('#SLP', () => {
// before(() => {
// console.log(`bchjs.SLP.restURL: ${bchjs.SLP.restURL}`)
// console.log(`bchjs.SLP.apiToken: ${bchjs.SLP.apiToken}`)
@@ -24,38 +24,40 @@ describe(`#SLP`, () => {
beforeEach(async () => {
// Introduce a delay so that the BVT doesn't trip the rate limits.
await sleep(1000)
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
bchjs = new BCHJS()
})
describe("#util", () => {
describe("#list", () => {
it(`should get information on the Spice token`, async () => {
const tokenId = `4de69e374a8ed21cbddd47f2338cc0f479dc58daa2bbe11cd604ca488eca0ddf`
describe('#util', () => {
describe('#list', () => {
it('should get information on the Spice token', async () => {
const tokenId = '4de69e374a8ed21cbddd47f2338cc0f479dc58daa2bbe11cd604ca488eca0ddf'
const result = await bchjs.SLP.Utils.list(tokenId)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAnyKeys(result, [
"decimals",
"timestamp",
"timestamp_unix",
"versionType",
"documentUri",
"symbol",
"name",
"containsBaton",
"id",
"documentHash",
"initialTokenQty",
"blockCreated",
"blockLastActiveSend",
"blockLastActiveMint",
"txnsSinceGenesis",
"validAddress",
"totalMinted",
"totalBurned",
"circulatingSupply",
"mintingBatonStatus"
'decimals',
'timestamp',
'timestamp_unix',
'versionType',
'documentUri',
'symbol',
'name',
'containsBaton',
'id',
'documentHash',
'initialTokenQty',
'blockCreated',
'blockLastActiveSend',
'blockLastActiveMint',
'txnsSinceGenesis',
'validAddress',
'totalMinted',
'totalBurned',
'circulatingSupply',
'mintingBatonStatus'
])
})
})
@@ -132,109 +134,109 @@ describe(`#SLP`, () => {
// })
// })
describe("#decodeOpReturn", () => {
it("should decode the OP_RETURN for a SEND txid", async () => {
describe('#decodeOpReturn', () => {
it('should decode the OP_RETURN for a SEND txid', async () => {
const txid =
"266844d53e46bbd7dd37134688dffea6e54d944edff27a0add63dd0908839bc1"
'266844d53e46bbd7dd37134688dffea6e54d944edff27a0add63dd0908839bc1'
const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAllKeys(result, ["tokenType", "txType", "tokenId", "amounts"])
assert.hasAllKeys(result, ['tokenType', 'txType', 'tokenId', 'amounts'])
assert.equal(
result.tokenId,
"497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7"
'497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7'
)
// Verify outputs
assert.equal(result.amounts.length, 2)
assert.equal(result.amounts[0], "100000000")
assert.equal(result.amounts[1], "99883300000000")
assert.equal(result.amounts[0], '100000000')
assert.equal(result.amounts[1], '99883300000000')
})
it("should decode the OP_RETURN for a GENESIS txid", async () => {
it('should decode the OP_RETURN for a GENESIS txid', async () => {
const txid =
"497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7"
'497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7'
const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAllKeys(result, [
"tokenType",
"txType",
"tokenId",
"ticker",
"name",
"documentUri",
"documentHash",
"decimals",
"mintBatonVout",
"qty"
'tokenType',
'txType',
'tokenId',
'ticker',
'name',
'documentUri',
'documentHash',
'decimals',
'mintBatonVout',
'qty'
])
assert.equal(
result.tokenId,
"497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7"
'497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7'
)
assert.equal(result.txType, "GENESIS")
assert.equal(result.ticker, "TOK-CH")
assert.equal(result.name, "TokyoCash")
assert.equal(result.txType, 'GENESIS')
assert.equal(result.ticker, 'TOK-CH')
assert.equal(result.name, 'TokyoCash')
})
it("should decode the OP_RETURN for a MINT txid", async () => {
it('should decode the OP_RETURN for a MINT txid', async () => {
const txid =
"65f21bbfcd545e5eb515e38e861a9dfe2378aaa2c4e458eb9e59e4d40e38f3a4"
'65f21bbfcd545e5eb515e38e861a9dfe2378aaa2c4e458eb9e59e4d40e38f3a4'
const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAllKeys(result, [
"tokenType",
"txType",
"tokenId",
"mintBatonVout",
"qty"
'tokenType',
'txType',
'tokenId',
'mintBatonVout',
'qty'
])
})
it("should throw an error for a non-SLP transaction", async () => {
it('should throw an error for a non-SLP transaction', async () => {
try {
const txid =
"3793d4906654f648e659f384c0f40b19c8f10c1e9fb72232a9b8edd61abaa1ec"
'3793d4906654f648e659f384c0f40b19c8f10c1e9fb72232a9b8edd61abaa1ec'
await bchjs.SLP.Utils.decodeOpReturn(txid)
assert.equal(true, false, "Unexpected result")
assert.equal(true, false, 'Unexpected result')
} catch (err) {
// console.log(`err: `, err)
assert.include(err.message, "scriptpubkey not op_return")
assert.include(err.message, 'scriptpubkey not op_return')
}
})
// Note: This TX is interpreted as valid by the original decodeOpReturn().
// Fixing this issue and related issues was the reason for creating the
// decodeOpReturn2() method using the slp-parser library.
it("should throw error for invalid SLP transaction", async () => {
it('should throw error for invalid SLP transaction', async () => {
try {
const txid =
"a60a522cc11ad7011b74e57fbabbd99296e4b9346bcb175dcf84efb737030415"
'a60a522cc11ad7011b74e57fbabbd99296e4b9346bcb175dcf84efb737030415'
await bchjs.SLP.Utils.decodeOpReturn(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
} catch (err) {
// console.log(`err: `, err)
assert.include(err.message, "amount string size not 8 bytes")
assert.include(err.message, 'amount string size not 8 bytes')
}
})
})
describe("#tokenUtxoDetails", () => {
describe('#tokenUtxoDetails', () => {
// // This captures an important corner-case. When an SLP token is created, the
// // change UTXO will contain the same SLP txid, but it is not an SLP UTXO.
it("should return details on minting baton from genesis transaction", async () => {
it('should return details on minting baton from genesis transaction', async () => {
const utxos = [
{
txid:
"bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90",
'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
vout: 3,
amount: 0.00002015,
satoshis: 2015,
@@ -243,7 +245,7 @@ describe(`#SLP`, () => {
},
{
txid:
"bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90",
'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
vout: 2,
amount: 0.00000546,
satoshis: 546,
@@ -255,32 +257,32 @@ describe(`#SLP`, () => {
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
assert.equal(data[0].isValid, false, "Change UTXO marked as false.")
assert.equal(data[0].isValid, false, 'Change UTXO marked as false.')
assert.property(data[1], "txid")
assert.property(data[1], "vout")
assert.property(data[1], "amount")
assert.property(data[1], "satoshis")
assert.property(data[1], "height")
assert.property(data[1], "confirmations")
assert.property(data[1], "utxoType")
assert.property(data[1], "tokenId")
assert.property(data[1], "tokenTicker")
assert.property(data[1], "tokenName")
assert.property(data[1], "tokenDocumentUrl")
assert.property(data[1], "tokenDocumentHash")
assert.property(data[1], "decimals")
assert.property(data[1], "isValid")
assert.property(data[1], 'txid')
assert.property(data[1], 'vout')
assert.property(data[1], 'amount')
assert.property(data[1], 'satoshis')
assert.property(data[1], 'height')
assert.property(data[1], 'confirmations')
assert.property(data[1], 'utxoType')
assert.property(data[1], 'tokenId')
assert.property(data[1], 'tokenTicker')
assert.property(data[1], 'tokenName')
assert.property(data[1], 'tokenDocumentUrl')
assert.property(data[1], 'tokenDocumentHash')
assert.property(data[1], 'decimals')
assert.property(data[1], 'isValid')
assert.equal(data[1].isValid, true)
})
it("should return details for a MINT token utxo", async () => {
it('should return details for a MINT token utxo', async () => {
// Mock the call to REST API
const utxos = [
{
txid:
"cf4b922d1e1aa56b52d752d4206e1448ea76c3ebe69b3b97d8f8f65413bd5c76",
'cf4b922d1e1aa56b52d752d4206e1448ea76c3ebe69b3b97d8f8f65413bd5c76',
vout: 1,
amount: 0.00000546,
satoshis: 546,
@@ -292,31 +294,31 @@ describe(`#SLP`, () => {
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
assert.property(data[0], "txid")
assert.property(data[0], "vout")
assert.property(data[0], "amount")
assert.property(data[0], "satoshis")
assert.property(data[0], "height")
assert.property(data[0], "confirmations")
assert.property(data[0], "utxoType")
assert.property(data[0], "transactionType")
assert.property(data[0], "tokenId")
assert.property(data[0], "tokenTicker")
assert.property(data[0], "tokenName")
assert.property(data[0], "tokenDocumentUrl")
assert.property(data[0], "tokenDocumentHash")
assert.property(data[0], "decimals")
assert.property(data[0], "mintBatonVout")
assert.property(data[0], "tokenQty")
assert.property(data[0], "isValid")
assert.property(data[0], 'txid')
assert.property(data[0], 'vout')
assert.property(data[0], 'amount')
assert.property(data[0], 'satoshis')
assert.property(data[0], 'height')
assert.property(data[0], 'confirmations')
assert.property(data[0], 'utxoType')
assert.property(data[0], 'transactionType')
assert.property(data[0], 'tokenId')
assert.property(data[0], 'tokenTicker')
assert.property(data[0], 'tokenName')
assert.property(data[0], 'tokenDocumentUrl')
assert.property(data[0], 'tokenDocumentHash')
assert.property(data[0], 'decimals')
assert.property(data[0], 'mintBatonVout')
assert.property(data[0], 'tokenQty')
assert.property(data[0], 'isValid')
assert.equal(data[0].isValid, true)
})
it("should return details for a simple SEND SLP token utxo", async () => {
it('should return details for a simple SEND SLP token utxo', async () => {
const utxos = [
{
txid:
"fde117b1f176b231e2fa9a6cb022e0f7c31c288221df6bcb05f8b7d040ca87cb",
'fde117b1f176b231e2fa9a6cb022e0f7c31c288221df6bcb05f8b7d040ca87cb',
vout: 1,
amount: 0.00000546,
satoshis: 546,
@@ -328,40 +330,40 @@ describe(`#SLP`, () => {
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
assert.property(data[0], "txid")
assert.property(data[0], "vout")
assert.property(data[0], "amount")
assert.property(data[0], "satoshis")
assert.property(data[0], "height")
assert.property(data[0], "confirmations")
assert.property(data[0], "utxoType")
assert.property(data[0], "tokenId")
assert.property(data[0], "tokenTicker")
assert.property(data[0], "tokenName")
assert.property(data[0], "tokenDocumentUrl")
assert.property(data[0], "tokenDocumentHash")
assert.property(data[0], "decimals")
assert.property(data[0], "tokenQty")
assert.property(data[0], "isValid")
assert.property(data[0], 'txid')
assert.property(data[0], 'vout')
assert.property(data[0], 'amount')
assert.property(data[0], 'satoshis')
assert.property(data[0], 'height')
assert.property(data[0], 'confirmations')
assert.property(data[0], 'utxoType')
assert.property(data[0], 'tokenId')
assert.property(data[0], 'tokenTicker')
assert.property(data[0], 'tokenName')
assert.property(data[0], 'tokenDocumentUrl')
assert.property(data[0], 'tokenDocumentHash')
assert.property(data[0], 'decimals')
assert.property(data[0], 'tokenQty')
assert.property(data[0], 'isValid')
assert.equal(data[0].isValid, true)
})
it("should handle BCH and SLP utxos in the same TX", async () => {
it('should handle BCH and SLP utxos in the same TX', async () => {
const utxos = [
{
txid:
"d56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56",
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
vout: 3,
value: "6816",
value: '6816',
height: 606848,
confirmations: 13,
satoshis: 6816
},
{
txid:
"d56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56",
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
vout: 2,
value: "546",
value: '546',
height: 606848,
confirmations: 13,
satoshis: 546
@@ -377,11 +379,11 @@ describe(`#SLP`, () => {
assert.equal(result[1].isValid, true)
})
it("should handle problematic utxos", async () => {
it('should handle problematic utxos', async () => {
const utxos = [
{
txid:
"0e3a217fc22612002031d317b4cecd9b692b66b52951a67b23c43041aefa3959",
'0e3a217fc22612002031d317b4cecd9b692b66b52951a67b23c43041aefa3959',
vout: 0,
amount: 0.00018362,
satoshis: 18362,
@@ -390,7 +392,7 @@ describe(`#SLP`, () => {
},
{
txid:
"67fd3c7c3a6eb0fea9ab311b91039545086220f7eeeefa367fa28e6e43009f19",
'67fd3c7c3a6eb0fea9ab311b91039545086220f7eeeefa367fa28e6e43009f19',
vout: 1,
amount: 0.00000546,
satoshis: 546,
@@ -408,11 +410,11 @@ describe(`#SLP`, () => {
assert.equal(result[1].isValid, true)
})
it("should return false for BCH-only UTXOs", async () => {
it('should return false for BCH-only UTXOs', async () => {
const utxos = [
{
txid:
"a937f792c7c9eb23b4f344ce5c233d1ac0909217d0a504d71e6b1e4efb864a3b",
'a937f792c7c9eb23b4f344ce5c233d1ac0909217d0a504d71e6b1e4efb864a3b',
vout: 0,
amount: 0.00001,
satoshis: 1000,
@@ -421,7 +423,7 @@ describe(`#SLP`, () => {
},
{
txid:
"53fd141c2e999e080a5860887441a2c45e9cbe262027e2bd2ac998fc76e43c44",
'53fd141c2e999e080a5860887441a2c45e9cbe262027e2bd2ac998fc76e43c44',
vout: 0,
amount: 0.00001,
satoshis: 1000,
@@ -437,45 +439,78 @@ describe(`#SLP`, () => {
assert.equal(data[0].isValid, false)
assert.equal(data[1].isValid, false)
})
})
describe("#balancesForAddress", () => {
it(`should throw an error if input is not a string or array of strings`, async () => {
try {
const address = 1234
it('should handle a dust attack', async () => {
// it("#dustattack", async () => {
const utxos = [
{
height: 655965,
tx_hash:
'a675af87dcd8d39be782737aa52e0076b52eb2f5ce355ffcb5567a64dd96b77e',
tx_pos: 151,
value: 547,
satoshis: 547,
txid:
'a675af87dcd8d39be782737aa52e0076b52eb2f5ce355ffcb5567a64dd96b77e',
vout: 151,
address: 'bitcoincash:qq4dw3sm8qvglspy6w2qg0u2ugsy9zcfcqrpeflwww',
hdIndex: 11
}
]
await bchjs.SLP.Utils.balancesForAddress(address)
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
assert.equal(true, false, "Uh oh. Code path should not end here.")
} catch (err) {
//console.log(`Error: `, err)
assert.include(
err.message,
`Input address must be a string or array of strings`
)
}
assert.equal(data[0].isValid, false)
})
it(`should fetch all balances for address: simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9`, async () => {
it('should handle null SLPDB validations', async () => {
const utxos = [
{
height: 665577,
tx_hash:
'4b89405c54d1c0bde8aa476a47561a42a6e7a5e927daa2ec69d428810eae3419',
tx_pos: 1,
value: 546
},
{
height: 665577,
tx_hash:
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488',
tx_pos: 1,
value: 546
}
]
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
assert.isArray(data)
// assert.equal(data[0].isValid, null)
})
})
describe('#balancesForAddress', () => {
it('should fetch all balances for address: simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9', async () => {
const balances = await bchjs.SLP.Utils.balancesForAddress(
"simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9"
'simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9'
)
// console.log(`balances: ${JSON.stringify(balances, null, 2)}`)
assert.isArray(balances)
assert.hasAllKeys(balances[0], [
"tokenId",
"balanceString",
"balance",
"decimalCount",
"slpAddress"
'tokenId',
'balanceString',
'balance',
'decimalCount',
'slpAddress'
])
})
it(`should fetch balances for multiple addresses`, async () => {
it('should fetch balances for multiple addresses', async () => {
const addresses = [
"simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9",
"simpleledger:qqss4zp80hn6szsa4jg2s9fupe7g5tcg5ucdyl3r57"
'simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9',
'simpleledger:qqss4zp80hn6szsa4jg2s9fupe7g5tcg5ucdyl3r57'
]
const balances = await bchjs.SLP.Utils.balancesForAddress(addresses)
@@ -484,23 +519,231 @@ describe(`#SLP`, () => {
assert.isArray(balances)
assert.isArray(balances[0])
assert.hasAllKeys(balances[0][0], [
"tokenId",
"balanceString",
"balance",
"decimalCount",
"slpAddress"
'tokenId',
'balanceString',
'balance',
'decimalCount',
'slpAddress'
])
})
})
describe('#hydrateUtxos', () => {
it('should hydrate UTXOs', async () => {
const utxos = [
{
utxos: [
{
txid:
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
vout: 3,
value: '6816',
height: 606848,
confirmations: 13,
satoshis: 6816
},
{
txid:
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
vout: 2,
value: '546',
height: 606848,
confirmations: 13,
satoshis: 546
}
]
}
]
const result = await bchjs.SLP.Utils.hydrateUtxos(utxos)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
// Test the general structure of the output.
assert.isArray(result.slpUtxos)
assert.equal(result.slpUtxos.length, 1)
assert.equal(result.slpUtxos[0].utxos.length, 2)
// Test the non-slp UTXO.
assert.property(result.slpUtxos[0].utxos[0], 'txid')
assert.property(result.slpUtxos[0].utxos[0], 'vout')
assert.property(result.slpUtxos[0].utxos[0], 'value')
assert.property(result.slpUtxos[0].utxos[0], 'height')
assert.property(result.slpUtxos[0].utxos[0], 'confirmations')
assert.property(result.slpUtxos[0].utxos[0], 'satoshis')
assert.property(result.slpUtxos[0].utxos[0], 'isValid')
assert.equal(result.slpUtxos[0].utxos[0].isValid, false)
// Test the slp UTXO.
assert.property(result.slpUtxos[0].utxos[1], 'txid')
assert.property(result.slpUtxos[0].utxos[1], 'vout')
assert.property(result.slpUtxos[0].utxos[1], 'value')
assert.property(result.slpUtxos[0].utxos[1], 'height')
assert.property(result.slpUtxos[0].utxos[1], 'confirmations')
assert.property(result.slpUtxos[0].utxos[1], 'satoshis')
assert.property(result.slpUtxos[0].utxos[1], 'isValid')
assert.equal(result.slpUtxos[0].utxos[1].isValid, true)
assert.property(result.slpUtxos[0].utxos[1], 'transactionType')
assert.property(result.slpUtxos[0].utxos[1], 'tokenId')
assert.property(result.slpUtxos[0].utxos[1], 'tokenTicker')
assert.property(result.slpUtxos[0].utxos[1], 'tokenName')
assert.property(result.slpUtxos[0].utxos[1], 'tokenDocumentUrl')
assert.property(result.slpUtxos[0].utxos[1], 'tokenDocumentHash')
assert.property(result.slpUtxos[0].utxos[1], 'decimals')
assert.property(result.slpUtxos[0].utxos[1], 'tokenType')
assert.property(result.slpUtxos[0].utxos[1], 'tokenQty')
})
it('should process data directly from Electrumx', async () => {
const addrs = [
'bitcoincash:qqnt53cfw990u6y38xgezm0lfa8hknw0wueezcpagp',
'bitcoincash:qrh3qgtax6adegzc7zxm6m4sgrv9wq28yqnfn33ce5',
'bitcoincash:qqcaee5w4ws77n8s2gzy6fwtma6uxd7ctq8553e495'
]
const utxos = await bchjs.Electrumx.utxo(addrs)
// console.log(`utxos: ${JSON.stringify(utxos, null, 2)}`)
const result = await bchjs.SLP.Utils.hydrateUtxos(utxos.utxos)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
// Test the general structure of the output.
assert.isArray(result.slpUtxos)
assert.equal(result.slpUtxos.length, 3)
assert.equal(result.slpUtxos[0].utxos.length, 1)
assert.equal(result.slpUtxos[1].utxos.length, 1)
assert.equal(result.slpUtxos[2].utxos.length, 2)
try {
// Test the expected values.
assert.equal(result.slpUtxos[0].utxos[0].isValid, false)
assert.equal(result.slpUtxos[1].utxos[0].isValid, true)
assert.equal(result.slpUtxos[1].utxos[0].tokenTicker, 'TROUT')
assert.equal(result.slpUtxos[2].utxos[0].isValid, false)
assert.equal(result.slpUtxos[2].utxos[1].isValid, true)
assert.equal(result.slpUtxos[2].utxos[1].tokenTicker, 'VALENTINE')
} catch (err) {
console.error(
'The hydrateUtxos call may hitting rate limits, or SLPDB may be having issues if "isValid" results are "null"'
)
console.log('Error: ', err)
}
})
it('should handle null SLPDB validations', async () => {
const utxos = [
{
height: 665577,
tx_hash:
'4b89405c54d1c0bde8aa476a47561a42a6e7a5e927daa2ec69d428810eae3419',
tx_pos: 1,
value: 546
},
{
height: 665577,
tx_hash:
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a',
tx_pos: 1,
value: 546
}
]
const data = await bchjs.SLP.Utils.hydrateUtxos([{ utxos: utxos }])
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
assert.isArray(data.slpUtxos)
assert.equal(data.slpUtxos[0].isValid, null)
})
})
describe('#validateTxid', () => {
// This test is not necessary.
it('should handle a null response from SLPDB', async () => {
const txid =
'4b89405c54d1c0bde8aa476a47561a42a6e7a5e927daa2ec69d428810eae3419'
const result = await bchjs.SLP.Utils.validateTxid(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.equal(result[0].txid, txid)
// assert.equal(result[0].valid, null)
})
it('should handle a null response from SLPDB', async () => {
const txid = [
'4b89405c54d1c0bde8aa476a47561a42a6e7a5e927daa2ec69d428810eae3419',
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488'
]
const result = await bchjs.SLP.Utils.validateTxid(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.equal(result[0].txid, txid[0])
// assert.equal(result[0].valid, null)
})
})
describe('#validateTxid2', () => {
it('should invalidate a known invalid TXID', async () => {
const txid =
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a'
const result = await bchjs.SLP.Utils.validateTxid2(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'txid')
assert.equal(result.txid, txid)
assert.property(result, 'isValid')
assert.equal(result.isValid, false)
})
it('should validate a known valid TXID', async () => {
const txid =
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488'
const result = await bchjs.SLP.Utils.validateTxid2(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'txid')
assert.equal(result.txid, txid)
assert.property(result, 'isValid')
assert.equal(result.isValid, true)
})
})
describe('#getWhitelist', () => {
it('should get the whitelist', async () => {
const result = await bchjs.SLP.Utils.getWhitelist()
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], 'name')
assert.property(result[1], 'tokenId')
})
})
describe('#getStatus', () => {
it('should return the current block height of the SLPDB indexer', async () => {
const result = await bchjs.SLP.Utils.getStatus()
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'bchBlockHeight')
assert.property(result, 'slpProcessedBlockHeight')
})
})
})
describe("#tokentype1", () => {
describe("#getHexOpReturn", () => {
it("should return OP_RETURN object ", async () => {
describe('#tokentype1', () => {
describe('#getHexOpReturn', () => {
it('should return OP_RETURN object ', async () => {
const tokenUtxos = [
{
tokenId:
"0a321bff9761f28e06a268b14711274bb77617410a16807bd0437ef234a072b1",
'0a321bff9761f28e06a268b14711274bb77617410a16807bd0437ef234a072b1',
decimals: 0,
tokenQty: 2
}
@@ -513,10 +756,10 @@ describe(`#SLP`, () => {
)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "script")
assert.property(result, 'script')
assert.isString(result.script)
assert.property(result, "outputs")
assert.property(result, 'outputs')
assert.isNumber(result.outputs)
})
})
@@ -524,6 +767,6 @@ describe(`#SLP`, () => {
})
// Promise-based sleep function
function sleep(ms) {
function sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
-7
View File
@@ -1,7 +0,0 @@
#!/bin/bash
export RESTURL=https://free-main.fullstack.cash/v3/
#export RESTURL=http://localhost:3000/v3/
cd test/integration/
mocha --timeout 30000 blockchain.js control.js electrumx.js ninsight.js openbazaar.js price.js rawtransaction.js slp.js util.js
-178
View File
@@ -1,178 +0,0 @@
/*
Integration tests for the Blockbook library.
*/
const chai = require("chai")
const assert = chai.assert
const RESTURL = process.env.RESTURL
? process.env.RESTURL
: `https://tapi.fullstack.cash/v3/`
// if (process.env.RESTURL) RESTURL = process.env.RESTURL
const BCHJS = require("../../../src/bch-js")
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v3/` })
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
// const bchjs = new BCHJS({ restURL: RESTURL })
//const axios = require("axios")
// Inspect utility used for debugging.
const util = require("util")
util.inspect.defaultOptions = {
showHidden: true,
colors: true,
depth: 3
}
describe(`#Blockbook`, () => {
describe(`#Balance`, () => {
it(`should GET balance for a single address`, async () => {
const addr = "bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2"
const result = await bchjs.Blockbook.balance(addr)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAnyKeys(result, [
"page",
"totalPages",
"itemsOnPage",
"address",
"balance",
"totalReceived",
"totalSent",
"unconfirmedBalance",
"unconfirmedTxs",
"txs",
"txids"
])
assert.isArray(result.txids)
})
it(`should POST request balances for an array of addresses`, async () => {
const addr = [
"bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2",
"bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2"
]
const result = await bchjs.Blockbook.balance(addr)
//console.log(`result: ${util.inspect(result)}`)
assert.isArray(result)
assert.hasAnyKeys(result[0], [
"page",
"totalPages",
"itemsOnPage",
"address",
"balance",
"totalReceived",
"totalSent",
"unconfirmedBalance",
"unconfirmedTxs",
"txs",
"txids"
])
assert.isArray(result[0].txids)
})
it(`should throw an error for improper input`, async () => {
try {
const addr = 12345
await bchjs.Blockbook.balance(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(
err.message,
`Input address must be a string or array of strings`
)
}
})
it(`should throw error on array size rate limit`, async () => {
try {
const addr = []
for (let i = 0; i < 25; i++)
addr.push("bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2")
const result = await bchjs.Blockbook.balance(addr)
console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
}
})
})
describe(`#utxo`, () => {
it(`should GET utxos for a single address`, async () => {
const addr = "bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2"
const result = await bchjs.Blockbook.utxo(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.hasAnyKeys(result[0], [
"txid",
"vout",
"value",
"height",
"confirmations"
])
})
it(`should POST utxo details for an array of addresses`, async () => {
const addr = [
"bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2",
"bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2"
]
const result = await bchjs.Blockbook.utxo(addr)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.isArray(result[0])
assert.hasAnyKeys(result[0][0], [
"txid",
"vout",
"value",
"height",
"confirmations"
])
})
it(`should throw an error for improper input`, async () => {
try {
const addr = 12345
await bchjs.Blockbook.utxo(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(
err.message,
`Input address must be a string or array of strings`
)
}
})
it(`should throw error on array size rate limit`, async () => {
try {
const addr = []
for (let i = 0; i < 25; i++)
addr.push("bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2")
const result = await bchjs.Blockbook.utxo(addr)
//console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
}
})
})
})
-308
View File
@@ -1,308 +0,0 @@
/*
Integration tests for the bchjs. Only covers calls made to
rest.bitcoin.com.
TODO
- getMempoolEntry() only works on TXs in the mempool, so it needs to be part
of an e2e test to be properly tested.
*/
const chai = require("chai")
const assert = chai.assert
const RESTURL = process.env.RESTURL
? process.env.RESTURL
: `https://tapi.fullstack.cash/v3/`
// if (process.env.RESTURL) RESTURL = process.env.RESTURL
const BCHJS = require("../../../src/bch-js")
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v3/` })
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
// Inspect utility used for debugging.
const util = require("util")
util.inspect.defaultOptions = {
showHidden: true,
colors: true,
depth: 3
}
describe(`#blockchain`, () => {
describe(`#getBestBlockHash`, () => {
it(`should GET best block hash`, async () => {
const result = await bchjs.Blockchain.getBestBlockHash()
//console.log(`result: ${util.inspect(result)}`)
assert.isString(result)
assert.equal(result.length, 64, "Specific hash length")
})
})
describe("#getBlockHeader", () => {
it(`should GET block header for a single hash`, async () => {
const hash =
"000000000000c57178ace90210289e6b5383134c5b5306e1cdd8395176e10aaf"
const result = await bchjs.Blockchain.getBlockHeader(hash)
assert.hasAllKeys(result, [
"hash",
"confirmations",
"height",
"version",
"versionHex",
"merkleroot",
"time",
"mediantime",
"nonce",
"bits",
"difficulty",
"chainwork",
"previousblockhash",
"nextblockhash",
"nTx"
])
})
it(`should GET block headers for an array of hashes`, async () => {
const hash = [
"000000000000c57178ace90210289e6b5383134c5b5306e1cdd8395176e10aaf",
"00000000000b7db4cbae48d852fcbef32f728014582094ad613fe12af6600ff2"
]
const result = await bchjs.Blockchain.getBlockHeader(hash)
assert.isArray(result)
assert.hasAllKeys(result[0], [
"hash",
"confirmations",
"height",
"version",
"versionHex",
"merkleroot",
"time",
"mediantime",
"nonce",
"bits",
"difficulty",
"chainwork",
"previousblockhash",
"nextblockhash",
"nTx"
])
})
it(`should throw an error for improper input`, async () => {
try {
const hash = 12345
await bchjs.Blockchain.getBlockHeader(hash)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.include(
err.message,
`Input hash must be a string or array of strings`
)
}
})
it(`should throw error on array size rate limit`, async () => {
try {
const data = []
for (let i = 0; i < 25; i++) {
data.push(
"00000000000b7db4cbae48d852fcbef32f728014582094ad613fe12af6600ff2"
)
}
const result = await bchjs.Blockchain.getBlockHeader(data)
// console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
}
})
})
describe("#getMempoolEntry", () => {
/*
// To run this test, the txid must be unconfirmed.
const txid =
"defea04c38ee00cf73ad402984714ed22dc0dd99b2ae5cb50d791d94343ba79b"
it(`should GET single mempool entry`, async () => {
const result = await bchjs.Blockchain.getMempoolEntry(txid)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAnyKeys(result, [
"size",
"fee",
"modifiedfee",
"time",
"height",
"startingpriority",
"currentpriority",
"descendantcount",
"descendantsize",
"descendantfees",
"ancestorcount",
"ancestorsize",
"ancestorfees",
"depends"
])
})
it(`should get an array of mempool entries`, async () => {
const result = await bchjs.Blockchain.getMempoolEntry([txid, txid])
console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.hasAnyKeys(result[0], [
"size",
"fee",
"modifiedfee",
"time",
"height",
"startingpriority",
"currentpriority",
"descendantcount",
"descendantsize",
"descendantfees",
"ancestorcount",
"ancestorsize",
"ancestorfees",
"depends"
])
})
*/
it(`should throw an error if txid is not in mempool`, async () => {
try {
const txid =
"1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04"
await bchjs.Blockchain.getMempoolEntry(txid)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: ${util.inspect(err)}`)
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, `Transaction not in mempool`)
}
})
it(`should throw an error for improper single input`, async () => {
try {
const txid = 12345
await bchjs.Blockchain.getMempoolEntry(txid)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.include(
err.message,
`Input must be a string or array of strings`
)
}
})
})
describe(`#getTxOutProof`, () => {
it(`should get single tx out proof`, async () => {
const txid =
"1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04"
const result = await bchjs.Blockchain.getTxOutProof(txid)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isString(result)
})
it(`should get an array of tx out proofs`, async () => {
const txid = [
"1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04",
"fc4f696c0ebb3d0994b3975f57d85be75ef752b9fd52c17e361ec3be2fa3e752"
]
const result = await bchjs.Blockchain.getTxOutProof(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.isString(result[0])
})
it(`should throw an error for improper single input`, async () => {
try {
const txid = 12345
await bchjs.Blockchain.getTxOutProof(txid)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.include(
err.message,
`Input must be a string or array of strings`
)
}
})
})
describe(`#verifyTxOutProof`, () => {
const mockTxOutProof =
"00000020ac86ce8f2bda235c0dc135d18f6a777c44b121e8f41db8a51ca65000000000000cd4de3c49337712f3a1092c47c3bf73ec2f9b1cfd289ee991ede0b6eab4df229d5b8c5dffff001d82ce005b0700000003ec55d9142eac2c1d2229e5af24898b2590c111b62e2787fa1998d3d713fd432fd557124ed758fa156a6cdc6d317d5575aec2b86dfb159c62ecb4743f28bef1cb52e7a32fbec31e367ec152fdb952f75ee75bd8575f97b394093dbb0e6c694ffc0135"
it(`should verify a single proof`, async () => {
const result = await bchjs.Blockchain.verifyTxOutProof(mockTxOutProof)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.isString(result[0])
assert.equal(
result[0],
"fc4f696c0ebb3d0994b3975f57d85be75ef752b9fd52c17e361ec3be2fa3e752"
)
})
it(`should verify an array of proofs`, async () => {
const proofs = [mockTxOutProof, mockTxOutProof]
const result = await bchjs.Blockchain.verifyTxOutProof(proofs)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.isString(result[0])
assert.equal(
result[0],
"fc4f696c0ebb3d0994b3975f57d85be75ef752b9fd52c17e361ec3be2fa3e752"
)
})
it(`should throw an error for improper single input`, async () => {
try {
const txid = 12345
await bchjs.Blockchain.verifyTxOutProof(txid)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.include(
err.message,
`Input must be a string or array of strings`
)
}
})
it(`should throw error on array size rate limit`, async () => {
try {
const data = []
for (let i = 0; i < 25; i++) data.push(mockTxOutProof)
const result = await bchjs.Blockchain.verifyTxOutProof(data)
console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
}
})
})
})
-24
View File
@@ -1,24 +0,0 @@
/*
Integration tests for bchjs control library.
*/
const chai = require("chai")
const assert = chai.assert
const RESTURL = process.env.RESTURL
? process.env.RESTURL
: `https://tapi.fullstack.cash/v3/`
const BCHJS = require("../../../src/bch-js")
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
describe(`#control`, () => {
describe(`#getNetworkInfo`, () => {
it("should get info on the full node", async () => {
const result = await bchjs.Control.getNetworkInfo()
console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "version")
})
})
})
-247
View File
@@ -1,247 +0,0 @@
const chai = require("chai")
const assert = chai.assert
const sinon = require("sinon")
const RESTURL = process.env.RESTURL
? process.env.RESTURL
: `https://tapi.fullstack.cash/v3/`
const BCHJS = require("../../../src/bch-js")
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
describe(`#ElectrumX`, () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
afterEach(() => sandbox.restore())
describe(`#utxo`, () => {
it(`should GET utxos for a single address`, async () => {
const addr = "bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2"
const result = await bchjs.Electrumx.utxo(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.equal(result.success, true)
assert.property(result, "utxos")
assert.isArray(result.utxos)
assert.property(result.utxos[0], "height")
assert.property(result.utxos[0], "tx_hash")
assert.property(result.utxos[0], "tx_pos")
assert.property(result.utxos[0], "value")
})
it(`should POST utxo details for an array of addresses`, async () => {
const addr = [
"bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2",
"bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2"
]
const result = await bchjs.Electrumx.utxo(addr)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.equal(result.success, true)
assert.property(result, "utxos")
assert.isArray(result.utxos)
assert.property(result.utxos[0], "utxos")
assert.isArray(result.utxos[0].utxos)
assert.property(result.utxos[0], "address")
assert.property(result.utxos[0].utxos[0], "height")
assert.property(result.utxos[0].utxos[0], "tx_hash")
assert.property(result.utxos[0].utxos[0], "tx_pos")
assert.property(result.utxos[0].utxos[0], "value")
})
it(`should throw error on array size rate limit`, async () => {
try {
const addr = []
for (let i = 0; i < 25; i++)
addr.push("bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2")
const result = await bchjs.Electrumx.utxo(addr)
//console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
}
})
})
describe(`#balance`, () => {
it(`should GET balance for a single address`, async () => {
const addr = "bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2"
const result = await bchjs.Electrumx.balance(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.equal(result.success, true)
assert.property(result, "balance")
assert.property(result.balance, "confirmed")
assert.property(result.balance, "unconfirmed")
})
it(`should POST request for balances for an array of addresses`, async () => {
const addr = [
"bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2",
"bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2"
]
const result = await bchjs.Electrumx.balance(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.equal(result.success, true)
assert.property(result, "balances")
assert.isArray(result.balances)
assert.property(result.balances[0], "address")
assert.property(result.balances[0], "balance")
assert.property(result.balances[0].balance, "confirmed")
assert.property(result.balances[0].balance, "unconfirmed")
})
it(`should throw error on array size rate limit`, async () => {
try {
const addr = []
for (let i = 0; i < 25; i++)
addr.push("bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2")
const result = await bchjs.Electrumx.balance(addr)
console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
}
})
})
describe(`#transactions`, () => {
it(`should GET transaction history for a single address`, async () => {
const addr = "bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2"
const result = await bchjs.Electrumx.transactions(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.equal(result.success, true)
assert.property(result, "transactions")
assert.isArray(result.transactions)
assert.property(result.transactions[0], "height")
assert.property(result.transactions[0], "tx_hash")
})
it(`should POST request for transaction history for an array of addresses`, async () => {
const addr = [
"bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2",
"bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2"
]
const result = await bchjs.Electrumx.transactions(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.equal(result.success, true)
assert.property(result, "transactions")
assert.isArray(result.transactions)
assert.property(result.transactions[0], "address")
assert.property(result.transactions[0], "transactions")
assert.isArray(result.transactions[0].transactions)
assert.property(result.transactions[0].transactions[0], "height")
assert.property(result.transactions[0].transactions[0], "tx_hash")
})
it(`should throw error on array size rate limit`, async () => {
try {
const addr = []
for (let i = 0; i < 25; i++)
addr.push("bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2")
const result = await bchjs.Electrumx.transactions(addr)
console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
}
})
})
describe(`#unconfirmed`, () => {
// These tests won't work because unconfirmed transactions are transient in nature.
/*
it(`should GET unconfirmed UTXOs (mempool) for a single address`, async () => {
const addr = "bchtest:qp25k20dgcljrz4hkdz43partam3j5httyprjp23qd"
const result = await bchjs.Electrumx.unconfirmed(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.equal(result.success, true)
assert.property(result, "utxos")
assert.isArray(result.utxos)
assert.property(result.utxos[0], "height")
assert.property(result.utxos[0], "tx_hash")
assert.property(result.utxos[0], "fee")
})
it(`should POST unconfirmed UTXO details for an array of addresses`, async () => {
const addr = [
"bchtest:qp25k20dgcljrz4hkdz43partam3j5httyprjp23qd",
"bchtest:qpkl3xylrjx4jup6m66e7zg7whlaucsxeudxeqawdj"
]
const result = await bchjs.Electrumx.unconfirmed(addr)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.equal(result.success, true)
assert.property(result, "utxos")
assert.isArray(result.utxos)
assert.property(result.utxos[0], "utxos")
assert.isArray(result.utxos[0].utxos)
assert.property(result.utxos[0], "address")
assert.property(result.utxos[0].utxos[0], "height")
assert.property(result.utxos[0].utxos[0], "tx_hash")
assert.property(result.utxos[0].utxos[0], "fee")
})
*/
it(`should throw error on array size rate limit`, async () => {
try {
const addr = []
for (let i = 0; i < 25; i++)
addr.push("bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2")
await bchjs.Electrumx.unconfirmed(addr)
//console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
}
})
})
})
-65
View File
@@ -1,65 +0,0 @@
const chai = require("chai")
const assert = chai.assert
const sinon = require("sinon")
const BCHJS = require("../../../src/bch-js")
const bchjs = new BCHJS({ ninsightURL: "https://trest.bitcoin.com/v2" })
describe(`#Ninsight`, () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
afterEach(() => sandbox.restore())
describe(`#utxo`, () => {
it(`should GET utxos for a single address`, async () => {
const addr = "bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr"
const result = await bchjs.Ninsight.utxo(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "utxos")
assert.property(result, "legacyAddress")
assert.property(result, "cashAddress")
assert.property(result, "slpAddress")
assert.property(result, "scriptPubKey")
assert.property(result, "asm")
assert.isArray(result.utxos)
assert.property(result.utxos[0], "txid")
assert.property(result.utxos[0], "vout")
assert.property(result.utxos[0], "amount")
assert.property(result.utxos[0], "satoshis")
assert.property(result.utxos[0], "height")
assert.property(result.utxos[0], "confirmations")
})
it(`should POST utxo details for an array of addresses`, async () => {
const addr = [
"bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr",
"bchtest:qp6hgvevf4gzz6l7pgcte3gaaud9km0l459fa23dul"
]
const result = await bchjs.Ninsight.utxo(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.isArray(result[0].utxos)
assert.property(result[0], "utxos")
assert.property(result[0], "legacyAddress")
assert.property(result[0], "cashAddress")
assert.property(result[0], "slpAddress")
assert.property(result[0], "scriptPubKey")
assert.property(result[0], "asm")
// assert.hasAnyKeys(result[0][0], [
// "txid",
// "vout",
// "value",
// "height",
// "confirmations"
// ])
})
})
})
-124
View File
@@ -1,124 +0,0 @@
/*
tests for OpenBazaar library.
*/
// Force testnet call to OB1 servers.
process.env.NETWORK = "testnet"
const chai = require("chai")
const assert = chai.assert
const RESTURL = process.env.RESTURL
? process.env.RESTURL
: `https://tapi.fullstack.cash/v3/`
const BCHJS = require("../../../src/bch-js")
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
describe(`#OpenBazaar`, () => {
describe(`#Balance`, () => {
// it(`should GET balance for a single address`, async () => {
// const addr = "bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2"
//
// const result = await bchjs.OpenBazaar.balance(addr)
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
//
// assert.hasAllKeys(result, [
// "page",
// "totalPages",
// "itemsOnPage",
// "addrStr",
// "balance",
// "totalReceived",
// "totalSent",
// "unconfirmedBalance",
// "unconfirmedTxApperances",
// "txApperances",
// "transactions"
// ])
// assert.isArray(result.transactions)
// })
it(`should throw an error for improper input`, async () => {
try {
const addr = 12345
await bchjs.OpenBazaar.balance(addr)
// assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(err.message, `Input address must be a string`)
}
})
})
describe(`#utxo`, () => {
// it(`should GET utxos for a single address`, async () => {
// const addr = "bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2"
//
// const result = await bchjs.OpenBazaar.utxo(addr)
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
//
// assert.isArray(result)
// assert.hasAllKeys(result[0], [
// "txid",
// "vout",
// "amount",
// "height",
// "confirmations",
// "satoshis"
// ])
// })
it(`should throw an error for improper input`, async () => {
try {
const addr = 12345
await bchjs.OpenBazaar.utxo(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(err.message, `Input address must be a string`)
}
})
})
describe(`#tx`, () => {
it(`should throw an error for improper input`, async () => {
try {
const addr = 12345
await bchjs.OpenBazaar.tx(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(err.message, `Input txid must be a string`)
}
})
// it(`should GET transactions for a single address`, async () => {
// const addr =
// "ed4692f50a4553527dd26cd8674ca06a0ab2d366f3135ca3668310467ead3cbf"
//
// const result = await bchjs.OpenBazaar.tx(addr)
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
//
// assert.hasAnyKeys(result, [
// "txid",
// "version",
// "vin",
// "vout",
// "blockhash",
// "blockheight",
// "confirmations",
// "blocktime",
// "valueOut",
// "valueIn",
// "fees",
// "hex"
// ])
// assert.isArray(result.vin)
// assert.isArray(result.vout)
// })
})
})
-147
View File
@@ -1,147 +0,0 @@
/*
Integration tests for the bchjs covering SLP tokens.
*/
const chai = require("chai")
const assert = chai.assert
const RESTURL = process.env.RESTURL
? process.env.RESTURL
: `https://tapi.fullstack.cash/v3/`
// if (process.env.RESTURL) RESTURL = process.env.RESTURL
const BCHJS = require("../../../src/bch-js")
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v3/` })
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
// Inspect utility used for debugging.
const util = require("util")
util.inspect.defaultOptions = {
showHidden: true,
colors: true,
depth: 1
}
describe(`#SLP`, () => {
beforeEach(async () => {
// Introduce a delay so that the BVT doesn't trip the rate limits.
await sleep(1000)
})
describe("#util", () => {
it(`should get information on the Oasis token`, async () => {
const tokenId = `a371e9934c7695d08a5eb7f31d3bceb4f3644860cc67520cda1e149423b9ec39`
const result = await bchjs.SLP.Utils.list(tokenId)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAnyKeys(result, [
"decimals",
"timestamp",
"timestamp_unix",
"versionType",
"documentUri",
"symbol",
"name",
"containsBaton",
"id",
"documentHash",
"initialTokenQty",
"blockCreated",
"blockLastActiveSend",
"blockLastActiveMint",
"txnsSinceGenesis",
"validAddress",
"totalMinted",
"totalBurned",
"circulatingSupply",
"mintingBatonStatus"
])
})
})
describe("#decodeOpReturn", () => {
it("should decode the OP_RETURN for a SEND txid", async () => {
const txid =
"ad28116e0818339342dddfc5f58ca8a5379ceb9679b4e4cbd72f4de905415ec1"
const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAllKeys(result, ["amounts", "tokenType", "tokenId", "txType"])
})
})
describe("#balancesForAddress", () => {
it(`should throw an error if input is not a string or array of strings`, async () => {
try {
const address = 1234
await bchjs.SLP.Utils.balancesForAddress(address)
assert.equal(true, false, "Uh oh. Code path should not end here.")
} catch (err) {
//console.log(`Error: `, err)
assert.include(
err.message,
`Input address must be a string or array of strings`
)
}
})
it(`should fetch all balances for address: simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9`, async () => {
// Mock the call to rest.bitcoin.com
if (process.env.TEST === "unit") {
sandbox
.stub(axios, "get")
.resolves({ data: mockData.balancesForAddress })
}
const balances = await bchjs.SLP.Utils.balancesForAddress(
"slptest:qz0kc67pm4emjyr3gaaa2wstdaykg9m4yqwlzpj3w9"
)
// console.log(`balances: ${JSON.stringify(balances, null, 2)}`)
assert.isArray(balances)
assert.hasAllKeys(balances[0], [
"tokenId",
"balanceString",
"balance",
"decimalCount",
"slpAddress"
])
})
it(`should fetch balances for multiple addresses`, async () => {
const addresses = [
"slptest:qz0kc67pm4emjyr3gaaa2wstdaykg9m4yqwlzpj3w9",
"slptest:qr5uy4h8ysyhwkp9s245scckdnc7teyjqc5ft2z43h"
]
// Mock the call to rest.bitcoin.com
if (process.env.TEST === "unit") {
sandbox
.stub(axios, "post")
.resolves({ data: mockData.balancesForAddresses })
}
const balances = await bchjs.SLP.Utils.balancesForAddress(addresses)
// console.log(`balances: ${JSON.stringify(balances, null, 2)}`)
assert.isArray(balances)
assert.isArray(balances[0])
assert.hasAllKeys(balances[0][0], [
"tokenId",
"balanceString",
"balance",
"decimalCount",
"slpAddress"
])
})
})
})
// Promise-based sleep function
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
@@ -1,9 +0,0 @@
#!/bin/bash
export RESTURL=https://free-test.fullstack.cash/v3/
export NETWORK=testnet
#export RESTURL=http://localhost:3000/v3/
cd test/integration/testnet/
mocha --timeout 30000 blockchain.js control.js electrumx.js openbazaar.js rawtransaction.js slp.js util.js
#mocha --timeout 30000 blockchain.js
-116
View File
@@ -1,116 +0,0 @@
/*
Integration tests for the bchjs. Only covers calls made to
rest.bitcoin.com.
*/
const chai = require("chai")
const assert = chai.assert
const RESTURL = process.env.RESTURL
? process.env.RESTURL
: `https://tapi.fullstack.cash/v3/`
// if (process.env.RESTURL) RESTURL = process.env.RESTURL
const BCHJS = require("../../../src/bch-js")
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v3/` })
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
// Inspect utility used for debugging.
const util = require("util")
util.inspect.defaultOptions = {
showHidden: true,
colors: true,
depth: 3
}
describe(`#util`, () => {
describe(`#validateAddress`, () => {
it(`should return false for testnet addr on mainnet`, async () => {
const address = `bitcoincash:qp4k8fjtgunhdr7yq30ha4peu`
const result = await bchjs.Util.validateAddress(address)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAllKeys(result, ["isvalid"])
assert.equal(result.isvalid, false)
})
it(`should return false for bad address`, async () => {
const address = `bchtest:qqqk4y6lsl5da64sg53xezmplyu5kmpyz2ysaa5y`
const result = await bchjs.Util.validateAddress(address)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAllKeys(result, ["isvalid"])
assert.equal(result.isvalid, false)
})
it(`should validate valid address`, async () => {
const address = `bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y`
const result = await bchjs.Util.validateAddress(address)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAnyKeys(result, [
"isvalid",
"address",
"scriptPubKey",
//"ismine",
//"iswatchonly",
"isscript"
])
assert.equal(result.isvalid, true)
})
it(`should validate an array of addresses`, async () => {
const address = [
`bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y`,
`bchtest:pq6k9969f6v6sg7a75jkru4n7wn9sknv5cztcp0dnh`
]
const result = await bchjs.Util.validateAddress(address)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.hasAnyKeys(result[0], [
"isvalid",
"address",
"scriptPubKey",
//"ismine",
//"iswatchonly",
"isscript"
])
})
it(`should throw an error for improper single input`, async () => {
try {
const address = 15432
await bchjs.Util.validateAddress(address)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(
err.message,
`Input must be a string or array of strings.`
)
}
})
it(`should throw error on array size rate limit`, async () => {
try {
const dataMock = `bchtest:pq6k9969f6v6sg7a75jkru4n7wn9sknv5cztcp0dnh`
const data = []
for (let i = 0; i < 25; i++) data.push(dataMock)
const result = await bchjs.Util.validateAddress(data)
console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
}
})
})
})
+45 -52
View File
@@ -3,107 +3,100 @@
rest.bitcoin.com.
*/
const chai = require("chai")
const chai = require('chai')
const assert = chai.assert
const BCHJS = require("../../src/bch-js")
const BCHJS = require('../../src/bch-js')
const bchjs = new BCHJS()
// Inspect utility used for debugging.
const util = require("util")
const util = require('util')
util.inspect.defaultOptions = {
showHidden: true,
colors: true,
depth: 3
}
describe(`#util`, () => {
describe(`#validateAddress`, () => {
it(`should return false for testnet addr on mainnet`, async () => {
const address = `bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y`
describe('#util', () => {
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
describe('#validateAddress', () => {
it('should return false for testnet addr on mainnet', async () => {
const address = 'bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y'
const result = await bchjs.Util.validateAddress(address)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAllKeys(result, ["isvalid"])
assert.hasAllKeys(result, ['isvalid'])
assert.equal(result.isvalid, false)
})
it(`should return false for bad address`, async () => {
const address = `bitcoincash:qp4k8fjtgunhdr7yq30ha4peu`
it('should return false for bad address', async () => {
const address = 'bitcoincash:qp4k8fjtgunhdr7yq30ha4peu'
const result = await bchjs.Util.validateAddress(address)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAllKeys(result, ["isvalid"])
assert.hasAllKeys(result, ['isvalid'])
assert.equal(result.isvalid, false)
})
it(`should validate valid address`, async () => {
const address = `bitcoincash:qp4k8fjtgunhdr7yq30ha4peuwupzan2vcnwrmpy0z`
it('should validate valid address', async () => {
const address = 'bitcoincash:qp4k8fjtgunhdr7yq30ha4peuwupzan2vcnwrmpy0z'
const result = await bchjs.Util.validateAddress(address)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAnyKeys(result, [
"isvalid",
"address",
"scriptPubKey",
//"ismine",
//"iswatchonly",
"isscript"
'isvalid',
'address',
'scriptPubKey',
// "ismine",
// "iswatchonly",
'isscript'
])
assert.equal(result.isvalid, true)
})
it(`should validate an array of addresses`, async () => {
it('should validate an array of addresses', async () => {
const address = [
`bitcoincash:qp4k8fjtgunhdr7yq30ha4peuwupzan2vcnwrmpy0z`,
`bitcoincash:qp4k8fjtgunhdr7yq30ha4peuwupzan2vcnwrmpy0z`
'bitcoincash:qp4k8fjtgunhdr7yq30ha4peuwupzan2vcnwrmpy0z',
'bitcoincash:qp4k8fjtgunhdr7yq30ha4peuwupzan2vcnwrmpy0z'
]
const result = await bchjs.Util.validateAddress(address)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.hasAnyKeys(result[0], [
"isvalid",
"address",
"scriptPubKey",
//"ismine",
//"iswatchonly",
"isscript"
'isvalid',
'address',
'scriptPubKey',
// "ismine",
// "iswatchonly",
'isscript'
])
})
it(`should throw an error for improper single input`, async () => {
it('should throw error on array size rate limit', async () => {
try {
const address = 15432
await bchjs.Util.validateAddress(address)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(
err.message,
`Input must be a string or array of strings.`
)
}
})
it(`should throw error on array size rate limit`, async () => {
try {
const dataMock = `bitcoincash:qp4k8fjtgunhdr7yq30ha4peuwupzan2vcnwrmpy0z`
const dataMock = 'bitcoincash:qp4k8fjtgunhdr7yq30ha4peuwupzan2vcnwrmpy0z'
const data = []
for (let i = 0; i < 25; i++) data.push(dataMock)
const result = await bchjs.Util.validateAddress(data)
console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
assert.hasAnyKeys(err, ['error'])
assert.include(err.error, 'Array too large')
}
})
})
})
function sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
+803 -770
View File
File diff suppressed because it is too large Load Diff
-25
View File
@@ -1,25 +0,0 @@
const chai = require("chai")
const assert = chai.assert
const BCHJS = require("../../src/bch-js")
// Used for debugging and iterrogating JS objects.
const util = require("util")
util.inspect.defaultOptions = { depth: 1 }
describe(`#BitboxShim`, () => {
it("should create the shim library", () => {
const BitboxShim = BCHJS.BitboxShim()
const bitbox = new BitboxShim()
//console.log(`bitbox.Address: ${util.inspect(bitbox.Address)}`)
assert.hasAnyKeys(bitbox.Address, [
// "details",
// "utxo",
// "unconfirmed",
// "transactions",
// "toLegacyAddress"
"restURL"
])
})
})
+56 -56
View File
@@ -1,7 +1,13 @@
const fixtures = require("./fixtures/bitcoincash.json")
const assert = require("assert")
const BCHJS = require("../../src/bch-js")
const bchjs = new BCHJS()
// Public npm libraries
const assert = require('assert')
// Mocks
const fixtures = require('./fixtures/bitcoincash.json')
// Unit under test (uut)
const BCHJS = require('../../src/bch-js')
// const bchjs = new BCHJS()
let bchjs
// TODO
// 1. generate testnet p2sh
@@ -19,29 +25,27 @@ const bchjs = new BCHJS()
// * confirm xpriv generates WIF
// 6. More error test cases.
describe("#BitcoinCash", () => {
describe("price conversion", () => {
describe("#toBitcoinCash", () => {
describe('#BitcoinCash', () => {
beforeEach(() => {
bchjs = new BCHJS()
})
describe('price conversion', () => {
it('should exercise toBitcoinCash', () => {
fixtures.conversion.toBCH.satoshis.forEach(satoshi => {
it(`should convert ${satoshi[0]} Satoshis to ${
satoshi[1]
} $BCH`, () => {
it(`should convert ${satoshi[0]} Satoshis to ${satoshi[1]} $BCH`, () => {
assert.equal(bchjs.BitcoinCash.toBitcoinCash(satoshi[0]), satoshi[1])
})
})
fixtures.conversion.toBCH.strings.forEach(satoshi => {
it(`should convert "${satoshi[0]}" Satoshis as a string to ${
satoshi[1]
} $BCH`, () => {
it(`should convert "${satoshi[0]}" Satoshis as a string to ${satoshi[1]} $BCH`, () => {
assert.equal(bchjs.BitcoinCash.toBitcoinCash(satoshi[0]), satoshi[1])
})
})
fixtures.conversion.toBCH.not.forEach(bch => {
it(`converts ${bch[0]} to Bitcoin Cash, not to ${
bch[1]
} Satoshi`, () => {
it(`converts ${bch[0]} to Bitcoin Cash, not to ${bch[1]} Satoshi`, () => {
assert.notEqual(bchjs.BitcoinCash.toBitcoinCash(bch[0]), bch[1])
})
})
@@ -53,7 +57,7 @@ describe("#BitcoinCash", () => {
})
})
describe("#toSatoshi", () => {
it('should exercise toSatoshi', () => {
fixtures.conversion.toSatoshi.bch.forEach(bch => {
it(`should convert ${bch[0]} $BCH to ${bch[1]} Satoshis`, () => {
assert.equal(bchjs.BitcoinCash.toSatoshi(bch[0]), bch[1])
@@ -61,17 +65,13 @@ describe("#BitcoinCash", () => {
})
fixtures.conversion.toSatoshi.strings.forEach(bch => {
it(`should convert "${bch[0]}" $BCH as a string to ${
bch[1]
} Satoshis`, () => {
it(`should convert "${bch[0]}" $BCH as a string to ${bch[1]} Satoshis`, () => {
assert.equal(bchjs.BitcoinCash.toSatoshi(bch[0]), bch[1])
})
})
fixtures.conversion.toSatoshi.not.forEach(satoshi => {
it(`converts ${satoshi[0]} to Satoshi, not to ${
satoshi[1]
} Bitcoin Cash`, () => {
it(`converts ${satoshi[0]} to Satoshi, not to ${satoshi[1]} Bitcoin Cash`, () => {
assert.notEqual(bchjs.BitcoinCash.toSatoshi(satoshi[0]), satoshi[1])
})
})
@@ -83,7 +83,7 @@ describe("#BitcoinCash", () => {
})
})
describe("#satsToBits", () => {
it('should exercise satsToBits', () => {
fixtures.conversion.satsToBits.bch.forEach(bch => {
it(`should convert ${bch[0]} BCH to ${bch[1]} bits`, () => {
assert.equal(
@@ -94,9 +94,7 @@ describe("#BitcoinCash", () => {
})
fixtures.conversion.satsToBits.strings.forEach(bch => {
it(`should convert "${bch[0]}" BCH as a string to ${
bch[1]
} bits`, () => {
it(`should convert "${bch[0]}" BCH as a string to ${bch[1]} bits`, () => {
assert.equal(
bchjs.BitcoinCash.satsToBits(bchjs.BitcoinCash.toSatoshi(bch[0])),
bch[1]
@@ -120,8 +118,8 @@ describe("#BitcoinCash", () => {
// });
})
describe("sign and verify messages", () => {
describe("#signMessageWithPrivKey", () => {
describe('sign and verify messages', () => {
it('should exercise signMessageWithPrivKey', () => {
fixtures.signatures.sign.forEach(sign => {
it(`should sign a message w/ ${sign.network} ${sign.privateKeyWIF}`, () => {
const privateKeyWIF = sign.privateKeyWIF
@@ -135,7 +133,7 @@ describe("#BitcoinCash", () => {
})
})
describe("#verifyMessage", () => {
it('shoudl exercise verifyMessage', () => {
fixtures.signatures.verify.forEach(sign => {
it(`should verify a valid signed message from ${sign.network} cashaddr address ${sign.address}`, () => {
assert.equal(
@@ -149,28 +147,30 @@ describe("#BitcoinCash", () => {
})
})
fixtures.signatures.verify.forEach(sign => {
const legacyAddress = bchjs.Address.toLegacyAddress(sign.address)
it(`should verify a valid signed message from ${sign.network} legacy address ${legacyAddress}`, () => {
assert.equal(
bchjs.BitcoinCash.verifyMessage(
legacyAddress,
sign.signature,
sign.message
),
true
)
it('should verify legacy addresses', () => {
fixtures.signatures.verify.forEach(sign => {
const legacyAddress = bchjs.Address.toLegacyAddress(sign.address)
it(`should verify a valid signed message from ${sign.network} legacy address ${legacyAddress}`, () => {
assert.equal(
bchjs.BitcoinCash.verifyMessage(
legacyAddress,
sign.signature,
sign.message
),
true
)
})
})
})
fixtures.signatures.verify.forEach(sign => {
const legacyAddress = bchjs.Address.toLegacyAddress(sign.address)
// const legacyAddress = bchjs.Address.toLegacyAddress(sign.address)
it(`should not verify an invalid signed message from ${sign.network} cashaddr address ${sign.address}`, () => {
assert.equal(
bchjs.BitcoinCash.verifyMessage(
sign.address,
sign.signature,
"nope"
'nope'
),
false
)
@@ -179,8 +179,8 @@ describe("#BitcoinCash", () => {
})
})
describe("encode and decode to base58Check", () => {
describe("#encodeBase58Check", () => {
describe('encode and decode to base58Check', () => {
describe('#encodeBase58Check', () => {
fixtures.encodeBase58Check.forEach((base58Check, i) => {
it(`encode ${base58Check.hex} as base58Check ${base58Check.base58Check}`, () => {
assert.equal(
@@ -191,7 +191,7 @@ describe("#BitcoinCash", () => {
})
})
describe("#decodeBase58Check", () => {
describe('#decodeBase58Check', () => {
fixtures.encodeBase58Check.forEach((base58Check, i) => {
it(`decode ${base58Check.base58Check} as ${base58Check.hex}`, () => {
assert.equal(
@@ -203,8 +203,8 @@ describe("#BitcoinCash", () => {
})
})
describe("encode and decode BIP21 urls", () => {
describe("#encodeBIP21", () => {
describe('encode and decode BIP21 urls', () => {
describe('#encodeBIP21', () => {
fixtures.bip21.valid.forEach((bip21, i) => {
it(`encode ${bip21.address} as url`, () => {
const url = bchjs.BitcoinCash.encodeBIP21(
@@ -226,7 +226,7 @@ describe("#BitcoinCash", () => {
})
})
describe("#decodeBIP21", () => {
describe('#decodeBIP21', () => {
fixtures.bip21.valid.forEach((bip21, i) => {
it(`decodes ${bip21.url}`, () => {
const decoded = bchjs.BitcoinCash.decodeBIP21(bip21.url)
@@ -252,9 +252,9 @@ describe("#BitcoinCash", () => {
})
})
describe("#getByteCount", () => {
describe('#getByteCount', () => {
fixtures.getByteCount.forEach(fixture => {
it(`get byte count`, () => {
it('get byte count', () => {
const byteCount = bchjs.BitcoinCash.getByteCount(
fixture.inputs,
fixture.outputs
@@ -264,8 +264,8 @@ describe("#BitcoinCash", () => {
})
})
describe("#bip38", () => {
describe("#encryptBIP38", () => {
describe('#bip38', () => {
describe('#encryptBIP38', () => {
fixtures.bip38.encrypt.mainnet.forEach(fixture => {
it(`BIP 38 encrypt wif ${fixture.wif} with password ${fixture.password} on mainnet`, () => {
const encryptedKey = bchjs.BitcoinCash.encryptBIP38(
@@ -287,13 +287,13 @@ describe("#BitcoinCash", () => {
})
})
describe("#decryptBIP38", () => {
describe('#decryptBIP38', () => {
fixtures.bip38.decrypt.mainnet.forEach(fixture => {
it(`BIP 38 decrypt encrypted key ${fixture.encryptedKey} on mainnet`, () => {
const wif = bchjs.BitcoinCash.decryptBIP38(
fixture.encryptedKey,
fixture.password,
"mainnet"
'mainnet'
)
assert.equal(wif, fixture.wif)
})
@@ -304,7 +304,7 @@ describe("#BitcoinCash", () => {
const wif = bchjs.BitcoinCash.decryptBIP38(
fixture.encryptedKey,
fixture.password,
"testnet"
'testnet'
)
assert.equal(wif, fixture.wif)
})
-275
View File
@@ -1,275 +0,0 @@
const chai = require("chai")
const assert = chai.assert
const BCHJS = require("../../src/bch-js")
const bchjs = new BCHJS()
const axios = require("axios")
const sinon = require("sinon")
const mockData = require("./fixtures/blockbook-mock")
describe(`#Blockbook`, () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
afterEach(() => sandbox.restore())
describe(`#Balance`, () => {
it(`should GET balance for a single address`, async () => {
// Stub the network call.
sandbox.stub(axios, "get").resolves({ data: mockData.balance })
const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
const result = await bchjs.Blockbook.balance(addr)
//console.log(`result: ${util.inspect(result)}`)
assert.hasAnyKeys(result, [
"page",
"totalPages",
"itemsOnPage",
"address",
"balance",
"totalReceived",
"totalSent",
"unconfirmedBalance",
"unconfirmedTxs",
"txs",
"txids"
])
assert.isArray(result.txids)
})
it(`should POST request balances for an array of addresses`, async () => {
// Stub the network call.
sandbox
.stub(axios, "post")
.resolves({ data: [mockData.balance, mockData.balance] })
const addr = [
"bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
"bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
]
const result = await bchjs.Blockbook.balance(addr)
//console.log(`result: ${util.inspect(result)}`)
assert.isArray(result)
assert.hasAnyKeys(result[0], [
"page",
"totalPages",
"itemsOnPage",
"address",
"balance",
"totalReceived",
"totalSent",
"unconfirmedBalance",
"unconfirmedTxs",
"txs",
"txids"
])
assert.isArray(result[0].txids)
})
it(`should throw an error for improper input`, async () => {
try {
// Stub the network call.
sandbox
.stub(axios, "post")
.throws(`Input address must be a string or array of strings`)
const addr = 12345
await bchjs.Blockbook.balance(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(
err.message,
`Input address must be a string or array of strings`
)
}
})
/*
it(`should throw error on array size rate limit`, async () => {
try {
// Stub the network call.
sandbox.stub(axios, "post").throws(`Array too large`)
const addr = []
for (let i = 0; i < 25; i++)
addr.push("bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf")
const result = await bchjs.Blockbook.balance(addr)
console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
}
})
*/
})
describe(`#utxo`, () => {
it(`should GET utxos for a single address`, async () => {
// Stub the network call.
sandbox.stub(axios, "get").resolves({ data: mockData.utxo })
const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
const result = await bchjs.Blockbook.utxo(addr)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.hasAnyKeys(result[0], [
"txid",
"vout",
"value",
"height",
"confirmations"
])
})
it(`should POST utxo details for an array of addresses`, async () => {
// Stub the network call.
sandbox.stub(axios, "post").resolves({ data: mockData.utxos })
const addr = [
"bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
"bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
]
const result = await bchjs.Blockbook.utxo(addr)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.isArray(result[0])
assert.hasAnyKeys(result[0][0], [
"txid",
"vout",
"value",
"height",
"confirmations"
])
})
it(`should throw an error for improper input`, async () => {
try {
// Stub the network call.
sandbox
.stub(axios, "post")
.throws(`Input address must be a string or array of strings`)
const addr = 12345
await bchjs.Blockbook.utxo(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(
err.message,
`Input address must be a string or array of strings`
)
}
})
/*
it(`should throw error on array size rate limit`, async () => {
try {
const addr = []
for (let i = 0; i < 25; i++)
addr.push("bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf")
const result = await bchjs.Blockbook.utxo(addr)
console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
}
})
*/
})
describe(`#tx`, () => {
it(`should GET tx details for a single txid`, async () => {
// Stub the network call.
sandbox.stub(axios, "get").resolves({ data: mockData.utxo })
const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
const result = await bchjs.Blockbook.utxo(addr)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.hasAnyKeys(result[0], [
"txid",
"vout",
"value",
"height",
"confirmations"
])
})
// it(`should POST utxo details for an array of addresses`, async () => {
// // Stub the network call.
// sandbox.stub(axios, "post").resolves({ data: mockData.utxos })
//
// const addr = [
// "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
// "bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
// ]
//
// const result = await bchjs.Blockbook.utxo(addr)
// //console.log(`result: ${JSON.stringify(result, null, 2)}`)
//
// assert.isArray(result)
// assert.isArray(result[0])
// assert.hasAnyKeys(result[0][0], [
// "txid",
// "vout",
// "value",
// "height",
// "confirmations"
// ])
// })
// it(`should throw an error for improper input`, async () => {
// try {
// // Stub the network call.
// sandbox
// .stub(axios, "post")
// .throws(`Input address must be a string or array of strings`)
//
// const addr = 12345
//
// await bchjs.Blockbook.utxo(addr)
// assert.equal(true, false, "Unexpected result!")
// } catch (err) {
// //console.log(`err: `, err)
// assert.include(
// err.message,
// `Input address must be a string or array of strings`
// )
// }
// })
/*
it(`should throw error on array size rate limit`, async () => {
try {
const addr = []
for (let i = 0; i < 25; i++)
addr.push("bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf")
const result = await bchjs.Blockbook.utxo(addr)
console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
}
})
*/
})
})
+149 -146
View File
@@ -1,102 +1,102 @@
const assert = require("assert")
const assert2 = require("chai").assert
const axios = require("axios")
const BCHJS = require("../../src/bch-js")
const assert = require('assert')
const assert2 = require('chai').assert
const axios = require('axios')
const BCHJS = require('../../src/bch-js')
const bchjs = new BCHJS()
const sinon = require("sinon")
const sinon = require('sinon')
const mockData = require("./fixtures/blockchain-mock")
const mockData = require('./fixtures/blockchain-mock')
describe("#Blockchain", () => {
describe("#getBestBlockHash", () => {
describe('#Blockchain', () => {
describe('#getBestBlockHash', () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
afterEach(() => sandbox.restore())
it("should get best block hash", done => {
const resolved = new Promise(r =>
r({
it('should get best block hash', done => {
const resolved = new Promise(resolve =>
resolve({
data:
"0000000000000000005f1f550d3d8b142b684277016ebd00fa29c668606ae52d"
'0000000000000000005f1f550d3d8b142b684277016ebd00fa29c668606ae52d'
})
)
sandbox.stub(axios, "get").returns(resolved)
sandbox.stub(axios, 'get').returns(resolved)
bchjs.Blockchain.getBestBlockHash()
.then(result => {
const hash =
"0000000000000000005f1f550d3d8b142b684277016ebd00fa29c668606ae52d"
assert.equal(hash, result)
'0000000000000000005f1f550d3d8b142b684277016ebd00fa29c668606ae52d'
assert.strictEqual(hash, result)
})
.then(done, done)
})
})
describe("#getBlock", () => {
describe('#getBlock', () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
afterEach(() => sandbox.restore())
const data = {
hash: "00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09",
hash: '00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09',
confirmations: 526807,
size: 216,
height: 1000,
version: 1,
versionHex: "00000001",
versionHex: '00000001',
merkleroot:
"fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33",
tx: ["fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33"],
'fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33',
tx: ['fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33'],
time: 1232346882,
mediantime: 1232344831,
nonce: 2595206198,
bits: "1d00ffff",
bits: '1d00ffff',
difficulty: 1,
chainwork:
"000000000000000000000000000000000000000000000000000003e903e903e9",
'000000000000000000000000000000000000000000000000000003e903e903e9',
previousblockhash:
"0000000008e647742775a230787d66fdf92c46a48c896bfbc85cdc8acc67e87d",
'0000000008e647742775a230787d66fdf92c46a48c896bfbc85cdc8acc67e87d',
nextblockhash:
"00000000a2887344f8db859e372e7e4bc26b23b9de340f725afbf2edb265b4c6"
'00000000a2887344f8db859e372e7e4bc26b23b9de340f725afbf2edb265b4c6'
}
it("should get block by hash", done => {
const resolved = new Promise(r => r({ data: data }))
sandbox.stub(axios, "get").returns(resolved)
it('should get block by hash', done => {
const resolved = new Promise(resolve => resolve({ data: data }))
sandbox.stub(axios, 'get').returns(resolved)
bchjs.Blockchain.getBlock(
"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"
'00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09'
)
.then(result => {
assert.deepEqual(data, result)
assert.deepStrictEqual(data, result)
})
.then(done, done)
})
})
describe("#getBlockchainInfo", () => {
describe('#getBlockchainInfo', () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
afterEach(() => sandbox.restore())
const data = {
chain: "main",
chain: 'main',
blocks: 527810,
headers: 527810,
bestblockhash:
"000000000000000001d127592d091d4c45062504663c9acab27a1b16c028e3c0",
'000000000000000001d127592d091d4c45062504663c9acab27a1b16c028e3c0',
difficulty: 576023394804.6666,
mediantime: 1524878499,
verificationprogress: 0.9999990106793685,
chainwork:
"00000000000000000000000000000000000000000096da5b040913fa09249b4e",
'00000000000000000000000000000000000000000096da5b040913fa09249b4e',
pruned: false,
softforks: [
{ id: "bip34", version: 2, reject: [Object] },
{ id: "bip66", version: 3, reject: [Object] },
{ id: "bip65", version: 4, reject: [Object] }
{ id: 'bip34', version: 2, reject: [Object] },
{ id: 'bip66', version: 3, reject: [Object] },
{ id: 'bip65', version: 4, reject: [Object] }
],
bip9_softforks: {
csv: {
status: "active",
status: 'active',
startTime: 1462060800,
timeout: 1493596800,
since: 419328
@@ -104,178 +104,178 @@ describe("#Blockchain", () => {
}
}
it("should get blockchain info", done => {
const resolved = new Promise(r => r({ data: data }))
sandbox.stub(axios, "get").returns(resolved)
it('should get blockchain info', done => {
const resolved = new Promise(resolve => resolve({ data: data }))
sandbox.stub(axios, 'get').returns(resolved)
bchjs.Blockchain.getBlockchainInfo()
.then(result => {
assert.deepEqual(data, result)
assert.deepStrictEqual(data, result)
})
.then(done, done)
})
})
describe("#getBlockCount", () => {
describe('#getBlockCount', () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
afterEach(() => sandbox.restore())
const data = 527810
it("should get block count", done => {
const resolved = new Promise(r => r({ data: data }))
sandbox.stub(axios, "get").returns(resolved)
it('should get block count', done => {
const resolved = new Promise(resolve => resolve({ data: data }))
sandbox.stub(axios, 'get').returns(resolved)
bchjs.Blockchain.getBlockCount()
.then(result => {
assert.deepEqual(data, result)
assert.deepStrictEqual(data, result)
})
.then(done, done)
})
})
describe("#getBlockHash", () => {
describe('#getBlockHash', () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
afterEach(() => sandbox.restore())
const data =
"000000000000000001d127592d091d4c45062504663c9acab27a1b16c028e3c0"
'000000000000000001d127592d091d4c45062504663c9acab27a1b16c028e3c0'
it("should get block hash by height", done => {
const resolved = new Promise(r => r({ data: data }))
sandbox.stub(axios, "get").returns(resolved)
it('should get block hash by height', done => {
const resolved = new Promise(resolve => resolve({ data: data }))
sandbox.stub(axios, 'get').returns(resolved)
bchjs.Blockchain.getBlockHash(527810)
.then(result => {
assert.deepEqual(data, result)
assert.deepStrictEqual(data, result)
})
.then(done, done)
})
})
describe("#getBlockHeader", () => {
describe('#getBlockHeader', () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
afterEach(() => sandbox.restore())
const data = {
hash: "000000000000000001d127592d091d4c45062504663c9acab27a1b16c028e3c0",
hash: '000000000000000001d127592d091d4c45062504663c9acab27a1b16c028e3c0',
confirmations: 1,
height: 527810,
version: 536870912,
versionHex: "20000000",
versionHex: '20000000',
merkleroot:
"9298432bbebe4638456aa19cb7ef91639da87668a285d88d0ecd6080424d223b",
'9298432bbebe4638456aa19cb7ef91639da87668a285d88d0ecd6080424d223b',
time: 1524881438,
mediantime: 1524878499,
nonce: 3326843941,
bits: "1801e8a5",
bits: '1801e8a5',
difficulty: 576023394804.6666,
chainwork:
"00000000000000000000000000000000000000000096da5b040913fa09249b4e",
'00000000000000000000000000000000000000000096da5b040913fa09249b4e',
previousblockhash:
"000000000000000000b33251708bc7a7b4540e61880d8c376e8e2db6a19a4789"
'000000000000000000b33251708bc7a7b4540e61880d8c376e8e2db6a19a4789'
}
it("should get block header by hash", done => {
const resolved = new Promise(r => r({ data: data }))
sandbox.stub(axios, "get").returns(resolved)
it('should get block header by hash', done => {
const resolved = new Promise(resolve => resolve({ data: data }))
sandbox.stub(axios, 'get').returns(resolved)
bchjs.Blockchain.getBlockHeader(
"000000000000000001d127592d091d4c45062504663c9acab27a1b16c028e3c0",
'000000000000000001d127592d091d4c45062504663c9acab27a1b16c028e3c0',
true
)
.then(result => {
assert.deepEqual(data, result)
assert.deepStrictEqual(data, result)
})
.then(done, done)
})
})
describe("#getDifficulty", () => {
describe('#getDifficulty', () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
afterEach(() => sandbox.restore())
const data = "577528469277.1339"
const data = '577528469277.1339'
it("should get difficulty", done => {
const resolved = new Promise(r => r({ data: data }))
sandbox.stub(axios, "get").returns(resolved)
it('should get difficulty', done => {
const resolved = new Promise(resolve => resolve({ data: data }))
sandbox.stub(axios, 'get').returns(resolved)
bchjs.Blockchain.getDifficulty()
.then(result => {
assert.deepEqual(data, result)
assert.deepStrictEqual(data, result)
})
.then(done, done)
})
})
describe("#getMempoolAncestors", () => {
describe('#getMempoolAncestors', () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
afterEach(() => sandbox.restore())
const data = "Transaction not in mempool"
const data = 'Transaction not in mempool'
it("should get mempool ancestors", done => {
const resolved = new Promise(r => r({ data: data }))
sandbox.stub(axios, "get").returns(resolved)
it('should get mempool ancestors', done => {
const resolved = new Promise(resolve => resolve({ data: data }))
sandbox.stub(axios, 'get').returns(resolved)
bchjs.Blockchain.getMempoolAncestors(
"daf58932cb91619304dd4cbd03c7202e89ad7d6cbd6e2209e5f64ce3b6ed7c88",
'daf58932cb91619304dd4cbd03c7202e89ad7d6cbd6e2209e5f64ce3b6ed7c88',
true
)
.then(result => {
assert.deepEqual(data, result)
assert.deepStrictEqual(data, result)
})
.then(done, done)
})
})
describe("#getMempoolDescendants", () => {
describe('#getMempoolDescendants', () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
afterEach(() => sandbox.restore())
const data = {
result: "Transaction not in mempool"
result: 'Transaction not in mempool'
}
it("should get mempool descendants", done => {
const resolved = new Promise(r => r({ data: data }))
sandbox.stub(axios, "get").returns(resolved)
it('should get mempool descendants', done => {
const resolved = new Promise(resolve => resolve({ data: data }))
sandbox.stub(axios, 'get').returns(resolved)
bchjs.Blockchain.getMempoolDescendants(
"daf58932cb91619304dd4cbd03c7202e89ad7d6cbd6e2209e5f64ce3b6ed7c88",
'daf58932cb91619304dd4cbd03c7202e89ad7d6cbd6e2209e5f64ce3b6ed7c88',
true
)
.then(result => {
assert.deepEqual(data, result)
assert.deepStrictEqual(data, result)
})
.then(done, done)
})
})
describe("#getMempoolEntry", () => {
describe('#getMempoolEntry', () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
afterEach(() => sandbox.restore())
const data = {
result: "Transaction not in mempool"
result: 'Transaction not in mempool'
}
it("should get mempool entry", done => {
const resolved = new Promise(r => r({ data: data }))
sandbox.stub(axios, "get").returns(resolved)
it('should get mempool entry', done => {
const resolved = new Promise(resolve => resolve({ data: data }))
sandbox.stub(axios, 'get').returns(resolved)
bchjs.Blockchain.getMempoolEntry(
"daf58932cb91619304dd4cbd03c7202e89ad7d6cbd6e2209e5f64ce3b6ed7c88"
'daf58932cb91619304dd4cbd03c7202e89ad7d6cbd6e2209e5f64ce3b6ed7c88'
)
.then(result => {
assert.deepEqual(data, result)
assert.deepStrictEqual(data, result)
})
.then(done, done)
})
})
describe("#getMempoolInfo", () => {
describe('#getMempoolInfo', () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
afterEach(() => sandbox.restore())
@@ -289,19 +289,19 @@ describe("#Blockchain", () => {
}
}
it("should get mempool info", done => {
const resolved = new Promise(r => r({ data: data }))
sandbox.stub(axios, "get").returns(resolved)
it('should get mempool info', done => {
const resolved = new Promise(resolve => resolve({ data: data }))
sandbox.stub(axios, 'get').returns(resolved)
bchjs.Blockchain.getMempoolInfo()
.then(result => {
assert.deepEqual(data, result)
assert.deepStrictEqual(data, result)
})
.then(done, done)
})
})
describe("#getRawMempool", () => {
describe('#getRawMempool', () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
afterEach(() => sandbox.restore())
@@ -310,7 +310,7 @@ describe("#Blockchain", () => {
transactions: [
{
txid:
"ab36d68dd0a618592fe34e4a898e8beeeb4049133547dbb16f9338384084af96",
'ab36d68dd0a618592fe34e4a898e8beeeb4049133547dbb16f9338384084af96',
size: 191,
fee: 0.00047703,
modifiedfee: 0.00047703,
@@ -330,19 +330,19 @@ describe("#Blockchain", () => {
}
}
it("should get mempool info", done => {
const resolved = new Promise(r => r({ data: data }))
sandbox.stub(axios, "get").returns(resolved)
it('should get mempool info', done => {
const resolved = new Promise(resolve => resolve({ data: data }))
sandbox.stub(axios, 'get').returns(resolved)
bchjs.Blockchain.getRawMempool()
.then(result => {
assert.deepEqual(data, result)
assert.deepStrictEqual(data, result)
})
.then(done, done)
})
})
describe("#getTxOut", () => {
describe('#getTxOut', () => {
// TODO finish this test
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
@@ -351,63 +351,66 @@ describe("#Blockchain", () => {
// result: {}
// }
it("should throw an error for improper txid.", async () => {
it('should throw an error for improper txid.', async () => {
try {
await bchjs.Blockchain.getTxOut("badtxid")
await bchjs.Blockchain.getTxOut('badtxid')
} catch (err) {
assert2.include(err.message, "txid needs to be a proper transaction ID")
assert2.include(
err.message,
'txid needs to be a proper transaction ID'
)
}
})
it("should throw an error if no vout value is provided.", async () => {
it('should throw an error if no vout value is provided.', async () => {
try {
await bchjs.Blockchain.getTxOut(
"daf58932cb91619304dd4cbd03c7202e89ad7d6cbd6e2209e5f64ce3b6ed7c88"
'daf58932cb91619304dd4cbd03c7202e89ad7d6cbd6e2209e5f64ce3b6ed7c88'
)
} catch (err) {
assert2.include(err.message, "n must be an integer")
assert2.include(err.message, 'n must be an integer')
}
})
it("should throw an error if include_mempool is not a boolean", async () => {
it('should throw an error if include_mempool is not a boolean', async () => {
try {
await bchjs.Blockchain.getTxOut(
"daf58932cb91619304dd4cbd03c7202e89ad7d6cbd6e2209e5f64ce3b6ed7c88",
'daf58932cb91619304dd4cbd03c7202e89ad7d6cbd6e2209e5f64ce3b6ed7c88',
0,
"bad value"
'bad value'
)
} catch (err) {
assert2.include(
err.message,
"include_mempool input must be of type boolean"
'includeMempool input must be of type boolean'
)
}
})
it("should get information on an unspent tx", async () => {
sandbox.stub(axios, "post").resolves({ data: mockData.txOutUnspent })
it('should get information on an unspent tx', async () => {
sandbox.stub(axios, 'post').resolves({ data: mockData.txOutUnspent })
const result = await bchjs.Blockchain.getTxOut(
"62a3ea958a463a372bc0caf2c374a7f60be9c624be63a0db8db78f05809df6d8",
'62a3ea958a463a372bc0caf2c374a7f60be9c624be63a0db8db78f05809df6d8',
0,
true
)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert2.hasAllKeys(result, [
"bestblock",
"confirmations",
"value",
"scriptPubKey",
"coinbase"
'bestblock',
'confirmations',
'value',
'scriptPubKey',
'coinbase'
])
})
it("should get information on a spent tx", async () => {
sandbox.stub(axios, "post").resolves({ data: null })
it('should get information on a spent tx', async () => {
sandbox.stub(axios, 'post').resolves({ data: null })
const result = await bchjs.Blockchain.getTxOut(
"87380e52d151856b23173d6d8a3db01b984c6b50f77ea045a5a1cf4f54497871",
'87380e52d151856b23173d6d8a3db01b984c6b50f77ea045a5a1cf4f54497871',
0,
true
)
@@ -417,7 +420,7 @@ describe("#Blockchain", () => {
})
})
describe("#preciousBlock", () => {
describe('#preciousBlock', () => {
// TODO finish this test
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
@@ -426,67 +429,67 @@ describe("#Blockchain", () => {
result: {}
}
it("should get TODO", done => {
const resolved = new Promise(r => r({ data: data }))
sandbox.stub(axios, "get").returns(resolved)
it('should get TODO', done => {
const resolved = new Promise(resolve => resolve({ data: data }))
sandbox.stub(axios, 'get').returns(resolved)
bchjs.Blockchain.preciousBlock()
.then(result => {
assert.deepEqual(data, result)
assert.deepStrictEqual(data, result)
})
.then(done, done)
})
})
describe("#pruneBlockchain", () => {
describe('#pruneBlockchain', () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
afterEach(() => sandbox.restore())
const data = "Cannot prune blocks because node is not in prune mode."
const data = 'Cannot prune blocks because node is not in prune mode.'
it("should prune blockchain", done => {
const resolved = new Promise(r => r({ data: data }))
sandbox.stub(axios, "post").returns(resolved)
it('should prune blockchain', done => {
const resolved = new Promise(resolve => resolve({ data: data }))
sandbox.stub(axios, 'post').returns(resolved)
bchjs.Blockchain.pruneBlockchain(507)
.then(result => {
assert.deepEqual(data, result)
assert.deepStrictEqual(data, result)
})
.then(done, done)
})
})
describe("#verifyChain", () => {
describe('#verifyChain', () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
afterEach(() => sandbox.restore())
const data = true
it("should verify blockchain", done => {
const resolved = new Promise(r => r({ data: data }))
sandbox.stub(axios, "get").returns(resolved)
it('should verify blockchain', done => {
const resolved = new Promise(resolve => resolve({ data: data }))
sandbox.stub(axios, 'get').returns(resolved)
bchjs.Blockchain.verifyChain(3, 6)
.then(result => {
assert.deepEqual(data, result)
assert.deepStrictEqual(data, result)
})
.then(done, done)
})
})
describe("#verifyTxOutProof", () => {
describe('#verifyTxOutProof', () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
afterEach(() => sandbox.restore())
const data = "proof must be hexadecimal string (not '')"
it("should verify utxo proof", done => {
const resolved = new Promise(r => r({ data: data }))
sandbox.stub(axios, "get").returns(resolved)
it('should verify utxo proof', done => {
const resolved = new Promise(resolve => resolve({ data: data }))
sandbox.stub(axios, 'get').returns(resolved)
bchjs.Blockchain.verifyTxOutProof("3")
bchjs.Blockchain.verifyTxOutProof('3')
.then(result => {
assert.deepEqual(data, result)
assert.deepStrictEqual(data, result)
})
.then(done, done)
})
+17 -17
View File
@@ -1,46 +1,46 @@
const assert = require("assert")
const axios = require("axios")
const BCHJS = require("../../src/bch-js")
const assert = require('assert')
const axios = require('axios')
const BCHJS = require('../../src/bch-js')
const bchjs = new BCHJS()
const sinon = require("sinon")
const sinon = require('sinon')
describe("#Control", () => {
describe("#getNetworkInfo", () => {
describe('#Control', () => {
describe('#getNetworkInfo', () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
afterEach(() => sandbox.restore())
it("should get info", done => {
it('should get info', done => {
const data = {
version: 170000,
protocolversion: 70015,
blocks: 527813,
timeoffset: 0,
connections: 21,
proxy: "",
proxy: '',
difficulty: 581086703759.5878,
testnet: false,
paytxfee: 0,
relayfee: 0.00001,
errors: ""
errors: ''
}
const resolved = new Promise(r => r({ data: data }))
sandbox.stub(axios, "get").returns(resolved)
const resolved = new Promise(resolve => resolve({ data: data }))
sandbox.stub(axios, 'get').returns(resolved)
bchjs.Control.getNetworkInfo()
.then(result => {
assert.deepEqual(data, result)
assert.deepStrictEqual(data, result)
})
.then(done, done)
})
})
describe("#getMemoryInfo", () => {
describe('#getMemoryInfo', () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
afterEach(() => sandbox.restore())
it("should get memory info", done => {
it('should get memory info', done => {
const data = {
locked: {
used: 0,
@@ -51,12 +51,12 @@ describe("#Control", () => {
chunks_free: 1
}
}
const resolved = new Promise(r => r({ data: data }))
sandbox.stub(axios, "get").returns(resolved)
const resolved = new Promise(resolve => resolve({ data: data }))
sandbox.stub(axios, 'get').returns(resolved)
bchjs.Control.getMemoryInfo()
.then(result => {
assert.deepEqual(data, result)
assert.deepStrictEqual(data, result)
})
.then(done, done)
})
+35 -35
View File
@@ -1,97 +1,97 @@
const fixtures = require("./fixtures/crypto.json")
const assert = require("assert")
const BCHJS = require("../../src/bch-js")
const fixtures = require('./fixtures/crypto.json')
const assert = require('assert')
const BCHJS = require('../../src/bch-js')
const bchjs = new BCHJS()
const Buffer = require("safe-buffer").Buffer
const Buffer = require('safe-buffer').Buffer
describe("#Crypto", () => {
describe("#sha256", () => {
describe('#Crypto', () => {
describe('#sha256', () => {
fixtures.sha256.forEach(fixture => {
it(`should create SHA256Hash hex encoded ${fixture.hash} from ${fixture.hex}`, () => {
const data = Buffer.from(fixture.hex, "hex")
const sha256Hash = bchjs.Crypto.sha256(data).toString("hex")
const data = Buffer.from(fixture.hex, 'hex')
const sha256Hash = bchjs.Crypto.sha256(data).toString('hex')
assert.equal(sha256Hash, fixture.hash)
})
it(`should create 64 character SHA256Hash hex encoded`, () => {
const data = Buffer.from(fixture.hex, "hex")
const sha256Hash = bchjs.Crypto.sha256(data).toString("hex")
it('should create 64 character SHA256Hash hex encoded', () => {
const data = Buffer.from(fixture.hex, 'hex')
const sha256Hash = bchjs.Crypto.sha256(data).toString('hex')
assert.equal(sha256Hash.length, 64)
})
})
})
describe("#ripemd160", () => {
describe('#ripemd160', () => {
fixtures.ripemd160.forEach(fixture => {
it(`should create RIPEMD160Hash hex encoded ${fixture.hash} from ${fixture.hex}`, () => {
const data = Buffer.from(fixture.hex, "hex")
const ripemd160 = bchjs.Crypto.ripemd160(data).toString("hex")
const data = Buffer.from(fixture.hex, 'hex')
const ripemd160 = bchjs.Crypto.ripemd160(data).toString('hex')
assert.equal(ripemd160, fixture.hash)
})
it(`should create 64 character RIPEMD160Hash hex encoded`, () => {
const data = Buffer.from(fixture.hex, "hex")
const ripemd160 = bchjs.Crypto.ripemd160(data).toString("hex")
it('should create 64 character RIPEMD160Hash hex encoded', () => {
const data = Buffer.from(fixture.hex, 'hex')
const ripemd160 = bchjs.Crypto.ripemd160(data).toString('hex')
assert.equal(ripemd160.length, 40)
})
})
})
describe("#hash256", () => {
describe('#hash256', () => {
fixtures.hash256.forEach(fixture => {
it(`should create double SHA256 Hash hex encoded ${fixture.hash} from ${fixture.hex}`, () => {
const data = Buffer.from(fixture.hex, "hex")
const hash256 = bchjs.Crypto.hash256(data).toString("hex")
const data = Buffer.from(fixture.hex, 'hex')
const hash256 = bchjs.Crypto.hash256(data).toString('hex')
assert.equal(hash256, fixture.hash)
})
it(`should create 64 character SHA256 Hash hex encoded`, () => {
const data = Buffer.from(fixture.hex, "hex")
const hash256 = bchjs.Crypto.hash256(data).toString("hex")
it('should create 64 character SHA256 Hash hex encoded', () => {
const data = Buffer.from(fixture.hex, 'hex')
const hash256 = bchjs.Crypto.hash256(data).toString('hex')
assert.equal(hash256.length, 64)
})
})
})
describe("#hash160", () => {
describe('#hash160', () => {
fixtures.hash160.forEach(fixture => {
it(`should create RIPEMD160(SHA256()) hex encoded ${fixture.hash} from ${fixture.hex}`, () => {
const data = Buffer.from(fixture.hex, "hex")
const hash160 = bchjs.Crypto.hash160(data).toString("hex")
const data = Buffer.from(fixture.hex, 'hex')
const hash160 = bchjs.Crypto.hash160(data).toString('hex')
assert.equal(hash160, fixture.hash)
})
it(`should create 64 character SHA256Hash hex encoded`, () => {
const data = Buffer.from(fixture.hex, "hex")
const hash160 = bchjs.Crypto.hash160(data).toString("hex")
it('should create 64 character SHA256Hash hex encoded', () => {
const data = Buffer.from(fixture.hex, 'hex')
const hash160 = bchjs.Crypto.hash160(data).toString('hex')
assert.equal(hash160.length, 40)
})
})
})
describe("#randomBytes", () => {
describe('#randomBytes', () => {
for (let i = 0; i < 6; i++) {
it("should return 16 bytes of entropy hex encoded", () => {
it('should return 16 bytes of entropy hex encoded', () => {
const entropy = bchjs.Crypto.randomBytes(16)
assert.equal(Buffer.byteLength(entropy), 16)
})
it("should return 20 bytes of entropy hex encoded", () => {
it('should return 20 bytes of entropy hex encoded', () => {
const entropy = bchjs.Crypto.randomBytes(20)
assert.equal(Buffer.byteLength(entropy), 20)
})
it("should return 24 bytes of entropy hex encoded", () => {
it('should return 24 bytes of entropy hex encoded', () => {
const entropy = bchjs.Crypto.randomBytes(24)
assert.equal(Buffer.byteLength(entropy), 24)
})
it("should return 28 bytes of entropy hex encoded", () => {
it('should return 28 bytes of entropy hex encoded', () => {
const entropy = bchjs.Crypto.randomBytes(28)
assert.equal(Buffer.byteLength(entropy), 28)
})
it("should return 32 bytes of entropy hex encoded", () => {
it('should return 32 bytes of entropy hex encoded', () => {
const entropy = bchjs.Crypto.randomBytes(32)
assert.equal(Buffer.byteLength(entropy), 32)
})
+37 -30
View File
@@ -1,18 +1,25 @@
const assert = require("assert")
// Public npm libraries.
const assert = require('assert')
const Buffer = require('safe-buffer').Buffer
const BCHJS = require("../../src/bch-js")
const bchjs = new BCHJS()
// Mocks
const fixtures = require('./fixtures/ecpair.json')
const Buffer = require("safe-buffer").Buffer
// Unit under test (uut)
const BCHJS = require('../../src/bch-js')
// const bchjs = new BCHJS()
let bchjs
const fixtures = require("./fixtures/ecpair.json")
describe('#ECPair', () => {
beforeEach(() => {
bchjs = new BCHJS()
})
describe("#ECPair", () => {
describe("#fromWIF", () => {
describe('#fromWIF', () => {
fixtures.fromWIF.forEach(fixture => {
it(`should create ECPair from WIF ${fixture.privateKeyWIF}`, () => {
const ecpair = bchjs.ECPair.fromWIF(fixture.privateKeyWIF)
assert.equal(typeof ecpair, "object")
assert.equal(typeof ecpair, 'object')
})
it(`should get ${fixture.legacy} legacy address`, () => {
@@ -35,7 +42,7 @@ describe("#ECPair", () => {
})
})
describe("#toWIF", () => {
describe('#toWIF', () => {
fixtures.toWIF.forEach(fixture => {
it(`should get WIF ${fixture.privateKeyWIF} from ECPair`, () => {
const ecpair = bchjs.ECPair.fromWIF(fixture.privateKeyWIF)
@@ -45,32 +52,32 @@ describe("#ECPair", () => {
})
})
describe("#fromPublicKey", () => {
describe('#fromPublicKey', () => {
fixtures.fromPublicKey.forEach(fixture => {
it(`should create ECPair from public key buffer`, () => {
it('should create ECPair from public key buffer', () => {
const ecpair = bchjs.ECPair.fromPublicKey(
Buffer.from(fixture.pubkeyHex, "hex")
Buffer.from(fixture.pubkeyHex, 'hex')
)
assert.equal(typeof ecpair, "object")
assert.equal(typeof ecpair, 'object')
})
it(`should get ${fixture.legacy} legacy address`, () => {
const ecpair = bchjs.ECPair.fromPublicKey(
Buffer.from(fixture.pubkeyHex, "hex")
Buffer.from(fixture.pubkeyHex, 'hex')
)
assert.equal(bchjs.HDNode.toLegacyAddress(ecpair), fixture.legacy)
})
it(`should get ${fixture.cashAddr} cash address`, () => {
const ecpair = bchjs.ECPair.fromPublicKey(
Buffer.from(fixture.pubkeyHex, "hex")
Buffer.from(fixture.pubkeyHex, 'hex')
)
assert.equal(bchjs.HDNode.toCashAddress(ecpair), fixture.cashAddr)
})
it(`should get ${fixture.regtestAddr} cash address`, () => {
const ecpair = bchjs.ECPair.fromPublicKey(
Buffer.from(fixture.pubkeyHex, "hex")
Buffer.from(fixture.pubkeyHex, 'hex')
)
assert.equal(
bchjs.HDNode.toCashAddress(ecpair, true),
@@ -80,19 +87,19 @@ describe("#ECPair", () => {
})
})
describe("#toPublicKey", () => {
describe('#toPublicKey', () => {
fixtures.toPublicKey.forEach(fixture => {
it(`should create a public key buffer from an ECPair`, () => {
it('should create a public key buffer from an ECPair', () => {
const ecpair = bchjs.ECPair.fromPublicKey(
Buffer.from(fixture.pubkeyHex, "hex")
Buffer.from(fixture.pubkeyHex, 'hex')
)
const pubkeyBuffer = bchjs.ECPair.toPublicKey(ecpair)
assert.equal(typeof pubkeyBuffer, "object")
assert.equal(typeof pubkeyBuffer, 'object')
})
})
})
describe("#toLegacyAddress", () => {
describe('#toLegacyAddress', () => {
fixtures.toLegacyAddress.forEach(fixture => {
it(`should create legacy address ${fixture.legacy} from an ECPair`, () => {
const ecpair = bchjs.ECPair.fromWIF(fixture.privateKeyWIF)
@@ -102,7 +109,7 @@ describe("#ECPair", () => {
})
})
describe("#toCashAddress", () => {
describe('#toCashAddress', () => {
fixtures.toCashAddress.forEach(fixture => {
it(`should create cash address ${fixture.cashAddr} from an ECPair`, () => {
const ecpair = bchjs.ECPair.fromWIF(fixture.privateKeyWIF)
@@ -120,23 +127,23 @@ describe("#ECPair", () => {
})
})
describe("#sign", () => {
describe('#sign', () => {
fixtures.sign.forEach(fixture => {
it(`should sign 32 byte hash buffer`, () => {
it('should sign 32 byte hash buffer', () => {
const ecpair = bchjs.ECPair.fromWIF(fixture.privateKeyWIF)
const buf = Buffer.from(bchjs.Crypto.sha256(fixture.data), "hex")
const buf = Buffer.from(bchjs.Crypto.sha256(fixture.data), 'hex')
const signatureBuf = bchjs.ECPair.sign(ecpair, buf)
assert.equal(typeof signatureBuf, "object")
assert.equal(typeof signatureBuf, 'object')
})
})
})
describe("#verify", () => {
describe('#verify', () => {
fixtures.verify.forEach(fixture => {
it(`should verify signed 32 byte hash buffer`, () => {
it('should verify signed 32 byte hash buffer', () => {
const ecpair1 = bchjs.ECPair.fromWIF(fixture.privateKeyWIF1)
//const ecpair2 = bchjs.ECPair.fromWIF(fixture.privateKeyWIF2)
const buf = Buffer.from(bchjs.Crypto.sha256(fixture.data), "hex")
// const ecpair2 = bchjs.ECPair.fromWIF(fixture.privateKeyWIF2)
const buf = Buffer.from(bchjs.Crypto.sha256(fixture.data), 'hex')
const signature = bchjs.ECPair.sign(ecpair1, buf)
const verify = bchjs.ECPair.verify(ecpair1, buf, signature)
assert.equal(verify, true)
+254 -96
View File
@@ -1,263 +1,421 @@
const chai = require("chai")
const chai = require('chai')
const assert = chai.assert
const axios = require("axios")
const sinon = require("sinon")
const axios = require('axios')
const sinon = require('sinon')
const BCHJS = require("../../src/bch-js")
const BCHJS = require('../../src/bch-js')
const bchjs = new BCHJS()
const mockData = require("./fixtures/electrumx-mock")
const mockData = require('./fixtures/electrumx-mock')
describe(`#ElectrumX`, () => {
describe('#ElectrumX', () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
afterEach(() => sandbox.restore())
describe(`#utxo`, () => {
it(`should throw an error for improper input`, async () => {
describe('#utxo', () => {
it('should throw an error for improper input', async () => {
try {
const addr = 12345
await bchjs.Electrumx.utxo(addr)
assert.equal(true, false, "Unexpected result!")
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
// console.log(`err: `, err)
assert.include(
err.message,
`Input address must be a string or array of strings`
'Input address must be a string or array of strings'
)
}
})
it(`should GET utxos for a single address`, async () => {
it('should GET utxos for a single address', async () => {
// Stub the network call.
sandbox.stub(axios, "get").resolves({ data: mockData.utxo })
sandbox.stub(axios, 'get').resolves({ data: mockData.utxo })
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
const addr = 'bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9'
const result = await bchjs.Electrumx.utxo(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, "utxos")
assert.property(result, 'utxos')
assert.isArray(result.utxos)
assert.property(result.utxos[0], "height")
assert.property(result.utxos[0], "tx_hash")
assert.property(result.utxos[0], "tx_pos")
assert.property(result.utxos[0], "value")
assert.property(result.utxos[0], 'height')
assert.property(result.utxos[0], 'tx_hash')
assert.property(result.utxos[0], 'tx_pos')
assert.property(result.utxos[0], 'value')
})
it(`should POST utxo details for an array of addresses`, async () => {
it('should POST utxo details for an array of addresses', async () => {
// Stub the network call.
sandbox.stub(axios, "post").resolves({ data: mockData.utxos })
sandbox.stub(axios, 'post').resolves({ data: mockData.utxos })
const addr = [
"bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
"bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf',
'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v'
]
const result = await bchjs.Electrumx.utxo(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, "utxos")
assert.property(result, 'utxos')
assert.isArray(result.utxos)
assert.property(result.utxos[0], "utxos")
assert.property(result.utxos[0], 'utxos')
assert.isArray(result.utxos[0].utxos)
assert.property(result.utxos[0], "address")
assert.property(result.utxos[0], 'address')
assert.property(result.utxos[0].utxos[0], "height")
assert.property(result.utxos[0].utxos[0], "tx_hash")
assert.property(result.utxos[0].utxos[0], "tx_pos")
assert.property(result.utxos[0].utxos[0], "value")
assert.property(result.utxos[0].utxos[0], 'height')
assert.property(result.utxos[0].utxos[0], 'tx_hash')
assert.property(result.utxos[0].utxos[0], 'tx_pos')
assert.property(result.utxos[0].utxos[0], 'value')
})
})
describe(`#balance`, () => {
it(`should throw an error for improper input`, async () => {
describe('#balance', () => {
it('should throw an error for improper input', async () => {
try {
const addr = 12345
await bchjs.Electrumx.balance(addr)
assert.equal(true, false, "Unexpected result!")
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
// console.log(`err: `, err)
assert.include(
err.message,
`Input address must be a string or array of strings`
'Input address must be a string or array of strings'
)
}
})
it(`should GET balance for a single address`, async () => {
it('should GET balance for a single address', async () => {
// Stub the network call.
sandbox.stub(axios, "get").resolves({ data: mockData.balance })
sandbox.stub(axios, 'get').resolves({ data: mockData.balance })
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
const addr = 'bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9'
const result = await bchjs.Electrumx.balance(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, "balance")
assert.property(result.balance, "confirmed")
assert.property(result.balance, "unconfirmed")
assert.property(result, 'balance')
assert.property(result.balance, 'confirmed')
assert.property(result.balance, 'unconfirmed')
})
it(`should POST balance for an array of addresses`, async () => {
it('should POST balance for an array of addresses', async () => {
// Stub the network call.
sandbox.stub(axios, "post").resolves({ data: mockData.balances })
sandbox.stub(axios, 'post').resolves({ data: mockData.balances })
const addr = [
"bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
"bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf',
'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v'
]
const result = await bchjs.Electrumx.balance(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, "balances")
assert.property(result, 'balances')
assert.isArray(result.balances)
assert.property(result.balances[0], "address")
assert.property(result.balances[0], "balance")
assert.property(result.balances[0].balance, "confirmed")
assert.property(result.balances[0].balance, "unconfirmed")
assert.property(result.balances[0], 'address')
assert.property(result.balances[0], 'balance')
assert.property(result.balances[0].balance, 'confirmed')
assert.property(result.balances[0].balance, 'unconfirmed')
})
})
describe(`#transactions`, () => {
it(`should throw an error for improper input`, async () => {
describe('#transactions', () => {
it('should throw an error for improper input', async () => {
try {
const addr = 12345
await bchjs.Electrumx.transactions(addr)
assert.equal(true, false, "Unexpected result!")
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
// console.log(`err: `, err)
assert.include(
err.message,
`Input address must be a string or array of strings`
'Input address must be a string or array of strings'
)
}
})
it(`should GET transactions for a single address`, async () => {
it('should GET transactions for a single address', async () => {
// Stub the network call.
sandbox.stub(axios, "get").resolves({ data: mockData.transaction })
sandbox.stub(axios, 'get').resolves({ data: mockData.transaction })
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
const addr = 'bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9'
const result = await bchjs.Electrumx.transactions(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, "transactions")
assert.property(result, 'transactions')
assert.isArray(result.transactions)
assert.property(result.transactions[0], "height")
assert.property(result.transactions[0], "tx_hash")
assert.property(result.transactions[0], 'height')
assert.property(result.transactions[0], 'tx_hash')
})
it(`should POST transaction history for an array of addresses`, async () => {
it('should POST transaction history for an array of addresses', async () => {
// Stub the network call.
sandbox.stub(axios, "post").resolves({ data: mockData.transactions })
sandbox.stub(axios, 'post').resolves({ data: mockData.transactions })
const addr = [
"bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
"bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf',
'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v'
]
const result = await bchjs.Electrumx.transactions(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, "transactions")
assert.property(result, 'transactions')
assert.isArray(result.transactions)
assert.property(result.transactions[0], "address")
assert.property(result.transactions[0], "transactions")
assert.property(result.transactions[0], 'address')
assert.property(result.transactions[0], 'transactions')
assert.isArray(result.transactions[0].transactions)
assert.property(result.transactions[0].transactions[0], "height")
assert.property(result.transactions[0].transactions[0], "tx_hash")
assert.property(result.transactions[0].transactions[0], 'height')
assert.property(result.transactions[0].transactions[0], 'tx_hash')
})
})
describe(`#unconfirmed`, () => {
it(`should throw an error for improper input`, async () => {
describe('#unconfirmed', () => {
it('should throw an error for improper input', async () => {
try {
const addr = 12345
await bchjs.Electrumx.unconfirmed(addr)
assert.equal(true, false, "Unexpected result!")
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
// console.log(`err: `, err)
assert.include(
err.message,
`Input address must be a string or array of strings`
'Input address must be a string or array of strings'
)
}
})
it(`should GET unconfirmed utxos for a single address`, async () => {
it('should GET unconfirmed utxos for a single address', async () => {
// Stub the network call.
sandbox.stub(axios, "get").resolves({ data: mockData.unconfirmed })
sandbox.stub(axios, 'get').resolves({ data: mockData.unconfirmed })
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
const addr = 'bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9'
const result = await bchjs.Electrumx.unconfirmed(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, "utxos")
assert.property(result, 'utxos')
assert.isArray(result.utxos)
assert.property(result.utxos[0], "height")
assert.property(result.utxos[0], "tx_hash")
assert.property(result.utxos[0], "fee")
assert.property(result.utxos[0], 'height')
assert.property(result.utxos[0], 'tx_hash')
assert.property(result.utxos[0], 'fee')
})
it(`should POST unconfirmed utxo details for an array of addresses`, async () => {
it('should POST unconfirmed utxo details for an array of addresses', async () => {
// Stub the network call.
sandbox.stub(axios, "post").resolves({ data: mockData.unconfirmedArray })
sandbox.stub(axios, 'post').resolves({ data: mockData.unconfirmedArray })
const addr = [
"bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
"bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf',
'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v'
]
const result = await bchjs.Electrumx.unconfirmed(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, "utxos")
assert.property(result, 'utxos')
assert.isArray(result.utxos)
assert.property(result.utxos[0], "utxos")
assert.property(result.utxos[0], 'utxos')
assert.isArray(result.utxos[0].utxos)
assert.property(result.utxos[0], "address")
assert.property(result.utxos[0], 'address')
assert.property(result.utxos[0].utxos[0], "height")
assert.property(result.utxos[0].utxos[0], "tx_hash")
assert.property(result.utxos[0].utxos[0], "fee")
assert.property(result.utxos[0].utxos[0], 'height')
assert.property(result.utxos[0].utxos[0], 'tx_hash')
assert.property(result.utxos[0].utxos[0], 'fee')
})
})
describe('#blockHeader', () => {
it('should throw an error for improper height input', async () => {
try {
// Mock network calls.
sandbox.stub(axios, 'get').rejects({
response: {
data: {
success: false,
error: 'height must be a positive number'
}
}
})
const height = -10
await bchjs.Electrumx.blockHeader(height)
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
// console.log(`err: `, err)
assert.include(err.message, 'height must be a positive number')
}
})
it('should throw an error for improper count input', async () => {
try {
// Mock network calls.
sandbox.stub(axios, 'get').rejects({
response: {
data: {
success: false,
error: 'count must be a positive number'
}
}
})
const height = 42
const count = -10
await bchjs.Electrumx.blockHeader(height, count)
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
// console.log(`err: `, err)
assert.include(err.message, 'count must be a positive number')
}
})
it('should GET block headers for a given height', async () => {
// Stub the network call.
sandbox.stub(axios, 'get').resolves({ data: mockData.blockHeaders })
const height = 42
const result = await bchjs.Electrumx.blockHeader(height)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.equal(result.length, 2)
})
})
describe('#txData', () => {
it('should throw an error for improper input', async () => {
try {
const txid = 12345
await bchjs.Electrumx.txData(txid)
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
// console.log(`err: `, err)
assert.include(
err.message,
'Input txId must be a string or array of strings'
)
}
})
it('should GET details data for a single transaction', async () => {
// Stub the network call.
sandbox.stub(axios, 'get').resolves({ data: mockData.details })
const txid =
'4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251'
const result = await bchjs.Electrumx.txData(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, 'details')
assert.isObject(result.details)
assert.property(result.details, 'blockhash')
assert.property(result.details, 'hash')
assert.property(result.details, 'hex')
assert.property(result.details, 'vin')
assert.property(result.details, 'vout')
assert.equal(result.details.hash, txid)
})
it('should POST details for an array of transactions', async () => {
// Stub the network call.
sandbox.stub(axios, 'post').resolves({ data: mockData.detailsArray })
const txids = [
'4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251',
'4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251'
]
const result = await bchjs.Electrumx.txData(txids)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, 'transactions')
assert.isArray(result.transactions)
assert.property(result.transactions[0], 'txid')
assert.property(result.transactions[0], 'details')
assert.property(result.transactions[0].details, 'blockhash')
assert.property(result.transactions[0].details, 'hash')
assert.property(result.transactions[0].details, 'hex')
assert.property(result.transactions[0].details, 'vin')
assert.property(result.transactions[0].details, 'vout')
assert.equal(result.transactions.length, 2, '2 outputs for 2 inputs')
})
})
describe('#broadcast', () => {
it('should throw an error for improper input', async () => {
try {
const txHex = 12345
await bchjs.Electrumx.broadcast(txHex)
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
// console.log(`err: `, err)
assert.include(err.message, 'Input txHex must be a string.')
}
})
it('should broadcast a single transaction', async () => {
// Stub the network call.
sandbox.stub(axios, 'post').resolves({ data: mockData.broadcast })
const tx = mockData.details
const txid = tx.details.txid
const result = await bchjs.Electrumx.broadcast(tx.details.hex)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, 'txid')
assert.equal(result.txid, txid)
})
})
})
+20 -20
View File
@@ -1,13 +1,13 @@
const assert = require("chai").assert
const sinon = require("sinon")
const assert = require('chai').assert
const sinon = require('sinon')
const BCHJS = require("../../src/bch-js")
const BCHJS = require('../../src/bch-js')
// const bchjs = new BCHJS()
let bchjs
const mockData = require("./fixtures/encryption-mock")
const mockData = require('./fixtures/encryption-mock')
describe("#Encryption", () => {
describe('#Encryption', () => {
let sandbox
beforeEach(() => {
@@ -17,52 +17,52 @@ describe("#Encryption", () => {
afterEach(() => sandbox.restore())
describe("#getPubKey", () => {
it("should throw error if BCH address is not provided.", async () => {
describe('#getPubKey', () => {
it('should throw error if BCH address is not provided.', async () => {
try {
await bchjs.encryption.getPubKey()
assert.equal(true, false, "Unexpected result!")
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
// console.log(`err: `, err)
assert.include(
err.message,
"Input must be a valid Bitcoin Cash address"
'Input must be a valid Bitcoin Cash address'
)
}
})
it("should report when public key can not be found", async () => {
it('should report when public key can not be found', async () => {
// Stub the network call.
sandbox
.stub(bchjs.encryption.axios, "get")
.stub(bchjs.encryption.axios, 'get')
.resolves({ data: mockData.failureMock })
const addr = "bitcoincash:qpxqr2pmcverj4vukgjqssvk2zju8tp9xsgz2nqagx"
const addr = 'bitcoincash:qpxqr2pmcverj4vukgjqssvk2zju8tp9xsgz2nqagx'
const result = await bchjs.encryption.getPubKey(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.property(result, 'success')
assert.equal(result.success, false)
assert.property(result, "publicKey")
assert.equal(result.publicKey, "not found")
assert.property(result, 'publicKey')
assert.equal(result.publicKey, 'not found')
})
it("should get a public key", async () => {
it('should get a public key', async () => {
// Stub the network call.
sandbox
.stub(bchjs.encryption.axios, "get")
.stub(bchjs.encryption.axios, 'get')
.resolves({ data: mockData.successMock })
const addr = "bitcoincash:qpf8jv9hmqcda0502gjp7nm3g24y5h5s4unutghsxq"
const addr = 'bitcoincash:qpf8jv9hmqcda0502gjp7nm3g24y5h5s4unutghsxq'
const result = await bchjs.encryption.getPubKey(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, "publicKey")
assert.property(result, 'publicKey')
})
})
})
+14 -14
View File
@@ -6,34 +6,34 @@ const balance = { confirmed: 230000, unconfirmed: 0, balance: 230000 }
const utxo = [
{
_id: "5cecdd39a9f1235e2a3d409a",
chain: "BCH",
network: "mainnet",
_id: '5cecdd39a9f1235e2a3d409a',
chain: 'BCH',
network: 'mainnet',
coinbase: false,
mintIndex: 0,
spentTxid: "",
spentTxid: '',
mintTxid:
"27ec8512c1a9ee9e9ae9b98eb60375f1d2bd60e2e76a1eff5a45afdbc517cf9c",
'27ec8512c1a9ee9e9ae9b98eb60375f1d2bd60e2e76a1eff5a45afdbc517cf9c',
mintHeight: 560430,
spentHeight: -2,
address: "qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
script: "76a914db6ea94fa26b7272dc5e1487c35f258391e0f38788ac",
address: 'qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf',
script: '76a914db6ea94fa26b7272dc5e1487c35f258391e0f38788ac',
value: 100000,
confirmations: -1
},
{
_id: "5cecdd1ca9f1235e2a3b6349",
chain: "BCH",
network: "mainnet",
_id: '5cecdd1ca9f1235e2a3b6349',
chain: 'BCH',
network: 'mainnet',
coinbase: false,
mintIndex: 0,
spentTxid: "",
spentTxid: '',
mintTxid:
"6e1ae1bf7db6de799ec1c05ab2816ac65549bd80141567af088e6f291385b07d",
'6e1ae1bf7db6de799ec1c05ab2816ac65549bd80141567af088e6f291385b07d',
mintHeight: 560039,
spentHeight: -2,
address: "qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
script: "76a914db6ea94fa26b7272dc5e1487c35f258391e0f38788ac",
address: 'qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf',
script: '76a914db6ea94fa26b7272dc5e1487c35f258391e0f38788ac',
value: 130000,
confirmations: -1
}
+7 -7
View File
@@ -4,24 +4,24 @@
module.exports = {
details: {
hash: "000000001c6aeec19265e9cc3ded8ba5ef5e63fae7747f30bf9c02c7bc8883f0",
hash: '000000001c6aeec19265e9cc3ded8ba5ef5e63fae7747f30bf9c02c7bc8883f0',
size: 216,
height: 507,
version: 1,
merkleroot:
"a85fa3d831ab6b0305e7ff88d2d4941e25a810d4461635df51490653822071a8",
tx: ["a85fa3d831ab6b0305e7ff88d2d4941e25a810d4461635df51490653822071a8"],
'a85fa3d831ab6b0305e7ff88d2d4941e25a810d4461635df51490653822071a8',
tx: ['a85fa3d831ab6b0305e7ff88d2d4941e25a810d4461635df51490653822071a8'],
time: 1231973656,
nonce: 330467862,
bits: "1d00ffff",
bits: '1d00ffff',
difficulty: 1,
chainwork:
"000000000000000000000000000000000000000000000000000001fc01fc01fc",
'000000000000000000000000000000000000000000000000000001fc01fc01fc',
confirmations: 585104,
previousblockhash:
"00000000a99525c043fd7e323414b60add43c254c44860094048f9c01e9a5fdd",
'00000000a99525c043fd7e323414b60add43c254c44860094048f9c01e9a5fdd',
nextblockhash:
"000000000d550f4161f2702165fdd782ec72ff9c541f864ebb8256b662b7e51a",
'000000000d550f4161f2702165fdd782ec72ff9c541f864ebb8256b662b7e51a',
reward: 50,
isMainChain: true,
poolInfo: {}
-64
View File
@@ -1,64 +0,0 @@
/*
Unit test mocks for Blockbook endpoints.
*/
const balance = {
page: 1,
totalPages: 1,
itemsOnPage: 1000,
address: "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
balance: "230000",
totalReceived: "6194528752",
totalSent: "6194298752",
unconfirmedBalance: "0",
unconfirmedTxs: 0,
txs: 3,
txids: [
"27ec8512c1a9ee9e9ae9b98eb60375f1d2bd60e2e76a1eff5a45afdbc517cf9c",
"6e1ae1bf7db6de799ec1c05ab2816ac65549bd80141567af088e6f291385b07d",
"5d95f4e6047901fc1502a9758bbdb14ce73f24662b1784d13e0217b3d37bb7a2"
]
}
const utxo = [
{
txid: "27ec8512c1a9ee9e9ae9b98eb60375f1d2bd60e2e76a1eff5a45afdbc517cf9c",
vout: 0,
value: "100000",
height: 560430,
confirmations: 29321
},
{
txid: "6e1ae1bf7db6de799ec1c05ab2816ac65549bd80141567af088e6f291385b07d",
vout: 0,
value: "130000",
height: 560039,
confirmations: 29712
}
]
const utxos = [
[
{
txid: "27ec8512c1a9ee9e9ae9b98eb60375f1d2bd60e2e76a1eff5a45afdbc517cf9c",
vout: 0,
value: "100000",
height: 560430,
confirmations: 29868
},
{
txid: "6e1ae1bf7db6de799ec1c05ab2816ac65549bd80141567af088e6f291385b07d",
vout: 0,
value: "130000",
height: 560039,
confirmations: 30259
}
],
[]
]
module.exports = {
balance,
utxo,
utxos
}
+15 -15
View File
@@ -4,47 +4,47 @@
module.exports = {
bestBlockHash:
"0000000000000000008e1f65f875703872544aa888c7ca6587f055f8f5fbd4bf",
'0000000000000000008e1f65f875703872544aa888c7ca6587f055f8f5fbd4bf',
blockHeader: {
hash: "000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201",
hash: '000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201',
confirmations: 85727,
height: 500000,
version: 536870912,
versionHex: "20000000",
versionHex: '20000000',
merkleroot:
"4af279645e1b337e655ae3286fc2ca09f58eb01efa6ab27adedd1e9e6ec19091",
'4af279645e1b337e655ae3286fc2ca09f58eb01efa6ab27adedd1e9e6ec19091',
time: 1509343584,
mediantime: 1509336533,
nonce: 3604508752,
bits: "1809b91a",
bits: '1809b91a',
difficulty: 113081236211.4533,
chainwork:
"0000000000000000000000000000000000000000007ae48aca46e3b449ad9714",
'0000000000000000000000000000000000000000007ae48aca46e3b449ad9714',
previousblockhash:
"0000000000000000043831d6ebb013716f0580287ee5e5687e27d0ed72e6e523",
'0000000000000000043831d6ebb013716f0580287ee5e5687e27d0ed72e6e523',
nextblockhash:
"00000000000000000568f0a96bf4348847bc84e455cbfec389f27311037a20f3"
'00000000000000000568f0a96bf4348847bc84e455cbfec389f27311037a20f3'
},
txOutProof:
"0000002086a4a3161f9ba2174883ec0b93acceac3b2f37b36ed1f90000000000000000009cb02406d1094ecf3e0b4c0ca7c585125e721147c39daf6b48c90b512741e13a12333e5cb38705180f441d8c7100000008fee9b60f1edb57e5712839186277ed39e0a004a32be9096ee47472efde8eae62f789f9d7a9f59d0ea7093dea1e0c65ff0b953f1d8cf3d47f92e732ca0295f603c272d5f4a63509f7a887f2549d78af7444aa0ecbb4f66d9cbe13bc6a89f59e05a199df8325d490818ffefe6b6321d32d7496a68580459836c0183f89082fc1b491cc91b23ecdcaa4c347bf599a62904d61f1c15b400ebbd5c90149010c139d9c1e31b774b796977393a238080ab477e1d240d0c4f155d36f519668f49bae6bd8cd5b8e40522edf76faa09cca6188d83ff13af6967cc6a569d1a5e9aeb1fdb7f531ddd2d0cbb81879741d5f38166ac1932136264366a4065cc96a42e41f96294f02df01",
'0000002086a4a3161f9ba2174883ec0b93acceac3b2f37b36ed1f90000000000000000009cb02406d1094ecf3e0b4c0ca7c585125e721147c39daf6b48c90b512741e13a12333e5cb38705180f441d8c7100000008fee9b60f1edb57e5712839186277ed39e0a004a32be9096ee47472efde8eae62f789f9d7a9f59d0ea7093dea1e0c65ff0b953f1d8cf3d47f92e732ca0295f603c272d5f4a63509f7a887f2549d78af7444aa0ecbb4f66d9cbe13bc6a89f59e05a199df8325d490818ffefe6b6321d32d7496a68580459836c0183f89082fc1b491cc91b23ecdcaa4c347bf599a62904d61f1c15b400ebbd5c90149010c139d9c1e31b774b796977393a238080ab477e1d240d0c4f155d36f519668f49bae6bd8cd5b8e40522edf76faa09cca6188d83ff13af6967cc6a569d1a5e9aeb1fdb7f531ddd2d0cbb81879741d5f38166ac1932136264366a4065cc96a42e41f96294f02df01',
verifiedProof:
"03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7",
'03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7',
txOutUnspent: {
bestblock:
"000000000000000000b441e02f5b1b9f5b3def961047afcc6f2f5636c952705e",
'000000000000000000b441e02f5b1b9f5b3def961047afcc6f2f5636c952705e',
confirmations: 2,
value: 0.00006,
scriptPubKey: {
asm:
"OP_DUP OP_HASH160 d19fae66b685f5c3633c0db0600313918347225f OP_EQUALVERIFY OP_CHECKSIG",
hex: "76a914d19fae66b685f5c3633c0db0600313918347225f88ac",
'OP_DUP OP_HASH160 d19fae66b685f5c3633c0db0600313918347225f OP_EQUALVERIFY OP_CHECKSIG',
hex: '76a914d19fae66b685f5c3633c0db0600313918347225f88ac',
reqSigs: 1,
type: "pubkeyhash",
addresses: ["bitcoincash:qrgeltnxk6zltsmr8sxmqcqrzwgcx3eztusrwgf0x3"]
type: 'pubkeyhash',
addresses: ['bitcoincash:qrgeltnxk6zltsmr8sxmqcqrzwgcx3eztusrwgf0x3']
},
coinbase: false
}
+121 -20
View File
@@ -8,7 +8,7 @@ const utxo = {
{
height: 602405,
tx_hash:
"2b37bdb3b63dd0bca720437754a36671431a950e684b64c44ea910ea9d5297c7",
'2b37bdb3b63dd0bca720437754a36671431a950e684b64c44ea910ea9d5297c7',
tx_pos: 0,
value: 1000
}
@@ -23,23 +23,23 @@ const utxos = {
{
height: 604392,
tx_hash:
"7774e449c5a3065144cefbc4c0c21e6b69c987f095856778ef9f45ddd8ae1a41",
'7774e449c5a3065144cefbc4c0c21e6b69c987f095856778ef9f45ddd8ae1a41',
tx_pos: 0,
value: 1000
},
{
height: 630834,
tx_hash:
"4fe60a51e0d8f5134bfd8e5f872d6e502d7f01b28a6afebb27f4438a4f638d53",
'4fe60a51e0d8f5134bfd8e5f872d6e502d7f01b28a6afebb27f4438a4f638d53',
tx_pos: 0,
value: 6000
}
],
address: "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
address: 'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf'
},
{
utxos: [],
address: "bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
address: 'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v'
}
]
}
@@ -60,14 +60,14 @@ const balances = {
confirmed: 7000,
unconfirmed: 0
},
address: "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
address: 'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf'
},
{
balance: {
confirmed: 0,
unconfirmed: 0
},
address: "bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
address: 'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v'
}
]
}
@@ -78,12 +78,12 @@ const transaction = {
{
height: 560430,
tx_hash:
"3e1f3e882be9c03897eeb197224bf87f312be556a89f4308fabeeeabcf9bc851"
'3e1f3e882be9c03897eeb197224bf87f312be556a89f4308fabeeeabcf9bc851'
},
{
height: 560534,
tx_hash:
"4ebbeaac51ce141e262964e3a0ce11b96ca72c0dffe9b4127ce80135f503a280"
'4ebbeaac51ce141e262964e3a0ce11b96ca72c0dffe9b4127ce80135f503a280'
}
]
}
@@ -96,25 +96,25 @@ const transactions = {
{
height: 631219,
tx_hash:
"ae2daa01c8172545b5edd205ea438706bcb74e63d4084a26b9ff2a46d46dc97f"
'ae2daa01c8172545b5edd205ea438706bcb74e63d4084a26b9ff2a46d46dc97f'
}
],
address: "bitcoincash:qrl2nlsaayk6ekxn80pq0ks32dya8xfclyktem2mqj"
address: 'bitcoincash:qrl2nlsaayk6ekxn80pq0ks32dya8xfclyktem2mqj'
},
{
transactions: [
{
height: 560430,
tx_hash:
"3e1f3e882be9c03897eeb197224bf87f312be556a89f4308fabeeeabcf9bc851"
'3e1f3e882be9c03897eeb197224bf87f312be556a89f4308fabeeeabcf9bc851'
},
{
height: 560534,
tx_hash:
"4ebbeaac51ce141e262964e3a0ce11b96ca72c0dffe9b4127ce80135f503a280"
'4ebbeaac51ce141e262964e3a0ce11b96ca72c0dffe9b4127ce80135f503a280'
}
],
address: "bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
address: 'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v'
}
]
}
@@ -125,7 +125,7 @@ const unconfirmed = {
{
height: 602405,
tx_hash:
"2b37bdb3b63dd0bca720437754a36671431a950e684b64c44ea910ea9d5297c7",
'2b37bdb3b63dd0bca720437754a36671431a950e684b64c44ea910ea9d5297c7',
fee: 34100
}
]
@@ -139,25 +139,122 @@ const unconfirmedArray = {
{
height: 604392,
tx_hash:
"7774e449c5a3065144cefbc4c0c21e6b69c987f095856778ef9f45ddd8ae1a41",
'7774e449c5a3065144cefbc4c0c21e6b69c987f095856778ef9f45ddd8ae1a41',
fee: 34210
},
{
height: 630834,
tx_hash:
"4fe60a51e0d8f5134bfd8e5f872d6e502d7f01b28a6afebb27f4438a4f638d53",
'4fe60a51e0d8f5134bfd8e5f872d6e502d7f01b28a6afebb27f4438a4f638d53',
value: 3000
}
],
address: "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
address: 'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf'
},
{
utxos: [],
address: "bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
address: 'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v'
}
]
}
const blockHeaders = [
'010000008b52bbd72c2f49569059f559c1b1794de5192e4f7d6d2b03c7482bad0000000083e4f8a9d502ed0c419075c1abb5d56f878a2e9079e5612bfb76a2dc37d9c42741dd6849ffff001d2b909dd6',
'01000000f528fac1bcb685d0cd6c792320af0300a5ce15d687c7149548904e31000000004e8985a786d864f21e9cbb7cbdf4bc9265fe681b7a0893ac55a8e919ce035c2f85de6849ffff001d385ccb7c'
]
const txDetails = {
blockhash: '0000000000000000002aaf94953da3b487317508ebd1003a1d75d6d6ec2e75cc',
blocktime: 1578327094,
confirmations: 31861,
hash: '4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251',
hex: '020000000265d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667010000006441dd1dd72770cadede1a7fd0363574846c48468a398ddfa41a9677c74cac8d2652b682743725a3b08c6c2021a629011e11a264d9036e9d5311e35b5f4937ca7b4e4121020797d8fd4d2fa6fd7cdeabe2526bfea2b90525d6e8ad506ec4ee3c53885aa309ffffffff65d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667000000006441347d7f218c11c04487c1ad8baac28928fb10e5054cd4494b94d078cfa04ccf68e064fb188127ff656c0b98e9ce87f036d183925d0d0860605877d61e90375f774121028a53f95eb631b460854fc836b2e5d31cad16364b4dc3d970babfbdcc3f2e4954ffffffff035ac355000000000017a914189ce02e332548f4804bac65cba68202c9dbf822878dfd0800000000001976a914285bb350881b21ac89724c6fb6dc914d096cd53b88acf9ef3100000000001976a91445f1f1c4a9b9419a5088a3e9c24a293d7a150e6488ac00000000',
locktime: 0,
size: 392,
time: 1578327094,
txid: '4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251',
version: 2,
vin: [
{
scriptSig: {
asm: 'dd1dd72770cadede1a7fd0363574846c48468a398ddfa41a9677c74cac8d2652b682743725a3b08c6c2021a629011e11a264d9036e9d5311e35b5f4937ca7b4e[ALL|FORKID] 020797d8fd4d2fa6fd7cdeabe2526bfea2b90525d6e8ad506ec4ee3c53885aa309',
hex: '41dd1dd72770cadede1a7fd0363574846c48468a398ddfa41a9677c74cac8d2652b682743725a3b08c6c2021a629011e11a264d9036e9d5311e35b5f4937ca7b4e4121020797d8fd4d2fa6fd7cdeabe2526bfea2b90525d6e8ad506ec4ee3c53885aa309'
},
sequence: 4294967295,
txid: '6796672c8f0342770e3d4ac2a3b0e4494daeb7af7997f3518a0c8402f43ed165',
vout: 1
},
{
scriptSig: {
asm: '347d7f218c11c04487c1ad8baac28928fb10e5054cd4494b94d078cfa04ccf68e064fb188127ff656c0b98e9ce87f036d183925d0d0860605877d61e90375f77[ALL|FORKID] 028a53f95eb631b460854fc836b2e5d31cad16364b4dc3d970babfbdcc3f2e4954',
hex: '41347d7f218c11c04487c1ad8baac28928fb10e5054cd4494b94d078cfa04ccf68e064fb188127ff656c0b98e9ce87f036d183925d0d0860605877d61e90375f774121028a53f95eb631b460854fc836b2e5d31cad16364b4dc3d970babfbdcc3f2e4954'
},
sequence: 4294967295,
txid: '6796672c8f0342770e3d4ac2a3b0e4494daeb7af7997f3518a0c8402f43ed165',
vout: 0
}
],
vout: [
{
n: 0,
scriptPubKey: {
addresses: ['bitcoincash: pqvfecpwxvj53ayqfwkxtjaxsgpvnklcyg8xewk9hl'],
asm: 'OP_HASH160 189ce02e332548f4804bac65cba68202c9dbf822 OP_EQUAL',
hex: 'a914189ce02e332548f4804bac65cba68202c9dbf82287',
reqSigs: 1,
type: 'scripthash'
},
value: 0.0562057
},
{
n: 1,
scriptPubKey: {
addresses: ['bitcoincash: qq59hv6s3qdjrtyfwfxxldkuj9xsjmx48vrz882knz'],
asm: 'OP_DUP OP_HASH160 285bb350881b21ac89724c6fb6dc914d096cd53b OP_EQUALVERIFY OP_CHECKSIG',
hex: '76a914285bb350881b21ac89724c6fb6dc914d096cd53b88ac',
reqSigs: 1,
type: 'pubkeyhash'
},
value: 0.00589197
},
{
n: 2,
scriptPubKey: {
addresses: ['bitcoincash: qpzlruwy4xu5rxjs3z37nsj29y7h59gwvsu4ddp0u4'],
asm: 'OP_DUP OP_HASH160 45f1f1c4a9b9419a5088a3e9c24a293d7a150e64 OP_EQUALVERIFY OP_CHECKSIG',
hex: '76a91445f1f1c4a9b9419a5088a3e9c24a293d7a150e6488ac',
reqSigs: 1,
type: 'pubkeyhash'
},
value: 0.03272697
}
]
}
const details = {
success: true,
details: txDetails
}
const detailsArray = {
success: true,
transactions: [
{
txid: txDetails.txid,
details: txDetails
},
{
txid: txDetails.txid,
details: txDetails
}
]
}
const broadcast = {
success: true,
txid: txDetails.txid
}
module.exports = {
utxo,
utxos,
@@ -166,5 +263,9 @@ module.exports = {
transaction,
transactions,
unconfirmed,
unconfirmedArray
unconfirmedArray,
blockHeaders,
details,
detailsArray,
broadcast
}
+2 -2
View File
@@ -5,12 +5,12 @@
const successMock = {
success: true,
publicKey:
"03fcc37586d93af1e146238217989924e0ab1f011c34e1a23aec529354d5b28eb4"
'03fcc37586d93af1e146238217989924e0ab1f011c34e1a23aec529354d5b28eb4'
}
const failureMock = {
success: false,
publicKey: "not found"
publicKey: 'not found'
}
module.exports = {
+40 -40
View File
@@ -5,17 +5,17 @@
const uploadData = {
successful: [
{
source: "Local",
id: "uppy-ipfs/js-1e-application/octet-stream",
name: "ipfs.js",
extension: "js",
source: 'Local',
id: 'uppy-ipfs/js-1e-application/octet-stream',
name: 'ipfs.js',
extension: 'js',
meta: {
test: "avatar",
name: "ipfs.js",
type: "application/octet-stream",
fileModelId: "5ec562319bfacc745e8d8a52"
test: 'avatar',
name: 'ipfs.js',
type: 'application/octet-stream',
fileModelId: '5ec562319bfacc745e8d8a52'
},
type: "application/octet-stream",
type: 'application/octet-stream',
progress: {
uploadStarted: 1589596706524,
uploadComplete: true,
@@ -25,22 +25,22 @@ const uploadData = {
},
size: null,
isRemote: false,
remote: "",
remote: '',
tus: {
uploadUrl:
"http://localhost:5001/uppy-files/6acd261f494c3375dc522e27880efe33"
'http://localhost:5001/uppy-files/6acd261f494c3375dc522e27880efe33'
},
response: {
uploadURL:
"http://localhost:5001/uppy-files/6acd261f494c3375dc522e27880efe33"
'http://localhost:5001/uppy-files/6acd261f494c3375dc522e27880efe33'
},
uploadURL:
"http://localhost:5001/uppy-files/6acd261f494c3375dc522e27880efe33",
'http://localhost:5001/uppy-files/6acd261f494c3375dc522e27880efe33',
isPaused: false
}
],
failed: [],
uploadID: "cka90u4m300000fi0cldg6lrf"
uploadID: 'cka90u4m300000fi0cldg6lrf'
}
const paymentInfo = {
@@ -48,72 +48,72 @@ const paymentInfo = {
hostingCostBCH: 0.00004201,
hostingCostUSD: 0.01,
file: {
payloadLink: "",
payloadLink: '',
hasBeenPaid: false,
_id: "5ebf5d04cba8b038394e0d62",
_id: '5ebf5d04cba8b038394e0d62',
schemaVersion: 1,
size: 2374,
fileId: "uppy-ipfs/js-1e-application/octet-stream",
fileName: "ipfs.js",
fileExtension: "js",
createdTimestamp: "1589599492.952",
fileId: 'uppy-ipfs/js-1e-application/octet-stream',
fileName: 'ipfs.js',
fileExtension: 'js',
createdTimestamp: '1589599492.952',
hostingCost: 4201,
walletIndex: 36,
bchAddr: "bchtest:qqymyk4zfvnw8rh6hcvl922ewudkyrn9jvk6gtuae6",
bchAddr: 'bchtest:qqymyk4zfvnw8rh6hcvl922ewudkyrn9jvk6gtuae6',
__v: 0
}
}
mockNewFileModel = {
const mockNewFileModel = {
success: true,
hostingCostBCH: 0.00004197,
hostingCostUSD: 0.01,
file: {
payloadLink: "",
payloadLink: '',
hasBeenPaid: false,
_id: "5ec562319bfacc745e8d8a52",
_id: '5ec562319bfacc745e8d8a52',
schemaVersion: 1,
size: 4458,
fileName: "ipfs.js",
fileExtension: "js",
createdTimestamp: "1589994033.655",
fileName: 'ipfs.js',
fileExtension: 'js',
createdTimestamp: '1589994033.655',
hostingCost: 4196,
walletIndex: 49,
bchAddr: "bchtest:qzrpkevu7h2ayfa4rjx08r5elvpfu72dg567x3mh3c",
bchAddr: 'bchtest:qzrpkevu7h2ayfa4rjx08r5elvpfu72dg567x3mh3c',
__v: 0
}
}
const unpaidFileData = {
file: {
payloadLink: "",
payloadLink: '',
hasBeenPaid: false,
_id: "5ec7392c2acfe57aa62e945a",
_id: '5ec7392c2acfe57aa62e945a',
schemaVersion: 1,
size: 726,
fileName: "ipfs-e2e.js",
fileExtension: "js",
createdTimestamp: "1590114604.986",
fileName: 'ipfs-e2e.js',
fileExtension: 'js',
createdTimestamp: '1590114604.986',
hostingCost: 4403,
walletIndex: 56,
bchAddr: "bchtest:qz5z82u0suqh80x5tfx4ht8kdrkkw664vcy44uz0wk",
bchAddr: 'bchtest:qz5z82u0suqh80x5tfx4ht8kdrkkw664vcy44uz0wk',
__v: 0
}
}
const paidFileData = {
file: {
payloadLink: "QmRDHPhY5hCNVRMVQvS2H9uty8P1skdwgLaHpUAkEvsjcE",
payloadLink: 'QmRDHPhY5hCNVRMVQvS2H9uty8P1skdwgLaHpUAkEvsjcE',
hasBeenPaid: true,
_id: "5ec7392c2acfe57aa62e945a",
_id: '5ec7392c2acfe57aa62e945a',
schemaVersion: 1,
size: 726,
fileName: "ipfs-e2e.js",
fileExtension: "js",
createdTimestamp: "1590114604.986",
fileName: 'ipfs-e2e.js',
fileExtension: 'js',
createdTimestamp: '1590114604.986',
hostingCost: 4403,
walletIndex: 56,
bchAddr: "bchtest:qz5z82u0suqh80x5tfx4ht8kdrkkw664vcy44uz0wk",
bchAddr: 'bchtest:qz5z82u0suqh80x5tfx4ht8kdrkkw664vcy44uz0wk',
__v: 0
}
}

Some files were not shown because too many files have changed in this diff Show More