mirror of
https://github.com/Permissionless-Software-Foundation/bch-dex.git
synced 2026-09-22 01:02:00 -07:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4d733f0995 | ||
|
|
f812580169 | ||
|
|
ec8dc91d36 | ||
|
|
03214fd7df | ||
|
|
9aae6da4a7 | ||
|
|
6e7ab40dea | ||
|
|
3b45e3c2c4 | ||
|
|
756002dd8c | ||
|
|
86da41b6c8 | ||
|
|
c2838b6117 | ||
|
|
af33de3f9a | ||
|
|
50d7cf137f | ||
|
|
dad9803d69 |
@@ -8,6 +8,10 @@ This repository contains the back end code. The user interface is contained in t
|
||||
|
||||
**Warning**: This repository is under active development. Things will be constantly changing and breaking.
|
||||
|
||||
## Media
|
||||
- [High-level Overview of bch-dex](https://youtu.be/LVX8CLi4sHw) (Video)
|
||||
- [Developer walk-through for installing and hacking on bch-dex](https://youtu.be/T5XI43-SWJo) (Video)
|
||||
|
||||
## 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)
|
||||
@@ -26,33 +30,37 @@ The above software is orchestrated using [Docker](https://www.docker.com/) and D
|
||||
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/).
|
||||
|
||||
Building the Docker containers and getting the app working involve these steps:
|
||||
- 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 by executing the [create-wallet.js script](./production/scripts/create-wallet.js) with `node create-wallet.js`
|
||||
- Move the `wallet.json` file to the [x86 Docker folder](./production/docker/bch-dex) or the [RPi Docker folder](./production/rpi-docker/bch-dex/) depending on your hardware target.
|
||||
- Change directory to the `docker` or `rpi-docker` folder depending on your hardware target.
|
||||
- Build the Docker containers with `docker-compose build --no-cache`.
|
||||
- Start the Docker containers with `docker-compose up -d`
|
||||
- Wait for the containers to run for about a minute, then bring them down with `docker-compose down`. That will create the needed folders in `production/data`.
|
||||
- Copy the `swarm.key` into the `production/data/go-ipfs/data/` directory. This will allow the IPFS node to connect to the PSF private network.
|
||||
- Bring the containers back up with `docker-compose up -d`.
|
||||
- Wait for the P2WDB to sync and populate bch-dex with trade data. You can monitor it with `docker logs --tail 20 -f p2wdb`.
|
||||
- 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.
|
||||
- To take the other side of the trade, click the `Take` button in the UI.
|
||||
- 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).
|
||||
|
||||
<ol>
|
||||
<li>Follow the direction in [this Gist](https://gist.github.com/christroutner/a39f656850dc022b60f25c9663dd1cdd) to install Node.js, Docker, and Docker Compose.</li>
|
||||
<li>Clone the repository with `git clone https://github.com/Permissionless-Software-Foundation/bch-dex` and enter it with `cd bch-dex`.</li>
|
||||
<li>Install dependencies by running `npm install`</li>
|
||||
<li>Create a wallet by executing the [create-wallet.js script](./production/scripts/create-wallet.js) with `node create-wallet.js`</li>
|
||||
<li>Move the `wallet.json` file to the `bch-dex` folder in either the [x86 Docker folder](./production/docker/bch-dex) or the [RPi Docker folder](./production/rpi-docker/bch-dex/) depending on your hardware target.</li>
|
||||
<li>Change directory to the `docker` or `rpi-docker` folder depending on your hardware target.</li>
|
||||
<li>Build the Docker containers with `docker-compose build --no-cache`.</li>
|
||||
<li>Start the Docker containers with `docker-compose up -d`</li>
|
||||
<li>Wait for the containers to run for about a minute, then bring them down with `docker-compose down`. That will create the needed folders in `production/data`.</li>
|
||||
<li>Copy the `swarm.key` into the `production/data/go-ipfs/data/` directory. This will allow the IPFS node to connect to the PSF private network.</li>
|
||||
<li>Bring the containers back up with `docker-compose up -d`.</li>
|
||||
<li>Wait for the P2WDB to sync and populate bch-dex with trade data. You can monitor it with `docker logs --tail 20 -f p2wdb`.</li>
|
||||
<li>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.</li>
|
||||
<li>To take the other side of the trade, click the `Take` button in the UI.</li>
|
||||
<li>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).</li>
|
||||
</ol>
|
||||
|
||||
### Applying Software Updates
|
||||
As this is an active project, software updates will happen frequently. To apply a software update, perform these steps.
|
||||
|
||||
- Enter the `docker` or `rpi-docker` folder, depending on your hardware target.
|
||||
- Bring down the Docker containers with `docker-compose down`.
|
||||
- Pull in the software updates with `git pull`
|
||||
- Update dependencies with `npm install`
|
||||
- Rebuild the Docker containers with `docker-compose build --no-cache`
|
||||
- Clean up disk space by deleting old Docker images with `./cleanup-images.sh`
|
||||
- Start the Docker containers with `docker-compose up -d`
|
||||
|
||||
<ol>
|
||||
<li>Enter the `docker` or `rpi-docker` folder, depending on your hardware target.</li>
|
||||
<li>Bring down the Docker containers with `docker-compose down`.</li>
|
||||
<li>Pull in the software updates with `git pull`</li>
|
||||
<li>Update dependencies with `npm install`</li>
|
||||
<li>Rebuild the Docker containers with `docker-compose build --no-cache`</li>
|
||||
<li>Clean up disk space by deleting old Docker images with `./cleanup-images.sh`</li>
|
||||
<li>Start the Docker containers with `docker-compose up -d`</li>
|
||||
</ol>
|
||||
|
||||
Sometimes it may be necessary to delete the databases before applying a software update. This can be done by stopping the Docker containers and deleting the `production/data` directory. When the Docker containers are restarted, they will recreate that directory. The P2WDB will re-sync and bch-dex will be populated with fresh trade data.
|
||||
|
||||
## License
|
||||
|
||||
Vendored
+1
-1
@@ -88,7 +88,7 @@ module.exports = {
|
||||
p2wdbAppId: process.env.APP_ID ? process.env.APP_ID : 'bch-dex-test557',
|
||||
webhookTarget: process.env.WEBHOOKTARGET
|
||||
? process.env.WEBHOOKTARGET
|
||||
: 'http://localhost:5700/offer',
|
||||
: 'http://localhost:5700/p2wdb',
|
||||
|
||||
// IPFS Ports
|
||||
ipfsTcpPort: process.env.IPFS_TCP_PORT ? process.env.IPFS_TCP_PORT : 4001,
|
||||
|
||||
Generated
+2550
-291
File diff suppressed because it is too large
Load Diff
+3
-3
@@ -27,9 +27,9 @@
|
||||
},
|
||||
"repository": "Permissionless-Software-Foundation/bch-dex",
|
||||
"dependencies": {
|
||||
"@psf/bch-js": "6.2.1",
|
||||
"@psf/bch-js": "6.2.5",
|
||||
"axios": "0.21.1",
|
||||
"bch-message-lib": "2.1.4",
|
||||
"bch-message-lib": "2.2.0",
|
||||
"bcryptjs": "2.4.3",
|
||||
"bitcoincashjs-lib": "3.3.3",
|
||||
"glob": "7.1.6",
|
||||
@@ -52,7 +52,7 @@
|
||||
"koa2-ratelimit": "0.9.1",
|
||||
"libp2p": "^0.36.2",
|
||||
"line-reader": "0.4.0",
|
||||
"minimal-slp-wallet": "4.4.5",
|
||||
"minimal-slp-wallet": "4.4.7",
|
||||
"mongoose": "5.13.13",
|
||||
"node-fetch": "npm:@achingbrain/node-fetch@2.6.7",
|
||||
"nodemailer": "6.4.17",
|
||||
|
||||
@@ -89,6 +89,8 @@ services:
|
||||
context: ./bch-dex-ui/
|
||||
dockerfile: Dockerfile
|
||||
container_name: dex-ui
|
||||
environment:
|
||||
SERVER: 'http://192.168.2.3'
|
||||
logging:
|
||||
driver: 'json-file'
|
||||
options:
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
|
||||
const axios = require('axios')
|
||||
|
||||
// const LOCALHOST = 'http://localhost:5700'
|
||||
const LOCALHOST = 'http://172.17.0.1:5700'
|
||||
const LOCALHOST = 'http://localhost:5700'
|
||||
// const LOCALHOST = 'http://172.17.0.1:5700'
|
||||
|
||||
async function start () {
|
||||
try {
|
||||
@@ -22,7 +22,7 @@ async function start () {
|
||||
buyOrSell: 'sell',
|
||||
rateInBaseUnit: 5000,
|
||||
minUnitsToExchange: 5000,
|
||||
numTokens: 1
|
||||
numTokens: 2
|
||||
}
|
||||
|
||||
const options = {
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// Public npm libraries
|
||||
const BCHJS = require('@psf/bch-js')
|
||||
const BchTokenSweep = require('bch-token-sweep/index')
|
||||
|
||||
// Local libraries
|
||||
const WalletAdapter = require('../../src/adapters/wallet')
|
||||
|
||||
// Constants
|
||||
const EMTPY_ADDR_CUTOFF = 10
|
||||
|
||||
async function sweepFunds () {
|
||||
try {
|
||||
// Open the wallet files.
|
||||
const wallet = new WalletAdapter()
|
||||
const walletInfo = await wallet.openWallet()
|
||||
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 = new BCHJS()
|
||||
const rootSeed = await bchjs.Mnemonic.toSeed(walletInfo.mnemonic)
|
||||
const masterHDNode = bchjs.HDNode.fromSeed(rootSeed)
|
||||
|
||||
let emptyAddrCnt = 0
|
||||
let hdIndex = 1
|
||||
|
||||
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}`)
|
||||
|
||||
try {
|
||||
// Sweep tokens from address
|
||||
const sweeper = new BchTokenSweep(
|
||||
wifToSweep,
|
||||
rootWif,
|
||||
bchjs,
|
||||
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}`)
|
||||
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()
|
||||
@@ -23,7 +23,8 @@ const Offer = new mongoose.Schema({
|
||||
sigMsg: { type: String },
|
||||
|
||||
// Utility data
|
||||
timestamp: { type: String },
|
||||
timestamp: { type: Number },
|
||||
globalTimestamp: { type: String },
|
||||
localTimestamp: { type: String },
|
||||
|
||||
// SWaP Protocol Properties
|
||||
|
||||
@@ -49,7 +49,8 @@ class Wlogger {
|
||||
}
|
||||
|
||||
notifyRotation (oldFilename, newFilename) {
|
||||
this.wlogger.info('Rotating log files')
|
||||
// this.wlogger.info('Rotating log files')
|
||||
console.log('Rotating log files')
|
||||
}
|
||||
|
||||
outputToConsole () {
|
||||
|
||||
@@ -70,6 +70,10 @@ class OfferEntity {
|
||||
throw new Error("Property 'ticker' must be a string.")
|
||||
}
|
||||
|
||||
// Convert the timestamp to a number.
|
||||
let timestamp = new Date(offerData.timestamp)
|
||||
timestamp = timestamp.getTime()
|
||||
|
||||
const validatedOfferData = {
|
||||
messageType,
|
||||
messageClass,
|
||||
@@ -80,7 +84,8 @@ class OfferEntity {
|
||||
numTokens,
|
||||
utxoTxid,
|
||||
utxoVout,
|
||||
timestamp: offerData.timestamp,
|
||||
timestamp,
|
||||
globaltimestamp: offerData.timestamp,
|
||||
localTimestamp: offerData.localTimeStamp,
|
||||
txid: offerData.txid,
|
||||
p2wdbHash: offerData.hash,
|
||||
|
||||
@@ -93,7 +93,7 @@ class OfferUseCases {
|
||||
|
||||
async listOffers () {
|
||||
try {
|
||||
return this.OfferModel.find({})
|
||||
return this.OfferModel.find({}).sort('-timestamp')
|
||||
} catch (error) {
|
||||
console.error('Error in use-cases/offer/listOffers()')
|
||||
throw error
|
||||
@@ -188,6 +188,10 @@ class OfferUseCases {
|
||||
}
|
||||
const hash = await this.adapters.p2wdb.write(p2wdbObj)
|
||||
|
||||
// Delete the Offer from the database, so that the user doesn't attempt
|
||||
// to take the offer more than once.
|
||||
offerInfo.remove()
|
||||
|
||||
// Return the P2WDB CID
|
||||
return hash
|
||||
|
||||
@@ -250,25 +254,27 @@ class OfferUseCases {
|
||||
}
|
||||
|
||||
async findOfferByHash (p2wdbHash) {
|
||||
try {
|
||||
if (typeof p2wdbHash !== 'string' || !p2wdbHash) {
|
||||
throw new Error('p2wdbHash must be a string')
|
||||
}
|
||||
|
||||
const offer = await this.OfferModel.findOne({ p2wdbHash })
|
||||
|
||||
if (!offer) {
|
||||
throw new Error('offer not found')
|
||||
}
|
||||
|
||||
const offerObject = offer.toObject()
|
||||
// return this.offerEntity.validateFromModel(offerObject)
|
||||
|
||||
return offerObject
|
||||
} catch (err) {
|
||||
console.error('Error in findOffer(): ', err)
|
||||
throw err
|
||||
// try {
|
||||
if (typeof p2wdbHash !== 'string' || !p2wdbHash) {
|
||||
throw new Error('p2wdbHash must be a string')
|
||||
}
|
||||
|
||||
const offer = await this.OfferModel.findOne({ p2wdbHash })
|
||||
|
||||
if (!offer) {
|
||||
throw new Error('offer not found')
|
||||
}
|
||||
|
||||
return offer
|
||||
|
||||
// const offerObject = offer.toObject()
|
||||
// return this.offerEntity.validateFromModel(offerObject)
|
||||
|
||||
// return offerObject
|
||||
// } catch (err) {
|
||||
// // console.error('Error in findOffer(): ', err)
|
||||
// throw err
|
||||
// }
|
||||
}
|
||||
|
||||
// This function is called by the P2WDB webhook REST API handler. When a
|
||||
@@ -367,6 +373,15 @@ class OfferUseCases {
|
||||
console.log(`Spent UTXO detected. Deleting this Offer: ${JSON.stringify(thisOffer, null, 2)}`)
|
||||
await thisOffer.remove()
|
||||
}
|
||||
|
||||
// If the Offer is older than 7 days, delete it.
|
||||
const nowMs = now.getTime()
|
||||
const sevenDays = 1000 * 60 * 60 * 24 * 7
|
||||
const sevenDaysAgo = nowMs - sevenDays
|
||||
if (thisOffer.timestamp < sevenDaysAgo) {
|
||||
console.log('Offer older than 7 days. Deleting.')
|
||||
await thisOffer.remove()
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Error in removeStaleOffers()')
|
||||
|
||||
@@ -101,6 +101,9 @@ class OrderLib {
|
||||
// console.log('this.adapters.wallet: ', this.adapters.wallet.bchWallet)
|
||||
// console.log(`walletInfo: ${JSON.stringify(this.adapters.wallet.bchWallet.walletInfo, null, 2)}`)
|
||||
|
||||
// Update the wallet balance
|
||||
await this.adapters.wallet.bchWallet.getUtxos()
|
||||
|
||||
// Ensure the app wallet has enough funds to write to the P2WDB.
|
||||
const wif = this.adapters.wallet.bchWallet.walletInfo.privateKey
|
||||
const canWriteToP2WDB = await this.adapters.p2wdb.checkForSufficientFunds(wif)
|
||||
|
||||
Reference in New Issue
Block a user