diff --git a/bin/server.js b/bin/server.js index 79d766c..c3a64db 100644 --- a/bin/server.js +++ b/bin/server.js @@ -94,13 +94,13 @@ class Server { try { try { // Delete an old webhook if it exists. - await webhookLib.deleteWebhook('http://localhost:5700/order') + await webhookLib.deleteWebhook(`http://localhost:${config.port}/order`) } catch (err) { /* exit quietly */ // console.log('err deleting webhook: ', err) } - await webhookLib.createWebhook('http://localhost:5700/order') + await webhookLib.createWebhook(`http://localhost:${config.port}/order`) console.log('Webhook created') } catch (error) { console.log('Webhook cant be created') diff --git a/config/env/common.js b/config/env/common.js index 9cfe928..e26ce4c 100644 --- a/config/env/common.js +++ b/config/env/common.js @@ -15,7 +15,7 @@ const ipfsCoordName = process.env.COORD_NAME module.exports = { // Configure TCP port. - port: process.env.PORT || 5002, + port: process.env.PORT || 5700, // Password for HTML UI that displays logs. logPass: 'test', @@ -31,6 +31,12 @@ module.exports = { ? process.env.EMAILPASS : 'emailpassword', + // PSF Web 3 community infrastructure + useFullStackCash: process.env.USE_FULLSTACKCASH ? true : false, + consumerUrl: process.env.CONSUMER_URL + ? process.env.CONSUMER_URL + : 'https://free-bch.fullstack.cash', + // FullStack.cash account information, used for automatic JWT handling. getJwtAtStartup: process.env.GET_JWT_AT_STARTUP ? true : false, authServer: process.env.AUTHSERVER @@ -72,9 +78,11 @@ module.exports = { }, // P2WDB webhook endpoint + p2wdbPort: process.env.P2WDB_PORT ? process.env.P2WDB_PORT : 5010, webhookService: process.env.WEBHOOKSERVICE ? process.env.WEBHOOKSERVICE - : 'http://localhost:5001/webhook', // P2WDB. + : 'http://localhost:5010/webhook', // P2WDB. + p2wdbAppId: process.env.APP_ID ? process.env.APP_ID : 'bch-dex-test556', // IPFS Ports ipfsTcpPort: process.env.IPFS_TCP_PORT ? process.env.IPFS_TCP_PORT : 4001, diff --git a/dev-docs/README.md b/dev-docs/README.md index 49e444a..c763c26 100644 --- a/dev-docs/README.md +++ b/dev-docs/README.md @@ -1,30 +1,29 @@ # Developer Documentation -This is living documentation that will be updated, edited, and changed over time, using the same version control as the rest of the code. The purpose of this documentation is to capture and explain how this ipfs-swap-service interacts with the [P2WDB](https://github.com/Permissionless-Software-Foundation/ipfs-p2wdb-service), to create a permissionless, censorship-resistant database for storing trading orders. A web client will be built in the future that will interact with the REST API of this app. +This is living documentation that will be updated, edited, and changed over time, using the same version control as the rest of the code. The purpose of this documentation is to capture and explain how the `bch-dex` interacts with the [P2WDB](https://github.com/Permissionless-Software-Foundation/ipfs-p2wdb-service), to create a permissionless, censorship-resistant database for storing trading orders. A web client will be built in the future that will interact with the REST API of this app. - [Specification](./specification.md) # Overview -There are three major pieces of software behind the ipfs-swap-service concept. They work together to form a censorship-resistant application for exchanging transaction data for building trades. +There are three major pieces of software behind the bch-dex concept. They work together to form a censorship-resistant application for exchanging transaction data for building trades. -![ipfs-swap-service major subcomponents](./diagrams/software-interaction.png) +![bch-dex major subcomponents](./diagrams/software-interaction.png) - _Client_ could be a web browser, or a command-line client like [psf-bch-wallet](https://github.com/Permissionless-Software-Foundation/psf-bch-wallet) or [psf-avax-wallet](https://github.com/Permissionless-Software-Foundation/psf-avax-wallet). -- [ipfs-swap-service](https://github.com/christroutner/ipfs-swap-service) is the back end REST API that maintains a local database of information that the client reads from. +- [bch-dex](https://github.com/Permissionless-Software-Foundation/bch-dex) is the back end REST API that maintains a local database of information that the client reads from. - [P2WDB](https://github.com/Permissionless-Software-Foundation/ipfs-p2wdb-service) is the pay-to-write global database with a REST API for interfacing with the other two pieces of software. The arrows in the image represent the information flow between the three pieces of software: -- The _Client_ displays information about orders. It _reads_ this information from ipfs-swap-service. -- The _Client_ is also a wallet. It can generate the needed transactions to _write_ information to the P2WDB. -- `ipfs-swap-service` imports data from the global P2WDB database into its local database, using a [webhook](https://en.wikipedia.org/wiki/Webhook) (dashed line). It can also custody funds by creating an _Offer_ and submitting the data to the P2WDB to generate an _Order_ (solid line). +- The _Client_ is essentially a 'dummy terminal' with a bidirectional interface to bch-dex. bch-dex does the heavy lifting, and the _Client_ is a 'thin' UI wrapper. +- `bch-dex` imports data from the global P2WDB database into its local database, using a [webhook](https://en.wikipedia.org/wiki/Webhook) (dashed line). It can also custody funds, pay transaction fees, and create an _Offer_ by submitting the data to the P2WDB to generate an _Order_ (solid line). -This architecture keeps the global database highly censorship resistant, while allowing local installations to maintain tight control over the user experience. The goal is to have many redundant copies of `ipfs-swap-service` on the network, and to empower individual traders to run their own, private copy. +This architecture keeps the global database highly censorship resistant, while allowing local installations to maintain tight control over the user experience. The goal is to have many redundant copies of `bch-dex` on the network, and to empower individual traders to run their own, private copy. # Back End -This section provides additional information on `ipfs-swap-service` and P2WDB back end software. +This section provides additional information on `bch-dex` and P2WDB back end software. ## P2WDB @@ -32,11 +31,11 @@ The heart of the censorship resistance is the pay-to-write database ([P2WDB](htt Because OrbitDB is a p2p database, no one party holds the 'official' copy of the database. Instead, like a blockchain, the database is replicated among several peers, and they coordinate updates to the database using consensus rules. Peers are free to leave or enter the network. Each peer independently verifies the database entries have sufficient proof-of-burn. -## `ipfs-swap-service` +## `bch-dex` -The [ipfs-swap-service](https://github.com/christroutner/ipfs-swap-service) replicates a copy of the global P2WDB, but has the ability to apply localized filters to the data before passing it on to the _Client_, to be displayed. +The `bch-dex` replicates a copy of the global P2WDB, but has the ability to apply localized filters to the data before passing it on to the _Client_, to be displayed. -`ipfs-swap-service` is based on this [ipfs-service-provider boilerplate](https://github.com/Permissionless-Software-Foundation/ipfs-service-provider). It's a production-ready template for a web server, providing interfaces via REST API over HTTP, as well as JSON RPC over IPFS. It includes many features for building a web app. This includes user management and authentication, REST API and JSON RPC scaffolding, API documentation, Docker container generation, and extensive test coverage. It's intended to be customized for the needs of the website administrator. +`bch-dex` is based on this [ipfs-service-provider boilerplate](https://github.com/Permissionless-Software-Foundation/ipfs-service-provider). It's a production-ready template for a web server, providing interfaces via REST API over HTTP, as well as JSON RPC over IPFS. It includes many features for building a web app. This includes user management and authentication, REST API and JSON RPC scaffolding, API documentation, Docker container generation, and extensive test coverage. It's intended to be customized for the needs of the website administrator. - [Specification](./specification.md) @@ -48,17 +47,17 @@ These are just a brief, high-level overview. Review the [Specifications](./speci ## Writing to the Global Database -Adding data to the global P2WDB is a result of the interaction between the _Client_ and the P2WDB. Ideally, `ipfs-swap-service` is not involved. The [p2wdb npm library](https://www.npmjs.com/package/p2wdb) can be leveraged for easy reading and writing to the P2WDB. - -During development, `ipfs-swap-service` is being used to submit Offers to the P2WDB and custody funds. When the project reaches maturity, these functions may be removed, and they should be handled by the Client, so that legal issues around custody of funds are not a problem. +Adding data to the global P2WDB is triggered by the _Client_ calling a REST API endpoint on `bch-dex`. `bch-dex` [p2wdb npm library](https://www.npmjs.com/package/p2wdb) can be leveraged for easy reading and writing to the P2WDB. Writing data follows these steps: -- A user submits data to the POST `/offer` REST API endpoint. This will move the funds a segregated UTXO and submit the data to the P2WDB to convert the Offer to an Order. Offers are tracked by the local instance of `ipfs-swap-service`, but Orders are tracked by all instances of `ipfs-swap-service`. -- The P2WDB REST API will then evaluate the data and attempt to update the p2p database using the TXID. -- Each peer on the network will independently validate the new database entry. -- `ipfs-swap-service` will receive a webhook call to its POST `/order` endpoint. This event will trigger the import of the new data into the apps local Mongo database, and generate a new Order model. +- Tokens and BCH are held by a wallet which is under the controlled of `bch-dex`. +- The _Client_ submits data to the POST `/offer` REST API endpoint to create a new Offer. +- `bch-dex` will move the funds into a segregated UTXO, and will use that UTXO to create an Offer. The Offer data is written to the P2WDB. +- `bch-dex` will receive a webhook call to its POST `/order` endpoint by the P2WDB. This event will trigger the import of the new data into the apps local Mongo database, and generate a new Order model. +- This webhook event is mirrored by every instance of `bch-dex` on the network. Each P2WDB peer on the network will independently validate the new database entry. + ## Reading from the Local Database -The Client reads data from the local database stored by `ipfs-swap-service`, and does not read the global database directly. This gives `ipfs-swap-service` the opportunity to filter and modify the data locally for a more controlled user experience. +The *Client* reads data from the local database stored by `bch-dex`, and does not read the P2WDB global database directly. This gives `bch-dex` the opportunity to filter and modify the data locally, for a more controlled user experience. diff --git a/dev-docs/diagrams/software-interaction.dia b/dev-docs/diagrams/software-interaction.dia index 44765c5..1b65276 100644 Binary files a/dev-docs/diagrams/software-interaction.dia and b/dev-docs/diagrams/software-interaction.dia differ diff --git a/dev-docs/diagrams/software-interaction.png b/dev-docs/diagrams/software-interaction.png index dfb7b3a..13fe7b5 100644 Binary files a/dev-docs/diagrams/software-interaction.png and b/dev-docs/diagrams/software-interaction.png differ diff --git a/dev-docs/specification.md b/dev-docs/specification.md index dd467bb..640ddc4 100644 --- a/dev-docs/specification.md +++ b/dev-docs/specification.md @@ -1,13 +1,13 @@ -# ipfs-swap-service Specification +# bch-dex Specification -This document contains a high-level, human-readable specification for the four major architectural areas of the ipfs-swap-service: +This document contains a high-level, human-readable specification for the four major architectural areas of the bch-dex: - Entities - Use Cases - Controllers (inputs) - Adapters (outputs) -This reflects the [Clean Architecture](https://troutsblog.com/blog/clean-architecture) design pattern. +This reflects the [Clean Architecture](https://bafybeiajggd4zju7oen627bcy5l32hrxqomoqzvwqfir6phzgducozksv4.ipfs.dweb.link/blog/clean-architecture) design pattern. ## Entities @@ -44,9 +44,9 @@ Order entities have the following properties: An Offer Entity is nearly the same as an Order. But while an Order is generated by a webhook from P2WDB, the Offer Entity is created internally. It is used -to track an Order generated by this application. +to track an 'Order' generated and managed by this application. -The Offer tracks the [HD index address](https://github.com/bitcoinbook/bitcoinbook/blob/develop/ch05.asciidoc#hd-wallets-bip-32bip-44) used to hold tokens or BCH for sale. This is the part of the app concerned with the custody of the funds. It creates a segregated [UTXO](https://github.com/bitcoinbook/bitcoinbook/blob/develop/ch06.asciidoc#transaction-outputs-and-inputs) to hold the offered asset. The Offer is automatically destroyed if the UTXO is accidentally spent, which is why it needs to be segregated from other wallet UTXOs. +The Offer tracks the [HD index address](https://github.com/bitcoinbook/bitcoinbook/blob/develop/ch05.asciidoc#hd-wallets-bip-32bip-44) used to hold tokens or BCH for sale. This is the part of the app concerned with the custody of the funds. It creates a segregated [UTXO](https://github.com/bitcoinbook/bitcoinbook/blob/develop/ch06.asciidoc#transaction-outputs-and-inputs) to hold the offered asset. The Offer is automatically destroyed if the UTXO is spent. Offer entities have the following properties: @@ -93,7 +93,7 @@ Controllers are inputs to the system. When a controller is activated, it causes ### Orders -- **POST /order** - This POST REST API endpoint will be triggered by a webhook generated by the P2WDB. This will notify the `ipfs-swap-service` that a new entry has been added to the P2WDB that matches the `appId` of `swap-`, where `` has a value of `avax`, `bch`, or `ecash`. It's a new entry that should be evaluated for inclusion in the `ipfs-swap-service` local database. +- **POST /order** - This POST REST API endpoint will be triggered by a webhook generated from P2WDB. This will notify the `bch-dex` that a new entry has been added to the P2WDB that matches the `appId` of `swap-`, where `` has a value of `avax`, `bch`, or `ecash`. It's a new entry that should be evaluated for inclusion in the `ipfs-swap-service` local database. ### Offers diff --git a/package-lock.json b/package-lock.json index c4f665f..e385c7e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,7 +33,7 @@ "koa2-ratelimit": "0.9.1", "libp2p": "^0.36.2", "line-reader": "0.4.0", - "minimal-slp-wallet": "4.4.1", + "minimal-slp-wallet": "../minimal-slp-wallet", "mongoose": "5.13.13", "node-fetch": "npm:@achingbrain/node-fetch@2.6.7", "nodemailer": "6.4.17", @@ -51,6 +51,7 @@ "eslint-config-standard": "16.0.2", "eslint-plugin-node": "11.1.0", "eslint-plugin-prettier": "3.3.1", + "eslint-plugin-promise": "^4.3.1", "eslint-plugin-standard": "4.0.0", "husky": "4.3.8", "mocha": "8.4.0", @@ -61,6 +62,36 @@ "uuid": "8.3.2" } }, + "../minimal-slp-wallet": { + "version": "4.0.0", + "license": "MIT", + "dependencies": { + "@psf/bch-js": "5.3.2", + "apidoc": "0.25.0", + "bch-consumer": "1.2.0", + "bch-donation": "1.1.1", + "crypto-js": "4.0.0" + }, + "devDependencies": { + "browserify": "17.0.0", + "chai": "4.2.0", + "coveralls": "3.1.0", + "eslint": "7.17.0", + "eslint-config-prettier": "7.1.0", + "eslint-config-standard": "16.0.2", + "eslint-plugin-node": "11.1.0", + "eslint-plugin-prettier": "3.3.1", + "eslint-plugin-standard": "4.0.1", + "husky": "4.3.8", + "lodash.clonedeep": "4.5.0", + "mocha": "8.2.0", + "nyc": "15.1.0", + "semantic-release": "17.4.4", + "sinon": "9.2.0", + "standard": "16.0.4", + "tinyify": "3.0.0" + } + }, "node_modules/@ampproject/remapping": { "version": "2.1.2", "dev": true, @@ -2261,6 +2292,7 @@ }, "node_modules/anymatch": { "version": "3.1.2", + "dev": true, "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", @@ -2293,6 +2325,7 @@ }, "node_modules/apidoc-core": { "version": "0.12.0", + "dev": true, "license": "MIT", "dependencies": { "fs-extra": "^9.0.1", @@ -2351,6 +2384,7 @@ }, "node_modules/argparse": { "version": "1.0.10", + "dev": true, "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" @@ -2587,6 +2621,7 @@ }, "node_modules/at-least-node": { "version": "1.0.0", + "dev": true, "license": "ISC", "engines": { "node": ">= 4.0.0" @@ -2668,126 +2703,6 @@ "node": ">=4.5.0" } }, - "node_modules/bch-consumer": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/bch-consumer/-/bch-consumer-1.2.0.tgz", - "integrity": "sha512-RzoJXA95OkXaV4MFAB1wFjdEsn9lmBO7F5lptUMswmpMhyRKhgfKN9m3+gN1Qj9Kiq66YTU2b2EcUlf1Iw1ETA==", - "dependencies": { - "@psf/bch-js": "5.3.1", - "apidoc": "0.25.0", - "axios": "0.25.0" - } - }, - "node_modules/bch-consumer/node_modules/@psf/bch-js": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/@psf/bch-js/-/bch-js-5.3.1.tgz", - "integrity": "sha512-HoeRM7q+zsTLIqifweEntFDHG35cL0Ps7nnh59CDbBsswpgWcvhPxBmgsHcf9m9SdHsTzHaNgX2WQuYw8nl0bg==", - "dependencies": { - "@chris.troutner/bip32-utils": "1.0.5", - "@psf/bip21": "2.0.1", - "@psf/bitcoincash-ops": "2.0.0", - "@psf/bitcoincashjs-lib": "4.0.2", - "@psf/coininfo": "4.0.0", - "@uppy/core": "1.10.4", - "@uppy/tus": "1.5.12", - "axios": "^0.21.4", - "bc-bip68": "1.0.5", - "bchaddrjs-slp": "0.2.5", - "bigi": "1.4.2", - "bignumber.js": "9.0.0", - "bip-schnorr": "0.3.0", - "bip38": "2.0.2", - "bip39": "3.0.2", - "bip66": "1.1.5", - "bitcoinjs-message": "2.0.0", - "bs58": "4.0.1", - "ecashaddrjs": "1.0.7", - "ini": "1.3.8", - "randombytes": "2.0.6", - "safe-buffer": "5.1.2", - "satoshi-bitcoin": "1.0.4", - "slp-mdm": "0.0.6", - "slp-parser": "0.0.4", - "wif": "2.0.6" - } - }, - "node_modules/bch-consumer/node_modules/@psf/bch-js/node_modules/axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", - "dependencies": { - "follow-redirects": "^1.14.0" - } - }, - "node_modules/bch-consumer/node_modules/apidoc": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/apidoc/-/apidoc-0.25.0.tgz", - "integrity": "sha512-5g9fp8OffXZOdBTzm4BBvV5Vw54s+NmKnGZIUKuH+gRTqqJuRJpcGN6sz6WnjJ+NcvXhB7rIRp6FhtJahazx2Q==", - "dependencies": { - "apidoc-core": "^0.12.0", - "commander": "^2.20.0", - "fs-extra": "^9.0.1", - "handlebars": "^4.7.6", - "lodash": "^4.17.20", - "markdown-it": "^11.0.0", - "nodemon": "^2.0.4", - "winston": "^3.3.3" - }, - "bin": { - "apidoc": "bin/apidoc" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/bch-consumer/node_modules/axios": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", - "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", - "dependencies": { - "follow-redirects": "^1.14.7" - } - }, - "node_modules/bch-consumer/node_modules/randombytes": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", - "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/bch-consumer/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/bch-donation": { - "version": "1.1.1", - "license": "MIT", - "dependencies": { - "apidoc": "^0.25.0" - } - }, - "node_modules/bch-donation/node_modules/apidoc": { - "version": "0.25.0", - "license": "MIT", - "dependencies": { - "apidoc-core": "^0.12.0", - "commander": "^2.20.0", - "fs-extra": "^9.0.1", - "handlebars": "^4.7.6", - "lodash": "^4.17.20", - "markdown-it": "^11.0.0", - "nodemon": "^2.0.4", - "winston": "^3.3.3" - }, - "bin": { - "apidoc": "bin/apidoc" - }, - "engines": { - "node": ">= 0.10.0" - } - }, "node_modules/bch-encrypt-lib": { "version": "2.0.0", "license": "MIT", @@ -2860,6 +2775,7 @@ }, "node_modules/binary-extensions": { "version": "2.2.0", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -3121,6 +3037,7 @@ }, "node_modules/braces": { "version": "3.0.2", + "dev": true, "license": "MIT", "dependencies": { "fill-range": "^7.0.1" @@ -3357,6 +3274,7 @@ }, "node_modules/camelcase": { "version": "5.3.1", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -3491,6 +3409,7 @@ }, "node_modules/chokidar": { "version": "3.5.1", + "dev": true, "license": "MIT", "dependencies": { "anymatch": "~3.1.1", @@ -3755,6 +3674,7 @@ }, "node_modules/commander": { "version": "2.20.3", + "dev": true, "license": "MIT" }, "node_modules/commondir": { @@ -4109,11 +4029,6 @@ "node": ">=0.8.0" } }, - "node_modules/crypto-js": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.0.0.tgz", - "integrity": "sha512-bzHZN8Pn+gS7DQA6n+iUmBfl0hO5DJq++QP3U6uTucDtk/0iGpXd/Gg7CGR0p8tJhofJyaKoWBuJI4eAO00BBg==" - }, "node_modules/crypto-random-string": { "version": "2.0.0", "license": "MIT", @@ -4896,6 +4811,7 @@ }, "node_modules/entities": { "version": "2.0.3", + "dev": true, "license": "BSD-2-Clause" }, "node_modules/env-ci": { @@ -5490,6 +5406,15 @@ } } }, + "node_modules/eslint-plugin-promise": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.3.1.tgz", + "integrity": "sha512-bY2sGqyptzFBDLh/GMbAxfdJC+b0f23ME63FOE4+Jao0oZ3E1LEwFtWJX/1pGMJLiTtrSSern2CRM/g+dfc0eQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/eslint-plugin-react": { "version": "7.25.3", "dev": true, @@ -5991,6 +5916,7 @@ }, "node_modules/fill-range": { "version": "7.0.1", + "dev": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -6313,6 +6239,7 @@ }, "node_modules/fs-extra": { "version": "9.1.0", + "dev": true, "license": "MIT", "dependencies": { "at-least-node": "^1.0.0", @@ -7187,6 +7114,7 @@ }, "node_modules/glob-parent": { "version": "5.1.2", + "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -7326,6 +7254,7 @@ }, "node_modules/handlebars": { "version": "4.7.7", + "dev": true, "license": "MIT", "dependencies": { "minimist": "^1.2.5", @@ -7748,6 +7677,7 @@ }, "node_modules/ignore-by-default": { "version": "1.0.1", + "dev": true, "license": "ISC" }, "node_modules/ignore-walk": { @@ -10220,6 +10150,7 @@ }, "node_modules/is-binary-path": { "version": "2.1.0", + "dev": true, "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" @@ -10323,6 +10254,7 @@ }, "node_modules/is-extglob": { "version": "2.1.1", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -10354,6 +10286,7 @@ }, "node_modules/is-glob": { "version": "4.0.3", + "dev": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -10419,6 +10352,7 @@ }, "node_modules/is-number": { "version": "7.0.0", + "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -11307,6 +11241,7 @@ }, "node_modules/jsonfile": { "version": "6.1.0", + "dev": true, "license": "MIT", "dependencies": { "universalify": "^2.0.0" @@ -11524,6 +11459,7 @@ }, "node_modules/klaw-sync": { "version": "6.0.0", + "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.1.11" @@ -12271,6 +12207,7 @@ }, "node_modules/linkify-it": { "version": "3.0.3", + "dev": true, "license": "MIT", "dependencies": { "uc.micro": "^1.0.1" @@ -12545,6 +12482,7 @@ }, "node_modules/markdown-it": { "version": "11.0.1", + "dev": true, "license": "MIT", "dependencies": { "argparse": "^1.0.7", @@ -12595,6 +12533,7 @@ }, "node_modules/mdurl": { "version": "1.0.1", + "dev": true, "license": "MIT" }, "node_modules/media-typer": { @@ -12741,36 +12680,8 @@ } }, "node_modules/minimal-slp-wallet": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/minimal-slp-wallet/-/minimal-slp-wallet-4.4.1.tgz", - "integrity": "sha512-xuwLUMUX2pPlyxbmHmPzsP0VF/Btehjb0nfJD+163I66CYu5pjcRNkqqIH5yrSp/U5vE0/tvij6P7nRumJ+PuQ==", - "dependencies": { - "@psf/bch-js": "5.3.2", - "apidoc": "0.25.0", - "bch-consumer": "1.2.0", - "bch-donation": "1.1.1", - "crypto-js": "4.0.0" - } - }, - "node_modules/minimal-slp-wallet/node_modules/apidoc": { - "version": "0.25.0", - "license": "MIT", - "dependencies": { - "apidoc-core": "^0.12.0", - "commander": "^2.20.0", - "fs-extra": "^9.0.1", - "handlebars": "^4.7.6", - "lodash": "^4.17.20", - "markdown-it": "^11.0.0", - "nodemon": "^2.0.4", - "winston": "^3.3.3" - }, - "bin": { - "apidoc": "bin/apidoc" - }, - "engines": { - "node": ">= 0.10.0" - } + "resolved": "../minimal-slp-wallet", + "link": true }, "node_modules/minimalistic-assert": { "version": "1.0.1", @@ -13467,6 +13378,7 @@ }, "node_modules/neo-async": { "version": "2.6.2", + "dev": true, "license": "MIT" }, "node_modules/nerf-dart": { @@ -13611,6 +13523,7 @@ }, "node_modules/nodemon": { "version": "2.0.12", + "dev": true, "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -13638,6 +13551,7 @@ }, "node_modules/nodemon/node_modules/boxen": { "version": "4.2.0", + "dev": true, "license": "MIT", "dependencies": { "ansi-align": "^3.0.0", @@ -13658,6 +13572,7 @@ }, "node_modules/nodemon/node_modules/chalk": { "version": "3.0.0", + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -13669,6 +13584,7 @@ }, "node_modules/nodemon/node_modules/chalk/node_modules/has-flag": { "version": "4.0.0", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -13676,6 +13592,7 @@ }, "node_modules/nodemon/node_modules/chalk/node_modules/supports-color": { "version": "7.2.0", + "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -13686,6 +13603,7 @@ }, "node_modules/nodemon/node_modules/debug": { "version": "3.2.7", + "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.1" @@ -13693,6 +13611,7 @@ }, "node_modules/nodemon/node_modules/global-dirs": { "version": "2.1.0", + "dev": true, "license": "MIT", "dependencies": { "ini": "1.3.7" @@ -13706,6 +13625,7 @@ }, "node_modules/nodemon/node_modules/has-flag": { "version": "3.0.0", + "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -13713,10 +13633,12 @@ }, "node_modules/nodemon/node_modules/ini": { "version": "1.3.7", + "dev": true, "license": "ISC" }, "node_modules/nodemon/node_modules/is-fullwidth-code-point": { "version": "3.0.0", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -13724,6 +13646,7 @@ }, "node_modules/nodemon/node_modules/is-installed-globally": { "version": "0.3.2", + "dev": true, "license": "MIT", "dependencies": { "global-dirs": "^2.0.1", @@ -13738,6 +13661,7 @@ }, "node_modules/nodemon/node_modules/is-npm": { "version": "4.0.0", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -13745,6 +13669,7 @@ }, "node_modules/nodemon/node_modules/semver": { "version": "5.7.1", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver" @@ -13752,6 +13677,7 @@ }, "node_modules/nodemon/node_modules/string-width": { "version": "4.2.3", + "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -13764,6 +13690,7 @@ }, "node_modules/nodemon/node_modules/supports-color": { "version": "5.5.0", + "dev": true, "license": "MIT", "dependencies": { "has-flag": "^3.0.0" @@ -13774,6 +13701,7 @@ }, "node_modules/nodemon/node_modules/update-notifier": { "version": "4.1.3", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "boxen": "^4.2.0", @@ -13826,6 +13754,7 @@ }, "node_modules/normalize-path": { "version": "3.0.0", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -17915,6 +17844,7 @@ }, "node_modules/picomatch": { "version": "2.3.0", + "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -18395,6 +18325,7 @@ }, "node_modules/pstree.remy": { "version": "1.1.8", + "dev": true, "license": "MIT" }, "node_modules/public-ip": { @@ -18777,6 +18708,7 @@ }, "node_modules/readdirp": { "version": "3.5.0", + "dev": true, "license": "MIT", "dependencies": { "picomatch": "^2.2.1" @@ -19728,6 +19660,7 @@ }, "node_modules/source-map": { "version": "0.6.1", + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -19844,6 +19777,7 @@ }, "node_modules/sprintf-js": { "version": "1.0.3", + "dev": true, "license": "BSD-3-Clause" }, "node_modules/sshpk": { @@ -20650,6 +20584,7 @@ }, "node_modules/term-size": { "version": "2.2.1", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -20757,6 +20692,7 @@ }, "node_modules/to-regex-range": { "version": "5.0.1", + "dev": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -20793,6 +20729,7 @@ }, "node_modules/touch": { "version": "3.1.0", + "dev": true, "license": "ISC", "dependencies": { "nopt": "~1.0.10" @@ -20803,6 +20740,7 @@ }, "node_modules/touch/node_modules/nopt": { "version": "1.0.10", + "dev": true, "license": "MIT", "dependencies": { "abbrev": "1" @@ -20971,6 +20909,7 @@ }, "node_modules/type-fest": { "version": "0.8.1", + "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=8" @@ -21005,10 +20944,12 @@ }, "node_modules/uc.micro": { "version": "1.0.6", + "dev": true, "license": "MIT" }, "node_modules/uglify-js": { "version": "3.15.1", + "dev": true, "license": "BSD-2-Clause", "optional": true, "bin": { @@ -21050,6 +20991,7 @@ }, "node_modules/undefsafe": { "version": "2.0.5", + "dev": true, "license": "MIT" }, "node_modules/underscore": { @@ -21080,6 +21022,7 @@ }, "node_modules/universalify": { "version": "2.0.0", + "dev": true, "license": "MIT", "engines": { "node": ">= 10.0.0" @@ -21486,6 +21429,7 @@ }, "node_modules/wordwrap": { "version": "1.0.0", + "dev": true, "license": "MIT" }, "node_modules/workerpool": { @@ -23543,6 +23487,7 @@ }, "anymatch": { "version": "3.1.2", + "dev": true, "requires": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -23564,6 +23509,7 @@ }, "apidoc-core": { "version": "0.12.0", + "dev": true, "requires": { "fs-extra": "^9.0.1", "glob": "^7.1.6", @@ -23606,6 +23552,7 @@ }, "argparse": { "version": "1.0.10", + "dev": true, "requires": { "sprintf-js": "~1.0.2" } @@ -23750,7 +23697,8 @@ "version": "0.4.0" }, "at-least-node": { - "version": "1.0.0" + "version": "1.0.0", + "dev": true }, "atomic-sleep": { "version": "1.0.0" @@ -23790,118 +23738,6 @@ "bc-bip68": { "version": "1.0.5" }, - "bch-consumer": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/bch-consumer/-/bch-consumer-1.2.0.tgz", - "integrity": "sha512-RzoJXA95OkXaV4MFAB1wFjdEsn9lmBO7F5lptUMswmpMhyRKhgfKN9m3+gN1Qj9Kiq66YTU2b2EcUlf1Iw1ETA==", - "requires": { - "@psf/bch-js": "5.3.1", - "apidoc": "0.25.0", - "axios": "0.25.0" - }, - "dependencies": { - "@psf/bch-js": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/@psf/bch-js/-/bch-js-5.3.1.tgz", - "integrity": "sha512-HoeRM7q+zsTLIqifweEntFDHG35cL0Ps7nnh59CDbBsswpgWcvhPxBmgsHcf9m9SdHsTzHaNgX2WQuYw8nl0bg==", - "requires": { - "@chris.troutner/bip32-utils": "1.0.5", - "@psf/bip21": "2.0.1", - "@psf/bitcoincash-ops": "2.0.0", - "@psf/bitcoincashjs-lib": "4.0.2", - "@psf/coininfo": "4.0.0", - "@uppy/core": "1.10.4", - "@uppy/tus": "1.5.12", - "axios": "^0.21.4", - "bc-bip68": "1.0.5", - "bchaddrjs-slp": "0.2.5", - "bigi": "1.4.2", - "bignumber.js": "9.0.0", - "bip-schnorr": "0.3.0", - "bip38": "2.0.2", - "bip39": "3.0.2", - "bip66": "1.1.5", - "bitcoinjs-message": "2.0.0", - "bs58": "4.0.1", - "ecashaddrjs": "1.0.7", - "ini": "1.3.8", - "randombytes": "2.0.6", - "safe-buffer": "5.1.2", - "satoshi-bitcoin": "1.0.4", - "slp-mdm": "0.0.6", - "slp-parser": "0.0.4", - "wif": "2.0.6" - }, - "dependencies": { - "axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", - "requires": { - "follow-redirects": "^1.14.0" - } - } - } - }, - "apidoc": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/apidoc/-/apidoc-0.25.0.tgz", - "integrity": "sha512-5g9fp8OffXZOdBTzm4BBvV5Vw54s+NmKnGZIUKuH+gRTqqJuRJpcGN6sz6WnjJ+NcvXhB7rIRp6FhtJahazx2Q==", - "requires": { - "apidoc-core": "^0.12.0", - "commander": "^2.20.0", - "fs-extra": "^9.0.1", - "handlebars": "^4.7.6", - "lodash": "^4.17.20", - "markdown-it": "^11.0.0", - "nodemon": "^2.0.4", - "winston": "^3.3.3" - } - }, - "axios": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", - "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", - "requires": { - "follow-redirects": "^1.14.7" - } - }, - "randombytes": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", - "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - } - } - }, - "bch-donation": { - "version": "1.1.1", - "requires": { - "apidoc": "^0.25.0" - }, - "dependencies": { - "apidoc": { - "version": "0.25.0", - "requires": { - "apidoc-core": "^0.12.0", - "commander": "^2.20.0", - "fs-extra": "^9.0.1", - "handlebars": "^4.7.6", - "lodash": "^4.17.20", - "markdown-it": "^11.0.0", - "nodemon": "^2.0.4", - "winston": "^3.3.3" - } - } - } - }, "bch-encrypt-lib": { "version": "2.0.0", "requires": { @@ -23949,7 +23785,8 @@ "version": "9.0.0" }, "binary-extensions": { - "version": "2.2.0" + "version": "2.2.0", + "dev": true }, "bindings": { "version": "1.5.0", @@ -24153,6 +23990,7 @@ }, "braces": { "version": "3.0.2", + "dev": true, "requires": { "fill-range": "^7.0.1" } @@ -24298,7 +24136,8 @@ } }, "camelcase": { - "version": "5.3.1" + "version": "5.3.1", + "dev": true }, "camelcase-keys": { "version": "6.2.2", @@ -24386,6 +24225,7 @@ }, "chokidar": { "version": "3.5.1", + "dev": true, "requires": { "anymatch": "~3.1.1", "braces": "~3.0.2", @@ -24570,7 +24410,8 @@ } }, "commander": { - "version": "2.20.3" + "version": "2.20.3", + "dev": true }, "commondir": { "version": "1.0.1", @@ -24833,11 +24674,6 @@ "boom": "0.4.x" } }, - "crypto-js": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.0.0.tgz", - "integrity": "sha512-bzHZN8Pn+gS7DQA6n+iUmBfl0hO5DJq++QP3U6uTucDtk/0iGpXd/Gg7CGR0p8tJhofJyaKoWBuJI4eAO00BBg==" - }, "crypto-random-string": { "version": "2.0.0" }, @@ -25381,7 +25217,8 @@ } }, "entities": { - "version": "2.0.3" + "version": "2.0.3", + "dev": true }, "env-ci": { "version": "5.5.0", @@ -25793,6 +25630,12 @@ "prettier-linter-helpers": "^1.0.0" } }, + "eslint-plugin-promise": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.3.1.tgz", + "integrity": "sha512-bY2sGqyptzFBDLh/GMbAxfdJC+b0f23ME63FOE4+Jao0oZ3E1LEwFtWJX/1pGMJLiTtrSSern2CRM/g+dfc0eQ==", + "dev": true + }, "eslint-plugin-react": { "version": "7.25.3", "dev": true, @@ -26094,6 +25937,7 @@ }, "fill-range": { "version": "7.0.1", + "dev": true, "requires": { "to-regex-range": "^5.0.1" } @@ -26287,6 +26131,7 @@ }, "fs-extra": { "version": "9.1.0", + "dev": true, "requires": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", @@ -26925,6 +26770,7 @@ }, "glob-parent": { "version": "5.1.2", + "dev": true, "requires": { "is-glob": "^4.0.1" } @@ -27016,6 +26862,7 @@ }, "handlebars": { "version": "4.7.7", + "dev": true, "requires": { "minimist": "^1.2.5", "neo-async": "^2.6.0", @@ -27273,7 +27120,8 @@ "dev": true }, "ignore-by-default": { - "version": "1.0.1" + "version": "1.0.1", + "dev": true }, "ignore-walk": { "version": "3.0.4", @@ -29369,6 +29217,7 @@ }, "is-binary-path": { "version": "2.1.0", + "dev": true, "requires": { "binary-extensions": "^2.0.0" } @@ -29414,7 +29263,8 @@ "version": "2.2.1" }, "is-extglob": { - "version": "2.1.1" + "version": "2.1.1", + "dev": true }, "is-fullwidth-code-point": { "version": "1.0.0", @@ -29431,6 +29281,7 @@ }, "is-glob": { "version": "4.0.3", + "dev": true, "requires": { "is-extglob": "^2.1.1" } @@ -29461,7 +29312,8 @@ "version": "5.0.0" }, "is-number": { - "version": "7.0.0" + "version": "7.0.0", + "dev": true }, "is-number-object": { "version": "1.0.6", @@ -30054,6 +29906,7 @@ }, "jsonfile": { "version": "6.1.0", + "dev": true, "requires": { "graceful-fs": "^4.1.6", "universalify": "^2.0.0" @@ -30208,6 +30061,7 @@ }, "klaw-sync": { "version": "6.0.0", + "dev": true, "requires": { "graceful-fs": "^4.1.11" } @@ -30774,6 +30628,7 @@ }, "linkify-it": { "version": "3.0.3", + "dev": true, "requires": { "uc.micro": "^1.0.1" } @@ -30967,6 +30822,7 @@ }, "markdown-it": { "version": "11.0.1", + "dev": true, "requires": { "argparse": "^1.0.7", "entities": "~2.0.0", @@ -31000,7 +30856,8 @@ } }, "mdurl": { - "version": "1.0.1" + "version": "1.0.1", + "dev": true }, "media-typer": { "version": "0.3.0" @@ -31090,30 +30947,30 @@ "dev": true }, "minimal-slp-wallet": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/minimal-slp-wallet/-/minimal-slp-wallet-4.4.1.tgz", - "integrity": "sha512-xuwLUMUX2pPlyxbmHmPzsP0VF/Btehjb0nfJD+163I66CYu5pjcRNkqqIH5yrSp/U5vE0/tvij6P7nRumJ+PuQ==", + "version": "file:../minimal-slp-wallet", "requires": { "@psf/bch-js": "5.3.2", "apidoc": "0.25.0", "bch-consumer": "1.2.0", "bch-donation": "1.1.1", - "crypto-js": "4.0.0" - }, - "dependencies": { - "apidoc": { - "version": "0.25.0", - "requires": { - "apidoc-core": "^0.12.0", - "commander": "^2.20.0", - "fs-extra": "^9.0.1", - "handlebars": "^4.7.6", - "lodash": "^4.17.20", - "markdown-it": "^11.0.0", - "nodemon": "^2.0.4", - "winston": "^3.3.3" - } - } + "browserify": "17.0.0", + "chai": "4.2.0", + "coveralls": "3.1.0", + "crypto-js": "4.0.0", + "eslint": "7.17.0", + "eslint-config-prettier": "7.1.0", + "eslint-config-standard": "16.0.2", + "eslint-plugin-node": "11.1.0", + "eslint-plugin-prettier": "3.3.1", + "eslint-plugin-standard": "4.0.1", + "husky": "4.3.8", + "lodash.clonedeep": "4.5.0", + "mocha": "8.2.0", + "nyc": "15.1.0", + "semantic-release": "17.4.4", + "sinon": "9.2.0", + "standard": "16.0.4", + "tinyify": "3.0.0" } }, "minimalistic-assert": { @@ -31562,7 +31419,8 @@ "version": "0.6.3" }, "neo-async": { - "version": "2.6.2" + "version": "2.6.2", + "dev": true }, "nerf-dart": { "version": "1.0.0", @@ -31661,6 +31519,7 @@ }, "nodemon": { "version": "2.0.12", + "dev": true, "requires": { "chokidar": "^3.2.2", "debug": "^3.2.6", @@ -31676,6 +31535,7 @@ "dependencies": { "boxen": { "version": "4.2.0", + "dev": true, "requires": { "ansi-align": "^3.0.0", "camelcase": "^5.3.1", @@ -31689,16 +31549,19 @@ }, "chalk": { "version": "3.0.0", + "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" }, "dependencies": { "has-flag": { - "version": "4.0.0" + "version": "4.0.0", + "dev": true }, "supports-color": { "version": "7.2.0", + "dev": true, "requires": { "has-flag": "^4.0.0" } @@ -31707,40 +31570,49 @@ }, "debug": { "version": "3.2.7", + "dev": true, "requires": { "ms": "^2.1.1" } }, "global-dirs": { "version": "2.1.0", + "dev": true, "requires": { "ini": "1.3.7" } }, "has-flag": { - "version": "3.0.0" + "version": "3.0.0", + "dev": true }, "ini": { - "version": "1.3.7" + "version": "1.3.7", + "dev": true }, "is-fullwidth-code-point": { - "version": "3.0.0" + "version": "3.0.0", + "dev": true }, "is-installed-globally": { "version": "0.3.2", + "dev": true, "requires": { "global-dirs": "^2.0.1", "is-path-inside": "^3.0.1" } }, "is-npm": { - "version": "4.0.0" + "version": "4.0.0", + "dev": true }, "semver": { - "version": "5.7.1" + "version": "5.7.1", + "dev": true }, "string-width": { "version": "4.2.3", + "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -31749,12 +31621,14 @@ }, "supports-color": { "version": "5.5.0", + "dev": true, "requires": { "has-flag": "^3.0.0" } }, "update-notifier": { "version": "4.1.3", + "dev": true, "requires": { "boxen": "^4.2.0", "chalk": "^3.0.0", @@ -31790,7 +31664,8 @@ } }, "normalize-path": { - "version": "3.0.0" + "version": "3.0.0", + "dev": true }, "normalize-url": { "version": "6.1.0", @@ -34620,7 +34495,8 @@ "dev": true }, "picomatch": { - "version": "2.3.0" + "version": "2.3.0", + "dev": true }, "pify": { "version": "3.0.0", @@ -34949,7 +34825,8 @@ "version": "1.8.0" }, "pstree.remy": { - "version": "1.1.8" + "version": "1.1.8", + "dev": true }, "public-ip": { "version": "4.0.4", @@ -35198,6 +35075,7 @@ }, "readdirp": { "version": "3.5.0", + "dev": true, "requires": { "picomatch": "^2.2.1" } @@ -35817,7 +35695,8 @@ } }, "source-map": { - "version": "0.6.1" + "version": "0.6.1", + "dev": true }, "sparse-array": { "version": "1.3.2" @@ -35906,7 +35785,8 @@ } }, "sprintf-js": { - "version": "1.0.3" + "version": "1.0.3", + "dev": true }, "sshpk": { "version": "1.17.0", @@ -36412,7 +36292,8 @@ } }, "term-size": { - "version": "2.2.1" + "version": "2.2.1", + "dev": true }, "test-exclude": { "version": "6.0.0", @@ -36485,6 +36366,7 @@ }, "to-regex-range": { "version": "5.0.1", + "dev": true, "requires": { "is-number": "^7.0.0" } @@ -36504,12 +36386,14 @@ }, "touch": { "version": "3.1.0", + "dev": true, "requires": { "nopt": "~1.0.10" }, "dependencies": { "nopt": { "version": "1.0.10", + "dev": true, "requires": { "abbrev": "1" } @@ -36626,7 +36510,8 @@ "dev": true }, "type-fest": { - "version": "0.8.1" + "version": "0.8.1", + "dev": true }, "type-is": { "version": "1.6.18", @@ -36649,10 +36534,12 @@ "version": "1.18.0" }, "uc.micro": { - "version": "1.0.6" + "version": "1.0.6", + "dev": true }, "uglify-js": { "version": "3.15.1", + "dev": true, "optional": true }, "uid-safe": { @@ -36677,7 +36564,8 @@ } }, "undefsafe": { - "version": "2.0.5" + "version": "2.0.5", + "dev": true }, "underscore": { "version": "1.7.0", @@ -36698,7 +36586,8 @@ "dev": true }, "universalify": { - "version": "2.0.0" + "version": "2.0.0", + "dev": true }, "unordered-array-remove": { "version": "1.0.2" @@ -36982,7 +36871,8 @@ "dev": true }, "wordwrap": { - "version": "1.0.0" + "version": "1.0.0", + "dev": true }, "workerpool": { "version": "6.1.0", diff --git a/package.json b/package.json index 5df4a13..bd481cb 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "test:all": "export BCH_DEX=test && nyc --reporter=text mocha --exit --timeout 15000 --recursive test/unit test/e2e/automated/", "test:unit": "export BCH_DEX=test && mocha --exit --timeout 15000 --recursive test/unit/", "test:e2e:auto": "export BCH_DEX=test && mocha --exit --timeout 15000 test/e2e/automated/", + "test:integration": "export BCH_DEX=test && mocha --exit --timeout 30000 --recursive test/integration", "test:temp": "export BCH_DEX=test && mocha --exit --timeout 15000 -g '#rate-limit' test/unit/json-rpc/", "lint": "standard --env mocha --fix", "docs": "./node_modules/.bin/apidoc -i src/ -o docs", @@ -50,7 +51,7 @@ "koa2-ratelimit": "0.9.1", "libp2p": "^0.36.2", "line-reader": "0.4.0", - "minimal-slp-wallet": "4.4.1", + "minimal-slp-wallet": "../minimal-slp-wallet", "mongoose": "5.13.13", "node-fetch": "npm:@achingbrain/node-fetch@2.6.7", "nodemailer": "6.4.17", @@ -68,6 +69,7 @@ "eslint-config-standard": "16.0.2", "eslint-plugin-node": "11.1.0", "eslint-plugin-prettier": "3.3.1", + "eslint-plugin-promise": "^4.3.1", "eslint-plugin-standard": "4.0.0", "husky": "4.3.8", "mocha": "8.4.0", diff --git a/src/adapters/index.js b/src/adapters/index.js index e10c7c1..ccc3fcb 100644 --- a/src/adapters/index.js +++ b/src/adapters/index.js @@ -72,7 +72,7 @@ class Adapters { } // Start the IPFS node. - await this.ipfs.start() + // await this.ipfs.start() // Open the wallet file const walletData = await this.wallet.openWallet() diff --git a/src/adapters/p2wdb.js b/src/adapters/p2wdb.js index 66e0e63..bde7012 100644 --- a/src/adapters/p2wdb.js +++ b/src/adapters/p2wdb.js @@ -5,14 +5,20 @@ // Public npm libraries. const axios = require('axios') +// Local libraries +const config = require('../../config') + // Global constants -const P2WDB_SERVER = 'http://localhost:5001/entry/write' +let P2WDB_SERVER = 'http://localhost:5001/entry/write' // const P2WDB_SERVER = 'https://p2wdb.fullstack.cash/entry/write' class P2wdbAdapter { constructor (localConfig = {}) { // Encapsulate dependencies this.axios = axios + this.config = config + + P2WDB_SERVER = `http://localhost:${config.p2wdbPort}/entry/write` } async write (inputObj) { diff --git a/src/adapters/wallet.js b/src/adapters/wallet.js index e0d3e66..b431caf 100644 --- a/src/adapters/wallet.js +++ b/src/adapters/wallet.js @@ -7,6 +7,7 @@ const BchWallet = require('minimal-slp-wallet/index') // Local libraries const JsonFiles = require('./json-files') +const config = require('../../config') const WALLET_FILE = `${__dirname.toString()}/../../wallet.json` const PROOF_OF_BURN_QTY = 0.01 @@ -19,9 +20,12 @@ class WalletAdapter { this.jsonFiles = new JsonFiles() this.WALLET_FILE = WALLET_FILE this.BchWallet = BchWallet + this.config = config } // Open the wallet file, or create one if the file doesn't exist. + // Does not instance the wallet. The output of this function is expected to + // be passed to instanceWallet(). async openWallet () { try { let walletData @@ -32,7 +36,6 @@ class WalletAdapter { walletData = await this.jsonFiles.readJSON(this.WALLET_FILE) } catch (err) { // Create a new wallet file if one does not already exist. - // console.log('caught: ', err) console.warn('Wallet file not found. Creating new wallet.json file.') // Create a new wallet. @@ -60,6 +63,35 @@ class WalletAdapter { } } + // Create an instance of minimal-slp-wallet. Use data in the wallet.json file, + // and pass the bch-js information to the minimal-slp-wallet library. + async instanceWallet (walletData) { + try { + // TODO: throw error if wallet data is not passed in. + + const advancedConfig = {} + if (this.config.useFullStackCash) { + advancedConfig.interface = 'rest-api' + advancedConfig.restURL = this.config.apiServer + advancedConfig.apiToken = this.config.apiToken + } else { + advancedConfig.interface = 'consumer-api' + advancedConfig.restURL = this.config.consumerUrl + } + + // Instantiate minimal-slp-wallet. + this.bchWallet = new this.BchWallet(walletData.mnemonic, advancedConfig) + + // Wait for wallet to initialize. + await this.bchWallet.walletInfoPromise + + return this.bchWallet + } catch (err) { + console.error('Error in instanceWallet()') + throw err + } + } + // Increments the 'nextAddress' property in the wallet file. This property // indicates the HD index that should be used to generate a key pair for // storing funds for Offers. @@ -107,7 +139,7 @@ class WalletAdapter { const childNode = masterHDNode.derivePath(`m/44'/245'/0'/0/${hdIndex}`) const cashAddress = this.bchWallet.bchjs.HDNode.toCashAddress(childNode) - console.log('cashAddress: ', cashAddress) + console.log('Generating a new key pair for cashAddress: ', cashAddress) const wif = this.bchWallet.bchjs.HDNode.toWIF(childNode) @@ -124,31 +156,6 @@ class WalletAdapter { } } - // Create an instance of minimal-slp-wallet. Use data in the wallet.json file, - // and pass the bch-js information to the minimal-slp-wallet library. - async instanceWallet (walletData, bchjs) { - try { - // TODO: Throw error if bch-js is not passed in. - // TODO: throw error if wallet data is not passed in. - - const advancedConfig = { - restURL: bchjs.restURL, - apiToken: bchjs.apiToken - } - - // Instantiate minimal-slp-wallet. - this.bchWallet = new this.BchWallet(walletData.mnemonic, advancedConfig) - - // Wait for wallet to initialize. - await this.bchWallet.walletInfoPromise - - return true - } catch (err) { - console.error('Error in instanceWallet()') - throw err - } - } - // Generate a cryptographic signature, required to write to the P2WDB. async generateSignature (message) { try { @@ -187,6 +194,7 @@ class WalletAdapter { // Get token UTXOs held by the wallet. const tokenUtxos = this.bchWallet.utxos.utxoStore.slpUtxos.type1.tokens + // console.log(`tokenUtxos: ${JSON.stringify(tokenUtxos, null, 2)}`) // Find a token UTXO that contains PSF with a quantity higher than needed // to generate a proof-of-burn. @@ -196,7 +204,7 @@ class WalletAdapter { // If token ID matches. if (thisUtxo.tokenId === P2WDB_TOKEN_ID) { - if (parseFloat(thisUtxo.tokenQty) >= PROOF_OF_BURN_QTY) { + if (parseFloat(thisUtxo.qtyStr) >= PROOF_OF_BURN_QTY) { tokenUtxo = thisUtxo break } @@ -208,6 +216,7 @@ class WalletAdapter { `Token UTXO of with ID of ${P2WDB_TOKEN_ID} and quantity greater than ${PROOF_OF_BURN_QTY} could not be found in wallet.` ) } + // console.log(`tokenUtxo: ${JSON.stringify(tokenUtxo, null, 2)}`) const result = await this.bchWallet.burnTokens( PROOF_OF_BURN_QTY, diff --git a/src/adapters/webhook.js b/src/adapters/webhook.js index 489b4e8..2a918fe 100644 --- a/src/adapters/webhook.js +++ b/src/adapters/webhook.js @@ -7,8 +7,6 @@ const axios = require('axios') let _this -const APPID = 'swapTest555' - class WebHook { constructor () { _this = this @@ -26,7 +24,7 @@ class WebHook { const endpoint = _this.config.webhookService const obj = { - appId: APPID, + appId: this.config.p2wdbAppId, url } @@ -49,7 +47,7 @@ class WebHook { const endpoint = _this.config.webhookService const obj = { - appId: APPID, + appId: this.config.p2wdbAppId, url } diff --git a/src/controllers/index.js b/src/controllers/index.js index ba3cc22..90bde54 100644 --- a/src/controllers/index.js +++ b/src/controllers/index.js @@ -32,7 +32,7 @@ class Controllers { // Attach the REST controllers to the Koa app. // this.attachRESTControllers(app) - this.attachRPCControllers() + // this.attachRPCControllers() } // Top-level function for this library. diff --git a/src/controllers/rest-api/offer/controller.js b/src/controllers/rest-api/offer/controller.js index 5915e61..6ae0f92 100644 --- a/src/controllers/rest-api/offer/controller.js +++ b/src/controllers/rest-api/offer/controller.js @@ -49,7 +49,8 @@ class OfferRESTControllerLib { // DRY error handler handleError (ctx, err) { - console.log('err', err.message) + console.log('err', err) + // If an HTTP status is specified by the buisiness logic, use that. if (err.status) { if (err.message) { diff --git a/src/controllers/rest-api/order/controller.js b/src/controllers/rest-api/order/controller.js index e1997ad..cd09aee 100644 --- a/src/controllers/rest-api/order/controller.js +++ b/src/controllers/rest-api/order/controller.js @@ -49,6 +49,18 @@ class OrderRESTControllerLib { } } + // curl -X GET http://localhost:5700/order/list + async listOrders (ctx) { + try { + const orders = await _this.useCases.order.listOrders() + + ctx.body = orders + } catch (err) { + console.log('Error in listOrders REST API handler.') + _this.handleError(ctx, err) + } + } + // DRY error handler handleError (ctx, err) { console.log('err', err.message) diff --git a/src/controllers/rest-api/order/index.js b/src/controllers/rest-api/order/index.js index 1fdd162..8e6712a 100644 --- a/src/controllers/rest-api/order/index.js +++ b/src/controllers/rest-api/order/index.js @@ -50,6 +50,7 @@ class OrderRouter { // Define the routes and attach the controller. this.router.post('/', _this.orderRESTController.createOrder) + this.router.get('/list', _this.orderRESTController.listOrders) // Attach the Controller routes to the Koa app. app.use(_this.router.routes()) diff --git a/src/use-cases/offer.js b/src/use-cases/offer.js index b262f8a..0b26410 100644 --- a/src/use-cases/offer.js +++ b/src/use-cases/offer.js @@ -1,6 +1,11 @@ -const { wlogger } = require('../adapters/wlogger') +/* + Offer use-case library. +*/ +// Local libraries +const { wlogger } = require('../adapters/wlogger') const OfferEntity = require('../entities/offer') +const config = require('../../config') class OfferLib { constructor (localConfig = {}) { @@ -16,6 +21,7 @@ class OfferLib { this.offerEntity = new OfferEntity() this.OfferModel = this.adapters.localdb.Offer this.bch = this.adapters.bch + this.config = config } // Create a new offer model and add it to the Mongo database. @@ -25,7 +31,7 @@ class OfferLib { // Input Validation const offerEntity = this.offerEntity.validate(entryObj) - // console.log('offerEntity: ', offerEntity) + console.log('offerEntity: ', offerEntity) // Ensure sufficient tokens exist to create the offer. await this.ensureFunds(offerEntity) @@ -57,7 +63,7 @@ class OfferLib { txid, signature, message, - appId: 'bch-dex-test556', + appId: this.config.p2wdbAppId, data: offerEntity } @@ -109,7 +115,7 @@ class OfferLib { // Get UTXOs. const utxos = this.adapters.wallet.bchWallet.utxos.utxoStore - // console.log(`utxos: ${JSON.stringify(utxos, null, 2)}`) + console.log(`utxos: ${JSON.stringify(utxos, null, 2)}`) if (offerEntity.buyOrSell.includes('sell')) { // Sell Offer @@ -135,6 +141,7 @@ class OfferLib { } } else { // Buy Offer + throw new Error('Buy orders are not supported yet.') } return true diff --git a/src/use-cases/order/index.js b/src/use-cases/order/index.js index 65c19c5..9ee758c 100644 --- a/src/use-cases/order/index.js +++ b/src/use-cases/order/index.js @@ -56,6 +56,15 @@ class OrderUseCases { throw err } } + + async listOrders () { + try { + return this.OrderModel.find({}) + } catch (error) { + console.error('Error in use-cases/order/listOrders()') + throw error + } + } } module.exports = OrderUseCases diff --git a/test/e2e/manual/create-offer.js b/test/e2e/manual/create-offer.js index 75dba1a..d6d057a 100644 --- a/test/e2e/manual/create-offer.js +++ b/test/e2e/manual/create-offer.js @@ -15,11 +15,11 @@ async function start () { messageType: 1, messageClass: 1, tokenId: - '38e97c5d7d3585a2cbf3f9580c82ca33985f9cb0845d4dcce220cb709f9538b0', + 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2', buyOrSell: 'sell', rateInSats: 1000, - minSatsToExchange: 10, - numTokens: 0.02 + minSatsToExchange: 1000, + numTokens: 1 } const options = { diff --git a/test/integration/adapters/wallet.adapter.integration.js b/test/integration/adapters/wallet.adapter.integration.js new file mode 100644 index 0000000..260c60e --- /dev/null +++ b/test/integration/adapters/wallet.adapter.integration.js @@ -0,0 +1,41 @@ +/* + Integration tests for the wallet.js adapter library. +*/ + +// Public npm libraries. +const assert = require('chai').assert + +// Local libraries. +const WalletAdapter = require('../../../src/adapters/wallet') + +describe('#wallet', () => { + let uut + + beforeEach(() => { + uut = new WalletAdapter() + }) + + describe('#instanceWallet', () => { + it('should instance the wallet using the web 3 infra by default', async () => { + const walletData = await uut.openWallet() + // console.log('walletData: ', walletData) + + const walletInstance = await uut.instanceWallet(walletData) + // console.log('walletInstance: ', walletInstance) + + assert.equal(walletInstance.ar.interface, 'consumer-api') + }) + + it('should instance using web 2 FullStack.cash infra', async () => { + const walletData = await uut.openWallet() + + // Force usage of FullStack.cash + uut.config.useFullStackCash = true + + const walletInstance = await uut.instanceWallet(walletData) + // console.log('walletInstance: ', walletInstance) + + assert.equal(walletInstance.ar.interface, 'rest-api') + }) + }) +}) diff --git a/test/unit/adapters/wallet.adapter.unit.js b/test/unit/adapters/wallet.adapter.unit.js index 4459b7a..69815f0 100644 --- a/test/unit/adapters/wallet.adapter.unit.js +++ b/test/unit/adapters/wallet.adapter.unit.js @@ -102,19 +102,15 @@ describe('#wallet', () => { // Mock dependencies uut.BchWallet = MockBchWallet - const bchjs = { - restURL: 'dummyUrl', - apiToken: 'dummyToken' - } - // Ensure we open the test file, not the production wallet file. uut.WALLET_FILE = testWalletFile const walletData = await uut.openWallet() - const result = await uut.instanceWallet(walletData.mnemonic, bchjs) + const result = await uut.instanceWallet(walletData.mnemonic) + console.log('result: ', result) - assert.equal(result, true) + assert.property(result, 'walletInfoPromise') }) it('should catch and throw an error', async () => { diff --git a/test/unit/mocks/adapters/wallet.js b/test/unit/mocks/adapters/wallet.js index 41fb198..349ecd2 100644 --- a/test/unit/mocks/adapters/wallet.js +++ b/test/unit/mocks/adapters/wallet.js @@ -105,7 +105,8 @@ class MockBchWallet { decimals: 8, tokenType: 1, isValid: true, - tokenQty: '1' + tokenQty: '1', + qtyStr: '1' } ] },