Compare commits

...
586 Commits
Author SHA1 Message Date
Chris Troutner ac83827fca Merge branch 'master' into fullstack 2025-12-04 15:29:13 +00:00
Chris Troutner 0811024030 Merge pull request #123 from Permissionless-Software-Foundation/dh-token-data
feat(offer): Added tokenData to offer model
2025-12-04 08:08:45 -07:00
Daniel Gonzalez 737d35463d feat(offer): Added tokenData to offer model 2025-12-03 19:21:40 -04:00
Chris Troutner 2ed1eaba9c Merge branch 'master' into fullstack 2025-11-26 14:16:56 +00:00
Chris Troutner 6dddfbdcb6 Merge pull request #122 from Permissionless-Software-Foundation/dh-ctr-offr-page
feat(counterOffer): Added new properties to counter offer model
2025-11-25 18:59:41 -08:00
Daniel Gonzalez fc2d7b4b9b feat(counterOffer): Added new properties to counter offer model 2025-11-25 20:57:44 -04:00
Chris Troutner c877898ae7 Merge pull request #121 from Permissionless-Software-Foundation/dh-track-counter-offrs
feat(offers): Track Counter Offers
2025-11-21 15:54:45 -08:00
Daniel Gonzalez 88e27f47f5 feat(offers): Track Counter Offers 2025-11-21 17:34:05 -04:00
Chris Troutner 9681def3e0 Merge branch 'master' into fullstack 2025-11-14 19:24:38 +00:00
Chris Troutner 0057007b4c Merge pull request #120 from Permissionless-Software-Foundation/dh-npub-offer
feat(nostr): Added npub to Offer model
2025-11-13 06:28:42 -08:00
Daniel Gonzalez 8aad93e572 feat(nostr): Added npub to Offer model 2025-11-11 14:48:09 -04:00
Chris Troutner fa0ec3ece2 Merge pull request #119 from Permissionless-Software-Foundation/dh-npub-order
feat(nostr): Added npub to order
2025-11-11 06:56:18 -08:00
Daniel Gonzalez 4f9f2f8370 feat(nostr): Added npub to order 2025-11-10 18:45:37 -04:00
Chris Troutner 0fb93be2cd Merge pull request #118 from Permissionless-Software-Foundation/dh-timer-deleted
feat(chats): Added timer to delete old deleted chat and post database models
2025-11-06 10:58:25 -08:00
Daniel Gonzalez 26dcd6072e feat(chats): Added timer to delete old deleted chat and post database models 2025-11-06 11:42:46 -04:00
Chris Troutner 42f228af0e Merge branch 'master' into fullstack 2025-11-05 18:50:34 +00:00
Chris Troutner 8be70baff2 Merge pull request #117 from Permissionless-Software-Foundation/dh-nostr-route
feat(nostr): Added new route for deleteChat and deletePost models
2025-10-29 09:02:51 -07:00
Daniel Gonzalez 7e5c314000 feat(nostr): Added new route for deleteChat and deletePost models 2025-10-28 19:18:18 -04:00
Chris Troutner 9669112d69 Merge pull request #116 from Permissionless-Software-Foundation/ct-unstable
fix(offer): Adding makerNpub property to db model
2025-10-26 11:14:07 -07:00
Chris Troutner 9a71763f79 fix(offer): Adding makerNpub property to db model 2025-10-26 11:12:49 -07:00
Chris Troutner 1a96eac8c9 Merge pull request #115 from Permissionless-Software-Foundation/ct-unstable
Adding deletedChat and deletedPost DB models
2025-10-25 16:03:55 -07:00
Chris Troutner a2acdef539 fix(database): Adding deletedChat and deletedPost DB models 2025-10-25 16:02:35 -07:00
Chris Troutner 58ddbbcc4e fix(updateUser): Adding util scripts for dev & prod 2025-10-25 14:35:22 -07:00
Chris Troutner 5ff33ff19f Merge remote-tracking branch 'upstream/master' into ct-unstable 2025-10-25 14:34:05 -07:00
Chris Troutner 682f599261 fixing updateUser script 2025-10-25 14:33:51 -07:00
Chris Troutner 7c26e33a8c Merge pull request #181 from Permissionless-Software-Foundation/ct-unstable
fix(util): Fixing problem with updateUser.js script
2025-10-25 14:33:12 -07:00
Chris Troutner 2595ee8295 fix(util): Fixing problem with updateUser.js script 2025-10-25 14:31:33 -07:00
Chris Troutner 531685c0e4 Fixing merge conflicts with upstream 2025-10-25 14:26:16 -07:00
Chris Troutner 476fdcd0aa Merge pull request #180 from Permissionless-Software-Foundation/ct-unstable
fix(utils): Adding script to update users password or convert to admin
2025-10-25 14:24:43 -07:00
Chris Troutner b6762b215e fix(utils): Adding script to update users password or convert to admin 2025-10-25 14:23:28 -07:00
Chris Troutner 4ac7f59378 Merge branch 'master' into fullstack 2025-10-25 18:30:01 +00:00
Chris Troutner 3cdf49bb56 Merge pull request #114 from Permissionless-Software-Foundation/dh-update-endpoint
feat(update): Added Update button REST endpoint
2025-10-25 11:25:02 -07:00
Chris Troutner 28615403b8 Formatting and adding dev comments 2025-10-25 11:22:13 -07:00
Daniel Gonzalez bb10bd819a feat(update): Added Update button REST endpoint 2025-10-24 19:58:56 -04:00
Chris Troutner 3882217e6a Merge pull request #113 from Permissionless-Software-Foundation/dh-user-data
feat(userdata): Store user data on the database
2025-10-21 12:57:45 -07:00
Chris Troutner 8cd2896115 linting 2025-10-21 12:56:23 -07:00
Chris Troutner e570519ec8 Switching default back end to free-bch 2025-10-21 12:56:07 -07:00
Chris Troutner 2f74b74110 fix(createOffer()): Handling API errors when token data can not be retrieved 2025-10-21 12:44:48 -07:00
Chris Troutner fddb5499f0 Making offer use-case unit tests less flaky 2025-10-21 12:29:23 -07:00
Daniel Gonzalez fed98d51be feat(userdata): Store user data on the database 2025-10-20 18:37:54 -04:00
Chris Troutner 8e3ee3a0fb Merge pull request #112 from Permissionless-Software-Foundation/dh-offer-model
feat(offer): Store mutable data in bch-dex Offer db model
2025-10-17 22:30:36 -07:00
Daniel Gonzalez e57faf8f26 feat(offer): Store mutable data in bch-dex Offer db model 2025-10-16 18:38:06 -04:00
Chris Troutner 725c1c39a5 Merge branch 'master' into fullstack 2025-10-09 15:09:25 +00:00
Chris Troutner 61fa6b0ed6 Merge pull request #111 from Permissionless-Software-Foundation/dh-pagination
feat(NFTs): Added pagination controls for NFTs
2025-10-09 07:21:07 -07:00
Daniel Gonzalez 99843061ab feat(NFTs): Added pagination controls for NFTs 2025-10-08 20:20:11 -04:00
Chris Troutner 3a23763800 Adding an extra property to offer db model 2025-10-04 09:44:15 -07:00
Chris Troutner 3f4d49a228 Merge pull request #110 from Permissionless-Software-Foundation/ct-unstable
fix(offer): Adding new properties to offer db model
2025-10-04 09:41:39 -07:00
Chris Troutner 88cfadbc17 fix(offer): Adding new properties to offer db model 2025-10-04 09:40:07 -07:00
Chris Troutner 6c1da41cb3 Syncing with upstream. Fixing merge conflicts 2025-10-04 09:00:38 -07:00
Chris Troutner 0e6a411012 Merge pull request #179 from Permissionless-Software-Foundation/ct-unstable
fix(IPFS): Adding API docs for the IPFS endpoints that need it
2025-10-04 08:32:55 -07:00
Chris Troutner 55e9e35c1f fix(IPFS): Adding API docs for the IPFS endpoints that need it 2025-10-04 08:31:17 -07:00
Chris Troutner 84603356ef Merge pull request #109 from Permissionless-Software-Foundation/dh-access-validation
feat(test): Added user/admin access validation to endpoint
2025-10-03 06:17:40 -07:00
Daniel Gonzalez 2f6b4dfc09 feat(test): Added user/admin access validation to endpoint 2025-10-01 17:24:29 -04:00
Chris Troutner b19af253ae Merge pull request #108 from Permissionless-Software-Foundation/dh-api-docs
fix(docs): Added api-docs to bch-dex endpoints
2025-09-30 07:03:10 -07:00
Daniel Gonzalez b6c6c186a8 fix(docs): Added api-docs to bch-dex endpoints 2025-09-29 18:58:20 -04:00
Chris Troutner ae6e708f51 Merge pull request #107 from Permissionless-Software-Foundation/ct-unstable
Reducing debug console logs
2025-09-16 10:22:09 -07:00
Chris Troutner 442f4ed752 Reducing more console logs 2025-09-16 10:04:00 -07:00
Chris Troutner 8617cf5fd0 fix(offers): Reducing console logs 2025-09-14 09:52:03 -07:00
Chris Troutner 2e00230f79 Merge branch 'master' into ct-unstable 2025-09-14 08:41:21 -07:00
Chris Troutner 44dcce6c45 Merge pull request #106 from Permissionless-Software-Foundation/dh-unit-test-coverage
feat(tests): Added more unit test coverage
2025-09-14 08:32:52 -07:00
Chris Troutner 8d43192a1c minor edits 2025-09-14 08:31:29 -07:00
Daniel Gonzalez 59e2bb473b feat(tests): Added more unit test coverage 2025-09-13 14:36:27 -04:00
Chris Troutner b4d2506e81 Tried AI generated architectural diagram 2025-09-10 06:50:35 -07:00
Chris Troutner 7290c8db30 Merge branch 'master' into fullstack 2025-08-10 18:11:09 +00:00
Chris Troutner 2af50ecf02 Merge pull request #105 from Permissionless-Software-Foundation/operator-fee
Adding required Operator fee to SWaP TX
2025-08-10 11:06:55 -07:00
Chris Troutner f88a24c1b5 Updating unit tests 2025-08-10 10:44:45 -07:00
Chris Troutner a4b4ff13d2 Handling corner cases when validating counter offer against operator fee 2025-08-09 17:54:30 -07:00
Chris Troutner 2bf4f9df28 fix(acceptCounterOffer()): Skipping Counter Offers that are missing an output for the operator 2025-08-09 16:28:56 -07:00
Chris Troutner 19ba38e8ce Adding operator fee to Offer use case, entity, and database model 2025-08-09 15:08:31 -07:00
Chris Troutner 373a52ebf1 feat(operator fee): Adding config values to ensure bch-dex operator recieves a fee 2025-08-09 15:02:29 -07:00
Chris Troutner fe82478dc4 linting 2025-08-09 14:49:41 -07:00
Chris Troutner bed281c8c3 minor edit 2025-08-09 14:49:32 -07:00
Chris Troutner 01484b4e03 fixing typo in comments 2025-08-07 07:00:58 -07:00
Chris Troutner c86512254d Merge pull request #104 from Permissionless-Software-Foundation/dh-test-coverage
feat(tests): Improved adapters test coverage
2025-08-06 09:42:17 -07:00
Daniel Gonzalez 7df9b9b8a4 feat(tests): Improved adapters test coverage 2025-08-05 16:45:37 -04:00
Chris Troutner 36e1ec1f8e Merge branch 'master' into fullstack 2025-07-28 18:19:52 +00:00
Chris Troutner 5f91395766 Merge pull request #103 from Permissionless-Software-Foundation/ct-unstable
fix(GET /offer/list/addr/:addr): Get offers by an address
2025-07-28 11:14:25 -07:00
Chris Troutner dda6cb2aa4 fix(GET /offer/list/addr/:addr): Get offers by an address 2025-07-28 11:12:04 -07:00
Chris Troutner 578aade39b Merge pull request #102 from Permissionless-Software-Foundation/ct-unstable
fix(metrics): Adding timer-controller that updates metrics of SM Acco…
2025-07-14 19:30:21 -07:00
Chris Troutner b09890a527 fix(metrics): Adding timer-controller that updates metrics of SM Accounts 2025-07-14 19:16:00 -07:00
Chris Troutner baa574a93e Merge branch 'master' into fullstack 2025-07-08 23:56:41 +00:00
Chris Troutner a32bd840b9 Merge pull request #101 from Permissionless-Software-Foundation/ct-unstable
fix(smAccount): Adding GET endpoints
2025-07-08 09:24:11 -07:00
Chris Troutner 0bdc232938 fix(smAccount): Adding GET endpoints 2025-07-08 08:58:31 -07:00
Chris Troutner 8333563d98 Merge branch 'master' into fullstack 2025-07-06 21:44:33 +00:00
Chris Troutner f543cfce73 Merge pull request #100 from Permissionless-Software-Foundation/trout-smAccount
Created Social Media account and REST endpoint
2025-07-02 17:09:59 -07:00
Chris Troutner 0f5e694682 Added GET /sm/list/all/0 endpoint 2025-07-01 18:45:53 -07:00
Chris Troutner 615638d705 Timer controller checks creates new social media DB models 2025-07-01 18:23:09 -07:00
Chris Troutner 9b46bbd7bb feat(smAccount): Tracking content creator social media accounts 2025-07-01 15:47:44 -07:00
Chris Troutner 1b58bda5a7 Merge pull request #99 from Permissionless-Software-Foundation/ct-unstable
Syncing with upstream ipfs-service-provider
2025-06-29 07:42:53 -07:00
Chris Troutner c1f15a4079 Fixing merge conflicts, commenting out broken tests 2025-06-29 07:38:58 -07:00
Chris Troutner 18ea03a4d6 Merge pull request #178 from Permissionless-Software-Foundation/dh-test-coverage
feat(tests): Increased unit test coverage
2025-06-28 07:28:04 -07:00
Daniel Gonzalez 3d911d1062 feat(tests): Increased unit test coverage 2025-06-27 20:11:27 -04:00
Chris Troutner 99fd116b6d Merge branch 'master' into fullstack 2025-06-27 16:28:28 +00:00
Chris Troutner 935ab94159 Merge pull request #98 from Permissionless-Software-Foundation/ct-unstable
fix(docker): Improved routing for dex-ui docker container
2025-06-27 09:10:45 -07:00
Chris Troutner 18dad062f6 fix(docker): Improved routing for dex-ui docker container 2025-06-27 09:09:14 -07:00
Chris Troutner 1e8fc1825c Merge pull request #97 from Permissionless-Software-Foundation/ct-unstable
Updating README
2025-06-13 12:13:46 -07:00
Chris Troutner f64795706d Editing README 2025-06-13 08:58:11 -07:00
Chris Troutner 67a9914a8b Editing README 2025-06-13 08:52:54 -07:00
Chris Troutner b01d15a67d Editing README 2025-06-13 08:52:06 -07:00
Chris Troutner e4c9d15e60 fix(README): Updating installation instructions 2025-06-13 08:51:29 -07:00
Chris Troutner ccae89ad01 Merge branch 'master' into fullstack 2025-06-06 18:53:44 +00:00
Chris Troutner 3c00ce6644 Merge pull request #96 from Permissionless-Software-Foundation/ct-unstable
fix(error): Removing confusing non-error error
2025-06-06 11:48:14 -07:00
Chris Troutner e9d1b763fd fix(error): Removing confusing non-error error 2025-06-06 11:46:43 -07:00
Chris Troutner cf88fadfdc Merge pull request #177 from Permissionless-Software-Foundation/ct-unstable
Usage: back up to DB to track usage over restarts.
2025-06-05 18:27:06 -07:00
Chris Troutner 4977ae7003 Increasing backup to 10 minutes 2025-06-05 18:25:45 -07:00
Chris Troutner f0f6970a08 Added timer controllers for managing usage stats 2025-06-05 18:25:10 -07:00
Chris Troutner fcb4acb11d feat(usage-use-cases.js): Added functions for persisting usage data to database 2025-06-04 12:26:03 -07:00
Chris Troutner 0ecae58be2 Merge branch 'master' into fullstack 2025-06-02 01:52:27 +00:00
Chris Troutner 98b5e300c0 Merge pull request #95 from Permissionless-Software-Foundation/ct-unstable
Using User wallet to create and settle Orders, not app wallet.
2025-06-01 18:49:24 -07:00
Chris Troutner 2ea062ae2b Removing e2e tests from unit tests 2025-06-01 18:47:15 -07:00
Chris Troutner c6e5eb9dc9 Updating package-lock 2025-06-01 18:42:16 -07:00
Chris Troutner 46a19b0fb1 linting 2025-06-01 18:34:14 -07:00
Chris Troutner 40cf8cc8de got tests passing again 2025-06-01 18:34:01 -07:00
Chris Troutner ddc70d6fbc feat(completeTx()): Uses user wallet to complete sale 2025-06-01 18:18:34 -07:00
Chris Troutner 625b8895b0 feat(moveTokensFromCustomWallet()): Using user wallet, not system wallet to stash new Offer UTXOs 2025-06-01 17:23:35 -07:00
Chris Troutner 5fd8d8fcd1 Adding llm-bch-dex.md for AI consuption 2025-06-01 16:18:04 -07:00
Chris Troutner 28e012feb6 Merge pull request #176 from Permissionless-Software-Foundation/e2e-tests
Separating E2E tests from Unit tests
2025-05-30 17:18:40 -07:00
Chris Troutner 958c637c24 Commenting out failing test 2025-05-30 17:17:22 -07:00
Daniel Gonzalez 34381e6e93 Improved e2e tests 2025-05-30 11:53:57 -04:00
Daniel Gonzalez 8843b3e2b0 Separate e2e tests 2025-05-28 20:52:25 -04:00
Chris Troutner 3f91653d23 feat(e2e): separating e2e from unit tests 2025-05-23 07:26:51 -07:00
Chris Troutner 5f442835e5 Customizing scrips 2025-05-20 19:38:16 +00:00
Chris Troutner aa8fd89227 Merge branch 'master' into fullstack 2025-05-19 22:45:42 +00:00
Chris Troutner 153ebc204a Merge pull request #94 from Permissionless-Software-Foundation/ct-unstable
feat(NOSTR_TOPIC): Changing default nostr topic
2025-05-19 15:40:19 -07:00
Chris Troutner 589c16550c Merge branch 'master' into ct-unstable 2025-05-19 15:37:01 -07:00
Chris Troutner 49063456b6 feat(NOSTR_TOPIC): Changing default nostr topic 2025-05-19 15:34:36 -07:00
Chris Troutner 87eb804cd1 Merge pull request #93 from Permissionless-Software-Foundation/ct-unstable
fix(util): Adding scripts for creating new users
2025-05-19 13:49:31 -07:00
Chris Troutner 23d5118b52 fix(util): Adding scripts for creating new users 2025-05-19 13:48:15 -07:00
Chris Troutner 94eb342435 Merge pull request #92 from Permissionless-Software-Foundation/ct-unstable
Syncing admin settings with upstream ipfs-service-provider
2025-05-19 13:18:38 -07:00
Chris Troutner ac326b8e34 fix(adapter/admin.js): Adding mnemonic for user 2025-05-19 13:16:32 -07:00
Chris Troutner 164a38ad20 linting 2025-05-19 13:11:23 -07:00
Chris Troutner 3300e0fc80 fix(config): Fixing merge conflict in common.js 2025-05-19 13:11:13 -07:00
Chris Troutner 3a4569c33f Merge pull request #175 from Permissionless-Software-Foundation/dh-env-var-admin
feat(admin): added env var setting so only admin can create new users
2025-05-19 13:06:40 -07:00
Daniel Gonzalez 05a0620663 feat(admin): added env var setting so only admin can create new users 2025-05-19 12:17:09 -04:00
Chris Troutner af83c06b43 Merge pull request #174 from Permissionless-Software-Foundation/ct-unstable
fix(usage): Debugging issue with usage tracking
2025-05-18 15:37:46 -07:00
Chris Troutner e6317c3282 fix(usage): Debugging issue with usage tracking 2025-05-18 15:36:32 -07:00
Chris Troutner 3da7432273 Building UI from psfoundation branch 2025-05-16 17:10:43 +00:00
Chris Troutner 61c1dd5878 Merge branch 'master' into fullstack 2025-05-16 14:56:09 +00:00
Chris Troutner c095e7af39 noop 2025-05-16 14:55:57 +00:00
Chris Troutner ddce40bb52 Merge pull request #91 from Permissionless-Software-Foundation/ct-unstable
Production improvements
2025-05-16 07:54:30 -07:00
Chris Troutner 746f9a3488 fix(production): Adding script to get users in prod env 2025-05-16 07:52:58 -07:00
Chris Troutner fb9612bb65 Using ct-unstable branch 2025-05-16 02:22:19 +00:00
Chris Troutner a611580f48 Turning off CI option 2025-05-15 19:18:41 -07:00
Chris Troutner e4a37b1c10 Merge branch 'ct-unstable' into fullstack 2025-05-16 00:58:49 +00:00
Chris Troutner 07c671ede4 fix(production): Using v3 UI 2025-05-15 17:58:29 -07:00
Chris Troutner ba4f847e57 Merge branch 'master' into fullstack 2025-05-16 00:39:57 +00:00
Chris Troutner 7c8d73810d linting 2025-05-15 07:43:24 -07:00
Chris Troutner 9829e8581c Adding sweep-funds2 script 2025-05-15 07:43:13 -07:00
Chris Troutner a12aa5609d Merge pull request #90 from Permissionless-Software-Foundation/dh-refactor-counteroffer
feat(order): refactored acceptCounterOffer()
2025-05-15 06:01:47 -07:00
Daniel Gonzalez abf834c5a8 feat(order): refactored acceptCounterOffer() 2025-05-14 20:33:25 -04:00
Chris Troutner 7ae557d143 Merge pull request #89 from Permissionless-Software-Foundation/ct-unstable
fix(debug): Adding debugging conosole.logs to bch-dex
2025-05-09 13:17:04 -07:00
Chris Troutner 5f4b0c8da3 fix(debug): Adding debugging conosole.logs to bch-dex 2025-05-09 13:15:39 -07:00
Chris Troutner 6ef197dae3 Merge pull request #88 from Permissionless-Software-Foundation/dh-create-order
feat(order): Modify createOrder() to work with the user model
2025-05-06 18:45:09 -07:00
Daniel Gonzalez fafa7eecd9 feat(order): Modify createOrder() to work with the user model 2025-05-05 18:26:04 -04:00
Chris Troutner 5ede934be5 Merge pull request #87 from Permissionless-Software-Foundation/ct-unstable
fix(wallet adapter): Binding 'this' object to class methods
2025-04-26 14:36:28 -07:00
Chris Troutner 8d036ea9ba fix(wallet adapter): Binding 'this' object to class methods 2025-04-26 14:30:54 -07:00
Chris Troutner bc6acc846a Merge pull request #86 from Permissionless-Software-Foundation/ct-unstable
Syncing with upstream
2025-04-26 14:13:25 -07:00
Chris Troutner afa050261f Merge remote-tracking branch 'upstream/master' into merge-upstream 2025-04-26 14:11:39 -07:00
Chris Troutner 1715d064fb Merge pull request #85 from Permissionless-Software-Foundation/dh-user-mnemonic
feat(user): Added mnemonic to user model
2025-04-26 12:35:37 -07:00
Daniel Gonzalez cf2f2af90f feat(user): Added mnemonic to user model 2025-04-24 12:45:55 -04:00
Chris Troutner 354321c956 Merge pull request #173 from Permissionless-Software-Foundation/ct-unstable
fix(wallet.adapter): Binding this object to all methods
2025-04-22 19:07:06 -07:00
Chris Troutner af2572a493 fix(wallet.adapter): Binding this object to all methods 2025-04-22 18:58:03 -07:00
Chris Troutner 1a5dadbf35 Merge pull request #84 from Permissionless-Software-Foundation/ct-unstable
fix(README): Updating README details
2025-04-11 16:18:37 -07:00
Chris Troutner ced7a60f14 More README edits 2025-04-11 16:15:29 -07:00
Chris Troutner 043c4a8b2b fix(README): Updating README details 2025-04-11 16:09:31 -07:00
Chris Troutner f9b4bf06ab Merge pull request #83 from Permissionless-Software-Foundation/ct-unstable
Syncing with upstream repo ipfs-service-provider
2025-04-10 18:06:27 -07:00
Chris Troutner 8048182f46 fixed tests 2025-04-10 18:04:51 -07:00
Chris Troutner cb4d1d3eba fix(ipfs-service-provider): Syncing with upstream repo 2025-04-10 17:57:44 -07:00
Chris Troutner 81e623e35f Merge branch 'ct-unstable' into fullstack 2025-03-09 01:10:05 +00:00
Chris Troutner 3209f96e7f fix(createOffer()): Removing broken NSFW check 2025-03-08 09:09:38 -08:00
Chris Troutner c65d662630 Merge pull request #172 from Permissionless-Software-Foundation/ct-unstable
fix(config): Added webRTC port & connection preference reporting
2025-02-23 10:37:30 -07:00
Chris Troutner 1b99f8afa1 fix(config): Added webRTC port & connection preference reporting 2025-02-23 10:34:00 -07:00
Chris Troutner c6f0a1317c Merge pull request #171 from Permissionless-Software-Foundation/ct-unstable
fix(prod): Switching Docker container to master branch
2025-02-23 09:57:41 -07:00
Chris Troutner fad5f8e23d fix(prod): Switching Docker container to master branch 2025-02-23 09:56:13 -07:00
Chris Troutner ec6e0f5e46 Merge pull request #170 from Permissionless-Software-Foundation/helia-v5
Helia v5
2025-02-23 09:46:10 -07:00
Chris Troutner f1caef2c0d fix(prod): Adding connection prefrence to production startup script 2025-02-23 09:41:55 -07:00
Chris Troutner 55bf9424f9 fix(libp2p): Updating deps to prevent AbortError issue 2702 2025-02-23 09:01:17 -07:00
Chris Troutner aa100c97ed fix(helia-coord): Updating to v1.7.1 2025-02-20 22:41:25 -07:00
Chris Troutner 9fa5eafe95 removing relay advetising deprecated setting 2025-02-20 20:51:40 -07:00
Chris Troutner 4d9e948e30 fix(helia): Manually porting @achingbrian PR to v5 branch 2025-02-20 20:51:09 -07:00
Chris Troutner e5cdf28e34 Catching and reporting AbortError race condition 2025-02-20 19:03:45 -07:00
Chris Troutner 1d82b36105 fix(helia): Updated to 1.7.0 with webRTC and circuit relay enabled 2025-02-16 15:27:43 -07:00
Chris Troutner b910cd1e6d fix(webRTC): Adding /p2p-circuit multiaddr + ping service 2025-02-16 09:29:18 -07:00
Chris Troutner 536861ba99 Re-enabled webRTC and circuit relays 2025-02-14 12:53:12 -07:00
Chris Troutner ef030e3dc6 fix(libp2p): Updated to v2.6.2 with node.js webrtc fix 2025-02-14 09:52:09 -07:00
Chris Troutner 3da46c3d6f Using helia-v5 branch when building docker container 2025-02-12 16:22:44 -07:00
Chris Troutner 82f5552836 feat(helia v5): Generating and saving new private key 2025-02-12 14:58:11 -07:00
Chris Troutner 4d25681c51 fix(helia v5): Changes to get node to connect to other nodes with helia v5 2025-02-12 09:22:36 -07:00
Chris Troutner 98a1631498 Merge pull request #167 from Permissionless-Software-Foundation/ct-unstable
Removing logging of usage middleware
2025-01-27 18:55:29 -07:00
Chris Troutner 8dce8cbf8d Removing logging of usage middleware 2025-01-27 18:53:17 -07:00
Chris Troutner 0b3049138b Merge pull request #166 from Permissionless-Software-Foundation/dh-usage-tests
feat(tests): Added Usage Unit Tests
2025-01-17 05:32:27 -07:00
Daniel Gonzalez d7136583b8 feat(tests): Added Usage Unit Tests 2025-01-15 17:59:09 -04:00
Chris Troutner db1da9172c Using fullstack branch of UI 2024-12-29 09:37:28 -08:00
Chris Troutner 19b13e5d6e Updating docker-compose .env 2024-12-29 09:23:05 -08:00
Chris Troutner c92ffac645 Merge pull request #82 from Permissionless-Software-Foundation/ct-unstable
Refactored to use Nostr instead of P2WDB
2024-12-29 09:16:40 -08:00
Chris Troutner 216f0b6910 fix(tests): fixed broken tests 2024-12-29 09:14:49 -08:00
Chris Troutner c31bf96986 fix(timers): Disabling unneeded timer controller designed for P2WDB issues. 2024-12-28 13:59:27 -08:00
Chris Troutner 7f8ef994a7 feat(Docker): Updating docker containers 2024-12-16 17:53:36 -08:00
Chris Troutner 72ba1c48c2 Can create and take offers using Nostr 2024-12-16 05:29:03 -08:00
Chris Troutner c721da1562 Merge pull request #165 from Permissionless-Software-Foundation/usage
Usage
2024-12-07 21:28:57 -08:00
Chris Troutner 3606a2d31b code cleanup 2024-12-07 21:27:41 -08:00
Chris Troutner 764905b041 fix(usage): Adding endpoints to analyize 24 hour usage of the REST API 2024-12-07 21:25:10 -08:00
Chris Troutner 556c6ec522 fix(usage): Adding Usage REST API 2024-12-07 20:48:08 -08:00
Chris Troutner 2a78145170 Debugging counter-offer 2024-12-07 20:33:25 -08:00
Chris Troutner 04395b70a6 Syncing with ct-unstable. Fixing merge conflict 2024-12-07 18:08:25 -08:00
Chris Troutner d15fee7c7a Merge pull request #81 from Permissionless-Software-Foundation/ct-unstable
fix(offers): Fixed workflow for creating offers from Nostr posts
2024-12-07 10:56:11 -08:00
Chris Troutner 9437b8fb80 fix(offers): Fixed workflow for creating offers from Nostr posts 2024-12-07 10:54:34 -08:00
Chris Troutner b611663379 Merge pull request #80 from Permissionless-Software-Foundation/dh-create-offr-nostr
feat(offer): Trigger createOffer() from Nostr topic
2024-12-06 09:43:58 -08:00
Chris Troutner 03b7ed980a fix(IPFS): Updating IPFS gateway for getting token data 2024-12-06 09:35:33 -08:00
Chris Troutner bf74d50bb0 linting 2024-12-04 17:12:40 -08:00
Chris Troutner 003480bcb5 fix(offer): Refactored _this in rest-api controller 2024-12-04 17:12:26 -08:00
Daniel Gonzalez 9dbd18d0d6 Increased test coverage 2024-12-04 06:51:28 -04:00
Chris Troutner b3ba7f03e4 Commenting out POST /offer/ webhook endpoint 2024-12-03 09:28:52 -08:00
Daniel Gonzalez 0a8bb52241 feat(offer): Trigger createOffer() from Nostr topic 2024-12-02 22:19:54 -04:00
Chris Troutner 5eeafd7ead Merge pull request #79 from Permissionless-Software-Foundation/dh-create-order-fix
fix(order): Refactored createOrder() to use Nostr
2024-11-29 04:02:53 -08:00
Chris Troutner df146382cb Reducing info posted to Nostr on Order 2024-11-29 04:00:10 -08:00
Daniel Gonzalez af8a7c3ff3 fix(order): Refactored createOrder() to use Nostr 2024-11-28 12:37:47 -04:00
Chris Troutner ed6d2af23c Merge pull request #77 from Permissionless-Software-Foundation/dh-nostr-adapter
feat(nostr): Added Nostr adapter
2024-11-26 04:25:26 -08:00
Chris Troutner 4f0ad71fff Making slight tweeks to common config 2024-11-26 04:23:54 -08:00
Daniel Gonzalez 6871380288 feat(nostr): Added Nostr adapter 2024-11-25 14:11:21 -04:00
Chris Troutner 285456656c Merge pull request #75 from Permissionless-Software-Foundation/ct-unstable
Synced with ipfs-service-provider
2024-11-22 10:56:21 -08:00
Chris Troutner 179d8f1656 Merged with ipfs-service-provider. Mitigated several conflict errors 2024-11-22 10:54:21 -08:00
Chris Troutner 94241c08ce Updating to v3.0 2024-11-22 09:51:10 -08:00
Chris Troutner abd4e872bf Merge pull request #73 from Permissionless-Software-Foundation/ct-unstable
Merging changes before branching
2024-11-22 09:48:40 -08:00
Chris Troutner 81521151f4 Merge pull request #164 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs): Disabling webRTC again
2024-09-18 12:02:22 -07:00
Chris Troutner 5a819c1d9c linting 2024-09-18 12:01:10 -07:00
Chris Troutner f2f3208fda fix(ipfs): Disabling webRTC again 2024-09-18 12:00:56 -07:00
Chris Troutner 7fe888cdda Merge pull request #163 from Permissionless-Software-Foundation/ct-unstable
fix(webRTC): Renabling webRTC & circuit relays
2024-09-17 07:50:59 -07:00
Chris Troutner db3f1bf2cf fix(webRTC): Renabling webRTC & circuit relays 2024-09-17 07:49:43 -07:00
Chris Troutner 5f64257dca Merge pull request #162 from Permissionless-Software-Foundation/ct-unstable
fix(webrtc): Disabling webRTC due to bug
2024-09-13 10:07:53 -07:00
Chris Troutner 2fbdccb883 fix(webrtc): Disabling webRTC due to bug 2024-09-13 10:06:19 -07:00
Chris Troutner ecc10afac3 linting 2024-09-13 10:05:05 -07:00
Chris Troutner 4fc54aa9c5 Merge pull request #161 from Permissionless-Software-Foundation/ct-unstable
fix(helia-coord): Updating to v1.5.14
2024-09-12 16:59:23 -07:00
Chris Troutner 2bd7f0c45c Merge branch 'master' into ct-unstable 2024-09-12 16:57:00 -07:00
Chris Troutner 900423339e fix(helia-coord): Updating to v1.5.14 2024-09-12 16:56:44 -07:00
Chris Troutner d907afa6bb Merge pull request #160 from Permissionless-Software-Foundation/ct-unstable
fix(helia-coord): Updating to v1.5.13
2024-09-12 16:48:03 -07:00
Chris Troutner 9b116d82b7 fix(helia-coord): Updating to v1.5.13 2024-09-12 16:42:43 -07:00
Chris Troutner 1d1bf50ee3 Merge pull request #159 from Permissionless-Software-Foundation/ct-unstable
Updating dependencies
2024-09-09 18:15:03 -07:00
Chris Troutner 5002004697 fix(minimal-slp-wallet): Upgraded to v5.12.0 2024-09-09 18:13:36 -07:00
Chris Troutner f311a3b9c6 fix(webRTC): Upgrading to new package, adding required config 2024-08-29 11:00:07 -07:00
Chris Troutner fe91f4b875 Merge pull request #158 from Permissionless-Software-Foundation/ct-unstable
fix(helia-coord): Updating to v1.5.12
2024-08-23 10:30:27 -07:00
Chris Troutner 2d9a2b811c fix(helia-coord): Updating to v1.5.12 2024-08-23 10:24:21 -07:00
Chris Troutner 514b65ed24 Merge pull request #157 from Permissionless-Software-Foundation/ct-unstable
fix(minimal-slp-wallet): Updated to v5.11.3
2024-08-23 07:02:19 -07:00
Chris Troutner 0c7f3088a8 fix(minimal-slp-wallet): Updated to v5.11.3 2024-08-23 06:59:58 -07:00
Chris Troutner 12cab02300 Merge pull request #156 from Permissionless-Software-Foundation/ct-unstable
Upgrading helia to v4.2.5
2024-08-20 07:53:53 -07:00
Chris Troutner 04a908261a Updating requirements in README 2024-08-20 07:32:30 -07:00
Chris Troutner 83898742f1 fix(webRTC): Falling back from v4.1.7 to v4.0.34 2024-08-19 07:35:59 -07:00
Chris Troutner 1795918719 Using node.js v20 for docker container 2024-08-19 06:33:31 -07:00
Chris Troutner 6894217078 fix(production): Limiting docker to 1GB of memory 2024-08-19 06:29:16 -07:00
Chris Troutner 3ffbed27b5 fix(helia-coord): Got running with v1.5.11 2024-08-18 08:41:28 -07:00
Chris Troutner b372e3d260 Merge pull request #155 from Permissionless-Software-Foundation/ct-unstable
fix(Mongo): Skipping some tests when noMongo is true
2024-06-09 09:12:31 -07:00
Chris Troutner 707b385b8a linting 2024-06-09 09:11:09 -07:00
Chris Troutner 6cb140a491 fix(Mongo): Skipping some tests when noMongo is true 2024-06-09 09:10:55 -07:00
Chris Troutner c43ee8c25a Merge pull request #154 from Permissionless-Software-Foundation/ct-unstable
feat(Mongo): Config variable can disable MongoDB usage and dependency in Docker
2024-06-09 08:38:00 -07:00
Chris Troutner 0a7ec11510 feat(Mongo): Config variable can disable MongoDB usage and dependency in Docker 2024-06-09 08:28:40 -07:00
Chris Troutner f7aaba71d1 Merge pull request #153 from Permissionless-Software-Foundation/ct-unstable
fix(helia-coord): Updating to v1.5.8
2024-05-04 09:38:28 -07:00
Chris Troutner 418a2e2ad2 fix(helia-coord): Updating to v1.5.8 2024-05-04 09:37:10 -07:00
Chris Troutner a1023e8224 Merge pull request #152 from Permissionless-Software-Foundation/ct-unstable
fix(Docker): Setting memory limit at 4GB
2024-04-27 13:20:20 -07:00
Chris Troutner a32ed63d47 fix(Docker): Setting memory limit at 4GB 2024-04-27 13:17:57 -07:00
Chris Troutner 934fb46ffc Merge pull request #151 from Permissionless-Software-Foundation/ct-unstable
fix(Docker): Removing Volume statement
2024-04-26 14:40:41 -07:00
Chris Troutner b27136d03b fix(Docker): Removing Volume statement 2024-04-26 14:39:18 -07:00
Chris Troutner 064ac36dc7 linting 2024-04-26 14:38:17 -07:00
Chris Troutner 5e2cf86f4b Checking in code before switching branches 2024-04-26 14:38:03 -07:00
Chris Troutner 425d2ada65 Binding 'this' object to some subfunctions 2024-04-20 07:14:17 -07:00
Chris Troutner 60a3d67c0b Merge pull request #150 from Permissionless-Software-Foundation/ct-unstable
fix(config): web2Api can be set with env var
2024-04-13 07:11:20 -07:00
Chris Troutner a03c5d8c91 fix(config): web2Api can be set with env var 2024-04-13 07:09:45 -07:00
Chris Troutner bcc90da49b Merge pull request #149 from Permissionless-Software-Foundation/ct-unstable
fix(config): Adding web2Api property to jsonLd config
2024-04-13 07:04:02 -07:00
Chris Troutner b473a3803c fix(config): Adding web2Api property to jsonLd config 2024-04-13 07:02:32 -07:00
Chris Troutner 9614f186b4 Merge pull request #148 from Permissionless-Software-Foundation/ct-unstable
fix(helia-coord): Updating to v1.5.7
2024-04-12 08:32:13 -07:00
Chris Troutner 0390f2d956 fix(helia-coord): Updating to v1.5.7 2024-04-12 08:30:14 -07:00
Chris Troutner ba5ead998d Merge pull request #147 from Permissionless-Software-Foundation/ct-unstable
fix(docker): Tweaking some defaults
2024-04-03 06:02:17 -07:00
Chris Troutner 409a0f1049 fix(docker): Tweaking some defaults 2024-04-03 05:54:24 -07:00
Chris Troutner bd2f27bb64 Merge pull request #146 from Permissionless-Software-Foundation/ct-unstable
fix(incrementNextAddress): fixing bug
2024-03-29 12:44:43 -07:00
Chris Troutner 55d8d131cf Removing commented code 2024-03-29 12:43:15 -07:00
Chris Troutner 5a6e3247e8 fix(incrementNextAddress): fixing bug 2024-03-29 12:43:02 -07:00
Chris Troutner 2a522775eb Adding wallet.json to gitignore 2024-03-29 11:36:58 -07:00
Chris Troutner d677c83795 Removing wallet.json file 2024-03-29 11:36:35 -07:00
Chris Troutner 7cffd9f377 Merge pull request #145 from Permissionless-Software-Foundation/ct-unstable
fix(helia-coord): Updating to v1.5.6, auto-retry of bootstrap list
2024-03-24 07:44:46 -07:00
Chris Troutner 0a406cb9a4 fix(helia-coord): Updating to v1.5.6, auto-retry of bootstrap list 2024-03-24 07:43:34 -07:00
Chris Troutner f172a51016 Merge pull request #144 from Permissionless-Software-Foundation/ct-unstable
Integrating minimal-slp-wallet. Wallet creation at startup
2024-03-23 17:46:55 -07:00
Chris Troutner 00d53659b1 Updating README 2024-03-23 17:44:41 -07:00
Chris Troutner b0797d92f5 Increased test coverage to 100% 2024-03-23 17:42:59 -07:00
Chris Troutner 48484ed7af Fixing typo with web3 wallet 2024-03-23 17:23:07 -07:00
Chris Troutner 6a4aadde8a Refactoring config file 2024-03-23 17:14:26 -07:00
Chris Troutner 79e3aba26e Adding default startup wallet 2024-03-23 16:18:10 -07:00
Chris Troutner bf61359bc7 feat(wallet): Added adapter library for consuming minimal-slp-wallet 2024-03-23 11:16:45 -07:00
Chris Troutner a79d152993 Merge pull request #143 from Permissionless-Software-Foundation/ct-unstable
fix(helia-coord): Updating to v1.5.5
2024-03-12 08:32:05 -07:00
Chris Troutner ce7c3a0e2f fix(helia-coord): Updating to v1.5.5 2024-03-12 08:30:32 -07:00
Chris Troutner e6b0580209 Merge pull request #142 from Permissionless-Software-Foundation/ct-unstable
Back to 100% unit test coverage
2024-03-10 07:44:19 -07:00
Chris Troutner 1f3c639100 fix(tests): Back to 100% unit test coverage 2024-03-10 07:43:06 -07:00
Chris Troutner e6efc4f49b Prototyped /ipfs/download 2024-03-07 21:27:06 -08:00
Chris Troutner dbbd321029 fix(/ipfs/node): Added unit tests for API controller 2024-03-07 18:55:09 -08:00
Chris Troutner 439dbc54ae fix(ipfs): Increased adapter to 100% unit test coverage 2024-03-07 10:22:25 -08:00
Chris Troutner 547e59f52f fix(Docker): Adding .env file 2024-03-04 10:47:08 -08:00
Chris Troutner a0d385de73 Merge pull request #141 from Permissionless-Software-Foundation/ct-unstable
fix(helia-coord): Updating to v1.5.4, fixes minor bug
2024-03-03 06:46:38 -08:00
Chris Troutner bec136009f fix(helia-coord): Updating to v1.5.4, fixes minor bug 2024-03-03 06:44:24 -08:00
Chris Troutner 98b7fa7734 Merge pull request #140 from Permissionless-Software-Foundation/ct-unstable
Removing Circuit Relay for nodes configured for direct connection
2024-02-05 06:41:01 -08:00
Chris Troutner d7bb476858 fix(circuit-relay): Removing CR transport if node is configured for direct connection 2024-02-05 06:39:01 -08:00
Chris Troutner 18c71c383f fix(webrtc): Upgrading from v3.2.11 to v4.0.17 2024-02-05 06:26:01 -08:00
Chris Troutner de85a933c4 fix(webrtc): Adding @libp2p/webrtc 2024-02-04 20:43:34 -08:00
Chris Troutner 16247372f1 linting 2024-02-04 20:35:34 -08:00
Chris Troutner c6c8b6418c Prototyping download REST API 2024-02-04 20:35:22 -08:00
Chris Troutner 10c4e7380f fix(webrtc): Removing webrtc library 2024-01-31 09:38:18 -08:00
Chris Troutner 4933dce472 Merge pull request #139 from Permissionless-Software-Foundation/ct-unstable
fix(webRTC): Explicitly adding @libp2p/webrtc package
2024-01-31 08:50:43 -08:00
Chris Troutner 80c2822716 fix(webRTC): Explicitly adding @libp2p/webrtc package 2024-01-31 08:42:38 -08:00
Chris Troutner f48ff9a67e Merge pull request #138 from Permissionless-Software-Foundation/ct-unstable
fix(helia-coord): Updating to v1.5.3
2024-01-30 19:45:57 -08:00
Chris Troutner 4bd2385359 fix(helia-coord): Updating to v1.5.3 2024-01-30 19:44:29 -08:00
Chris Troutner be71492773 Merge pull request #137 from Permissionless-Software-Foundation/ct-unstable
fix(createNode()): Updating RSA to Ed25519 keys
2024-01-29 07:58:49 -08:00
Chris Troutner bcb70edf2b fix(createNode()): Updating RSA to Ed25519 keys 2024-01-29 07:57:32 -08:00
Chris Troutner 07071032bc Merge pull request #136 from Permissionless-Software-Foundation/ct-unstable
fix(Docker): Updated new node.js installation
2024-01-28 19:57:45 -08:00
Chris Troutner f476e119a2 fix(Docker): Updated new node.js installation 2024-01-28 19:54:21 -08:00
Chris Troutner 0fed232428 Merge pull request #135 from Permissionless-Software-Foundation/ct-unstable
fix(Docker): Switching to ct-unstable branch
2024-01-28 19:42:02 -08:00
Chris Troutner 0273510485 fix(Docker): Switching to ct-unstable branch 2024-01-28 19:38:42 -08:00
Chris Troutner a62dee37f4 Merge pull request #134 from Permissionless-Software-Foundation/v1.0.10
libp2p v1.2.1
2024-01-28 19:36:24 -08:00
Chris Troutner 8d6af3e1b7 fix(helia-coord): Updating to v1.4.3 2024-01-28 15:17:01 -08:00
Chris Troutner ee0f2da641 fix(docker): Building container rather than using image 2024-01-28 15:05:34 -08:00
Chris Troutner 44499d9652 Updating Dockerfile to use v1.0.10 branch 2024-01-28 15:00:30 -08:00
Chris Troutner 365a5dcd4b Updated to libp2p 1.2.1 2024-01-28 14:59:25 -08:00
Chris Troutner 7f5b456018 linting 2024-01-28 14:13:42 -08:00
Chris Troutner c7217486bd fix(getSeed()): Generates seed for IPFS private key 2024-01-28 12:49:18 -08:00
Chris Troutner 050141d31e Creating todo for seed 2024-01-28 08:22:55 -08:00
Chris Troutner b697f37199 fix(keys): Creating persistent keystore for libp2p v1.0.x 2024-01-28 08:19:38 -08:00
Chris Troutner ceb58caba1 linting 2024-01-28 08:04:02 -08:00
Chris Troutner 2724b500ee Got keychain working for first time 2024-01-28 08:03:41 -08:00
Chris Troutner 1b84e7beb8 Merge pull request #133 from Permissionless-Software-Foundation/v0.46.21
fix(pubsub): Removing chat handler causing screen spam
2024-01-27 17:48:29 -08:00
Chris Troutner 383900d8b5 fix(pubsub): Removing chat handler causing screen spam 2024-01-27 17:45:23 -08:00
Chris Troutner ba806d86b5 Merge pull request #132 from Permissionless-Software-Foundation/v0.46.21
Updated to helia-coord v1.4.1
2024-01-27 15:02:57 -08:00
Chris Troutner 4d7c7350a0 linting 2024-01-27 15:01:01 -08:00
Chris Troutner adc6500aed Adding config options for V2 Circuit Relay server 2024-01-27 13:17:34 -08:00
Chris Troutner eb9fce73eb Updated helia-coord to v1.4.1 2024-01-27 10:45:44 -08:00
Chris Troutner ec3ed165e4 feat(GET /ipfs/node): Retrieves thisNode object 2024-01-27 09:26:50 -08:00
Chris Troutner d41d20cc81 prototyping keychain example 2024-01-26 19:52:55 -08:00
Chris Troutner 5f965e7146 Switching back to libp2p v0.46.21 2024-01-11 12:26:16 -08:00
Chris Troutner f382bb4578 Merge pull request #131 from Permissionless-Software-Foundation/ct-unstable
Helia v1.2.24 - recommended peers from gist
2023-12-18 20:56:26 -08:00
Chris Troutner ba37f87f80 fix(helia-coord): updating to v1.2.24, adding recommended peers 2023-12-18 20:55:25 -08:00
Chris Troutner eaa9c23f55 Updating helia-coord ot v1.2.23 2023-12-16 06:42:12 -08:00
Chris Troutner ac3730dbd9 Merge pull request #130 from Permissionless-Software-Foundation/libp2p-v1
Libp2p v1
2023-12-13 19:46:43 -08:00
Chris Troutner 581b8eb626 fix(libp2p): Updating to v1.0.10 2023-12-13 19:44:58 -08:00
Chris Troutner cd4ec2711e Updated circuit-relay library 2023-12-06 10:32:59 -08:00
Chris Troutner e9e3dbad0d Updated to libp2p 1.0.9, added @libp2p/identify 2023-12-06 10:20:48 -08:00
Chris Troutner 295b361431 Merge pull request #129 from Permissionless-Software-Foundation/ct-unstable
Updating helia-coord to v1.2.21
2023-12-04 08:53:58 -08:00
Chris Troutner ad60df9d51 Updating helia-coord to v1.2.21 2023-12-04 08:52:16 -08:00
Chris Troutner 6ae635c21d Merge pull request #128 from Permissionless-Software-Foundation/ct-unstable
fix(bootstrap): Loading bootstrap nodes from gist only
2023-12-04 07:27:14 -08:00
Chris Troutner 61807a2f3d fix(bootstrap): Loading bootstrap nodes from gist only 2023-12-04 07:25:32 -08:00
Chris Troutner 16ba5a8980 Merge pull request #127 from Permissionless-Software-Foundation/ct-unstable
fix(deps): Updating helia-coord and helia
2023-12-03 16:43:34 -08:00
Chris Troutner 99b817549e fix(deps): Updating helia-coord and helia 2023-12-03 16:42:32 -08:00
Chris Troutner 60a8c335c8 Merge pull request #126 from Permissionless-Software-Foundation/ct-unstable
fix(helia-coord): Updated to v1.2.18
2023-12-03 09:42:52 -08:00
Chris Troutner 1783768c32 fix(helia-coord): Updated to v1.2.18 2023-12-03 09:41:42 -08:00
Chris Troutner b3630eaa06 Merge pull request #125 from Permissionless-Software-Foundation/ct-unstable
fix(helia): Upgrade to v0.46.21
2023-12-03 09:04:01 -08:00
Chris Troutner d691016911 fix(helia): Upgrade to v0.46.21 2023-12-03 09:01:03 -08:00
Chris Troutner 6506aead8c Merge pull request #124 from Permissionless-Software-Foundation/ct-unstable
fix(webrtc): Adding webrtc as a transport
2023-12-03 07:37:11 -08:00
Chris Troutner ddfc83d026 fix(webrtc): Adding webrtc as a transport 2023-12-03 07:35:47 -08:00
Chris Troutner fe42c1e0e3 Merge pull request #123 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs): Autodetecting ip addr and adding to multiaddr
2023-12-03 07:30:15 -08:00
Chris Troutner 928a211a63 fix(ipfs): Autodetecting ip addr and adding to multiaddr 2023-12-03 07:28:31 -08:00
Chris Troutner 8bff69a4ca Merge pull request #122 from Permissionless-Software-Foundation/ct-unstable
fix(helia-coord): Updating to v1.2.17
2023-12-02 17:12:47 -08:00
Chris Troutner 5fced7d501 fix(helia-coord): Updating to v1.2.17 2023-12-02 17:11:05 -08:00
Chris Troutner 7cdf622ad6 Merge pull request #121 from Permissionless-Software-Foundation/ct-unstable
fix(helia-coord): Updating helida-coord to v1.2.16
2023-12-02 14:13:43 -08:00
Chris Troutner afd8ceac7b fix(helia-coord): Updating helida-coord to v1.2.16 2023-12-02 14:12:32 -08:00
Chris Troutner 5d63db3662 Merge pull request #120 from Permissionless-Software-Foundation/ct-unstable
fix(helia-coord): Updating to v1.2.5
2023-11-04 08:47:34 -07:00
Chris Troutner 9f6cd7dbf1 fix(helia-coord): Updating to v1.2.5 2023-11-04 08:45:46 -07:00
Chris Troutner 0725aa3ada Merge pull request #119 from Permissionless-Software-Foundation/ct-unstable
fix(peers): Adding connectionAddr to /ipfs/peers
2023-11-03 14:42:28 -07:00
Chris Troutner 3eb88d4076 fix(peers): Adding connectionAddr to /ipfs/peers 2023-11-03 14:33:58 -07:00
Chris Troutner 1c61f150b1 fix(v1 relays): Discerning between v1 and v2 circuit relays 2023-11-03 12:07:43 -07:00
Chris Troutner 4c74b287d8 Merge pull request #118 from Permissionless-Software-Foundation/ct-unstable
feat(/ipfs/connect): Adding REST API endpoint to connect to an IPFS peer
2023-11-01 14:18:51 -07:00
Chris Troutner 264d762f74 feat(/ipfs/connect): Adding REST API endpoint to connect to an IPFS peer 2023-11-01 14:17:24 -07:00
Chris Troutner 3c02461c6b Merge pull request #117 from Permissionless-Software-Foundation/ct-unstable
fix(circuit relay): Adding ability to creating and consume circuit re…
2023-10-29 16:41:52 -07:00
Chris Troutner a30f2be51f fix(circuit relay): Adding ability to creating and consume circuit relays 2023-10-29 16:39:35 -07:00
Chris Troutner 0690a9fb65 Merge pull request #116 from Permissionless-Software-Foundation/ct-unstable
fix(README): Adding link to video demo
2023-10-28 13:57:55 -07:00
Chris Troutner 4fa103765e Merge branch 'master' into ct-unstable 2023-10-28 13:51:35 -07:00
Chris Troutner b0d6ce40a9 fix(README): Adding link to video demo 2023-10-28 13:50:46 -07:00
Chris Troutner c57a3d935b Merge pull request #115 from Permissionless-Software-Foundation/ct-unstable
Updating Docker container for production
2023-10-28 11:32:24 -07:00
Chris Troutner 82b5943601 Adding collaborative coinjoin project to README 2023-10-28 11:30:57 -07:00
Chris Troutner 41b76967f5 Adding production section back to README 2023-10-28 11:27:06 -07:00
Chris Troutner e4c2ee44c1 fix(production): Updating docker container 2023-10-28 11:24:40 -07:00
Chris Troutner c05f022995 Bumping to v5.0.0 2023-10-28 10:32:45 -07:00
Chris Troutner 7723c3a201 Merge pull request #114 from Permissionless-Software-Foundation/helia
Helia refactor. v4.0.0
2023-10-28 10:24:20 -07:00
Chris Troutner 8e338818ca Updating READMe 2023-10-28 10:19:59 -07:00
Chris Troutner ea51aa420c Updating README 2023-10-28 10:14:42 -07:00
Chris Troutner bc410678b4 Updating README and package.json 2023-10-28 10:11:04 -07:00
Chris Troutner a42c15c969 Updating package.json 2023-10-28 09:55:41 -07:00
Chris Troutner a3102a0278 Cleaned up comments 2023-10-28 09:50:12 -07:00
Chris Troutner f4f142dc48 fix(tests): Increased test coverage to 100% 2023-10-28 09:17:48 -07:00
Chris Troutner e03a70c9a3 fix(get-peers): finalizing REST endpoint behavior 2023-10-27 17:39:24 -07:00
Chris Troutner d47b8797d4 fix(libp2p): Updated to v0.46.16 2023-10-25 22:13:35 -07:00
Chris Troutner 56ba0aad02 Adding IPFS REST API endpoints 2023-10-23 20:28:17 -07:00
Chris Troutner 825bc6d2de fix(ipfs): Creating block & data store directories if they don't exit 2023-10-23 09:16:06 -07:00
Chris Troutner 18fe63a5ad fix(tests): Fixed broken tests 2023-10-22 17:35:10 -07:00
Chris Troutner d6e0e7b903 got helia working 2023-10-22 07:51:45 -07:00
Chris Troutner 8759e1af5e Merge pull request #113 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord-esm): Updating to v9.1.13
2023-08-29 16:38:56 -07:00
Chris Troutner b78f3fb08b fix(ipfs-coord-esm): Updating to v9.1.13 2023-08-29 16:34:41 -07:00
Chris Troutner 5fa0b2e1c8 Merge pull request #112 from Permissionless-Software-Foundation/ct-unstable
fix(license): Updating license file
2023-06-25 06:15:14 -07:00
Chris Troutner 6a88d0559a fix(license): Updating license file 2023-06-25 06:13:22 -07:00
Chris Troutner 314fdc2bb0 fix(minimal-slp-wallet): Updating to v5.11.1 2023-06-25 06:11:45 -07:00
Chris Troutner acd7154d41 fix(docker): Updating p2wdb image to v4.1.3 2023-05-14 17:22:13 -07:00
Chris Troutner 63a1bea60d fix(docker): Updating P2WDB image to v4.1.1 2023-05-13 14:46:24 -07:00
Chris Troutner 077c60bd34 Merge pull request #111 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord-esm): Updating to v9.1.9
2023-05-13 07:06:26 -07:00
Chris Troutner 6485537207 Turning down debug logs 2023-05-13 07:03:49 -07:00
Chris Troutner 286f079679 fix(ipfs-coord-esm): Updating to v9.1.9 2023-05-13 06:59:25 -07:00
Chris Troutner 075818d551 Adding test coverage reporting for just unit tests 2023-05-12 15:25:58 -07:00
Chris Troutner b0f42d613b Adding Dia workflows 2023-05-12 14:34:55 -07:00
Chris Troutner 8e5b87f142 Merge pull request #71 from Permissionless-Software-Foundation/ct-unstable
fix(dependencies): Updating npm dependencies
2023-05-11 12:14:38 -07:00
Chris Troutner 92483ee5e1 fix(dependencies): Updating npm dependencies 2023-05-11 12:09:43 -07:00
Chris Troutner a80b82da7a Merge pull request #70 from Permissionless-Software-Foundation/ct-unstable
Updating P2WDB docker image
2023-05-11 07:12:38 -07:00
Chris Troutner 41d2aaa16d fix(production): Updating P2WDB docker image 2023-05-11 07:11:11 -07:00
Chris Troutner 9de2caba94 Merge pull request #110 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord-esm): Updating to 9.1.7
2023-05-09 09:00:04 -07:00
Chris Troutner a45fb3ad08 fix(ipfs-coord-esm): Updating to 9.1.7 2023-05-09 08:56:26 -07:00
Chris Troutner 666f954529 Merge pull request #109 from Permissionless-Software-Foundation/ct-unstable
Minor Fixes
2023-05-09 08:07:55 -07:00
Chris Troutner 7d2e02fe64 fix(timer-controller): Adding unit tests for startTimers() 2023-05-09 08:06:57 -07:00
Chris Troutner 9912ed7af7 fix(json-files): Rejecting promise rather than throwing an error 2023-05-09 08:00:30 -07:00
Chris Troutner 441d898ae7 fix(timer controller): Preventing duplicate timer controllers 2023-05-08 08:01:02 -07:00
Chris Troutner 553a7ff86a Merge pull request #108 from Permissionless-Software-Foundation/ct-unstable
feat(ipfs): Allowing disabling IPFS features with config flag
2023-04-10 09:22:11 -07:00
Chris Troutner 349d070273 feat(ipfs): Allowing disabling IPFS features with config flag 2023-04-10 09:19:51 -07:00
Chris Troutner b6dcb9c177 Updating link to clean architecture 2023-03-22 17:10:51 -07:00
Chris Troutner 8aff3a6568 Merge pull request #107 from Permissionless-Software-Foundation/ct-unstable
feat(timer-controllers): Added template for timer-based controllers
2023-02-25 06:10:53 -08:00
Chris Troutner 9e885b8bc3 feat(timer-controllers): Added template for timer-based controllers 2023-02-25 06:09:56 -08:00
Chris Troutner d6b924a5f4 Merge pull request #106 from Permissionless-Software-Foundation/ct-unstable
Updating ipfs-coord-esm for bch-coinjoin pubsub
2023-02-24 13:50:17 -08:00
Chris Troutner 97691a0dd9 fix(minimal-slp-wallet): Updated to v5.8.5 2023-02-24 13:47:22 -08:00
Chris Troutner 3781af6305 fix(ipfs-coord-esm): Updating to v9.1.5 2023-02-24 13:45:48 -08:00
Chris Troutner cb5d5a603d fixing typo in user REST controller 2023-02-23 08:36:47 -08:00
Chris Troutner 81713bfebe Updating README 2023-01-16 05:37:52 -08:00
Chris Troutner b9aeb8faa0 Updating list-addrs script 2022-12-24 21:07:30 -08:00
Chris Troutner a4e75cdccc fix(scripts): Adding script to list addresses in a wallet 2022-12-24 21:05:42 -08:00
Chris Troutner f74c94ef50 fix(sweep): Adding fullstack-sweep-wallet.js for faster wallet sweeping 2022-12-24 07:34:54 -08:00
Chris Troutner bfb51fdcc6 fix(docker): Bumping p2wdb to v3.3.5 2022-12-13 06:52:10 -08:00
Chris Troutner 25aaf4146f Merge pull request #69 from Permissionless-Software-Foundation/ct-unstable
Minor fixes. New docker image v2.2.4
2022-12-13 06:47:11 -08:00
Chris Troutner 8ee10f2f8c fix(docker): Increasing docker image to v2.2.4 2022-12-13 06:44:20 -08:00
Chris Troutner bf96821c2c fix(docker): Fixing issue with P2WDB 2022-12-13 06:09:02 -08:00
Chris Troutner 9787806427 fix(docker): Disabling BCH payments in local P2WDB (be default) 2022-12-10 12:36:02 -08:00
Chris Troutner 9043aab432 fix(docker): Switching to p2wdbv3.3.3 2022-12-10 12:19:53 -08:00
Chris Troutner 58989a81dc Merge pull request #68 from Permissionless-Software-Foundation/ct-unstable
fix(config): Using public P2WDB for writes by default
2022-12-10 10:54:07 -08:00
Chris Troutner 82acd623d8 fix(config): Using public P2WDB for writes by default 2022-12-10 10:43:55 -08:00
Chris Troutner e4fe8cc492 Adding minor debug log 2022-12-07 15:26:35 -08:00
Chris Troutner 0f8a6b9299 Merge pull request #103 from Permissionless-Software-Foundation/ct-unstable
fix(minimal-slp-wallet): Updating to v5.5.5
2022-12-05 13:53:19 -08:00
Chris Troutner 4f2c87bbd4 fix(minimal-slp-wallet): Updating to v5.5.5 2022-12-05 13:51:41 -08:00
Chris Troutner 66b8e6b263 Merge branch 'ct-unstable' 2022-12-05 10:36:25 -08:00
Chris Troutner cabff83222 Updating docker image to v2.2.3 2022-12-05 10:36:16 -08:00
Chris Troutner d94b527780 Merge pull request #67 from Permissionless-Software-Foundation/ct-unstable
fix(minimal-slp-wallet): Updating to v5.5.5
2022-12-05 10:32:38 -08:00
Chris Troutner f0e8a05f08 fix(minimal-slp-wallet): Updating to v5.5.5 2022-12-05 10:27:37 -08:00
Chris Troutner 278b4127e1 fix(docker): Bumping bch-dex container to v2.2.2 2022-12-05 09:51:54 -08:00
Chris Troutner 87b3d7519c Merge pull request #66 from Permissionless-Software-Foundation/ct-unstable
Optimize wallet on new orders. Use local P2WDB
2022-12-05 09:43:14 -08:00
Chris Troutner ed4e75c9ad fix(docker): Using local P2WDB rather than p2wdb.fullstack.cash 2022-12-05 09:39:52 -08:00
Chris Troutner b0cc5a6e0b fix(order): Optimizing wallet before creating new orders 2022-12-05 09:38:28 -08:00
Chris Troutner 6b4139a29e Merge pull request #65 from Permissionless-Software-Foundation/ct-unstable
fix(docker): Disabling P2WDB payment service by default
2022-12-03 13:35:13 -08:00
Chris Troutner 925242262a fix(docker): Disabling P2WDB payment service by default 2022-12-03 13:32:13 -08:00
Chris Troutner 74fe77009c fix(timer): Setting time controller to fire every 10 minutes 2022-12-03 13:27:47 -08:00
Chris Troutner 51f7905dad fix(p2wdb-esm): Upgrading to v2.2.9 2022-12-02 21:10:18 -08:00
Chris Troutner 0b1d3e63f6 Merge pull request #64 from Permissionless-Software-Foundation/ct-unstable
feat(order): Adding functions needed by AMM
2022-12-02 20:07:54 -08:00
Chris Troutner 549fd4fd5a feat(order): Adding functions needed by AMM 2022-12-02 07:44:35 -08:00
Chris Troutner 846ee21c48 Merge pull request #63 from Permissionless-Software-Foundation/ct-unstable
feat(Orders): Added new REST endpoint to get all Orders
2022-12-01 15:12:46 -08:00
Chris Troutner 6654836440 Merge branch 'master' into ct-unstable 2022-12-01 15:10:41 -08:00
Chris Troutner a25a13673e feat(Orders): Added new REST endpoint to get all Orders 2022-12-01 15:10:04 -08:00
Chris Troutner dd7db3814a Merge pull request #102 from Permissionless-Software-Foundation/ct-unstable
fix(minimal-slp-wallet): Updating to v5.5.3
2022-11-30 15:06:29 -08:00
Chris Troutner fdb3b9c3ac fix(minimal-slp-wallet): Updating to v5.5.3 2022-11-30 14:59:54 -08:00
Chris Troutner 30eed1ffb1 Merge pull request #62 from Permissionless-Software-Foundation/ct-unstable
fix(production): Updating docker images
2022-11-29 15:49:36 -08:00
Chris Troutner 7884cffdc6 fix(production): Updating docker images 2022-11-29 15:47:18 -08:00
Chris Troutner c1a8210fa7 Merge pull request #61 from Permissionless-Software-Foundation/ct-unstable
fix(p2wdb-esm): Bumping to v2.2.8
2022-11-03 05:58:54 -07:00
Chris Troutner 9f3b482f57 fix(p2wdb-esm): Bumping to v2.2.8 2022-11-03 05:56:48 -07:00
Chris Troutner 9487027852 Merge pull request #60 from Permissionless-Software-Foundation/ct-unstable
fix(garbage collection): Fixing bug that was deleting valid offers
2022-11-02 17:32:45 -07:00
Chris Troutner 9065900608 fix(garbage collection): Fixing bug that was deleting valid offers 2022-11-02 17:02:36 -07:00
Chris Troutner 2da319f896 fix(garbage): Debugging garbage collection 2022-11-02 15:07:47 -07:00
Chris Troutner 449a98d80c fix(offers): Rounding sats 2022-11-02 15:06:10 -07:00
Chris Troutner 2343120fcf Merge pull request #59 from Permissionless-Software-Foundation/ct-unstable
Updating p2wdb lib
2022-10-10 16:49:24 -07:00
Chris Troutner 2d4fa523cd fix(production): Updating startup script 2022-10-09 08:23:26 -07:00
Chris Troutner c8cc3adbc5 fix(p2wd-esm): Bumping to v2.2.7 2022-10-09 08:16:07 -07:00
Chris Troutner 169e0ad3d2 Updating p2wdb lib 2022-10-09 06:51:03 -07:00
Chris Troutner e20a0a5d27 Rebuilding containers 2022-10-09 06:41:41 -07:00
Chris Troutner 6dda29bb14 fixing create-wallet script 2022-10-09 06:39:42 -07:00
Chris Troutner dd662e9fe9 fix(deps): Updating minimal-slp-wallet 2022-10-09 06:37:12 -07:00
Chris Troutner 9b775c5bf6 Merge pull request #58 from Permissionless-Software-Foundation/ct-unstable
Updating retry-queue to v1.0.8
2022-10-05 14:53:16 -07:00
Chris Troutner 2047673862 fix(timer controllers): Wrapper stale order/offer detection in retry-queue 2022-10-05 14:50:53 -07:00
Chris Troutner 5b545aebeb Updating RPi docker image 2022-10-03 06:46:49 -07:00
Chris Troutner 1e75816125 fix(RPi): Updating dex-ui docker image 2022-10-03 06:45:39 -07:00
Chris Troutner 455fd807a4 fix(docker): Updating dex-ui docker image 2022-10-03 05:58:33 -07:00
Chris Troutner 8b75ac0f32 Removing old comments 2022-10-02 16:50:54 -07:00
Chris Troutner f1a5ae70e2 fix(docker): Updating docker image 2022-10-02 15:43:16 -07:00
Chris Troutner 46bd532eeb Merge pull request #57 from Permissionless-Software-Foundation/ct-unstable
fixing missing ticker
2022-10-02 14:07:43 -07:00
Chris Troutner 6f99b215cd fixing missing ticker 2022-10-02 14:03:27 -07:00
Chris Troutner 3482540fc8 fix(order): fixing missing ticker 2022-10-02 13:46:19 -07:00
Chris Troutner fb999c7bd4 fix(RPi): Not specifying a P2WDB string' 2022-10-02 09:02:50 -07:00
Chris Troutner a09e5a5ba7 Merge pull request #56 from Permissionless-Software-Foundation/ct-unstable
Updating docker images
2022-10-02 08:47:10 -07:00
Chris Troutner ba14b97258 fix(RPi): Updating docker container to v2.0.6 2022-10-02 08:41:57 -07:00
Chris Troutner 79ac3729c9 fix(spam): Reducing screen spam 2022-10-02 08:36:55 -07:00
Chris Troutner bd77754686 fix(docker): Updating docker image for bch-dex 2022-10-02 08:27:09 -07:00
Chris Troutner b3b5322226 Merge pull request #55 from Permissionless-Software-Foundation/ct-unstable
fix(moveTokens): Trying to fix tx-mempool conflict error
2022-10-02 08:06:17 -07:00
Chris Troutner ec1f950ffb fix(moveTokens): Trying to fix tx-mempool conflict error 2022-10-02 08:02:40 -07:00
Chris Troutner b18bc51885 Merge pull request #54 from Permissionless-Software-Foundation/ct-unstable
Added timer controller to remove duplicate offers
2022-10-02 07:22:24 -07:00
Chris Troutner e8c35dd1f3 Merge branch 'master' into ct-unstable 2022-10-02 07:19:49 -07:00
Chris Troutner 8be0accdca Merge branch 'ct-unstable' of https://github.com/Permissionless-Software-Foundation/bch-dex into ct-unstable 2022-10-02 07:18:38 -07:00
Chris Troutner 94c56a06b7 fix(offers): Added timer controller to remove duplicate offers 2022-10-02 07:18:17 -07:00
Chris Troutner 42f64e3304 Merge branch 'ct-unstable' of https://github.com/Permissionless-Software-Foundation/bch-dex into ct-unstable 2022-10-02 00:14:24 -07:00
Chris Troutner cc9bbc3c5d Merge pull request #53 from Permissionless-Software-Foundation/ct-unstable
Refactoring Maker workflow to use retry queue
2022-10-02 00:12:43 -07:00
Chris Troutner 0c6696875b fix(offer): Refactored createOffer to use retry queue 2022-10-02 00:06:02 -07:00
Chris Troutner 37b2e426a5 fix(order): Retry-Queue used to wrap workflow 2022-10-01 23:45:49 -07:00
Chris Troutner f3713985ed fix(order): Refactored to completed some to-do items 2022-10-01 22:57:29 -07:00
Chris Troutner 4ed9994414 Merge pull request #52 from Permissionless-Software-Foundation/ct-unstable
several little tweeks
2022-10-01 22:44:58 -07:00
Chris Troutner 140707ce6b fix(RPi): Updating P2WDB image 2022-10-01 16:54:49 -07:00
Chris Troutner c289e82b0e fix(scripts): Coverting scripts to ES6 2022-10-01 15:58:36 -07:00
Chris Troutner 84210d07c4 Merge branch 'ct-unstable' of https://github.com/Permissionless-Software-Foundation/bch-dex into ct-unstable 2022-10-01 15:44:51 -07:00
Chris Troutner 6d285c77cd fix(RPi): Updating docker images 2022-10-01 15:43:49 -07:00
Chris Troutner 7cefbd71ef fix(ipfs): Adding gateway setting to config 2022-10-01 14:20:37 -07:00
Chris Troutner 85d6aa7d46 Updating package.json to reflect major release 2022-10-01 13:17:30 -07:00
Chris Troutner aaee25389f Merge pull request #51 from Permissionless-Software-Foundation/ct-unstable
fix(docker): Updating docker image. Bumping to v2
2022-10-01 13:12:48 -07:00
Chris Troutner ce83ddcadf fix(docker): Updating docker image. Bumping to v2 2022-10-01 13:10:21 -07:00
Chris Troutner 1b961905e0 Merge pull request #50 from Permissionless-Software-Foundation/ct-unstable
Syncing with upstream. Converting from CommonJS to ES6
2022-10-01 13:02:35 -07:00
Chris Troutner e757bd0fe0 Updating p2wdb image 2022-10-01 13:00:22 -07:00
Chris Troutner 3da78ce46b fix(ES6): Synced with upstream, converted from CommonJS to ES6 2022-10-01 12:16:14 -07:00
Chris Troutner c9d1d79e11 linting 2022-10-01 11:40:41 -07:00
Chris Troutner ce118069eb Syncing with upstream. Fixing merge conflicts, converting to ES6 2022-10-01 11:40:26 -07:00
Chris Troutner f8dce21d95 fix(dex-ui): Updating docker image for rpi 2022-09-27 17:56:12 -07:00
Chris Troutner e8104a8a12 Merge pull request #49 from Permissionless-Software-Foundation/ct-unstable
fix(production): Updating docker container
2022-09-19 19:34:35 -07:00
Chris Troutner 2c43793bf2 fix(production): Updating docker container 2022-09-19 19:28:21 -07:00
Chris Troutner c13a5d1593 Merge pull request #101 from Permissionless-Software-Foundation/ct-unstable
Increased test coverage to 100%
2022-09-17 15:24:26 -07:00
Chris Troutner 6d7b3db370 Using latest version of ipfs-coord-esm 2022-09-17 15:19:37 -07:00
Chris Troutner 33d06e99e8 fix(tests): got ipfs-coord lib to 100% test coverage 2022-09-17 14:51:57 -07:00
Chris Troutner 3203e56a4d fix(tests): Added user e2e tests back in 2022-09-17 14:47:17 -07:00
Chris Troutner ff47f1b356 fix(test): Got use cases to 100% test coverage 2022-09-17 14:23:46 -07:00
Chris Troutner d9377ea78b fix(tests): Increased coverage of REST API validators 2022-09-17 14:18:16 -07:00
Chris Troutner d266bcc54b fix(deps): Updating dependencies 2022-09-17 10:10:39 -07:00
Chris Troutner a033fb1042 fix(tests): Replacing nyc with c8, for test coverage of ESM 2022-09-16 08:38:53 -07:00
Chris Troutner b0eda392a6 Merge pull request #48 from Permissionless-Software-Foundation/ct-unstable
Better error handling for tokens without mutable data
2022-09-14 06:29:01 -07:00
Chris Troutner f81d6853fc Merge branch 'ct-unstable' of https://github.com/Permissionless-Software-Foundation/bch-dex into ct-unstable 2022-09-14 06:26:20 -07:00
Chris Troutner 02a889385d fix(offer): Better error handling for tokens without mutable data 2022-09-14 06:26:12 -07:00
Chris Troutner f17b21bee8 fixing typo 2022-09-13 15:37:57 -07:00
Chris Troutner 78b9e4fcb1 fix(rpi-docker): Updating docker images 2022-09-13 15:34:50 -07:00
Chris Troutner eb1bee1b61 fix(docker): Updating docker images 2022-09-13 15:10:03 -07:00
Chris Troutner 611c2d1631 Merge pull request #47 from Permissionless-Software-Foundation/ct-unstable
feat(nsfw): Detecting tokens marked NSFW in the mutable data
2022-09-13 14:17:12 -07:00
Chris Troutner cb9f5af62e feat(nsfw): Detecting tokens marked NSFW in the mutable data 2022-09-13 13:40:01 -07:00
Chris Troutner 2fca908c97 Merge pull request #46 from Permissionless-Software-Foundation/ct-unstable
feat(NSFW): Adding hook for handling NSFW flags from users
2022-09-13 11:53:03 -07:00
Chris Troutner 3aba1e061b feat(NSFW): Adding hook for handling NSFW flags from users 2022-09-13 11:50:14 -07:00
Chris Troutner c398942c95 temp mod to docker-compose.yml 2022-09-12 13:36:24 -07:00
Chris Troutner c2bffd8c4e Merge pull request #45 from Permissionless-Software-Foundation/ct-unstable
feat(pagination): Adding filtering and pagination
2022-09-12 10:40:32 -07:00
Chris Troutner ac97831721 feat(pagination): Adding filtering and pagination 2022-09-12 10:34:45 -07:00
Chris Troutner 02eab8686c Merge pull request #44 from Permissionless-Software-Foundation/ct-unstable
feat(categorizeToken): New field to Offer model, for UI display
2022-09-11 14:45:15 -07:00
Chris Troutner 1c1169dd93 linting 2022-09-11 14:41:56 -07:00
Chris Troutner 0896adffbb feat(categorizeToken): New field to Offer model, for UI display 2022-09-11 14:36:40 -07:00
Chris Troutner 56e0f7e8df fix(p2wdb): Updating p2wdb to v2.2.3 2022-09-11 11:55:07 -07:00
Chris Troutner 34841f53db Merge pull request #43 from Permissionless-Software-Foundation/ct-unstable
fix(offer): Fixing bugs related to making and taking offers
2022-09-11 10:54:53 -07:00
Chris Troutner c27209cceb fix(offer): Fixing bugs related to making and taking offers 2022-09-11 10:51:32 -07:00
Chris Troutner 5a0fc31c7a Merge pull request #42 from Permissionless-Software-Foundation/ct-unstable
Updating depenencies. Fixing issue with garbage collection.
2022-09-11 09:24:28 -07:00
Chris Troutner 4701f245b9 fix(garbage collection): Fixing issue with garbage collection 2022-09-11 09:21:50 -07:00
Chris Troutner daa06a57ed fix(deps): Updated dependencies and updated tests 2022-09-11 07:39:58 -07:00
Chris Troutner b3157a04ed Merge pull request #41 from Permissionless-Software-Foundation/ct-unstable
Updating docker images
2022-09-11 07:06:35 -07:00
Chris Troutner 3753db46f6 fixing merge conflict 2022-09-11 07:02:27 -07:00
Chris Troutner b924449d02 Updating docker images 2022-09-11 06:57:54 -07:00
Chris Troutner 569dcbd576 Merge pull request #100 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Updating to new version to fix bugs
2022-09-08 09:32:01 -07:00
Chris Troutner b0a2d73540 fix(ipfs-coord): Updating to new version to fix bugs 2022-09-08 09:30:21 -07:00
Chris Troutner 0d4c8cd56e Merge pull request #99 from Permissionless-Software-Foundation/ct-unstable
Breaking change: Converted from CommonJS to ESM
2022-09-08 09:00:19 -07:00
Chris Troutner b37dae60d1 fix(ESM): Converted from CommonJS to ESM 2022-09-08 08:59:03 -07:00
Chris Troutner 448b028bb4 fixed linting issue 2022-09-08 08:58:39 -07:00
Chris Troutner dd8d992b8a Merge pull request #40 from Permissionless-Software-Foundation/ct-unstable
fix(garbage collection): Replacing web2 with web3 calls to validate UTXO
2022-09-04 15:49:43 -07:00
Chris Troutner 4ed657ae28 fix(production): Creating new v1.9.6 docker images for amd64 and arm64 2022-09-04 15:35:50 -07:00
Chris Troutner e14633db79 Updating bch-message-lib 2022-09-04 14:38:11 -07:00
Chris Troutner 6a4e749218 fix(garbage collection): Replacing web2 with web3 calls to validate UTXO 2022-09-04 14:27:51 -07:00
Chris Troutner 7a5036e3aa Merge pull request #39 from Permissionless-Software-Foundation/ct-unstable
fix(production): Created new RPi images
2022-08-28 16:20:45 -07:00
Chris Troutner cca10452c0 fix(production): Created new RPi images 2022-08-28 16:17:33 -07:00
Chris Troutner 309ea0774d Merge pull request #38 from Permissionless-Software-Foundation/ct-unstable
New Docker images
2022-08-28 10:15:13 -07:00
Chris Troutner c2b68a0787 fix(production): Using new docker images 2022-08-28 10:12:36 -07:00
Chris Troutner 2bb4cd7cae fix(production): Updating Dockerfiles 2022-08-28 09:23:47 -07:00
Chris Troutner 9ca581e998 Merge pull request #37 from Permissionless-Software-Foundation/ct-unstable
Syncing with upstream ipfs-service-provider
2022-08-27 15:43:49 -07:00
Chris Troutner 02adbd5634 fixing merge conflicts 2022-08-27 15:40:59 -07:00
Chris Troutner da637df44a Merge pull request #98 from Permissionless-Software-Foundation/ct-unstable
Using bandwidth limited IPFS Docker container
2022-08-27 13:43:51 -07:00
Chris Troutner 9315e6f166 fix(production): Updating docker image 2022-08-27 13:39:06 -07:00
Chris Troutner 7e965e8415 Adding comments 2022-08-27 12:59:20 -07:00
Chris Troutner a5916c95f9 fix(production): Using bandwidth limited IPFS Docker container 2022-08-27 12:58:41 -07:00
Chris Troutner 708f97d107 More dependency updates 2022-08-27 12:55:24 -07:00
Chris Troutner 637738bfb9 Updated npm deps 2022-08-27 12:53:43 -07:00
Chris Troutner d8e82c5ad2 fix(ipfs-coord): Updating to v8.0.5 2022-08-27 12:52:16 -07:00
Chris Troutner b23acd3cdc Merge pull request #97 from Permissionless-Software-Foundation/ct-unstable
fix(production): Switching to Docker Image
2022-07-25 19:17:27 -07:00
Chris Troutner c71fda38ff fix(production): Switching to Docker Image 2022-07-25 19:14:44 -07:00
Chris Troutner f99f49d840 Merge pull request #96 from Permissionless-Software-Foundation/ct-unstable
Configuring ports with env vars
2022-07-25 17:58:40 -07:00
Chris Troutner 2edd924c57 fix(production): Adding 4003 websocket port 2022-07-25 17:56:02 -07:00
Chris Troutner 689c8fd8d9 fix(ipfs): Using config to set ports 2022-07-25 17:40:05 -07:00
Chris Troutner ffd6c452c9 Merge pull request #95 from Permissionless-Software-Foundation/ct-unstable
fix(mocks): Another update to IPFS test mocks
2022-07-24 08:15:55 -07:00
Chris Troutner fc8e160874 fix(mocks): Another update to IPFS test mocks 2022-07-24 08:14:27 -07:00
Chris Troutner d2f83307e6 Merge pull request #94 from Permissionless-Software-Foundation/ct-unstable
fix(mocks): Improvement to adapter mocks used in tests
2022-07-24 08:08:13 -07:00
Chris Troutner 1a09fcd26f fix(mocks): Improvement to adapter mocks used in tests 2022-07-24 08:06:32 -07:00
Chris Troutner db54a067f4 Merge pull request #36 from Permissionless-Software-Foundation/ct-unstable
Updating ipfs-coord & docker images
2022-07-08 16:09:45 -07:00
Chris Troutner 9fcee20498 Switching bch-dex app ID for RPi 2022-07-08 16:07:33 -07:00
Chris Troutner 0a04ee61ef Merge branch 'ct-unstable' of https://github.com/Permissionless-Software-Foundation/bch-dex into ct-unstable 2022-07-08 15:45:18 -07:00
Chris Troutner 7cae06dd65 fix(rpi): Updating containers for RPi 2022-07-08 15:44:30 -07:00
Chris Troutner 96064ac9a7 fix(production): New docker image 2022-07-08 12:48:31 -07:00
Chris Troutner 3690b749fe fix(package.json): Synced with upstream 2022-07-08 09:55:22 -07:00
Chris Troutner e2c5821dbe Merge pull request #93 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Updating bootstrap nodes
2022-07-07 15:56:42 -07:00
Chris Troutner 9967d5145b fix(ipfs-coord): Updating bootstrap nodes 2022-07-07 15:55:33 -07:00
Chris Troutner 9d16291855 Merge pull request #92 from Permissionless-Software-Foundation/ct-unstable
fix(ipfs-coord): Updating to v8
2022-07-07 15:17:09 -07:00
Chris Troutner 1518d1a12b fix(ipfs-coord): Updating to v8 2022-07-07 15:16:03 -07:00
243 changed files with 55828 additions and 30340 deletions
+4
View File
@@ -69,5 +69,9 @@ ipfs-service-provider.sh
run-dev.sh run-dev.sh
wallet.json wallet.json
data/ data/
run-dev.sh
*.zip
!README.md !README.md
wallet.json
+93
View File
@@ -0,0 +1,93 @@
# Permissionless Software Foundation Community Contributing Guide 1.0
This document describes a very simple process suitable for most projects under
the PSF umbrella. It is based on [this Medium article](https://medium.com/the-node-js-collection/healthy-open-source-967fa8be7951) and the [Node.js Community Contribution Guide](https://github.com/nodejs/TSC/blob/master/BasePolicies/CONTRIBUTING.md).
Projects are encouraged to adopt this whether they
are hosted under the PSF or not.
The goal of this document is to create a contribution process that:
* Encourages new contributions.
* Encourages contributors to remain involved.
* Avoids unnecessary processes and bureaucracy whenever possible.
* Creates a transparent decision making process which makes it clear how
contributors can be involved in decision making.
This document is based on much prior art in the Node.js community, io.js,
and the Node.js project.
Additional guidance can be found at the [Permissionless Software Foundation Telegram Channel](https://t.me/permissionless_software).
## Vocabulary
* A **Contributor** is any individual creating or commenting on an issue or pull request.
* A **Committer** is a subset of contributors who have been given write access to the repository.
* A **TC (Technical Committee)** is a group of committers representing the required technical
expertise to resolve rare disputes.
# Logging Issues
Log an issue for any question or problem you might have. When in doubt, log an issue,
any additional policies about what to include will be provided in the responses. The only
exception is security disclosures which should be sent privately.
Committers may direct you to another repository, ask for additional clarifications, and
add appropriate metadata before the issue is addressed.
Please be courteous, respectful, and every participant is expected to follow the
project's Code of Conduct.
# Contributions
Any change to resources in this repository must be through pull requests. This applies to all changes
to documentation, code, binary files, etc. Even long term committers and TC members must use
pull requests.
No pull request can be merged without being reviewed.
For non-trivial contributions, pull requests should sit for at least 36 hours to ensure that
contributors in other timezones have time to review. Consideration should also be given to
weekends and other holiday periods to ensure active committers all have reasonable time to
become involved in the discussion and review process if they wish.
The default for each contribution is that it is accepted once no committer has an objection.
During review committers may also request that a specific contributor who is most versed in a
particular area gives a "LGTM" before the PR can be merged. There is no additional "sign off"
process for contributions to land. Once all issues brought by committers are addressed it can
be landed by any committer.
In the case of an objection being raised in a pull request by another committer, all involved
committers should seek to arrive at a consensus by way of addressing concerns being expressed
by discussion, compromise on the proposed change, or withdrawal of the proposed change.
If a contribution is controversial and committers cannot agree about how to get it to land
or if it should land then it should be escalated to the TC. TC members should regularly
discuss pending contributions in order to find a resolution. It is expected that only a
small minority of issues be brought to the TC for resolution and that discussion and
compromise among committers be the default resolution mechanism.
# Becoming a Committer
All contributors who land a non-trivial contribution should be on-boarded in a timely manner,
and added as a committer, and be given write access to the repository.
Committers are expected to follow this policy and continue to send pull requests, go through
proper review, and have other committers merge their pull requests.
# TC Process
The TC uses a "consensus seeking" process for issues that are escalated to the TC.
The group tries to find a resolution that has no open objections among TC members.
If a consensus cannot be reached that has no objections then a majority wins vote
is called. It is also expected that the majority of decisions made by the TC are via
a consensus seeking process and that voting is only used as a last-resort.
Resolution may involve returning the issue to committers with suggestions on how to
move forward towards a consensus. It is not expected that a meeting of the TC
will resolve all issues on its agenda during that meeting and may prefer to continue
the discussion happening among the committers.
Members can be added to the TC at any time. Any committer can nominate another committer
to the TC and the TC uses its standard consensus seeking process to evaluate whether or
not to add this new member. Members who do not participate consistently at the level of
a majority of the other members are expected to resign.
+1 -1
View File
@@ -1,5 +1,5 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2022 Permissionless Software Foundation Copyright (c) 2021-2024 Permissionless Software Foundation
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+3
View File
@@ -0,0 +1,3 @@
# Pedigree
This repository was forked from [koa-api-boilerplate](https://github.com/christroutner/koa-api-boilerplate). Code changes from that upstream repository is frequently pulled in and merged to this repository.
+27 -41
View File
@@ -1,14 +1,14 @@
# bch-dex # bch-dex
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com) [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) [![Join the chat at https://gitter.im/Permissionless-Software-Foundation/psf-dex-dev](https://badges.gitter.im/Permissionless-Software-Foundation/psf-dex-dev.svg)](https://gitter.im/Permissionless-Software-Foundation/psf-dex-dev?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com) [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)
`bch-dex` is a decentralized exchange for permissionless trading of [SLP tokens](https://github.com/simpleledger/slp-specifications/blob/master/slp-token-type-1.md) and [NFTs](https://github.com/simpleledger/slp-specifications/blob/master/slp-nft-1.md). Trading fees are incredibly small, compared to other DEX platforms. The software is based entirely on open protocols and open source software. It's not a '.com' website that you visit, but software you run on your own computer, in the confort of your own home. So long as you have an internet connection and the technical knowledge to run this software, no one can stop you from trading tokens. `bch-dex` software is maintained by the [Permissionless Software Foundation](https://psfoundation.cash/). `bch-dex` is a decentralized exchange *protocol* for permissionless trading of [SLP tokens](https://github.com/simpleledger/slp-specifications/blob/master/slp-token-type-1.md) and [NFTs](https://github.com/simpleledger/slp-specifications/blob/master/slp-nft-1.md). Trading fees are incredibly small, compared to other DEX platforms. The software is based entirely on open protocols and open source software. `bch-dex` software is maintained by the [Permissionless Software Foundation](https://psfoundation.info).
- [High-level Overview of bch-dex](https://youtu.be/LVX8CLi4sHw) (Video) - [High-level Overview of bch-dex](https://youtu.be/LVX8CLi4sHw) (Video)
This is a prototype web service that monitors the [P2WDB](https://github.com/Permissionless-Software-Foundation/ipfs-p2wdb-service) for trading signals, to trade BCH and SLP tokens. It's inspired by the [SWaP Protocol](https://github.com/vinarmani/swap-protocol/blob/master/swap-protocol-spec.md). This is a prototype web service that monitors one or more [Nostr relays](https://nostr.com) for trading signals, to trade BCH and SLP tokens. It's inspired by the [SWaP Protocol](https://github.com/vinarmani/swap-protocol/blob/master/swap-protocol-spec.md).
This repository contains the back end code. The user interface is contained in the [bch-dex-ui](https://github.com/Permissionless-Software-Foundation/bch-dex-ui) repository. This repository contains the back end code. The user interface is contained in the [bch-dex-ui-v3](https://github.com/Permissionless-Software-Foundation/bch-dex-ui-v3) repository.
**Warning**: This repository is under active development. Things will be constantly changing and breaking. **Warning**: This repository is under active development. Things will be constantly changing and breaking.
@@ -19,57 +19,43 @@ This repository contains the back end code. The user interface is contained in t
## Participate ## Participate
This is an open source project, and we encourage other JavaScript developers to participate in its creation and maintenance. We have two chat rooms for the community: This is an open source project, and we encourage other JavaScript developers to participate in its creation and maintenance. We have two chat rooms for the community:
- [Telegram Channel](https://t.me/psf_dex_dev) - [Telegram Channel](https://t.me/bch_js_toolkit)
- [Gitter Channel](https://gitter.im/Permissionless-Software-Foundation/psf-dex-dev)
## Installation ## Installation
Running the DEX requires composition of these different software packages: Running the DEX requires composition of these different software packages:
- bch-dex - This repository is the back end software that tracks trade data on the network, generates [Offers and Counter Offers](https://github.com/Permissionless-Software-Foundation/bch-dex/tree/ct-unstable/dev-docs#definitions), and finalizes trades by accepting Counter Offers. - bch-dex - This repository is the back end software that tracks trade data on the network, generates [Offers and Counter Offers](https://github.com/Permissionless-Software-Foundation/bch-dex/tree/ct-unstable/dev-docs#definitions), and finalizes trades by accepting Counter Offers.
- [bch-dex-ui](https://github.com/Permissionless-Software-Foundation/bch-dex-ui) is a [Gatsby](https://www.gatsbyjs.com/) web app and user interface (UI) for bch-dex. - [bch-dex-ui-v3](https://github.com/Permissionless-Software-Foundation/bch-dex-ui-v3) web app and user interface (UI) for bch-dex focused on Sellers of tokens.
- [P2WDB](https://github.com/Permissionless-Software-Foundation/ipfs-p2wdb-service) is a censorship-resistant database used to communicate trade data between peers running bch-dex. - [MongoDB](https://www.mongodb.com/) is a database used by bch-dex to store and manage local data, user accounts, etc.
- [IPFS](https://ipfs.io/) is a censorship-resistant network for communicating data over the internet.
- [MongoDB](https://www.mongodb.com/) is a database used by both P2WDB and bch-dex to store and manage local data.
The above software is orchestrated using [Docker](https://www.docker.com/) and Docker Compose. The target operating system is Ubuntu 20+, and the target hardware is amd64 (normal desktop PCs) and the arm64 (Raspberry Pi 4). Trying to operate this software on other operating systems or hardware is possible, but not supported. The above software is orchestrated using [Docker](https://www.docker.com/) and Docker Compose. The target operating system is Ubuntu 20+, and the target hardware is amd64 (normal desktop PCs). Trying to operate this software on other operating systems or hardware is possible, but not supported.
The Raspberry Pi 4 is the primary hardware target, because this software functions best when it is always running. The Pi 4 makes a great appliance for monitoring trade signals and finalizing trades. Setup instructions:
Instructions for setting up Node.js, Docker, and Docker Compose can be found in [this Gist](https://gist.github.com/christroutner/a39f656850dc022b60f25c9663dd1cdd). Walk-through videos can also be found on the [PSF Videos page](https://psfoundation.cash/video/). - Follow the direction in [this Gist](https://gist.github.com/christroutner/a39f656850dc022b60f25c9663dd1cdd) to install Node.js, Docker, and Docker Compose.
- Clone the repository with `git clone https://github.com/Permissionless-Software-Foundation/bch-dex` and enter it with `cd bch-dex`.
Here are the steps involved in setting up bch-dex: - Install dependencies by running `npm install`
- Create a wallet:
1. Follow the direction in [this Gist](https://gist.github.com/christroutner/a39f656850dc022b60f25c9663dd1cdd) to install Node.js, Docker, and Docker Compose.
1. Clone the repository with `git clone https://github.com/Permissionless-Software-Foundation/bch-dex` and enter it with `cd bch-dex`.
1. Install dependencies by running `npm install`
1. Create a wallet:
- `cd production/scripts` - `cd production/scripts`
- `node create-wallet.js` - `node create-wallet.js`
1. Change directory to the `production/docker` or `production/rpi-docker` folder depending on your hardware target. - Change directory to the `production/docker` folder.
1. Pull the Docker images down from Docker Hub: `docker-compose pull` - Pull the Docker images down from Docker Hub: `docker-compose pull`
1. Start the Docker containers with `docker-compose up -d` - Build the back end: `docker-compose build --no-cache bch-dex`
1. Wait for the P2WDB to sync and populate bch-dex with trade data. You can monitor it with `docker logs --tail 20 -f p2wdb`. - Build the front end: `docker-compose build --no-cache dex-ui`
1. Open a web browser and navigate the `http://localhost:4500`. You'll be able to see new Offers as they come in and are detected by bch-dex. - Start the Docker containers with `docker-compose up -d`
1. To take the other side of the trade, click the `Take` button in the UI. - It will take about 10 minutes for the bch-dex to sync with the network and display tokens for sale.
1. You can add the 12-word mnemonic from the `wallet.json` file to the the web wallet, which will mirror your wallet in the UI, and allow you to perform basic wallet functions (send and receive BCH and tokens). - Open a web browser and navigate to `http://localhost:4500`.
- You will be presented with a login screen. Click the sign-up tab, enter an email and password to create an account. This information is stored locally on bch-dex, it is not set to a third party.
- Once logged in, you can retrieve your BCH and SLP addresses, to fund your wallet.
## Blockchain Infrastructure ## Blockchain Infrastructure
The P2WDB and bch-dex containers requires a 'Global Back End' (as described in [CashStack.info](https://cashstack.info)) in order to connect to the blockchain. By default, the Docker containers connect to [free-bch.fullstack.cash](https://free-bch.fullstack.cash/). Several community-provided Global Back End servers are provided and can be [viewed here](https://gist.github.com/christroutner/63c5513782181f8b8ea3eb89f7cadeb6). The back end can be changed by setting the `CONSUMER_URL` environment variable in the `docker-compose.yml` file. bch-dex requires a [Cash Stack](https://cashstack.info) back end in order to connect to the blockchain. By default, the Docker containers connect to [free-bch.fullstack.cash](https://free-bch.fullstack.cash/). Several community-provided servers are provided and can be [viewed here](https://consumers.psfoundation.info/consumers.json). The back end can be changed by setting the `CONSUMER_URL` environment variable in the `docker-compose.yml` file.
### Applying Software Updates ## Environment Variables
As this is an active project, software updates will happen frequently. To apply a software update, perform these steps.
- `DISABLE_NEW_ACCOUNTS` - If set, only the admin user can create new accounts. The sign-up tab becomes non-functional. Useful for controlling access to your instance of bch-dex.
1. Enter the `docker` or `rpi-docker` folder, depending on your hardware target. - `ADMIN_PASSWORD` - Sets the password for the admin user. This can be used with the [createUser.js script](/util/users/production/createUser.js) to add new users to the system, if the `DISABLE_NEW_ACCOUNTS` env var is set.
1. Bring down the Docker containers with `docker-compose down`.
1. Pull in the software updates with `git pull`
1. Update dependencies with `npm install`
1. Pull new Docker images with `docker-compose pull`
1. Clean up disk space by deleting old Docker images with `./cleanup-images.sh`
1. Start the Docker containers with `docker-compose up -d`
Sometimes it may be necessary to delete the databases before applying a software update. This can be done by stopping the Docker containers and deleting the `production/data` directory. When the Docker containers are restarted, they will recreate that directory. The P2WDB will re-sync and bch-dex will be populated with fresh trade data.
## License ## License
+42 -38
View File
@@ -8,31 +8,27 @@
*/ */
// npm libraries // npm libraries
const Koa = require('koa') import Koa from 'koa'
const bodyParser = require('koa-bodyparser')
const convert = require('koa-convert') import bodyParser from 'koa-bodyparser'
const logger = require('koa-logger') import convert from 'koa-convert'
const mongoose = require('mongoose') import logger from 'koa-logger'
const session = require('koa-generic-session') import mongoose from 'mongoose'
const passport = require('koa-passport') import session from 'koa-generic-session'
const mount = require('koa-mount') import passport from 'koa-passport'
const serve = require('koa-static') import mount from 'koa-mount'
const cors = require('kcors') import serve from 'koa-static'
import cors from 'kcors'
// Local libraries // Local libraries
const config = require('../config') // this first. import config from '../config/index.js' // this first.
const AdminLib = require('../src/adapters/admin')
// const adminLib = new AdminLib()
// const WebHookLib = require('../src/adapters/webhook') import AdminLib from '../src/adapters/admin.js'
// const webhookLib = new WebHookLib() import errorMiddleware from '../src/controllers/rest-api/middleware/error.js'
import { usageMiddleware } from '../src/use-cases/usage-use-cases.js'
// const JSONRPC = require('../src/rpc') // import wlogger from '../src/adapters/wlogger.js'
// const rpc = new JSONRPC() import Controllers from '../src/controllers/index.js'
import { applyPassportMods } from '../config/passport.js'
const errorMiddleware = require('../src/controllers/rest-api/middleware/error')
// const { wlogger } = require('../src/adapters/wlogger')
const Controllers = require('../src/controllers')
class Server { class Server {
constructor () { constructor () {
@@ -50,16 +46,18 @@ class Server {
const app = new Koa() const app = new Koa()
app.keys = [this.config.session] app.keys = [this.config.session]
// Connect to the Mongo Database. if (!this.config.noMongo) {
this.mongoose.Promise = global.Promise // Connect to the Mongo Database.
this.mongoose.set('useCreateIndex', true) // Stop deprecation warning. this.mongoose.Promise = global.Promise
console.log( this.mongoose.set('useCreateIndex', true) // Stop deprecation warning.
`Connecting to MongoDB with this connection string: ${this.config.database}` console.log(
) `Connecting to MongoDB with this connection string: ${this.config.database}`
await this.mongoose.connect(this.config.database, { )
useUnifiedTopology: true, await this.mongoose.connect(this.config.database, {
useNewUrlParser: true useUnifiedTopology: true,
}) useNewUrlParser: true
})
}
console.log(`Starting environment: ${this.config.env}`) console.log(`Starting environment: ${this.config.env}`)
console.log(`Debug level: ${this.config.debugLevel}\n`) console.log(`Debug level: ${this.config.debugLevel}\n`)
@@ -73,6 +71,7 @@ class Server {
app.use(bodyParser()) app.use(bodyParser())
app.use(session()) app.use(session())
app.use(errorMiddleware()) app.use(errorMiddleware())
app.use(usageMiddleware())
// Used to generate the docs. // Used to generate the docs.
app.use(mount('/', serve(`${process.cwd()}/docs`))) app.use(mount('/', serve(`${process.cwd()}/docs`)))
@@ -81,7 +80,8 @@ class Server {
app.use(mount('/logs', serve(`${process.cwd()}/config/logs`))) app.use(mount('/logs', serve(`${process.cwd()}/config/logs`)))
// User Authentication // User Authentication
require('../config/passport') // require('../config/passport')
applyPassportMods(passport)
app.use(passport.initialize()) app.use(passport.initialize())
app.use(passport.session()) app.use(passport.session())
@@ -128,9 +128,11 @@ class Server {
this.server = await app.listen(config.port) this.server = await app.listen(config.port)
console.log(`Server started on ${config.port}`) console.log(`Server started on ${config.port}`)
// Create the system admin user. if (!this.config.noMongo) {
const success = await this.adminLib.createSystemUser() // Create the system admin user.
if (success) console.log('System admin user created.') const success = await this.adminLib.createSystemUser()
if (success) console.log('System admin user created.')
}
// Attach the other IPFS controllers. // Attach the other IPFS controllers.
// Skip if this is a test environment. // Skip if this is a test environment.
@@ -142,7 +144,9 @@ class Server {
console.log('\nConfiguration:') console.log('\nConfiguration:')
console.log(`Circuit Relay: ${this.config.isCircuitRelay}`) console.log(`Circuit Relay: ${this.config.isCircuitRelay}`)
console.log(`IPFS TCP port: ${this.config.ipfsTcpPort}`) console.log(`IPFS TCP port: ${this.config.ipfsTcpPort}`)
console.log(`IPFS WS port: ${this.config.ipfsWsPort}\n`) console.log(`IPFS WS port: ${this.config.ipfsWsPort}`)
console.log(`IPFS WebRTC port: ${this.config.ipfsWebRtcPort}`)
console.log(`Connection preference: ${this.config.connectPref}\n`)
return app return app
} catch (err) { } catch (err) {
@@ -161,4 +165,4 @@ class Server {
} }
} }
module.exports = Server export default Server
+103 -14
View File
@@ -1,19 +1,31 @@
/* /*
This file is used to store unsecure, application-specific data common to all This file is used to store unsecure, application-specific data common to all
environments. environments.
Additional Environent Variables:
- CONNECT_PREF: should have a value of 'cr' (default), or 'direct'. This is
used by helia-coord to select a connection preference between peers. Servers
with an ip4 or ip6 address should use 'direct'.
*/ */
/* eslint no-unneeded-ternary:0 */ /* eslint no-unneeded-ternary:0 */
// Hack to get __dirname back.
// https://blog.logrocket.com/alternatives-dirname-node-js-es-modules/
import * as url from 'url'
// Get the version from the package.json file. // Get the version from the package.json file.
const pkgInfo = require('../../package.json') import { readFileSync } from 'fs'
const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
const pkgInfo = JSON.parse(readFileSync(`${__dirname.toString()}/../../package.json`))
const version = pkgInfo.version const version = pkgInfo.version
const ipfsCoordName = process.env.COORD_NAME const ipfsCoordName = process.env.COORD_NAME
? process.env.COORD_NAME ? process.env.COORD_NAME
: 'ipfs-torlist-service-generic' : 'ipfs-torlist-service-generic'
module.exports = { export default {
// Configure TCP port. // Configure TCP port.
port: process.env.PORT || 5700, port: process.env.PORT || 5700,
@@ -36,27 +48,75 @@ module.exports = {
consumerUrl: process.env.CONSUMER_URL consumerUrl: process.env.CONSUMER_URL
? process.env.CONSUMER_URL ? process.env.CONSUMER_URL
: 'https://free-bch.fullstack.cash', : 'https://free-bch.fullstack.cash',
// : 'https://dev-consumer.psfoundation.info',
// : 'https://wa-usa-bch-consumer.fullstackcash.nl', // : 'https://wa-usa-bch-consumer.fullstackcash.nl',
// P2WDB URL that will accept API calls from the p2wdb npm library. // P2WDB URL that will accept API calls from the p2wdb npm library.
p2wdbUrl: process.env.P2WDB_URL ? process.env.P2WDB_URL : 'https://p2wdb.fullstack.cash', p2wdbUrl: process.env.P2WDB_URL ? process.env.P2WDB_URL : 'https://p2wdb.fullstack.cash',
// p2wdbUrl: process.env.P2WDB_URL ? process.env.P2WDB_URL : 'http://localhost:5010',
// Enable or Disable the usage of Mongo DB.
noMongo: process.env.NO_MONGO ? true : false,
// BEGIN WALLET CONFIGURATION
// BCH Mnemonic for generating encryption keys and payment address
mnemonic: process.env.MNEMONIC ? process.env.MNEMONIC : '',
// (Optional) use a wallet file generated by psf-bch-wallet.
walletFile: process.env.WALLET_FILE
? process.env.WALLET_FILE
: `${__dirname.toString()}/../../wallet.json`,
// Wallet Configuration
// Default value: web3 - connect to bch-api through web 3 JSON RPC over IPFS.
// Alternate value: web2 - connect to bch-api through a web 2 REST API over HTTP.
walletInterface: process.env.WALLET_INTERFACE ? process.env.WALLET_INTERFACE : 'web3',
// Wallet API Server
// Default web2 server: https://api.fullstack.cash/v5/
// Default web3 server: https://free-bch.fullstack.cash/
apiServer: process.env.WALLET_INTERFACE === 'web2'
? (
process.env.APISERVER
? process.env.APISERVER
: 'https://api.fullstack.cash/v5/'
)
: 'https://free-bch.fullstack.cash/',
// Basic Authentication Password for connecting to bch-api through a web 2
// REST API over HTTP.
authPass: process.env.WALLET_AUTH_PASS
? process.env.WALLET_AUTH_PASS
: '',
// FullStack.cash account information, used for automatic JWT handling. // FullStack.cash account information, used for automatic JWT handling.
getJwtAtStartup: process.env.GET_JWT_AT_STARTUP ? true : false, getJwtAtStartup: process.env.GET_JWT_AT_STARTUP ? true : false,
authServer: process.env.AUTHSERVER authServer: process.env.AUTHSERVER
? process.env.AUTHSERVER ? process.env.AUTHSERVER
: 'https://auth.fullstack.cash', : 'https://auth.fullstack.cash',
apiServer: process.env.APISERVER
? process.env.APISERVER
: 'https://api.fullstack.cash/v5/',
fullstackLogin: process.env.FULLSTACKLOGIN fullstackLogin: process.env.FULLSTACKLOGIN
? process.env.FULLSTACKLOGIN ? process.env.FULLSTACKLOGIN
: 'demo@demo.com', : 'demo@demo.com',
fullstackPassword: process.env.FULLSTACKPASS fullstackPassword: process.env.FULLSTACKPASS
? process.env.FULLSTACKPASS ? process.env.FULLSTACKPASS
: 'demo', : 'demo',
// authPass: process.env.FULLSTACK_AUTH_PASS
// ? process.env.FULLSTACK_AUTH_PASS
// : '',
// END WALLET CONFIGURATION
// BEGIN IPFS CONFIGURATION
// Debug verbosity level of helia-coord.
// 0 = no debug logs. 3 = maximum logs.
debugLevel: process.env.DEBUG_LEVEL ? parseInt(process.env.DEBUG_LEVEL) : 2,
// Enable/Disable the IPFS node at startup. Enabled by default.
// useIpfs: process.env.DISABLE_IPFS ? false : true,
useIpfs: false,
// IPFS settings.
isCircuitRelay: process.env.ENABLE_CIRCUIT_RELAY ? true : false, isCircuitRelay: process.env.ENABLE_CIRCUIT_RELAY ? true : false,
// SSL domain used for websocket connection via browsers. // SSL domain used for websocket connection via browsers.
crDomain: process.env.CR_DOMAIN ? process.env.CR_DOMAIN : '', crDomain: process.env.CR_DOMAIN ? process.env.CR_DOMAIN : '',
@@ -77,7 +137,10 @@ module.exports = {
'@type': 'Organization', '@type': 'Organization',
name: 'Permissionless Software Foundation', name: 'Permissionless Software Foundation',
url: 'https://PSFoundation.cash' url: 'https://PSFoundation.cash'
} },
// If this node has an IP4 address or domain name used to provide a REST API.
web2Api: process.env.WEB2_API ? process.env.WEB2_API : null
}, },
// P2WDB webhook endpoint // P2WDB webhook endpoint
@@ -93,18 +156,44 @@ module.exports = {
// IPFS Ports // IPFS Ports
ipfsTcpPort: process.env.IPFS_TCP_PORT ? process.env.IPFS_TCP_PORT : 4001, ipfsTcpPort: process.env.IPFS_TCP_PORT ? process.env.IPFS_TCP_PORT : 4001,
ipfsWsPort: process.env.IPFS_WS_PORT ? process.env.IPFS_WS_PORT : 4003, ipfsWsPort: process.env.IPFS_WS_PORT ? process.env.IPFS_WS_PORT : 4003,
ipfsWebRtcPort: process.env.IPFS_WEB_RTC_PORT ? process.env.IPFS_WEB_RTC_PORT : 4005,
// BCH Mnemonic for generating encryption keys and payment address connectPref: process.env.CONNECT_PREF, // Used in helia-coord to select connection preference.
mnemonic: process.env.MNEMONIC ? process.env.MNEMONIC : '',
debugLevel: process.env.DEBUG_LEVEL ? parseInt(process.env.DEBUG_LEVEL) : 1,
// Settings for production, using external go-ipfs node. // Settings for production, using external go-ipfs node.
isProduction: process.env.SVC_ENV === 'production' ? true : false, isProduction: process.env.SVC_ENV === 'prod' ? true : false,
ipfsHost: process.env.IPFS_HOST ? process.env.IPFS_HOST : 'localhost', ipfsHost: process.env.IPFS_HOST ? process.env.IPFS_HOST : 'localhost',
ipfsApiPort: process.env.IPFS_API_PORT ipfsApiPort: process.env.IPFS_API_PORT
? parseInt(process.env.IPFS_API_PORT) ? parseInt(process.env.IPFS_API_PORT)
: 5001, : 5001,
chatPubSubChan: 'psf-ipfs-chat-001' chatPubSubChan: 'psf-ipfs-chat-001',
// IPFS gateway
ipfsGateway: process.env.IPFS_GATEWAY ? process.env.IPFS_GATEWAY : 'https://pin.fullstack.cash/ipfs/download/',
// This can add specific Circuit Relay v2 servers to connect to.
bootstrapRelays: [
// v2 Circuit Relay (Token Tiger)
// '/ip4/137.184.93.145/tcp/8001/p2p/12D3KooWGMEKkdJfyZbwdH9EafZbRTtMn7FnhWPrE4MhRty2763g',
// v2 Circuit Relay server (FullStack.cash)
// '/ip4/78.46.129.7/tcp/4001/p2p/12D3KooWFQ11GQ5NubsJGhYZ4X3wrAGimLevxfm6HPExCrMYhpSL'
],
// END IPFS CONFIGURATION
// Nostr
nostrRelay: process.env.NOSTR_RELAY ? process.env.NOSTR_RELAY : 'wss://nostr-relay.psfoundation.info',
nostrTopic: process.env.NOSTR_TOPIC ? process.env.NOSTR_TOPIC : 'bch-dex-test-topic-02',
nostrGlobalFeed: process.env.NOSTR_GLOBAL_FEED ? process.env.NOSTR_GLOBAL_FEED : 'slpdex-socialmedia',
// Account Configuration
disableNewAccounts: process.env.DISABLE_NEW_ACCOUNTS ? true : false,
// Admin password
adminPassword: process.env.ADMIN_PASSWORD,
// The Operator of BCH DEX can elect to receive a percentage of each sale.
operatorAddress: process.env.OPERATOR_ADDRESS ? process.env.OPERATOR_ADDRESS : 'bitcoincash:qqsrke9lh257tqen99dkyy2emh4uty0vky9y0z0lsr',
operatorPercentage: process.env.OPERATOR_PERCENTAGE ? parseFloat(process.env.OPERATOR_PERCENTAGE) : 2.0
} }
+1 -1
View File
@@ -4,7 +4,7 @@
specified. specified.
*/ */
module.exports = { export default {
session: 'secret-boilerplate-token', session: 'secret-boilerplate-token',
token: 'secret-jwt-token', token: 'secret-jwt-token',
database: 'mongodb://localhost:27017/bch-swap-service-dev', database: 'mongodb://localhost:27017/bch-swap-service-dev',
+1 -1
View File
@@ -7,7 +7,7 @@
so as not to conflict with the default host port of 27017 for MongoDB. so as not to conflict with the default host port of 27017 for MongoDB.
*/ */
module.exports = { export default {
session: 'secret-boilerplate-token', session: 'secret-boilerplate-token',
token: 'secret-jwt-token', token: 'secret-jwt-token',
// database: 'mongodb://172.17.0.1:5555/ipfs-service-prod', // database: 'mongodb://172.17.0.1:5555/ipfs-service-prod',
+3 -2
View File
@@ -4,9 +4,10 @@
This is the environment run by the test suite. This is the environment run by the test suite.
*/ */
module.exports = { export default {
session: 'secret-boilerplate-token', session: 'secret-boilerplate-token',
token: 'secret-jwt-token', token: 'secret-jwt-token',
database: 'mongodb://localhost:27017/bch-swap-service-test', database: 'mongodb://localhost:27017/bch-swap-service-test',
env: 'test' env: 'test',
nostrRelay: 'wss://'
} }
+14 -3
View File
@@ -1,6 +1,17 @@
const common = require('./env/common') import common from './env/common.js'
import development from './env/development.js'
import production from './env/production.js'
import test from './env/test.js'
const env = process.env.BCH_DEX || 'development' const env = process.env.BCH_DEX || 'development'
const config = require(`./env/${env}`) console.log(`Loading config for this environment: ${env}`)
module.exports = Object.assign({}, common, config) let config = development
if (env === 'test') {
config = test
} else if (env === 'prod') {
config = production
}
export default Object.assign({}, common, config)
+32 -29
View File
@@ -1,30 +1,6 @@
const passport = require('koa-passport') // import passport from 'koa-passport';
const User = require('../src/adapters/localdb/models/users') import User from '../src/adapters/localdb/models/users.js'
const Strategy = require('passport-local') import Strategy from 'passport-local'
passport.serializeUser((user, done) => {
done(null, user.id)
})
passport.deserializeUser(async (id, done) => {
try {
const user = await User.findById(id, '-password')
done(null, user)
} catch (err) {
done(err)
}
})
passport.use(
'local',
new Strategy(
{
usernameField: 'email',
passwordField: 'password'
},
passportCallback
)
)
async function passportCallback (email, password, done) { async function passportCallback (email, password, done) {
try { try {
@@ -49,5 +25,32 @@ async function passportCallback (email, password, done) {
} }
} }
// For testing function applyPassportMods (passport) {
module.exports = { passport, passportCallback } passport.serializeUser((user, done) => {
done(null, user.id)
})
passport.deserializeUser(async (id, done) => {
try {
const user = await User.findById(id, '-password')
done(null, user)
} catch (err) {
done(err)
}
})
passport.use(
'local',
new Strategy(
{
usernameField: 'email',
passwordField: 'password'
},
passportCallback
)
)
return true
}
export { applyPassportMods, passportCallback }
Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

+5 -1
View File
@@ -1,4 +1,8 @@
const Server = require('./bin/server.js') import Server from './bin/server.js'
const server = new Server() const server = new Server()
process.on('unhandledRejection', (reason, promise) => {
console.log(`Handling ${reason.code} error. stack: `, reason)
})
server.startServer() server.startServer()
+26701
View File
File diff suppressed because it is too large Load Diff
+13673 -27486
View File
File diff suppressed because it is too large Load Diff
+43 -27
View File
@@ -1,20 +1,22 @@
{ {
"name": "bch-dex", "name": "bch-dex",
"version": "1.0.0", "version": "3.0.0",
"description": "A DEX on BCH for trading SLP tokens.", "description": "A DEX on BCH for trading SLP tokens.",
"main": "index.js", "main": "index.js",
"type": "module",
"scripts": { "scripts": {
"start": "node index.js", "start": "node index.js",
"test": "npm run test:all", "test": "npm run test:unit",
"test:all": "export BCH_DEX=test && nyc --reporter=text mocha --exit --timeout 30000 --recursive test/unit test/e2e/automated/", "test:all": "export BCH_DEX=test && c8 --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:unit": "export BCH_DEX=test && c8 --reporter=text mocha --exit --timeout 15000 --recursive test/unit/",
"test:e2e:auto": "export BCH_DEX=test && mocha --exit --timeout 30000 test/e2e/automated/", "test:e2e:auto": "export BCH_DEX=test && mocha --exit --timeout 30000 test/e2e/automated/",
"start:e2e:server": "export BCH_DEX=test && node index.js",
"test:integration": "export BCH_DEX=test && mocha --exit --timeout 45000 --recursive test/integration", "test:integration": "export BCH_DEX=test && mocha --exit --timeout 45000 --recursive test/integration",
"test:temp": "export BCH_DEX=test && mocha --exit --timeout 15000 -g '#rate-limit' test/unit/json-rpc/", "test:temp": "export BCH_DEX=test && mocha --exit --timeout 15000 -g '#rate-limit' test/unit/json-rpc/",
"lint": "standard --env mocha --fix", "lint": "standard --env mocha --fix",
"docs": "./node_modules/.bin/apidoc -i src/ -o docs", "docs": "./node_modules/.bin/apidoc -i src/ -o docs",
"coverage": "nyc report --reporter=text-lcov | coveralls", "coverage": "c8 report --reporter=text-lcov | coveralls",
"coverage:report": "export BCH_DEX=test && nyc --reporter=html mocha --exit --timeout 15000 --recursive test/unit/ test/e2e/automated/" "coverage:report": "export BCH_DEX=test && c8 --reporter=html mocha --exit --timeout 15000 --recursive test/unit/ test/e2e/automated/"
}, },
"author": "Chris Troutner <chris.troutner@gmail.com>", "author": "Chris Troutner <chris.troutner@gmail.com>",
"contributors": [ "contributors": [
@@ -27,15 +29,35 @@
}, },
"repository": "Permissionless-Software-Foundation/bch-dex", "repository": "Permissionless-Software-Foundation/bch-dex",
"dependencies": { "dependencies": {
"@psf/bch-js": "6.4.1", "@chainsafe/libp2p-gossipsub": "14.1.0",
"@chainsafe/libp2p-noise": "16.0.1",
"@chainsafe/libp2p-yamux": "7.0.1",
"@chris.troutner/retry-queue": "1.0.8",
"@helia/unixfs": "4.0.2",
"@libp2p/bootstrap": "11.0.26",
"@libp2p/circuit-relay-v2": "3.2.2",
"@libp2p/config": "1.1.0",
"@libp2p/identify": "3.0.22",
"@libp2p/keychain": "5.0.14",
"@libp2p/logger": "5.1.8",
"@libp2p/ping": "2.0.22",
"@libp2p/tcp": "10.1.2",
"@libp2p/webrtc": "5.2.2",
"@libp2p/websockets": "9.2.2",
"@multiformats/multiaddr": "12.3.5",
"axios": "0.27.2", "axios": "0.27.2",
"bch-message-lib": "2.2.0", "bch-message-lib": "2.2.1",
"bch-nostr": "1.3.3",
"bch-token-sweep": "2.2.1",
"bcryptjs": "2.4.3", "bcryptjs": "2.4.3",
"bitcoincashjs-lib": "3.3.3", "bitcoincashjs-lib": "3.3.3",
"blockstore-fs": "2.0.2",
"datastore-fs": "10.0.2",
"glob": "7.1.6", "glob": "7.1.6",
"ipfs": "0.62.3", "helia": "5.2.1",
"ipfs-coord": "7.1.19", "helia-coord": "1.7.2",
"ipfs-http-client": "55.0.0", "ipfs-coord-esm": "9.1.7",
"ipfs-http-client": "58.0.0",
"jsonrpc-lite": "2.2.0", "jsonrpc-lite": "2.2.0",
"jsonwebtoken": "8.5.1", "jsonwebtoken": "8.5.1",
"jwt-bch-lib": "1.3.0", "jwt-bch-lib": "1.3.0",
@@ -50,36 +72,30 @@
"koa-router": "10.0.0", "koa-router": "10.0.0",
"koa-static": "5.0.0", "koa-static": "5.0.0",
"koa2-ratelimit": "0.9.1", "koa2-ratelimit": "0.9.1",
"libp2p": "^0.36.2", "libp2p": "2.7.2",
"line-reader": "0.4.0", "line-reader": "0.4.0",
"minimal-slp-wallet": "4.6.5", "minimal-slp-wallet": "5.13.2",
"mongoose": "5.13.13", "mongoose": "5.13.14",
"node-fetch": "npm:@achingbrain/node-fetch@2.6.7", "node-fetch": "npm:@achingbrain/node-fetch@2.6.7",
"nodemailer": "6.7.5", "nodemailer": "6.7.5",
"p2wdb": "1.4.0", "nostr-tools": "2.10.4",
"p2wdb-esm": "2.2.9",
"passport-local": "1.0.0", "passport-local": "1.0.0",
"public-ip": "^4.0.4", "public-ip": "6.0.1",
"winston": "3.3.3", "winston": "3.3.3",
"winston-daily-rotate-file": "4.5.0" "winston-daily-rotate-file": "4.5.0"
}, },
"devDependencies": { "devDependencies": {
"apidoc": "0.51.1", "apidoc": "0.51.1",
"bch-token-sweep": "2.1.2", "c8": "7.12.0",
"chai": "4.3.0", "chai": "4.3.0",
"coveralls": "2.11.4", "coveralls": "2.11.4",
"eslint": "7.19.0",
"eslint-config-prettier": "7.2.0",
"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", "husky": "4.3.8",
"lodash.clonedeep": "4.5.0",
"mocha": "10.0.0", "mocha": "10.0.0",
"nyc": "15.1.0",
"semantic-release": "19.0.3", "semantic-release": "19.0.3",
"sinon": "9.2.4", "sinon": "9.2.4",
"standard": "16.0.4", "standard": "17.0.0",
"uuid": "8.3.2" "uuid": "8.3.2"
}, },
"release": { "release": {
+1
View File
@@ -0,0 +1 @@
COMPOSE_PROJECT_NAME=bch-dex
+12 -9
View File
@@ -12,7 +12,7 @@ RUN apt-get update
RUN apt-get install -y sudo git curl nano gnupg wget RUN apt-get install -y sudo git curl nano gnupg wget
#Install Node and NPM #Install Node and NPM
RUN curl -sL https://deb.nodesource.com/setup_16.x -o nodesource_setup.sh RUN curl -sL https://deb.nodesource.com/setup_20.x -o nodesource_setup.sh
RUN bash nodesource_setup.sh RUN bash nodesource_setup.sh
RUN apt-get install -y nodejs build-essential RUN apt-get install -y nodejs build-essential
@@ -34,10 +34,10 @@ WORKDIR /home/safeuser
# Update to the latest version of npm. # Update to the latest version of npm.
#RUN npm install -g npm@7.23.0 #RUN npm install -g npm@7.23.0
RUN npm install -g npm #RUN npm install -g npm
# npm mirror to prevent direct dependency on npm. # npm mirror to prevent direct dependency on npm.
RUN npm set registry http://94.130.170.209:4873/ #RUN npm set registry http://94.130.170.209:4873/
# Switch to user account. # Switch to user account.
#USER safeuser #USER safeuser
@@ -46,28 +46,31 @@ RUN npm set registry http://94.130.170.209:4873/
# Clone the rest.bitcoin.com repository # Clone the rest.bitcoin.com repository
WORKDIR /home/safeuser WORKDIR /home/safeuser
RUN git clone https://github.com/Permissionless-Software-Foundation/bch-dex-ui RUN git clone https://github.com/Permissionless-Software-Foundation/bch-dex-ui-v3
# Switch to the desired branch. `master` is usually stable, # Switch to the desired branch. `master` is usually stable,
# and `stage` has the most up-to-date changes. # and `stage` has the most up-to-date changes.
WORKDIR /home/safeuser/bch-dex-ui WORKDIR /home/safeuser/bch-dex-ui-v3
# For development: switch to unstable branch # For development: switch to unstable branch
RUN git checkout ct-unstable RUN git checkout psfoundation
# Install dependencies # Install dependencies
#RUN mkdir .ipfsdata #RUN mkdir .ipfsdata
#RUN npm install -g @mapbox/node-pre-gyp #RUN npm install -g @mapbox/node-pre-gyp
RUN npm install --force RUN npm install
# Build the site # Build the site
RUN CI=true npm run build RUN npm run build
# Load the NGINX image. # Load the NGINX image.
FROM nginx FROM nginx
EXPOSE 80 EXPOSE 80
# Copy the files built in the first container to the new NGINX container. # Copy the files built in the first container to the new NGINX container.
COPY --from=builder /home/safeuser/bch-dex-ui/public /usr/share/nginx/html COPY --from=builder /home/safeuser/bch-dex-ui-v3/build /usr/share/nginx/html
# Copy the NGINX configuration file.
COPY default.conf /etc/nginx/conf.d/default.conf
#USER safeuser #USER safeuser
+23
View File
@@ -0,0 +1,23 @@
server {
listen 80;
listen [::]:80;
server_name localhost;
#access_log /var/log/nginx/host.access.log main;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
+6 -3
View File
@@ -12,7 +12,7 @@ RUN apt-get update
RUN apt-get install -y sudo git curl nano gnupg wget RUN apt-get install -y sudo git curl nano gnupg wget
#Install Node and NPM #Install Node and NPM
RUN curl -sL https://deb.nodesource.com/setup_16.x -o nodesource_setup.sh RUN curl -sL https://deb.nodesource.com/setup_20.x -o nodesource_setup.sh
RUN bash nodesource_setup.sh RUN bash nodesource_setup.sh
RUN apt-get install -y nodejs build-essential RUN apt-get install -y nodejs build-essential
@@ -34,7 +34,7 @@ WORKDIR /home/safeuser
# Update to the latest version of npm. # Update to the latest version of npm.
#RUN npm install -g npm@7.23.0 #RUN npm install -g npm@7.23.0
RUN npm install -g npm #RUN npm install -g npm
# npm mirror to prevent direct dependency on npm. # npm mirror to prevent direct dependency on npm.
RUN npm set registry http://94.130.170.209:4873/ RUN npm set registry http://94.130.170.209:4873/
@@ -72,7 +72,10 @@ RUN npm run docs
#EXPOSE 5010 #EXPOSE 5010
# Start the application. # Start the application.
#COPY start-production.sh start-production.sh
CMD ["./start-production.sh"] CMD ["./start-production.sh"]
#CMD ["npm", "start"] #CMD ["npm", "start"]
# Used for debugging
#COPY dummy-app.js dummy-app.js
#CMD ["node", "dummy-app.js"]
+4
View File
@@ -0,0 +1,4 @@
setInterval(function () {
const now = new Date()
console.log(`timestamp: ${now.toLocaleString()}`)
}, 5000)
@@ -24,9 +24,14 @@ export DBURL=mongodb://172.17.0.1:5666/bch-swap-service-prod
export PORT=5700 export PORT=5700
# bch-dex specific env vars # bch-dex specific env vars
export BCH_DEX=production export BCH_DEX=prod
export WEBHOOKSERVICE=http://172.17.0.1:5667/webhook export WEBHOOKSERVICE=http://172.17.0.1:5667/webhook
export WEBHOOKTARGET=http://172.17.0.1:5700/p2wdb export WEBHOOKTARGET=http://172.17.0.1:5700/p2wdb
export APP_ID=bch-dex-001 export APP_ID=bch-dex-001
#export P2WDB_URL=http://172.17.0.1:5667
export DISABLE_NEW_ACCOUNTS=true
export ADMIN_PASSWORD=decatur
npm start npm start
+21 -72
View File
@@ -3,9 +3,9 @@
version: '3.9' version: '3.9'
services: services:
mongo-p2wdb-service: mongo-dex:
image: mongo:4.4.2-bionic image: mongo:4.2.0
container_name: mongo-p2wdb-service container_name: mongo-dex
ports: ports:
- '5666:27017' # <host port>:<container port> - '5666:27017' # <host port>:<container port>
volumes: volumes:
@@ -13,67 +13,11 @@ services:
command: mongod --logpath=/dev/null # -- quiet command: mongod --logpath=/dev/null # -- quiet
restart: always restart: always
ipfs:
image: ipfs/go-ipfs:v0.13.0
container_name: ipfs
environment:
MY_ENV_VAR: 'placeholder'
logging:
driver: 'json-file'
options:
max-size: '10m'
max-file: '10'
mem_limit: 2000mb
ports:
- 4001:4001
- 172.17.0.1:5001:5001
- 172.17.0.1:8080:8080
volumes:
- ../data/go-ipfs/data:/data/ipfs
- ../../swarm.key:/data/ipfs/swarm.key
# https://docs.docker.com/compose/compose-file/compose-file-v3/#command
# https://github.com/ipfs/go-ipfs/blob/91c52657166bcf86f2476926e4fe56694dc26562/Dockerfile#L115
command:
[
'daemon',
'--migrate=true',
'--agent-version-suffix=docker',
'--enable-pubsub-experiment'
]
restart: always
p2wdb:
build:
context: ./p2wdb/
dockerfile: Dockerfile
#image: christroutner/ipfs-p2wdb-service:v3.0.4
container_name: p2wdb
environment:
CONSUMER_URL: 'https://free-bch.fullstack.cash'
DEBUG_LEVEL: 1
logging:
driver: 'json-file'
options:
max-size: '10m'
max-file: '10'
mem_limit: 1gb
links:
- mongo-p2wdb-service
ports:
# <host port>:<container port>
- 5667:5667 # REST API
#- 5668:5668 # IPFS TCP port
#- 5669:5669 # IPFS WS Port
volumes:
- ../data/ipfsdata/p2wdb:/home/safeuser/ipfs-p2wdb-service/.ipfsdata/p2wdb
- ./p2wdb/start-production.sh:/home/safeuser/ipfs-p2wdb-service/start-production.sh
restart: always
bch-dex: bch-dex:
#build: build:
# context: ./bch-dex/ context: ./bch-dex/
# dockerfile: Dockerfile dockerfile: Dockerfile
image: christroutner/bch-dex:v1.9.0 #image: christroutner/bch-dex:v2.2.4
container_name: bch-dex container_name: bch-dex
environment: environment:
CONSUMER_URL: 'https://free-bch.fullstack.cash' CONSUMER_URL: 'https://free-bch.fullstack.cash'
@@ -84,29 +28,34 @@ services:
max-file: '10' max-file: '10'
mem_limit: 1000mb mem_limit: 1000mb
links: links:
- mongo-p2wdb-service - mongo-dex
- p2wdb #- p2wdb
ports: ports:
- '5700:5700' # <host port>:<container port> # <host port>:<container port>
- '5700:5700' # REST API
- '4001:4001' # TCP
- '4003:4003' # Websockets
- '4005:4005' # WebRTC
volumes: volumes:
- ../scripts/wallet.json:/home/safeuser/bch-dex/wallet.json - ../scripts/wallet.json:/home/safeuser/bch-dex/wallet.json
- ./bch-dex/start-production.sh:/home/safeuser/bch-dex/start-production.sh - ./bch-dex/start-production.sh:/home/safeuser/bch-dex/start-production.sh
restart: always restart: always
dex-ui: dex-ui:
#build: build:
# context: ./bch-dex-ui/ context: ./bch-dex-ui/
# dockerfile: Dockerfile dockerfile: Dockerfile
image: christroutner/bch-dex-ui:v1.6.5 #image: christroutner/bch-dex-ui:v1.2.4
container_name: dex-ui container_name: dex-ui
environment: environment:
SERVER: 'http://192.168.2.3' SERVER: 'http://172.17.0.1'
logging: logging:
driver: 'json-file' driver: 'json-file'
options: options:
max-size: '10m' max-size: '10m'
max-file: '10' max-file: '10'
mem_limit: 500mb mem_limit: 1000mb
links: links:
- bch-dex - bch-dex
ports: ports:
-71
View File
@@ -1,71 +0,0 @@
# Create a Docker container for the P2WDB
#
#IMAGE BUILD COMMANDS
FROM ubuntu:20.04
MAINTAINER Chris Troutner <chris.troutner@gmail.com>
#Update the OS and install any OS packages needed.
RUN apt-get update
RUN apt-get install -y sudo git curl nano gnupg wget
#Install Node and NPM
RUN curl -sL https://deb.nodesource.com/setup_16.x -o nodesource_setup.sh
RUN bash nodesource_setup.sh
RUN apt-get install -y nodejs build-essential
#Create the user 'safeuser' and add them to the sudo group.
RUN useradd -ms /bin/bash safeuser
RUN adduser safeuser sudo
#Set password to 'abcd8765' change value below if you want a different password
RUN echo safeuser:abcd8765 | chpasswd
#Set the working directory to be the users home directory
WORKDIR /home/safeuser
#Setup NPM for non-root global install (like on a mac)
RUN mkdir /home/safeuser/.npm-global
RUN chown -R safeuser .npm-global
RUN echo "export PATH=~/.npm-global/bin:$PATH" >> /home/safeuser/.profile
RUN runuser -l safeuser -c "npm config set prefix '~/.npm-global'"
# Update to the latest version of npm.
#RUN npm install -g npm@7.23.0
RUN npm install -g npm
# npm mirror to prevent direct dependency on npm.
RUN npm set registry http://94.130.170.209:4873/
# Switch to user account.
#USER safeuser
# Prep 'sudo' commands.
#RUN echo 'abcd8765' | sudo -S pwd
# Clone the rest.bitcoin.com repository
RUN git clone https://github.com/Permissionless-Software-Foundation/ipfs-p2wdb-service
WORKDIR /home/safeuser/ipfs-p2wdb-service
RUN mkdir .ipfsdata
RUN git checkout ct-unstable
#RUN npm install fsevents
# Install dependencies
#RUN mkdir .ipfsdata
RUN npm install
# Generate the API docs
RUN npm run docs
# Expose the port the API will be served on.
#EXPOSE 5010
# Start the application.
#COPY start-production.sh start-production.sh
CMD ["./start-production.sh"]
#CMD ["npm", "start"]
# Used for debugging
#COPY dummyapp.js dummyapp.js
#CMD ["node", "dummyapp.js"]
-4
View File
@@ -1,4 +0,0 @@
setInterval(function () {
const now = new Date()
console.log(`ping ${now.toLocaleString()}`)
}, 10000)
@@ -1,47 +0,0 @@
#!/bin/bash
# BEGIN: Optional configuration settings
# This mnemonic is used to set up persistent public key for e2ee
# Replace this with your own 12-word mnemonic.
export MNEMONIC="mass response fiscal world message exact series swallow forward confirm canoe festival"
# The human readable name this IPFS node identifies as.
export COORD_NAME=generic-p2wdb-production
# Allow this node to function as a circuit relay. It must not be behind a firewall.
#export ENABLE_CIRCUIT_RELAY=true
# For browsers to use your circuit realy, you must set up a domain, SSL certificate,
# and you must forward that subdomain to the IPFS_WS_PORT.
#export CR_DOMAIN=subdomain.yourdomain.com
# Debug level. 0 = minimal info. 2 = max info.
# This value set by docker-compose.yml
#export DEBUG_LEVEL=1
# Log-in information for retrieving a JWT token from FullStack.cash.
export FULLSTACKLOGIN=demo@demo.com
export FULLSTACKPASS=demo
# END: Optional configuration settings
# Production database connection string.
export DBURL=mongodb://172.17.0.1:5666/p2wdb-service-dev
# Configure IPFS ports
#export IPFS_TCP_PORT=5668
#export IPFS_WS_PORT=5669
# Configure REST API port
export PORT=5667
export P2W_ENV=production
export IPFS_HOST=172.17.0.1
export IPFS_API_PORT=5001
export IPFS_TCP_PORT=4001
# P2WDB specific env vars
#export ORBITDB_NAME=/orbitdb/zdpuAm4fPafpjs5mgbBUJV8Az7kd8Xj1ttD6M1JaAxF8RMRrw/psf-bch-p2wdb-keyvalue-v1.0.0-0004
npm start
+4 -4
View File
@@ -46,11 +46,11 @@ RUN npm set registry http://94.130.170.209:4873/
# Clone the rest.bitcoin.com repository # Clone the rest.bitcoin.com repository
WORKDIR /home/safeuser WORKDIR /home/safeuser
RUN git clone https://github.com/Permissionless-Software-Foundation/bch-dex-ui RUN git clone https://github.com/Permissionless-Software-Foundation/bch-dex-ui-v2
# Switch to the desired branch. `master` is usually stable, # Switch to the desired branch. `master` is usually stable,
# and `stage` has the most up-to-date changes. # and `stage` has the most up-to-date changes.
WORKDIR /home/safeuser/bch-dex-ui WORKDIR /home/safeuser/bch-dex-ui-v2
# For development: switch to unstable branch # For development: switch to unstable branch
RUN git checkout ct-unstable RUN git checkout ct-unstable
@@ -58,7 +58,7 @@ RUN git checkout ct-unstable
# Install dependencies # Install dependencies
#RUN mkdir .ipfsdata #RUN mkdir .ipfsdata
#RUN npm install -g @mapbox/node-pre-gyp #RUN npm install -g @mapbox/node-pre-gyp
RUN npm install --force RUN npm install
# Build the site # Build the site
RUN CI=true npm run build RUN CI=true npm run build
@@ -68,6 +68,6 @@ FROM nginx
EXPOSE 80 EXPOSE 80
# Copy the files built in the first container to the new NGINX container. # Copy the files built in the first container to the new NGINX container.
COPY --from=builder /home/safeuser/bch-dex-ui/public /usr/share/nginx/html COPY --from=builder /home/safeuser/bch-dex-ui-v2/build /usr/share/nginx/html
#USER safeuser #USER safeuser
+9 -14
View File
@@ -12,9 +12,12 @@ RUN apt-get update
RUN apt-get install -y sudo git curl nano gnupg wget RUN apt-get install -y sudo git curl nano gnupg wget
#Install Node and NPM #Install Node and NPM
RUN curl -sL https://deb.nodesource.com/setup_16.x -o nodesource_setup.sh RUN sudo apt-get install -y ca-certificates curl gnupg
RUN bash nodesource_setup.sh RUN sudo mkdir -p /etc/apt/keyrings
RUN apt-get install -y nodejs build-essential RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
RUN echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list
RUN sudo apt-get update
RUN sudo apt-get install -y nodejs build-essential
#Create the user 'safeuser' and add them to the sudo group. #Create the user 'safeuser' and add them to the sudo group.
#RUN useradd -ms /bin/bash safeuser #RUN useradd -ms /bin/bash safeuser
@@ -34,7 +37,7 @@ WORKDIR /home/safeuser
# Update to the latest version of npm. # Update to the latest version of npm.
#RUN npm install -g npm@7.23.0 #RUN npm install -g npm@7.23.0
RUN npm install -g npm #RUN npm install -g npm
# npm mirror to prevent direct dependency on npm. # npm mirror to prevent direct dependency on npm.
RUN npm set registry http://94.130.170.209:4873/ RUN npm set registry http://94.130.170.209:4873/
@@ -53,7 +56,7 @@ RUN git clone https://github.com/Permissionless-Software-Foundation/bch-dex
WORKDIR /home/safeuser/bch-dex WORKDIR /home/safeuser/bch-dex
# For development: switch to unstable branch # For development: switch to unstable branch
RUN git checkout ct-unstable RUN git checkout master
# Install dependencies # Install dependencies
#RUN mkdir .ipfsdata #RUN mkdir .ipfsdata
@@ -63,16 +66,8 @@ RUN npm install
# Generate the API docs # Generate the API docs
RUN npm run docs RUN npm run docs
# Copy the wallet files
#COPY wallet.json wallet.json
#VOLUME /home/safeuser/keys
# Expose the port the API will be served on.
#EXPOSE 5010
# Start the application. # Start the application.
COPY start-production.sh start-production.sh #COPY start-production.sh start-production.sh
CMD ["./start-production.sh"] CMD ["./start-production.sh"]
#CMD ["npm", "start"] #CMD ["npm", "start"]
@@ -24,9 +24,9 @@ export DBURL=mongodb://172.17.0.1:5666/bch-swap-service-prod
export PORT=5700 export PORT=5700
# bch-dex specific env vars # bch-dex specific env vars
export BCH_ENV=production export BCH_DEX=prod
export WEBHOOKSERVICE=http://172.17.0.1:5667/webhook export WEBHOOKSERVICE=http://172.17.0.1:5667/webhook
export WEBHOOKTARGET=http://172.17.0.1:5700/p2wdb export WEBHOOKTARGET=http://172.17.0.1:5700/p2wdb
export APP_ID=bch-dex-test557 export APP_ID=bch-dex-001
npm start npm start
+26 -27
View File
@@ -3,9 +3,9 @@
version: '3.9' version: '3.9'
services: services:
mongo-p2wdb-service: mongo-bch-dex:
image: mongo:4.4 image: mongo:4.2.0
container_name: mongo-p2wdb-service container_name: mongo-bch-dex
ports: ports:
- '5666:27017' # <host port>:<container port> - '5666:27017' # <host port>:<container port>
volumes: volumes:
@@ -14,43 +14,39 @@ services:
restart: always restart: always
ipfs: ipfs:
#image: ipfs/go-ipfs:v0.12.0 image: christroutner/trickle-ipfs-rpi:v1.0.1
image: odanado/go-ipfs:v0.11.0 #image: odanado/go-ipfs:v0.11.0
container_name: ipfs container_name: ipfs
environment: environment:
MY_ENV_VAR: 'placeholder' IPFS_DAEMON_ARGUMENTS: '--enable-pubsub-experiment --migrate=true --agent-version-suffix=docker --routing=dhtclient'
UPLOAD_KBPS: '25'
DOWNLOAD_KBPS: '25'
logging: logging:
driver: 'json-file' driver: 'json-file'
options: options:
max-size: '10m' max-size: '10m'
max-file: '10' max-file: '10'
mem_limit: 2000mb mem_limit: 1000mb
ports: ports:
- 4001:4001 - 4001:4001
- 4003:4003
- 172.17.0.1:5001:5001 - 172.17.0.1:5001:5001
- 172.17.0.1:8080:8080 - 172.17.0.1:8080:8080
volumes: volumes:
- ../data/go-ipfs/data:/data/ipfs - ./data/go-ipfs:/root/.ipfs
- ../../swarm.key:/data/ipfs/swarm.key command: [
# https://docs.docker.com/compose/compose-file/compose-file-v3/#command './start-ipfs.sh'
# https://github.com/ipfs/go-ipfs/blob/91c52657166bcf86f2476926e4fe56694dc26562/Dockerfile#L115 ]
command:
[
'daemon',
'--migrate=true',
'--agent-version-suffix=docker',
'--enable-pubsub-experiment'
]
restart: always restart: always
p2wdb: p2wdb:
#build: #build:
# context: ./p2wdb/ # context: ./p2wdb/
# dockerfile: Dockerfile # dockerfile: Dockerfile
image: christroutner/pwd-bch-dex-rpi:v1.7.1 image: christroutner/p2wdb-rpi:v3.1.9
container_name: p2wdb container_name: p2wdb
environment: environment:
CONSUMER_URL: 'https://free-bch.fullstack.cash' CONSUMER_URL: 'https://wa-usa-bch-consumer.fullstackcash.nl'
DEBUG_LEVEL: 1 DEBUG_LEVEL: 1
logging: logging:
driver: 'json-file' driver: 'json-file'
@@ -59,7 +55,7 @@ services:
max-file: '10' max-file: '10'
mem_limit: 1gb mem_limit: 1gb
links: links:
- mongo-p2wdb-service - mongo-bch-dex
ports: ports:
# <host port>:<container port> # <host port>:<container port>
- 5667:5667 # REST API - 5667:5667 # REST API
@@ -67,16 +63,18 @@ services:
#- 5669:5669 # IPFS WS Port #- 5669:5669 # IPFS WS Port
volumes: volumes:
- ../data/ipfsdata/p2wdb:/home/safeuser/ipfs-p2wdb-service/.ipfsdata/p2wdb - ../data/ipfsdata/p2wdb:/home/safeuser/ipfs-p2wdb-service/.ipfsdata/p2wdb
- ./p2wdb/start-production.sh:/home/safeuser/ipfs-p2wdb-service/start-production.sh
restart: always restart: always
bch-dex: bch-dex:
#build: #build:
# context: ./bch-dex/ # context: ./bch-dex/
# dockerfile: Dockerfile # dockerfile: Dockerfile
image: christroutner/bch-dex-rpi:v1.7.1 image: christroutner/bch-dex-rpi:v2.0.8
container_name: bch-dex container_name: bch-dex
environment: environment:
CONSUMER_URL: 'https://free-bch.fullstack.cash' #CONSUMER_URL: 'https://free-bch.fullstack.cash'
CONSUMER_URL: 'https://wa-usa-bch-consumer.fullstackcash.nl'
logging: logging:
driver: 'json-file' driver: 'json-file'
options: options:
@@ -84,19 +82,20 @@ services:
max-file: '10' max-file: '10'
mem_limit: 1000mb mem_limit: 1000mb
links: links:
- mongo-p2wdb-service - mongo-bch-dex
- p2wdb - p2wdb
ports: ports:
- '5700:5700' # <host port>:<container port> - '5700:5700' # <host port>:<container port>
volumes: volumes:
- ../scripts/wallet.json:/home/safeuser/bch-dex/wallet.json - ../scripts/wallet.json:/home/safeuser/bch-dex/wallet.json
- ./bch-dex/start-production.sh:/home/safeuser/bch-dex/start-production.sh
restart: always restart: always
dex-ui: dex-ui:
#build: #build:
# context: ./bch-dex-ui/ # context: ./bch-dex-ui/
# dockerfile: Dockerfile # dockerfile: Dockerfile
image: christroutner/bch-dex-ui-rpi:v1.7.3 image: christroutner/bch-dex-ui-rpi:v1.2.4
container_name: dex-ui container_name: dex-ui
logging: logging:
driver: 'json-file' driver: 'json-file'
+1 -1
View File
@@ -61,7 +61,7 @@ RUN npm run docs
#EXPOSE 5010 #EXPOSE 5010
# Start the application. # Start the application.
COPY start-production.sh start-production.sh #COPY start-production.sh start-production.sh
CMD ["./start-production.sh"] CMD ["./start-production.sh"]
#CMD ["npm", "start"] #CMD ["npm", "start"]
@@ -40,8 +40,15 @@ export P2W_ENV=production
export IPFS_HOST=172.17.0.1 export IPFS_HOST=172.17.0.1
export IPFS_API_PORT=5001 export IPFS_API_PORT=5001
export IPFS_TCP_PORT=4001 export IPFS_TCP_PORT=4001
export IPFS_WS_PORT=4003
export IPFS_WEB_RTC_PORT=4005
# Set the debug level for helia-coord. 0-3.
# 0 = no debug logs. 3 = maximum debug logs.
export DEBUG_LEVEL=0
# P2WDB specific env vars # Use this if the IPFS node has a publically accessible IP address.
export ORBITDB_NAME=/orbitdb/zdpuAm4fPafpjs5mgbBUJV8Az7kd8Xj1ttD6M1JaAxF8RMRrw/psf-bch-p2wdb-keyvalue-v1.0.0-0004 #export CONNECT_PREF=direct
# Use this if the IPFS node is behind a NAT or Firewall and cannot be accessed directly.
export CONNECT_PREF=cr
npm start npm start
+153
View File
@@ -0,0 +1,153 @@
/*
This script is similar ot sweep-wallet.js, but it can do a much faster (bulk)
scanning of addresses. However, this requires a subscription to a FullStack.cash
or access to a web2 Cash Stack.
This script will scan 20 addresses at a time. If a balance is found in any
of the addresses, it will sweep the funds from that address.
*/
/*
// Public npm libraries
import BchTokenSweep from 'bch-token-sweep/index.js'
// Local libraries
import WalletAdapter from '../../src/adapters/wallet.js'
import BCHJS from '@psf/bch-js'
import JwtLib from 'jwt-bch-lib'
// Constants
// const EMTPY_ADDR_CUTOFF = 100
const LAST_ADDR_INDEX = 100
if (!process.env.BCHJSTOKEN) {
console.log('You will need a JWT token from FullStack.cash to execute this script. Export it to the BCHJSTOKEN environment variable and try again.')
exit(0)
}
async function sweepFunds () {
try {
// Configure the wallet library to use a FullStack.cash or a local Cash Stack
const walletLib = new WalletAdapter()
walletLib.config.useFullStackCash = true
walletLib.config.apiServer = 'http://192.168.2.129:3000/v5/'
// const walletInfo = await walletLib.openWallet()
const walletInfo = await openWallet(walletLib)
const wallet = await walletLib.instanceWallet(walletInfo)
console.log('walletInfo: ', walletInfo)
const rootAddr = walletInfo.cashAddress
const rootWif = walletInfo.privateKey
console.log(`Sweeping all funds into root address ${rootAddr}...`)
// Instantiate bch-js, and use the JWT token saved to environment variable.
// Generate an HD tree
// const bchjs = wallet.bchjs
const bchjs = new BCHJS()
const rootSeed = await bchjs.Mnemonic.toSeed(walletInfo.mnemonic)
const masterHDNode = bchjs.HDNode.fromSeed(rootSeed)
const emptyAddrCnt = 0
const hdIndex = 1
// Divide all the addresses by 20, since that's how many will be checked at once.
const numOfLoops = Math.ceil(LAST_ADDR_INDEX / 20)
for (let i = 1; i < numOfLoops; i++) {
const startIndex = i
const stopIndex = i * 20
console.log(`startIndex: ${startIndex}, stopIndex: ${stopIndex}`)
// Generate the next block of 20 key pairs to scan.
const addrsToScan = []
const wifsToScan = []
for (let j = startIndex; j < stopIndex; j++) {
// Generate a keypair from the HD wallet.
const childNode = masterHDNode.derivePath(`m/44'/245'/0'/0/${j}`)
const cashAddress = bchjs.HDNode.toCashAddress(childNode)
const wifToSweep = bchjs.HDNode.toWIF(childNode)
addrsToScan.push(cashAddress)
wifsToScan.push(wifToSweep)
}
console.log(`Scanning these addresses for a balance: ${JSON.stringify(addrsToScan, null, 2)}`)
// Scan a block of 20 addresses for a balance.
const balances = await bchjs.Electrumx.balance(addrsToScan)
console.log(`balances: ${JSON.stringify(balances, null, 2)}`)
// Scan through the results and look for a balance.
for (let j = 0; j < balances.balances.length; j++) {
const thisBalance = balances.balances[j]
// const combinedBal = thisBalance.balance.confirmed + thisBalance.balance.
// if(thisBalance.)
}
}
// do {
// // Generate a keypair from the HD wallet.
// const childNode = masterHDNode.derivePath(`m/44'/245'/0'/0/${hdIndex}`)
// const cashAddress = bchjs.HDNode.toCashAddress(childNode)
// const wifToSweep = bchjs.HDNode.toWIF(childNode)
//
// console.log(`\nSweeping ${cashAddress} with private key ${wifToSweep}`)
//
// try {
// // Sweep tokens from address
// const sweeper = new BchTokenSweep(
// wifToSweep,
// rootWif,
// wallet,
// 550,
// rootAddr
// )
// await sweeper.populateObjectFromNetwork()
//
// const hex = await sweeper.sweepTo(rootAddr)
// // console.log(`hex: ${hex}`)
//
// const txid = await sweeper.blockchain.broadcast(hex)
//
// // console.log('Transaction ID', txid)
// console.log(`Swept HD index ${hdIndex}. TXID: ${txid}`)
//
// emptyAddrCnt = 0
//
// // Wait between loop iterations.
// await bchjs.Util.sleep(3000)
// } catch (err) {
// console.log(`error message with index ${hdIndex}: ${err.message}`)
// // console.log(err)
// emptyAddrCnt++
// }
//
// hdIndex++
// } while (emptyAddrCnt < EMTPY_ADDR_CUTOFF)
//
// console.log(`${EMTPY_ADDR_CUTOFF} empty addresses detected. Exiting.`)
//
// console.log('\n\nDo not forget to reset the nextAddress property in the wallet.json file!\n\n')
} catch (err) {
console.error('Error in sweepFunds(): ', err)
}
}
sweepFunds()
// 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 function openWallet (walletLib) {
try {
// console.log('this.WALLET_FILE: ', this.WALLET_FILE)
const walletData = await walletLib.jsonFiles.readJSON('./wallet.json')
return walletData
} catch (err) {
console.error('Error in openWallet()')
throw err
}
}
*/
+1 -1
View File
@@ -6,7 +6,7 @@
the DEX app wallet in order to be acceped. the DEX app wallet in order to be acceped.
*/ */
const axios = require('axios') import axios from 'axios'
const LOCALHOST = 'http://localhost:5700' const LOCALHOST = 'http://localhost:5700'
// const LOCALHOST = 'http://172.17.0.1:5700' // const LOCALHOST = 'http://172.17.0.1:5700'
+6 -5
View File
@@ -3,8 +3,9 @@
*/ */
// Public NPM libraries // Public NPM libraries
const BchWallet = require('minimal-slp-wallet/index') import BchWallet from 'minimal-slp-wallet'
const fs = require('fs').promises
import { promises as fs } from 'fs'
async function createWallet () { async function createWallet () {
try { try {
@@ -15,9 +16,9 @@ async function createWallet () {
} }
// Wait for the wallet to be created. // Wait for the wallet to be created.
this.bchWallet = new BchWallet(undefined, advancedConfig) const bchWallet = new BchWallet(undefined, advancedConfig)
await this.bchWallet.walletInfoPromise await bchWallet.walletInfoPromise
const walletData = this.bchWallet.walletInfo const walletData = bchWallet.walletInfo
walletData.nextAddress = 1 walletData.nextAddress = 1
// Save the wallet file to disk. // Save the wallet file to disk.
@@ -0,0 +1,111 @@
/*
This script is the same as sweep-wallet.js, but it requires a FullStack.cash
account, which makes the scanning much faster.
*/
// Public npm libraries
// const BCHJS = require('@psf/bch-js')
import BchTokenSweep from 'bch-token-sweep/index.js'
// Local libraries
import WalletAdapter from '../../src/adapters/wallet.js'
// Constants
// const EMTPY_ADDR_CUTOFF = 10
const START_INDEX = 1
const LAST_ADDR_INDEX = 100
if (!process.env.BCHJSTOKEN) {
console.log('You will need a JWT token from FullStack.cash to execute this script. Export it to the BCHJSTOKEN environment variable and try again.')
process.exit(0)
}
async function sweepFunds () {
try {
// Configure the wallet library to use a FullStack.cash or a local Cash Stack
const walletLib = new WalletAdapter()
walletLib.config.useFullStackCash = true
// walletLib.config.apiServer = 'http://192.168.2.129:3000/v5/'
walletLib.config.apiServer = 'https://api.fullstack.cash/v5/'
// Open the wallet files.
const walletInfo = await openWallet(walletLib)
const wallet = await walletLib.instanceWallet(walletInfo)
console.log('walletInfo: ', walletInfo)
const rootAddr = walletInfo.cashAddress
const rootWif = walletInfo.privateKey
console.log(`Sweeping all funds into root address ${rootAddr}...`)
// Generate an HD tree
const bchjs = wallet.bchjs
const rootSeed = await bchjs.Mnemonic.toSeed(walletInfo.mnemonic)
const masterHDNode = bchjs.HDNode.fromSeed(rootSeed)
let emptyAddrCnt = 0
let hdIndex = START_INDEX
do {
// Generate a keypair from the HD wallet.
const childNode = masterHDNode.derivePath(`m/44'/245'/0'/0/${hdIndex}`)
const cashAddress = bchjs.HDNode.toCashAddress(childNode)
const wifToSweep = bchjs.HDNode.toWIF(childNode)
console.log(`\nSweeping ${cashAddress} with private key ${wifToSweep}`)
try {
// Sweep tokens from address
const sweeper = new BchTokenSweep(
wifToSweep,
rootWif,
wallet,
550,
rootAddr
)
await sweeper.populateObjectFromNetwork()
const hex = await sweeper.sweepTo(rootAddr)
// console.log(`hex: ${hex}`)
const txid = await sweeper.blockchain.broadcast(hex)
// console.log('Transaction ID', txid)
console.log(`Swept HD index ${hdIndex}. TXID: ${txid}`)
emptyAddrCnt = 0
// Wait between loop iterations.
await bchjs.Util.sleep(3000)
} catch (err) {
console.log(`error message with index ${hdIndex}: ${err.message}`)
// console.log(err)
emptyAddrCnt++
}
hdIndex++
// } while (emptyAddrCnt < EMTPY_ADDR_CUTOFF)
// console.log(`${EMTPY_ADDR_CUTOFF} empty addresses detected. Exiting.`)
} while (hdIndex < LAST_ADDR_INDEX)
console.log(`Last index of ${LAST_ADDR_INDEX} reached. emptyAddrCnt: ${emptyAddrCnt}`)
console.log('\n\nDo not forget to reset the nextAddress property in the wallet.json file!\n\n')
} catch (err) {
console.error('Error in sweepFunds(): ', err)
}
}
sweepFunds()
// 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 function openWallet (walletLib) {
try {
// console.log('this.WALLET_FILE: ', this.WALLET_FILE)
const walletData = await walletLib.jsonFiles.readJSON('./wallet.json')
return walletData
} catch (err) {
console.error('Error in openWallet()')
throw err
}
}
+67
View File
@@ -0,0 +1,67 @@
/*
This script is the same as sweep-wallet.js, but instead of sweeping the keys,
it simply lists out the addresses in the HD keychain. This is hany when trying
to figure out which address a token was sent to.
*/
// Public npm libraries
// Local libraries
import WalletAdapter from '../../src/adapters/wallet.js'
// Constants
const START_INDEX = 1
const LAST_ADDR_INDEX = 100
async function listAddrs () {
try {
// Configure the wallet library to use a FullStack.cash or a local Cash Stack
const walletLib = new WalletAdapter()
// Open the wallet files.
const walletInfo = await openWallet(walletLib)
const wallet = await walletLib.instanceWallet(walletInfo)
console.log('walletInfo: ', walletInfo)
const rootAddr = walletInfo.cashAddress
// const rootWif = walletInfo.privateKey
console.log(`Sweeping all funds into root address ${rootAddr}...`)
// Generate an HD tree
const bchjs = wallet.bchjs
const rootSeed = await bchjs.Mnemonic.toSeed(walletInfo.mnemonic)
const masterHDNode = bchjs.HDNode.fromSeed(rootSeed)
let hdIndex = START_INDEX
do {
// Generate a keypair from the HD wallet.
const childNode = masterHDNode.derivePath(`m/44'/245'/0'/0/${hdIndex}`)
const cashAddress = bchjs.HDNode.toCashAddress(childNode)
// const wifToSweep = bchjs.HDNode.toWIF(childNode)
console.log(`HD Index ${hdIndex}: ${cashAddress}`)
hdIndex++
} while (hdIndex < LAST_ADDR_INDEX)
console.log(`Last index of ${LAST_ADDR_INDEX} reached.`)
} catch (err) {
console.error('Error in sweepFunds(): ', err)
}
}
listAddrs()
// 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 function openWallet (walletLib) {
try {
// console.log('this.WALLET_FILE: ', this.WALLET_FILE)
const walletData = await walletLib.jsonFiles.readJSON('./wallet.json')
return walletData
} catch (err) {
console.error('Error in openWallet()')
throw err
}
}
+7 -3
View File
@@ -5,10 +5,10 @@
*/ */
// Global npm libraries // Global npm libraries
const BchWallet = require('minimal-slp-wallet/index') import BchWallet from 'minimal-slp-wallet'
// Local libraries // Local libraries
const WalletAdapter = require('../../src/adapters/wallet') import WalletAdapter from '../../src/adapters/wallet.js'
// Constants // Constants
const EMTPY_ADDR_CUTOFF = 10 const EMTPY_ADDR_CUTOFF = 10
@@ -64,6 +64,8 @@ async function sweepNfts () {
if (thisToken.tokenType === 65) { if (thisToken.tokenType === 65) {
console.log(`NFT ${thisToken.ticker} (${thisToken.name}) found. Sweeping to ${rootAddr}`) console.log(`NFT ${thisToken.ticker} (${thisToken.name}) found. Sweeping to ${rootAddr}`)
await walletRoot.initialize()
// Send BCH to the child address, to pay for transaction fees. // Send BCH to the child address, to pay for transaction fees.
const receiver1 = [{ const receiver1 = [{
address: cashAddress, address: cashAddress,
@@ -74,7 +76,9 @@ async function sweepNfts () {
// Wait for indexers to update. // Wait for indexers to update.
console.log('Waiting for indexers to update...') console.log('Waiting for indexers to update...')
await bchjs.Util.sleep(20000) await bchjs.Util.sleep(120000)
await walletChild.initialize()
// Send NFT to root address. // Send NFT to root address.
const receiver2 = [{ const receiver2 = [{
+2 -4
View File
@@ -2,16 +2,14 @@
This script will travers the HD wallet and sweep funds and tokens back This script will travers the HD wallet and sweep funds and tokens back
into the root address (index 0). That root address needs to have funds into the root address (index 0). That root address needs to have funds
to pay for the transactions. to pay for the transactions.
This script will sweep BCH and fungible (Type 1) tokens, but not NFTs.
*/ */
// Public npm libraries // Public npm libraries
// const BCHJS = require('@psf/bch-js') // const BCHJS = require('@psf/bch-js')
const BchTokenSweep = require('bch-token-sweep/index') import BchTokenSweep from 'bch-token-sweep/index.js'
// Local libraries // Local libraries
const WalletAdapter = require('../../src/adapters/wallet') import WalletAdapter from '../../src/adapters/wallet.js'
// Constants // Constants
const EMTPY_ADDR_CUTOFF = 10 const EMTPY_ADDR_CUTOFF = 10
+11
View File
@@ -0,0 +1,11 @@
{
"privateKey": "L4VyBDiWYYeeZhkM3xE3nsZigXJYmvRM29YBxoC7da4FzvubjxFo",
"publicKey": "028d6c77d865e6140db4b879a9bdf69ee4846593c0b6c48a82c448d5792806aab1",
"mnemonic": "split title trigger soda execute frost brush labor vague protect bicycle fiscal",
"cashAddress": "bitcoincash:qprrdk7en7m774gsafkycxcymc9ry209jus5v8wx5z",
"address": "bitcoincash:qprrdk7en7m774gsafkycxcymc9ry209jus5v8wx5z",
"legacyAddress": "17QG25rNUfnfj2NtdaFiyiqKSJatvEnMYd",
"hdPath": "m/44'/245'/0'/0/0",
"slpAddress": "simpleledger:qprrdk7en7m774gsafkycxcymc9ry209juu08umx2u",
"nextAddress": 1
}
+1 -1
View File
@@ -13,7 +13,7 @@ export COORD_NAME=ipfs-service-provider-generic
export MNEMONIC="churn aisle shield silver ladder swear hunt slim pen demand spoil veteran" export MNEMONIC="churn aisle shield silver ladder swear hunt slim pen demand spoil veteran"
# 0 = less verbose. 3 = most verbose # 0 = less verbose. 3 = most verbose
export DEBUG_LEVEL=2 export DEBUG_LEVEL=0
# Production settings that use external IPFS node. # Production settings that use external IPFS node.
# https://github.com/christroutner/docker-ipfs # https://github.com/christroutner/docker-ipfs
+43 -64
View File
@@ -13,16 +13,24 @@
in the Adapter directory. in the Adapter directory.
*/ */
'use strict' // Global npm libraries
const axios = require('axios').default import axios from 'axios'
const mongoose = require('mongoose') import mongoose from 'mongoose'
const User = require('../adapters/localdb/models/users')
const config = require('../../config') // Local libraries
const JsonFiles = require('../adapters/json-files') import User from '../adapters/localdb/models/users.js'
import config from '../../config/index.js'
import JsonFiles from '../adapters/json-files.js'
// Hack to get __dirname back.
// https://blog.logrocket.com/alternatives-dirname-node-js-es-modules/
import * as url from 'url'
const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
const jsonFiles = new JsonFiles() const jsonFiles = new JsonFiles()
const JSON_FILE = `system-user-${config.env}.json` const JSON_FILE = `system-user-${config.env}.json`
const JSON_PATH = `${__dirname.toString()}/../../config/${JSON_FILE}` const JSON_PATH = `${__dirname.toString()}../../config/${JSON_FILE}`
const LOCALHOST = `http://localhost:${config.port}` const LOCALHOST = `http://localhost:${config.port}`
const context = {} const context = {}
@@ -43,68 +51,38 @@ class Admin {
// used by the Listing Manager and test scripts, in order access private API // used by the Listing Manager and test scripts, in order access private API
// functions. // functions.
async createSystemUser () { async createSystemUser () {
// Create the system user.
try { try {
context.password = _this._randomString(20) const context = {
email: 'system@system.com',
const options = { name: 'admin',
method: 'POST', password: _this.config.adminPassword || _this._randomString(20),
url: `${LOCALHOST}/users`, type: 'admin',
data: { mnemonic: 'spread ivory oval pioneer flash gap merit nerve simple image entire trouble'
user: {
email: 'system@system.com',
password: context.password,
name: 'admin'
}
}
} }
const result = await _this.axios.request(options) // Check if the user already exists
// console.log('admin.data: ', result.data) let adminUser = await _this.User.findOne({ email: context.email })
context.email = result.data.user.email if (adminUser) {
context.id = result.data.user._id // Update the password
context.token = result.data.token adminUser.password = context.password
} else {
// Create a new admin user
adminUser = new _this.User(context)
}
// Update context with the new user id and token
context.id = adminUser._id
context.token = await adminUser.generateToken()
// Get the mongoDB entry // Save the user
const user = await _this.User.findById(context.id) await adminUser.save()
// Change the user type to admin // Write the user data to the JSON file
user.type = 'admin' await _this.jsonFiles.writeJSON(context, JSON_PATH)
// console.log(`user created: ${JSON.stringify(user, null, 2)}`)
// Save the user model.
await user.save()
// console.log(`admin user created: ${JSON.stringify(result.body, null, 2)}`)
// console.log(`with password: ${context.password}`)
// Write out the system user information to a JSON file that external
// applications like the Task Manager and the test scripts can access.
await jsonFiles.writeJSON(context, JSON_PATH)
return context return context
} catch (err) { } catch (error) {
// Handle existing system user. console.log('Error in admin.js/createSystemUser()')
if (err.response.status === 422) { throw error
try {
// Delete the existing user
await _this.deleteExistingSystemUser()
// Call this function again.
return _this.createSystemUser()
} catch (err2) {
console.error(
'Error in admin.js/createSystemUser() while trying generate new system user.'
)
// process.end(1)
throw err2
}
} else {
console.log('Error in admin.js/createSystemUser: ')
// process.end(1)
throw err
}
} }
} }
@@ -119,6 +97,7 @@ class Admin {
}) })
await _this.User.deleteOne({ email: 'system@system.com' }) await _this.User.deleteOne({ email: 'system@system.com' })
return true
} catch (err) { } catch (err) {
console.log('Error in admin.js/deleteExistingSystemUser()') console.log('Error in admin.js/deleteExistingSystemUser()')
throw err throw err
@@ -142,7 +121,7 @@ class Admin {
Accept: 'application/json' Accept: 'application/json'
}, },
data: { data: {
email: 'system@system.com', email: existingUser.email,
password: existingUser.password password: existingUser.password
} }
} }
@@ -169,4 +148,4 @@ class Admin {
} }
} }
module.exports = Admin export default Admin
+8 -4
View File
@@ -3,9 +3,10 @@
*/ */
// Public npm libraries // Public npm libraries
const BCHJS = require('@psf/bch-js') import BCHJS from '@psf/bch-js'
const MsgLib = require('bch-message-lib')
const BchWallet = require('minimal-slp-wallet/index') import MsgLib from 'bch-message-lib'
import BchWallet from 'minimal-slp-wallet'
class Bch { class Bch {
constructor () { constructor () {
@@ -65,6 +66,9 @@ class Bch {
// } // }
// } // }
/** DEV NOTE: This function are deprecated.?
* https://github.com/Permissionless-Software-Foundation/bch-message-lib/pull/41
*/
async getMerit (slpAddr) { async getMerit (slpAddr) {
try { try {
if (!slpAddr || typeof slpAddr !== 'string') { if (!slpAddr || typeof slpAddr !== 'string') {
@@ -79,4 +83,4 @@ class Bch {
} }
} }
module.exports = Bch export default Bch
+5 -6
View File
@@ -3,13 +3,12 @@
*/ */
/* eslint-disable no-useless-escape */ /* eslint-disable no-useless-escape */
import config from '../../config/index.js'
import NodeMailer from '../adapters/nodemailer.js'
import wlogger from '../adapters/wlogger.js'
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0' process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
const config = require('../../config')
const NodeMailer = require('../adapters/nodemailer')
const nodemailer = new NodeMailer() const nodemailer = new NodeMailer()
const { wlogger } = require('../adapters/wlogger')
let _this let _this
@@ -60,4 +59,4 @@ class ContactLib {
} }
} }
} }
module.exports = ContactLib export default ContactLib
+4 -3
View File
@@ -5,8 +5,9 @@
for this file. for this file.
*/ */
const JwtLib = require('jwt-bch-lib') import JwtLib from 'jwt-bch-lib'
const BCHJS = require('@psf/bch-js')
import BCHJS from '@psf/bch-js'
class FullStackJWT { class FullStackJWT {
constructor (localConfig = {}) { constructor (localConfig = {}) {
@@ -98,4 +99,4 @@ class FullStackJWT {
} }
} }
module.exports = FullStackJWT export default FullStackJWT
+43 -16
View File
@@ -5,23 +5,25 @@
*/ */
// Public NPM libraries // Public NPM libraries
const BCHJS = require('@psf/bch-js') import BCHJS from '@psf/bch-js'
// Load individual adapter libraries. // Load individual adapter libraries.
const IPFSAdapter = require('./ipfs') import IPFSAdapter from './ipfs/index.js'
const LocalDB = require('./localdb') import LocalDB from './localdb/index.js'
const LogsAPI = require('./logapi') import LogsAPI from './logapi.js'
const Passport = require('./passport') import Passport from './passport.js'
const Nodemailer = require('./nodemailer') import Nodemailer from './nodemailer.js'
// const { wlogger } = require('./wlogger') // const { wlogger } = require('./wlogger')
const JSONFiles = require('./json-files') import JSONFiles from './json-files.js'
const FullStackJWT = require('./fullstack-jwt') import FullStackJWT from './fullstack-jwt.js'
const BCHAdapter = require('./bch') import config from '../../config/index.js'
const WalletAdapter = require('./wallet') // import Wallet from './wallet.adapter.js'
const P2wdbAdapter = require('./p2wdb-adapter')
const Webhook = require('./webhook')
const config = require('../../config') import BCHAdapter from './bch.js'
import WalletAdapter from './wallet.js'
import P2wdbAdapter from './p2wdb-adapter.js'
import Webhook from './webhook.js'
import NostrAdapter from './nostr.js'
class Adapters { class Adapters {
constructor (localConfig = {}) { constructor (localConfig = {}) {
@@ -37,8 +39,12 @@ class Adapters {
this.bch = new BCHAdapter() this.bch = new BCHAdapter()
this.config = config this.config = config
this.wallet = new WalletAdapter() this.wallet = new WalletAdapter()
localConfig.bchWallet = this.wallet.bchWallet
this.p2wdb = new P2wdbAdapter(localConfig) this.p2wdb = new P2wdbAdapter(localConfig)
this.webhook = new Webhook() this.webhook = new Webhook()
this.nostr = new NostrAdapter(this.config)
// this.wallet = new Wallet(localConfig)
// Get a valid JWT API key and instance bch-js. // Get a valid JWT API key and instance bch-js.
this.fullStackJwt = new FullStackJWT(config) this.fullStackJwt = new FullStackJWT(config)
@@ -46,14 +52,22 @@ class Adapters {
async start () { async start () {
try { try {
// let apiToken
if (this.config.getJwtAtStartup) { if (this.config.getJwtAtStartup) {
// Get a JWT token and instantiate bch-js with it. Then pass that instance // Get a JWT token and instantiate bch-js with it. Then pass that instance
// to all the rest of the apps controllers and adapters. // to all the rest of the apps controllers and adapters.
await this.fullStackJwt.getJWT() // apiToken = await this.fullStackJwt.getJWT()
// Instantiate bch-js with the JWT token, and overwrite the placeholder for bch-js. // Instantiate bch-js with the JWT token, and overwrite the placeholder for bch-js.
this.bchjs = await this.fullStackJwt.instanceBchjs() this.bchjs = await this.fullStackJwt.instanceBchjs()
} }
// Create a default instance of minimal-slp-wallet without initializing it
// (without retrieving the wallets UTXOs). This instance will be overwritten
// if the operator has configured BCH payments.
console.log('\nCreating default startup wallet. This wallet may be overwritten.')
// await this.wallet.instanceWalletWithoutInitialization({}, { apiToken })
this.bchjs = this.wallet.bchWallet.bchjs
// Start the IPFS node. // Start the IPFS node.
// Do not start these adapters if this is an e2e test. // Do not start these adapters if this is an e2e test.
// if (this.config.env !== 'test') { // if (this.config.env !== 'test') {
@@ -62,6 +76,8 @@ class Adapters {
// Open the wallet file // Open the wallet file
const walletData = await this.wallet.openWallet() const walletData = await this.wallet.openWallet()
await this.nostr.start(walletData.privateKey)
// console.log('walletData: ', walletData) // console.log('walletData: ', walletData)
if (this.config.env !== 'test') { if (this.config.env !== 'test') {
@@ -69,7 +85,18 @@ class Adapters {
await this.wallet.instanceWallet(walletData, this.bchjs) await this.wallet.instanceWallet(walletData, this.bchjs)
// Wait until a webhook is established with the P2WDB // Wait until a webhook is established with the P2WDB
await this.webhook.waitUntilSuccess(this.config.webhookTarget) // await this.webhook.waitUntilSuccess(this.config.webhookTarget)
// Overwrite instances of wallet used by P2WDB lib.
this.p2wdb.bchWallet = this.wallet.bchWallet
this.p2wdb.bchjs = this.wallet.bchWallet.bchjs
if (this.config.useIpfs) {
await this.ipfs.start()
}
} else {
// These lines are here to ensure code coverage hits 100%.
console.log('Not starting IPFS node since this is an e2e test.')
} }
console.log('Async Adapters have been started.') console.log('Async Adapters have been started.')
@@ -82,4 +109,4 @@ class Adapters {
} }
} }
module.exports = Adapters export default Adapters
+143 -4
View File
@@ -3,8 +3,10 @@
*/ */
// Local libraries // Local libraries
const IpfsAdapter = require('./ipfs') import IpfsAdapter from './ipfs.js'
const IpfsCoordAdapter = require('./ipfs-coord')
import IpfsCoordAdapter from './ipfs-coord.js'
import config from '../../../config/index.js'
class IPFS { class IPFS {
constructor (localConfig = {}) { constructor (localConfig = {}) {
@@ -12,6 +14,7 @@ class IPFS {
this.ipfsAdapter = new IpfsAdapter() this.ipfsAdapter = new IpfsAdapter()
this.IpfsCoordAdapter = IpfsCoordAdapter this.IpfsCoordAdapter = IpfsCoordAdapter
this.process = process this.process = process
this.config = config
this.ipfsCoordAdapter = {} // placeholder this.ipfsCoordAdapter = {} // placeholder
@@ -32,7 +35,9 @@ class IPFS {
// Start ipfs-coord // Start ipfs-coord
this.ipfsCoordAdapter = new this.IpfsCoordAdapter({ this.ipfsCoordAdapter = new this.IpfsCoordAdapter({
ipfs: this.ipfs ipfs: this.ipfs,
tcpPort: this.config.ipfsTcpPort,
wsPort: this.config.ipfsWsPort
}) })
await this.ipfsCoordAdapter.start() await this.ipfsCoordAdapter.start()
console.log('ipfs-coord is ready.') console.log('ipfs-coord is ready.')
@@ -53,6 +58,140 @@ class IPFS {
throw err throw err
} }
} }
// Get the status of this IPFS node.
// Create an object with different metrics about this IPFS node, then return
// the object.
getStatus () {
try {
const statusObj = {
ipfsId: this.ipfsCoordAdapter.ipfsCoord.thisNode.ipfsId,
multiAddrs: this.ipfsCoordAdapter.ipfsCoord.thisNode.ipfsMultiaddrs,
bchAddr: this.ipfsCoordAdapter.ipfsCoord.thisNode.bchAddr,
slpAddr: this.ipfsCoordAdapter.ipfsCoord.thisNode.slpAddr,
pubKey: this.ipfsCoordAdapter.ipfsCoord.thisNode.pubKey,
peers: this.ipfsCoordAdapter.ipfsCoord.thisNode.peerList.length,
relays: this.ipfsCoordAdapter.ipfsCoord.thisNode.relayData.length
}
return statusObj
} catch (err) {
console.error('Error in ipfs-coord.js/getStatus()')
throw err
}
}
// Get details on the other peers this node is connected to.
async getPeers (showAll) {
try {
const peerData = this.ipfsCoordAdapter.ipfsCoord.thisNode.peerData
// console.log(`peerData: ${JSON.stringify(peerData, null, 2)}`)
let ipfsPeers =
await this.ipfsCoordAdapter.ipfsCoord.adapters.ipfs.getPeers()
// console.log('ipfsPeers: ', ipfsPeers)
ipfsPeers = this._removeDuplicatePeers(ipfsPeers)
// console.log('filtered ipfsPeers: ', ipfsPeers)
const peerDataOut = []
// Loop through each IPFS peer and hydrate it with data from the peerData.
for (let i = 0; i < ipfsPeers.length; i++) {
const thisPeer = {
peer: ipfsPeers[i]
}
// if (!showAll) {
// // Delete properties that don't contain good info.
// delete thisPeer.muxer
// delete thisPeer.latency
// delete thisPeer.streams
// }
// Get the ipfs-coord peer data for this peer.
let thisPeerData = peerData.filter((x) =>
x.from.includes(thisPeer.peer)
)
thisPeerData = thisPeerData[0]
// console.log('thisPeerData: ', thisPeerData)
// Skip if peerData for this IPFS peer could not be found.
// if (!thisPeerData) continue
try {
// console.log('thisPeerData: ', thisPeerData)
// Add data to the IPFS peer data.
thisPeer.name = thisPeerData.data.jsonLd.name
thisPeer.protocol = thisPeerData.data.jsonLd.protocol
thisPeer.version = thisPeerData.data.jsonLd.version
thisPeer.connectionAddr = thisPeerData.data.connectionAddr
if (showAll) {
// Add all the peer data.
thisPeer.peerData = thisPeerData
}
} catch (err) {
console.warn(
`warning: ${thisPeer.peer}: ${err.message}`
)
}
peerDataOut.push(thisPeer)
}
return peerDataOut
} catch (err) {
console.error('Error in getPeers(): ', err)
throw err
}
}
// Expects an array of peers and returns an array of peers with duplicates
// removed.
// This function is used by getPeers()
_removeDuplicatePeers (arr) {
// https://stackoverflow.com/questions/2218999/how-to-remove-all-duplicates-from-an-array-of-objects
return arr.filter((v, i, a) => a.findIndex((t) => t === v) === i)
}
// Get data about the known Circuit Relays. Hydrate with data from peers list.
getRelays () {
try {
const relayData = this.ipfsCoordAdapter.ipfsCoord.thisNode.relayData
const peerData = this.ipfsCoordAdapter.ipfsCoord.thisNode.peerData
// console.log(`relayData: ${JSON.stringify(relayData, null, 2)}`)
// console.log(`peerData: ${JSON.stringify(peerData, null, 2)}`)
for (let i = 0; i < relayData.length; i++) {
const thisRelay = relayData[i]
// Find the peer that corresponds to this relay.
const thisPeer = peerData.filter((x) =>
x.from.includes(thisRelay.ipfsId)
)
// console.log('thisPeer: ', thisPeer)
// If the peer couldn't be found, skip.
if (!thisPeer.length) {
thisRelay.name = ''
thisRelay.description = ''
continue
}
thisRelay.name = thisPeer[0].data.jsonLd.name
thisRelay.description = thisPeer[0].data.jsonLd.description
}
const v1Relays = this.config.v1Relays
return { v2Relays: relayData, v1Relays }
} catch (err) {
console.error('Error in getRelays(): ', err)
throw err
}
}
} }
module.exports = IPFS export default IPFS
+31 -15
View File
@@ -5,12 +5,16 @@
*/ */
// Global npm libraries // Global npm libraries
const IpfsCoord = require('ipfs-coord') // import IpfsCoord from 'ipfs-coord-esm'
const BCHJS = require('@psf/bch-js') import IpfsCoord from 'helia-coord'
const publicIp = require('public-ip')
// import BCHJS from '@psf/bch-js';
import SlpWallet from 'minimal-slp-wallet'
import { publicIpv4 } from 'public-ip'
// Local libraries // Local libraries
const config = require('../../../config') import config from '../../../config/index.js'
// const JSONRPC = require('../../controllers/json-rpc/') // const JSONRPC = require('../../controllers/json-rpc/')
let _this let _this
@@ -28,9 +32,10 @@ class IpfsCoordAdapter {
// Encapsulate dependencies // Encapsulate dependencies
this.IpfsCoord = IpfsCoord this.IpfsCoord = IpfsCoord
this.ipfsCoord = {} this.ipfsCoord = {}
this.bchjs = new BCHJS() // this.bchjs = new BCHJS()
this.wallet = new SlpWallet()
this.config = config this.config = config
this.publicIp = publicIp this.publicIp = publicIpv4
// Properties of this class instance. // Properties of this class instance.
this.isReady = false this.isReady = false
@@ -41,10 +46,13 @@ class IpfsCoordAdapter {
async start () { async start () {
const circuitRelayInfo = {} const circuitRelayInfo = {}
// Wait for the BCH wallet to create the wallet.
await this.wallet.walletInfoPromise
// If configured as a Circuit Relay, get the public IP addresses for this node. // If configured as a Circuit Relay, get the public IP addresses for this node.
if (this.config.isCircuitRelay) { if (this.config.isCircuitRelay) {
try { try {
const ip4 = await this.publicIp.v4() const ip4 = await this.publicIp()
// const ip6 = await publicIp.v6() // const ip6 = await publicIp.v6()
circuitRelayInfo.ip4 = ip4 circuitRelayInfo.ip4 = ip4
@@ -57,23 +65,28 @@ class IpfsCoordAdapter {
} }
} }
const nullLog = () => {}
const ipfsCoordOptions = { const ipfsCoordOptions = {
ipfs: this.ipfs, ipfs: this.ipfs,
type: 'node.js', type: 'node.js',
// type: 'browser', // type: 'browser',
bchjs: this.bchjs, wallet: this.wallet,
privateLog: console.log, // Default to console.log // privateLog: console.log, // Default to console.log
privateLog: nullLog,
isCircuitRelay: this.config.isCircuitRelay, isCircuitRelay: this.config.isCircuitRelay,
circuitRelayInfo, circuitRelayInfo,
apiInfo: this.config.apiInfo, apiInfo: this.config.apiInfo,
announceJsonLd: this.config.announceJsonLd, announceJsonLd: this.config.announceJsonLd,
debugLevel: this.config.debugLevel debugLevel: this.config.debugLevel,
v1Relays: this.config.v1Relays,
tcpPort: this.config.ipfsTcpPort
} }
// Production env uses external go-ipfs node. // Production env uses external go-ipfs node.
if (this.config.isProduction) { // if (this.config.isProduction) {
ipfsCoordOptions.nodeType = 'external' // ipfsCoordOptions.nodeType = 'external'
} // }
this.ipfsCoord = new this.IpfsCoord(ipfsCoordOptions) this.ipfsCoord = new this.IpfsCoord(ipfsCoordOptions)
@@ -100,12 +113,15 @@ class IpfsCoordAdapter {
// Subscribe to the chat pubsub channel // Subscribe to the chat pubsub channel
async subscribeToChat () { async subscribeToChat () {
// TODO: Allow user to replace nullog with their own log handler at startup.
const nullLog = () => {}
await this.ipfsCoord.adapters.pubsub.subscribeToPubsubChannel( await this.ipfsCoord.adapters.pubsub.subscribeToPubsubChannel(
this.config.chatPubSubChan, this.config.chatPubSubChan,
console.log, nullLog,
this.ipfsCoord.thisNode this.ipfsCoord.thisNode
) )
} }
} }
module.exports = IpfsCoordAdapter export default IpfsCoordAdapter
+257 -81
View File
@@ -9,94 +9,98 @@
*/ */
// Global npm libraries // Global npm libraries
// const IPFS = require('ipfs') import { createHelia } from 'helia'
// const IPFS = require('@chris.troutner/ipfs') import fs from 'fs'
const IPFSembedded = require('ipfs') import { FsBlockstore } from 'blockstore-fs'
const IPFSexternal = require('ipfs-http-client') import { FsDatastore } from 'datastore-fs'
const fs = require('fs') import { createLibp2p } from 'libp2p'
const http = require('http') import { tcp } from '@libp2p/tcp'
import { noise } from '@chainsafe/libp2p-noise'
import { yamux } from '@chainsafe/libp2p-yamux'
// import { bootstrap } from '@libp2p/bootstrap'
// import { identifyService } from 'libp2p/identify'
import { identify, identifyPush } from '@libp2p/identify'
import { circuitRelayServer, circuitRelayTransport } from '@libp2p/circuit-relay-v2'
// import { circuitRelayServer } from '@libp2p/circuit-relay-v2'
import { gossipsub } from '@chainsafe/libp2p-gossipsub'
import { webSockets } from '@libp2p/websockets'
import { publicIpv4 } from 'public-ip'
import { multiaddr } from '@multiformats/multiaddr'
import { webRTC, webRTCDirect } from '@libp2p/webrtc'
import { keychain } from '@libp2p/keychain'
import { unixfs } from '@helia/unixfs'
// import { generateKeyPairFromSeed } from '@libp2p/crypto/keys'
// import crypto from 'crypto'
import { ping } from '@libp2p/ping'
import { loadOrCreateSelfKey } from '@libp2p/config'
// Local libraries // Local libraries
const config = require('../../../config') import config from '../../../config/index.js'
import JsonFiles from '../json-files.js'
const IPFS_DIR = './.ipfsdata/ipfs' // Hack to get __dirname back.
// https://blog.logrocket.com/alternatives-dirname-node-js-es-modules/
import * as url from 'url'
const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
// console.log('__dirname: ', __dirname)
const ROOT_DIR = `${__dirname}../../../`
const IPFS_DIR = `${__dirname}../../../.ipfsdata/ipfs`
class IpfsAdapter { class IpfsAdapter {
constructor (localConfig) { constructor (localConfig) {
// Encapsulate dependencies // Encapsulate dependencies
this.config = config this.config = config
this.fs = fs
// Choose the IPFS constructor based on the config settings. this.createLibp2p = createLibp2p
this.IPFS = IPFSembedded // default this.publicIp = publicIpv4
if (this.config.isProduction) { this.multiaddr = multiaddr
this.IPFS = IPFSexternal this.jsonFiles = new JsonFiles()
} this.keychain = keychain
this.createHelia = createHelia
// Properties of this class instance. // Properties of this class instance.
this.isReady = false this.isReady = false
this.fs = fs // Bind 'this' object to all subfunctions
this.start = this.start.bind(this)
this.createNode = this.createNode.bind(this)
this.stop = this.stop.bind(this)
this.ensureBlocksDir = this.ensureBlocksDir.bind(this)
// this.getPrivateKey = this.getPrivateKey.bind(this)
this.getSeed = this.getSeed.bind(this)
} }
// Start an IPFS node. // Start an IPFS node.
async start () { async start () {
try { try {
// Ipfs Options // Ensure the directory structure exists that is needed by the IPFS node to store data.
const ipfsOptionsEmbedded = { this.ensureBlocksDir()
repo: IPFS_DIR,
start: true,
config: {
relay: {
enabled: true, // enable circuit relay dialer and listener
hop: {
enabled: config.isCircuitRelay // enable circuit relay HOP (make this node a relay)
}
},
pubsub: true, // enable pubsub
Swarm: {
ConnMgr: {
HighWater: 30,
LowWater: 10
}
},
Addresses: {
Swarm: [
`/ip4/0.0.0.0/tcp/${this.config.ipfsTcpPort}`,
`/ip4/0.0.0.0/tcp/${this.config.ipfsWsPort}/ws`
]
},
Datastore: {
StorageMax: '2GB',
StorageGCWatermark: 50,
GCPeriod: '15m'
}
}
}
const ipfsOptionsExternal = { // Create an IPFS node
host: this.config.ipfsHost, const ipfs = await this.createNode()
port: this.config.ipfsApiPort, // console.log('ipfs: ', ipfs)
agent: http.Agent({ keepAlive: true, maxSockets: 2000 })
}
let ipfsOptions = ipfsOptionsEmbedded this.id = ipfs.libp2p.peerId.toString()
if (this.config.isProduction) { console.log('IPFS ID: ', this.id)
ipfsOptions = ipfsOptionsExternal
}
// Create a new IPFS node. // Attempt to guess our ip4 IP address.
this.ipfs = await this.IPFS.create(ipfsOptions) const ip4 = await this.publicIp()
let detectedMultiaddr = `/ip4/${ip4}/tcp/${this.config.ipfsTcpPort}/p2p/${this.id}`
detectedMultiaddr = this.multiaddr(detectedMultiaddr)
// Set the 'server' profile so the node does not scan private networks. // Get the multiaddrs for the node.
await this.ipfs.config.profiles.apply('server') const multiaddrs = ipfs.libp2p.getMultiaddrs()
multiaddrs.push(detectedMultiaddr)
console.log('Multiaddrs: ', multiaddrs)
// Debugging: Display IPFS config settings. this.multiaddrs = multiaddrs
// const configSettings = await this.ipfs.config.getAll()
// console.log(`configSettings: ${JSON.stringify(configSettings, null, 2)}`)
// Signal that this adapter is ready. // Signal that this adapter is ready.
this.isReady = true this.isReady = true
this.ipfs = ipfs
return this.ipfs return this.ipfs
} catch (err) { } catch (err) {
console.error('Error in ipfs.js/start()') console.error('Error in ipfs.js/start()')
@@ -110,31 +114,203 @@ class IpfsAdapter {
} }
} }
// This function creates an IPFS node using Helia.
// It returns the node as an object.
async createNode () {
try {
// Create block and data stores.
const blockstore = new FsBlockstore(`${IPFS_DIR}/blockstore`)
const datastore = new FsDatastore(`${IPFS_DIR}/datastore`)
// Get the private key.
// const privateKey = await this.getPrivateKey()
// console.log('privateKey: ', privateKey)
// Create an identity
const keychainInit = {
selfKey: 'myKey',
pass: await this.getSeed()
}
const privateKey = await loadOrCreateSelfKey(datastore, keychainInit)
// Configure services
const services = {
identify: identify(),
identifyPush: identifyPush(),
pubsub: gossipsub({ allowPublishToZeroTopicPeers: true }),
ping: ping(),
keychain: keychain(keychainInit)
}
if (this.config.isCircuitRelay) {
console.log('Helia (IPFS) node IS configured as Circuit Relay')
services.relay = circuitRelayServer({ // makes the node function as a relay server
hopTimeout: 30 * 1000, // incoming relay requests must be resolved within this time limit
reservations: {
maxReservations: 15, // how many peers are allowed to reserve relay slots on this server
reservationClearInterval: 300 * 1000, // how often to reclaim stale reservations
applyDefaultLimit: true, // whether to apply default data/duration limits to each relayed connection
defaultDurationLimit: 2 * 60 * 1000, // the default maximum amount of time a relayed connection can be open for
defaultDataLimit: BigInt(2 << 7) // the default maximum number of bytes that can be transferred over a relayed connection
},
maxInboundHopStreams: 32, // how many inbound HOP streams are allow simultaneously
maxOutboundHopStreams: 64 // how many outbound HOP streams are allow simultaneously
})
} else {
console.log('Helia (IPFS) node IS NOT configured as Circuit Relay')
}
const transports = [
tcp(),
webSockets(),
circuitRelayTransport({
discoverRelays: 3,
reservationConcurrency: 3
}),
webRTC(),
webRTCDirect()
]
// libp2p is the networking layer that underpins Helia
const libp2p = await this.createLibp2p({
// peerId,
privateKey,
datastore,
addresses: {
listen: [
'/ip4/127.0.0.1/tcp/0',
`/ip4/0.0.0.0/tcp/${this.config.ipfsTcpPort}`,
`/ip4/0.0.0.0/tcp/${this.config.ipfsWsPort}/ws`,
'/webrtc',
'/p2p-circuit'
]
},
transports,
connectionEncrypters: [
noise()
],
streamMuxers: [
yamux()
],
services
})
// create a Helia node
const helia = await this.createHelia({
blockstore,
datastore,
libp2p
})
// Attach IPFS file system.
const fs = unixfs(helia)
helia.fs = fs
return helia
} catch (err) {
console.error('Error creating Helia node: ', err)
throw err
}
}
async stop () { async stop () {
await this.ipfs.stop() await this.ipfs.stop()
return true return true
} }
// Remove the '/blocks' directory that is used to store IPFS data. // Ensure that the directories exist to store blocks from the IPFS network.
// Dev Note: It's assumed this node is not pinning any data and that // This function is called at startup, before the IPFS node is started.
// everything in this directory is transient. This folder will regularly ensureBlocksDir () {
// fill up and prevent IPFS from starting. try {
// rmBlocksDir () { !this.fs.existsSync(`${ROOT_DIR}.ipfsdata`) && this.fs.mkdirSync(`${ROOT_DIR}.ipfsdata`)
// try {
// const dir = `${IPFS_DIR}/blocks` !this.fs.existsSync(`${IPFS_DIR}`) && this.fs.mkdirSync(`${IPFS_DIR}`)
// console.log(`Deleting ${dir} directory...`)
// !this.fs.existsSync(`${IPFS_DIR}/blockstore`) && this.fs.mkdirSync(`${IPFS_DIR}/blockstore`)
// this.fs.rmdirSync(dir, { recursive: true })
// !this.fs.existsSync(`${IPFS_DIR}/datastore`) && this.fs.mkdirSync(`${IPFS_DIR}/datastore`)
// console.log(`${dir} directory is deleted!`)
// !this.fs.existsSync(`${IPFS_DIR}/datastore/pkcs8`) && this.fs.mkdirSync(`${IPFS_DIR}/datastore/pkcs8`)
// return true // Signal successful execution.
// } catch (err) { // !fs.existsSync(`${IPFS_DIR}/datastore/peers`) && fs.mkdirSync(`${IPFS_DIR}/datastore/peers`)
// console.log('Error in rmBlocksDir()')
// throw err return true
// } } catch (err) {
console.error('Error in adapters/ipfs.js/ensureBlocksDir(): ', err)
throw err
}
}
// This function opens the seed used to generate the key for this IPFS peer.
// The seed is stored in a JSON file. If it doesn't exist, a new one is created.
async getSeed () {
try {
let seed
const filename = `${IPFS_DIR}/seed.json`
try {
// Try to read the JSON file containing the seed.
seed = await this.jsonFiles.readJSON(filename)
} catch (err) {
const seedNum = Math.floor(Math.random() * 1000000000000000000000)
seed = seedNum.toString()
// Save the newly generated seed
await this.jsonFiles.writeJSON(seed, filename)
}
// console.log('getSeed() seed: ', seed)
return seed
} catch (err) {
console.error('Error in adapters/ipfs/ipfs.js/getSeed()')
throw err
}
}
// Get the private key from disk, or generate a new one and save it,
// if it doesn't exist.
// async getPrivateKey () {
// try {
// const filename = `${IPFS_DIR}/privkey.json`
// let privKeyHex
// try {
// // Try to read the JSON file containing the seed.
// privKeyHex = await this.jsonFiles.readJSON(filename)
// // console.log('saved privKeyHex: ', privKeyHex)
// } catch (err) {
// // Generate a new private key and save it to disk.
// // Generate a new private key and save it to disk.
// const randomBuffer = crypto.randomBytes(32)
// // console.log('randomBuffer: ', randomBuffer)
// privKeyHex = randomBuffer.toString('hex')
// // console.log('new privKeyHex: ', privKeyHex)
// // Save the newly generated seed
// await this.jsonFiles.writeJSON(privKeyHex, filename)
// }
// // Convert the saved hex string to a buffer.
// const privKeyBuf = Buffer.from(privKeyHex, 'hex')
// // Convert the buffer to a Uint8Array 'seed'
// const seed = new Uint8Array(privKeyBuf.buffer, privKeyBuf.byteOffset, privKeyBuf.byteLength)
// // console.log('seed: ', seed)
// // Generate a ED25519 key pair.
// const privKey = await generateKeyPairFromSeed('Ed25519', seed)
// return privKey
// } catch (err) {
// console.error('Error in adapters/ipfs/ipfs.js/getPrivateKey(): ', err)
// throw err
// }
// } // }
} }
module.exports = IpfsAdapter export default IpfsAdapter
+3 -3
View File
@@ -1,8 +1,8 @@
/* /*
A utility file for reading and writing JSON files. A utility file for reading and writing JSON files.
*/ */
'use strict'
const fs = require('fs') import fs from 'fs'
let _this let _this
@@ -75,4 +75,4 @@ class JsonFiles {
} }
} }
module.exports = JsonFiles export default JsonFiles
+15 -5
View File
@@ -3,10 +3,15 @@
*/ */
// Load Mongoose models. // Load Mongoose models.
const Users = require('./models/users') import Users from './models/users.js'
const Entries = require('./models/entry') import Entries from './models/entry.js'
const Order = require('./models/order') import Order from './models/order.js'
const Offer = require('./models/offer') import Offer from './models/offer.js'
import Usage from './models/usage.js'
import SmAccount from './models/smAccount.js'
import DeletedChat from './models/deletedChat.js'
import DeletedPost from './models/deletedPost.js'
import CounterOffer from './models/counter-offer.js'
class LocalDB { class LocalDB {
constructor () { constructor () {
@@ -15,7 +20,12 @@ class LocalDB {
this.Entry = Entries this.Entry = Entries
this.Order = Order this.Order = Order
this.Offer = Offer this.Offer = Offer
this.Usage = Usage
this.SmAccount = SmAccount
this.DeletedChat = DeletedChat
this.DeletedPost = DeletedPost
this.CounterOffer = CounterOffer
} }
} }
module.exports = LocalDB export default LocalDB
@@ -0,0 +1,14 @@
import mongoose from 'mongoose'
const CounterOffer = new mongoose.Schema({
nostrEventId: { type: String, required: true }, // Nostr Event Id.
takerAddr: { type: String, default: null },
takerNpub: { type: String, default: null },
makerNpub: { type: String, default: null },
counterOfferAddr: { type: String, default: null },
counterOfferUtxo: { type: String, default: null },
takerOfferUtxo: { type: String, default: null },
tokenId: { type: String, default: null }
})
export default mongoose.model('counterOffer', CounterOffer)
@@ -0,0 +1,16 @@
/*
Database model for tracking deleted Nostr chat messages.
*/
import mongoose from 'mongoose'
const DeletedChat = new mongoose.Schema({
eventId: { type: String, required: true, default: null }, // Event ID of the deleted message.
npub: { type: String, default: null }, // Nostr public key of the user who created the message.
bchAddr: { type: String, default: null }, // bch address of the user who created the message.
pubkey: { type: String, default: null }, // Nostr public key of the user who created the message.
createdAt: { type: Date, default: Date.now },
updatedAt: { type: Date, default: Date.now }
})
export default mongoose.model('deletedChat', DeletedChat)
@@ -0,0 +1,16 @@
/*
Database model for tracking deleted Nostr posts.
*/
import mongoose from 'mongoose'
const DeletedPost = new mongoose.Schema({
eventId: { type: String, required: true, default: null }, // Event ID of the deleted post.
npub: { type: String, default: null }, // Nostr public key of the user who created the post.
bchAddr: { type: String, default: null }, // bch address of the user who created the post.
pubkey: { type: String, default: null }, // Nostr public key of the user who created the post.
createdAt: { type: Date, default: Date.now },
updatedAt: { type: Date, default: Date.now }
})
export default mongoose.model('deletedPost', DeletedPost)
+2 -2
View File
@@ -1,4 +1,4 @@
const mongoose = require('mongoose') import mongoose from 'mongoose'
const Entry = new mongoose.Schema({ const Entry = new mongoose.Schema({
entry: { type: String }, entry: { type: String },
@@ -10,4 +10,4 @@ const Entry = new mongoose.Schema({
merit: { type: Number } merit: { type: Number }
}) })
module.exports = mongoose.model('entry', Entry) export default mongoose.model('entry', Entry)
+22 -4
View File
@@ -1,4 +1,4 @@
const mongoose = require('mongoose') import mongoose from 'mongoose'
const Offer = new mongoose.Schema({ const Offer = new mongoose.Schema({
@@ -6,7 +6,7 @@ const Offer = new mongoose.Schema({
tokenId: { type: String }, tokenId: { type: String },
utxoTxid: { type: String }, utxoTxid: { type: String },
utxoVout: { type: Number }, utxoVout: { type: Number },
ticker: { type: String }, ticker: { type: String, default: '' },
tokenType: { type: Number }, tokenType: { type: Number },
// Trade data // Trade data
@@ -18,6 +18,7 @@ const Offer = new mongoose.Schema({
p2wdbHash: { type: String }, p2wdbHash: { type: String },
offerStatus: { type: String }, offerStatus: { type: String },
makerAddr: { type: String }, makerAddr: { type: String },
makerNpub: { type: String, default: null },
// Authentication data // Authentication data
signature: { type: String }, signature: { type: String },
@@ -27,12 +28,29 @@ const Offer = new mongoose.Schema({
timestamp: { type: Number }, timestamp: { type: Number },
globalTimestamp: { type: String }, globalTimestamp: { type: String },
localTimestamp: { type: String }, localTimestamp: { type: String },
displayCategory: { type: String },
nsfw: { type: Boolean, default: false },
flags: { type: Array },
// SWaP Protocol Properties // SWaP Protocol Properties
lokadId: { type: String }, lokadId: { type: String },
messageType: { type: Number }, messageType: { type: Number },
messageClass: { type: Number } messageClass: { type: Number },
nostrEventId: { type: String }, // Nostr Event Id.
// Operator fee and address
operatorAddress: { type: String },
operatorPercentage: { type: Number },
// Token Data
immutableDataCid: { type: String, default: null },
mutableDataCid: { type: String, default: null },
tokenIconUrl: { type: String, default: null },
tokenData: { type: Object },
tokenCategories: { type: Array, default: [] },
tokenTags: { type: Array, default: [] },
userDataStr: { type: String }, // Token user data
lastUpdatedTokenData: { type: String, default: null } // ISO timestamp of the last time token data was updated.
}) })
module.exports = mongoose.model('offer', Offer) export default mongoose.model('offer', Offer)
+24 -13
View File
@@ -6,24 +6,25 @@
See the dev-docs/specification.md for details on each property. See the dev-docs/specification.md for details on each property.
*/ */
const mongoose = require('mongoose') import mongoose from 'mongoose'
const Order = new mongoose.Schema({ const Order = new mongoose.Schema({
// Token data // Token data
tokenId: { type: String }, tokenId: { type: String, required: true },
utxoTxid: { type: String }, utxoTxid: { type: String, required: true },
utxoVout: { type: Number }, utxoVout: { type: Number, required: true },
ticker: { type: String }, ticker: { type: String, required: true },
tokenType: { type: Number }, tokenType: { type: Number, required: true },
// Trade data // Trade data
buyOrSell: { type: String }, buyOrSell: { type: String, required: true },
numTokens: { type: Number }, numTokens: { type: Number, required: true },
rateInBaseUnit: { type: String }, rateInBaseUnit: { type: String, required: true },
minUnitsToExchange: { type: String }, minUnitsToExchange: { type: String },
p2wdbTxid: { type: String }, p2wdbTxid: { type: String },
p2wdbHash: { type: String }, p2wdbHash: { type: String },
makerAddr: { type: String }, makerAddr: { type: String, required: true },
makerNpub: { type: String, required: true },
// Authentication data // Authentication data
signature: { type: String }, signature: { type: String },
@@ -32,12 +33,22 @@ const Order = new mongoose.Schema({
offerPubKey: { type: String }, offerPubKey: { type: String },
// Wallet Data // Wallet Data
hdIndex: { type: Number }, // HD index address holding the UTXO for this offer. hdIndex: { type: Number, required: true }, // HD index address holding the UTXO for this offer.
// SWaP Protocol Properties // SWaP Protocol Properties
lokadId: { type: String }, lokadId: { type: String },
messageType: { type: Number }, messageType: { type: Number },
messageClass: { type: Number } messageClass: { type: Number },
nostrEventId: { type: String, required: true }, // Nostr Event Id.
// Additional properties found in createOrder
dataType: { type: String, required: true },
userId: { type: String, required: true },
// Operator fee and address
operatorAddress: { type: String },
operatorPercentage: { type: Number }
}) })
module.exports = mongoose.model('order', Order) export default mongoose.model('order', Order)
+25
View File
@@ -0,0 +1,25 @@
/*
Social Media Account Model.
This model is used to track content creators using the DEX
Nostr social media channel.
*/
import mongoose from 'mongoose'
const SmAccount = new mongoose.Schema({
npub: { type: String, required: true },
bchAddr: { type: String, required: true, default: '' },
pubkey: { type: String, required: true },
pfp: { type: String, default: '' },
createdAt: { type: Date, default: Date.now },
updatedAt: { type: Date, default: Date.now },
followerCnt: { type: Number, default: 0 },
followingCnt: { type: Number, default: 0 },
posts: { type: Number, default: 0 },
likes: { type: Number, default: 0 },
comments: { type: Number, default: 0 },
reposts: { type: Number, default: 0 }
})
export default mongoose.model('smAccount', SmAccount)
+15
View File
@@ -0,0 +1,15 @@
/*
Usage data model
*/
// Global npm libraries
import mongoose from 'mongoose'
const Usage = new mongoose.Schema({
ip: { type: String },
url: { type: String },
method: { type: String },
timestamp: { type: Date }
})
export default mongoose.model('usage', Usage)
+9 -5
View File
@@ -1,13 +1,17 @@
const mongoose = require('mongoose') // Global npm libraries
const bcrypt = require('bcryptjs') import mongoose from 'mongoose'
const config = require('../../../../config') import bcrypt from 'bcryptjs'
const jwt = require('jsonwebtoken') import jwt from 'jsonwebtoken'
// Local libraries
import config from '../../../../config/index.js'
const User = new mongoose.Schema({ const User = new mongoose.Schema({
type: { type: String, default: 'user' }, type: { type: String, default: 'user' },
name: { type: String }, name: { type: String },
username: { type: String }, username: { type: String },
password: { type: String, required: true }, password: { type: String, required: true },
mnemonic: { type: String, required: true },
email: { email: {
type: String, type: String,
required: true, required: true,
@@ -51,4 +55,4 @@ User.methods.generateToken = function generateToken () {
} }
// export default mongoose.model('user', User) // export default mongoose.model('user', User)
module.exports = mongoose.model('user', User) export default mongoose.model('user', User)
+2 -2
View File
@@ -3,7 +3,7 @@
orders from the datatabase. orders from the datatabase.
*/ */
const Order = require('./models/order') import Order from './models/order.js'
// let _this // let _this
@@ -39,4 +39,4 @@ class OrderPagination {
} }
} }
module.exports = OrderPagination export default OrderPagination
+9 -4
View File
@@ -1,9 +1,14 @@
const lineReader = require('line-reader') import lineReader from 'line-reader'
const fs = require('fs') import fs from 'fs'
const config = require('../../config') import config from '../../config/index.js'
// Hack to get __dirname back.
// https://blog.logrocket.com/alternatives-dirname-node-js-es-modules/
import * as url from 'url'
let _this let _this
const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
class LogsApi { class LogsApi {
constructor () { constructor () {
@@ -169,4 +174,4 @@ class LogsApi {
} }
} }
module.exports = LogsApi export default LogsApi
+4 -5
View File
@@ -3,11 +3,10 @@
*/ */
'use strict' 'use strict'
const nodemailer = require('nodemailer') import nodemailer from 'nodemailer'
const config = require('../../config') import config from '../../config/index.js'
import wlogger from './wlogger.js'
const { wlogger } = require('./wlogger')
let _this let _this
@@ -150,4 +149,4 @@ class NodeMailer {
} }
} }
module.exports = NodeMailer export default NodeMailer
+280
View File
@@ -0,0 +1,280 @@
/*
Adapter library for working with Nostr.
*/
// Global npm libraries
import BchNostr from 'bch-nostr'
import { RelayPool } from 'nostr'
import RetryQueue from '@chris.troutner/retry-queue'
import * as nip19 from 'nostr-tools/nip19'
import { base58_to_binary as base58Tobinary } from 'base58-js'
import { getPublicKey } from 'nostr-tools/pure'
class NostrAdapter {
constructor (localConfig = { nostrRelay: '', nostrTopic: '' }) {
this.relayWs = localConfig.nostrRelay //
this.topic = localConfig.nostrTopic
this.globalFeed = localConfig.nostrGlobalFeed
if (!this.relayWs) {
throw new Error(
'"nostrRelay" must be passed when instantiate NostrAdapter'
)
}
if (!this.topic) {
throw new Error(
'"nostrTopic" must be passed when instantiate NostrAdapter'
)
}
// Encapsulate dependencies
this.bchNostr = new BchNostr()
this.RelayPool = RelayPool
this.retryQueue = new RetryQueue({
concurrency: 1,
attempts: 5,
retryPeriod: 1000
})
// Bind the 'this' object
this.start = this.start.bind(this)
this.post = this.post.bind(this)
this.read = this.read.bind(this)
this.eventId2note = this.eventId2note.bind(this)
this.pubkey2npub = this.pubkey2npub.bind(this)
this.npub2pubkey = this.npub2pubkey.bind(this)
this.readGlobalFeed = this.readGlobalFeed.bind(this)
this.getFollowers = this.getFollowers.bind(this)
this.privKeyToNpub = this.privKeyToNpub.bind(this)
}
// Create nostr keys.
// NOTE: WIF must be provided in this function instead the constructor function
// we can provide it after app wallet creation.
async start (WIF) {
try {
if (!WIF || typeof WIF !== 'string') {
throw new Error('WIF must be a string!')
}
const { privKeyBuf, nostrPubKey } =
this.bchNostr.keys.createNostrPubKeyFromWif({ wif: WIF })
this.privKeyBuf = privKeyBuf
this.nostrPubKey = nostrPubKey
console.log(`Nostr Pub Key : ${nostrPubKey}`)
return true
} catch (error) {
console.log(`Error in nostr.js/start() ${error.message} `)
throw error
}
}
// Post a message over the instance-topic.
async post (msg = '') {
try {
if (!msg || typeof msg !== 'string') {
throw new Error('msg must be a string!')
}
const inObj = {
kind: 867,
privKeyBuf: this.privKeyBuf,
nostrPubKey: this.nostrPubKey,
relayWs: this.relayWs,
msg,
tags: [['t', this.topic]]
}
const eventId = await this.retryQueue.addToQueue(this.bchNostr.post.uploadToNostr, inObj)
return eventId
} catch (error) {
console.log(`Error in nostr.js/post() ${error.message} `)
throw error
}
}
// Read a message over the instance-topic.
async read (limit = 10) {
try {
if (typeof limit !== 'number' || limit < 1) {
throw new Error('Limit must be greater than 0')
}
const relays = [this.relayWs]
const pool = this.RelayPool(relays)
const nostrData = new Promise((resolve, reject) => {
const messages = []
pool.on('open', (relay) => {
// relay.subscribe('REQ', { ids: [eventId] })
relay.subscribe('REQ', { limit, kinds: [867], '#t': [this.topic] })
})
pool.on('eose', (relay) => {
relay.close()
resolve(messages)
})
pool.on('event', (relay, subId, ev) => {
// console.log('ev: ', ev)
messages.push({ content: ev.content, eventId: ev.id })
})
})
const messages = await nostrData
return messages
} catch (error) {
console.log(`Error in nostr.js/read() ${error.message} `)
throw error
}
}
// Convert an Event ID into a `noteabc..` syntax that Astral expects.
// This can be used to generate a link to Astral to display the post.
eventId2note (eventId) {
return nip19.noteEncode(eventId)
}
// Convert a pubkey into a `npubabc..` syntax that Astral expects.
pubkey2npub (pubkey) {
return nip19.npubEncode(pubkey)
}
npub2pubkey (npub) {
return nip19.decode(npub)
}
// Read the global feed.
async readGlobalFeed (inObj = {}) {
try {
const { limit = 10 } = inObj
if (typeof limit !== 'number' || limit < 1) {
throw new Error('Limit must be greater than 0')
}
const relays = [this.relayWs]
const pool = this.RelayPool(relays)
const nostrData = new Promise((resolve, reject) => {
const messages = []
pool.on('open', (relay) => {
// relay.subscribe('REQ', { ids: [eventId] })
relay.subscribe('REQ', { limit, kinds: [1], '#t': [this.globalFeed] })
})
pool.on('eose', (relay) => {
relay.close()
resolve(messages)
})
pool.on('event', (relay, subId, ev) => {
// console.log('ev: ', ev)
const { content, id, tags, pubkey } = ev
const msg = {
content,
id,
tags,
npub: this.pubkey2npub(pubkey),
pubkey
}
messages.push(msg)
})
})
const messages = await nostrData
return messages
} catch (error) {
console.log(`Error in nostr.js/readGlobalFeed() ${error.message} `)
throw error
}
}
async getFollowers (inObj = {}) {
try {
const { pubkey } = inObj
if (!pubkey || typeof pubkey !== 'string') {
throw new Error('pubkey must be a string!')
}
const relays = [this.relayWs]
const pool = this.RelayPool(relays)
const nostrData = new Promise((resolve, reject) => {
const followers = []
pool.on('open', (relay) => {
// Query for kind 3 events where the target pubkey appears in tags
// This finds all contact lists that include the target pubkey
relay.subscribe('subid', {
limit: 100,
kinds: [3],
'#p': [pubkey] // Filter by tag 'p' containing the target pubkey
})
})
pool.on('eose', relay => {
relay.close()
resolve(followers)
})
pool.on('event', (relay, subId, ev) => {
// Each event represents a contact list from someone who follows the target
// The author of this event is a follower
const follower = {
pubkey: ev.pubkey,
npub: this.pubkey2npub(ev.pubkey),
contactList: ev.tags,
createdAt: ev.created_at
}
followers.push(follower)
})
})
const followers = await nostrData
return followers
} catch (error) {
console.log(`Error in nostr.js/getFollowers() ${error.message} `)
throw error
}
}
// Convert a BCH private key (WIF) to a Nostr npub.
privKeyToNpub (privKey) {
try {
if (!privKey || typeof privKey !== 'string') {
throw new Error('privKey must be a string!')
}
// Extract the privaty key from the WIF, using this guide:
// https://learnmeabitcoin.com/technical/keys/private-key/wif/
const wifBuf = base58Tobinary(privKey)
const privBuf = wifBuf.slice(1, 33)
// console.log('privBuf: ', privBuf)
const nostrPubKey = getPublicKey(privBuf)
// console.log('nostrPubKey: ', nostrPubKey)
// Convert pubkey to npub
const nostrNpub = nip19.npubEncode(nostrPubKey)
// console.log('nostrNpub: ', nostrNpub)
return nostrNpub
} catch (error) {
console.log(`Error in nostr.js/privKeyToNpub() ${error.message} `)
throw error
}
}
}
export default NostrAdapter
+22 -9
View File
@@ -3,18 +3,20 @@
*/ */
// Public npm libraries. // Public npm libraries.
const axios = require('axios') import axios from 'axios'
const { Write, Read } = require('p2wdb/index')
import P2WDB from 'p2wdb-esm'
// Local libraries // Local libraries
const config = require('../../config') import config from '../../config/index.js'
const { Write, Read } = P2WDB
class P2wdbAdapter { class P2wdbAdapter {
constructor (localConfig = {}) { constructor (localConfig = {}) {
// Dependency injection // Dependency injection
this.bchjs = localConfig.bchjs this.bchWallet = localConfig.bchWallet
if (!this.bchjs) { if (!this.bchWallet) {
throw new Error('Must pass an instance of bch-js when instantiating p2wdb.js adapter.') throw new Error('Must pass an instance of minimal-slp-wallet as bchWallet when instantiating p2wdb.js adapter.')
} }
// Encapsulate dependencies // Encapsulate dependencies
@@ -22,9 +24,14 @@ class P2wdbAdapter {
this.config = config this.config = config
this.Write = Write this.Write = Write
this.Read = Read this.Read = Read
this.bchjs = this.bchWallet.bchjs
// Allow the localConfig to overwrite the config file values. // Allow the localConfig to overwrite the config file values.
this.p2wdbURL = localConfig.p2wdbURL || config.p2wdbUrl this.p2wdbURL = localConfig.p2wdbURL || config.p2wdbUrl
// Bind the 'this' object to all functions
this.write = this.write.bind(this)
this.checkForSufficientFunds = this.checkForSufficientFunds.bind(this)
} }
// Write some data to the P2WDB // Write some data to the P2WDB
@@ -51,6 +58,10 @@ class P2wdbAdapter {
// settings. // settings.
instantiateWriteLib (wif) { instantiateWriteLib (wif) {
try { try {
if (!wif) {
throw new Error('WIF input required when calling instantiateWriteLib()')
}
// Object used to configure the Write library. // Object used to configure the Write library.
let configObj = {} let configObj = {}
@@ -62,7 +73,8 @@ class P2wdbAdapter {
wif, wif,
serverURL: this.p2wdbURL, serverURL: this.p2wdbURL,
restURL: this.bchjs.restURL, restURL: this.bchjs.restURL,
apiToken: this.bchjs.apiToken apiToken: this.bchjs.apiToken,
bchWallet: this.bchWallet
} }
} else { } else {
// Use web 3 infrastructure. // Use web 3 infrastructure.
@@ -72,7 +84,8 @@ class P2wdbAdapter {
wif, wif,
serverURL: this.p2wdbURL, serverURL: this.p2wdbURL,
interface: 'consumer-api', interface: 'consumer-api',
restURL: this.config.consumerUrl restURL: this.config.consumerUrl,
bchWallet: this.bchWallet
} }
} }
@@ -104,4 +117,4 @@ class P2wdbAdapter {
} }
} }
module.exports = P2wdbAdapter export default P2wdbAdapter
+2 -2
View File
@@ -2,7 +2,7 @@
koa-passport is an authorization library used for different authentication schemes. koa-passport is an authorization library used for different authentication schemes.
*/ */
const passport = require('koa-passport') import passport from 'koa-passport'
let _this let _this
class Passport { class Passport {
@@ -32,4 +32,4 @@ class Passport {
} }
} }
module.exports = Passport export default Passport
+251
View File
@@ -0,0 +1,251 @@
/*
Wallet adapter. This library instantiates minimal-slp-wallet based on different
configuration settings. That single instance of minimal-slp-wallet is then
easily passed around the rest of this application.
*/
// Global npm libraries
import BchWallet from 'minimal-slp-wallet'
// Local libraries
import config from '../../config/index.js'
import JsonFiles from './json-files.js'
class Wallet {
constructor (localConfig = {}) {
// Encapsulate dependencies
this.config = config
this.BchWallet = BchWallet
this.jsonFiles = new JsonFiles()
// Bind 'this' object to all subfunctions
this.instanceWalletWithoutInitialization = this.instanceWalletWithoutInitialization.bind(this)
this._instanceWallet = this._instanceWallet.bind(this)
this.openWallet = this.openWallet.bind(this)
this.instanceWallet = this.instanceWallet.bind(this)
this.incrementNextAddress = this.incrementNextAddress.bind(this)
this.getKeyPair = this.getKeyPair.bind(this)
this.optimize = this.optimize.bind(this)
this.getBalance = this.getBalance.bind(this)
}
// This is used for initializing the wallet, without waiting to update the wallet
// UTXOs from the blockchain.
// This is useful when the wallet is simply needed to make calls to the blockchain,
// and there is no need to hydrate it with UTXO data.
async instanceWalletWithoutInitialization (walletData = {}, advancedConfig = {}) {
try {
// Use the apiToken from the config settings, if one is not passed-in at
// run-time.
if (!advancedConfig.apiToken) {
advancedConfig.apiToken = this.config.apiToken
}
// If an authentication password is passed in the config, add it.
if (this.config.authPass) {
advancedConfig.authPass = this.config.authPass
}
// Detect and configure different blockchain infrastructure settings.
if (this.config.walletInterface === 'web2') {
advancedConfig.interface = 'rest-api'
advancedConfig.restURL = this.config.apiServer
} else {
// By default use the web3 Cash Stack (https://cashstack.info)
advancedConfig.interface = 'consumer-api'
advancedConfig.restURL = this.config.apiServer
}
// console.log('advancedConfig setting when creating wallet: ', advancedConfig)
// Instantiate minimal-slp-wallet.
if (walletData.mnemonic) {
// Instance the wallet using the mnemonic passed in to this function.
console.log('Mnemonic provided to wallet library from calling function.')
this.bchWallet = await this._instanceWallet(walletData.mnemonic, advancedConfig)
} else if (this.config.mnemonic) {
// Otherwise use the mnemonic in the config setting or passed as an environment variable.
console.log('Mnemonic retrieved from config file or environment variable.')
this.bchWallet = await this._instanceWallet(this.config.mnemonic, advancedConfig)
} else {
// If no mnemonic is provided, then generate a new mnemonic to create the wallet.
console.log('New mnemonic generated.')
this.bchWallet = await this._instanceWallet(undefined, advancedConfig)
}
// Wait for wallet to initialize.
await this.bchWallet.walletInfoPromise
console.log('BCH wallet initialized.')
console.log(`Wallet address: ${this.bchWallet.walletInfo.cashAddress}`)
console.log(`Wallet mnemonic: ${this.bchWallet.walletInfo.mnemonic}`)
return this.bchWallet
} catch (err) {
console.error('Error in instanceWalletWithoutInitialization()')
throw err
}
}
// This function is used for easier mocking of unit tests.
async _instanceWallet (mnemonic, config) {
const wallet = new this.BchWallet(mnemonic, config)
await wallet.walletInfoPromise
return wallet
}
// 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 (advancedConfig = {}) {
try {
let walletData
// Try to open the wallet.json file.
try {
walletData = await this.jsonFiles.readJSON(this.config.walletFile)
walletData = walletData.wallet
} catch (err) {
// Create a new wallet file if one does not already exist.
console.log('Wallet file not found. Creating new wallet.json file.')
// Create a new wallet.
// No-Update flag creates wallet without making any network calls.
const walletInstance = await this.instanceWalletWithoutInitialization({}, advancedConfig)
walletData = walletInstance.walletInfo
// Add the nextAddress property
walletData.nextAddress = 1
// Write the wallet data to the JSON file.
await this.jsonFiles.writeJSON({ wallet: walletData }, this.config.walletFile)
}
// console.log('walletData: ', walletData)
return walletData
} catch (err) {
console.error('Error in openWallet()')
throw err
}
}
// Create an instance of minimal-slp-wallet. Same as
// instanceWalletWithoutInitialization(), but waits for the wallet to initialize
// its UTXOs (wallet balance and tokens).
async instanceWallet (walletData = {}, advancedConfig = {}) {
try {
// Instance the wallet without initialization.
await this.instanceWalletWithoutInitialization(walletData, advancedConfig)
// Initialize the wallet
await this.bchWallet.initialize()
return this.bchWallet
} catch (err) {
console.error('Error in wallet.js/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.
// This function opens the wallet file, increments the nextAddress property,
// then saves the change to the wallet file.
async incrementNextAddress () {
try {
const walletData = await this.openWallet()
await this.instanceWalletWithoutInitialization(walletData)
walletData.nextAddress++
// console.log('walletData finish: ', walletData)
await this.jsonFiles.writeJSON({ wallet: walletData }, this.config.walletFile)
// Update the working instance of the wallet.
this.bchWallet.walletInfo.nextAddress++
// console.log('this.bchWallet.walletInfo: ', this.bchWallet.walletInfo)
return walletData.nextAddress
} catch (err) {
console.error('Error in incrementNextAddress()')
throw err
}
}
// This method returns an object that contains a private key WIF, public address,
// and the index of the HD wallet that the key pair was generated from.
// TODO: Allow input integer. If input is used, use that as the index. If no
// input is provided, then call incrementNextAddress().
async getKeyPair (hdIndex = 0) {
try {
if (!hdIndex) {
// Increment the HD index and generate a new key pair.
hdIndex = await this.incrementNextAddress()
}
const mnemonic = this.bchWallet.walletInfo.mnemonic
// root seed buffer
const rootSeed = await this.bchWallet.bchjs.Mnemonic.toSeed(mnemonic)
const masterHDNode = this.bchWallet.bchjs.HDNode.fromSeed(rootSeed)
// HDNode of BIP44 account
// const account = this.bchWallet.bchjs.HDNode.derivePath(masterHDNode, "m/44'/245'/0'")
const childNode = masterHDNode.derivePath(`m/44'/245'/0'/0/${hdIndex}`)
const cashAddress = this.bchWallet.bchjs.HDNode.toCashAddress(childNode)
console.log('Generating a new key pair for cashAddress: ', cashAddress)
const wif = this.bchWallet.bchjs.HDNode.toWIF(childNode)
const outObj = {
cashAddress,
wif,
hdIndex
}
return outObj
} catch (err) {
console.error('Error in getKeyPair()')
throw err
}
}
// Optimize the wallet by consolidating the UTXOs.
async optimize () {
const UTXO_THREASHOLD = 7
// Do a dry-run first to see if there are enough UTXOs worth consolidating.
const dryRunOut = await this.bchWallet.optimize(true)
if (dryRunOut.bchUtxoCnt > UTXO_THREASHOLD) {
// Consolidate BCH UTXOs if the count is above the threashold.
const txids = await this.bchWallet.optimize()
console.log(`Wallet optimized with these return values: ${JSON.stringify(txids, null, 2)}`)
}
return true
}
// Get the balance of the wallet in sats and PSF tokens.
// This function is called by the GET /entry/balance controller.
async getBalance () {
const balance = await this.bchWallet.getBalance()
// console.log('balance: ', balance)
const tokens = await this.bchWallet.listTokens()
// console.log('tokens: ', tokens)
// Find the array entry for the PSF token
const psfTokens = tokens.find(x => x.tokenId === '38e97c5d7d3585a2cbf3f9580c82ca33985f9cb0845d4dcce220cb709f9538b0')
// console.log('psfTokens: ', psfTokens)
let psfBalance = 0
if (psfTokens) {
psfBalance = psfTokens.qty
}
const outObj = {
satBalance: balance,
psfBalance,
success: true
}
return outObj
}
}
export default Wallet
+215 -17
View File
@@ -1,28 +1,62 @@
/* /*
Adapter library for working with a wallet. Adapter library for working with a wallet.
This library is specific to bch-dex. The other wallet adapter library is
inherited from ipfs-service-provider.
*/ */
// Public npm libraries // Public npm libraries
const BchWallet = require('minimal-slp-wallet/index') import BchWallet from 'minimal-slp-wallet'
const bitcoinJs = require('bitcoincashjs-lib') import BchTokenSweep from 'bch-token-sweep/index.js'
import bitcoinJs from 'bitcoincashjs-lib'
import RetryQueue from '@chris.troutner/retry-queue'
// Local libraries // Local libraries
const JsonFiles = require('./json-files') import JsonFiles from './json-files.js'
const config = require('../../config') import config from '../../config/index.js'
// Hack to get __dirname back.
// https://blog.logrocket.com/alternatives-dirname-node-js-es-modules/
import * as url from 'url'
const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
const WALLET_FILE = `${__dirname.toString()}/../../wallet.json` const WALLET_FILE = `${__dirname.toString()}/../../wallet.json`
// const PROOF_OF_BURN_QTY = 0.01 // const PROOF_OF_BURN_QTY = 0.01
// const P2WDB_TOKEN_ID = // const P2WDB_TOKEN_ID =
// '38e97c5d7d3585a2cbf3f9580c82ca33985f9cb0845d4dcce220cb709f9538b0' // '38e97c5d7d3585a2cbf3f9580c82ca33985f9cb0845d4dcce220cb709f9538b0'
const advancedConfig = {}
class WalletAdapter { class WalletAdapter {
constructor (localConfig = {}) { constructor (localConfig = {}) {
// Encapsulate dependencies // Encapsulate dependencies
this.jsonFiles = new JsonFiles() this.jsonFiles = new JsonFiles()
this.WALLET_FILE = WALLET_FILE this.WALLET_FILE = WALLET_FILE
this.BchWallet = BchWallet
this.config = config this.config = config
this.bitcoinJs = bitcoinJs this.bitcoinJs = bitcoinJs
this.BchWallet = BchWallet
this.BchTokenSweep = BchTokenSweep
this.bchWallet = {} // Will be replaced when initialized.
// this.advancedConfig = localConfig.advancedConfig
this.retryQueue = new RetryQueue({
concurrency: 1,
attempts: 5,
retryPeriod: 5000
})
// Bind the 'this' object
this.openWallet = this.openWallet.bind(this)
this.instanceWallet = this.instanceWallet.bind(this)
this.incrementNextAddress = this.incrementNextAddress.bind(this)
this.getKeyPair = this.getKeyPair.bind(this)
this.generateSignature = this.generateSignature.bind(this)
this.generatePartialTx = this.generatePartialTx.bind(this)
this.moveTokens = this.moveTokens.bind(this)
this.moveBch = this.moveBch.bind(this)
this.deseralizeTx = this.deseralizeTx.bind(this)
this.completeTx = this.completeTx.bind(this)
this.reclaimTokens = this.reclaimTokens.bind(this)
this.moveTokensFromCustomWallet = this.moveTokensFromCustomWallet.bind(this)
this.cid2json = this.cid2json.bind(this)
} }
// Open the wallet file, or create one if the file doesn't exist. // Open the wallet file, or create one if the file doesn't exist.
@@ -76,7 +110,8 @@ class WalletAdapter {
throw new Error('Wallet data is not formatted correctly. Can not read mnemonic in wallet file!') throw new Error('Wallet data is not formatted correctly. Can not read mnemonic in wallet file!')
} }
const advancedConfig = {} // const advancedConfig = {}
console.log(`Using FullStack.cash: ${this.config.useFullStackCash}`)
if (this.config.useFullStackCash) { if (this.config.useFullStackCash) {
advancedConfig.interface = 'rest-api' advancedConfig.interface = 'rest-api'
advancedConfig.restURL = this.config.apiServer advancedConfig.restURL = this.config.apiServer
@@ -91,6 +126,7 @@ class WalletAdapter {
// Wait for wallet to initialize. // Wait for wallet to initialize.
await this.bchWallet.walletInfoPromise await this.bchWallet.walletInfoPromise
await this.bchWallet.initialize()
console.log(`BCH wallet initialized. Wallet address: ${this.bchWallet.walletInfo.cashAddress}`) console.log(`BCH wallet initialized. Wallet address: ${this.bchWallet.walletInfo.cashAddress}`)
// console.log(`this.bchWallet.walletInfo: ${JSON.stringify(this.bchWallet.walletInfo, null, 2)}`) // console.log(`this.bchWallet.walletInfo: ${JSON.stringify(this.bchWallet.walletInfo, null, 2)}`)
@@ -127,10 +163,9 @@ class WalletAdapter {
} }
} }
// Note: This method uses the system wallet, not the user or admin wallet.
// This method returns an object that contains a private key WIF, public address, // This method returns an object that contains a private key WIF, public address,
// and the index of the HD wallet that the key pair was generated from. // and the index of the HD wallet that the key pair was generated from.
// TODO: Allow input integer. If input is used, use that as the index. If no
// input is provided, then call incrementNextAddress().
async getKeyPair (hdIndex = 0) { async getKeyPair (hdIndex = 0) {
try { try {
if (!hdIndex) { if (!hdIndex) {
@@ -139,6 +174,7 @@ class WalletAdapter {
} }
const mnemonic = this.bchWallet.walletInfo.mnemonic const mnemonic = this.bchWallet.walletInfo.mnemonic
console.log(`getKeyPair() for HD index: ${hdIndex} called on mnemonic: ${mnemonic}`)
// root seed buffer // root seed buffer
const rootSeed = await this.bchWallet.bchjs.Mnemonic.toSeed(mnemonic) const rootSeed = await this.bchWallet.bchjs.Mnemonic.toSeed(mnemonic)
@@ -171,7 +207,9 @@ class WalletAdapter {
// Generate a cryptographic signature, required to write to the P2WDB. // Generate a cryptographic signature, required to write to the P2WDB.
async generateSignature (message) { async generateSignature (message) {
try { try {
// TODO: Add input validation for message. if (!message || typeof message !== 'string') {
throw new Error('message is required!')
}
const privKey = this.bchWallet.walletInfo.privateKey const privKey = this.bchWallet.walletInfo.privateKey
@@ -328,7 +366,7 @@ class WalletAdapter {
throw err throw err
} }
// return true // return true
} }
// Move tokens to an address controlled by the HD wallet, to generate a // Move tokens to an address controlled by the HD wallet, to generate a
@@ -336,6 +374,12 @@ class WalletAdapter {
async moveTokens (inObj = {}) { async moveTokens (inObj = {}) {
try { try {
const { tokenId, qty } = inObj const { tokenId, qty } = inObj
if (!tokenId || typeof tokenId !== 'string') {
throw new Error('tokenId must be a string!')
}
if (!qty || typeof qty !== 'number') {
throw new Error('qty must be a number!')
}
const keyPair = await this.getKeyPair() const keyPair = await this.getKeyPair()
console.log('keyPair: ', keyPair) console.log('keyPair: ', keyPair)
@@ -347,7 +391,7 @@ class WalletAdapter {
} }
// Update the UTXO store of the wallet. // Update the UTXO store of the wallet.
await this.bchWallet.getUtxos() await this.bchWallet.initialize()
// Get the token type of the token being moved. // Get the token type of the token being moved.
// Combine Fungible and NFT token UTXOs. // Combine Fungible and NFT token UTXOs.
@@ -358,6 +402,10 @@ class WalletAdapter {
x => x.tokenId === tokenId x => x.tokenId === tokenId
) )
if (tokenUtxos.length === 0) {
throw new Error('tokenId not found!')
}
const txid = await this.bchWallet.sendTokens(receiver, 3) const txid = await this.bchWallet.sendTokens(receiver, 3)
const utxoInfo = { const utxoInfo = {
@@ -378,6 +426,10 @@ class WalletAdapter {
// generate a segregated UTXO. // generate a segregated UTXO.
async moveBch (amountSat) { async moveBch (amountSat) {
try { try {
if (!amountSat) {
throw new Error('amountSat is required!')
}
const keyPair = await this.getKeyPair() const keyPair = await this.getKeyPair()
console.log('keyPair: ', keyPair) console.log('keyPair: ', keyPair)
@@ -410,6 +462,10 @@ class WalletAdapter {
// representing the transaction. // representing the transaction.
async deseralizeTx (txHex) { async deseralizeTx (txHex) {
try { try {
// Input validation
if (!txHex || typeof txHex !== 'string') {
throw new Error('hex must be a string!')
}
// Ensure the URL points at FullStack.cash, since the web 3 infra does not // Ensure the URL points at FullStack.cash, since the web 3 infra does not
// yet support this call. // yet support this call.
const oldUrl = this.bchWallet.bchjs.RawTransactions.restURL const oldUrl = this.bchWallet.bchjs.RawTransactions.restURL
@@ -424,18 +480,33 @@ class WalletAdapter {
return txObj2 return txObj2
} catch (err) { } catch (err) {
console.error('Error in wallet.js/deserializePartialTx()') console.error('Error in wallet.js/deserializeTx()')
throw err throw err
} }
} }
// Complete the partially signed transaction by signing the first input, // Complete the partially signed transaction by signing the first input,
// then broadcasting the transaction to the network. // then broadcasting the transaction to the network.
async completeTx (hex, hdIndex) { async completeTx (hex, hdIndex, mnemonic) {
try { try {
// Input validation
if (!hex || typeof hex !== 'string') {
throw new Error('hex must be a string!')
}
if (typeof hdIndex !== 'number' || hdIndex < 0) {
throw new Error('hdIndex must be a non-negative number!')
}
if (!mnemonic || typeof mnemonic !== 'string') {
throw new Error('mnemonic must be a string!')
}
// console.log('hex: ', hex) // console.log('hex: ', hex)
console.log('completeTx() hdIndex: ', hdIndex)
console.log('completeTx() mnemonic: ', mnemonic)
const bchjs = this.bchWallet.bchjs // Instantiate the user wallet
const userWallet = await this.instanceWallet({ mnemonic })
const bchjs = userWallet.bchjs
// instance of transaction builder // instance of transaction builder
// const transactionBuilder = new bchjs.TransactionBuilder() // const transactionBuilder = new bchjs.TransactionBuilder()
@@ -458,8 +529,10 @@ class WalletAdapter {
// 'mainnet' // 'mainnet'
// ) // )
console.log('completeTx() userWallet.walletInfo: ', userWallet.walletInfo)
// Get the keypair for the address used in the Order // Get the keypair for the address used in the Order
const keyPair = await this.getKeyPair(hdIndex) const keyPair = await userWallet.getKeyPair(hdIndex)
console.log(`maker keyPair: ${JSON.stringify(keyPair, null, 2)}`) console.log(`maker keyPair: ${JSON.stringify(keyPair, null, 2)}`)
const makerECPair = bchjs.ECPair.fromWIF(keyPair.wif) const makerECPair = bchjs.ECPair.fromWIF(keyPair.wif)
@@ -491,7 +564,9 @@ class WalletAdapter {
// return csTxHex // return csTxHex
// Broadcast transaction to the network // Broadcast transaction to the network
const txid = await this.bchWallet.ar.sendTx(csTxHex) // const txid = await this.bchWallet.ar.sendTx(csTxHex)
const txid = await this.retryQueue.addToQueue(this.bchWallet.broadcast, { hex: csTxHex })
console.log('completeTx() txid: ', txid)
return txid return txid
} catch (err) { } catch (err) {
@@ -499,6 +574,129 @@ class WalletAdapter {
throw err throw err
} }
} }
// Given an Order database object, this function sends the tokens from the
// HD index where they are stored, back to the root address of the wallet.
async reclaimTokens (orderData = {}) {
try {
if (!orderData.hdIndex) {
throw new Error('orderData.hdIndex is required!')
}
// Get the key pair from the Order.
const keyPair = await this.getKeyPair(orderData.hdIndex)
console.log('keyPair: ', keyPair)
// Instantiate the wallet using the private key of the Order.
// const tempWallet = new this.BchWallet(keyPair.wif, advancedConfig)
// await tempWallet.initialize()
// Send the tokens from the Order to the root address.
// const receiver = {
// address: this.bchWallet.walletInfo.address,
// tokenId: orderData.tokenId,
// qty: orderData.numTokens
// }
// console.log('receiver: ', receiver)
//
// const txid = await tempWallet.sendTokens(receiver)
// Sweep the tokens to the root address.
const sweeper = new this.BchTokenSweep(
keyPair.wif,
this.bchWallet.walletInfo.privateKey,
this.bchWallet,
550,
this.bchWallet.walletInfo.cashAddress
)
await sweeper.populateObjectFromNetwork()
const hex = await sweeper.sweepTo(this.bchWallet.walletInfo.cashAddress)
const txid = await this.bchWallet.ar.sendTx(hex)
return txid
} catch (err) {
console.error('Error in wallet.js/reclaimTokens()')
throw err
}
}
// This function is consumed by the use-cases/order.js/createOrder() function.
// Tokens are moved from the primary address to a holding address to protect the Order UTXO.
async moveTokensFromCustomWallet (inObj = {}) {
try {
const { tokenId, qty, wallet } = inObj
// Input validation
if (!tokenId || typeof tokenId !== 'string') {
throw new Error('tokenId must be a string!')
}
if (!qty) {
throw new Error('qty must be a number!')
}
if (!wallet) {
throw new Error('wallet is required!')
}
// Replace the system wallet with the user wallet.
// this.bchWallet = wallet
// DEV Note: Storing all token Offers in index 2 of the HD wallet.
// This makes them easy to sweep, and can be uniquely identified by their UTXO.
// Note: use walle.getKeyPair() to use the user wallet. this.getKeyPair uses the system wallet.
const keyPair = await wallet.getKeyPair(2)
console.log('keyPair: ', keyPair)
const receiver = {
address: keyPair.cashAddress,
tokenId,
qty
}
console.log('receiver: ', receiver)
// Update the UTXO store of the wallet.
await wallet.initialize()
// Get the token type of the token being moved.
// Combine Fungible and NFT token UTXOs.
let tokenUtxos = wallet.utxos.utxoStore.slpUtxos.type1.tokens.concat(
wallet.utxos.utxoStore.slpUtxos.nft.tokens)
// Get token UTXOs that match the token in the order.
tokenUtxos = tokenUtxos.filter(
x => x.tokenId === tokenId
)
const txid = await wallet.sendTokens(receiver, 3)
const utxoInfo = {
txid,
vout: 1,
hdIndex: keyPair.hdIndex,
tokenType: tokenUtxos[0].tokenType
}
return utxoInfo
} catch (err) {
console.error('Error in wallet.js/moveTokensFromCustomWallet()')
throw err
}
}
async cid2json (urlOrCid) {
try {
// Input validation
if (!urlOrCid || typeof urlOrCid !== 'string') {
throw new Error('urlOrCid must be a string!')
}
// Extract the cid from the url or cid.
const cid = urlOrCid.split('/').pop()
console.log('cid to json: ', cid)
const jsonRes = await this.bchWallet.cid2json({ cid })
const json = jsonRes.json
// console.log('json: ', json)
return json
} catch (err) {
console.error('Error in wallet.js/cid2json()', err.message)
throw err
}
}
} }
module.exports = WalletAdapter export default WalletAdapter
+19 -16
View File
@@ -2,16 +2,19 @@
The (Clean Architecture) Adapter for manageing a webhook connection to P2WDB. The (Clean Architecture) Adapter for manageing a webhook connection to P2WDB.
*/ */
const config = require('../../config') import config from '../../config/index.js'
const axios = require('axios')
let _this import axios from 'axios'
class WebHook { class WebHook {
constructor () { constructor () {
_this = this this.config = config
_this.config = config this.axios = axios
_this.axios = axios this.sleepTime = 2000
this.createWebhook = this.createWebhook.bind(this)
this.deleteWebhook = this.deleteWebhook.bind(this)
this.waitUntilSuccess = this.waitUntilSuccess.bind(this)
this.sleep = this.sleep.bind(this)
} }
// REST petition to create a webhook in p2wdb-service // REST petition to create a webhook in p2wdb-service
@@ -21,14 +24,14 @@ class WebHook {
throw new Error('url must be a string') throw new Error('url must be a string')
} }
const endpoint = _this.config.webhookService const endpoint = this.config.webhookService
const obj = { const obj = {
appId: this.config.p2wdbAppId, appId: this.config.p2wdbAppId,
url url
} }
const result = await axios.post(endpoint, obj) const result = await this.axios.post(endpoint, obj)
return result.data return result.data
} catch (err) { } catch (err) {
@@ -44,14 +47,14 @@ class WebHook {
throw new Error('url must be a string') throw new Error('url must be a string')
} }
const endpoint = _this.config.webhookService const endpoint = this.config.webhookService
const obj = { const obj = {
appId: this.config.p2wdbAppId, appId: this.config.p2wdbAppId,
url url
} }
const result = await axios.delete(endpoint, { data: obj }) const result = await this.axios.delete(endpoint, { data: obj })
return result.data return result.data
} catch (err) { } catch (err) {
@@ -85,7 +88,7 @@ class WebHook {
} catch (err) { } catch (err) {
const now = new Date() const now = new Date()
console.log(`${now.toLocaleString()}: Error trying to create webhook with P2WDB. Trying again...`) console.log(`${now.toLocaleString()}: Error trying to create webhook with P2WDB. Trying again...`)
await sleep(2000) await this.sleep(this.sleepTime)
} }
} while (!success) } while (!success)
@@ -95,10 +98,10 @@ class WebHook {
throw err throw err
} }
} }
async sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
} }
function sleep (ms) { export default WebHook
return new Promise(resolve => setTimeout(resolve, ms))
}
module.exports = WebHook
+12 -4
View File
@@ -6,10 +6,17 @@
'use strict' 'use strict'
const winston = require('winston') // Global npm libraries
require('winston-daily-rotate-file') import winston from 'winston'
import 'winston-daily-rotate-file'
const config = require('../../config') // Local libraries
import config from '../../config/index.js'
// Hack to get __dirname back.
// https://blog.logrocket.com/alternatives-dirname-node-js-es-modules/
import * as url from 'url'
const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
class Wlogger { class Wlogger {
constructor (localConfig = {}) { constructor (localConfig = {}) {
@@ -70,4 +77,5 @@ logger.outputToConsole()
const wlogger = logger.wlogger const wlogger = logger.wlogger
module.exports = { wlogger, Wlogger } export { wlogger as default, Wlogger }
// export default wlogger
+22 -8
View File
@@ -7,18 +7,27 @@
// Public npm libraries. // Public npm libraries.
// Local libraries // Local libraries
const Adapters = require('../adapters') import Adapters from '../adapters/index.js'
const JSONRPC = require('./json-rpc') import JSONRPC from './json-rpc/index.js'
const UseCases = require('../use-cases') import UseCases from '../use-cases/index.js'
const RESTControllers = require('./rest-api') import RESTControllers from './rest-api/index.js'
const TimerControllers = require('./timer-controllers') import TimerControllers from './timer-controllers.js'
import config from '../../config/index.js'
class Controllers { class Controllers {
constructor (localConfig = {}) { constructor (localConfig = {}) {
// Encapsulate dependencies
this.adapters = new Adapters() this.adapters = new Adapters()
this.useCases = new UseCases({ adapters: this.adapters }) this.useCases = new UseCases({ adapters: this.adapters })
this.timerControllers = new TimerControllers({ adapters: this.adapters, useCases: this.useCases }) this.timerControllers = new TimerControllers({ adapters: this.adapters, useCases: this.useCases })
this.config = config
// Bind 'this' object to all subfunction
this.initAdapters = this.initAdapters.bind(this)
this.initUseCases = this.initUseCases.bind(this)
this.attachRESTControllers = this.attachRESTControllers.bind(this)
this.attachControllers = this.attachControllers.bind(this)
this.attachRPCControllers = this.attachRPCControllers.bind(this)
} }
// Spin up any adapter libraries that have async startup needs. // Spin up any adapter libraries that have async startup needs.
@@ -45,8 +54,13 @@ class Controllers {
// Attach any other controllers other than REST API controllers. // Attach any other controllers other than REST API controllers.
async attachControllers (app) { async attachControllers (app) {
if (this.config.useIpfs) {
// Attach JSON RPC controllers
this.attachRPCControllers()
}
// this.attachRPCControllers() // Attach and start the timer controllers
this.timerControllers.startTimers()
} }
// Add the JSON RPC router to the ipfs-coord adapter. // Add the JSON RPC router to the ipfs-coord adapter.
@@ -63,4 +77,4 @@ class Controllers {
} }
} }
module.exports = Controllers export default Controllers
+3 -3
View File
@@ -6,10 +6,10 @@
*/ */
// Public npm libraries // Public npm libraries
const jsonrpc = require('jsonrpc-lite') import jsonrpc from 'jsonrpc-lite'
// Local libraries // Local libraries
const config = require('../../../../config') import config from '../../../../config/index.js'
class AboutRPC { class AboutRPC {
constructor (localConfig) { constructor (localConfig) {
@@ -48,4 +48,4 @@ class AboutRPC {
} }
} }
module.exports = AboutRPC export default AboutRPC
+5 -4
View File
@@ -3,13 +3,14 @@
*/ */
// Public npm libraries // Public npm libraries
const jsonrpc = require('jsonrpc-lite') import jsonrpc from 'jsonrpc-lite'
// Local libraries // Local libraries
// const AuthLib = require('../../lib/auth') // const AuthLib = require('../../lib/auth')
// const UserLib = require('../../../use-cases/user') // const UserLib = require('../../../use-cases/user')
const { wlogger } = require('../../../adapters/wlogger') import wlogger from '../../../adapters/wlogger.js'
const RateLimit = require('../rate-limit')
import RateLimit from '../rate-limit.js'
class AuthRPC { class AuthRPC {
constructor (localConfig = {}) { constructor (localConfig = {}) {
@@ -173,4 +174,4 @@ class AuthRPC {
} }
} }
module.exports = AuthRPC export default AuthRPC
+7 -6
View File
@@ -3,13 +3,14 @@
*/ */
// Public npm libraries // Public npm libraries
const jsonrpc = require('jsonrpc-lite') import jsonrpc from 'jsonrpc-lite'
// Local support libraries // Local support libraries
const { wlogger } = require('../../adapters/wlogger') import wlogger from '../../adapters/wlogger.js'
const UserController = require('./users')
const AuthController = require('./auth') import UserController from './users/index.js'
const AboutController = require('./about') import AuthController from './auth/index.js'
import AboutController from './about/index.js'
let _this let _this
@@ -190,4 +191,4 @@ class JSONRPC {
} }
} }
module.exports = JSONRPC export default JSONRPC
+2 -2
View File
@@ -4,7 +4,7 @@
/* eslint no-useless-catch: 0 */ /* eslint no-useless-catch: 0 */
// Local libraries // Local libraries
const RateLimitLib = require('koa2-ratelimit').RateLimit import { RateLimit as RateLimitLib } from 'koa2-ratelimit'
class RateLimit { class RateLimit {
constructor (options) { constructor (options) {
@@ -80,4 +80,4 @@ class RateLimit {
} }
} }
module.exports = RateLimit export default RateLimit
+5 -4
View File
@@ -3,12 +3,13 @@
*/ */
// Public npm libraries // Public npm libraries
const jsonrpc = require('jsonrpc-lite') import jsonrpc from 'jsonrpc-lite'
// Local libraries // Local libraries
// const UserLib = require('../../../use-cases/user') // const UserLib = require('../../../use-cases/user')
const Validators = require('../validators') import Validators from '../validators.js'
const RateLimit = require('../rate-limit')
import RateLimit from '../rate-limit.js'
class UserRPC { class UserRPC {
constructor (localConfig = {}) { constructor (localConfig = {}) {
@@ -533,4 +534,4 @@ class UserRPC {
// TODO create deleteUser() // TODO create deleteUser()
} }
module.exports = UserRPC export default UserRPC
+4 -3
View File
@@ -4,10 +4,11 @@
/* eslint no-useless-catch: 0 */ /* eslint no-useless-catch: 0 */
// Public npm libraries // Public npm libraries
const jwt = require('jsonwebtoken') import jwt from 'jsonwebtoken'
// Local libraries // Local libraries
const config = require('../../../config') import config from '../../../config/index.js'
// const UserModel = require('../../adapters/localdb/models/users') // const UserModel = require('../../adapters/localdb/models/users')
class Validators { class Validators {
@@ -93,4 +94,4 @@ class Validators {
} }
} }
module.exports = Validators export default Validators
+2 -2
View File
@@ -1,4 +1,4 @@
const Passport = require('../../../adapters/passport') import Passport from '../../../adapters/passport.js'
const passport = new Passport() const passport = new Passport()
let _this let _this
@@ -96,4 +96,4 @@ class AuthRESTController {
} }
} }
module.exports = AuthRESTController export default AuthRESTController
+3 -3
View File
@@ -3,10 +3,10 @@
*/ */
// Public npm libraries. // Public npm libraries.
const Router = require('koa-router') import Router from 'koa-router'
// Local libraries. // Local libraries.
const AuthRESTController = require('./controller') import AuthRESTController from './controller.js'
class AuthRouter { class AuthRouter {
constructor (localConfig = {}) { constructor (localConfig = {}) {
@@ -48,4 +48,4 @@ class AuthRouter {
} }
} }
module.exports = AuthRouter export default AuthRouter
@@ -3,9 +3,9 @@
*/ */
/* eslint-disable no-useless-escape */ /* eslint-disable no-useless-escape */
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0' import ContactLib from '../../../adapters/contact.js'
const ContactLib = require('../../../adapters/contact') process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
const contactLib = new ContactLib() const contactLib = new ContactLib()
let _this let _this
@@ -74,4 +74,4 @@ class ContactController {
} }
} }
} }
module.exports = ContactController export default ContactController
+3 -3
View File
@@ -3,10 +3,10 @@
*/ */
// Public npm libraries. // Public npm libraries.
const Router = require('koa-router') import Router from 'koa-router'
// Local libraries. // Local libraries.
const ContactRESTControllerLib = require('./controller') import ContactRESTControllerLib from './controller.js'
class ContactRouter { class ContactRouter {
constructor (localConfig = {}) { constructor (localConfig = {}) {
@@ -53,4 +53,4 @@ class ContactRouter {
} }
} }
module.exports = ContactRouter export default ContactRouter
+30 -1
View File
@@ -29,7 +29,36 @@ class EntryRESTControllerLib {
_this = this _this = this
} }
/**
* @api {post} /entry Create an entry
* @apiPermission public
* @apiName CreateEntry
* @apiGroup REST Entry
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X POST -d '{"entry": "1234567890", "description": "1234567890", "slpAddress": "1234567890", "signature": "1234567890", "category": "1234567890"}' localhost:5001/entry
*
* @apiSuccess {Object} entry Entry object
* @apiSuccess {String} entry.id Entry ID
* @apiSuccess {String} entry.description Entry description
* @apiSuccess {String} entry.slpAddress Entry slp address
* @apiSuccess {String} entry.signature Entry signature
* @apiSuccess {String} entry.category Entry category
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "entry": {
* "id": "1234567890",
* "description": "1234567890",
* "slpAddress": "1234567890",
* "signature": "1234567890",
* "category": "1234567890"
* }
* }
*/
// No api-doc documentation because this wont be a public endpoint // No api-doc documentation because this wont be a public endpoint
// Note: this is a private endpoint, needs to be authenticated
async createEntry (ctx) { async createEntry (ctx) {
try { try {
console.log('body: ', ctx.request.body) console.log('body: ', ctx.request.body)
@@ -64,4 +93,4 @@ class EntryRESTControllerLib {
} }
} }
module.exports = EntryRESTControllerLib export default EntryRESTControllerLib
+3 -3
View File
@@ -3,10 +3,10 @@
*/ */
// Public npm libraries. // Public npm libraries.
const Router = require('koa-router') import Router from 'koa-router'
// Local libraries. // Local libraries.
const EntryRESTControllerLib = require('./controller') import EntryRESTControllerLib from './controller.js'
let _this let _this
@@ -57,4 +57,4 @@ class UserRouter {
} }
} }
module.exports = UserRouter export default UserRouter
+43 -17
View File
@@ -6,15 +6,20 @@
// Public npm libraries. // Public npm libraries.
// Load the REST API Controllers. // Local libraries
const AuthRESTController = require('./auth') import AuthRESTController from './auth/index.js'
const UserRouter = require('./users') import UserRouter from './users/index.js'
const ContactRESTController = require('./contact') import ContactRESTController from './contact/index.js'
const LogsRESTController = require('./logs') import LogsRESTController from './logs/index.js'
const EntryRouter = require('./entry') import IpfsRESTController from './ipfs/index.js'
const OfferRouter = require('./offer') import config from '../../../config/index.js'
const OrderRouter = require('./order') import EntryRouter from './entry/index.js'
const P2WDBRouter = require('./p2wdb') import OfferRouter from './offer/index.js'
import OrderRouter from './order/index.js'
import P2WDBRouter from './p2wdb/index.js'
import UsageRESTController from './usage/index.js'
import SmAccountRouter from './smAccount/index.js'
import NostrRouter from './nostr/index.js'
class RESTControllers { class RESTControllers {
constructor (localConfig = {}) { constructor (localConfig = {}) {
@@ -32,7 +37,11 @@ class RESTControllers {
) )
} }
// console.log('Controllers localConfig: ', localConfig) // Bind 'this' object to all subfunctions.
this.attachRESTControllers = this.attachRESTControllers.bind(this)
// Encapsulate dependencies
this.config = config
} }
attachRESTControllers (app) { attachRESTControllers (app) {
@@ -41,13 +50,15 @@ class RESTControllers {
useCases: this.useCases useCases: this.useCases
} }
// Attach the REST API Controllers associated with the /auth route if (!this.config.noMongo) {
const authRESTController = new AuthRESTController(dependencies) // Attach the REST API Controllers associated with the /auth route
authRESTController.attach(app) const authRESTController = new AuthRESTController(dependencies)
authRESTController.attach(app)
// Attach the REST API Controllers associated with the /user route // Attach the REST API Controllers associated with the /user route
const userRouter = new UserRouter(dependencies) const userRouter = new UserRouter(dependencies)
userRouter.attach(app) userRouter.attach(app)
}
// Attach the REST API Controllers associated with the /contact route // Attach the REST API Controllers associated with the /contact route
const contactRESTController = new ContactRESTController(dependencies) const contactRESTController = new ContactRESTController(dependencies)
@@ -57,6 +68,10 @@ class RESTControllers {
const logsRESTController = new LogsRESTController(dependencies) const logsRESTController = new LogsRESTController(dependencies)
logsRESTController.attach(app) logsRESTController.attach(app)
// Attach the REST API Controllers associated with the /ipfs route
const ipfsRESTController = new IpfsRESTController(dependencies)
ipfsRESTController.attach(app)
// Attach the REST API Controllers associated with the /entry route // Attach the REST API Controllers associated with the /entry route
const entryRouter = new EntryRouter(dependencies) const entryRouter = new EntryRouter(dependencies)
entryRouter.attach(app) entryRouter.attach(app)
@@ -69,7 +84,18 @@ class RESTControllers {
const p2wdbRouter = new P2WDBRouter(dependencies) const p2wdbRouter = new P2WDBRouter(dependencies)
p2wdbRouter.attach(app) p2wdbRouter.attach(app)
// Attach the REST API Controllers associated with the /usage route
const usageRESTController = new UsageRESTController(dependencies)
usageRESTController.attach(app)
const smAccountRouter = new SmAccountRouter(dependencies)
smAccountRouter.attach(app)
// Attach the REST API Controllers associated with the /nostr route
const nostrRouter = new NostrRouter(dependencies)
nostrRouter.attach(app)
} }
} }
module.exports = RESTControllers export default RESTControllers
+212
View File
@@ -0,0 +1,212 @@
/*
REST API Controller library for the /ipfs route
*/
// Global npm libraries
// Local libraries
import wlogger from '../../../adapters/wlogger.js'
class IpfsRESTControllerLib {
constructor (localConfig = {}) {
// Dependency Injection.
this.adapters = localConfig.adapters
if (!this.adapters) {
throw new Error(
'Instance of Adapters library required when instantiating /ipfs REST Controller.'
)
}
this.useCases = localConfig.useCases
if (!this.useCases) {
throw new Error(
'Instance of Use Cases library required when instantiating /ipfs REST Controller.'
)
}
// Encapsulate dependencies
// this.UserModel = this.adapters.localdb.Users
// this.userUseCases = this.useCases.user
// Bind 'this' object to all subfunctions
this.getStatus = this.getStatus.bind(this)
this.getPeers = this.getPeers.bind(this)
this.getRelays = this.getRelays.bind(this)
this.handleError = this.handleError.bind(this)
this.connect = this.connect.bind(this)
this.getThisNode = this.getThisNode.bind(this)
}
/**
* @api {get} /ipfs Get status on IPFS infrastructure
* @apiPermission public
* @apiName GetIpfsStatus
* @apiGroup REST IPFS
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X GET localhost:5001/ipfs
*
* @apiSuccess {Object} status IPFS status object
* @apiSuccess {String} status.ipfsId IPFS ID
* @apiSuccess {String} status.multiaddrs IPFS multiaddrs
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "status": {
* "ipfsId": "1234567890",
* "multiaddrs": ["/ip4/123.45.67.89/tcp/4001/p2p/1234567890"]
* }
* }
*/
async getStatus (ctx) {
try {
const status = await this.adapters.ipfs.getStatus()
ctx.body = { status }
} catch (err) {
wlogger.error('Error in ipfs/controller.js/getStatus(): ')
// ctx.throw(422, err.message)
this.handleError(ctx, err)
}
}
/**
* @api {post} /ipfs/peers Get information on IPFS peers this node is connected to
* @apiPermission public
* @apiName GetIpfsPeers
* @apiGroup REST IPFS
*
* @apiParam {Boolean} [showAll=false] Whether to include detailed peer data
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X POST localhost:5001/ipfs/peers \
* -d '{"showAll": false}'
*
* @apiSuccess {Object[]} peers Array of peer objects
* @apiSuccess {String} peers[].peer Peer ID
* @apiSuccess {String} peers[].name Peer name
* @apiSuccess {String} peers[].protocol Protocol used by the peer
* @apiSuccess {String} peers[].version Peer version
* @apiSuccess {String} peers[].connectionAddr Connection address
* @apiSuccess {Object} [peers[].peerData] Detailed peer data (when showAll=true)
*/
async getPeers (ctx) {
try {
const showAll = ctx.request.body.showAll
const peers = await this.adapters.ipfs.getPeers(showAll)
ctx.body = { peers }
} catch (err) {
wlogger.error('Error in ipfs/controller.js/getPeers(): ')
// ctx.throw(422, err.message)
this.handleError(ctx, err)
}
}
/**
* @api {post} /ipfs/relays Get data about the known Circuit Relays
* @apiPermission public
* @apiName GetIpfsRelays
* @apiGroup REST IPFS
*
* @apiDescription Returns information about Circuit Relays, both v1 and v2, that this node knows about. V2 relays are hydrated with peer data from the connected peers list.
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X POST localhost:5001/ipfs/relays
*
* @apiSuccess {Object} relays Object containing relay information
* @apiSuccess {Object[]} relays.v2Relays Array of v2 Circuit Relay objects
* @apiSuccess {String} relays.v2Relays[].ipfsId IPFS ID of the relay
* @apiSuccess {String} relays.v2Relays[].name Name of the relay (hydrated from peer data)
* @apiSuccess {String} relays.v2Relays[].description Description of the relay (hydrated from peer data)
* @apiSuccess {Object[]} relays.v1Relays Array of v1 Circuit Relay configurations
*/
// Get data about the known Circuit Relays. Hydrate with data from peers list.
async getRelays (ctx) {
try {
const relays = await this.adapters.ipfs.getRelays()
ctx.body = { relays }
} catch (err) {
wlogger.error('Error in ipfs/controller.js/getRelays(): ')
// ctx.throw(422, err.message)
this.handleError(ctx, err)
}
}
/**
* @api {post} /ipfs/connect Connect to a specific IPFS peer
* @apiPermission public
* @apiName ConnectToIpfsPeer
* @apiGroup REST IPFS
*
* @apiDescription Attempts to establish a connection to a specific IPFS peer using the provided multiaddr. Optionally returns detailed information about the connection.
*
* @apiParam {String} multiaddr Multiaddress of the peer to connect to (required)
* @apiParam {Boolean} [getDetails=false] Whether to return detailed connection information
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X POST localhost:5001/ipfs/connect \
* -d '{"multiaddr": "/ip4/161.35.99.207/tcp/4001/p2p/12D3KooWDtj9cfj1SKuLbDNKvKRKSsGN8qivq9M8CYpLPDpcD5pu", "getDetails": false}'
*
* @apiSuccess {Boolean} success Indicates whether the connection attempt was successful
* @apiSuccess {Object} [details] Additional connection details (when getDetails=true)
*/
async connect (ctx) {
try {
const multiaddr = ctx.request.body.multiaddr
const getDetails = ctx.request.body.getDetails
// console.log('this.adapters.ipfs.ipfsCoordAdapter.ipfsCoord.adapters.ipfs: ', this.adapters.ipfs.ipfsCoordAdapter.ipfsCoord.adapters.ipfs)
const result = await this.adapters.ipfs.ipfsCoordAdapter.ipfsCoord.adapters.ipfs.connectToPeer({ multiaddr, getDetails })
// console.log('result: ', result)
ctx.body = result
} catch (err) {
wlogger.error('Error in ipfs/controller.js/connect():', err)
// ctx.throw(422, err.message)
this.handleError(ctx, err)
}
}
/**
* @api {get} /ipfs/node Get a copy of the thisNode object from helia-coord
* @apiPermission public
* @apiName GetThisNode
* @apiGroup REST IPFS
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X GET localhost:5001/ipfs/node
*
*/
async getThisNode (ctx) {
try {
const thisNode = this.adapters.ipfs.ipfsCoordAdapter.ipfsCoord.thisNode
ctx.body = { thisNode }
} catch (err) {
wlogger.error('Error in ipfs/controller.js/getThisNode(): ')
// ctx.throw(422, err.message)
this.handleError(ctx, err)
}
}
// DRY error handler
handleError (ctx, err) {
// If an HTTP status is specified by the buisiness logic, use that.
if (err.status) {
if (err.message) {
ctx.throw(err.status, err.message)
} else {
ctx.throw(err.status)
}
} else {
// By default use a 422 error if the HTTP status is not specified.
ctx.throw(422, err.message)
}
}
}
// module.exports = IpfsRESTControllerLib
export default IpfsRESTControllerLib
+67
View File
@@ -0,0 +1,67 @@
/*
REST API library for the /ipfs route.
*/
// Public npm libraries.
import Router from 'koa-router'
// Local libraries.
import IPFSRESTControllerLib from './controller.js'
import Validators from '../middleware/validators.js'
// let _this
class IpfsRouter {
constructor (localConfig = {}) {
// Dependency Injection.
this.adapters = localConfig.adapters
if (!this.adapters) {
throw new Error(
'Instance of Adapters library required when instantiating IPFS REST Controller.'
)
}
this.useCases = localConfig.useCases
if (!this.useCases) {
throw new Error(
'Instance of Use Cases library required when instantiating IPFS REST Controller.'
)
}
const dependencies = {
adapters: this.adapters,
useCases: this.useCases
}
// Encapsulate dependencies.
this.ipfsRESTController = new IPFSRESTControllerLib(dependencies)
this.validators = new Validators()
// Instantiate the router and set the base route.
const baseUrl = '/ipfs'
this.router = new Router({ prefix: baseUrl })
// _this = this
}
attach (app) {
if (!app) {
throw new Error(
'Must pass app object when attaching REST API controllers.'
)
}
// Define the routes and attach the controller.
this.router.get('/', this.ipfsRESTController.getStatus)
this.router.post('/peers', this.ipfsRESTController.getPeers)
this.router.post('/relays', this.ipfsRESTController.getRelays)
this.router.post('/connect', this.ipfsRESTController.connect)
this.router.get('/node', this.ipfsRESTController.getThisNode)
// Attach the Controller routes to the Koa app.
app.use(this.router.routes())
app.use(this.router.allowedMethods())
}
}
// module.exports = BchRouter
export default IpfsRouter
+2 -2
View File
@@ -1,4 +1,4 @@
const LogsApiLib = require('../../../adapters/logapi') import LogsApiLib from '../../../adapters/logapi.js'
const logsApiLib = new LogsApiLib() const logsApiLib = new LogsApiLib()
let _this let _this
@@ -62,4 +62,4 @@ class LogsApi {
} }
} }
module.exports = LogsApi export default LogsApi
+3 -3
View File
@@ -3,10 +3,10 @@
*/ */
// Public npm libraries. // Public npm libraries.
const Router = require('koa-router') import Router from 'koa-router'
// Local libraries. // Local libraries.
const LogsRESTControllerLib = require('./controller') import LogsRESTControllerLib from './controller.js'
class LogsRouter { class LogsRouter {
constructor (localConfig = {}) { constructor (localConfig = {}) {
@@ -52,4 +52,4 @@ class LogsRouter {
} }
} }
module.exports = LogsRouter export default LogsRouter
+2 -2
View File
@@ -1,4 +1,4 @@
module.exports = function errorMiddleware () { export default function errorMiddleware () {
return async (ctx, next) => { return async (ctx, next) => {
try { try {
await next() await next()
@@ -8,4 +8,4 @@ module.exports = function errorMiddleware () {
ctx.app.emit('error', err, ctx) ctx.app.emit('error', err, ctx)
} }
} }
} };
@@ -1,11 +1,24 @@
/* /*
REST API validator middleware. REST API validator middleware.
These are a series of functions that ensure the user making a REST API
matches a user in the database (or not). In can do fine-grain user control
such as telling the difference between an admin, a normal user, and an
anonymous user.
This middleware is used to gatekeep access to different REST API resources.
CT 9/17/22:
This library was lightly refactored to make it work with the new unit tests.
This not and the commented code below can be deleted once it is verified that
this refactor did not result in any breaking changes.
*/ */
const User = require('../../../adapters/localdb/models/users') import User from '../../../adapters/localdb/models/users.js'
const config = require('../../../../config')
const jwt = require('jsonwebtoken') import config from '../../../../config/index.js'
const { wlogger } = require('../../../adapters/wlogger') import jwt from 'jsonwebtoken'
import wlogger from '../../../adapters/wlogger.js'
let _this let _this
@@ -20,12 +33,10 @@ class Validators {
async ensureUser (ctx, next) { async ensureUser (ctx, next) {
try { try {
// console.log(`getToken: ${typeof (getToken)}`)
const token = _this.getToken(ctx) const token = _this.getToken(ctx)
if (!token) { if (!token) {
// console.log(`Err: Token not provided.`) throw new Error('Token could not be retrieved from header')
ctx.throw(401)
} }
let decoded = null let decoded = null
@@ -34,20 +45,23 @@ class Validators {
// console.log(`config: ${JSON.stringify(config, null, 2)}`) // console.log(`config: ${JSON.stringify(config, null, 2)}`)
decoded = _this.jwt.verify(token, config.token) decoded = _this.jwt.verify(token, config.token)
} catch (err) { } catch (err) {
// console.log(`Err: Token could not be decoded: ${err}`) throw new Error('Could not verify JWT')
ctx.throw(401)
} }
ctx.state.user = await _this.User.findById(decoded.id, '-password') ctx.state.user = await _this.User.findById(decoded.id, '-password')
if (!ctx.state.user) { if (!ctx.state.user) {
// console.log(`Err: Could not find user.`) // console.log('Err: Could not find user.')
ctx.throw(401) throw new Error('Could not find user')
} }
// return next() // return next()
return true return true
} catch (error) { } catch (error) {
ctx.throw(401) // console.log('Ensure user error: ', error)
// console.log('ctx: ', ctx)
ctx.status = 401
ctx.throw(401, error.message)
} }
} }
@@ -60,7 +74,8 @@ class Validators {
if (!token) { if (!token) {
// console.log(`Err: Token not provided.`) // console.log(`Err: Token not provided.`)
ctx.throw(401) // ctx.throw(401)
throw new Error('Token could not be retrieved from header')
} }
let decoded = null let decoded = null
@@ -70,22 +85,26 @@ class Validators {
decoded = _this.jwt.verify(token, config.token) decoded = _this.jwt.verify(token, config.token)
} catch (err) { } catch (err) {
// console.log(`Err: Token could not be decoded: ${err}`) // console.log(`Err: Token could not be decoded: ${err}`)
ctx.throw(401) // ctx.throw(401)
throw new Error('Could not verify JWT')
} }
ctx.state.user = await _this.User.findById(decoded.id, '-password') ctx.state.user = await _this.User.findById(decoded.id, '-password')
if (!ctx.state.user) { if (!ctx.state.user) {
// console.log(`Err: Could not find user.`) // console.log(`Err: Could not find user.`)
ctx.throw(401) // ctx.throw(401)
throw new Error('Could not find user')
} }
if (ctx.state.user.type !== 'admin') { if (ctx.state.user.type !== 'admin') {
ctx.throw(401, 'not admin') // ctx.throw(401, 'not admin')
throw new Error('User is not an admin')
} }
// return next() // return next()
return true return true
} catch (error) { } catch (error) {
ctx.status = 401
ctx.throw(401, error.message) ctx.throw(401, error.message)
} }
} }
@@ -101,7 +120,8 @@ class Validators {
if (!token) { if (!token) {
// console.log(`Err: Token not provided.`) // console.log(`Err: Token not provided.`)
ctx.throw(401) // ctx.throw(401)
throw new Error('Token could not be retrieved from header')
} }
// The user ID targeted in this API call. // The user ID targeted in this API call.
@@ -114,14 +134,16 @@ class Validators {
// console.log(`config: ${JSON.stringify(config, null, 2)}`) // console.log(`config: ${JSON.stringify(config, null, 2)}`)
decoded = _this.jwt.verify(token, config.token) decoded = _this.jwt.verify(token, config.token)
} catch (err) { } catch (err) {
// console.log(`Err: Token could not be decoded: ${err}`) console.log(`Err: Token could not be decoded: ${err}`)
ctx.throw(401) // ctx.throw(401)
throw new Error('Could not verify JWT')
} }
ctx.state.user = await _this.User.findById(decoded.id, '-password') ctx.state.user = await _this.User.findById(decoded.id, '-password')
if (!ctx.state.user) { if (!ctx.state.user) {
// console.log(`Err: Could not find user.`) // console.log(`Err: Could not find user.`)
ctx.throw(401) // ctx.throw(401)
throw new Error('Could not find user')
} }
// console.log('ctx.state.user: ', ctx.state.user) // console.log('ctx.state.user: ', ctx.state.user)
@@ -135,7 +157,8 @@ class Validators {
// If they don't match, then the calling user better be an admin. // If they don't match, then the calling user better be an admin.
if (ctx.state.user.type !== 'admin') { if (ctx.state.user.type !== 'admin') {
ctx.throw(401, 'not admin') // ctx.throw(401, 'not admin')
throw new Error('User is not an admin')
} else { } else {
wlogger.verbose("It's ok. The user is an admin.") wlogger.verbose("It's ok. The user is an admin.")
} }
@@ -144,6 +167,8 @@ class Validators {
// return next() // return next()
return true return true
} catch (error) { } catch (error) {
// console.log('Error in ensureTargetUserOrAdmin(): ', error)
ctx.status = 401
ctx.throw(401, error.message) ctx.throw(401, error.message)
} }
} }
@@ -166,4 +191,4 @@ class Validators {
} }
} }
module.exports = Validators export default Validators
@@ -0,0 +1,219 @@
/*
REST API Controller library for the /nostr route
*/
import wlogger from '../../../adapters/wlogger.js'
class NostrRESTControllerLib {
constructor (localConfig = {}) {
// Dependency Injection.
this.adapters = localConfig.adapters
if (!this.adapters) {
throw new Error(
'Instance of Adapters library required when instantiating /nostr REST Controller.'
)
}
this.useCases = localConfig.useCases
if (!this.useCases) {
throw new Error(
'Instance of Use Cases library required when instantiating /nostr REST Controller.'
)
}
this.createDeletedChat = this.createDeletedChat.bind(this)
this.getDeletedChats = this.getDeletedChats.bind(this)
this.createDeletedPost = this.createDeletedPost.bind(this)
this.getDeletedPosts = this.getDeletedPosts.bind(this)
this.handleError = this.handleError.bind(this)
}
/**
* @api {post} /nostr/deletedChat Create Deleted Chat.
* @apiPermission admin
* @apiName CreateDeletedChat
* @apiGroup REST Nostr
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -H "Authorization: Bearer <token>" -X POST -d '{"eventId": "note19e93faw4ffqepsqsrwrnstd3ee00nmzakwwuyfjm43dankgummfqms4p6q" , "npub" : "npub1d4ed5x49d7p24xn63flj4985dc4gpfngdhtqcxpth0ywhm6czxcscfpcq8" , "bchAddr" : "bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a", "pubkey":"6d72da1aa56f82aa9a7a8a7f2a94f46e2a80a6686dd60c182bbbc8ebef5811b1"}' localhost:5700/nostr/deletedChat
*
* @apiSuccess {String} _id DB Model id
* @apiSuccess {String} eventId Event id
* @apiSuccess {String} bchAddr BCH Address
* @apiSuccess {String} npub Nostr Npub
* @apiSuccess {String} pubkey Nostr pubkey
* @apiSuccess {Date} createdAt Created at date.
* @apiSuccess {Date} updatedAt Updated at date.
*
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "_id": "6900f87f9cafee38028ea27e",
* "npub": "npub1d4ed5x49d7p24xn63flj4985dc4gpfngdhtqcxpth0ywhm6czxcscfpcq8",
* "bchAddr" : "bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a",
* "pubKey": "6d72da1aa56f82aa9a7a8a7f2a94f46e2a80a6686dd60c182bbbc8ebef5811b1",
* "createdAt":"2025-10-28T17:08:15.409Z",
* "updatedAt": "2025-10-28T17:08:15.409Z"
* }
*
* @apiUse TokenError
*/
async createDeletedChat (ctx) {
try {
const chat = ctx.request.body
const result = await this.useCases.nostr.createDeletedChat(chat)
ctx.body = {
deletedChat: result
}
} catch (err) {
wlogger.error('Error in createDeletedChat() REST API handler.')
this.handleError(ctx, err)
}
}
/**
* @api {get} /nostr/deletedChat Get Deleted Chats.
* @apiPermission public
* @apiName GetDeletedChats
* @apiGroup REST Nostr
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X GET localhost:5700/nostr/deletedChat
*
* @apiSuccess {String} _id DB Model id
* @apiSuccess {String} eventId Event id
* @apiSuccess {String} bchAddr BCH Address
* @apiSuccess {String} npub Nostr Npub
* @apiSuccess {String} pubkey Nostr pubkey
* @apiSuccess {Date} createdAt Created at date.
* @apiSuccess {Date} updatedAt Updated at date.
*
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* [{
* "_id": "6900f87f9cafee38028ea27e",
* "npub": "npub1d4ed5x49d7p24xn63flj4985dc4gpfngdhtqcxpth0ywhm6czxcscfpcq8",
* "bchAddr" : "bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a",
* "pubKey": "6d72da1aa56f82aa9a7a8a7f2a94f46e2a80a6686dd60c182bbbc8ebef5811b1",
* "createdAt":"2025-10-28T17:08:15.409Z",
* "updatedAt": "2025-10-28T17:08:15.409Z"
* }]
*
* */
async getDeletedChats (ctx) {
try {
const deletedChats = await this.useCases.nostr.getDeletedChats()
ctx.body = { deletedChats }
} catch (err) {
wlogger.error('Error in getDeletedChats() REST API handler.')
this.handleError(ctx, err)
}
}
/**
* @api {post} /nostr/deletedPost Create Deleted Post.
* @apiPermission admin
* @apiName CreateDeletedPost
* @apiGroup REST Nostr
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -H "Authorization: Bearer <token>" -X POST -d '{"eventId": "note19e93faw4ffqepsqsrwrnstd3ee00nmzakwwuyfjm43dankgummfqms4p6q" , "npub" : "npub1d4ed5x49d7p24xn63flj4985dc4gpfngdhtqcxpth0ywhm6czxcscfpcq8" , "bchAddr" : "bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a", "pubkey":"6d72da1aa56f82aa9a7a8a7f2a94f46e2a80a6686dd60c182bbbc8ebef5811b1"}' localhost:5700/nostr/deletedPost
*
* @apiSuccess {String} _id DB Model id
* @apiSuccess {String} eventId Event id
* @apiSuccess {String} bchAddr BCH Address
* @apiSuccess {String} npub Nostr Npub
* @apiSuccess {String} pubkey Nostr pubkey
* @apiSuccess {Date} createdAt Created at date.
* @apiSuccess {Date} updatedAt Updated at date.
*
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "_id": "6900f87f9cafee38028ea27e",
* "npub": "npub1d4ed5x49d7p24xn63flj4985dc4gpfngdhtqcxpth0ywhm6czxcscfpcq8",
* "bchAddr" : "bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a",
* "pubKey": "6d72da1aa56f82aa9a7a8a7f2a94f46e2a80a6686dd60c182bbbc8ebef5811b1",
* "createdAt":"2025-10-28T17:08:15.409Z",
* "updatedAt": "2025-10-28T17:08:15.409Z"
* }
*
* @apiUse TokenError
*/
async createDeletedPost (ctx) {
try {
const post = ctx.request.body
const result = await this.useCases.nostr.createDeletedPost(post)
ctx.body = {
deletedPost: result
}
} catch (err) {
wlogger.error('Error in createDeletedPost() REST API handler.')
this.handleError(ctx, err)
}
}
/**
* @api {get} /nostr/deletedPost Get Deleted Posts.
* @apiPermission public
* @apiName GetDeletedPosts
* @apiGroup REST Nostr
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X GET localhost:5700/nostr/deletedPost
*
* @apiSuccess {String} _id DB Model id
* @apiSuccess {String} eventId Event id
* @apiSuccess {String} bchAddr BCH Address
* @apiSuccess {String} npub Nostr Npub
* @apiSuccess {String} pubkey Nostr pubkey
* @apiSuccess {Date} createdAt Created at date.
* @apiSuccess {Date} updatedAt Updated at date.
*
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* [{
* "_id": "6900f87f9cafee38028ea27e",
* "npub": "npub1d4ed5x49d7p24xn63flj4985dc4gpfngdhtqcxpth0ywhm6czxcscfpcq8",
* "bchAddr" : "bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a",
* "pubKey": "6d72da1aa56f82aa9a7a8a7f2a94f46e2a80a6686dd60c182bbbc8ebef5811b1",
* "createdAt":"2025-10-28T17:08:15.409Z",
* "updatedAt": "2025-10-28T17:08:15.409Z"
* }]
*
* */
async getDeletedPosts (ctx) {
try {
const deletedPosts = await this.useCases.nostr.getDeletedPosts()
ctx.body = { deletedPosts }
} catch (err) {
wlogger.error('Error in getDeletedPosts() REST API handler.')
this.handleError(ctx, err)
}
}
// DRY error handler
handleError (ctx, err) {
// If an HTTP status is specified by the buisiness logic, use that.
if (err.status) {
if (err.message) {
ctx.throw(err.status, err.message)
} else {
ctx.throw(err.status)
}
} else {
// By default use a 422 error if the HTTP status is not specified.
ctx.throw(422, err.message)
}
}
}
export default NostrRESTControllerLib
+81
View File
@@ -0,0 +1,81 @@
/*
REST API library for /nostr route.
*/
// Public npm libraries.
import Router from 'koa-router'
// Local libraries.
import NostrRESTControllerLib from './controller.js'
import Validators from '../middleware/validators.js'
import config from '../../../../config/index.js'
class NostrRouter {
constructor (localConfig = {}) {
// Dependency Injection.
this.adapters = localConfig.adapters
if (!this.adapters) {
throw new Error(
'Instance of Adapters library required when instantiating NostrRouter REST Controller.'
)
}
this.useCases = localConfig.useCases
if (!this.useCases) {
throw new Error(
'Instance of Use Cases library required when instantiating NostrRouter REST Controller.'
)
}
const dependencies = {
adapters: this.adapters,
useCases: this.useCases
}
// Encapsulate dependencies.
this.config = config
this.nostrRESTController = new NostrRESTControllerLib(dependencies)
this.validators = new Validators()
// Instantiate the router and set the base route.
const baseUrl = '/nostr'
this.router = new Router({ prefix: baseUrl })
this.attach = this.attach.bind(this)
this.createDeletedChat = this.createDeletedChat.bind(this)
this.createDeletedPost = this.createDeletedPost.bind(this)
}
attach (app) {
if (!app) {
throw new Error(
'Must pass app object when attaching REST API controllers.'
)
}
// Define the routes and attach the controller.
this.router.post('/deletedChat', this.createDeletedChat)
this.router.get('/deletedChat', this.nostrRESTController.getDeletedChats)
this.router.post('/deletedPost', this.createDeletedPost)
this.router.get('/deletedPost', this.nostrRESTController.getDeletedPosts)
// Attach the Controller routes to the Koa app.
app.use(this.router.routes())
app.use(this.router.allowedMethods())
}
async createDeletedChat (ctx, next) {
await this.validators.ensureAdmin(ctx, next)
await this.nostrRESTController.createDeletedChat(ctx, next)
return true
}
async createDeletedPost (ctx, next) {
await this.validators.ensureAdmin(ctx, next)
await this.nostrRESTController.createDeletedPost(ctx, next)
return true
}
}
export default NostrRouter
+392 -15
View File
@@ -1,10 +1,11 @@
/* /*
REST API Controller library for the /offer route REST API Controller library for the /offer route
TODO:
- Add api-doc documentation for all endpoints in this file.
*/ */
const { wlogger } = require('../../../adapters/wlogger') import wlogger from '../../../adapters/wlogger.js'
let _this
class OfferRESTControllerLib { class OfferRESTControllerLib {
constructor (localConfig = {}) { constructor (localConfig = {}) {
@@ -26,17 +27,27 @@ class OfferRESTControllerLib {
this.OfferModel = this.adapters.localdb.Offer this.OfferModel = this.adapters.localdb.Offer
// this.userUseCases = this.useCases.user // this.userUseCases = this.useCases.user
_this = this // Bind 'this' object to all subfunctions.
this.createOffer = this.createOffer.bind(this)
this.listOffers = this.listOffers.bind(this)
this.listNftOffers = this.listNftOffers.bind(this)
this.listFungibleOffers = this.listFungibleOffers.bind(this)
this.takeOffer = this.takeOffer.bind(this)
this.listOffersByAddress = this.listOffersByAddress.bind(this)
this.syncOfferMutableData = this.syncOfferMutableData.bind(this)
this.listCounterOffersByAddress = this.listCounterOffersByAddress.bind(this)
this.handleError = this.handleError.bind(this)
} }
// No api-doc documentation because this wont be a public endpoint // No api-doc documentation because this wont be a public endpoint
// This function has no endpoint
async createOffer (ctx) { async createOffer (ctx) {
try { try {
console.log('body: ', ctx.request.body) console.log('body: ', ctx.request.body)
const offerObj = ctx.request.body const offerObj = ctx.request.body
await _this.useCases.offer.createOffer(offerObj) await this.useCases.offer.createOffer(offerObj)
ctx.body = { ctx.body = {
success: true success: true
@@ -45,36 +56,402 @@ class OfferRESTControllerLib {
// console.log(`err.message: ${err.message}`) // console.log(`err.message: ${err.message}`)
// console.log('err: ', err) // console.log('err: ', err)
// ctx.throw(422, err.message) // ctx.throw(422, err.message)
_this.handleError(ctx, err) this.handleError(ctx, err)
} }
} }
/**
* @api {get} /offer/list/all/:page Get all offers
* @apiPermission public
* @apiName ListOffers
* @apiGroup REST Offer
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X GET localhost:5000/offer/list/all/0
*
* @apiSuccess {Object[]} offers Array of offer objects
* @apiSuccess {ObjectId} offers._id Offer id
* @apiSuccess {String} offers.ticker Ticker
* @apiSuccess {String} offers.tokenId Token id
* @apiSuccess {String} offers.utxoTxid Utxo transaction id
* @apiSuccess {Number} offers.utxoVout Utxo output index
* @apiSuccess {String} offers.buyOrSell Buy or sell
* @apiSuccess {Number} offers.numTokens Number of tokens
* @apiSuccess {String} offers.rateInBaseUnit Rate in base unit
* @apiSuccess {String} offers.minUnitsToExchange Minimum units to exchange
* @apiSuccess {String} offers.offerStatus Offer status
* @apiSuccess {String} offers.makerAddr Maker address
* @apiSuccess {Number} offers.timestamp Timestamp
* @apiSuccess {String} offers.displayCategory Display category
* @apiSuccess {Boolean} offers.nsfw Nsfw
* @apiSuccess {Array} offers.flags Flags
* @apiSuccess {Number} offers.messageType Message type
* @apiSuccess {Number} offers.messageClass Message class
* @apiSuccess {String} offers.nostrEventId Nostr event id
* @apiSuccess {String} offers.operatorAddress Operator address
* @apiSuccess {Number} offers.operatorPercentage Operator percentage
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "offers": [{
* "_id": "56bd1da600a526986cf65c80",
* "tokenId": "1234567890",
* "utxoTxid": "1234567890",
* "utxoVout": 0,
* "buyOrSell": "buy",
* "numTokens": 1,
* "rateInBaseUnit": "100000000",
* "minUnitsToExchange": "100000000",
* "offerStatus": "active",
* "makerAddr": "1234567890",
* "timestamp": 1716883200,
* "displayCategory": "nft",
* "nsfw": false,
* "flags": [],
* "messageType": 1,
* "messageClass": 1,
* "nostrEventId": "1234567890",
* "operatorAddress": "1234567890",
* "operatorPercentage": 100
* }]
* }
*
* @apiUse TokenError
*/
// curl -X GET http://localhost:5700/offer/list // curl -X GET http://localhost:5700/offer/list/all/0
async listOffers (ctx) { async listOffers (ctx) {
try { try {
const offers = await _this.useCases.offer.listOffers() let page = ctx.params.page
if (!page) page = 0
const offers = await this.useCases.offer.listOffers(page)
ctx.body = offers ctx.body = offers
} catch (err) { } catch (err) {
console.log('Error in listOffers REST API handler.') console.log('Error in listOffers REST API handler: ', err)
_this.handleError(ctx, err) this.handleError(ctx, err)
} }
} }
/**
* @api {get} /offer/list/nft/:page Get all nft offers
* @apiPermission public
* @apiName ListNftOffers
* @apiGroup REST Offer
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X GET localhost:5000/offer/list/nft/0
*
* @apiSuccess {Object[]} offers Array of offer objects
* @apiSuccess {ObjectId} offers._id Offer id
* @apiSuccess {String} offers.ticker Ticker
* @apiSuccess {String} offers.tokenId Token id
* @apiSuccess {String} offers.utxoTxid Utxo transaction id
* @apiSuccess {Number} offers.utxoVout Utxo output index
* @apiSuccess {String} offers.buyOrSell Buy or sell
* @apiSuccess {Number} offers.numTokens Number of tokens
* @apiSuccess {String} offers.rateInBaseUnit Rate in base unit
* @apiSuccess {String} offers.minUnitsToExchange Minimum units to exchange
* @apiSuccess {String} offers.offerStatus Offer status
* @apiSuccess {String} offers.makerAddr Maker address
* @apiSuccess {Number} offers.timestamp Timestamp
* @apiSuccess {String} offers.displayCategory Display category
* @apiSuccess {Boolean} offers.nsfw Nsfw
* @apiSuccess {Array} offers.flags Flags
* @apiSuccess {Number} offers.messageType Message type
* @apiSuccess {Number} offers.messageClass Message class
* @apiSuccess {String} offers.nostrEventId Nostr event id
* @apiSuccess {String} offers.operatorAddress Operator address
* @apiSuccess {Number} offers.operatorPercentage Operator percentage
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "offers": [{
* "_id": "56bd1da600a526986cf65c80",
* "tokenId": "1234567890",
* "utxoTxid": "1234567890",
* "utxoVout": 0,
* "buyOrSell": "buy",
* "numTokens": 1,
* "rateInBaseUnit": "100000000",
* "minUnitsToExchange": "100000000",
* "offerStatus": "active",
* "makerAddr": "1234567890",
* "timestamp": 1716883200,
* "displayCategory": "nft",
* "nsfw": false,
* "flags": [],
* "messageType": 1,
* "messageClass": 1,
* "nostrEventId": "1234567890",
* "operatorAddress": "1234567890",
* "operatorPercentage": 100
* }]
* }
*
* @apiUse TokenError
*/
// curl -X GET http://localhost:5700/offer/list/nft/0
async listNftOffers (ctx) {
try {
let page = ctx.params.page
if (!page) page = 0
const offers = await this.useCases.offer.listNftOffers(page)
ctx.body = offers
} catch (err) {
console.log('Error in listNftOffers REST API handler: ', err)
this.handleError(ctx, err)
}
}
/**
* @api {get} /offer/list/fungible/:page Get all fungible offers
* @apiPermission public
* @apiName ListFungibleOffers
* @apiGroup REST Offer
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X GET localhost:5000/offer/list/fungible/0
*
* @apiSuccess {Object[]} offers Array of offer objects
* @apiSuccess {ObjectId} offers._id Offer id
* @apiSuccess {String} offers.ticker Ticker
* @apiSuccess {String} offers.tokenId Token id
* @apiSuccess {String} offers.utxoTxid Utxo transaction id
* @apiSuccess {Number} offers.utxoVout Utxo output index
* @apiSuccess {String} offers.buyOrSell Buy or sell
* @apiSuccess {Number} offers.numTokens Number of tokens
* @apiSuccess {String} offers.rateInBaseUnit Rate in base unit
* @apiSuccess {String} offers.minUnitsToExchange Minimum units to exchange
* @apiSuccess {String} offers.offerStatus Offer status
* @apiSuccess {String} offers.makerAddr Maker address
* @apiSuccess {Number} offers.timestamp Timestamp
* @apiSuccess {String} offers.displayCategory Display category
* @apiSuccess {Boolean} offers.nsfw Nsfw
* @apiSuccess {Array} offers.flags Flags
* @apiSuccess {Number} offers.messageType Message type
* @apiSuccess {Number} offers.messageClass Message class
* @apiSuccess {String} offers.nostrEventId Nostr event id
* @apiSuccess {String} offers.operatorAddress Operator address
* @apiSuccess {Number} offers.operatorPercentage Operator percentage
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "offers": [{
* "_id": "56bd1da600a526986cf65c80",
* "tokenId": "1234567890",
* "utxoTxid": "1234567890",
* "utxoVout": 0,
* "buyOrSell": "buy",
* "numTokens": 1,
* "rateInBaseUnit": "100000000",
* "minUnitsToExchange": "100000000",
* "offerStatus": "active",
* "makerAddr": "1234567890",
* "timestamp": 1716883200,
* "displayCategory": "fungible",
* "nsfw": false,
* "flags": [],
* "messageType": 1,
* "messageClass": 1,
* "nostrEventId": "1234567890",
* "operatorAddress": "1234567890",
* "operatorPercentage": 100
* }]
* }
*
* @apiUse TokenError
*/
// curl -X GET http://localhost:5700/offer/list/fungible/0
async listFungibleOffers (ctx) {
try {
let page = ctx.params.page
if (!page) page = 0
const offers = await this.useCases.offer.listFungibleOffers(page)
ctx.body = offers
} catch (err) {
console.log('Error in Fungible REST API handler: ', err)
this.handleError(ctx, err)
}
}
/**
* @api {post} /offer/take Take an offer
* @apiPermission public
* @apiName TakeOffer
* @apiGroup REST Offer
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X POST -d '{ "nostrEventId": "1234567890" }' localhost:5010/offer/take
*
* @apiSuccess {String} eventId Event id
* @apiSuccess {String} noteId Note id
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "eventId": "1234567890",
* "noteId": "1234567890"
* }
*
* @apiUse TokenError
*/
// Currently only supports 'sell' offers, and will only buy the 'numTokens' // Currently only supports 'sell' offers, and will only buy the 'numTokens'
// listed in the offer. // listed in the offer.
async takeOffer (ctx) { async takeOffer (ctx) {
try { try {
console.log('REST API controller, body: ', ctx.request.body) console.log('REST API controller, body: ', ctx.request.body)
const offerCid = ctx.request.body.offerCid const nostrEventId = ctx.request.body.nostrEventId
const hash = await _this.useCases.offer.takeOffer(offerCid) const { eventId, noteId } = await this.useCases.offer.takeOffer(nostrEventId)
ctx.body = { hash } ctx.body = { eventId, noteId }
} catch (err) { } catch (err) {
wlogger.error('Error in takeOffer() REST API handler.') wlogger.error('Error in takeOffer() REST API handler.')
_this.handleError(ctx, err) this.handleError(ctx, err)
}
}
/**
* @api {get} /offer/list/addr/:addr List all offers being made by a given address
* @apiPermission public
* @apiName ListOffersByAddress
* @apiGroup REST Offer
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X GET localhost:5000/offer/list/addr/bitcoincash:qrpxtnrlhfz9wsuuse7z5k2mxmvw0r3pu5qepyhmq2
*
*
* @apiSuccess {Object[]} offers Array of offer objects
* @apiSuccess {ObjectId} offers._id Offer id
* @apiSuccess {String} offers.ticker Ticker
* @apiSuccess {String} offers.tokenId Token id
* @apiSuccess {String} offers.utxoTxid Utxo transaction id
* @apiSuccess {Number} offers.utxoVout Utxo output index
* @apiSuccess {String} offers.buyOrSell Buy or sell
* @apiSuccess {Number} offers.numTokens Number of tokens
* @apiSuccess {String} offers.rateInBaseUnit Rate in base unit
* @apiSuccess {String} offers.minUnitsToExchange Minimum units to exchange
* @apiSuccess {String} offers.offerStatus Offer status
* @apiSuccess {String} offers.makerAddr Maker address
* @apiSuccess {Number} offers.timestamp Timestamp
* @apiSuccess {String} offers.displayCategory Display category
* @apiSuccess {Boolean} offers.nsfw Nsfw
* @apiSuccess {Array} offers.flags Flags
* @apiSuccess {Number} offers.messageType Message type
* @apiSuccess {Number} offers.messageClass Message class
* @apiSuccess {String} offers.nostrEventId Nostr event id
* @apiSuccess {String} offers.operatorAddress Operator address
* @apiSuccess {Number} offers.operatorPercentage Operator percentage
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "offers": [{
* "_id": "56bd1da600a526986cf65c80",
* "tokenId": "1234567890",
* "utxoTxid": "1234567890",
* "utxoVout": 0,
* "buyOrSell": "buy",
* "numTokens": 1,
* "rateInBaseUnit": "100000000",
* "minUnitsToExchange": "100000000",
* "offerStatus": "active",
* "makerAddr": "bitcoincash:qrpxtnrlhfz9wsuuse7z5k2mxmvw0r3pu5qepyhmq2",
* "timestamp": 1716883200,
* "displayCategory": "fungible",
* "nsfw": false,
* "flags": [],
* "messageType": 1,
* "messageClass": 1,
* "nostrEventId": "1234567890",
* "operatorAddress": "1234567890",
* "operatorPercentage": 100
* }]
* }
*
* @apiUse TokenError
*/
// List all offers being made by a given address.
// curl -X GET http://localhost:5700/offer/list/addr/bitcoincash:qrpxtnrlhfz9wsuuse7z5k2mxmvw0r3pu5qepyhmq2
async listOffersByAddress (ctx) {
try {
const addr = ctx.params.addr
const offers = await this.useCases.offer.listOffersByAddress(addr)
ctx.body = offers
} catch (err) {
console.log('Error in listOffersByAddress REST API handler: ', err)
this.handleError(ctx, err)
}
}
async syncOfferMutableData (ctx) {
try {
const tokenId = ctx.request.body.tokenId
const offer = await this.useCases.offer.syncOfferMutableData(tokenId)
ctx.body = offer
} catch (err) {
console.log('Error in syncOfferMutableData REST API handler: ', err)
this.handleError(ctx, err)
}
}
/**
* @api {get} /offer/list/counter-offer/:addr List all counter offers being made by a given address
* @apiPermission public
* @apiName listCounterOffersByAddress
* @apiGroup REST Offer
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X GET localhost:5000/offer/list/counter-offer/bitcoincash:qq54a3xyyptty63ztlcavzzh64gy4d247qs4ueaupe
*
*
* @apiSuccess {String} offers.nostrEventId Nostr event id
* @apiSuccess {String} offers.takerNpub Nostr Npub.
* @apiSuccess {String} offers.takerAddr BCH Address.
* @apiSuccess {String} offers.counterOfferAddr BCH Address
* @apiSuccess {String} offers.counterOfferUtxo Utxo txid.
*
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "counterOffers": [{
* "_id": "56bd1da600a526986cf65c80",
* "nostrEventId": "1234567890",
* "takerAddr": "bitcoincash:qq54a3xyyptty63ztlcavzzh64gy4d247qs4ueaupe",
* "takerNpub": "npub1nhc47z2tf42a4ps7plzcyax2j76gdausve763tqw3xuw7jjd7ceqppquly",
* "counterOfferAddr": "bitcoincash:qzltx40ldxr53edchprppj5lpg4q7vl20usx25ga44",
* "counterOfferUtxo": "71dab5b81cf06f3495aeebcc70fb351109e5e88bc85da67d0d144c0e5ca0bd6a",
* }]
* }
*
* @apiUse TokenError
*/
async listCounterOffersByAddress (ctx) {
try {
const addr = ctx.params.addr
const counterOffers = await this.useCases.offer.listCounterOffersByAddress(addr)
ctx.body = { counterOffers }
} catch (err) {
console.log('Error in listCounterOffersByAddress REST API handler: ', err)
this.handleError(ctx, err)
} }
} }
@@ -95,4 +472,4 @@ class OfferRESTControllerLib {
} }
} }
module.exports = OfferRESTControllerLib export default OfferRESTControllerLib
+20 -11
View File
@@ -3,12 +3,10 @@
*/ */
// Public npm libraries. // Public npm libraries.
const Router = require('koa-router') import Router from 'koa-router'
// Local libraries. // Local libraries.
const OfferRESTControllerLib = require('./controller') import OfferRESTControllerLib from './controller.js'
let _this
class OfferRouter { class OfferRouter {
constructor (localConfig = {}) { constructor (localConfig = {}) {
@@ -38,7 +36,8 @@ class OfferRouter {
const baseUrl = '/offer' const baseUrl = '/offer'
this.router = new Router({ prefix: baseUrl }) this.router = new Router({ prefix: baseUrl })
_this = this // Bind 'this' object to all subfunctions.
this.attach = this.attach.bind(this)
} }
attach (app) { attach (app) {
@@ -48,15 +47,25 @@ class OfferRouter {
) )
} }
// 12/3/24 CT:
// Note: The createOffer() path was used by a P2WDB webhook to generate an
// Offer from an Order. This has been deprecated and Offers are now created
// by a Timer Controller monitoring a Nostr topic.
// Define the routes and attach the controller. // Define the routes and attach the controller.
this.router.post('/', _this.offerRESTController.createOffer) // this.router.post('/', _this.offerRESTController.createOffer) // Deprecated.
this.router.get('/list', _this.offerRESTController.listOffers) this.router.post('/take', this.offerRESTController.takeOffer)
this.router.post('/take', _this.offerRESTController.takeOffer) this.router.post('/mutable/sync/', this.offerRESTController.syncOfferMutableData)
this.router.get('/list/all/:page', this.offerRESTController.listOffers)
this.router.get('/list/nft/:page', this.offerRESTController.listNftOffers)
this.router.get('/list/fungible/:page', this.offerRESTController.listFungibleOffers)
this.router.get('/list/addr/:addr', this.offerRESTController.listOffersByAddress)
this.router.get('/list/counter-offer/:addr', this.offerRESTController.listCounterOffersByAddress)
// Attach the Controller routes to the Koa app. // Attach the Controller routes to the Koa app.
app.use(_this.router.routes()) app.use(this.router.routes())
app.use(_this.router.allowedMethods()) app.use(this.router.allowedMethods())
} }
} }
module.exports = OfferRouter export default OfferRouter
+147 -4
View File
@@ -29,16 +29,159 @@ class OrderRESTControllerLib {
_this = this _this = this
} }
// No api-doc documentation because this wont be a public endpoint /**
* @api {post} /order Create an order
* @apiPermission User
* @apiName CreateOrder
* @apiGroup REST Order
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X POST -d '{"messageType": "1", "messageClass": "1", "tokenId": "1234567890", "buyOrSell": "buy", "rateInBaseUnit": "100000000", "minUnitsToExchange": "100000000", "numTokens": "1", "makerAddr": "1234567890"}' localhost:5001/order
*
* @apiSuccess {String} eventId Event id
* @apiSuccess {String} noteId Note id
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "eventId": "1234567890",
* "noteId": "1234567890"
* }
*
* @apiUse TokenError
*/
async createOrder (ctx) { async createOrder (ctx) {
try { try {
// console.log('body: ', ctx.request.body) // console.log('body: ', ctx.request.body)
const orderObj = ctx.request.body.order const orderObj = ctx.request.body.order
const user = ctx.state.user
orderObj.userId = user._id
console.log('orderObj: ', orderObj)
const hash = await _this.useCases.order.createOrder(orderObj) const { eventId, noteId } = await _this.useCases.order.createOrder(orderObj)
ctx.body = { hash } ctx.body = { eventId, noteId }
} catch (err) {
// console.log(`err.message: ${err.message}`)
// console.log('err: ', err)
// ctx.throw(422, err.message)
_this.handleError(ctx, err)
}
}
/**
* @api {get} /order/list/all/:page List all orders
* @apiPermission user
* @apiName ListOrders
* @apiGroup REST Order
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X GET localhost:5000/order/list/all/0
*
* @apiSuccess {Object[]} orders Array of order objects
* @apiSuccess {ObjectId} orders._id Order id
* @apiSuccess {String} orders.tokenId Token id
* @apiSuccess {String} orders.ticker Ticker
* @apiSuccess {String} orders.dataType Data type
* @apiSuccess {String} orders.utxoTxid Utxo transaction id
* @apiSuccess {Number} orders.utxoVout Utxo output index
* @apiSuccess {String} orders.buyOrSell Buy or sell
* @apiSuccess {Number} orders.numTokens Number of tokens
* @apiSuccess {String} orders.rateInBaseUnit Rate in base unit
* @apiSuccess {String} orders.minUnitsToExchange Minimum units to exchange
* @apiSuccess {String} orders.offerStatus Offer status
* @apiSuccess {String} orders.makerAddr Maker address
* @apiSuccess {Number} orders.timestamp Timestamp
* @apiSuccess {String} orders.displayCategory Display category
* @apiSuccess {Boolean} orders.nsfw Nsfw
* @apiSuccess {Array} orders.flags Flags
* @apiSuccess {Number} orders.messageType Message type
* @apiSuccess {Number} orders.messageClass Message class
* @apiSuccess {String} orders.nostrEventId Nostr event id
* @apiSuccess {String} orders.operatorAddress Operator address
* @apiSuccess {Number} orders.operatorPercentage Operator percentage
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "orders": [{
* "_id": "56bd1da600a526986cf65c80",
* "tokenId": "1234567890",
* "ticker": "BTC",
* "dataType": "offer",
* "utxoTxid": "1234567890",
* "utxoVout": 0,
* "buyOrSell": "buy",
* "numTokens": 1,
* "rateInBaseUnit": "100000000",
* "minUnitsToExchange": "100000000",
* "offerStatus": "active",
* "makerAddr": "1234567890",
* "timestamp": 1716883200,
* "displayCategory": "nft",
* "nsfw": false,
* "flags": [],
* "messageType": 1,
* "messageClass": 1,
* "nostrEventId": "1234567890",
* "operatorAddress": "1234567890",
* "operatorPercentage": 100
* }]
* }
*
* @apiUse TokenError
*/
// curl -X GET http://localhost:5700/order/list/all/0
async listOrders (ctx) {
try {
let page = ctx.params.page
if (!page) page = 0
const offers = await _this.useCases.order.listOrders(page)
ctx.body = offers
} catch (err) {
console.log('Error in listOrders REST API handler: ', err)
_this.handleError(ctx, err)
}
}
// Delete an existing order by returning the token to the root address of
// the DEX wallet.
/**
* @api {post} /order/delete Delete an order
* @apiPermission user
* @apiName DeleteOrder
* @apiGroup REST Order
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X POST -d '{ "nostrEventId": "1234567890" }' localhost:5000/order/delete
*
* @apiSuccess {String} txid Transaction id
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "txid": "1234567890"
* }
*
* @apiUse TokenError
*/
// curl -X POST http://localhost:5700/order/delete -d '{ "nostrEventId": "1234567890" }'
async deleteOrder (ctx) {
try {
// console.log('body: ', ctx.request.body)
const nostrEventId = ctx.request.body.nostrEventId
// console.log('p2wdbHash: ', p2wdbHash)
const txid = await _this.useCases.order.deleteOrder(nostrEventId)
ctx.body = { txid }
} catch (err) { } catch (err) {
// console.log(`err.message: ${err.message}`) // console.log(`err.message: ${err.message}`)
// console.log('err: ', err) // console.log('err: ', err)
@@ -65,4 +208,4 @@ class OrderRESTControllerLib {
} }
} }
module.exports = OrderRESTControllerLib export default OrderRESTControllerLib
+19 -4
View File
@@ -3,10 +3,11 @@
*/ */
// Public npm libraries. // Public npm libraries.
const Router = require('koa-router') import Router from 'koa-router'
// Local libraries. // Local libraries.
const OrderRESTControllerLib = require('./controller') import OrderRESTControllerLib from './controller.js'
import Validators from '../middleware/validators.js'
let _this let _this
@@ -32,12 +33,14 @@ class OrderRouter {
} }
// Encapsulate dependencies. // Encapsulate dependencies.
this.validators = new Validators()
this.orderRESTController = new OrderRESTControllerLib(dependencies) this.orderRESTController = new OrderRESTControllerLib(dependencies)
// Instantiate the router and set the base route. // Instantiate the router and set the base route.
const baseUrl = '/order' const baseUrl = '/order'
this.router = new Router({ prefix: baseUrl }) this.router = new Router({ prefix: baseUrl })
this.createOrder = this.createOrder.bind(this)
_this = this _this = this
} }
@@ -49,12 +52,24 @@ class OrderRouter {
} }
// Define the routes and attach the controller. // Define the routes and attach the controller.
this.router.post('/', _this.orderRESTController.createOrder) this.router.post('/', this.createOrder)
this.router.get('/list/all/:page', _this.orderRESTController.listOrders)
this.router.post('/delete', this.deleteOrder)
// Attach the Controller routes to the Koa app. // Attach the Controller routes to the Koa app.
app.use(_this.router.routes()) app.use(_this.router.routes())
app.use(_this.router.allowedMethods()) app.use(_this.router.allowedMethods())
} }
async createOrder (ctx, next) {
await _this.validators.ensureUser(ctx, next)
await _this.orderRESTController.createOrder(ctx, next)
}
async deleteOrder (ctx, next) {
await _this.validators.ensureUser(ctx, next)
await _this.orderRESTController.deleteOrder(ctx, next)
}
} }
module.exports = OrderRouter export default OrderRouter
+32 -2
View File
@@ -31,7 +31,25 @@ class P2WDBRESTControllerLib {
_this = this _this = this
} }
// No api-doc documentation because this wont be a public endpoint /**
* @api {post} /p2wdb Route a P2WDB webhook
* @apiPermission public
* @apiName RouteWebhook
* @apiGroup REST P2WDB
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X POST -d '{"data": {"dataType": "offer"} } ' localhost:5001/p2wdb
*
* @apiSuccess {String} success Success message
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "success": true
* }
*/
// Note: verify if this is a private endpoint, needs to be authenticated
async routeWebhook (ctx) { async routeWebhook (ctx) {
try { try {
console.log('p2wdb REST API handler: body: ', ctx.request.body) console.log('p2wdb REST API handler: body: ', ctx.request.body)
@@ -45,14 +63,26 @@ class P2WDBRESTControllerLib {
const counterOffer = ctx.request.body const counterOffer = ctx.request.body
await _this.useCases.offer.acceptCounterOffer(counterOffer) await _this.useCases.offer.acceptCounterOffer(counterOffer)
//
} else if (dataType.includes('offer')) { } else if (dataType.includes('offer')) {
// Detect and handle new Offers // Detect and handle new Offers
console.log('offer data detected') console.log('offer data detected')
const offerObj = ctx.request.body const offerObj = ctx.request.body
await _this.useCases.offer.createOffer(offerObj) await _this.useCases.offer.createOffer(offerObj)
//
} else if (dataType.includes('flag')) {
// Detect and handle data generated by users flagging NSFW Offers.
const flagData = ctx.request.body
console.log('Flag type data received: ', flagData)
// const p2wdbHash = flagData.p2wdbHash
await _this.useCases.offer.flagOffer(flagData)
} else { } else {
console.log('Could not route P2WDB webhook data.') console.log('Could not route P2WDB webhook data.')
// NOTE: Should we throw an error here?
} }
// const orderObj = ctx.request.body.order // const orderObj = ctx.request.body.order
@@ -90,4 +120,4 @@ class P2WDBRESTControllerLib {
} }
} }
module.exports = P2WDBRESTControllerLib export default P2WDBRESTControllerLib

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