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 | |
|---|---|---|---|
|
|
5eeafd7ead | ||
|
|
df146382cb | ||
|
|
af8a7c3ff3 |
@@ -37,7 +37,8 @@ const Order = new mongoose.Schema({
|
||||
// SWaP Protocol Properties
|
||||
lokadId: { type: String },
|
||||
messageType: { type: Number },
|
||||
messageClass: { type: Number }
|
||||
messageClass: { type: Number },
|
||||
nostrEventId: { type: String } // Nostr Event Id.
|
||||
})
|
||||
|
||||
export default mongoose.model('order', Order)
|
||||
|
||||
@@ -69,10 +69,10 @@ class OrderRESTControllerLib {
|
||||
try {
|
||||
// console.log('body: ', ctx.request.body)
|
||||
|
||||
const p2wdbHash = ctx.request.body.p2wdbHash
|
||||
const nostrEventId = ctx.request.body.nostrEventId
|
||||
// console.log('p2wdbHash: ', p2wdbHash)
|
||||
|
||||
const txid = await _this.useCases.order.deleteOrder(p2wdbHash)
|
||||
const txid = await _this.useCases.order.deleteOrder(nostrEventId)
|
||||
|
||||
ctx.body = { txid }
|
||||
} catch (err) {
|
||||
|
||||
@@ -454,7 +454,7 @@ class OfferUseCases {
|
||||
const orderHash = p2wdbData.data.offerHash
|
||||
let orderData = {}
|
||||
try {
|
||||
orderData = await this.orderUseCase.findOrderByHash(orderHash)
|
||||
orderData = await this.orderUseCase.findOrderByEvent(orderHash)
|
||||
console.log(`orderData: ${JSON.stringify(orderData, null, 2)}`)
|
||||
} catch (err) {
|
||||
console.log('Order matching this Counter Offer is not managed by this instance of bch-dex. Exiting.')
|
||||
|
||||
+20
-24
@@ -70,7 +70,7 @@ class OrderLib {
|
||||
}
|
||||
// const utxoInfo = await this.adapters.wallet.moveTokens(moveObj)
|
||||
const utxoInfo = await this.retryQueue.addToQueue(this.adapters.wallet.moveTokens, moveObj)
|
||||
console.log('utxoInfo: ', utxoInfo)
|
||||
// console.log('utxoInfo: ', utxoInfo)
|
||||
|
||||
// Update the UTXO store for the wallet.
|
||||
await this.adapters.wallet.bchWallet.bchjs.Util.sleep(3000)
|
||||
@@ -85,25 +85,24 @@ class OrderLib {
|
||||
// Add P2WDB specific flag for signaling that this is a new offer.
|
||||
orderEntity.dataType = 'offer'
|
||||
|
||||
// Add order to P2WDB.
|
||||
const p2wdbObj = {
|
||||
wif: this.adapters.wallet.bchWallet.walletInfo.privateKey,
|
||||
data: orderEntity,
|
||||
appId: this.config.p2wdbAppId
|
||||
// Post the new Order information to Nostr under the topic set in the
|
||||
// config file.
|
||||
const postObj = {
|
||||
data: orderEntity
|
||||
}
|
||||
// const hash = await this.adapters.p2wdb.write(p2wdbObj)
|
||||
const hash = await this.retryQueue.addToQueue(this.adapters.p2wdb.write, p2wdbObj)
|
||||
const postMsg = JSON.stringify(postObj)
|
||||
const eventId = await this.adapters.nostr.post(postMsg)
|
||||
// console.log('hash: ', hash)
|
||||
|
||||
// Create a MongoDB model to hold the Order
|
||||
orderEntity.hdIndex = utxoInfo.hdIndex
|
||||
orderEntity.p2wdbHash = hash
|
||||
orderEntity.nostrEventId = eventId
|
||||
|
||||
console.log(`creating new order model: ${JSON.stringify(orderEntity, null, 2)}`)
|
||||
const order = new this.OrderModel(orderEntity)
|
||||
await order.save()
|
||||
|
||||
return hash
|
||||
return eventId
|
||||
} catch (err) {
|
||||
// console.log("Error in use-cases/entry.js/createEntry()", err.message)
|
||||
wlogger.error('Error in use-cases/order.js/createOrder())')
|
||||
@@ -130,19 +129,17 @@ class OrderLib {
|
||||
|
||||
// Get UTXOs.
|
||||
const utxos = this.adapters.wallet.bchWallet.utxos.utxoStore
|
||||
// console.log(`utxos: ${JSON.stringify(utxos, null, 2)}`)
|
||||
console.log(`utxos: ${JSON.stringify(utxos, null, 2)}`)
|
||||
|
||||
if (orderEntity.buyOrSell.includes('sell')) {
|
||||
// Sell Order
|
||||
|
||||
// Combine Fungible and NFT token UTXOs.
|
||||
let tokenUtxos = utxos.slpUtxos.type1.tokens.concat(utxos.slpUtxos.nft.tokens)
|
||||
|
||||
// Get token UTXOs that match the token in the order.
|
||||
tokenUtxos = tokenUtxos.filter(
|
||||
x => x.tokenId === orderEntity.tokenId
|
||||
)
|
||||
console.log('tokenUtxos: ', tokenUtxos)
|
||||
|
||||
// Get the total amount of tokens in the wallet that match the token
|
||||
// in the order.
|
||||
@@ -171,14 +168,14 @@ class OrderLib {
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve an Order model from the database. Find it by its P2WDB CID.
|
||||
async findOrderByHash (p2wdbHash) {
|
||||
// Retrieve an Order model from the database. Find it by its event Id.
|
||||
async findOrderByEvent (nostrEventId) {
|
||||
try {
|
||||
if (typeof p2wdbHash !== 'string' || !p2wdbHash) {
|
||||
throw new Error('p2wdbHash must be a string')
|
||||
if (typeof nostrEventId !== 'string' || !nostrEventId) {
|
||||
throw new Error('nostrEventId must be a string')
|
||||
}
|
||||
|
||||
const order = await this.OrderModel.findOne({ p2wdbHash })
|
||||
const order = await this.OrderModel.findOne({ nostrEventId })
|
||||
|
||||
if (!order) {
|
||||
throw new Error('order not found')
|
||||
@@ -189,7 +186,7 @@ class OrderLib {
|
||||
|
||||
return orderObject
|
||||
} catch (err) {
|
||||
console.error('Error in findOrder()')
|
||||
console.error('Error in findOrderByEvent()')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
@@ -204,7 +201,7 @@ class OrderLib {
|
||||
|
||||
// Get all Orders in the database.
|
||||
const orders = await this.OrderModel.find({})
|
||||
// console.log('orders: ', orders)
|
||||
console.log('orders: ', orders)
|
||||
|
||||
// Loop through each Order and ensure the UTXO is still valid.
|
||||
for (let i = 0; i < orders.length; i++) {
|
||||
@@ -256,6 +253,7 @@ class OrderLib {
|
||||
async listOrders (page = 0) {
|
||||
try {
|
||||
const data = await this.OrderModel.find({})
|
||||
|
||||
// Sort entries so newest entries show first.
|
||||
.sort('-timestamp')
|
||||
// Skip to the start of the selected page.
|
||||
@@ -272,12 +270,10 @@ class OrderLib {
|
||||
|
||||
// Delete an Order model by sending the token back to the root address. This
|
||||
// will allow the garbage collectors to delete the Order and the Offer.
|
||||
async deleteOrder (p2wdbHash) {
|
||||
async deleteOrder (nostrEventId) {
|
||||
try {
|
||||
console.log('p2wdbHash: ', p2wdbHash)
|
||||
|
||||
// Find the order by the given hash.
|
||||
const order = await this.findOrderByHash(p2wdbHash)
|
||||
const order = await this.findOrderByEvent(nostrEventId)
|
||||
console.log('order: ', order)
|
||||
|
||||
// Reclaim the tokens
|
||||
|
||||
@@ -150,7 +150,8 @@ const wallet = {
|
||||
return { cashAddress: 'fakeAddr', wif: 'fakeWif', hdIndex: 1 }
|
||||
},
|
||||
bchWallet: new MockBchWallet(),
|
||||
moveTokens: async () => {}
|
||||
moveTokens: async () => {},
|
||||
reclaimTokens: async ()=>{}
|
||||
}
|
||||
|
||||
const p2wdb = {
|
||||
@@ -159,4 +160,9 @@ const p2wdb = {
|
||||
checkForSufficientFunds: async () => true
|
||||
}
|
||||
|
||||
export default { ipfs, localdb, bch, wallet, p2wdb, bchjs}
|
||||
const nostr = {
|
||||
post: async () => {return true },
|
||||
read: async () => { return true }
|
||||
}
|
||||
|
||||
export default { ipfs, localdb, bch, wallet, p2wdb, bchjs, nostr}
|
||||
|
||||
@@ -62,6 +62,69 @@ describe('#order-use-case', () => {
|
||||
|
||||
assert.equal(result, true)
|
||||
})
|
||||
it('should handle insufficient funds', async () => {
|
||||
try {
|
||||
sandbox.stub(uut.adapters.p2wdb, 'checkForSufficientFunds').resolves(false)
|
||||
const orderEntity = {
|
||||
lokadId: 'SWP',
|
||||
messageType: 1,
|
||||
messageClass: 1,
|
||||
tokenId: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2',
|
||||
buyOrSell: 'sell',
|
||||
rateInSats: 1000,
|
||||
minSatsToExchange: 0,
|
||||
numTokens: 1
|
||||
}
|
||||
|
||||
await uut.ensureFunds(orderEntity)
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'App wallet does not have funds for writing to the P2WDB')
|
||||
}
|
||||
})
|
||||
|
||||
it('should handle insufficient tokens to satisfy the order', async () => {
|
||||
try {
|
||||
const orderEntity = {
|
||||
lokadId: 'SWP',
|
||||
messageType: 1,
|
||||
messageClass: 1,
|
||||
tokenId: '38e97c5d7d3585a2cbf3f9580c82ca33985f9cb0845d4dcce220cb709f9538b0',
|
||||
buyOrSell: 'sell',
|
||||
rateInSats: 1000,
|
||||
minSatsToExchange: 0,
|
||||
numTokens: 1000
|
||||
}
|
||||
|
||||
await uut.ensureFunds(orderEntity)
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'App wallet does not have enough tokens to satisfy the SELL order.')
|
||||
}
|
||||
})
|
||||
|
||||
it('should handle BUY order', async () => {
|
||||
try {
|
||||
const orderEntity = {
|
||||
lokadId: 'SWP',
|
||||
messageType: 1,
|
||||
messageClass: 1,
|
||||
tokenId: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2',
|
||||
buyOrSell: 'buy',
|
||||
rateInSats: 1000,
|
||||
minSatsToExchange: 0,
|
||||
numTokens: 1
|
||||
}
|
||||
|
||||
await uut.ensureFunds(orderEntity)
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'Buy orders are not supported yet')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// describe('#moveTokens', () => {
|
||||
@@ -113,7 +176,7 @@ describe('#order-use-case', () => {
|
||||
sandbox.stub(uut.adapters.wallet.bchWallet.bchjs.Util, 'sleep').resolves()
|
||||
sandbox.stub(uut.adapters.wallet, 'moveTokens').resolves({ txid: 'fakeTxid', vout: 0, hdIndex: 1 })
|
||||
sandbox.stub(uut.adapters.wallet.bchWallet, 'initialize').resolves()
|
||||
sandbox.stub(uut.adapters.p2wdb, 'write').resolves('fakeHash')
|
||||
sandbox.stub(uut.adapters.nostr, 'post').resolves('fakeEvenetId')
|
||||
|
||||
const result = await uut.createOrder(entryObj)
|
||||
console.log('result: ', result)
|
||||
@@ -137,4 +200,137 @@ describe('#order-use-case', () => {
|
||||
assert.equal(result, false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#findOrderByEvent', () => {
|
||||
it('should throw an error if hash is not provided', async () => {
|
||||
try {
|
||||
await uut.findOrderByEvent()
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'nostrEventId must be a string')
|
||||
}
|
||||
})
|
||||
it('should throw an error if order is not found!', async () => {
|
||||
try {
|
||||
sandbox.stub(uut.OrderModel, 'findOne').resolves(null)
|
||||
await uut.findOrderByEvent('hash')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'order not found')
|
||||
}
|
||||
})
|
||||
it('should return order by hash', async () => {
|
||||
sandbox.stub(uut.OrderModel, 'findOne').resolves({ toObject: () => { return { hash: 'hash' } } })
|
||||
const result = await uut.findOrderByEvent('hash')
|
||||
assert.isObject(result)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#removeStaleOrders', () => {
|
||||
it('should remove stale orders', async () => {
|
||||
const spy = sinon.spy() // Spy the function
|
||||
|
||||
// Create 2 orders mock .
|
||||
const ordersMock = new Array(2)
|
||||
ordersMock.fill({ remove: () => { spy.call() } })
|
||||
|
||||
sandbox.stub(uut.OrderModel, 'find').resolves(ordersMock)
|
||||
sandbox.stub(uut.retryQueue, 'addToQueue').resolves(false)
|
||||
|
||||
await uut.removeStaleOrders()
|
||||
|
||||
assert.equal(spy.callCount, 2, 'Expected to be called twice.')
|
||||
})
|
||||
it('should handle wrong txid', async () => {
|
||||
const spy = sinon.spy() // Spy the function
|
||||
|
||||
// Create 2 orders mock .
|
||||
const ordersMock = new Array(2)
|
||||
ordersMock.fill({ remove: () => { spy.call() } })
|
||||
|
||||
sandbox.stub(uut.OrderModel, 'find').resolves(ordersMock)
|
||||
sandbox.stub(uut.retryQueue, 'addToQueue').throws(new Error('txid needs to be a proper transaction ID'))
|
||||
|
||||
await uut.removeStaleOrders()
|
||||
|
||||
assert.equal(spy.callCount, 2, 'Expected to be called twice.')
|
||||
})
|
||||
it('should skip order on axios error', async () => {
|
||||
const spy = sinon.spy() // Spy the function
|
||||
|
||||
// Create 2 orders mock .
|
||||
const ordersMock = new Array(2)
|
||||
ordersMock.fill({ remove: () => { spy.call() } })
|
||||
|
||||
const axiosError = new Error()
|
||||
axiosError.isAxiosError = true
|
||||
|
||||
sandbox.stub(uut.OrderModel, 'find').resolves(ordersMock)
|
||||
sandbox.stub(uut.retryQueue, 'addToQueue').throws(axiosError)
|
||||
|
||||
await uut.removeStaleOrders()
|
||||
|
||||
assert.equal(spy.callCount, 0, 'Expected to no be called.')
|
||||
})
|
||||
it('should handle unknow error', async () => {
|
||||
try {
|
||||
// Create 2 orders mock .
|
||||
const ordersMock = new Array(2)
|
||||
ordersMock.fill({ remove: () => { } })
|
||||
|
||||
sandbox.stub(uut.OrderModel, 'find').resolves(ordersMock)
|
||||
sandbox.stub(uut.retryQueue, 'addToQueue').throws(new Error('test error'))
|
||||
|
||||
await uut.removeStaleOrders()
|
||||
assert.fail('unexpected code path')
|
||||
} catch (error) {
|
||||
assert.include(error.message, 'test error')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#listOrders', () => {
|
||||
it('should handle error', async () => {
|
||||
try {
|
||||
sandbox.stub(uut.OrderModel, 'find').throws(new Error('test error'))
|
||||
await uut.listOrders()
|
||||
assert.fail('unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
|
||||
it('should list orders', async () => {
|
||||
const queryMock = {
|
||||
sort () {
|
||||
return this
|
||||
},
|
||||
skip () {
|
||||
return this
|
||||
},
|
||||
limit () { return [] }
|
||||
}
|
||||
|
||||
sandbox.stub(uut.OrderModel, 'find').returns(queryMock)
|
||||
const result = await uut.listOrders()
|
||||
assert.isArray(result)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#deleteOrder', () => {
|
||||
it('should handle error', async () => {
|
||||
try {
|
||||
sandbox.stub(uut, 'findOrderByEvent').throws(new Error('test error'))
|
||||
await uut.deleteOrder()
|
||||
assert.fail('unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
|
||||
it('should delete orders', async () => {
|
||||
sandbox.stub(uut, 'findOrderByEvent').resolves([])
|
||||
sandbox.stub(uut.adapters.wallet, 'reclaimTokens').resolves('txid')
|
||||
const result = await uut.deleteOrder()
|
||||
assert.isString(result)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user