mirror of
https://github.com/Permissionless-Software-Foundation/bch-js.git
synced 2026-09-22 09:02:01 -07:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7274475898 | ||
|
|
7bb347a833 | ||
|
|
fadceedd00 | ||
|
|
7f4ef60f8e | ||
|
|
81e54e0590 | ||
|
|
1d5e3da976 | ||
|
|
2cff305f46 | ||
|
|
9495381cf4 | ||
|
|
32f89346c3 | ||
|
|
e8582fd0ab |
Generated
+2128
-21048
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -17,7 +17,7 @@
|
||||
"test:integration:local:bchn": "export RESTURL=http://localhost:3000/v4/ && mocha --timeout 30000 test/integration/ && mocha --timeout 30000 test/integration/chains/bchn/",
|
||||
"test:integration:local:testnet": "RESTURL=http://localhost:4000/v4/ mocha --timeout 30000 test/integration/chains/testnet",
|
||||
"test:temp": "export RESTURL=https://bchn.fullstack.cash/v4/ && mocha --timeout 30000 -g '#UTXO' test/integration/chains/bchn/",
|
||||
"test:temp2": "mocha --timeout=30000 -g '#utxo' test/unit/",
|
||||
"test:temp2": "mocha --timeout=30000 -g '#Util' test/unit/",
|
||||
"coverage": "nyc report --reporter=text-lcov | coveralls",
|
||||
"coverage:report": "nyc --reporter=html mocha --timeout 25000 test/unit/",
|
||||
"docs": "./node_modules/.bin/apidoc -i src/ -o docs",
|
||||
|
||||
@@ -118,11 +118,11 @@ class TokenType1 {
|
||||
|
||||
// Convert the send quantity to the format expected by slp-mdm.
|
||||
const baseQty = sendQtyBig.toString()
|
||||
console.log('baseQty: ', baseQty)
|
||||
// console.log('baseQty: ', baseQty)
|
||||
|
||||
// Convert the change quantity to the format expected by slp-mdm.
|
||||
const baseChange = change.toString()
|
||||
console.log('baseChange: ', baseChange)
|
||||
// console.log('baseChange: ', baseChange)
|
||||
|
||||
// Check for potential burns
|
||||
const outputQty = new BigNumber(baseChange).plus(
|
||||
|
||||
+123
@@ -27,6 +27,129 @@ class Util {
|
||||
_this = this
|
||||
}
|
||||
|
||||
/**
|
||||
* @api util.floor8() floor8()
|
||||
* @apiName floor8
|
||||
* @apiGroup Util
|
||||
* @apiDescription Round a number down to 8 decimal places.
|
||||
*
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* (async () => {
|
||||
* try {
|
||||
* const num = 1.234567891111
|
||||
* const result = bchjs.Util.floor8(num)
|
||||
* console.log(result)
|
||||
* } catch(error) {
|
||||
* console.error(error)
|
||||
* }
|
||||
* })()
|
||||
*
|
||||
* // returns
|
||||
* 1.23456789
|
||||
*/
|
||||
// floor8 - round to 8 decimal places
|
||||
// Takes a number and returns it, rounded to the nearest 8 decimal place.
|
||||
floor8 (num) {
|
||||
const thisNum = Number(num)
|
||||
|
||||
if (isNaN(thisNum)) throw new Error('input must be a number')
|
||||
|
||||
let tempNum = thisNum * 100000000
|
||||
tempNum = Math.floor(tempNum)
|
||||
tempNum = tempNum / 100000000
|
||||
|
||||
return tempNum
|
||||
}
|
||||
|
||||
/**
|
||||
* @api util.floor2() floor2()
|
||||
* @apiName floor2
|
||||
* @apiGroup Util
|
||||
* @apiDescription Round a number down to 2 decimal places.
|
||||
*
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* (async () => {
|
||||
* try {
|
||||
* const num = 1.234567891111
|
||||
* const result = bchjs.Util.floor2(num)
|
||||
* console.log(result)
|
||||
* } catch(error) {
|
||||
* console.error(error)
|
||||
* }
|
||||
* })()
|
||||
*
|
||||
* // returns
|
||||
* 1.23
|
||||
*/
|
||||
// floor2 - round down to 2 decimal places
|
||||
// Takes a number and returns it, rounded to the nearest 2 decimal place.
|
||||
floor2 (num) {
|
||||
const thisNum = Number(num)
|
||||
|
||||
if (isNaN(thisNum)) throw new Error('input must be a number')
|
||||
|
||||
let tempNum = thisNum * 100
|
||||
tempNum = Math.floor(tempNum)
|
||||
tempNum = tempNum / 100
|
||||
|
||||
return tempNum
|
||||
}
|
||||
|
||||
/**
|
||||
* @api util.chunk20() chunk20()
|
||||
* @apiName chunk20
|
||||
* @apiGroup Util
|
||||
* @apiDescription chunk up an array into multiple arrays of 20 elements each.
|
||||
* Input: arrayToSlice - a one-dimensional array of elements.
|
||||
* Returns a two-dimensional array. An array of 20-element arrays.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* (async () => {
|
||||
* try {
|
||||
* const bigArray = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26]
|
||||
*
|
||||
* const chunked = bchjs.Util.chunk20(bigArray)
|
||||
* console.log(chunked)
|
||||
* } catch(error) {
|
||||
* console.error(error)
|
||||
* }
|
||||
* })()
|
||||
*
|
||||
* // returns
|
||||
* [
|
||||
* [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19],
|
||||
* [20,21,22,23,24,25,26]
|
||||
* ]
|
||||
*/
|
||||
// chunk20 - chunk up an array into multiple arrays of 20 elements each.
|
||||
// Input: arrayToSlice - a one-dimensional array of elements.
|
||||
// Returns a two-dimensional array. An array of 20-element arrays.
|
||||
chunk20 (arrayToSlice) {
|
||||
try {
|
||||
// Validate inputs
|
||||
if (!Array.isArray(arrayToSlice)) {
|
||||
throw new Error('input must be an array')
|
||||
}
|
||||
|
||||
let offset = 0
|
||||
const result = []
|
||||
|
||||
// Loop over the array and slice off chunks of 20 elements.
|
||||
while (offset < arrayToSlice.length) {
|
||||
const chunk = arrayToSlice.slice(offset, offset + 20)
|
||||
result.push(chunk)
|
||||
offset = offset + 20
|
||||
}
|
||||
|
||||
return result
|
||||
} catch (err) {
|
||||
console.error('Error in chunk20()')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api util.validateAddress() validateAddress()
|
||||
* @apiName Validate Address.
|
||||
|
||||
+64
@@ -279,6 +279,70 @@ class UTXO {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Utxo.findBiggestUtxo() findBiggestUtxo()
|
||||
* @apiName findBiggestUtxo
|
||||
* @apiGroup UTXO
|
||||
* @apiDescription Get the biggest UTXO in an array.
|
||||
*
|
||||
* Given an array of BCH UTXOs, this method will return the biggest UTXO.
|
||||
* This is often the simplest way to pick a UTXO for generating a transaction.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* (async () => {
|
||||
* try {
|
||||
* const utxos = await bchjs.Utxo.get('bitcoincash:qq54fgjn3hz0357n8a6guy4demw9xfkjk5jcj0xr0z');
|
||||
* const utxo = bchjs.Utxo.findBiggestUtxo(utxos[0].bchUtxos)
|
||||
* console.log(utxo);
|
||||
* } catch(error) {
|
||||
* console.error(error)
|
||||
* }
|
||||
* })()
|
||||
*
|
||||
* // returns
|
||||
* {
|
||||
* "height": 655431,
|
||||
* "tx_hash": "7a091716f8137e94f87e7760648cd34a17e32754ef95f7c7bda38a635c9b2b1b",
|
||||
* "tx_pos": 0,
|
||||
* "value": 800,
|
||||
* "txid": "7a091716f8137e94f87e7760648cd34a17e32754ef95f7c7bda38a635c9b2b1b",
|
||||
* "vout": 0,
|
||||
* "isValid": false,
|
||||
* "satoshis": 800
|
||||
* }
|
||||
*/
|
||||
// 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 (let 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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const assert = require('assert')
|
||||
const assert2 = require('chai').assert
|
||||
const axios = require('axios')
|
||||
const BCHJS = require('../../src/bch-js')
|
||||
const bchjs = new BCHJS()
|
||||
@@ -32,4 +33,143 @@ describe('#Util', () => {
|
||||
.then(done, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#floor8', () => {
|
||||
it('should floor a number to 8 decimals', () => {
|
||||
const num = 1.234567891111
|
||||
|
||||
const result = bchjs.Util.floor8(num)
|
||||
// console.log(result)
|
||||
|
||||
assert2.equal(result, 1.23456789)
|
||||
})
|
||||
|
||||
it('should throw an error for non-number input', () => {
|
||||
try {
|
||||
const num = 'string'
|
||||
|
||||
bchjs.Util.floor8(num)
|
||||
|
||||
assert2.equal(true, false, 'Unexpected result')
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
assert2.include(err.message, 'input must be a number')
|
||||
}
|
||||
})
|
||||
|
||||
it('should not effect a number with less than 8 decimals', () => {
|
||||
const num = 1.23
|
||||
|
||||
const result = bchjs.Util.floor8(num)
|
||||
// console.log(result)
|
||||
|
||||
assert2.equal(result, 1.23)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#floor2', () => {
|
||||
it('should round a number to 2 decimals', () => {
|
||||
const num = 1.234567891111
|
||||
|
||||
const result = bchjs.Util.floor2(num)
|
||||
// console.log(result)
|
||||
|
||||
assert2.equal(result, 1.23)
|
||||
})
|
||||
|
||||
it('should throw an error for non-number input', () => {
|
||||
try {
|
||||
const num = 'string'
|
||||
|
||||
bchjs.Util.floor2(num)
|
||||
|
||||
assert2.equal(true, false, 'Unexpected result')
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
assert2.include(err.message, 'input must be a number')
|
||||
}
|
||||
})
|
||||
|
||||
it('should not effect a number with less than 8 decimals', () => {
|
||||
const num = 1.2
|
||||
|
||||
const result = bchjs.Util.floor2(num)
|
||||
// console.log(result)
|
||||
|
||||
assert2.equal(result, 1.2)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#chunk20', () => {
|
||||
const thirtyFiveElements = [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25,
|
||||
26,
|
||||
27,
|
||||
28,
|
||||
29,
|
||||
30,
|
||||
31,
|
||||
32,
|
||||
33,
|
||||
34
|
||||
]
|
||||
|
||||
it('should split 35 elements into 2 arrays', () => {
|
||||
const result = bchjs.Util.chunk20(thirtyFiveElements)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert2.isArray(result)
|
||||
assert2.isArray(result[0])
|
||||
assert2.equal(result.length, 2)
|
||||
assert2.equal(result[0].length, 20)
|
||||
})
|
||||
|
||||
it('should return accurately with an array of less than 20 elements', () => {
|
||||
const elems = [0, 1, 2, 3, 4, 5]
|
||||
|
||||
const result = bchjs.Util.chunk20(elems)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert2.isArray(result)
|
||||
assert2.isArray(result[0])
|
||||
assert2.equal(result.length, 1)
|
||||
assert2.equal(result[0].length, 6)
|
||||
})
|
||||
|
||||
it('should throw an error for non-array input', () => {
|
||||
try {
|
||||
bchjs.Util.chunk20('string')
|
||||
|
||||
assert2.equal(true, false, 'Unexpected result')
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
assert2.include(err.message, 'input must be an array')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user