mirror of
https://github.com/Permissionless-Software-Foundation/bch-dex.git
synced 2026-09-22 17:12:03 -07:00
fix(moveTokens): Moved from order use-case to wallet adapter
This commit is contained in:
@@ -303,6 +303,36 @@ class WalletAdapter {
|
||||
|
||||
// return true
|
||||
}
|
||||
|
||||
// Move tokens to an address controlled by the HD wallet, to generate a
|
||||
// segregated UTXO.
|
||||
async moveTokens (inObj = {}) {
|
||||
try {
|
||||
const { tokenId, qty } = inObj
|
||||
|
||||
const keyPair = await this.getKeyPair()
|
||||
console.log('keyPair: ', keyPair)
|
||||
|
||||
const receiver = {
|
||||
address: keyPair.cashAddress,
|
||||
tokenId,
|
||||
qty
|
||||
}
|
||||
|
||||
const txid = await this.bchWallet.sendTokens(receiver, 3)
|
||||
|
||||
const utxoInfo = {
|
||||
txid,
|
||||
vout: 1,
|
||||
hdIndex: keyPair.hdIndex
|
||||
}
|
||||
|
||||
return utxoInfo
|
||||
} catch (err) {
|
||||
console.error('Error in wallet.js/moveTokens()')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = WalletAdapter
|
||||
|
||||
@@ -119,28 +119,30 @@ class OfferUseCases {
|
||||
|
||||
// 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.adapters.wallet.generatePartialTx(offerInfo)
|
||||
// return partialTxHex
|
||||
// const partialTxHex = await this.adapters.wallet.generatePartialTx(offerInfo)
|
||||
// // return partialTxHex
|
||||
//
|
||||
// // Create valid Offer object
|
||||
// const takenOfferInfo = Object.assign({}, offerInfo)
|
||||
// takenOfferInfo.patialTxHex = partialTxHex
|
||||
// delete takenOfferInfo.p2wdbHash
|
||||
// delete takenOfferInfo._id
|
||||
// takenOfferInfo.offerHash = offerInfo.p2wdbHash
|
||||
//
|
||||
// // Write offer info to the P2WDB
|
||||
// // TODO: This will trigger the webhook. Find some way of triggering the
|
||||
// // webhook on new offers, but not on counteroffers
|
||||
// const p2wdbObj = {
|
||||
// wif: this.adapters.wallet.bchWallet.walletInfo.privateKey,
|
||||
// data: takenOfferInfo,
|
||||
// appId: this.config.p2wdbAppId
|
||||
// }
|
||||
// const hash = await this.adapters.p2wdb.write(p2wdbObj)
|
||||
//
|
||||
// // Return the P2WDB CID
|
||||
// return hash
|
||||
|
||||
// Create valid Offer object
|
||||
const takenOfferInfo = Object.assign({}, offerInfo)
|
||||
takenOfferInfo.patialTxHex = partialTxHex
|
||||
delete takenOfferInfo.p2wdbHash
|
||||
delete takenOfferInfo._id
|
||||
takenOfferInfo.offerHash = offerInfo.p2wdbHash
|
||||
|
||||
// Write offer info to the P2WDB
|
||||
// TODO: This will trigger the webhook. Find some way of triggering the
|
||||
// webhook on new offers, but not on counteroffers
|
||||
const p2wdbObj = {
|
||||
wif: this.adapters.wallet.bchWallet.walletInfo.privateKey,
|
||||
data: takenOfferInfo,
|
||||
appId: this.config.p2wdbAppId
|
||||
}
|
||||
const hash = await this.adapters.p2wdb.write(p2wdbObj)
|
||||
|
||||
// Return the P2WDB CID
|
||||
return hash
|
||||
return 'fake-hash'
|
||||
} catch (err) {
|
||||
console.error('Error in use-cases/offer/takeOffer(): ', err)
|
||||
throw err
|
||||
@@ -155,6 +157,7 @@ class OfferUseCases {
|
||||
// console.log(`walletInfo: ${JSON.stringify(this.adapters.wallet.bchWallet.walletInfo, null, 2)}`)
|
||||
|
||||
await this.adapters.wallet.bchWallet.walletInfoPromise
|
||||
// console.log(`utxos: ${JSON.stringify(this.adapters.wallet.bchWallet.utxos.utxoStore, null, 2)}`)
|
||||
|
||||
// Ensure the app wallet has enough funds to write to the P2WDB.
|
||||
const wif = this.adapters.wallet.bchWallet.walletInfo.privateKey
|
||||
@@ -164,12 +167,19 @@ class OfferUseCases {
|
||||
if (offerEntity.buyOrSell.includes('sell')) {
|
||||
// Sell Offer
|
||||
|
||||
// Calculate the sats needed
|
||||
const satsNeeded = offerEntity.numTokens * parseInt(offerEntity.rateInBaseUnit)
|
||||
if (isNaN(satsNeeded)) {
|
||||
throw new Error('Could not calculate sats needed!')
|
||||
}
|
||||
|
||||
// Ensure the app wallet controlls enough BCH to pay for the tokens.
|
||||
const satsNeeded = offerEntity.numTokens * parseInt(offerEntity.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.') }
|
||||
if (satsNeeded + SATS_MARGIN > balance) {
|
||||
throw new Error('App wallet does not control enough BCH to purchase the tokens.')
|
||||
}
|
||||
|
||||
//
|
||||
} else {
|
||||
|
||||
+30
-26
@@ -37,7 +37,11 @@ class OrderLib {
|
||||
await this.ensureFunds(orderEntity)
|
||||
|
||||
// Move the tokens to holding address.
|
||||
const utxoInfo = await this.moveTokens(orderEntity)
|
||||
const moveObj = {
|
||||
tokenId: orderEntity.tokenId,
|
||||
qty: orderEntity.numTokens
|
||||
}
|
||||
const utxoInfo = await this.adapters.wallet.moveTokens(moveObj)
|
||||
console.log('utxoInfo: ', utxoInfo)
|
||||
|
||||
// Update the UTXO store for the wallet.
|
||||
@@ -76,31 +80,31 @@ class OrderLib {
|
||||
// Move the tokens indicated in the order to a temporary holding address.
|
||||
// This will generate the UTXO used in the Signal message. This function
|
||||
// moves the funds and returns the UTXO information.
|
||||
async moveTokens (orderEntity) {
|
||||
try {
|
||||
const keyPair = await this.adapters.wallet.getKeyPair()
|
||||
console.log('keyPair: ', keyPair)
|
||||
|
||||
const receiver = {
|
||||
address: keyPair.cashAddress,
|
||||
tokenId: orderEntity.tokenId,
|
||||
qty: orderEntity.numTokens
|
||||
}
|
||||
|
||||
const txid = await this.adapters.wallet.bchWallet.sendTokens(receiver, 3)
|
||||
|
||||
const utxoInfo = {
|
||||
txid,
|
||||
vout: 1,
|
||||
hdIndex: keyPair.hdIndex
|
||||
}
|
||||
|
||||
return utxoInfo
|
||||
} catch (err) {
|
||||
console.error('Error in moveTokens(): ', err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
// async moveTokens (orderEntity) {
|
||||
// try {
|
||||
// const keyPair = await this.adapters.wallet.getKeyPair()
|
||||
// console.log('keyPair: ', keyPair)
|
||||
//
|
||||
// const receiver = {
|
||||
// address: keyPair.cashAddress,
|
||||
// tokenId: orderEntity.tokenId,
|
||||
// qty: orderEntity.numTokens
|
||||
// }
|
||||
//
|
||||
// const txid = await this.adapters.wallet.bchWallet.sendTokens(receiver, 3)
|
||||
//
|
||||
// const utxoInfo = {
|
||||
// txid,
|
||||
// vout: 1,
|
||||
// hdIndex: keyPair.hdIndex
|
||||
// }
|
||||
//
|
||||
// return utxoInfo
|
||||
// } catch (err) {
|
||||
// console.error('Error in moveTokens(): ', err)
|
||||
// throw err
|
||||
// }
|
||||
// }
|
||||
|
||||
// Ensure that the wallet has enough BCH and tokens to complete the requested
|
||||
// trade.
|
||||
|
||||
@@ -38,4 +38,27 @@ describe('#wallet', () => {
|
||||
assert.equal(walletInstance.ar.interface, 'rest-api')
|
||||
})
|
||||
})
|
||||
|
||||
describe('#moveTokens', () => {
|
||||
it('should move tokens to a new address in the HD wallet', async () => {
|
||||
const walletData = await uut.openWallet()
|
||||
|
||||
// Force usage of FullStack.cash
|
||||
uut.config.useFullStackCash = true
|
||||
|
||||
await uut.instanceWallet(walletData)
|
||||
|
||||
const inObj = {
|
||||
tokenId: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2',
|
||||
qty: 1
|
||||
}
|
||||
|
||||
const result = await uut.moveTokens(inObj)
|
||||
// console.log('result: ', result)
|
||||
|
||||
assert.property(result, 'txid')
|
||||
assert.property(result, 'vout')
|
||||
assert.property(result, 'hdIndex')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -24,27 +24,6 @@ describe('#offer-use-case.js', () => {
|
||||
})
|
||||
|
||||
describe('#ensureFunds', () => {
|
||||
it('should throw error if wallet does not have enough funds', async () => {
|
||||
try {
|
||||
const offerEntity = {
|
||||
lokadId: 'SWP',
|
||||
messageType: 1,
|
||||
messageClass: 1,
|
||||
tokenId: 'token-id',
|
||||
buyOrSell: 'sell',
|
||||
rateInSats: 1000,
|
||||
minSatsToExchange: 1250,
|
||||
numTokens: 1
|
||||
}
|
||||
|
||||
await uut.ensureFunds(offerEntity)
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'App wallet does not have enough tokens to satisfy the SELL offer.')
|
||||
}
|
||||
})
|
||||
|
||||
it('should return true if wallet has enough funds', async () => {
|
||||
const offerEntity = {
|
||||
lokadId: 'SWP',
|
||||
@@ -52,8 +31,8 @@ describe('#offer-use-case.js', () => {
|
||||
messageClass: 1,
|
||||
tokenId: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2',
|
||||
buyOrSell: 'sell',
|
||||
rateInSats: 1000,
|
||||
minSatsToExchange: 1250,
|
||||
rateInBaseUnit: 1000,
|
||||
minUnitsToExchange: 1250,
|
||||
numTokens: 1
|
||||
}
|
||||
|
||||
|
||||
@@ -253,6 +253,32 @@ describe('#wallet', () => {
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#moveTokens', () => {
|
||||
it('should move tokens to a new address in the HD wallet', async () => {
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut, 'getKeyPair').resolves({
|
||||
cashAddress: 'bitcoincash:qqsj63493jk4p05zzdgqzc29k5unqtet9vv8l4x0yt',
|
||||
wif: 'L4qKTMCwjH9jHnYtNh9Vsrxj7Hg6zmoN8E2v7N47UKvNVEjw7FU8',
|
||||
hdIndex: 6
|
||||
})
|
||||
uut.bchWallet = {
|
||||
sendTokens: async () => 'fake-txid'
|
||||
}
|
||||
|
||||
const inObj = {
|
||||
tokenId: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2',
|
||||
qty: 1
|
||||
}
|
||||
|
||||
const result = await uut.moveTokens(inObj)
|
||||
// console.log('result: ', result)
|
||||
|
||||
assert.property(result, 'txid')
|
||||
assert.property(result, 'vout')
|
||||
assert.property(result, 'hdIndex')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
const deleteFile = (filepath) => {
|
||||
|
||||
@@ -126,7 +126,8 @@ const wallet = {
|
||||
getKeyPair: async () => {
|
||||
return { cashAddress: 'fakeAddr', wif: 'fakeWif', hdIndex: 1 }
|
||||
},
|
||||
bchWallet: new MockBchWallet()
|
||||
bchWallet: new MockBchWallet(),
|
||||
moveTokens: async () => {}
|
||||
}
|
||||
|
||||
const p2wdb = {
|
||||
|
||||
@@ -65,34 +65,34 @@ describe('#order-use-case', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('#moveTokens', () => {
|
||||
it('should move tokens to the holding address', async () => {
|
||||
// Mock dependencies
|
||||
// sandbox
|
||||
// .stub(uut.adapters.wallet.bchWallet, 'sendTokens')
|
||||
// .resolves('fakeTxid')
|
||||
|
||||
const orderEntity = {
|
||||
lokadId: 'SWP',
|
||||
messageType: 1,
|
||||
messageClass: 1,
|
||||
tokenId: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2',
|
||||
buyOrSell: 'sell',
|
||||
rateInSats: 1000,
|
||||
minSatsToExchange: 0,
|
||||
numTokens: 1
|
||||
}
|
||||
|
||||
const result = await uut.moveTokens(orderEntity)
|
||||
// console.log('result: ', result)
|
||||
|
||||
assert.property(result, 'txid')
|
||||
assert.property(result, 'vout')
|
||||
|
||||
assert.equal(result.txid, 'fakeTxid')
|
||||
assert.equal(result.vout, 1)
|
||||
})
|
||||
})
|
||||
// describe('#moveTokens', () => {
|
||||
// it('should move tokens to the holding address', async () => {
|
||||
// // Mock dependencies
|
||||
// // sandbox
|
||||
// // .stub(uut.adapters.wallet.bchWallet, 'sendTokens')
|
||||
// // .resolves('fakeTxid')
|
||||
//
|
||||
// const orderEntity = {
|
||||
// lokadId: 'SWP',
|
||||
// messageType: 1,
|
||||
// messageClass: 1,
|
||||
// tokenId: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2',
|
||||
// buyOrSell: 'sell',
|
||||
// rateInBaseUnit: 1000,
|
||||
// minUnitsToExchange: 0,
|
||||
// numTokens: 1
|
||||
// }
|
||||
//
|
||||
// const result = await uut.moveTokens(orderEntity)
|
||||
// // console.log('result: ', result)
|
||||
//
|
||||
// assert.property(result, 'txid')
|
||||
// assert.property(result, 'vout')
|
||||
//
|
||||
// assert.equal(result.txid, 'fakeTxid')
|
||||
// assert.equal(result.vout, 1)
|
||||
// })
|
||||
// })
|
||||
|
||||
describe('#createOrder', () => {
|
||||
it('should create an order and return the hash', async () => {
|
||||
@@ -102,8 +102,8 @@ describe('#order-use-case', () => {
|
||||
messageClass: 1,
|
||||
tokenId: 'token-id',
|
||||
buyOrSell: 'sell',
|
||||
rateInSats: 1000,
|
||||
minSatsToExchange: 1250,
|
||||
rateInBaseUnit: 1000,
|
||||
minUnitsToExchange: 1250,
|
||||
numTokens: 1
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ describe('#order-use-case', () => {
|
||||
// sandbox.stub(uut.adapters.wallet, 'burnPsf').resolves('fakeTxid')
|
||||
sandbox.stub(uut.orderEntity, 'validate').returns(entryObj)
|
||||
sandbox.stub(uut, 'ensureFunds').resolves()
|
||||
sandbox.stub(uut, 'moveTokens').resolves({ txid: 'fakeTxid', vout: 0, hdIndex: 1 })
|
||||
sandbox.stub(uut.adapters.wallet, 'moveTokens').resolves({ txid: 'fakeTxid', vout: 0, hdIndex: 1 })
|
||||
sandbox.stub(uut.adapters.wallet.bchWallet, 'getUtxos').resolves()
|
||||
// sandbox
|
||||
// .stub(uut.adapters.wallet, 'generateSignature')
|
||||
|
||||
Reference in New Issue
Block a user