diff --git a/src/utxo.js b/src/utxo.js index 96d0da5..73d4e92 100644 --- a/src/utxo.js +++ b/src/utxo.js @@ -279,6 +279,38 @@ class UTXO { throw err } } + + // Returns the utxo with the biggest balance from an array of utxos. + findBiggestUtxo (utxos) { + let largestAmount = 0 + let largestIndex = 0 + + if (!Array.isArray(utxos)) { + throw new Error('utxos input to findBiggestUtxo() must be an array') + } + + for (var i = 0; i < utxos.length; i++) { + const thisUtxo = utxos[i] + + // Give Elecrumx utxos a satoshis property. + if (thisUtxo.value) { + if (!thisUtxo.satoshis) thisUtxo.satoshis = Number(thisUtxo.value) + } + + if (!thisUtxo.satoshis) { + throw new Error( + 'UTXOs require a satoshis or value property for findBiggestUtxo()' + ) + } + + if (thisUtxo.satoshis > largestAmount) { + largestAmount = thisUtxo.satoshis + largestIndex = i + } + } + + return utxos[largestIndex] + } } module.exports = UTXO diff --git a/test/integration/chains/bchn/utxo-integration.js b/test/integration/chains/bchn/utxo-integration.js index 771d67a..43e5b8a 100644 --- a/test/integration/chains/bchn/utxo-integration.js +++ b/test/integration/chains/bchn/utxo-integration.js @@ -90,6 +90,34 @@ describe('#UTXO', () => { assert.isAbove(result[0].nullUtxos.length, 1) }) }) + + describe('#findBiggestUtxo', () => { + it('should sort UTXOs from Electrumx', async () => { + const addr = 'bitcoincash:qq54fgjn3hz0357n8a6guy4demw9xfkjk5jcj0xr0z' + + const electrumxUtxos = await bchjs.Electrumx.utxo(addr) + // console.log(`Electrumx utxos: ${JSON.stringify(electrumxUtxos, null, 2)}`) + + const result = bchjs.Utxo.findBiggestUtxo(electrumxUtxos.utxos) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.property(result, 'satoshis') + assert.equal(result.satoshis, 800) + }) + + it('should sort UTXOs from Utxos.get()', async () => { + const addr = 'bitcoincash:qq54fgjn3hz0357n8a6guy4demw9xfkjk5jcj0xr0z' + + const utxos = await bchjs.Utxo.get(addr) + // console.log(`utxos: ${JSON.stringify(utxos, null, 2)}`) + + const result = bchjs.Utxo.findBiggestUtxo(utxos[0].bchUtxos) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.property(result, 'satoshis') + assert.equal(result.satoshis, 800) + }) + }) }) function sleep (ms) { diff --git a/test/unit/fixtures/utxo-mocks.js b/test/unit/fixtures/utxo-mocks.js index e261c59..72094c5 100644 --- a/test/unit/fixtures/utxo-mocks.js +++ b/test/unit/fixtures/utxo-mocks.js @@ -253,9 +253,37 @@ const mockEveryUtxoType = { ] } +const electrumxUtxos = { + success: true, + utxos: [ + { + height: 0, + tx_hash: + '192f5037bb3822afd92d6b6ab51842a5dcfbe6bff783290057342da1f27ed414', + tx_pos: 0, + value: 600 + }, + { + height: 0, + tx_hash: + 'f913646f7c180f8de020cb1387951272e8a3f764a0f88e68f7fc1145a0bf02e9', + tx_pos: 0, + value: 700 + }, + { + height: 0, + tx_hash: + '7a091716f8137e94f87e7760648cd34a17e32754ef95f7c7bda38a635c9b2b1b', + tx_pos: 0, + value: 800 + } + ] +} + module.exports = { mockUtxoData, mockHydratedUtxos, mockTwoHydratedAddrs, - mockEveryUtxoType + mockEveryUtxoType, + electrumxUtxos } diff --git a/test/unit/utxo-unit.js b/test/unit/utxo-unit.js index a331f38..3992f65 100644 --- a/test/unit/utxo-unit.js +++ b/test/unit/utxo-unit.js @@ -145,4 +145,47 @@ describe('#utxo', () => { assert.isArray(result[0].nullUtxos) }) }) + + describe('#findBiggestUtxo', () => { + it('should throw error for non-array input', async () => { + try { + await bchjs.Utxo.findBiggestUtxo({}) + + assert.equal(true, false, 'Unexpected result!') + } catch (err) { + assert.include( + err.message, + 'utxos input to findBiggestUtxo() must be an array' + ) + } + }) + + it('should throw an error if input does not have a value or satoshis property', async () => { + try { + const badUtxos = [ + { + height: 0, + tx_hash: + '192f5037bb3822afd92d6b6ab51842a5dcfbe6bff783290057342da1f27ed414', + tx_pos: 0 + } + ] + + await bchjs.Utxo.findBiggestUtxo(badUtxos) + } catch (err) { + assert.include( + err.message, + 'UTXOs require a satoshis or value property for findBiggestUtxo()' + ) + } + }) + + it('should sort UTXOs from Electrumx', async () => { + const result = bchjs.Utxo.findBiggestUtxo(mockData.electrumxUtxos.utxos) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.property(result, 'satoshis') + assert.equal(result.satoshis, 800) + }) + }) })