UNPKG

minimal-slp-wallet

Version:
909 lines (733 loc) 31 kB
/* Unit tests for the token library. */ const assert = require('chai').assert const sinon = require('sinon') const BCHJS = require('@psf/bch-js') const Tokens = require('../../lib/tokens') const Utxos = require('../../lib/utxos') const AdapterRouter = require('../../lib/adapters/router') let uut const mockDataLib = require('./mocks/utxo-mocks') let mockData const sendMockDataLib = require('./mocks/send-bch-mocks') let sendMockData describe('#tokens', () => { let sandbox let utxos beforeEach(() => { const config = { restURL: 'https://api.fullstack.cash/v5/' } const bchjs = new BCHJS(config) config.bchjs = bchjs config.ar = new AdapterRouter(config) uut = new Tokens(config) utxos = new Utxos(config) sandbox = sinon.createSandbox() mockData = Object.assign({}, mockDataLib) sendMockData = Object.assign({}, sendMockDataLib) }) afterEach(() => sandbox.restore()) describe('#constructor', () => { it('should throw an error if instance of bch-js is not passed', () => { try { uut = new Tokens() assert.fail('Unexpected code path') } catch (err) { assert.include( err.message, 'Must pass instance of bch-js when instantiating Tokens library.' ) } }) it('should throw an error if instance of bch-js is not passed', () => { try { uut = new Tokens({ bchjs: {} }) assert.fail('Unexpected code path') } catch (err) { assert.include(err.message, 'Must pass instance of Adapter Router.') } }) }) describe('#listTokensFromUtxos', () => { it('should return a list of tokens', () => { const tokenInfo = uut.listTokensFromUtxos(mockData.hydratedUtxos) // console.log(`tokenInfo: ${JSON.stringify(tokenInfo, null, 2)}`) // Assert that the returned array is the expected size. assert.isArray(tokenInfo) assert.equal(tokenInfo.length, 1) // Assert the objects in the array have the expected properties. assert.property(tokenInfo[0], 'tokenId') assert.property(tokenInfo[0], 'ticker') assert.property(tokenInfo[0], 'name') assert.property(tokenInfo[0], 'decimals') assert.property(tokenInfo[0], 'tokenType') assert.property(tokenInfo[0], 'url') assert.property(tokenInfo[0], 'qty') // Assert that the quantities are as expected. assert.equal(tokenInfo[0].qty, 1) }) it('should return for non-SLP UTXOs', () => { const tokenInfo = uut.listTokensFromUtxos([{ isSlp: false }]) // console.log(`tokenInfo: ${JSON.stringify(tokenInfo, null, 2)}`) assert.equal(tokenInfo.length, 0) }) it('should combine UTXOs with the same token', () => { const utxos = [mockData.hydratedUtxos[0], mockData.hydratedUtxos[0]] const tokenInfo = uut.listTokensFromUtxos(utxos) // console.log(`tokenInfo: ${JSON.stringify(tokenInfo, null, 2)}`) assert.equal(tokenInfo[0].qty, 2) }) it('should return aggregate token data', () => { const tokenInfo = uut.listTokensFromUtxos(mockData.tokenUtxos02) // console.log(`tokenInfo: ${JSON.stringify(tokenInfo, null, 2)}`) // Assert that the returned array is the expected size. assert.isArray(tokenInfo) assert.equal(tokenInfo.length, 1) // Assert that the quantities are as expected. assert.equal(tokenInfo[0].qty, 1) }) it('should handle and throw errors', async () => { try { uut.listTokensFromUtxos('a') assert(true, false, 'unexpected result') } catch (err) { // console.log('err: ', err) assert.include(err.message, 'utxos.forEach is not a function') } }) }) describe('#createTransaction', () => { it('should throw an error if there are no BCH UTXOs.', async () => { try { await uut.createTransaction({}, {}, [], []) assert.equal(true, false, 'unexpecte result') } catch (err) { assert.include(err.message, 'BCH UTXO list is empty') } }) it('should throw an error if there are no token UTXOs.', async () => { try { await uut.createTransaction({}, {}, ['placeholder'], []) assert.equal(true, false, 'unexpecte result') } catch (err) { assert.include(err.message, 'Token UTXO list is empty') } }) it('should send token with no token change and no UTXO change', async () => { const output = { address: 'simpleledger:qqwsylce7r5ufe4mfc94xkd56t30ncnanqahwq6kvv', tokenId: '497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7', qty: 1 } const walletInfo = sendMockData.mockWallet // Prep the utxo data. utxos.utxoStore = mockData.tokenUtxos01 const bchUtxos = utxos.utxoStore.bchUtxos const tokenUtxos = utxos.getSpendableTokenUtxos() // console.log('tokenUtxos: ', tokenUtxos) // Modify the BCH UTXO for this test. // bchUtxos[0].value = bchUtxos[0].satoshis = 100000 const { hex, txid } = await uut.createTransaction( output, walletInfo, bchUtxos, tokenUtxos ) assert.isString(hex) assert.isString(txid) }) it('should send token with token change and no UTXO change', async () => { const output = { address: 'simpleledger:qqwsylce7r5ufe4mfc94xkd56t30ncnanqahwq6kvv', tokenId: '497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7', qty: 0.5 } const walletInfo = sendMockData.mockWallet // Prep the utxo data. utxos.utxoStore = mockData.tokenUtxos01 const bchUtxos = utxos.utxoStore.bchUtxos let tokenUtxos = utxos.getSpendableTokenUtxos() // modify tokenUtxo for this test. tokenUtxos = tokenUtxos.find(elem => elem.tokenId === output.tokenId) // console.log(`tokenUtxos: ${JSON.stringify(tokenUtxos, null, 2)}`) tokenUtxos.tokenQty = '2' const { hex, txid } = await uut.createTransaction( output, walletInfo, bchUtxos, [tokenUtxos] ) assert.isString(hex) assert.isString(txid) }) it('should send token with no token change and UTXO change', async () => { const output = { address: 'simpleledger:qqwsylce7r5ufe4mfc94xkd56t30ncnanqahwq6kvv', tokenId: '497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7', qty: 1 } const walletInfo = sendMockData.mockWallet // Prep the utxo data. // utxos.utxoStore = mockData.hydratedUtxos // const bchUtxos = utxos.getBchUtxos() // const tokenUtxos = utxos.getTokenUtxos() utxos.utxoStore = mockData.tokenUtxos01 const bchUtxos = utxos.utxoStore.bchUtxos const tokenUtxos = utxos.getSpendableTokenUtxos() // Modify the BCH UTXO for this test. bchUtxos[0].value = bchUtxos[0].satoshis = 100000 const { hex, txid } = await uut.createTransaction( output, walletInfo, bchUtxos, tokenUtxos ) assert.isString(hex) assert.isString(txid) }) it('should send NFT Group token', async () => { const output = { address: 'simpleledger:qqwsylce7r5ufe4mfc94xkd56t30ncnanqahwq6kvv', tokenId: '8cd26481aaed66198e22e05450839fda763daadbb9938b0c71521ef43c642299', qty: 1 } const walletInfo = sendMockData.mockWallet // Prep the utxo data. // utxos.utxoStore = mockData.mockNFTGroupUtxos // const bchUtxos = utxos.getBchUtxos() // const tokenUtxos = utxos.getTokenUtxos() utxos.utxoStore = mockData.mockNFTGroupUtxos const bchUtxos = utxos.utxoStore.bchUtxos const tokenUtxos = utxos.getSpendableTokenUtxos() // Modify the BCH UTXO for this test. bchUtxos[0].value = bchUtxos[0].satoshis = 100000 const { hex, txid } = await uut.createTransaction( output, walletInfo, bchUtxos, tokenUtxos ) assert.isString(hex) assert.isString(txid) }) it('should send NFT (Child) token', async () => { const output = { address: 'simpleledger:qqwsylce7r5ufe4mfc94xkd56t30ncnanqahwq6kvv', tokenId: '82e3d97b3cd033e60ffa755450b9075cf44fe1b2f6d5dc13657d8263e716b6a5', qty: 1 } const walletInfo = sendMockData.mockWallet // Prep the utxo data. // utxos.utxoStore = mockData.mockNFTChildUtxos // const bchUtxos = utxos.getBchUtxos() // const tokenUtxos = utxos.getTokenUtxos() utxos.utxoStore = mockData.mockNFTChildUtxos const bchUtxos = utxos.utxoStore.bchUtxos const tokenUtxos = utxos.getSpendableTokenUtxos() // Modify the BCH UTXO for this test. bchUtxos[0].value = bchUtxos[0].satoshis = 100000 const { hex, txid } = await uut.createTransaction( output, walletInfo, bchUtxos, tokenUtxos ) assert.isString(hex) assert.isString(txid) }) it('should throw an error for unknown token type', async () => { try { const output = { address: 'simpleledger:qqwsylce7r5ufe4mfc94xkd56t30ncnanqahwq6kvv', tokenId: '82e3d97b3cd033e60ffa755450b9075cf44fe1b2f6d5dc13657d8263e716b6a5', qty: 1 } const walletInfo = sendMockData.mockWallet // Prep the utxo data. utxos.utxoStore = mockData.mockNFTChildUtxos const bchUtxos = utxos.utxoStore.bchUtxos const tokenUtxos = utxos.getSpendableTokenUtxos() // console.log(`tokenUtxos: ${JSON.stringify(tokenUtxos, null, 2)}`) // Manipulate the token type to force an error. tokenUtxos[0].tokenType = 888 await uut.createTransaction(output, walletInfo, bchUtxos, tokenUtxos) assert.fail('Unexpected result') } catch (err) { // console.log('err: ', err) assert.include(err.message, 'Token Type 888 unknown') } }) it('should throw an error if expected token UTXOs are not in the wallet', async () => { try { const output = { address: 'simpleledger:qqwsylce7r5ufe4mfc94xkd56t30ncnanqahwq6kvv', tokenId: '82e3d97b3cd033e60ffa755450b9075cf44fe1b2f6d5dc13657d8263e7165555', qty: 1 } const walletInfo = sendMockData.mockWallet // Prep the utxo data. utxos.utxoStore = mockData.mockNFTChildUtxos const bchUtxos = utxos.utxoStore.bchUtxos const tokenUtxos = utxos.getSpendableTokenUtxos() await uut.createTransaction(output, walletInfo, bchUtxos, tokenUtxos) assert.fail('Unexpected result') } catch (err) { assert.include(err.message, 'Token UTXO with token ID') } }) it('should use custom token utxo filtering function', async () => { const output = { address: 'simpleledger:qqwsylce7r5ufe4mfc94xkd56t30ncnanqahwq6kvv', tokenId: '497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7', qty: 1 } const walletInfo = sendMockData.mockWallet // Prep the utxo data. utxos.utxoStore = mockData.tokenUtxos01 const bchUtxos = utxos.utxoStore.bchUtxos const tokenUtxos = utxos.getSpendableTokenUtxos() const utxosFilterStub = sinon.stub().returnsArg(0) await uut.createTransaction( output, walletInfo, bchUtxos, tokenUtxos, 1.0, { tokenUtxosFilter: utxosFilterStub } ) assert.ok(utxosFilterStub.calledOnce) }) it('should pass opts to sendBch.getNecessaryUtxosAndChange', async () => { const output = { address: 'simpleledger:qqwsylce7r5ufe4mfc94xkd56t30ncnanqahwq6kvv', tokenId: '497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7', qty: 1 } const walletInfo = sendMockData.mockWallet // Prep the utxo data. utxos.utxoStore = mockData.tokenUtxos01 const bchUtxos = utxos.utxoStore.bchUtxos const tokenUtxos = utxos.getSpendableTokenUtxos() const fn = sandbox.stub(uut.sendBch, 'getNecessaryUtxosAndChange').returns({ necessaryUtxos: mockData.simpleUtxos.utxos, change: 0 }) await uut.createTransaction( output, walletInfo, bchUtxos, tokenUtxos, 1.0, { config: 'ok' } ) assert.ok(fn.calledOnceWith( sinon.match.any, sinon.match.any, sinon.match.any, { config: 'ok' } )) }) }) describe('#sendTokens', () => { it('should broadcast a transaction and return a txid', async () => { const hex = '0200000002abdb671501c19d11c35473aa84547f7f3b301d6924d6c8f419a26616dc486ea3010000006b4830450221009833f7bbecd7ba4c193f1edd693e42b337cd295b7e530cab3b2210f46c6cebe102200b65bf9b9bc66992c09cb1a40a2c84b629ba48c066b9f3cc5fe713a898051b6d41210259da20750fbde4e48d48068aa93e02701554dc66b4fe83851a91023110093449ffffffffcc198a396570aebd10605cdde223356c0d8f92133560c52013ae5d43dccccf53010000006a47304402207bd190fce11a0cbf8dd8d0d987bcdd428168312f217ec61d018c3198014a786a02200b0ac3db775ea708eb9a76a9fa84fe9a68a0553408b143f52c220313cc2ecbd241210259da20750fbde4e48d48068aa93e02701554dc66b4fe83851a91023110093449ffffffff0271020000000000001976a914543dc8f7c91721da06da8c3941f79e26cfbce67288ac6c030000000000001976a9141d027f19f0e9c4e6bb4e0b5359b4d2e2f9e27d9888ac00000000' const txid = '66b7d1fced6df27feb7faf305de2e3d6470decb0276648411fd6a2f69fec8543' // Mock live network calls. sandbox.stub(uut, 'createTransaction').resolves(hex) sandbox.stub(uut.ar, 'sendTx').resolves(txid) const output = await uut.sendTokens() assert.equal(output, txid) }) it('should throw an error if there is an issue with broadcasting a tx', async () => { try { const hex = '0200000002abdb671501c19d11c35473aa84547f7f3b301d6924d6c8f419a26616dc486ea3010000006b4830450221009833f7bbecd7ba4c193f1edd693e42b337cd295b7e530cab3b2210f46c6cebe102200b65bf9b9bc66992c09cb1a40a2c84b629ba48c066b9f3cc5fe713a898051b6d41210259da20750fbde4e48d48068aa93e02701554dc66b4fe83851a91023110093449ffffffffcc198a396570aebd10605cdde223356c0d8f92133560c52013ae5d43dccccf53010000006a47304402207bd190fce11a0cbf8dd8d0d987bcdd428168312f217ec61d018c3198014a786a02200b0ac3db775ea708eb9a76a9fa84fe9a68a0553408b143f52c220313cc2ecbd241210259da20750fbde4e48d48068aa93e02701554dc66b4fe83851a91023110093449ffffffff0271020000000000001976a914543dc8f7c91721da06da8c3941f79e26cfbce67288ac6c030000000000001976a9141d027f19f0e9c4e6bb4e0b5359b4d2e2f9e27d9888ac00000000' // Mock live network calls. sandbox.stub(uut, 'createTransaction').resolves(hex) sandbox.stub(uut.ar, 'sendTx').throws(new Error('error message')) await uut.sendTokens() assert.equal(true, false, 'unexpected result') } catch (err) { // console.log('err: ', err) assert.include(err.message, 'error message') } }) it('should pass options to createTransaction', async () => { // Mock live network calls. const ct = sandbox.stub(uut, 'createTransaction').resolves('ok') sandbox.stub(uut.ar, 'sendTx').resolves('ok') await uut.sendTokens(null, null, null, null, null, { utxoSortingFn: 'sortingFn' }) assert.ok(ct.calledOnceWith( sinon.match.any, sinon.match.any, sinon.match.any, sinon.match.any, sinon.match.any, { utxoSortingFn: 'sortingFn' } )) }) }) describe('#listTokensFromAddress', () => { it('should get token information for an address', async () => { const addr = 'simpleledger:qqmjqwsplscmx0aet355p4l0j8q74thv7vf5epph4z' // Stub network calls and subfunctions that are not within the scope of testing. sandbox.stub(uut.utxos, 'initUtxoStore').resolves({}) uut.utxos.utxoStore = mockData.tokenUtxos03 // console.log(`uut.utxos.utxoStore: ${JSON.stringify(uut.utxos.utxoStore, null, 2)}`) const tokenInfo = await uut.listTokensFromAddress(addr) // console.log(`tokenInfo: ${JSON.stringify(tokenInfo, null, 2)}`) assert.isArray(tokenInfo) assert.property(tokenInfo[0], 'tokenId') assert.property(tokenInfo[0], 'ticker') assert.property(tokenInfo[0], 'name') assert.property(tokenInfo[0], 'decimals') assert.property(tokenInfo[0], 'tokenType') assert.property(tokenInfo[0], 'url') assert.property(tokenInfo[0], 'qty') }) it('should throw an error if address is not specified', async () => { try { await uut.listTokensFromAddress() assert.equal(true, false, 'Unexpected result') } catch (err) { // console.log('err: ', err) assert.include(err.message, 'Address not provided') } }) }) describe('#getTokenBalance', () => { it('should get token information for an address', async () => { // Mock dependencies and force desired code path. sandbox.stub(uut, 'listTokensFromAddress').resolves([ { tokenId: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2', ticker: 'TROUT', name: "Trout's test token", decimals: 2, tokenType: 1, url: 'troutsblog.com', qty: 1 } ]) const addr = 'simpleledger:qqmjqwsplscmx0aet355p4l0j8q74thv7vf5epph4z' const tokenId = 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2' const tokenBalance = await uut.getTokenBalance(tokenId, addr) // console.log(`tokenBalance: ${JSON.stringify(tokenBalance, null, 2)}`) assert.equal(tokenBalance, 1) }) it('should throw an error if token ID is not specified', async () => { try { await uut.getTokenBalance() assert.equal(true, false, 'Unexpected result') } catch (err) { // console.log('err: ', err) assert.include(err.message, 'token ID not provided') } }) it('should throw an error if address is not specified', async () => { try { await uut.getTokenBalance('fake-token-id') assert.equal(true, false, 'Unexpected result') } catch (err) { // console.log('err: ', err) assert.include(err.message, 'Address not provided') } }) it('should return zero if address has not tokens', async () => { // Mock dependencies and force desired code path. sandbox.stub(uut, 'listTokensFromAddress').resolves([]) const addr = 'simpleledger:qqmjqwsplscmx0aet355p4l0j8q74thv7vf5epph4z' const tokenId = 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2' const tokenBalance = await uut.getTokenBalance(tokenId, addr) // console.log(`tokenBalance: ${JSON.stringify(tokenBalance, null, 2)}`) assert.equal(tokenBalance, 0) }) }) describe('#createBurnTransaction', () => { it('should throw an error if qty input is not provided.', async () => { try { await uut.createBurnTransaction() assert.equal(true, false, 'unexpecte result') } catch (err) { assert.include(err.message, 'qty must be number') } }) it('should throw an error if tokenId input is not provided.', async () => { try { const tokenId = '' await uut.createBurnTransaction(1, tokenId) assert.equal(true, false, 'unexpecte result') } catch (err) { assert.include(err.message, 'tokenId must be string') } }) it('should throw an error if walletInfo is not provided.', async () => { try { const tokenId = 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2' const walletInfo = '' await uut.createBurnTransaction(1, tokenId, walletInfo) assert.equal(true, false, 'unexpecte result') } catch (err) { assert.include(err.message, 'walletInfo must be a object') } }) it('should throw an error if there are no BCH UTXOs.', async () => { try { const tokenId = 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2' const walletInfo = sendMockData.mockWallet const bchUtxos = [] await uut.createBurnTransaction(1, tokenId, walletInfo, bchUtxos) assert.equal(true, false, 'unexpecte result') } catch (err) { assert.include(err.message, 'BCH UTXO list is empty') } }) it('should throw an error if there are no token UTXOs.', async () => { try { const tokenId = 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2' const walletInfo = sendMockData.mockWallet // Prep the utxo data. utxos.utxoStore = mockData.tokenUtxos01 const bchUtxos = utxos.utxoStore.bchUtxos await uut.createBurnTransaction(1, tokenId, walletInfo, bchUtxos) assert.equal(true, false, 'unexpecte result') } catch (err) { assert.include(err.message, 'Token UTXO list is empty') } }) it('should throw an error if tokenId does not match', async () => { try { const tokenId = 'bad token id' const walletInfo = sendMockData.mockWallet // Prep the utxo data. utxos.utxoStore = mockData.mockNFTGroupUtxos const bchUtxos = utxos.utxoStore.bchUtxos const tokenUtxos = utxos.getSpendableTokenUtxos() await uut.createBurnTransaction( 1, tokenId, walletInfo, bchUtxos, tokenUtxos ) assert.equal(true, false, 'unexpected result') } catch (err) { assert.include(err.message, 'tokenId does not match') } }) it('should throw an error if wallet contains fewer tokens than are requested to burn', async () => { try { const tokenId = 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2' const walletInfo = sendMockData.mockWallet // Prep the utxo data. utxos.utxoStore = mockData.tokenUtxos01 const bchUtxos = utxos.utxoStore.bchUtxos const tokenUtxos = utxos.getSpendableTokenUtxos() await uut.createBurnTransaction( 100.5, tokenId, walletInfo, bchUtxos, tokenUtxos ) assert.equal(true, false, 'unexpected result') } catch (err) { assert.include(err.message, 'which is less than quantity to burn') } }) /* it('should throw an error for non token type1.', async () => { try { const tokenId = '8cd26481aaed66198e22e05450839fda763daadbb9938b0c71521ef43c642299' const walletInfo = sendMockData.mockWallet // Prep the utxo data. utxos.utxoStore = mockData.mockNFTGroupUtxos const bchUtxos = utxos.utxoStore.bchUtxos const tokenUtxos = utxos.getSpendableTokenUtxos() await uut.createBurnTransaction( 1, tokenId, walletInfo, bchUtxos, tokenUtxos ) assert.equal(true, false, 'unexpecte result') } catch (err) { assert.include(err.message, 'Token must be type 1') } }) */ it('should generate burn transaction', async () => { const tokenId = 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2' const walletInfo = sendMockData.mockWallet // Prep the utxo data. utxos.utxoStore = mockData.tokenUtxos01 const bchUtxos = utxos.utxoStore.bchUtxos const tokenUtxos = utxos.getSpendableTokenUtxos() // console.log('tokenUtxos: ', tokenUtxos) const { hex, txid } = await uut.createBurnTransaction( 1, tokenId, walletInfo, bchUtxos, tokenUtxos ) assert.isString(hex) assert.isString(txid) }) }) describe('#burnTokens', () => { it('should broadcast a transaction and return a txid', async () => { const hex = '0200000002abdb671501c19d11c35473aa84547f7f3b301d6924d6c8f419a26616dc486ea3010000006b4830450221009833f7bbecd7ba4c193f1edd693e42b337cd295b7e530cab3b2210f46c6cebe102200b65bf9b9bc66992c09cb1a40a2c84b629ba48c066b9f3cc5fe713a898051b6d41210259da20750fbde4e48d48068aa93e02701554dc66b4fe83851a91023110093449ffffffffcc198a396570aebd10605cdde223356c0d8f92133560c52013ae5d43dccccf53010000006a47304402207bd190fce11a0cbf8dd8d0d987bcdd428168312f217ec61d018c3198014a786a02200b0ac3db775ea708eb9a76a9fa84fe9a68a0553408b143f52c220313cc2ecbd241210259da20750fbde4e48d48068aa93e02701554dc66b4fe83851a91023110093449ffffffff0271020000000000001976a914543dc8f7c91721da06da8c3941f79e26cfbce67288ac6c030000000000001976a9141d027f19f0e9c4e6bb4e0b5359b4d2e2f9e27d9888ac00000000' const txid = '66b7d1fced6df27feb7faf305de2e3d6470decb0276648411fd6a2f69fec8543' // Mock live network calls. sandbox.stub(uut, 'createBurnTransaction').resolves(hex) sandbox.stub(uut.ar, 'sendTx').resolves(txid) const output = await uut.burnTokens() assert.equal(output, txid) }) it('should throw an error if there is an issue with broadcasting a tx', async () => { try { const hex = '0200000002abdb671501c19d11c35473aa84547f7f3b301d6924d6c8f419a26616dc486ea3010000006b4830450221009833f7bbecd7ba4c193f1edd693e42b337cd295b7e530cab3b2210f46c6cebe102200b65bf9b9bc66992c09cb1a40a2c84b629ba48c066b9f3cc5fe713a898051b6d41210259da20750fbde4e48d48068aa93e02701554dc66b4fe83851a91023110093449ffffffffcc198a396570aebd10605cdde223356c0d8f92133560c52013ae5d43dccccf53010000006a47304402207bd190fce11a0cbf8dd8d0d987bcdd428168312f217ec61d018c3198014a786a02200b0ac3db775ea708eb9a76a9fa84fe9a68a0553408b143f52c220313cc2ecbd241210259da20750fbde4e48d48068aa93e02701554dc66b4fe83851a91023110093449ffffffff0271020000000000001976a914543dc8f7c91721da06da8c3941f79e26cfbce67288ac6c030000000000001976a9141d027f19f0e9c4e6bb4e0b5359b4d2e2f9e27d9888ac00000000' // Mock live network calls. sandbox.stub(uut, 'createBurnTransaction').resolves(hex) sandbox.stub(uut.ar, 'sendTx').throws(new Error('error message')) await uut.burnTokens() assert.equal(true, false, 'unexpected result') } catch (err) { // console.log('err: ', err) assert.include(err.message, 'error message') } }) }) describe('#burnAll', () => { it('should throw an error if tokenId is not provided', async () => { try { await uut.burnAll() assert.equal(true, false, 'unexpected result') } catch (err) { // console.log('err: ', err) assert.include(err.message, 'tokenId must be a string') } }) it('should throw an error if walletInfo is not provided', async () => { try { const slpUtxos = mockData.mockTokenUtxos const tokenId = slpUtxos[0].tokenId await uut.burnAll(tokenId) assert.equal(true, false, 'unexpected result') } catch (err) { // console.log('err: ', err) assert.include(err.message, 'walletInfo is required') } }) it('should throw an error if bchUtxos is not provided', async () => { try { const slpUtxos = mockData.mockTokenUtxos const tokenId = slpUtxos[0].tokenId const walletInfo = sendMockData.mockWallet await uut.burnAll(tokenId, walletInfo) assert.equal(true, false, 'unexpected result') } catch (err) { // console.log('err: ', err) assert.include(err.message, 'BCH UTXO list is empty') } }) it('should throw an error if bchUtxos list is empty', async () => { try { const slpUtxos = mockData.mockTokenUtxos const tokenId = slpUtxos[0].tokenId const walletInfo = sendMockData.mockWallet await uut.burnAll(tokenId, walletInfo, []) assert.equal(true, false, 'unexpected result') } catch (err) { // console.log('err: ', err) assert.include(err.message, 'BCH UTXO list is empty') } }) it('should throw an error if slpUtxos is not provided', async () => { try { const slpUtxos = mockData.mockTokenUtxos const tokenId = slpUtxos[0].tokenId const walletInfo = sendMockData.mockWallet const bchUtxos = mockData.mockBchUtxos await uut.burnAll(tokenId, walletInfo, bchUtxos) assert.equal(true, false, 'unexpected result') } catch (err) { // console.log('err: ', err) assert.include(err.message, 'SLP UTXO list is empty') } }) it('should throw an error if slpUtxos list is empty', async () => { try { const slpUtxos = mockData.mockTokenUtxos const tokenId = slpUtxos[0].tokenId const walletInfo = sendMockData.mockWallet const bchUtxos = mockData.mockBchUtxos await uut.burnAll(tokenId, walletInfo, bchUtxos, []) assert.equal(true, false, 'unexpected result') } catch (err) { // console.log('err: ', err) assert.include(err.message, 'SLP UTXO list is empty') } }) it('should broadcast a transaction and return a txid', async () => { sandbox.stub(uut.sendBch, 'sendAllBch').resolves('fakeTxid') const walletInfo = sendMockData.mockWallet const bchUtxos = mockData.mockBchUtxos const slpUtxos = mockData.mockTokenUtxos const tokenId = slpUtxos[0].tokenId const output = await uut.burnAll(tokenId, walletInfo, bchUtxos, slpUtxos) assert.equal(output, 'fakeTxid') }) it('should throw an error if there is an issue with broadcasting a tx', async () => { try { // Force an error sandbox.stub(uut.sendBch, 'sendAllBch').rejects(new Error('fake error')) const walletInfo = sendMockData.mockWallet const bchUtxos = mockData.mockBchUtxos const slpUtxos = mockData.mockTokenUtxos const tokenId = slpUtxos[0].tokenId await uut.burnAll(tokenId, walletInfo, bchUtxos, slpUtxos) assert.fail('Unexpected code path') } catch (err) { // console.log('err: ', err) assert.include(err.message, 'fake error') } }) it('should throw an error if no token UTXOs with token ID found', async () => { try { // sandbox.stub(uut.sendBch, 'sendAllBch').resolves('fakeTxid') const walletInfo = sendMockData.mockWallet const bchUtxos = mockData.mockBchUtxos const slpUtxos = mockData.mockTokenUtxos const tokenId = 'abc123' await uut.burnAll(tokenId, walletInfo, bchUtxos, slpUtxos) assert.fail('Unexpected result') } catch (err) { assert.include(err.message, 'No token UTXOs found to burn after filtering') } }) }) })