Compare commits

..
504 Commits
Author SHA1 Message Date
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 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 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 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 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 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 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 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 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 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 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 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 a611580f48 Turning off CI option 2025-05-15 19:18:41 -07:00
Chris Troutner 07c671ede4 fix(production): Using v3 UI 2025-05-15 17:58:29 -07: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 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 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 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
226 changed files with 53004 additions and 23579 deletions
+4
View File
@@ -69,5 +69,9 @@ ipfs-service-provider.sh
run-dev.sh
wallet.json
data/
run-dev.sh
*.zip
!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)
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:
+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
[![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)
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.
@@ -19,57 +19,43 @@ This repository contains the back end code. The user interface is contained in t
## 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:
- [Telegram Channel](https://t.me/psf_dex_dev)
- [Gitter Channel](https://gitter.im/Permissionless-Software-Foundation/psf-dex-dev)
- [Telegram Channel](https://t.me/bch_js_toolkit)
## Installation
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-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.
- [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.
- [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.
- [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.
- [MongoDB](https://www.mongodb.com/) is a database used by bch-dex to store and manage local data, user accounts, etc.
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/).
Here are the steps involved in setting up bch-dex:
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:
- 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`.
- Install dependencies by running `npm install`
- Create a wallet:
- `cd production/scripts`
- `node create-wallet.js`
1. Change directory to the `production/docker` or `production/rpi-docker` folder depending on your hardware target.
1. Pull the Docker images down from Docker Hub: `docker-compose pull`
1. Start the Docker containers with `docker-compose up -d`
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`.
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.
1. To take the other side of the trade, click the `Take` button in the UI.
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).
- Change directory to the `production/docker` folder.
- Pull the Docker images down from Docker Hub: `docker-compose pull`
- Build the back end: `docker-compose build --no-cache bch-dex`
- Build the front end: `docker-compose build --no-cache dex-ui`
- Start the Docker containers with `docker-compose up -d`
- It will take about 10 minutes for the bch-dex to sync with the network and display tokens for sale.
- 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
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
As this is an active project, software updates will happen frequently. To apply a software update, perform these steps.
## Environment Variables
1. Enter the `docker` or `rpi-docker` folder, depending on your hardware target.
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.
- `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.
- `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.
## License
+42 -38
View File
@@ -8,31 +8,27 @@
*/
// npm libraries
const Koa = require('koa')
const bodyParser = require('koa-bodyparser')
const convert = require('koa-convert')
const logger = require('koa-logger')
const mongoose = require('mongoose')
const session = require('koa-generic-session')
const passport = require('koa-passport')
const mount = require('koa-mount')
const serve = require('koa-static')
const cors = require('kcors')
import Koa from 'koa'
import bodyParser from 'koa-bodyparser'
import convert from 'koa-convert'
import logger from 'koa-logger'
import mongoose from 'mongoose'
import session from 'koa-generic-session'
import passport from 'koa-passport'
import mount from 'koa-mount'
import serve from 'koa-static'
import cors from 'kcors'
// Local libraries
const config = require('../config') // this first.
const AdminLib = require('../src/adapters/admin')
// const adminLib = new AdminLib()
import config from '../config/index.js' // this first.
// const WebHookLib = require('../src/adapters/webhook')
// const webhookLib = new WebHookLib()
// const JSONRPC = require('../src/rpc')
// const rpc = new JSONRPC()
const errorMiddleware = require('../src/controllers/rest-api/middleware/error')
// const { wlogger } = require('../src/adapters/wlogger')
const Controllers = require('../src/controllers')
import AdminLib from '../src/adapters/admin.js'
import errorMiddleware from '../src/controllers/rest-api/middleware/error.js'
import { usageMiddleware } from '../src/use-cases/usage-use-cases.js'
// import wlogger from '../src/adapters/wlogger.js'
import Controllers from '../src/controllers/index.js'
import { applyPassportMods } from '../config/passport.js'
class Server {
constructor () {
@@ -50,16 +46,18 @@ class Server {
const app = new Koa()
app.keys = [this.config.session]
// Connect to the Mongo Database.
this.mongoose.Promise = global.Promise
this.mongoose.set('useCreateIndex', true) // Stop deprecation warning.
console.log(
`Connecting to MongoDB with this connection string: ${this.config.database}`
)
await this.mongoose.connect(this.config.database, {
useUnifiedTopology: true,
useNewUrlParser: true
})
if (!this.config.noMongo) {
// Connect to the Mongo Database.
this.mongoose.Promise = global.Promise
this.mongoose.set('useCreateIndex', true) // Stop deprecation warning.
console.log(
`Connecting to MongoDB with this connection string: ${this.config.database}`
)
await this.mongoose.connect(this.config.database, {
useUnifiedTopology: true,
useNewUrlParser: true
})
}
console.log(`Starting environment: ${this.config.env}`)
console.log(`Debug level: ${this.config.debugLevel}\n`)
@@ -73,6 +71,7 @@ class Server {
app.use(bodyParser())
app.use(session())
app.use(errorMiddleware())
app.use(usageMiddleware())
// Used to generate the docs.
app.use(mount('/', serve(`${process.cwd()}/docs`)))
@@ -81,7 +80,8 @@ class Server {
app.use(mount('/logs', serve(`${process.cwd()}/config/logs`)))
// User Authentication
require('../config/passport')
// require('../config/passport')
applyPassportMods(passport)
app.use(passport.initialize())
app.use(passport.session())
@@ -128,9 +128,11 @@ class Server {
this.server = await app.listen(config.port)
console.log(`Server started on ${config.port}`)
// Create the system admin user.
const success = await this.adminLib.createSystemUser()
if (success) console.log('System admin user created.')
if (!this.config.noMongo) {
// Create the system admin user.
const success = await this.adminLib.createSystemUser()
if (success) console.log('System admin user created.')
}
// Attach the other IPFS controllers.
// Skip if this is a test environment.
@@ -142,7 +144,9 @@ class Server {
console.log('\nConfiguration:')
console.log(`Circuit Relay: ${this.config.isCircuitRelay}`)
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
} 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
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 */
// 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.
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 ipfsCoordName = process.env.COORD_NAME
? process.env.COORD_NAME
: 'ipfs-torlist-service-generic'
module.exports = {
export default {
// Configure TCP port.
port: process.env.PORT || 5700,
@@ -36,27 +48,75 @@ module.exports = {
consumerUrl: process.env.CONSUMER_URL
? process.env.CONSUMER_URL
: 'https://free-bch.fullstack.cash',
// : 'https://dev-consumer.psfoundation.info',
// : 'https://wa-usa-bch-consumer.fullstackcash.nl',
// 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 : '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.
getJwtAtStartup: process.env.GET_JWT_AT_STARTUP ? true : false,
authServer: process.env.AUTHSERVER
? process.env.AUTHSERVER
: 'https://auth.fullstack.cash',
apiServer: process.env.APISERVER
? process.env.APISERVER
: 'https://api.fullstack.cash/v5/',
fullstackLogin: process.env.FULLSTACKLOGIN
? process.env.FULLSTACKLOGIN
: 'demo@demo.com',
fullstackPassword: process.env.FULLSTACKPASS
? process.env.FULLSTACKPASS
: '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,
// SSL domain used for websocket connection via browsers.
crDomain: process.env.CR_DOMAIN ? process.env.CR_DOMAIN : '',
@@ -77,7 +137,10 @@ module.exports = {
'@type': 'Organization',
name: 'Permissionless Software Foundation',
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
@@ -93,18 +156,44 @@ module.exports = {
// IPFS Ports
ipfsTcpPort: process.env.IPFS_TCP_PORT ? process.env.IPFS_TCP_PORT : 4001,
ipfsWsPort: process.env.IPFS_WS_PORT ? process.env.IPFS_WS_PORT : 4003,
// BCH Mnemonic for generating encryption keys and payment address
mnemonic: process.env.MNEMONIC ? process.env.MNEMONIC : '',
debugLevel: process.env.DEBUG_LEVEL ? parseInt(process.env.DEBUG_LEVEL) : 1,
ipfsWebRtcPort: process.env.IPFS_WEB_RTC_PORT ? process.env.IPFS_WEB_RTC_PORT : 4005,
connectPref: process.env.CONNECT_PREF, // Used in helia-coord to select connection preference.
// 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',
ipfsApiPort: process.env.IPFS_API_PORT
? parseInt(process.env.IPFS_API_PORT)
: 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.
*/
module.exports = {
export default {
session: 'secret-boilerplate-token',
token: 'secret-jwt-token',
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.
*/
module.exports = {
export default {
session: 'secret-boilerplate-token',
token: 'secret-jwt-token',
// 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.
*/
module.exports = {
export default {
session: 'secret-boilerplate-token',
token: 'secret-jwt-token',
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 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')
const User = require('../src/adapters/localdb/models/users')
const Strategy = require('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
)
)
// import passport from 'koa-passport';
import User from '../src/adapters/localdb/models/users.js'
import Strategy from 'passport-local'
async function passportCallback (email, password, done) {
try {
@@ -49,5 +25,32 @@ async function passportCallback (email, password, done) {
}
}
// For testing
module.exports = { passport, passportCallback }
function applyPassportMods (passport) {
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()
process.on('unhandledRejection', (reason, promise) => {
console.log(`Handling ${reason.code} error. stack: `, reason)
})
server.startServer()
+26701
View File
File diff suppressed because it is too large Load Diff
+12995 -20779
View File
File diff suppressed because it is too large Load Diff
+41 -18
View File
@@ -1,20 +1,22 @@
{
"name": "bch-dex",
"version": "1.0.0",
"version": "3.0.0",
"description": "A DEX on BCH for trading SLP tokens.",
"main": "index.js",
"type": "module",
"scripts": {
"start": "node index.js",
"test": "npm run test:all",
"test:all": "export BCH_DEX=test && nyc --reporter=text mocha --exit --timeout 30000 --recursive test/unit test/e2e/automated/",
"test:unit": "export BCH_DEX=test && mocha --exit --timeout 15000 --recursive test/unit/",
"test": "npm run test:unit",
"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 && c8 --reporter=text mocha --exit --timeout 15000 --recursive test/unit/",
"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:temp": "export BCH_DEX=test && mocha --exit --timeout 15000 -g '#rate-limit' test/unit/json-rpc/",
"lint": "standard --env mocha --fix",
"docs": "./node_modules/.bin/apidoc -i src/ -o docs",
"coverage": "nyc 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": "c8 report --reporter=text-lcov | coveralls",
"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>",
"contributors": [
@@ -27,15 +29,35 @@
},
"repository": "Permissionless-Software-Foundation/bch-dex",
"dependencies": {
"@psf/bch-js": "6.4.5",
"@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",
"bch-message-lib": "2.2.1",
"bch-nostr": "1.3.3",
"bch-token-sweep": "2.2.1",
"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",
"ipfs": "0.62.3",
"ipfs-coord": "8.0.5",
"ipfs-http-client": "55.0.0",
"helia": "5.2.1",
"helia-coord": "1.7.2",
"ipfs-coord-esm": "9.1.7",
"ipfs-http-client": "58.0.0",
"jsonrpc-lite": "2.2.0",
"jsonwebtoken": "8.5.1",
"jwt-bch-lib": "1.3.0",
@@ -50,26 +72,27 @@
"koa-router": "10.0.0",
"koa-static": "5.0.0",
"koa2-ratelimit": "0.9.1",
"libp2p": "^0.36.2",
"libp2p": "2.7.2",
"line-reader": "0.4.0",
"minimal-slp-wallet": "5.1.0",
"mongoose": "5.13.13",
"minimal-slp-wallet": "5.13.2",
"mongoose": "5.13.14",
"node-fetch": "npm:@achingbrain/node-fetch@2.6.7",
"nodemailer": "6.7.5",
"p2wdb": "2.2.1",
"nostr-tools": "2.10.4",
"p2wdb-esm": "2.2.9",
"passport-local": "1.0.0",
"public-ip": "^4.0.4",
"public-ip": "6.0.1",
"winston": "3.3.3",
"winston-daily-rotate-file": "4.5.0"
},
"devDependencies": {
"apidoc": "0.51.1",
"bch-token-sweep": "2.1.2",
"c8": "7.12.0",
"chai": "4.3.0",
"coveralls": "2.11.4",
"husky": "4.3.8",
"lodash.clonedeep": "4.5.0",
"mocha": "10.0.0",
"nyc": "15.1.0",
"semantic-release": "19.0.3",
"sinon": "9.2.4",
"standard": "17.0.0",
+1
View File
@@ -0,0 +1 @@
COMPOSE_PROJECT_NAME=bch-dex
+9 -6
View File
@@ -12,7 +12,7 @@ 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 curl -sL https://deb.nodesource.com/setup_20.x -o nodesource_setup.sh
RUN bash nodesource_setup.sh
RUN apt-get install -y nodejs build-essential
@@ -34,7 +34,7 @@ WORKDIR /home/safeuser
# Update to the latest version of npm.
#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.
#RUN npm set registry http://94.130.170.209:4873/
@@ -46,11 +46,11 @@ RUN npm install -g npm
# Clone the rest.bitcoin.com repository
WORKDIR /home/safeuser
RUN git clone https://github.com/Permissionless-Software-Foundation/bch-dex-ui-v2
RUN git clone https://github.com/Permissionless-Software-Foundation/bch-dex-ui-v3
# Switch to the desired branch. `master` is usually stable,
# and `stage` has the most up-to-date changes.
WORKDIR /home/safeuser/bch-dex-ui-v2
WORKDIR /home/safeuser/bch-dex-ui-v3
# For development: switch to unstable branch
RUN git checkout ct-unstable
@@ -61,13 +61,16 @@ RUN git checkout ct-unstable
RUN npm install
# Build the site
RUN CI=true npm run build
RUN npm run build
# Load the NGINX image.
FROM nginx
EXPOSE 80
# Copy the files built in the first container to the new NGINX container.
COPY --from=builder /home/safeuser/bch-dex-ui-v2/build /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
+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
#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 apt-get install -y nodejs build-essential
@@ -34,7 +34,7 @@ WORKDIR /home/safeuser
# Update to the latest version of npm.
#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.
RUN npm set registry http://94.130.170.209:4873/
@@ -72,7 +72,10 @@ RUN npm run docs
#EXPOSE 5010
# Start the application.
#COPY start-production.sh start-production.sh
CMD ["./start-production.sh"]
#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,11 @@ export DBURL=mongodb://172.17.0.1:5666/bch-swap-service-prod
export PORT=5700
# bch-dex specific env vars
export BCH_DEX=production
export BCH_DEX=prod
export WEBHOOKSERVICE=http://172.17.0.1:5667/webhook
export WEBHOOKTARGET=http://172.17.0.1:5700/p2wdb
export APP_ID=bch-dex-001
#export P2WDB_URL=http://172.17.0.1:5667
npm start
+20 -71
View File
@@ -3,9 +3,9 @@
version: '3.9'
services:
mongo-p2wdb-service:
mongo-dex:
image: mongo:4.2.0
container_name: mongo-p2wdb-service
container_name: mongo-dex
ports:
- '5666:27017' # <host port>:<container port>
volumes:
@@ -13,67 +13,11 @@ services:
command: mongod --logpath=/dev/null # -- quiet
restart: always
ipfs:
# https://github.com/christroutner/trickle-ipfs
image: christroutner/trickle-ipfs:v1.0.1
#build:
# context: ./
# dockerfile: Dockerfile
container_name: ipfs
environment:
IPFS_DAEMON_ARGUMENTS: '--enable-pubsub-experiment --migrate=true --agent-version-suffix=docker --routing=dhtclient'
UPLOAD_KBPS: '1000'
DOWNLOAD_KBPS: '1000'
logging:
driver: 'json-file'
options:
max-size: '10m'
max-file: '10'
mem_limit: 2000mb
ports:
- 4001:4001
- 4003:4003
- 172.17.0.1:5001:5001
- 172.17.0.1:8080:8080
command: [
'./start-ipfs.sh'
]
volumes:
- ../data/go-ipfs/data:/root/.ipfs
restart: always
p2wdb:
#build:
# context: ./p2wdb/
# dockerfile: Dockerfile
image: christroutner/p2wdb:v3.0.9
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:
#build:
# context: ./bch-dex/
# dockerfile: Dockerfile
image: christroutner/bch-dex:v1.9.6
build:
context: ./bch-dex/
dockerfile: Dockerfile
#image: christroutner/bch-dex:v2.2.4
container_name: bch-dex
environment:
CONSUMER_URL: 'https://free-bch.fullstack.cash'
@@ -84,29 +28,34 @@ services:
max-file: '10'
mem_limit: 1000mb
links:
- mongo-p2wdb-service
- p2wdb
- mongo-dex
#- p2wdb
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:
- ../scripts/wallet.json:/home/safeuser/bch-dex/wallet.json
- ./bch-dex/start-production.sh:/home/safeuser/bch-dex/start-production.sh
restart: always
dex-ui:
#build:
# context: ./bch-dex-ui/
# dockerfile: Dockerfile
image: christroutner/bch-dex-ui:v1.6.6
build:
context: ./bch-dex-ui/
dockerfile: Dockerfile
#image: christroutner/bch-dex-ui:v1.2.4
container_name: dex-ui
environment:
SERVER: 'http://192.168.2.3'
SERVER: 'http://172.17.0.1'
logging:
driver: 'json-file'
options:
max-size: '10m'
max-file: '10'
mem_limit: 500mb
mem_limit: 1000mb
links:
- bch-dex
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
+8 -13
View File
@@ -12,9 +12,12 @@ 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
RUN sudo apt-get install -y ca-certificates curl gnupg
RUN sudo mkdir -p /etc/apt/keyrings
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.
#RUN useradd -ms /bin/bash safeuser
@@ -34,7 +37,7 @@ WORKDIR /home/safeuser
# Update to the latest version of npm.
#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.
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
# For development: switch to unstable branch
RUN git checkout ct-unstable
RUN git checkout master
# Install dependencies
#RUN mkdir .ipfsdata
@@ -63,14 +66,6 @@ RUN npm install
# Generate the API 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.
#COPY start-production.sh start-production.sh
CMD ["./start-production.sh"]
@@ -24,7 +24,7 @@ export DBURL=mongodb://172.17.0.1:5666/bch-swap-service-prod
export PORT=5700
# bch-dex specific env vars
export BCH_DEX=production
export BCH_DEX=prod
export WEBHOOKSERVICE=http://172.17.0.1:5667/webhook
export WEBHOOKTARGET=http://172.17.0.1:5700/p2wdb
export APP_ID=bch-dex-001
+7 -6
View File
@@ -43,10 +43,10 @@ services:
#build:
# context: ./p2wdb/
# dockerfile: Dockerfile
image: christroutner/p2wdb-rpi:v3.0.10
image: christroutner/p2wdb-rpi:v3.1.9
container_name: p2wdb
environment:
CONSUMER_URL: 'https://free-bch.fullstack.cash'
CONSUMER_URL: 'https://wa-usa-bch-consumer.fullstackcash.nl'
DEBUG_LEVEL: 1
logging:
driver: 'json-file'
@@ -69,11 +69,12 @@ services:
bch-dex:
#build:
# context: ./bch-dex/
# dockerfile: Dockerfile
image: christroutner/bch-dex-rpi:v1.9.6
# dockerfile: Dockerfile
image: christroutner/bch-dex-rpi:v2.0.8
container_name: bch-dex
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:
driver: 'json-file'
options:
@@ -94,7 +95,7 @@ services:
#build:
# context: ./bch-dex-ui/
# dockerfile: Dockerfile
image: christroutner/bch-dex-ui-rpi:v1.7.5
image: christroutner/bch-dex-ui-rpi:v1.2.4
container_name: dex-ui
logging:
driver: 'json-file'
@@ -41,8 +41,14 @@ export IPFS_HOST=172.17.0.1
export IPFS_API_PORT=5001
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
export ORBITDB_NAME=/orbitdb/zdpuAqNiwLiJBfbRK7uihV2hAbNSXj78ufzv5VyQb8GuvRwDh/psf-bch-p2wdb-keyvalue-v3.0.0-0001
# Use this if the IPFS node has a publically accessible IP address.
#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
+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.
*/
const axios = require('axios')
import axios from 'axios'
const LOCALHOST = 'http://localhost:5700'
// const LOCALHOST = 'http://172.17.0.1:5700'
+6 -5
View File
@@ -3,8 +3,9 @@
*/
// Public NPM libraries
const BchWallet = require('minimal-slp-wallet/index')
const fs = require('fs').promises
import BchWallet from 'minimal-slp-wallet'
import { promises as fs } from 'fs'
async function createWallet () {
try {
@@ -15,9 +16,9 @@ async function createWallet () {
}
// Wait for the wallet to be created.
this.bchWallet = new BchWallet(undefined, advancedConfig)
await this.bchWallet.walletInfoPromise
const walletData = this.bchWallet.walletInfo
const bchWallet = new BchWallet(undefined, advancedConfig)
await bchWallet.walletInfoPromise
const walletData = bchWallet.walletInfo
walletData.nextAddress = 1
// 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
}
}
+6 -2
View File
@@ -5,10 +5,10 @@
*/
// Global npm libraries
const BchWallet = require('minimal-slp-wallet/index')
import BchWallet from 'minimal-slp-wallet'
// Local libraries
const WalletAdapter = require('../../src/adapters/wallet')
import WalletAdapter from '../../src/adapters/wallet.js'
// Constants
const EMTPY_ADDR_CUTOFF = 10
@@ -64,6 +64,8 @@ async function sweepNfts () {
if (thisToken.tokenType === 65) {
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.
const receiver1 = [{
address: cashAddress,
@@ -76,6 +78,8 @@ async function sweepNfts () {
console.log('Waiting for indexers to update...')
await bchjs.Util.sleep(120000)
await walletChild.initialize()
// Send NFT to root address.
const receiver2 = [{
address: rootAddr,
+2 -4
View File
@@ -2,16 +2,14 @@
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
to pay for the transactions.
This script will sweep BCH and fungible (Type 1) tokens, but not NFTs.
*/
// Public npm libraries
// const BCHJS = require('@psf/bch-js')
const BchTokenSweep = require('bch-token-sweep/index')
import BchTokenSweep from 'bch-token-sweep/index.js'
// Local libraries
const WalletAdapter = require('../../src/adapters/wallet')
import WalletAdapter from '../../src/adapters/wallet.js'
// Constants
const EMTPY_ADDR_CUTOFF = 10
+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"
# 0 = less verbose. 3 = most verbose
export DEBUG_LEVEL=2
export DEBUG_LEVEL=0
# Production settings that use external IPFS node.
# https://github.com/christroutner/docker-ipfs
+43 -64
View File
@@ -13,16 +13,24 @@
in the Adapter directory.
*/
'use strict'
const axios = require('axios').default
const mongoose = require('mongoose')
const User = require('../adapters/localdb/models/users')
const config = require('../../config')
const JsonFiles = require('../adapters/json-files')
// Global npm libraries
import axios from 'axios'
import mongoose from 'mongoose'
// Local libraries
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 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 context = {}
@@ -43,68 +51,38 @@ class Admin {
// used by the Listing Manager and test scripts, in order access private API
// functions.
async createSystemUser () {
// Create the system user.
try {
context.password = _this._randomString(20)
const options = {
method: 'POST',
url: `${LOCALHOST}/users`,
data: {
user: {
email: 'system@system.com',
password: context.password,
name: 'admin'
}
}
const context = {
email: 'system@system.com',
name: 'admin',
password: _this.config.adminPassword || _this._randomString(20),
type: 'admin',
mnemonic: 'spread ivory oval pioneer flash gap merit nerve simple image entire trouble'
}
const result = await _this.axios.request(options)
// console.log('admin.data: ', result.data)
// Check if the user already exists
let adminUser = await _this.User.findOne({ email: context.email })
context.email = result.data.user.email
context.id = result.data.user._id
context.token = result.data.token
if (adminUser) {
// Update the password
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
const user = await _this.User.findById(context.id)
// Save the user
await adminUser.save()
// Change the user type to admin
user.type = 'admin'
// 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)
// Write the user data to the JSON file
await _this.jsonFiles.writeJSON(context, JSON_PATH)
return context
} catch (err) {
// Handle existing system user.
if (err.response.status === 422) {
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
}
} catch (error) {
console.log('Error in admin.js/createSystemUser()')
throw error
}
}
@@ -119,6 +97,7 @@ class Admin {
})
await _this.User.deleteOne({ email: 'system@system.com' })
return true
} catch (err) {
console.log('Error in admin.js/deleteExistingSystemUser()')
throw err
@@ -142,7 +121,7 @@ class Admin {
Accept: 'application/json'
},
data: {
email: 'system@system.com',
email: existingUser.email,
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
const BCHJS = require('@psf/bch-js')
const MsgLib = require('bch-message-lib')
const BchWallet = require('minimal-slp-wallet/index')
import BCHJS from '@psf/bch-js'
import MsgLib from 'bch-message-lib'
import BchWallet from 'minimal-slp-wallet'
class Bch {
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) {
try {
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 */
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'
const config = require('../../config')
const NodeMailer = require('../adapters/nodemailer')
const nodemailer = new NodeMailer()
const { wlogger } = require('../adapters/wlogger')
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.
*/
const JwtLib = require('jwt-bch-lib')
const BCHJS = require('@psf/bch-js')
import JwtLib from 'jwt-bch-lib'
import BCHJS from '@psf/bch-js'
class FullStackJWT {
constructor (localConfig = {}) {
@@ -98,4 +99,4 @@ class FullStackJWT {
}
}
module.exports = FullStackJWT
export default FullStackJWT
+42 -16
View File
@@ -5,23 +5,25 @@
*/
// Public NPM libraries
const BCHJS = require('@psf/bch-js')
import BCHJS from '@psf/bch-js'
// Load individual adapter libraries.
const IPFSAdapter = require('./ipfs')
const LocalDB = require('./localdb')
const LogsAPI = require('./logapi')
const Passport = require('./passport')
const Nodemailer = require('./nodemailer')
import IPFSAdapter from './ipfs/index.js'
import LocalDB from './localdb/index.js'
import LogsAPI from './logapi.js'
import Passport from './passport.js'
import Nodemailer from './nodemailer.js'
// const { wlogger } = require('./wlogger')
const JSONFiles = require('./json-files')
const FullStackJWT = require('./fullstack-jwt')
const BCHAdapter = require('./bch')
const WalletAdapter = require('./wallet')
const P2wdbAdapter = require('./p2wdb-adapter')
const Webhook = require('./webhook')
import JSONFiles from './json-files.js'
import FullStackJWT from './fullstack-jwt.js'
import config from '../../config/index.js'
// import Wallet from './wallet.adapter.js'
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 {
constructor (localConfig = {}) {
@@ -40,6 +42,9 @@ class Adapters {
localConfig.bchWallet = this.wallet.bchWallet
this.p2wdb = new P2wdbAdapter(localConfig)
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.
this.fullStackJwt = new FullStackJWT(config)
@@ -47,14 +52,22 @@ class Adapters {
async start () {
try {
// let apiToken
if (this.config.getJwtAtStartup) {
// Get a JWT token and instantiate bch-js with it. Then pass that instance
// 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.
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.
// Do not start these adapters if this is an e2e test.
// if (this.config.env !== 'test') {
@@ -63,6 +76,8 @@ class Adapters {
// Open the wallet file
const walletData = await this.wallet.openWallet()
await this.nostr.start(walletData.privateKey)
// console.log('walletData: ', walletData)
if (this.config.env !== 'test') {
@@ -70,7 +85,18 @@ class Adapters {
await this.wallet.instanceWallet(walletData, this.bchjs)
// 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.')
@@ -83,4 +109,4 @@ class Adapters {
}
}
module.exports = Adapters
export default Adapters
+139 -4
View File
@@ -3,9 +3,10 @@
*/
// Local libraries
const IpfsAdapter = require('./ipfs')
const IpfsCoordAdapter = require('./ipfs-coord')
const config = require('../../../config')
import IpfsAdapter from './ipfs.js'
import IpfsCoordAdapter from './ipfs-coord.js'
import config from '../../../config/index.js'
class IPFS {
constructor (localConfig = {}) {
@@ -57,6 +58,140 @@ class IPFS {
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
const IpfsCoord = require('ipfs-coord')
const BCHJS = require('@psf/bch-js')
const publicIp = require('public-ip')
// import IpfsCoord from 'ipfs-coord-esm'
import IpfsCoord from 'helia-coord'
// import BCHJS from '@psf/bch-js';
import SlpWallet from 'minimal-slp-wallet'
import { publicIpv4 } from 'public-ip'
// Local libraries
const config = require('../../../config')
import config from '../../../config/index.js'
// const JSONRPC = require('../../controllers/json-rpc/')
let _this
@@ -28,9 +32,10 @@ class IpfsCoordAdapter {
// Encapsulate dependencies
this.IpfsCoord = IpfsCoord
this.ipfsCoord = {}
this.bchjs = new BCHJS()
// this.bchjs = new BCHJS()
this.wallet = new SlpWallet()
this.config = config
this.publicIp = publicIp
this.publicIp = publicIpv4
// Properties of this class instance.
this.isReady = false
@@ -41,10 +46,13 @@ class IpfsCoordAdapter {
async start () {
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 (this.config.isCircuitRelay) {
try {
const ip4 = await this.publicIp.v4()
const ip4 = await this.publicIp()
// const ip6 = await publicIp.v6()
circuitRelayInfo.ip4 = ip4
@@ -57,23 +65,28 @@ class IpfsCoordAdapter {
}
}
const nullLog = () => {}
const ipfsCoordOptions = {
ipfs: this.ipfs,
type: 'node.js',
// type: 'browser',
bchjs: this.bchjs,
privateLog: console.log, // Default to console.log
wallet: this.wallet,
// privateLog: console.log, // Default to console.log
privateLog: nullLog,
isCircuitRelay: this.config.isCircuitRelay,
circuitRelayInfo,
apiInfo: this.config.apiInfo,
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.
if (this.config.isProduction) {
ipfsCoordOptions.nodeType = 'external'
}
// if (this.config.isProduction) {
// ipfsCoordOptions.nodeType = 'external'
// }
this.ipfsCoord = new this.IpfsCoord(ipfsCoordOptions)
@@ -100,12 +113,15 @@ class IpfsCoordAdapter {
// Subscribe to the chat pubsub channel
async subscribeToChat () {
// TODO: Allow user to replace nullog with their own log handler at startup.
const nullLog = () => {}
await this.ipfsCoord.adapters.pubsub.subscribeToPubsubChannel(
this.config.chatPubSubChan,
console.log,
nullLog,
this.ipfsCoord.thisNode
)
}
}
module.exports = IpfsCoordAdapter
export default IpfsCoordAdapter
+257 -81
View File
@@ -9,94 +9,98 @@
*/
// Global npm libraries
// const IPFS = require('ipfs')
// const IPFS = require('@chris.troutner/ipfs')
const IPFSembedded = require('ipfs')
const IPFSexternal = require('ipfs-http-client')
const fs = require('fs')
const http = require('http')
import { createHelia } from 'helia'
import fs from 'fs'
import { FsBlockstore } from 'blockstore-fs'
import { FsDatastore } from 'datastore-fs'
import { createLibp2p } from 'libp2p'
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
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 {
constructor (localConfig) {
// Encapsulate dependencies
this.config = config
// Choose the IPFS constructor based on the config settings.
this.IPFS = IPFSembedded // default
if (this.config.isProduction) {
this.IPFS = IPFSexternal
}
this.fs = fs
this.createLibp2p = createLibp2p
this.publicIp = publicIpv4
this.multiaddr = multiaddr
this.jsonFiles = new JsonFiles()
this.keychain = keychain
this.createHelia = createHelia
// Properties of this class instance.
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.
async start () {
try {
// Ipfs Options
const ipfsOptionsEmbedded = {
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'
}
}
}
// Ensure the directory structure exists that is needed by the IPFS node to store data.
this.ensureBlocksDir()
const ipfsOptionsExternal = {
host: this.config.ipfsHost,
port: this.config.ipfsApiPort,
agent: http.Agent({ keepAlive: true, maxSockets: 2000 })
}
// Create an IPFS node
const ipfs = await this.createNode()
// console.log('ipfs: ', ipfs)
let ipfsOptions = ipfsOptionsEmbedded
if (this.config.isProduction) {
ipfsOptions = ipfsOptionsExternal
}
this.id = ipfs.libp2p.peerId.toString()
console.log('IPFS ID: ', this.id)
// Create a new IPFS node.
this.ipfs = await this.IPFS.create(ipfsOptions)
// Attempt to guess our ip4 IP address.
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.
await this.ipfs.config.profiles.apply('server')
// Get the multiaddrs for the node.
const multiaddrs = ipfs.libp2p.getMultiaddrs()
multiaddrs.push(detectedMultiaddr)
console.log('Multiaddrs: ', multiaddrs)
// Debugging: Display IPFS config settings.
// const configSettings = await this.ipfs.config.getAll()
// console.log(`configSettings: ${JSON.stringify(configSettings, null, 2)}`)
this.multiaddrs = multiaddrs
// Signal that this adapter is ready.
this.isReady = true
this.ipfs = ipfs
return this.ipfs
} catch (err) {
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 () {
await this.ipfs.stop()
return true
}
// Remove the '/blocks' directory that is used to store IPFS data.
// Dev Note: It's assumed this node is not pinning any data and that
// everything in this directory is transient. This folder will regularly
// fill up and prevent IPFS from starting.
// rmBlocksDir () {
// try {
// const dir = `${IPFS_DIR}/blocks`
// console.log(`Deleting ${dir} directory...`)
//
// this.fs.rmdirSync(dir, { recursive: true })
//
// console.log(`${dir} directory is deleted!`)
//
// return true // Signal successful execution.
// } catch (err) {
// console.log('Error in rmBlocksDir()')
// throw err
// }
// Ensure that the directories exist to store blocks from the IPFS network.
// This function is called at startup, before the IPFS node is started.
ensureBlocksDir () {
try {
!this.fs.existsSync(`${ROOT_DIR}.ipfsdata`) && this.fs.mkdirSync(`${ROOT_DIR}.ipfsdata`)
!this.fs.existsSync(`${IPFS_DIR}`) && this.fs.mkdirSync(`${IPFS_DIR}`)
!this.fs.existsSync(`${IPFS_DIR}/blockstore`) && this.fs.mkdirSync(`${IPFS_DIR}/blockstore`)
!this.fs.existsSync(`${IPFS_DIR}/datastore`) && this.fs.mkdirSync(`${IPFS_DIR}/datastore`)
!this.fs.existsSync(`${IPFS_DIR}/datastore/pkcs8`) && this.fs.mkdirSync(`${IPFS_DIR}/datastore/pkcs8`)
// !fs.existsSync(`${IPFS_DIR}/datastore/peers`) && fs.mkdirSync(`${IPFS_DIR}/datastore/peers`)
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.
*/
'use strict'
const fs = require('fs')
import fs from 'fs'
let _this
@@ -75,4 +75,4 @@ class JsonFiles {
}
}
module.exports = JsonFiles
export default JsonFiles
+9 -5
View File
@@ -3,10 +3,12 @@
*/
// Load Mongoose models.
const Users = require('./models/users')
const Entries = require('./models/entry')
const Order = require('./models/order')
const Offer = require('./models/offer')
import Users from './models/users.js'
import Entries from './models/entry.js'
import Order from './models/order.js'
import Offer from './models/offer.js'
import Usage from './models/usage.js'
import SmAccount from './models/smAccount.js'
class LocalDB {
constructor () {
@@ -15,7 +17,9 @@ class LocalDB {
this.Entry = Entries
this.Order = Order
this.Offer = Offer
this.Usage = Usage
this.SmAccount = SmAccount
}
}
module.exports = LocalDB
export default LocalDB
@@ -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({
entry: { type: String },
@@ -10,4 +10,4 @@ const Entry = new mongoose.Schema({
merit: { type: Number }
})
module.exports = mongoose.model('entry', Entry)
export default mongoose.model('entry', Entry)
+20 -4
View File
@@ -1,4 +1,4 @@
const mongoose = require('mongoose')
import mongoose from 'mongoose'
const Offer = new mongoose.Schema({
@@ -6,7 +6,7 @@ const Offer = new mongoose.Schema({
tokenId: { type: String },
utxoTxid: { type: String },
utxoVout: { type: Number },
ticker: { type: String },
ticker: { type: String, default: '' },
tokenType: { type: Number },
// Trade data
@@ -27,12 +27,28 @@ const Offer = new mongoose.Schema({
timestamp: { type: Number },
globalTimestamp: { type: String },
localTimestamp: { type: String },
displayCategory: { type: String },
nsfw: { type: Boolean, default: false },
flags: { type: Array },
// SWaP Protocol Properties
lokadId: { type: String },
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 },
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)
+23 -13
View File
@@ -6,24 +6,24 @@
See the dev-docs/specification.md for details on each property.
*/
const mongoose = require('mongoose')
import mongoose from 'mongoose'
const Order = new mongoose.Schema({
// Token data
tokenId: { type: String },
utxoTxid: { type: String },
utxoVout: { type: Number },
ticker: { type: String },
tokenType: { type: Number },
tokenId: { type: String, required: true },
utxoTxid: { type: String, required: true },
utxoVout: { type: Number, required: true },
ticker: { type: String, required: true },
tokenType: { type: Number, required: true },
// Trade data
buyOrSell: { type: String },
numTokens: { type: Number },
rateInBaseUnit: { type: String },
buyOrSell: { type: String, required: true },
numTokens: { type: Number, required: true },
rateInBaseUnit: { type: String, required: true },
minUnitsToExchange: { type: String },
p2wdbTxid: { type: String },
p2wdbHash: { type: String },
makerAddr: { type: String },
makerAddr: { type: String, required: true },
// Authentication data
signature: { type: String },
@@ -32,12 +32,22 @@ const Order = new mongoose.Schema({
offerPubKey: { type: String },
// 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
lokadId: { type: String },
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')
const bcrypt = require('bcryptjs')
const config = require('../../../../config')
const jwt = require('jsonwebtoken')
// Global npm libraries
import mongoose from 'mongoose'
import bcrypt from 'bcryptjs'
import jwt from 'jsonwebtoken'
// Local libraries
import config from '../../../../config/index.js'
const User = new mongoose.Schema({
type: { type: String, default: 'user' },
name: { type: String },
username: { type: String },
password: { type: String, required: true },
mnemonic: { type: String, required: true },
email: {
type: String,
required: true,
@@ -51,4 +55,4 @@ User.methods.generateToken = function generateToken () {
}
// 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.
*/
const Order = require('./models/order')
import Order from './models/order.js'
// 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')
const fs = require('fs')
import lineReader from 'line-reader'
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
const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
class LogsApi {
constructor () {
@@ -169,4 +174,4 @@ class LogsApi {
}
}
module.exports = LogsApi
export default LogsApi
+4 -5
View File
@@ -3,11 +3,10 @@
*/
'use strict'
const nodemailer = require('nodemailer')
import nodemailer from 'nodemailer'
const config = require('../../config')
const { wlogger } = require('./wlogger')
import config from '../../config/index.js'
import wlogger from './wlogger.js'
let _this
@@ -150,4 +149,4 @@ class NodeMailer {
}
}
module.exports = NodeMailer
export default NodeMailer
+252
View File
@@ -0,0 +1,252 @@
/*
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'
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)
}
// 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
}
}
}
export default NostrAdapter
+10 -4
View File
@@ -3,11 +3,13 @@
*/
// Public npm libraries.
const axios = require('axios')
const { Write, Read } = require('p2wdb/index')
import axios from 'axios'
import P2WDB from 'p2wdb-esm'
// Local libraries
const config = require('../../config')
import config from '../../config/index.js'
const { Write, Read } = P2WDB
class P2wdbAdapter {
constructor (localConfig = {}) {
@@ -26,6 +28,10 @@ class P2wdbAdapter {
// Allow the localConfig to overwrite the config file values.
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
@@ -111,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.
*/
const passport = require('koa-passport')
import passport from 'koa-passport'
let _this
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
+212 -16
View File
@@ -1,20 +1,31 @@
/*
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
const BchWallet = require('minimal-slp-wallet/index')
const bitcoinJs = require('bitcoincashjs-lib')
import BchWallet from 'minimal-slp-wallet'
import BchTokenSweep from 'bch-token-sweep/index.js'
import bitcoinJs from 'bitcoincashjs-lib'
import RetryQueue from '@chris.troutner/retry-queue'
// Local libraries
const JsonFiles = require('./json-files')
const config = require('../../config')
import JsonFiles from './json-files.js'
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 PROOF_OF_BURN_QTY = 0.01
// const P2WDB_TOKEN_ID =
// '38e97c5d7d3585a2cbf3f9580c82ca33985f9cb0845d4dcce220cb709f9538b0'
const advancedConfig = {}
class WalletAdapter {
constructor (localConfig = {}) {
// Encapsulate dependencies
@@ -23,7 +34,29 @@ class WalletAdapter {
this.config = config
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.
@@ -77,7 +110,8 @@ class WalletAdapter {
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) {
advancedConfig.interface = 'rest-api'
advancedConfig.restURL = this.config.apiServer
@@ -129,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,
// 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) {
@@ -141,6 +174,7 @@ class WalletAdapter {
}
const mnemonic = this.bchWallet.walletInfo.mnemonic
console.log(`getKeyPair() for HD index: ${hdIndex} called on mnemonic: ${mnemonic}`)
// root seed buffer
const rootSeed = await this.bchWallet.bchjs.Mnemonic.toSeed(mnemonic)
@@ -173,7 +207,9 @@ class WalletAdapter {
// Generate a cryptographic signature, required to write to the P2WDB.
async generateSignature (message) {
try {
// TODO: Add input validation for message.
if (!message || typeof message !== 'string') {
throw new Error('message is required!')
}
const privKey = this.bchWallet.walletInfo.privateKey
@@ -330,7 +366,7 @@ class WalletAdapter {
throw err
}
// return true
// return true
}
// Move tokens to an address controlled by the HD wallet, to generate a
@@ -338,6 +374,12 @@ class WalletAdapter {
async moveTokens (inObj = {}) {
try {
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()
console.log('keyPair: ', keyPair)
@@ -349,7 +391,7 @@ class WalletAdapter {
}
// Update the UTXO store of the wallet.
await this.bchWallet.getUtxos()
await this.bchWallet.initialize()
// Get the token type of the token being moved.
// Combine Fungible and NFT token UTXOs.
@@ -360,6 +402,10 @@ class WalletAdapter {
x => x.tokenId === tokenId
)
if (tokenUtxos.length === 0) {
throw new Error('tokenId not found!')
}
const txid = await this.bchWallet.sendTokens(receiver, 3)
const utxoInfo = {
@@ -380,6 +426,10 @@ class WalletAdapter {
// generate a segregated UTXO.
async moveBch (amountSat) {
try {
if (!amountSat) {
throw new Error('amountSat is required!')
}
const keyPair = await this.getKeyPair()
console.log('keyPair: ', keyPair)
@@ -412,6 +462,10 @@ class WalletAdapter {
// representing the transaction.
async deseralizeTx (txHex) {
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
// yet support this call.
const oldUrl = this.bchWallet.bchjs.RawTransactions.restURL
@@ -426,18 +480,33 @@ class WalletAdapter {
return txObj2
} catch (err) {
console.error('Error in wallet.js/deserializePartialTx()')
console.error('Error in wallet.js/deserializeTx()')
throw err
}
}
// Complete the partially signed transaction by signing the first input,
// then broadcasting the transaction to the network.
async completeTx (hex, hdIndex) {
async completeTx (hex, hdIndex, mnemonic) {
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('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
// const transactionBuilder = new bchjs.TransactionBuilder()
@@ -460,8 +529,10 @@ class WalletAdapter {
// 'mainnet'
// )
console.log('completeTx() userWallet.walletInfo: ', userWallet.walletInfo)
// 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)}`)
const makerECPair = bchjs.ECPair.fromWIF(keyPair.wif)
@@ -493,7 +564,9 @@ class WalletAdapter {
// return csTxHex
// 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
} catch (err) {
@@ -501,6 +574,129 @@ class WalletAdapter {
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.
*/
const config = require('../../config')
const axios = require('axios')
import config from '../../config/index.js'
let _this
import axios from 'axios'
class WebHook {
constructor () {
_this = this
_this.config = config
_this.axios = axios
this.config = config
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
@@ -21,14 +24,14 @@ class WebHook {
throw new Error('url must be a string')
}
const endpoint = _this.config.webhookService
const endpoint = this.config.webhookService
const obj = {
appId: this.config.p2wdbAppId,
url
}
const result = await axios.post(endpoint, obj)
const result = await this.axios.post(endpoint, obj)
return result.data
} catch (err) {
@@ -44,14 +47,14 @@ class WebHook {
throw new Error('url must be a string')
}
const endpoint = _this.config.webhookService
const endpoint = this.config.webhookService
const obj = {
appId: this.config.p2wdbAppId,
url
}
const result = await axios.delete(endpoint, { data: obj })
const result = await this.axios.delete(endpoint, { data: obj })
return result.data
} catch (err) {
@@ -85,7 +88,7 @@ class WebHook {
} catch (err) {
const now = new Date()
console.log(`${now.toLocaleString()}: Error trying to create webhook with P2WDB. Trying again...`)
await sleep(2000)
await this.sleep(this.sleepTime)
}
} while (!success)
@@ -95,10 +98,10 @@ class WebHook {
throw err
}
}
async sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
}
function sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
module.exports = WebHook
export default WebHook
+12 -4
View File
@@ -6,10 +6,17 @@
'use strict'
const winston = require('winston')
require('winston-daily-rotate-file')
// Global npm libraries
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 {
constructor (localConfig = {}) {
@@ -70,4 +77,5 @@ logger.outputToConsole()
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.
// Local libraries
const Adapters = require('../adapters')
const JSONRPC = require('./json-rpc')
const UseCases = require('../use-cases')
const RESTControllers = require('./rest-api')
const TimerControllers = require('./timer-controllers')
import Adapters from '../adapters/index.js'
import JSONRPC from './json-rpc/index.js'
import UseCases from '../use-cases/index.js'
import RESTControllers from './rest-api/index.js'
import TimerControllers from './timer-controllers.js'
import config from '../../config/index.js'
class Controllers {
constructor (localConfig = {}) {
// Encapsulate dependencies
this.adapters = new Adapters()
this.useCases = new UseCases({ adapters: this.adapters })
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.
@@ -45,8 +54,13 @@ class Controllers {
// Attach any other controllers other than REST API controllers.
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.
@@ -63,4 +77,4 @@ class Controllers {
}
}
module.exports = Controllers
export default Controllers
+3 -3
View File
@@ -6,10 +6,10 @@
*/
// Public npm libraries
const jsonrpc = require('jsonrpc-lite')
import jsonrpc from 'jsonrpc-lite'
// Local libraries
const config = require('../../../../config')
import config from '../../../../config/index.js'
class AboutRPC {
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
const jsonrpc = require('jsonrpc-lite')
import jsonrpc from 'jsonrpc-lite'
// Local libraries
// const AuthLib = require('../../lib/auth')
// const UserLib = require('../../../use-cases/user')
const { wlogger } = require('../../../adapters/wlogger')
const RateLimit = require('../rate-limit')
import wlogger from '../../../adapters/wlogger.js'
import RateLimit from '../rate-limit.js'
class AuthRPC {
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
const jsonrpc = require('jsonrpc-lite')
import jsonrpc from 'jsonrpc-lite'
// Local support libraries
const { wlogger } = require('../../adapters/wlogger')
const UserController = require('./users')
const AuthController = require('./auth')
const AboutController = require('./about')
import wlogger from '../../adapters/wlogger.js'
import UserController from './users/index.js'
import AuthController from './auth/index.js'
import AboutController from './about/index.js'
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 */
// Local libraries
const RateLimitLib = require('koa2-ratelimit').RateLimit
import { RateLimit as RateLimitLib } from 'koa2-ratelimit'
class RateLimit {
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
const jsonrpc = require('jsonrpc-lite')
import jsonrpc from 'jsonrpc-lite'
// Local libraries
// const UserLib = require('../../../use-cases/user')
const Validators = require('../validators')
const RateLimit = require('../rate-limit')
import Validators from '../validators.js'
import RateLimit from '../rate-limit.js'
class UserRPC {
constructor (localConfig = {}) {
@@ -533,4 +534,4 @@ class UserRPC {
// TODO create deleteUser()
}
module.exports = UserRPC
export default UserRPC
+4 -3
View File
@@ -4,10 +4,11 @@
/* eslint no-useless-catch: 0 */
// Public npm libraries
const jwt = require('jsonwebtoken')
import jwt from 'jsonwebtoken'
// Local libraries
const config = require('../../../config')
import config from '../../../config/index.js'
// const UserModel = require('../../adapters/localdb/models/users')
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()
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.
const Router = require('koa-router')
import Router from 'koa-router'
// Local libraries.
const AuthRESTController = require('./controller')
import AuthRESTController from './controller.js'
class AuthRouter {
constructor (localConfig = {}) {
@@ -48,4 +48,4 @@ class AuthRouter {
}
}
module.exports = AuthRouter
export default AuthRouter
@@ -3,9 +3,9 @@
*/
/* 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()
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.
const Router = require('koa-router')
import Router from 'koa-router'
// Local libraries.
const ContactRESTControllerLib = require('./controller')
import ContactRESTControllerLib from './controller.js'
class ContactRouter {
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
}
/**
* @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
// Note: this is a private endpoint, needs to be authenticated
async createEntry (ctx) {
try {
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.
const Router = require('koa-router')
import Router from 'koa-router'
// Local libraries.
const EntryRESTControllerLib = require('./controller')
import EntryRESTControllerLib from './controller.js'
let _this
@@ -57,4 +57,4 @@ class UserRouter {
}
}
module.exports = UserRouter
export default UserRouter
+38 -17
View File
@@ -6,15 +6,19 @@
// Public npm libraries.
// Load the REST API Controllers.
const AuthRESTController = require('./auth')
const UserRouter = require('./users')
const ContactRESTController = require('./contact')
const LogsRESTController = require('./logs')
const EntryRouter = require('./entry')
const OfferRouter = require('./offer')
const OrderRouter = require('./order')
const P2WDBRouter = require('./p2wdb')
// Local libraries
import AuthRESTController from './auth/index.js'
import UserRouter from './users/index.js'
import ContactRESTController from './contact/index.js'
import LogsRESTController from './logs/index.js'
import IpfsRESTController from './ipfs/index.js'
import config from '../../../config/index.js'
import EntryRouter from './entry/index.js'
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'
class RESTControllers {
constructor (localConfig = {}) {
@@ -32,7 +36,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) {
@@ -41,13 +49,15 @@ class RESTControllers {
useCases: this.useCases
}
// Attach the REST API Controllers associated with the /auth route
const authRESTController = new AuthRESTController(dependencies)
authRESTController.attach(app)
if (!this.config.noMongo) {
// Attach the REST API Controllers associated with the /auth route
const authRESTController = new AuthRESTController(dependencies)
authRESTController.attach(app)
// Attach the REST API Controllers associated with the /user route
const userRouter = new UserRouter(dependencies)
userRouter.attach(app)
// Attach the REST API Controllers associated with the /user route
const userRouter = new UserRouter(dependencies)
userRouter.attach(app)
}
// Attach the REST API Controllers associated with the /contact route
const contactRESTController = new ContactRESTController(dependencies)
@@ -57,6 +67,10 @@ class RESTControllers {
const logsRESTController = new LogsRESTController(dependencies)
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
const entryRouter = new EntryRouter(dependencies)
entryRouter.attach(app)
@@ -69,7 +83,14 @@ class RESTControllers {
const p2wdbRouter = new P2WDBRouter(dependencies)
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)
}
}
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()
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.
const Router = require('koa-router')
import Router from 'koa-router'
// Local libraries.
const LogsRESTControllerLib = require('./controller')
import LogsRESTControllerLib from './controller.js'
class LogsRouter {
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) => {
try {
await next()
@@ -8,4 +8,4 @@ module.exports = function errorMiddleware () {
ctx.app.emit('error', err, ctx)
}
}
}
};
@@ -1,11 +1,24 @@
/*
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')
const config = require('../../../../config')
const jwt = require('jsonwebtoken')
const { wlogger } = require('../../../adapters/wlogger')
import User from '../../../adapters/localdb/models/users.js'
import config from '../../../../config/index.js'
import jwt from 'jsonwebtoken'
import wlogger from '../../../adapters/wlogger.js'
let _this
@@ -20,12 +33,10 @@ class Validators {
async ensureUser (ctx, next) {
try {
// console.log(`getToken: ${typeof (getToken)}`)
const token = _this.getToken(ctx)
if (!token) {
// console.log(`Err: Token not provided.`)
ctx.throw(401)
throw new Error('Token could not be retrieved from header')
}
let decoded = null
@@ -34,20 +45,23 @@ class Validators {
// console.log(`config: ${JSON.stringify(config, null, 2)}`)
decoded = _this.jwt.verify(token, config.token)
} catch (err) {
// console.log(`Err: Token could not be decoded: ${err}`)
ctx.throw(401)
throw new Error('Could not verify JWT')
}
ctx.state.user = await _this.User.findById(decoded.id, '-password')
if (!ctx.state.user) {
// console.log(`Err: Could not find user.`)
ctx.throw(401)
// console.log('Err: Could not find user.')
throw new Error('Could not find user')
}
// return next()
return true
} 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) {
// 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
@@ -70,22 +85,26 @@ class Validators {
decoded = _this.jwt.verify(token, config.token)
} catch (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')
if (!ctx.state.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') {
ctx.throw(401, 'not admin')
// ctx.throw(401, 'not admin')
throw new Error('User is not an admin')
}
// return next()
return true
} catch (error) {
ctx.status = 401
ctx.throw(401, error.message)
}
}
@@ -101,7 +120,8 @@ class Validators {
if (!token) {
// 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.
@@ -114,14 +134,16 @@ class Validators {
// console.log(`config: ${JSON.stringify(config, null, 2)}`)
decoded = _this.jwt.verify(token, config.token)
} catch (err) {
// console.log(`Err: Token could not be decoded: ${err}`)
ctx.throw(401)
console.log(`Err: Token could not be decoded: ${err}`)
// ctx.throw(401)
throw new Error('Could not verify JWT')
}
ctx.state.user = await _this.User.findById(decoded.id, '-password')
if (!ctx.state.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)
@@ -135,7 +157,8 @@ class Validators {
// If they don't match, then the calling user better be an 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 {
wlogger.verbose("It's ok. The user is an admin.")
}
@@ -144,6 +167,8 @@ class Validators {
// return next()
return true
} catch (error) {
// console.log('Error in ensureTargetUserOrAdmin(): ', error)
ctx.status = 401
ctx.throw(401, error.message)
}
}
@@ -166,4 +191,4 @@ class Validators {
}
}
module.exports = Validators
export default Validators
+345 -15
View File
@@ -1,10 +1,11 @@
/*
REST API Controller library for the /offer route
TODO:
- Add api-doc documentation for all endpoints in this file.
*/
const { wlogger } = require('../../../adapters/wlogger')
let _this
import wlogger from '../../../adapters/wlogger.js'
class OfferRESTControllerLib {
constructor (localConfig = {}) {
@@ -26,17 +27,26 @@ class OfferRESTControllerLib {
this.OfferModel = this.adapters.localdb.Offer
// 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.handleError = this.handleError.bind(this)
}
// No api-doc documentation because this wont be a public endpoint
// This function has no endpoint
async createOffer (ctx) {
try {
console.log('body: ', ctx.request.body)
const offerObj = ctx.request.body
await _this.useCases.offer.createOffer(offerObj)
await this.useCases.offer.createOffer(offerObj)
ctx.body = {
success: true
@@ -45,36 +55,356 @@ class OfferRESTControllerLib {
// console.log(`err.message: ${err.message}`)
// console.log('err: ', err)
// 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) {
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
} catch (err) {
console.log('Error in listOffers REST API handler.')
_this.handleError(ctx, err)
console.log('Error in listOffers REST API handler: ', 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'
// listed in the offer.
async takeOffer (ctx) {
try {
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) {
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)
}
}
@@ -95,4 +425,4 @@ class OfferRESTControllerLib {
}
}
module.exports = OfferRESTControllerLib
export default OfferRESTControllerLib
+19 -11
View File
@@ -3,12 +3,10 @@
*/
// Public npm libraries.
const Router = require('koa-router')
import Router from 'koa-router'
// Local libraries.
const OfferRESTControllerLib = require('./controller')
let _this
import OfferRESTControllerLib from './controller.js'
class OfferRouter {
constructor (localConfig = {}) {
@@ -38,7 +36,8 @@ class OfferRouter {
const baseUrl = '/offer'
this.router = new Router({ prefix: baseUrl })
_this = this
// Bind 'this' object to all subfunctions.
this.attach = this.attach.bind(this)
}
attach (app) {
@@ -48,15 +47,24 @@ 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.
this.router.post('/', _this.offerRESTController.createOffer)
this.router.get('/list', _this.offerRESTController.listOffers)
this.router.post('/take', _this.offerRESTController.takeOffer)
// this.router.post('/', _this.offerRESTController.createOffer) // Deprecated.
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)
// Attach the Controller routes to the Koa app.
app.use(_this.router.routes())
app.use(_this.router.allowedMethods())
app.use(this.router.routes())
app.use(this.router.allowedMethods())
}
}
module.exports = OfferRouter
export default OfferRouter
+147 -4
View File
@@ -29,16 +29,159 @@ class OrderRESTControllerLib {
_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) {
try {
// console.log('body: ', ctx.request.body)
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) {
// console.log(`err.message: ${err.message}`)
// 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.
const Router = require('koa-router')
import Router from 'koa-router'
// Local libraries.
const OrderRESTControllerLib = require('./controller')
import OrderRESTControllerLib from './controller.js'
import Validators from '../middleware/validators.js'
let _this
@@ -32,12 +33,14 @@ class OrderRouter {
}
// Encapsulate dependencies.
this.validators = new Validators()
this.orderRESTController = new OrderRESTControllerLib(dependencies)
// Instantiate the router and set the base route.
const baseUrl = '/order'
this.router = new Router({ prefix: baseUrl })
this.createOrder = this.createOrder.bind(this)
_this = this
}
@@ -49,12 +52,24 @@ class OrderRouter {
}
// 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.
app.use(_this.router.routes())
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
}
// 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) {
try {
console.log('p2wdb REST API handler: body: ', ctx.request.body)
@@ -45,14 +63,26 @@ class P2WDBRESTControllerLib {
const counterOffer = ctx.request.body
await _this.useCases.offer.acceptCounterOffer(counterOffer)
//
} else if (dataType.includes('offer')) {
// Detect and handle new Offers
console.log('offer data detected')
const offerObj = ctx.request.body
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 {
console.log('Could not route P2WDB webhook data.')
// NOTE: Should we throw an error here?
}
// const orderObj = ctx.request.body.order
@@ -90,4 +120,4 @@ class P2WDBRESTControllerLib {
}
}
module.exports = P2WDBRESTControllerLib
export default P2WDBRESTControllerLib
+3 -3
View File
@@ -5,10 +5,10 @@
*/
// Public npm libraries.
const Router = require('koa-router')
import Router from 'koa-router'
// Local libraries.
const P2WDBRESTControllerLib = require('./controller')
import P2WDBRESTControllerLib from './controller.js'
let _this
@@ -59,4 +59,4 @@ class P2WDBRouter {
}
}
module.exports = P2WDBRouter
export default P2WDBRouter
@@ -0,0 +1,137 @@
/*
REST API Controller library for the /order route
*/
// const { wlogger } = require('../../../adapters/wlogger')
let _this
class SmAccountRESTControllerLib {
constructor (localConfig = {}) {
// Dependency Injection.
this.adapters = localConfig.adapters
if (!this.adapters) {
throw new Error(
'Instance of Adapters library required when instantiating /sm REST Controller.'
)
}
this.useCases = localConfig.useCases
if (!this.useCases) {
throw new Error(
'Instance of Use Cases library required when instantiating /sm REST Controller.'
)
}
// Encapsulate dependencies
this.SmAccountModel = this.adapters.localdb.SmAccount
// this.userUseCases = this.useCases.user
_this = this
}
/**
* @api {get} /sm/list/all/{page} List all Social Media Accounts
* @apiPermission public
* @apiName ListAccounts
* @apiGroup REST Social Media Accounts
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X GET localhost:5700/sm/list/all/0
*
*/
// curl -X GET http://localhost:5700/sm/list/all/0
async listAccounts (ctx) {
try {
let page = ctx.params.page
if (!page) page = 0
const offers = await _this.useCases.smAccount.listAccounts(page)
ctx.body = offers
} catch (err) {
console.log('Error in listAccounts REST API handler: ', err)
_this.handleError(ctx, err)
}
}
/**
* @api {get} /sm/npub/{npub} Get Social Media Account by Npub
* @apiPermission public
* @apiName GetAccountByNpub
* @apiGroup REST Social Media Accounts
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X GET localhost:5700/sm/npub/npub1y3xq402pu9aqms3khetnt5gzm54t63pzcla56wwfmwshde0ws77qkff5gc
*
*/
// curl -X GET http://localhost:5700/sm/npub/npub1y3xq402pu9aqms3khetnt5gzm54t63pzcla56wwfmwshde0ws77qkff5gc
async getAccountByNpub (ctx) {
try {
const npub = ctx.params.npub
if (!npub) {
ctx.throw(400, 'Npub is required')
}
const account = await _this.useCases.smAccount.getAccountByNpub(npub)
if (!account) {
ctx.throw(404, 'Account not found')
}
ctx.body = account
} catch (err) {
// console.log('Error in getAccountByNpub REST API handler: ', err)
_this.handleError(ctx, err)
}
}
/**
* @api {get} /sm/bchAddr/{bchAddr} Get Social Media Account by BCH address
* @apiPermission public
* @apiName GetAccountByBchAddr
* @apiGroup REST Social Media Accounts
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X GET localhost:5700/sm/bchAddr/bitcoincash:qz6lf6gpmn3secx73g7ucfcgy8mrh3sz2y2ylk643x
*
*/
// curl -X GET http://localhost:5700/sm/bchAddr/bitcoincash:qz6lf6gpmn3secx73g7ucfcgy8mrh3sz2y2ylk643x
async getAccountByBchAddr (ctx) {
try {
const bchAddr = ctx.params.bchAddr
if (!bchAddr) {
ctx.throw(400, 'BCH address is required')
}
const account = await _this.useCases.smAccount.getAccountByBchAddr(bchAddr)
if (!account) {
ctx.throw(404, 'Account not found')
}
ctx.body = account
} catch (err) {
// console.log('Error in getAccountByBchAddr REST API handler: ', err)
_this.handleError(ctx, err)
}
}
// DRY error handler
handleError (ctx, err) {
console.log('err', 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 SmAccountRESTControllerLib
@@ -0,0 +1,64 @@
/*
REST API library for /order route.
*/
// Public npm libraries.
import Router from 'koa-router'
// Local libraries.
import SmAccountRESTControllerLib from './controller.js'
import Validators from '../middleware/validators.js'
let _this
class SmAccountRouter {
constructor (localConfig = {}) {
// Dependency Injection.
this.adapters = localConfig.adapters
if (!this.adapters) {
throw new Error(
'Instance of Adapters library required when instantiating /sm REST Controller.'
)
}
this.useCases = localConfig.useCases
if (!this.useCases) {
throw new Error(
'Instance of Use Cases library required when instantiating /sm REST Controller.'
)
}
const dependencies = {
adapters: this.adapters,
useCases: this.useCases
}
// Encapsulate dependencies.
this.validators = new Validators()
this.smAccountRESTController = new SmAccountRESTControllerLib(dependencies)
// Instantiate the router and set the base route.
const baseUrl = '/sm'
this.router = new Router({ prefix: baseUrl })
_this = this
}
attach (app) {
if (!app) {
throw new Error(
'Must pass app object when attached REST API controllers.'
)
}
// Define the routes and attach the controller.
this.router.get('/list/all/:page', _this.smAccountRESTController.listAccounts)
this.router.get('/npub/:npub', _this.smAccountRESTController.getAccountByNpub)
this.router.get('/bchAddr/:bchAddr', _this.smAccountRESTController.getAccountByBchAddr)
// Attach the Controller routes to the Koa app.
app.use(_this.router.routes())
app.use(_this.router.allowedMethods())
}
}
export default SmAccountRouter
@@ -0,0 +1,119 @@
/*
REST API Controller library for the /usage route
*/
// Global npm libraries
// Local libraries
import wlogger from '../../../adapters/wlogger.js'
class UsageRESTControllerLib {
constructor (localConfig = {}) {
// Dependency Injection.
this.adapters = localConfig.adapters
if (!this.adapters) {
throw new Error(
'Instance of Adapters library required when instantiating /usage REST Controller.'
)
}
this.useCases = localConfig.useCases
if (!this.useCases) {
throw new Error(
'Instance of Use Cases library required when instantiating /usage REST Controller.'
)
}
// Encapsulate dependencies
// Bind 'this' object to all subfunctions
this.getStatus = this.getStatus.bind(this)
this.getTopIps = this.getTopIps.bind(this)
this.getTopEndpoints = this.getTopEndpoints.bind(this)
this.handleError = this.handleError.bind(this)
}
/**
* @api {get} /usage Get status on IPFS infrastructure
* @apiPermission public
* @apiName GetUsageStatus
* @apiGroup REST Usage
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X GET localhost:5020/usage
*
*/
getStatus (ctx) {
try {
// const status = await this.adapters.ipfs.getStatus()
const status = this.useCases.usage.getRestSummary()
ctx.body = { status }
} catch (err) {
wlogger.error('Error in usage/controller.js/getStatus(): ')
// ctx.throw(422, err.message)
this.handleError(ctx, err)
}
}
/**
* @api {get} /usage/ips Get top IP addresses consuming the REST API
* @apiPermission public
* @apiName GetUsageIPs
* @apiGroup REST Usage
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X GET localhost:5020/usage/ips
*
*/
getTopIps (ctx) {
try {
const ips = this.useCases.usage.getTopIps()
ctx.body = { ips }
} catch (err) {
wlogger.error('Error in usage/controller.js/getTopIps(): ')
// ctx.throw(422, err.message)
this.handleError(ctx, err)
}
}
/**
* @api {get} /usage/endpoints Get top endpoints consumed from the REST API
* @apiPermission public
* @apiName GetUsageEndpoints
* @apiGroup REST Usage
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X GET localhost:5020/usage/endpoints
*
*/
getTopEndpoints (ctx) {
try {
const endpoints = this.useCases.usage.getTopEndpoints()
ctx.body = { endpoints }
} catch (err) {
wlogger.error('Error in usage/controller.js/getTopEndpoints(): ')
// 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 UsageRESTControllerLib
+65
View File
@@ -0,0 +1,65 @@
/*
REST API library for the /usage route.
*/
// Public npm libraries.
import Router from 'koa-router'
// Local libraries.
import UsageRESTControllerLib from './controller.js'
import Validators from '../middleware/validators.js'
// let _this
class UsageRouter {
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.usageRESTController = new UsageRESTControllerLib(dependencies)
this.validators = new Validators()
// Instantiate the router and set the base route.
const baseUrl = '/usage'
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.usageRESTController.getStatus)
this.router.get('/ips', this.usageRESTController.getTopIps)
this.router.get('/endpoints', this.usageRESTController.getTopEndpoints)
// Attach the Controller routes to the Koa app.
app.use(this.router.routes())
app.use(this.router.allowedMethods())
}
}
// module.exports = BchRouter
export default UsageRouter
+5 -5
View File
@@ -2,7 +2,7 @@
REST API Controller library for the /user route
*/
const { wlogger } = require('../../../adapters/wlogger')
import wlogger from '../../../adapters/wlogger.js'
let _this
@@ -36,7 +36,7 @@ class UserRESTControllerLib {
* @apiGroup REST Users
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X POST -d '{ "user": { "email": "email@format.com", "name": "my name", "password": "secretpasas" } }' localhost:5001/users
* curl -H "Content-Type: application/json" -X POST -d '{ "user": { "email": "email@format.com", "name": "my name", "password": "secretpasas" } }' localhost:5010/users
*
* @apiParam {Object} user User object (required)
* @apiParam {String} user.email Email
@@ -124,7 +124,7 @@ class UserRESTControllerLib {
ctx.body = { users }
} catch (err) {
wlogger.error('Error in users/controller.js/getUsers(): '.err)
wlogger.error('Error in users/controller.js/getUsers(): ', err)
ctx.throw(422, err.message)
}
}
@@ -136,7 +136,7 @@ class UserRESTControllerLib {
* @apiGroup REST Users
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X GET localhost:5000/users/56bd1da600a526986cf65c80
* curl -H "Content-Type: application/json" -X GET localhost:5010/users/56bd1da600a526986cf65c80
*
* @apiSuccess {Object} users User object
* @apiSuccess {ObjectId} users._id User id
@@ -281,4 +281,4 @@ class UserRESTControllerLib {
}
}
module.exports = UserRESTControllerLib
export default UserRESTControllerLib

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