Working on take-offer logic

This commit is contained in:
Chris Troutner
2022-03-10 13:21:25 -08:00
parent bf71810974
commit a6b4677571
7 changed files with 167 additions and 58 deletions
+13 -57
View File
@@ -178,63 +178,19 @@ class WalletAdapter {
}
}
// Burn enough PSF to generate a valide proof-of-burn for writing to the P2WDB.
// async burnPsf () {
// try {
// // TODO: Throw error if this.bchWallet has not been instantiated.
//
// // console.log('walletData: ', walletData)
// // console.log(
// // `walletData.utxos.utxoStore.slpUtxos: ${JSON.stringify(
// // walletData.utxos.utxoStore.slpUtxos,
// // null,
// // 2,
// // )}`,
// // )
//
// // Get token UTXOs held by the wallet.
// const tokenUtxos = this.bchWallet.utxos.utxoStore.slpUtxos.type1.tokens
// // console.log(`tokenUtxos: ${JSON.stringify(tokenUtxos, null, 2)}`)
//
// // Find a token UTXO that contains PSF with a quantity higher than needed
// // to generate a proof-of-burn.
// let tokenUtxo = {}
// for (let i = 0; i < tokenUtxos.length; i++) {
// const thisUtxo = tokenUtxos[i]
//
// // If token ID matches.
// if (thisUtxo.tokenId === P2WDB_TOKEN_ID) {
// if (parseFloat(thisUtxo.qtyStr) >= PROOF_OF_BURN_QTY) {
// tokenUtxo = thisUtxo
// break
// }
// }
// }
//
// if (tokenUtxo.tokenId !== P2WDB_TOKEN_ID) {
// throw new Error(
// `Token UTXO of with ID of ${P2WDB_TOKEN_ID} and quantity greater than ${PROOF_OF_BURN_QTY} could not be found in wallet.`
// )
// }
// // console.log(`tokenUtxo: ${JSON.stringify(tokenUtxo, null, 2)}`)
//
// const result = await this.bchWallet.burnTokens(
// PROOF_OF_BURN_QTY,
// P2WDB_TOKEN_ID
// )
// // console.log('walletData.burnTokens() result: ', result)
//
// return result
//
// // return {
// // success: true,
// // txid: 'fakeTxid',
// // }
// } catch (err) {
// console.error('Error in burnPsf(): ', err)
// throw err
// }
// }
// Generate a partial transcation to *take* a 'sell' order.
async generatePartialTx (orderInfo) {
// try {
// // const bchjs = this.bchWallet.bchjs
//
// return true
// } catch (err) {
// console.error('Error in wallet.js/generatePartialTx()')
// throw err
// }
return true
}
}
module.exports = WalletAdapter
@@ -61,6 +61,27 @@ class OrderRESTControllerLib {
}
}
// Currently only supports 'sell' orders, and will only buy the 'numTokens'
// listed in the order.
async takeOrder (ctx) {
try {
console.log('body: ', ctx.request.body)
const orderCid = ctx.request.body.orderCid
// Find the Order.
// const orderEntity = await _this.useCases.order.findOrder(orderId)
// 'Take' the Order.
const hash = await _this.useCases.order.takeOrder(orderCid)
ctx.body = { hash }
} catch (err) {
console.log('Error in takeOrder REST API handler.')
_this.handleError(ctx, err)
}
}
// DRY error handler
handleError (ctx, err) {
console.log('err', err.message)
+1
View File
@@ -51,6 +51,7 @@ class OrderRouter {
// Define the routes and attach the controller.
this.router.post('/', _this.orderRESTController.createOrder)
this.router.get('/list', _this.orderRESTController.listOrders)
this.router.post('/take', _this.orderRESTController.takeOrder)
// Attach the Controller routes to the Koa app.
app.use(_this.router.routes())
+1 -1
View File
@@ -90,7 +90,7 @@ class OfferLib {
const utxoInfo = {
txid,
vout: 0,
vout: 1,
hdIndex: keyPair.hdIndex
}
+106
View File
@@ -68,6 +68,112 @@ class OrderUseCases {
throw error
}
}
// Generate phase 2 of 3 - take the other side of an Order.
// Based on this example:
// https://github.com/Permissionless-Software-Foundation/bch-js-examples/blob/master/bch/applications/collaborate/sell-slp/e2e-exchange/step2-purchase-tx.js
async takeOrder (orderCid) {
try {
console.log('orderCid: ', orderCid)
// Get the Order information
const orderInfo = await this.findOrderByHash(orderCid)
console.log(`orderInfo: ${JSON.stringify(orderInfo, null, 2)}`)
// Ensure the order is in a 'posted' state and not already 'taken'
if (orderInfo.orderStatus && orderInfo.orderStatus !== 'posted') {
throw new Error('order already taken')
}
// Verify that UTXO for sale is unspent. Abort if it's been spent.
const txid = orderInfo.utxoTxid
const vout = orderInfo.utxoVout
const utxoStatus = await this.adapters.bchjs.Blockchain.getTxOut(
txid,
vout
)
console.log('utxoStatus: ', utxoStatus)
if (utxoStatus === null) {
console.log(`utxo txid: ${txid}, vout: ${vout}`)
throw new Error('UTXO does not exist. Aborting.')
}
// Ensure the app has enough funds to complete the trade.
await this.ensureFunds(orderInfo)
// Get UTXOs.
const utxos = this.adapters.wallet.bchWallet.utxos.utxoStore
console.log(`utxos: ${JSON.stringify(utxos, null, 2)}`)
// Create a partially signed transaction.
// https://github.com/Permissionless-Software-Foundation/bch-js-examples/blob/master/bch/applications/collaborate/sell-slp/e2e-exchange/step2-purchase-tx.js#L59
// const partialTxHex = await this.adapaters.wallet.generatePartialTx(orderInfo)
// return partialTxHex
return true
} catch (err) {
console.error('Error in use-cases/order/takeOrder()')
throw err
}
}
// Ensure that the wallet has enough BCH and tokens to complete the requested
// trade. Will return true if it does. Will throw an error if it doesn't.
async ensureFunds (orderEntity) {
try {
// console.log('this.adapters.wallet: ', this.adapters.wallet.bchWallet)
// console.log(`walletInfo: ${JSON.stringify(this.adapters.wallet.bchWallet.walletInfo, null, 2)}`)
// 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)
if (!canWriteToP2WDB) throw new Error('App wallet does not have funds for writing to the P2WDB.')
if (orderEntity.buyOrSell.includes('sell')) {
// Sell Offer
// Ensure the app wallet controlls enough BCH to pay for the tokens.
const satsNeeded = orderEntity.numTokens * parseInt(orderEntity.rateInSats)
const balance = await this.adapters.wallet.bchWallet.getBalance()
console.log(`wallet balance: ${balance}, sats needed: ${satsNeeded}`)
const SATS_MARGIN = 5000
if (satsNeeded + SATS_MARGIN > balance) { throw new Error('App wallet does not control enough BCH to purchase the tokens.') }
//
} else {
// Buy Offer
throw new Error('Buy orders are not supported yet.')
}
return true
} catch (err) {
console.error('Error in ensureFunds()')
throw err
}
}
async findOrderByHash (p2wdbHash) {
try {
if (typeof p2wdbHash !== 'string' || !p2wdbHash) {
throw new Error('p2wdbHash must be a string')
}
const order = await this.OrderModel.findOne({ p2wdbHash })
if (!order) {
throw new Error('order not found')
}
const orderObject = order.toObject()
// return this.orderEntity.validateFromModel(orderObject)
return orderObject
} catch (err) {
console.error('Error in findOrder(): ', err)
throw err
}
}
}
module.exports = OrderUseCases
+25
View File
@@ -0,0 +1,25 @@
/*
Part 2 of 3: Take an order
*/
const axios = require('axios')
const LOCALHOST = 'http://localhost:5700'
async function start () {
try {
const options = {
method: 'post',
url: `${LOCALHOST}/order/take`,
data: {
orderCid: 'zdpuAkp98gTuivaNzGP31jTQi3ADXrFA6uANrceQcrQkTXy2j'
}
}
const result = await axios(options)
console.log('result.data: ', result.data)
} catch (err) {
console.log(err)
}
}
start()