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 | |
|---|---|---|---|
|
|
02eab8686c | ||
|
|
1c1169dd93 | ||
|
|
0896adffbb | ||
|
|
56e0f7e8df | ||
|
|
34841f53db | ||
|
|
c27209cceb |
Generated
+11
-8
@@ -38,7 +38,7 @@
|
||||
"mongoose": "5.13.13",
|
||||
"node-fetch": "npm:@achingbrain/node-fetch@2.6.7",
|
||||
"nodemailer": "6.7.5",
|
||||
"p2wdb": "2.2.1",
|
||||
"p2wdb": "2.2.3",
|
||||
"passport-local": "1.0.0",
|
||||
"public-ip": "^4.0.4",
|
||||
"winston": "3.3.3",
|
||||
@@ -14738,9 +14738,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/p2wdb": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/p2wdb/-/p2wdb-2.2.1.tgz",
|
||||
"integrity": "sha512-ft/mGRRLXqWfcodiL7d/403QfImOflpw8BJBpULM0F6rGt/8sTY6i5W3NCyUQp3Mx39xIEw/wTgdb32Hn5Uomg==",
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/p2wdb/-/p2wdb-2.2.3.tgz",
|
||||
"integrity": "sha512-eZQaE3iVudOJV6Iji/fBO20tYhs23EmtcxLZbXK7ZjY+c0NysBzhS0mGCkEUWrU/qBthjIEZ2O5detuAHsmHCw==",
|
||||
"dependencies": {
|
||||
"apidoc": "0.52.0",
|
||||
"axios": "0.24.0"
|
||||
@@ -14788,7 +14788,8 @@
|
||||
},
|
||||
"node_modules/p2wdb/node_modules/axios": {
|
||||
"version": "0.24.0",
|
||||
"license": "MIT",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz",
|
||||
"integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.14.4"
|
||||
}
|
||||
@@ -29378,9 +29379,9 @@
|
||||
"version": "1.0.1"
|
||||
},
|
||||
"p2wdb": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/p2wdb/-/p2wdb-2.2.1.tgz",
|
||||
"integrity": "sha512-ft/mGRRLXqWfcodiL7d/403QfImOflpw8BJBpULM0F6rGt/8sTY6i5W3NCyUQp3Mx39xIEw/wTgdb32Hn5Uomg==",
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/p2wdb/-/p2wdb-2.2.3.tgz",
|
||||
"integrity": "sha512-eZQaE3iVudOJV6Iji/fBO20tYhs23EmtcxLZbXK7ZjY+c0NysBzhS0mGCkEUWrU/qBthjIEZ2O5detuAHsmHCw==",
|
||||
"requires": {
|
||||
"apidoc": "0.52.0",
|
||||
"axios": "0.24.0"
|
||||
@@ -29415,6 +29416,8 @@
|
||||
},
|
||||
"axios": {
|
||||
"version": "0.24.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz",
|
||||
"integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.14.4"
|
||||
}
|
||||
|
||||
+1
-1
@@ -56,7 +56,7 @@
|
||||
"mongoose": "5.13.13",
|
||||
"node-fetch": "npm:@achingbrain/node-fetch@2.6.7",
|
||||
"nodemailer": "6.7.5",
|
||||
"p2wdb": "2.2.1",
|
||||
"p2wdb": "2.2.3",
|
||||
"passport-local": "1.0.0",
|
||||
"public-ip": "^4.0.4",
|
||||
"winston": "3.3.3",
|
||||
|
||||
@@ -67,10 +67,10 @@ services:
|
||||
restart: always
|
||||
|
||||
bch-dex:
|
||||
#build:
|
||||
# context: ./bch-dex/
|
||||
# dockerfile: Dockerfile
|
||||
image: christroutner/bch-dex-rpi:v1.9.6
|
||||
build:
|
||||
context: ./bch-dex/
|
||||
dockerfile: Dockerfile
|
||||
#image: christroutner/bch-dex-rpi:v1.9.8
|
||||
container_name: bch-dex
|
||||
environment:
|
||||
CONSUMER_URL: 'https://free-bch.fullstack.cash'
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -71,6 +71,10 @@ class Adapters {
|
||||
|
||||
// Wait until a webhook is established with the P2WDB
|
||||
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
|
||||
}
|
||||
|
||||
console.log('Async Adapters have been started.')
|
||||
|
||||
@@ -27,6 +27,7 @@ const Offer = new mongoose.Schema({
|
||||
timestamp: { type: Number },
|
||||
globalTimestamp: { type: String },
|
||||
localTimestamp: { type: String },
|
||||
displayCategory: { type: String },
|
||||
|
||||
// SWaP Protocol Properties
|
||||
lokadId: { type: String },
|
||||
|
||||
@@ -80,8 +80,11 @@ class OfferUseCases {
|
||||
const offerEntity = this.offerEntity.validate(offerObj)
|
||||
console.log('offerEntity: ', offerEntity)
|
||||
|
||||
// const displayCategory = await this.categorizeToken(offerEntity)
|
||||
// console.log('displayCategory: ', displayCategory)
|
||||
// Generate a 'display category' for the token. This will allow the
|
||||
// front end UI to figure out how to display the token.
|
||||
const displayCategory = await this.categorizeToken(offerEntity)
|
||||
console.log('displayCategory: ', displayCategory)
|
||||
offerEntity.displayCategory = displayCategory
|
||||
|
||||
// Add offer to the local database.
|
||||
const offerModel = new this.OfferModel(offerEntity)
|
||||
@@ -105,14 +108,35 @@ class OfferUseCases {
|
||||
// with a quantity of 1, decimals of 0, and no minting baton. Categorizing this
|
||||
// type of token is the main reason why this function exists.
|
||||
async categorizeToken (offerData) {
|
||||
console.log(`categorizeToken(): ${JSON.stringify(offerData, null, 2)}`)
|
||||
try {
|
||||
console.log(`categorizeToken(): ${JSON.stringify(offerData, null, 2)}`)
|
||||
|
||||
const tokenId = offerData.tokenId
|
||||
const tokenId = offerData.tokenId
|
||||
|
||||
const tokenData = await this.adapters.wallet.bchWallet.getTokenData(tokenId)
|
||||
console.log(`tokenData: ${JSON.stringify(tokenData, null, 2)}`)
|
||||
const tokenData = await this.adapters.wallet.bchWallet.getTokenData(tokenId)
|
||||
console.log(`tokenData: ${JSON.stringify(tokenData, null, 2)}`)
|
||||
|
||||
return 'placeholder'
|
||||
if (tokenData.genesisData.type === 65) {
|
||||
return 'nft'
|
||||
}
|
||||
|
||||
// Create a set of checks to detect a simple NFT
|
||||
const isType1 = tokenData.genesisData.type === 1
|
||||
const hasNoMintingBaton = !tokenData.genesisData.mintBatonIsActive
|
||||
const hasNoDecimals = !tokenData.genesisData.decimals
|
||||
const hasQtyOfOne = parseInt(tokenData.genesisData.tokensInCirculationStr) === 1
|
||||
|
||||
if (isType1 && hasNoMintingBaton && hasNoDecimals && hasQtyOfOne) {
|
||||
return 'simple-nft'
|
||||
}
|
||||
|
||||
if (isType1) return 'fungible'
|
||||
|
||||
throw new Error(`Unknown token type: ${tokenData.genesisData.type}`)
|
||||
} catch (err) {
|
||||
console.error('Error in use-cases/offer/index.js categorizeToken(): ', err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
async listOffers () {
|
||||
@@ -146,15 +170,21 @@ class OfferUseCases {
|
||||
}
|
||||
|
||||
// Verify that UTXO for sale is unspent. Abort if it's been spent.
|
||||
const txid = offerInfo.utxoTxid
|
||||
const vout = offerInfo.utxoVout
|
||||
const utxoStatus = await this.adapters.bchjs.Blockchain.getTxOut(
|
||||
txid,
|
||||
vout
|
||||
)
|
||||
// const txid = offerInfo.utxoTxid
|
||||
// const vout = offerInfo.utxoVout
|
||||
|
||||
const utxo = {
|
||||
tx_hash: offerInfo.utxoTxid,
|
||||
tx_pos: offerInfo.utxoVout
|
||||
}
|
||||
const utxoStatus = await this.adapters.wallet.bchWallet.utxoIsValid(utxo)
|
||||
// const utxoStatus = await this.adapters.bchjs.Blockchain.getTxOut(
|
||||
// txid,
|
||||
// vout
|
||||
// )
|
||||
console.log('utxoStatus: ', utxoStatus)
|
||||
if (utxoStatus === null) {
|
||||
console.log(`utxo txid: ${txid}, vout: ${vout}`)
|
||||
if (!utxoStatus) {
|
||||
console.log(`utxo txid: ${offerInfo.utxoTxid}, vout: ${offerInfo.utxoVout}`)
|
||||
|
||||
// TODO: Mark this Offer as 'dead'
|
||||
|
||||
@@ -236,6 +266,9 @@ class OfferUseCases {
|
||||
await this.adapters.wallet.bchWallet.walletInfoPromise
|
||||
// console.log(`utxos: ${JSON.stringify(this.adapters.wallet.bchWallet.utxos.utxoStore, null, 2)}`)
|
||||
|
||||
// Refresh the wallet UTXOs
|
||||
await this.adapters.wallet.bchWallet.initialize()
|
||||
|
||||
// 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)
|
||||
|
||||
@@ -34,6 +34,7 @@ class MockBchWallet {
|
||||
tokenTicker: 'TROUT'
|
||||
}]
|
||||
}
|
||||
this.getTokenData = async () => {}
|
||||
|
||||
// Environment variable is used by wallet-balance.unit.js to force an error.
|
||||
if (process.env.NO_UTXO) {
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
Mocking data for Offer Use Case unit tests.
|
||||
*/
|
||||
|
||||
const nftOffer01 = {
|
||||
"messageType": 1,
|
||||
"messageClass": 1,
|
||||
"tokenId": "eb93f05553ff088bffb0ec687519e83c59e5108c160f7c25a4b6c45109d7e40b",
|
||||
"buyOrSell": "sell",
|
||||
"rateInBaseUnit": 7672536,
|
||||
"minUnitsToExchange": 7672536,
|
||||
"numTokens": 1,
|
||||
"utxoTxid": "c736d73e274df20e9b069b4990d1a264fb80aa98d67cc6c7a39e42bff48e7c04",
|
||||
"utxoVout": 1,
|
||||
"timestamp": 1662930309998,
|
||||
"globaltimestamp": "2022-09-11T21:05:09.998Z",
|
||||
"localTimestamp": "9/11/2022, 9:05:09 PM",
|
||||
"txid": "4266862b8358664996038d8c29d49dc0f3d3058fd1ef3d567b084e6b16ceb5b2",
|
||||
"p2wdbHash": "zdpuArq7rCuVCGPyTnWpLjy9AYsh8yrbwjGdKwg2GDDALkM8t",
|
||||
"offerStatus": "posted",
|
||||
"makerAddr": "bitcoincash:qrqlz63cwmu0hcmsrfnd8jemn3atkpaqds6tf4ksrr",
|
||||
"ticker": "TV001",
|
||||
"tokenType": 65
|
||||
}
|
||||
|
||||
const nftTokenData01 = {
|
||||
"genesisData": {
|
||||
"type": 65,
|
||||
"ticker": "TV001",
|
||||
"name": "Introduction to NFTs on BCH",
|
||||
"tokenId": "eb93f05553ff088bffb0ec687519e83c59e5108c160f7c25a4b6c45109d7e40b",
|
||||
"documentUri": "ipfs://bafybeibmgilu4lk3uivwyzhtm7jorl5zbsluewqmcsxs6otzrphh33okk4",
|
||||
"documentHash": "c1731268f4873f1928438abdaf6ffc546d86a1817dc6f3c6bc73fbdfb4664f10",
|
||||
"decimals": 0,
|
||||
"mintBatonIsActive": false,
|
||||
"tokensInCirculationBN": "1",
|
||||
"tokensInCirculationStr": "1",
|
||||
"blockCreated": 740395,
|
||||
"totalBurned": "0",
|
||||
"totalMinted": "1",
|
||||
"parentGroupId": "030563ddd65772d8e9b79b825529ed53c7d27037507b57c528788612b4911107"
|
||||
},
|
||||
"immutableData": "ipfs://bafybeibmgilu4lk3uivwyzhtm7jorl5zbsluewqmcsxs6otzrphh33okk4",
|
||||
"mutableData": "ipfs://bafybeifzhunfpodsztsj5x4ypopngkxuapbxwaxaxkahaybdktk6joqtlq"
|
||||
}
|
||||
|
||||
const simpleNftOffer01 = {
|
||||
"messageType": 1,
|
||||
"messageClass": 1,
|
||||
"tokenId": "a80c89d2f9f7ad7584743587c4950a0f28514ba8054e8cec4e871747cf9c162c",
|
||||
"buyOrSell": "sell",
|
||||
"rateInBaseUnit": 76725,
|
||||
"minUnitsToExchange": 76725,
|
||||
"numTokens": 1,
|
||||
"utxoTxid": "dd51a8bf96c8ab16a2935b09e51650e1769a1fa75cce9f0455abdbf72071d3c2",
|
||||
"utxoVout": 1,
|
||||
"timestamp": 1662930102814,
|
||||
"globaltimestamp": "2022-09-11T21:01:42.814Z",
|
||||
"localTimestamp": "9/11/2022, 9:01:42 PM",
|
||||
"txid": "4013177602ee75bbc5c4a67ea8d6d80e4f3d12b9c46ae2a6643911f48257b578",
|
||||
"p2wdbHash": "zdpuAzyLPFBwFWbNi8XQuxgAx9aBNGWZEGqib7KE6Hp3AEEhq",
|
||||
"offerStatus": "posted",
|
||||
"makerAddr": "bitcoincash:qrqlz63cwmu0hcmsrfnd8jemn3atkpaqds6tf4ksrr",
|
||||
"ticker": "BAA",
|
||||
"tokenType": 1
|
||||
}
|
||||
|
||||
const simpleNftTokenData01 = {
|
||||
"genesisData": {
|
||||
"type": 1,
|
||||
"ticker": "BAA",
|
||||
"name": "Bitcoin AI Art 001",
|
||||
"tokenId": "a80c89d2f9f7ad7584743587c4950a0f28514ba8054e8cec4e871747cf9c162c",
|
||||
"documentUri": "ipfs://bafybeifevvtnap3m3fsjbwnvpknvzhqihl2ouuypio33f2vtwqejipgpkq",
|
||||
"documentHash": "d6213e5629d01fd2cd714cde709e11b888c0ba441e05bb1cc649f8b784df5a6c",
|
||||
"decimals": 0,
|
||||
"mintBatonIsActive": false,
|
||||
"tokensInCirculationBN": "1",
|
||||
"tokensInCirculationStr": "1",
|
||||
"blockCreated": 757238,
|
||||
"totalBurned": "0",
|
||||
"totalMinted": "1"
|
||||
},
|
||||
"immutableData": "ipfs://bafybeifevvtnap3m3fsjbwnvpknvzhqihl2ouuypio33f2vtwqejipgpkq",
|
||||
"mutableData": "ipfs://bafybeibqnsmmh6bkf2wwextetki4tly65z4r4qkrrpl5xwgvzdzjley6wm"
|
||||
}
|
||||
|
||||
const fungibleOffer01 = {
|
||||
"messageType": 1,
|
||||
"messageClass": 1,
|
||||
"tokenId": "a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2",
|
||||
"buyOrSell": "sell",
|
||||
"rateInBaseUnit": 7672,
|
||||
"minUnitsToExchange": 7672,
|
||||
"numTokens": 1,
|
||||
"utxoTxid": "822dc4c765cc68314479c7707bba28028eacab6013bb683b1680dbcc9c95b286",
|
||||
"utxoVout": 1,
|
||||
"timestamp": 1662930501091,
|
||||
"globaltimestamp": "2022-09-11T21:08:21.091Z",
|
||||
"localTimestamp": "9/11/2022, 9:08:21 PM",
|
||||
"txid": "7ee0ec32e116b068ff43c5516fa500058d14f53037ba5cc729e78eb51d1f1ffd",
|
||||
"p2wdbHash": "zdpuB2gHDvmByfvPFLJgEAaRyUi1cwnD45Qt66y4f5tnMXFo7",
|
||||
"offerStatus": "posted",
|
||||
"makerAddr": "bitcoincash:qrqlz63cwmu0hcmsrfnd8jemn3atkpaqds6tf4ksrr",
|
||||
"ticker": "TROUT",
|
||||
"tokenType": 1
|
||||
}
|
||||
|
||||
const fungibleTokenData01 = {
|
||||
"genesisData": {
|
||||
"type": 1,
|
||||
"ticker": "TROUT",
|
||||
"name": "Trout's test token",
|
||||
"tokenId": "a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2",
|
||||
"documentUri": "troutsblog.com",
|
||||
"documentHash": "",
|
||||
"decimals": 2,
|
||||
"mintBatonIsActive": true,
|
||||
"tokensInCirculationBN": "100097954686",
|
||||
"tokensInCirculationStr": "100097954686",
|
||||
"blockCreated": 622414,
|
||||
"totalBurned": "2045314",
|
||||
"totalMinted": "100100000000"
|
||||
},
|
||||
"immutableData": "troutsblog.com",
|
||||
"mutableData": ""
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
nftOffer01,
|
||||
nftTokenData01,
|
||||
simpleNftOffer01,
|
||||
simpleNftTokenData01,
|
||||
fungibleOffer01,
|
||||
fungibleTokenData01
|
||||
}
|
||||
@@ -13,6 +13,7 @@ const sinon = require('sinon')
|
||||
const OfferLib = require('../../../src/use-cases/offer')
|
||||
const OrderUseCase = require('../../../src/use-cases/order')
|
||||
const adapters = require('../mocks/adapters')
|
||||
const mockData = require('../mocks/use-cases/offer-mock-data.js')
|
||||
|
||||
describe('#offer-use-case', () => {
|
||||
let uut
|
||||
@@ -118,6 +119,7 @@ describe('#offer-use-case', () => {
|
||||
},
|
||||
coinbase: false
|
||||
})
|
||||
sandbox.stub(uut, 'categorizeToken').resolves('fungible')
|
||||
|
||||
const result = await uut.createOffer(offerObj)
|
||||
// console.log('result: ', result)
|
||||
@@ -125,4 +127,39 @@ describe('#offer-use-case', () => {
|
||||
assert.equal(result, true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#categorizeToken', () => {
|
||||
it('should categorize an NFT', async () => {
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut.adapters.wallet.bchWallet, 'getTokenData').resolves(mockData.nftTokenData01)
|
||||
|
||||
const offerData = mockData.nftOffer01
|
||||
|
||||
const result = await uut.categorizeToken(offerData)
|
||||
|
||||
assert.equal(result, 'nft')
|
||||
})
|
||||
|
||||
it('should categorize a simple NFT', async () => {
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut.adapters.wallet.bchWallet, 'getTokenData').resolves(mockData.simpleNftTokenData01)
|
||||
|
||||
const offerData = mockData.simpleNftOffer01
|
||||
|
||||
const result = await uut.categorizeToken(offerData)
|
||||
|
||||
assert.equal(result, 'simple-nft')
|
||||
})
|
||||
|
||||
it('should categorize a fungible token', async () => {
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut.adapters.wallet.bchWallet, 'getTokenData').resolves(mockData.fungibleTokenData01)
|
||||
|
||||
const offerData = mockData.fungibleOffer01
|
||||
|
||||
const result = await uut.categorizeToken(offerData)
|
||||
|
||||
assert.equal(result, 'fungible')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user