mirror of
https://github.com/Permissionless-Software-Foundation/bch-dex.git
synced 2026-09-22 09:11:59 -07:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac83827fca | ||
|
|
0811024030 | ||
|
|
737d35463d | ||
|
|
2ed1eaba9c | ||
|
|
6dddfbdcb6 | ||
|
|
fc2d7b4b9b | ||
|
|
c877898ae7 | ||
|
|
88e27f47f5 | ||
|
|
9681def3e0 | ||
|
|
0057007b4c | ||
|
|
8aad93e572 | ||
|
|
42f228af0e | ||
|
|
4ac7f59378 | ||
|
|
725c1c39a5 | ||
|
|
7290c8db30 | ||
|
|
36e1ec1f8e | ||
|
|
baa574a93e | ||
|
|
8333563d98 | ||
|
|
99fd116b6d | ||
|
|
ccae89ad01 | ||
|
|
0ecae58be2 | ||
|
|
5f442835e5 | ||
|
|
aa8fd89227 | ||
|
|
3da7432273 | ||
|
|
61c1dd5878 | ||
|
|
c095e7af39 | ||
|
|
fb9612bb65 | ||
|
|
e4a37b1c10 | ||
|
|
ba4f847e57 | ||
|
|
81e623e35f | ||
|
|
db1da9172c |
@@ -53,7 +53,7 @@ RUN git clone https://github.com/Permissionless-Software-Foundation/bch-dex-ui-v
|
|||||||
WORKDIR /home/safeuser/bch-dex-ui-v3
|
WORKDIR /home/safeuser/bch-dex-ui-v3
|
||||||
|
|
||||||
# For development: switch to unstable branch
|
# For development: switch to unstable branch
|
||||||
RUN git checkout ct-unstable
|
RUN git checkout psfoundation
|
||||||
|
|
||||||
# Install dependencies
|
# Install dependencies
|
||||||
#RUN mkdir .ipfsdata
|
#RUN mkdir .ipfsdata
|
||||||
|
|||||||
@@ -31,4 +31,7 @@ export APP_ID=bch-dex-001
|
|||||||
|
|
||||||
#export P2WDB_URL=http://172.17.0.1:5667
|
#export P2WDB_URL=http://172.17.0.1:5667
|
||||||
|
|
||||||
|
export DISABLE_NEW_ACCOUNTS=true
|
||||||
|
export ADMIN_PASSWORD=decatur
|
||||||
|
|
||||||
npm start
|
npm start
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"privateKey": "L4VyBDiWYYeeZhkM3xE3nsZigXJYmvRM29YBxoC7da4FzvubjxFo",
|
||||||
|
"publicKey": "028d6c77d865e6140db4b879a9bdf69ee4846593c0b6c48a82c448d5792806aab1",
|
||||||
|
"mnemonic": "split title trigger soda execute frost brush labor vague protect bicycle fiscal",
|
||||||
|
"cashAddress": "bitcoincash:qprrdk7en7m774gsafkycxcymc9ry209jus5v8wx5z",
|
||||||
|
"address": "bitcoincash:qprrdk7en7m774gsafkycxcymc9ry209jus5v8wx5z",
|
||||||
|
"legacyAddress": "17QG25rNUfnfj2NtdaFiyiqKSJatvEnMYd",
|
||||||
|
"hdPath": "m/44'/245'/0'/0/0",
|
||||||
|
"slpAddress": "simpleledger:qprrdk7en7m774gsafkycxcymc9ry209juu08umx2u",
|
||||||
|
"nextAddress": 1
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ import Usage from './models/usage.js'
|
|||||||
import SmAccount from './models/smAccount.js'
|
import SmAccount from './models/smAccount.js'
|
||||||
import DeletedChat from './models/deletedChat.js'
|
import DeletedChat from './models/deletedChat.js'
|
||||||
import DeletedPost from './models/deletedPost.js'
|
import DeletedPost from './models/deletedPost.js'
|
||||||
|
import CounterOffer from './models/counter-offer.js'
|
||||||
|
|
||||||
class LocalDB {
|
class LocalDB {
|
||||||
constructor () {
|
constructor () {
|
||||||
@@ -23,6 +24,7 @@ class LocalDB {
|
|||||||
this.SmAccount = SmAccount
|
this.SmAccount = SmAccount
|
||||||
this.DeletedChat = DeletedChat
|
this.DeletedChat = DeletedChat
|
||||||
this.DeletedPost = DeletedPost
|
this.DeletedPost = DeletedPost
|
||||||
|
this.CounterOffer = CounterOffer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import mongoose from 'mongoose'
|
||||||
|
|
||||||
|
const CounterOffer = new mongoose.Schema({
|
||||||
|
nostrEventId: { type: String, required: true }, // Nostr Event Id.
|
||||||
|
takerAddr: { type: String, default: null },
|
||||||
|
takerNpub: { type: String, default: null },
|
||||||
|
makerNpub: { type: String, default: null },
|
||||||
|
counterOfferAddr: { type: String, default: null },
|
||||||
|
counterOfferUtxo: { type: String, default: null },
|
||||||
|
takerOfferUtxo: { type: String, default: null },
|
||||||
|
tokenId: { type: String, default: null }
|
||||||
|
})
|
||||||
|
|
||||||
|
export default mongoose.model('counterOffer', CounterOffer)
|
||||||
@@ -18,7 +18,7 @@ const Offer = new mongoose.Schema({
|
|||||||
p2wdbHash: { type: String },
|
p2wdbHash: { type: String },
|
||||||
offerStatus: { type: String },
|
offerStatus: { type: String },
|
||||||
makerAddr: { type: String },
|
makerAddr: { type: String },
|
||||||
makerNpub: { type: String },
|
makerNpub: { type: String, default: null },
|
||||||
|
|
||||||
// Authentication data
|
// Authentication data
|
||||||
signature: { type: String },
|
signature: { type: String },
|
||||||
@@ -46,6 +46,7 @@ const Offer = new mongoose.Schema({
|
|||||||
immutableDataCid: { type: String, default: null },
|
immutableDataCid: { type: String, default: null },
|
||||||
mutableDataCid: { type: String, default: null },
|
mutableDataCid: { type: String, default: null },
|
||||||
tokenIconUrl: { type: String, default: null },
|
tokenIconUrl: { type: String, default: null },
|
||||||
|
tokenData: { type: Object },
|
||||||
tokenCategories: { type: Array, default: [] },
|
tokenCategories: { type: Array, default: [] },
|
||||||
tokenTags: { type: Array, default: [] },
|
tokenTags: { type: Array, default: [] },
|
||||||
userDataStr: { type: String }, // Token user data
|
userDataStr: { type: String }, // Token user data
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ class OfferRESTControllerLib {
|
|||||||
this.takeOffer = this.takeOffer.bind(this)
|
this.takeOffer = this.takeOffer.bind(this)
|
||||||
this.listOffersByAddress = this.listOffersByAddress.bind(this)
|
this.listOffersByAddress = this.listOffersByAddress.bind(this)
|
||||||
this.syncOfferMutableData = this.syncOfferMutableData.bind(this)
|
this.syncOfferMutableData = this.syncOfferMutableData.bind(this)
|
||||||
|
this.listCounterOffersByAddress = this.listCounterOffersByAddress.bind(this)
|
||||||
this.handleError = this.handleError.bind(this)
|
this.handleError = this.handleError.bind(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,6 +409,52 @@ class OfferRESTControllerLib {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @api {get} /offer/list/counter-offer/:addr List all counter offers being made by a given address
|
||||||
|
* @apiPermission public
|
||||||
|
* @apiName listCounterOffersByAddress
|
||||||
|
* @apiGroup REST Offer
|
||||||
|
*
|
||||||
|
* @apiExample Example usage:
|
||||||
|
* curl -H "Content-Type: application/json" -X GET localhost:5000/offer/list/counter-offer/bitcoincash:qq54a3xyyptty63ztlcavzzh64gy4d247qs4ueaupe
|
||||||
|
*
|
||||||
|
*
|
||||||
|
|
||||||
|
* @apiSuccess {String} offers.nostrEventId Nostr event id
|
||||||
|
* @apiSuccess {String} offers.takerNpub Nostr Npub.
|
||||||
|
* @apiSuccess {String} offers.takerAddr BCH Address.
|
||||||
|
* @apiSuccess {String} offers.counterOfferAddr BCH Address
|
||||||
|
* @apiSuccess {String} offers.counterOfferUtxo Utxo txid.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @apiSuccessExample {json} Success-Response:
|
||||||
|
* HTTP/1.1 200 OK
|
||||||
|
* {
|
||||||
|
* "counterOffers": [{
|
||||||
|
* "_id": "56bd1da600a526986cf65c80",
|
||||||
|
* "nostrEventId": "1234567890",
|
||||||
|
* "takerAddr": "bitcoincash:qq54a3xyyptty63ztlcavzzh64gy4d247qs4ueaupe",
|
||||||
|
* "takerNpub": "npub1nhc47z2tf42a4ps7plzcyax2j76gdausve763tqw3xuw7jjd7ceqppquly",
|
||||||
|
* "counterOfferAddr": "bitcoincash:qzltx40ldxr53edchprppj5lpg4q7vl20usx25ga44",
|
||||||
|
* "counterOfferUtxo": "71dab5b81cf06f3495aeebcc70fb351109e5e88bc85da67d0d144c0e5ca0bd6a",
|
||||||
|
* }]
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @apiUse TokenError
|
||||||
|
*/
|
||||||
|
async listCounterOffersByAddress (ctx) {
|
||||||
|
try {
|
||||||
|
const addr = ctx.params.addr
|
||||||
|
|
||||||
|
const counterOffers = await this.useCases.offer.listCounterOffersByAddress(addr)
|
||||||
|
|
||||||
|
ctx.body = { counterOffers }
|
||||||
|
} catch (err) {
|
||||||
|
console.log('Error in listCounterOffersByAddress REST API handler: ', err)
|
||||||
|
this.handleError(ctx, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// DRY error handler
|
// DRY error handler
|
||||||
handleError (ctx, err) {
|
handleError (ctx, err) {
|
||||||
console.log('err', err.message)
|
console.log('err', err.message)
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ class OfferRouter {
|
|||||||
this.router.get('/list/nft/:page', this.offerRESTController.listNftOffers)
|
this.router.get('/list/nft/:page', this.offerRESTController.listNftOffers)
|
||||||
this.router.get('/list/fungible/:page', this.offerRESTController.listFungibleOffers)
|
this.router.get('/list/fungible/:page', this.offerRESTController.listFungibleOffers)
|
||||||
this.router.get('/list/addr/:addr', this.offerRESTController.listOffersByAddress)
|
this.router.get('/list/addr/:addr', this.offerRESTController.listOffersByAddress)
|
||||||
|
this.router.get('/list/counter-offer/:addr', this.offerRESTController.listCounterOffersByAddress)
|
||||||
|
|
||||||
// Attach the Controller routes to the Koa app.
|
// Attach the Controller routes to the Koa app.
|
||||||
app.use(this.router.routes())
|
app.use(this.router.routes())
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
Counter Offer Entity
|
||||||
|
*/
|
||||||
|
|
||||||
|
class CounterOfferEntity {
|
||||||
|
validate (offerData = {}) {
|
||||||
|
console.log('counter offer data input validation ', offerData)
|
||||||
|
// Throw an error if input object does not have a data property
|
||||||
|
if (!offerData.data) {
|
||||||
|
throw new Error(
|
||||||
|
'Input to counterOffer.validate() must be an object with a data property.'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
nostrEventId,
|
||||||
|
takerAddr,
|
||||||
|
takerNpub,
|
||||||
|
makerNpub,
|
||||||
|
counterOfferAddr,
|
||||||
|
counterOfferUtxo,
|
||||||
|
takerOfferUtxo,
|
||||||
|
tokenId
|
||||||
|
} = offerData.data
|
||||||
|
|
||||||
|
// Input Validation
|
||||||
|
if (!nostrEventId || typeof nostrEventId !== 'string') {
|
||||||
|
throw new Error("Property 'nostrEventId' must be a string.")
|
||||||
|
}
|
||||||
|
// Next validations are optional, to allow old counter offers without the data.
|
||||||
|
if (takerAddr && typeof takerAddr !== 'string') {
|
||||||
|
throw new Error("Property 'takerAddr' must be a string.")
|
||||||
|
}
|
||||||
|
if (takerNpub && typeof takerNpub !== 'string') {
|
||||||
|
throw new Error("Property 'takerNpub' must be a string.")
|
||||||
|
}
|
||||||
|
if (counterOfferAddr && typeof counterOfferAddr !== 'string') {
|
||||||
|
throw new Error("Property 'counterOfferAddr' must be a string.")
|
||||||
|
}
|
||||||
|
if (counterOfferUtxo && typeof counterOfferUtxo !== 'string') {
|
||||||
|
throw new Error("Property 'counterOfferUtxo' must be a string.")
|
||||||
|
}
|
||||||
|
if (takerOfferUtxo && typeof takerOfferUtxo !== 'string') {
|
||||||
|
throw new Error("Property 'takerOfferUtxo' must be a string.")
|
||||||
|
}
|
||||||
|
if (tokenId && typeof tokenId !== 'string') {
|
||||||
|
throw new Error("Property 'tokenId' must be a string.")
|
||||||
|
}
|
||||||
|
if (makerNpub && typeof makerNpub !== 'string') {
|
||||||
|
throw new Error("Property 'makerNpub' must be a string.")
|
||||||
|
}
|
||||||
|
|
||||||
|
const validatedCounterOfferData = {
|
||||||
|
nostrEventId,
|
||||||
|
takerAddr,
|
||||||
|
takerNpub,
|
||||||
|
counterOfferAddr,
|
||||||
|
counterOfferUtxo,
|
||||||
|
takerOfferUtxo,
|
||||||
|
tokenId,
|
||||||
|
makerNpub
|
||||||
|
}
|
||||||
|
|
||||||
|
return validatedCounterOfferData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CounterOfferEntity
|
||||||
@@ -31,6 +31,7 @@ class OfferEntity {
|
|||||||
utxoVout,
|
utxoVout,
|
||||||
offerStatus,
|
offerStatus,
|
||||||
makerAddr,
|
makerAddr,
|
||||||
|
makerNpub,
|
||||||
ticker,
|
ticker,
|
||||||
tokenType,
|
tokenType,
|
||||||
nostrEventId,
|
nostrEventId,
|
||||||
@@ -89,6 +90,10 @@ class OfferEntity {
|
|||||||
if (!operatorPercentage || typeof operatorPercentage !== 'number') {
|
if (!operatorPercentage || typeof operatorPercentage !== 'number') {
|
||||||
throw new Error("Property 'operatorPercentage' must be a number.")
|
throw new Error("Property 'operatorPercentage' must be a number.")
|
||||||
}
|
}
|
||||||
|
// Validate npub type if it exist
|
||||||
|
if (makerNpub && typeof makerNpub !== 'string') {
|
||||||
|
throw new Error("Property 'makerNpub' must be a string.")
|
||||||
|
}
|
||||||
|
|
||||||
// Convert the timestamp to a number.
|
// Convert the timestamp to a number.
|
||||||
let timestamp = new Date(offerData.timestamp)
|
let timestamp = new Date(offerData.timestamp)
|
||||||
@@ -113,7 +118,8 @@ class OfferEntity {
|
|||||||
makerAddr,
|
makerAddr,
|
||||||
ticker,
|
ticker,
|
||||||
tokenType,
|
tokenType,
|
||||||
nostrEventId
|
nostrEventId,
|
||||||
|
makerNpub
|
||||||
}
|
}
|
||||||
// console.log('offer entity validatedOfferData: ', validatedOfferData)
|
// console.log('offer entity validatedOfferData: ', validatedOfferData)
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import RetryQueue from '@chris.troutner/retry-queue'
|
|||||||
|
|
||||||
// Local libraries
|
// Local libraries
|
||||||
import OfferEntity from '../../entities/offer.js'
|
import OfferEntity from '../../entities/offer.js'
|
||||||
|
import CounterOfferEntity from '../../entities/counterOffer.js'
|
||||||
import config from '../../../config/index.js'
|
import config from '../../../config/index.js'
|
||||||
|
|
||||||
const DEFAULT_ENTRIES_PER_PAGE = 20
|
const DEFAULT_ENTRIES_PER_PAGE = 20
|
||||||
@@ -45,7 +46,9 @@ class OfferUseCases {
|
|||||||
this.config = config
|
this.config = config
|
||||||
this.axios = axios
|
this.axios = axios
|
||||||
this.offerEntity = new OfferEntity()
|
this.offerEntity = new OfferEntity()
|
||||||
|
this.counterOfferEntity = new CounterOfferEntity()
|
||||||
this.OfferModel = this.adapters.localdb.Offer
|
this.OfferModel = this.adapters.localdb.Offer
|
||||||
|
this.CounterOfferModel = this.adapters.localdb.CounterOffer
|
||||||
this.retryQueue = new RetryQueue({ retryPeriod: 1000, attempts: 3 })
|
this.retryQueue = new RetryQueue({ retryPeriod: 1000, attempts: 3 })
|
||||||
|
|
||||||
// Bind 'this' object to functions
|
// Bind 'this' object to functions
|
||||||
@@ -66,6 +69,7 @@ class OfferUseCases {
|
|||||||
this.loadOffers = this.loadOffers.bind(this)
|
this.loadOffers = this.loadOffers.bind(this)
|
||||||
this.listOffersByAddress = this.listOffersByAddress.bind(this)
|
this.listOffersByAddress = this.listOffersByAddress.bind(this)
|
||||||
this.syncOfferMutableData = this.syncOfferMutableData.bind(this)
|
this.syncOfferMutableData = this.syncOfferMutableData.bind(this)
|
||||||
|
this.listCounterOffersByAddress = this.listCounterOffersByAddress.bind(this)
|
||||||
|
|
||||||
// State
|
// State
|
||||||
this.seenOffers = []
|
this.seenOffers = []
|
||||||
@@ -144,6 +148,7 @@ class OfferUseCases {
|
|||||||
const immutableDataCid = tokenData.immutableData
|
const immutableDataCid = tokenData.immutableData
|
||||||
offerEntity.mutableDataCid = mutableDataCid
|
offerEntity.mutableDataCid = mutableDataCid
|
||||||
offerEntity.immutableDataCid = immutableDataCid
|
offerEntity.immutableDataCid = immutableDataCid
|
||||||
|
offerEntity.tokenData = tokenData
|
||||||
|
|
||||||
// Get the mutable data from the cid if it exists.
|
// Get the mutable data from the cid if it exists.
|
||||||
if (mutableDataCid && typeof mutableDataCid === 'string') {
|
if (mutableDataCid && typeof mutableDataCid === 'string') {
|
||||||
@@ -595,10 +600,23 @@ class OfferUseCases {
|
|||||||
// and broadcasts the transaction to accept the Counter Offer.
|
// and broadcasts the transaction to accept the Counter Offer.
|
||||||
async acceptCounterOffer (offerData) {
|
async acceptCounterOffer (offerData) {
|
||||||
try {
|
try {
|
||||||
|
console.log('offerData', offerData)
|
||||||
// console.log(`acceptCounterOffer() offerData: ${JSON.stringify(offerData, null, 2)}`)
|
// console.log(`acceptCounterOffer() offerData: ${JSON.stringify(offerData, null, 2)}`)
|
||||||
|
|
||||||
// Quickly skip over offers that have already been processed.
|
// Quickly skip over offers that have already been processed.
|
||||||
const eventId = offerData.data.nostrEventId
|
const eventId = offerData.data.nostrEventId
|
||||||
|
|
||||||
|
// Create counter offer entity for nostr event id if it not exist
|
||||||
|
const existingCounterOffer = await this.CounterOfferModel.findOne(({ nostrEventId: eventId }))
|
||||||
|
if (!existingCounterOffer) {
|
||||||
|
// Add taker offer utxo to counter offer data.
|
||||||
|
offerData.data.takerOfferUtxo = offerData.data.utxoTxid
|
||||||
|
const counterOEntity = this.counterOfferEntity.validate(offerData)
|
||||||
|
// Create new counter offfer model and save it.
|
||||||
|
const counterOffer = new this.CounterOfferModel(counterOEntity)
|
||||||
|
await counterOffer.save()
|
||||||
|
}
|
||||||
|
|
||||||
if (this.seenOffers.includes(eventId)) {
|
if (this.seenOffers.includes(eventId)) {
|
||||||
// console.log(`Offer with event ID ${eventId} already processed. Skipping.`)
|
// console.log(`Offer with event ID ${eventId} already processed. Skipping.`)
|
||||||
return false
|
return false
|
||||||
@@ -983,6 +1001,7 @@ class OfferUseCases {
|
|||||||
const immutableDataCid = tokenData.immutableData
|
const immutableDataCid = tokenData.immutableData
|
||||||
offer.mutableDataCid = mutableDataCid
|
offer.mutableDataCid = mutableDataCid
|
||||||
offer.immutableDataCid = immutableDataCid
|
offer.immutableDataCid = immutableDataCid
|
||||||
|
offer.tokenData = tokenData
|
||||||
|
|
||||||
// Get the mutable data from the cid if it exists.
|
// Get the mutable data from the cid if it exists.
|
||||||
if (mutableDataCid && typeof mutableDataCid === 'string') {
|
if (mutableDataCid && typeof mutableDataCid === 'string') {
|
||||||
@@ -1020,6 +1039,20 @@ class OfferUseCases {
|
|||||||
throw err
|
throw err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async listCounterOffersByAddress (takerAddr) {
|
||||||
|
try {
|
||||||
|
if (!takerAddr || typeof takerAddr !== 'string') {
|
||||||
|
throw new Error('takerAddr must be a string')
|
||||||
|
}
|
||||||
|
|
||||||
|
const counterOffers = await this.CounterOfferModel.find({ takerAddr })
|
||||||
|
return counterOffers
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error in listCounterOffersByAddress(): ', err)
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default OfferUseCases
|
export default OfferUseCases
|
||||||
|
|||||||
@@ -251,6 +251,28 @@ describe('#Offer-REST-Router', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('#listCounterOffersByAddress', () => {
|
||||||
|
it('should list counter offers by address', async () => {
|
||||||
|
ctx.params = { addr: 'testAddress' }
|
||||||
|
sandbox.stub(uut.useCases.offer, 'listCounterOffersByAddress').resolves([])
|
||||||
|
await uut.listCounterOffersByAddress(ctx)
|
||||||
|
assert.isArray(ctx.body.counterOffers)
|
||||||
|
})
|
||||||
|
it('should catch and throw an error', async () => {
|
||||||
|
try {
|
||||||
|
ctx.params = { addr: 'testAddress' }
|
||||||
|
sandbox
|
||||||
|
.stub(uut.useCases.offer, 'listCounterOffersByAddress')
|
||||||
|
.throws(new Error('test error'))
|
||||||
|
|
||||||
|
await uut.listCounterOffersByAddress(ctx)
|
||||||
|
assert.fail('Unexpected code path')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, 'test error')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('#handleError', () => {
|
describe('#handleError', () => {
|
||||||
it('should still throw error if there is no message', () => {
|
it('should still throw error if there is no message', () => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -0,0 +1,177 @@
|
|||||||
|
/*
|
||||||
|
Unit tests for the CounterOffer entity library.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { assert } from 'chai'
|
||||||
|
import sinon from 'sinon'
|
||||||
|
|
||||||
|
import CounterOfferEntity from '../../../src/entities/counterOffer.js'
|
||||||
|
|
||||||
|
let sandbox
|
||||||
|
let uut
|
||||||
|
|
||||||
|
describe('#CounterOffer-Entity', () => {
|
||||||
|
before(async () => { })
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
uut = new CounterOfferEntity()
|
||||||
|
|
||||||
|
sandbox = sinon.createSandbox()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => sandbox.restore())
|
||||||
|
|
||||||
|
describe('#validate', () => {
|
||||||
|
it('should throw an error if data is not provided', () => {
|
||||||
|
try {
|
||||||
|
uut.validate({})
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, 'Input to counterOffer.validate() must be an object with a data property.')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should throw an error if nostrEventId is not provided', () => {
|
||||||
|
try {
|
||||||
|
uut.validate({ data: {} })
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, "Property 'nostrEventId' must be a string")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should throw an error if provided takerAddr is not string', () => {
|
||||||
|
try {
|
||||||
|
const inObj = {
|
||||||
|
nostrEventId: 'nostr event id',
|
||||||
|
takerAddr: 1234
|
||||||
|
}
|
||||||
|
uut.validate({ data: inObj })
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, "Property 'takerAddr' must be a string")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should throw an error if provided takerNpub is not string', () => {
|
||||||
|
try {
|
||||||
|
const inObj = {
|
||||||
|
nostrEventId: 'nostr event id',
|
||||||
|
takerAddr: 'taker address',
|
||||||
|
takerNpub: 1234
|
||||||
|
}
|
||||||
|
uut.validate({ data: inObj })
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, "Property 'takerNpub' must be a string")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should throw an error if provided makerNpub is not string', () => {
|
||||||
|
try {
|
||||||
|
const inObj = {
|
||||||
|
nostrEventId: 'nostr event id',
|
||||||
|
takerAddr: 'taker address',
|
||||||
|
takerNpub: 'npub',
|
||||||
|
makerNpub: 1234
|
||||||
|
}
|
||||||
|
uut.validate({ data: inObj })
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, "Property 'makerNpub' must be a string")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should throw an error if provided counterOfferAddr is not string', () => {
|
||||||
|
try {
|
||||||
|
const inObj = {
|
||||||
|
nostrEventId: 'nostr event id',
|
||||||
|
takerAddr: 'taker address',
|
||||||
|
takerNpub: 'npub',
|
||||||
|
makerNpub: 'npub',
|
||||||
|
counterOfferAddr: 1234
|
||||||
|
}
|
||||||
|
uut.validate({ data: inObj })
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, "Property 'counterOfferAddr' must be a string")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should throw an error if provided counterOfferUtxo is not string', () => {
|
||||||
|
try {
|
||||||
|
const inObj = {
|
||||||
|
nostrEventId: 'nostr event id',
|
||||||
|
takerAddr: 'taker address',
|
||||||
|
takerNpub: 'npub',
|
||||||
|
makerNpub: 'npub',
|
||||||
|
counterOfferAddr: 'counter offer address',
|
||||||
|
counterOfferUtxo: 1234
|
||||||
|
}
|
||||||
|
uut.validate({ data: inObj })
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, "Property 'counterOfferUtxo' must be a string")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should throw an error if provided takerOfferUtxo is not string', () => {
|
||||||
|
try {
|
||||||
|
const inObj = {
|
||||||
|
nostrEventId: 'nostr event id',
|
||||||
|
takerAddr: 'taker address',
|
||||||
|
takerNpub: 'npub',
|
||||||
|
makerNpub: 'npub',
|
||||||
|
counterOfferAddr: 'counter offer address',
|
||||||
|
counterOfferUtxo: 'utxo txid',
|
||||||
|
takerOfferUtxo: 1234
|
||||||
|
}
|
||||||
|
uut.validate({ data: inObj })
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, "Property 'takerOfferUtxo' must be a string")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
it('should throw an error if provided tokenId is not string', () => {
|
||||||
|
try {
|
||||||
|
const inObj = {
|
||||||
|
nostrEventId: 'nostr event id',
|
||||||
|
takerAddr: 'taker address',
|
||||||
|
takerNpub: 'npub',
|
||||||
|
makerNpub: 'npub',
|
||||||
|
counterOfferAddr: 'counter offer address',
|
||||||
|
counterOfferUtxo: 'utxo txid',
|
||||||
|
takerOfferUtxo: 'utxo txid',
|
||||||
|
tokenId: 1234
|
||||||
|
}
|
||||||
|
uut.validate({ data: inObj })
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, "Property 'tokenId' must be a string")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return a counter offer object', () => {
|
||||||
|
const inObj = {
|
||||||
|
nostrEventId: 'nostr event id',
|
||||||
|
takerAddr: 'taker address',
|
||||||
|
takerNpub: 'npub',
|
||||||
|
makerNpub: 'npub',
|
||||||
|
counterOfferAddr: 'counter offer address',
|
||||||
|
counterOfferUtxo: 'utxo txid',
|
||||||
|
takerOfferUtxo: 'utxo txid',
|
||||||
|
tokenId: 'token id'
|
||||||
|
}
|
||||||
|
|
||||||
|
const counterOfferEntity = uut.validate({ data: inObj })
|
||||||
|
|
||||||
|
assert.property(counterOfferEntity, 'nostrEventId')
|
||||||
|
assert.equal(counterOfferEntity.nostrEventId, inObj.nostrEventId)
|
||||||
|
|
||||||
|
assert.property(counterOfferEntity, 'takerAddr')
|
||||||
|
assert.equal(counterOfferEntity.takerAddr, inObj.takerAddr)
|
||||||
|
|
||||||
|
assert.property(counterOfferEntity, 'takerNpub')
|
||||||
|
assert.equal(counterOfferEntity.takerNpub, inObj.takerNpub)
|
||||||
|
|
||||||
|
assert.property(counterOfferEntity, 'makerNpub')
|
||||||
|
assert.equal(counterOfferEntity.makerNpub, inObj.makerNpub)
|
||||||
|
|
||||||
|
assert.property(counterOfferEntity, 'counterOfferAddr')
|
||||||
|
assert.equal(counterOfferEntity.counterOfferAddr, inObj.counterOfferAddr)
|
||||||
|
|
||||||
|
assert.property(counterOfferEntity, 'counterOfferUtxo')
|
||||||
|
assert.equal(counterOfferEntity.counterOfferUtxo, inObj.counterOfferUtxo)
|
||||||
|
|
||||||
|
assert.property(counterOfferEntity, 'takerOfferUtxo')
|
||||||
|
assert.equal(counterOfferEntity.takerOfferUtxo, inObj.takerOfferUtxo)
|
||||||
|
|
||||||
|
assert.property(counterOfferEntity, 'tokenId')
|
||||||
|
assert.equal(counterOfferEntity.tokenId, inObj.tokenId)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -491,6 +491,36 @@ describe('#Offer-Entity', () => {
|
|||||||
assert.include(err.message, "Property 'operatorPercentage' must be a number.")
|
assert.include(err.message, "Property 'operatorPercentage' must be a number.")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
it('should throw an error if makerNpub is not a string', () => {
|
||||||
|
try {
|
||||||
|
const offerData = {
|
||||||
|
data: {
|
||||||
|
messageType: 1,
|
||||||
|
messageClass: 1,
|
||||||
|
tokenId: 'fakeId',
|
||||||
|
buyOrSell: 'buy',
|
||||||
|
rateInBaseUnit: 1000,
|
||||||
|
minUnitsToExchange: 350,
|
||||||
|
numTokens: 1,
|
||||||
|
utxoTxid: 'fakeTxid',
|
||||||
|
utxoVout: 0,
|
||||||
|
offerStatus: 'posted',
|
||||||
|
makerAddr: 'bitcoincash:qzl0d3gcqeypv4cy7gh8rgdszxa9vvm2acv7fqtd00',
|
||||||
|
tokenType: 1,
|
||||||
|
nostrEventId: 'test',
|
||||||
|
operatorAddress: 'bitcoincash:qzl0d3gcqeypv4cy7gh8rgdszxa9vvm2acv7fqtd00',
|
||||||
|
operatorPercentage: 10,
|
||||||
|
makerNpub: 1234
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uut.validate(offerData)
|
||||||
|
|
||||||
|
assert.fail('Unexpected code path')
|
||||||
|
} catch (err) {
|
||||||
|
// console.log(err)
|
||||||
|
assert.include(err.message, "Property 'makerNpub' must be a string.")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
it('should validate a new offer', () => {
|
it('should validate a new offer', () => {
|
||||||
const offerObj = {
|
const offerObj = {
|
||||||
@@ -513,7 +543,8 @@ describe('#Offer-Entity', () => {
|
|||||||
tokenType: 1,
|
tokenType: 1,
|
||||||
nostrEventId: 'test',
|
nostrEventId: 'test',
|
||||||
operatorAddress: 'bitcoincash:qzl0d3gcqeypv4cy7gh8rgdszxa9vvm2acv7fqtd00',
|
operatorAddress: 'bitcoincash:qzl0d3gcqeypv4cy7gh8rgdszxa9vvm2acv7fqtd00',
|
||||||
operatorPercentage: 10
|
operatorPercentage: 10,
|
||||||
|
makerNpub: 'npub1dtkf954h5k2yuv04xp44g5hnmk5k0ppv8mekxafm2gc0vveaxh6s0297qg'
|
||||||
},
|
},
|
||||||
timestamp: '2021-09-20T17:54:26.395Z',
|
timestamp: '2021-09-20T17:54:26.395Z',
|
||||||
localTimeStamp: '9/20/2021, 10:54:26 AM',
|
localTimeStamp: '9/20/2021, 10:54:26 AM',
|
||||||
@@ -539,6 +570,8 @@ describe('#Offer-Entity', () => {
|
|||||||
assert.property(result, 'txid')
|
assert.property(result, 'txid')
|
||||||
assert.property(result, 'p2wdbHash')
|
assert.property(result, 'p2wdbHash')
|
||||||
assert.property(result, 'tokenType')
|
assert.property(result, 'tokenType')
|
||||||
|
assert.property(result, 'makerAddr')
|
||||||
|
assert.property(result, 'makerNpub')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -154,6 +154,17 @@ const localdb = {
|
|||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
CounterOffer: class CounterOffer {
|
||||||
|
constructor (obj) {}
|
||||||
|
|
||||||
|
static findById () {}
|
||||||
|
static find () {}
|
||||||
|
static findOne () {}
|
||||||
|
static countDocuments(){}
|
||||||
|
async save () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
SmAccount: class SmAccount {
|
SmAccount: class SmAccount {
|
||||||
constructor (obj) {}
|
constructor (obj) {}
|
||||||
|
|
||||||
|
|||||||
@@ -74,6 +74,9 @@ class Offer {
|
|||||||
async syncOfferMutableData(){
|
async syncOfferMutableData(){
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
async listCounterOffersByAddress() {
|
||||||
|
return []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Order {
|
class Order {
|
||||||
|
|||||||
@@ -107,14 +107,14 @@ describe('#offer-use-case', () => {
|
|||||||
const result = await uut.createOffer(offerObj)
|
const result = await uut.createOffer(offerObj)
|
||||||
assert.isFalse(result)
|
assert.isFalse(result)
|
||||||
})
|
})
|
||||||
|
it('should create offer with token data', async () => {
|
||||||
it('should create offer with mutable data', async () => {
|
|
||||||
const tokenDataMock = mockData.nftTokenData01
|
const tokenDataMock = mockData.nftTokenData01
|
||||||
const offerObj = mockData.offerMockData
|
const offerObj = mockData.offerMockData
|
||||||
const mutableDataMock = mockData.mutableDataMock
|
const mutableDataMock = mockData.mutableDataMock
|
||||||
|
const offerEntityMock = Object.assign({}, mockData.offerMockData.data)
|
||||||
|
|
||||||
// Mock dependencies
|
// Mock dependencies
|
||||||
// sandbox.stub(uut.adapters.wallet.bchWallet, 'utxoIsValid').resolves(false)
|
sandbox.stub(uut.offerEntity, 'validate').returns(offerEntityMock)
|
||||||
sandbox.stub(uut, 'findOfferByTxid').throws(new Error('offer not found'))
|
sandbox.stub(uut, 'findOfferByTxid').throws(new Error('offer not found'))
|
||||||
sandbox.stub(uut.retryQueue, 'addToQueue')
|
sandbox.stub(uut.retryQueue, 'addToQueue')
|
||||||
.onCall(0).resolves({}) // Utxo Status call
|
.onCall(0).resolves({}) // Utxo Status call
|
||||||
@@ -123,6 +123,31 @@ describe('#offer-use-case', () => {
|
|||||||
|
|
||||||
const result = await uut.createOffer(offerObj)
|
const result = await uut.createOffer(offerObj)
|
||||||
assert.isTrue(result)
|
assert.isTrue(result)
|
||||||
|
console.log('offerEntityMock', offerEntityMock)
|
||||||
|
assert.property(offerEntityMock, 'tokenData')
|
||||||
|
})
|
||||||
|
it('should create offer with mutable data', async () => {
|
||||||
|
const tokenDataMock = mockData.nftTokenData01
|
||||||
|
const offerObj = mockData.offerMockData
|
||||||
|
const mutableDataMock = mockData.mutableDataMock
|
||||||
|
const offerEntityMock = Object.assign({}, mockData.offerMockData.data)
|
||||||
|
|
||||||
|
// Mock dependencies
|
||||||
|
sandbox.stub(uut.offerEntity, 'validate').returns(offerEntityMock)
|
||||||
|
sandbox.stub(uut, 'findOfferByTxid').throws(new Error('offer not found'))
|
||||||
|
sandbox.stub(uut.retryQueue, 'addToQueue')
|
||||||
|
.onCall(0).resolves({}) // Utxo Status call
|
||||||
|
.onCall(1).resolves(tokenDataMock) // Token Data call
|
||||||
|
.onCall(2).resolves(mutableDataMock)
|
||||||
|
|
||||||
|
const result = await uut.createOffer(offerObj)
|
||||||
|
assert.isTrue(result)
|
||||||
|
console.log('offerEntityMock', offerEntityMock)
|
||||||
|
|
||||||
|
assert.property(offerEntityMock, 'tokenIconUrl')
|
||||||
|
assert.property(offerEntityMock, 'tokenCategories')
|
||||||
|
assert.property(offerEntityMock, 'tokenTags')
|
||||||
|
assert.property(offerEntityMock, 'lastUpdatedTokenData')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should skip userData stringify error', async () => {
|
it('should skip userData stringify error', async () => {
|
||||||
@@ -835,6 +860,25 @@ describe('#offer-use-case', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe('#acceptCounterOffer', () => {
|
describe('#acceptCounterOffer', () => {
|
||||||
|
it('should capture counter offer if does not exist', async () => {
|
||||||
|
const offerObj = mockData.offerMockData
|
||||||
|
sandbox.stub(uut.CounterOfferModel, 'findOne').resolves(null)
|
||||||
|
const spy = sandbox.stub(uut.CounterOfferModel.prototype, 'save')
|
||||||
|
// Mock dependencies
|
||||||
|
|
||||||
|
await uut.acceptCounterOffer(offerObj)
|
||||||
|
assert.isTrue(spy.calledOnce)
|
||||||
|
})
|
||||||
|
it('should not save counter offer if already exist', async () => {
|
||||||
|
const offerObj = mockData.offerMockData
|
||||||
|
sandbox.stub(uut.CounterOfferModel, 'findOne').resolves(offerObj.data)
|
||||||
|
const spy = sandbox.stub(uut.CounterOfferModel.prototype, 'save')
|
||||||
|
// Mock dependencies
|
||||||
|
|
||||||
|
await uut.acceptCounterOffer(offerObj)
|
||||||
|
assert.isFalse(spy.calledOnce)
|
||||||
|
})
|
||||||
|
|
||||||
it('should return false if order already processed', async () => {
|
it('should return false if order already processed', async () => {
|
||||||
const offerObj = mockData.offerMockData
|
const offerObj = mockData.offerMockData
|
||||||
uut.seenOffers.push(offerObj.data.nostrEventId)
|
uut.seenOffers.push(offerObj.data.nostrEventId)
|
||||||
@@ -846,14 +890,18 @@ describe('#offer-use-case', () => {
|
|||||||
|
|
||||||
it('should return if order is not found!', async () => {
|
it('should return if order is not found!', async () => {
|
||||||
// Mock dependencies
|
// Mock dependencies
|
||||||
|
const offerObj = mockData.offerMockData
|
||||||
|
|
||||||
sandbox.stub(uut.orderUseCase, 'findOrderByUtxo').throws(new Error('test error'))
|
sandbox.stub(uut.orderUseCase, 'findOrderByUtxo').throws(new Error('test error'))
|
||||||
|
|
||||||
const result = await uut.acceptCounterOffer({ data: { /** .... */ } })
|
const result = await uut.acceptCounterOffer(offerObj)
|
||||||
assert.equal(result, 'N/A')
|
assert.equal(result, 'N/A')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should return N/A on axios error', async () => {
|
it('should return N/A on axios error', async () => {
|
||||||
// Mock dependencies
|
// Mock dependencies
|
||||||
|
const offerObj = mockData.offerMockData
|
||||||
|
|
||||||
const mock = Object.assign({}, mockData.offerMockData.data)
|
const mock = Object.assign({}, mockData.offerMockData.data)
|
||||||
sandbox.stub(uut.orderUseCase, 'findOrderByUtxo').resolves(mock)
|
sandbox.stub(uut.orderUseCase, 'findOrderByUtxo').resolves(mock)
|
||||||
// sandbox.stub(uut.adapters.wallet.bchWallet, 'utxoIsValid').throws(new Error('test error'))
|
// sandbox.stub(uut.adapters.wallet.bchWallet, 'utxoIsValid').throws(new Error('test error'))
|
||||||
@@ -861,32 +909,38 @@ describe('#offer-use-case', () => {
|
|||||||
axiosErr.isAxiosError = true
|
axiosErr.isAxiosError = true
|
||||||
sandbox.stub(uut.retryQueue, 'addToQueue').throws(axiosErr)
|
sandbox.stub(uut.retryQueue, 'addToQueue').throws(axiosErr)
|
||||||
|
|
||||||
const result = await uut.acceptCounterOffer({ data: { /** .... */ } })
|
const result = await uut.acceptCounterOffer(offerObj)
|
||||||
assert.equal(result, 'N/A')
|
assert.equal(result, 'N/A')
|
||||||
})
|
})
|
||||||
it('should return if utxo can not be validated', async () => {
|
it('should return if utxo can not be validated', async () => {
|
||||||
// Mock dependencies
|
// Mock dependencies
|
||||||
|
const offerObj = mockData.offerMockData
|
||||||
|
|
||||||
const mock = Object.assign({}, mockData.offerMockData.data)
|
const mock = Object.assign({}, mockData.offerMockData.data)
|
||||||
sandbox.stub(uut.orderUseCase, 'findOrderByUtxo').resolves(mock)
|
sandbox.stub(uut.orderUseCase, 'findOrderByUtxo').resolves(mock)
|
||||||
// sandbox.stub(uut.adapters.wallet.bchWallet, 'utxoIsValid').throws(new Error('test error'))
|
// sandbox.stub(uut.adapters.wallet.bchWallet, 'utxoIsValid').throws(new Error('test error'))
|
||||||
sandbox.stub(uut.retryQueue, 'addToQueue').throws(new Error('test error'))
|
sandbox.stub(uut.retryQueue, 'addToQueue').throws(new Error('test error'))
|
||||||
|
|
||||||
const result = await uut.acceptCounterOffer({ data: { /** .... */ } })
|
const result = await uut.acceptCounterOffer(offerObj)
|
||||||
assert.equal(result, 'N/A')
|
assert.equal(result, 'N/A')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should return if utxo is invalid', async () => {
|
it('should return if utxo is invalid', async () => {
|
||||||
// Mock dependencies
|
// Mock dependencies
|
||||||
|
const offerObj = mockData.offerMockData
|
||||||
|
|
||||||
const mock = Object.assign({}, mockData.offerMockData.data)
|
const mock = Object.assign({}, mockData.offerMockData.data)
|
||||||
sandbox.stub(uut.orderUseCase, 'findOrderByUtxo').resolves(mock)
|
sandbox.stub(uut.orderUseCase, 'findOrderByUtxo').resolves(mock)
|
||||||
sandbox.stub(uut.adapters.wallet.bchWallet, 'utxoIsValid').resolves(false)
|
sandbox.stub(uut.adapters.wallet.bchWallet, 'utxoIsValid').resolves(false)
|
||||||
|
|
||||||
const result = await uut.acceptCounterOffer({ data: { /** .... */ } })
|
const result = await uut.acceptCounterOffer(offerObj)
|
||||||
assert.equal(result, 'N/A')
|
assert.equal(result, 'N/A')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should handle error if counter offer cant be calculated', async () => {
|
it('should handle error if counter offer cant be calculated', async () => {
|
||||||
try {
|
try {
|
||||||
|
const offerObj = mockData.offerMockData
|
||||||
|
|
||||||
// Mock Data
|
// Mock Data
|
||||||
const mock = Object.assign({}, mockData.offerMockData.data)
|
const mock = Object.assign({}, mockData.offerMockData.data)
|
||||||
mock.rateInBaseUnit = null
|
mock.rateInBaseUnit = null
|
||||||
@@ -895,8 +949,7 @@ describe('#offer-use-case', () => {
|
|||||||
sandbox.stub(uut.orderUseCase, 'findOrderByEvent').resolves(mock)
|
sandbox.stub(uut.orderUseCase, 'findOrderByEvent').resolves(mock)
|
||||||
sandbox.stub(uut.orderUseCase, 'findOrderByUtxo').resolves(mock)
|
sandbox.stub(uut.orderUseCase, 'findOrderByUtxo').resolves(mock)
|
||||||
|
|
||||||
const result = await uut.acceptCounterOffer({ data: {} })
|
await uut.acceptCounterOffer(offerObj)
|
||||||
console.log('result: ', result)
|
|
||||||
assert.fail('unexpected code path')
|
assert.fail('unexpected code path')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
assert.include(err.message, 'Could not calculate the amount of BCH offered in the Counter Offer')
|
assert.include(err.message, 'Could not calculate the amount of BCH offered in the Counter Offer')
|
||||||
@@ -906,6 +959,7 @@ describe('#offer-use-case', () => {
|
|||||||
it('should handle error for wrong transaction output', async () => {
|
it('should handle error for wrong transaction output', async () => {
|
||||||
try {
|
try {
|
||||||
// Mock Data
|
// Mock Data
|
||||||
|
|
||||||
const mock = Object.assign({}, mockData.offerMockData.data)
|
const mock = Object.assign({}, mockData.offerMockData.data)
|
||||||
|
|
||||||
// Mock dependencies
|
// Mock dependencies
|
||||||
@@ -923,6 +977,7 @@ describe('#offer-use-case', () => {
|
|||||||
|
|
||||||
it('should skip transactions that do not have an output for the operator', async () => {
|
it('should skip transactions that do not have an output for the operator', async () => {
|
||||||
// Mock data
|
// Mock data
|
||||||
|
|
||||||
const mock = Object.assign({}, mockData.offerMockData.data)
|
const mock = Object.assign({}, mockData.offerMockData.data)
|
||||||
mock.makerAddr = 'bitcoincash:qzy97glp47ut7tstm5g0tlrmkhk742795gkmyc7477' // Unknow Adress
|
mock.makerAddr = 'bitcoincash:qzy97glp47ut7tstm5g0tlrmkhk742795gkmyc7477' // Unknow Adress
|
||||||
mock.rateInBaseUnit = 0
|
mock.rateInBaseUnit = 0
|
||||||
@@ -934,7 +989,7 @@ describe('#offer-use-case', () => {
|
|||||||
|
|
||||||
sandbox.stub(uut.adapters.wallet, 'deseralizeTx').resolves(mockData.deserealizeTxMockNoOperatorOut)
|
sandbox.stub(uut.adapters.wallet, 'deseralizeTx').resolves(mockData.deserealizeTxMockNoOperatorOut)
|
||||||
|
|
||||||
const result = await uut.acceptCounterOffer({ data: { /** .... */ } })
|
const result = await uut.acceptCounterOffer({ data: mock })
|
||||||
assert.equal(result, 'N/A')
|
assert.equal(result, 'N/A')
|
||||||
})
|
})
|
||||||
it('should skip transactions if operator address does not match', async () => {
|
it('should skip transactions if operator address does not match', async () => {
|
||||||
@@ -952,7 +1007,7 @@ describe('#offer-use-case', () => {
|
|||||||
|
|
||||||
sandbox.stub(uut.adapters.wallet, 'deseralizeTx').resolves(mockData.deserealizeTxMock)
|
sandbox.stub(uut.adapters.wallet, 'deseralizeTx').resolves(mockData.deserealizeTxMock)
|
||||||
|
|
||||||
await uut.acceptCounterOffer({ data: {} })
|
await uut.acceptCounterOffer({ data: mock })
|
||||||
assert.fail('unexpected code path')
|
assert.fail('unexpected code path')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
assert.include(error.message, 'The Counter Offer has an output address of')
|
assert.include(error.message, 'The Counter Offer has an output address of')
|
||||||
@@ -974,7 +1029,7 @@ describe('#offer-use-case', () => {
|
|||||||
|
|
||||||
sandbox.stub(uut.adapters.wallet, 'deseralizeTx').resolves(mockData.deserealizeTxMock)
|
sandbox.stub(uut.adapters.wallet, 'deseralizeTx').resolves(mockData.deserealizeTxMock)
|
||||||
|
|
||||||
await uut.acceptCounterOffer({ data: {} })
|
await uut.acceptCounterOffer({ data: mock })
|
||||||
assert.fail('unexpected code path')
|
assert.fail('unexpected code path')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
assert.include(err.message, 'The Counter Offer has an output address of')
|
assert.include(err.message, 'The Counter Offer has an output address of')
|
||||||
@@ -997,7 +1052,7 @@ describe('#offer-use-case', () => {
|
|||||||
|
|
||||||
sandbox.stub(uut.adapters.wallet, 'deseralizeTx').resolves(mockData.deserealizeTxMock)
|
sandbox.stub(uut.adapters.wallet, 'deseralizeTx').resolves(mockData.deserealizeTxMock)
|
||||||
|
|
||||||
const result = await uut.acceptCounterOffer({ data: {} })
|
const result = await uut.acceptCounterOffer({ data: mock })
|
||||||
assert.equal(result, 'N/A')
|
assert.equal(result, 'N/A')
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -1017,7 +1072,7 @@ describe('#offer-use-case', () => {
|
|||||||
sandbox.stub(uut.adapters.wallet, 'deseralizeTx').resolves(mockData.deserealizeTxMock)
|
sandbox.stub(uut.adapters.wallet, 'deseralizeTx').resolves(mockData.deserealizeTxMock)
|
||||||
|
|
||||||
//
|
//
|
||||||
const result = await uut.acceptCounterOffer({ data: {} })
|
const result = await uut.acceptCounterOffer({ data: mock })
|
||||||
assert.isString(result)
|
assert.isString(result)
|
||||||
assert.notEqual('N/A')
|
assert.notEqual('N/A')
|
||||||
})
|
})
|
||||||
@@ -1076,6 +1131,12 @@ describe('#offer-use-case', () => {
|
|||||||
const offer = await uut.syncOfferMutableData('tokenId')
|
const offer = await uut.syncOfferMutableData('tokenId')
|
||||||
assert.isObject(offer)
|
assert.isObject(offer)
|
||||||
assert.isNumber(offer.lastUpdatedTokenData)
|
assert.isNumber(offer.lastUpdatedTokenData)
|
||||||
|
|
||||||
|
assert.property(offer, 'tokenData')
|
||||||
|
assert.property(offer, 'tokenIconUrl')
|
||||||
|
assert.property(offer, 'tokenCategories')
|
||||||
|
assert.property(offer, 'tokenTags')
|
||||||
|
assert.property(offer, 'lastUpdatedTokenData')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should skip userData stringify error', async () => {
|
it('should skip userData stringify error', async () => {
|
||||||
@@ -1130,4 +1191,23 @@ describe('#offer-use-case', () => {
|
|||||||
assert.isNumber(offer.lastUpdatedTokenData)
|
assert.isNumber(offer.lastUpdatedTokenData)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
describe('#listCounterOffersByAddress', () => {
|
||||||
|
it('should throw an error if takerAddr is not provided!', async () => {
|
||||||
|
try {
|
||||||
|
await uut.listCounterOffersByAddress()
|
||||||
|
|
||||||
|
assert.fail('unexpected code path')
|
||||||
|
} catch (err) {
|
||||||
|
assert.include(err.message, 'takerAddr must be a string')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return counter offers by address', async () => {
|
||||||
|
// Mock dependencies
|
||||||
|
sandbox.stub(uut.CounterOfferModel, 'find').resolves([])
|
||||||
|
|
||||||
|
const result = await uut.listCounterOffersByAddress('bitcoincash:qzltx40ldxr53edchprppj5lpg4q7vl20usx25ga44')
|
||||||
|
assert.isArray(result)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -11,12 +11,12 @@ import axios from 'axios'
|
|||||||
// import User from '../../../src/adapters/localdb/models/users.js'
|
// import User from '../../../src/adapters/localdb/models/users.js'
|
||||||
|
|
||||||
// Customize these variables
|
// Customize these variables
|
||||||
const EMAIL = 'someone@somewhere.com'
|
const EMAIL = 'chris.troutner@gmail.com'
|
||||||
const NAME = 'Someone'
|
const NAME = 'Chris'
|
||||||
const PASSWORD = 'test'
|
const PASSWORD = '0mega16'
|
||||||
|
|
||||||
const ADMIN_EMAIL = 'system@system.com'
|
const ADMIN_EMAIL = 'system@system.com'
|
||||||
const ADMIN_PASSWORD = 'admin'
|
const ADMIN_PASSWORD = 'decatur'
|
||||||
|
|
||||||
async function createUser () {
|
async function createUser () {
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user