2020-07-27 21:32:51 -07:00
|
|
|
const chai = require("chai")
|
|
|
|
|
const assert = chai.assert
|
|
|
|
|
const axios = require("axios")
|
|
|
|
|
const sinon = require("sinon")
|
|
|
|
|
|
|
|
|
|
const BCHJS = require("../../src/bch-js")
|
|
|
|
|
const bchjs = new BCHJS()
|
|
|
|
|
|
|
|
|
|
const mockData = require("./fixtures/electrumx-mock")
|
|
|
|
|
|
|
|
|
|
describe(`#ElectrumX`, () => {
|
|
|
|
|
let sandbox
|
|
|
|
|
beforeEach(() => (sandbox = sinon.createSandbox()))
|
|
|
|
|
afterEach(() => sandbox.restore())
|
|
|
|
|
|
|
|
|
|
describe(`#utxo`, () => {
|
|
|
|
|
it(`should throw an error for improper input`, async () => {
|
|
|
|
|
try {
|
|
|
|
|
const addr = 12345
|
|
|
|
|
|
|
|
|
|
await bchjs.Electrumx.utxo(addr)
|
|
|
|
|
assert.equal(true, false, "Unexpected result!")
|
|
|
|
|
} catch (err) {
|
|
|
|
|
// console.log(`err: `, err)
|
|
|
|
|
assert.include(
|
|
|
|
|
err.message,
|
|
|
|
|
`Input address must be a string or array of strings`
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
it(`should GET utxos for a single address`, async () => {
|
|
|
|
|
// Stub the network call.
|
|
|
|
|
sandbox.stub(axios, "get").resolves({ data: mockData.utxo })
|
|
|
|
|
|
|
|
|
|
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
|
|
|
|
|
|
|
|
|
|
const result = await bchjs.Electrumx.utxo(addr)
|
|
|
|
|
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
|
|
|
|
|
|
|
|
assert.property(result, "success")
|
|
|
|
|
assert.equal(result.success, true)
|
|
|
|
|
|
|
|
|
|
assert.property(result, "utxos")
|
|
|
|
|
assert.isArray(result.utxos)
|
|
|
|
|
|
|
|
|
|
assert.property(result.utxos[0], "height")
|
|
|
|
|
assert.property(result.utxos[0], "tx_hash")
|
|
|
|
|
assert.property(result.utxos[0], "tx_pos")
|
|
|
|
|
assert.property(result.utxos[0], "value")
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
it(`should POST utxo details for an array of addresses`, async () => {
|
|
|
|
|
// Stub the network call.
|
|
|
|
|
sandbox.stub(axios, "post").resolves({ data: mockData.utxos })
|
|
|
|
|
|
|
|
|
|
const addr = [
|
|
|
|
|
"bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
|
|
|
|
|
"bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
const result = await bchjs.Electrumx.utxo(addr)
|
|
|
|
|
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
|
|
|
|
|
|
|
|
assert.property(result, "success")
|
|
|
|
|
assert.equal(result.success, true)
|
|
|
|
|
|
|
|
|
|
assert.property(result, "utxos")
|
|
|
|
|
assert.isArray(result.utxos)
|
|
|
|
|
|
|
|
|
|
assert.property(result.utxos[0], "utxos")
|
|
|
|
|
assert.isArray(result.utxos[0].utxos)
|
|
|
|
|
assert.property(result.utxos[0], "address")
|
|
|
|
|
|
|
|
|
|
assert.property(result.utxos[0].utxos[0], "height")
|
|
|
|
|
assert.property(result.utxos[0].utxos[0], "tx_hash")
|
|
|
|
|
assert.property(result.utxos[0].utxos[0], "tx_pos")
|
|
|
|
|
assert.property(result.utxos[0].utxos[0], "value")
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
describe(`#balance`, () => {
|
|
|
|
|
it(`should throw an error for improper input`, async () => {
|
|
|
|
|
try {
|
|
|
|
|
const addr = 12345
|
|
|
|
|
|
|
|
|
|
await bchjs.Electrumx.balance(addr)
|
|
|
|
|
assert.equal(true, false, "Unexpected result!")
|
|
|
|
|
} catch (err) {
|
|
|
|
|
// console.log(`err: `, err)
|
|
|
|
|
assert.include(
|
|
|
|
|
err.message,
|
|
|
|
|
`Input address must be a string or array of strings`
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
it(`should GET balance for a single address`, async () => {
|
|
|
|
|
// Stub the network call.
|
|
|
|
|
sandbox.stub(axios, "get").resolves({ data: mockData.balance })
|
|
|
|
|
|
|
|
|
|
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
|
|
|
|
|
|
|
|
|
|
const result = await bchjs.Electrumx.balance(addr)
|
|
|
|
|
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
|
|
|
|
|
|
|
|
assert.property(result, "success")
|
|
|
|
|
assert.equal(result.success, true)
|
|
|
|
|
|
|
|
|
|
assert.property(result, "balance")
|
|
|
|
|
assert.property(result.balance, "confirmed")
|
|
|
|
|
assert.property(result.balance, "unconfirmed")
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
it(`should POST balance for an array of addresses`, async () => {
|
|
|
|
|
// Stub the network call.
|
|
|
|
|
sandbox.stub(axios, "post").resolves({ data: mockData.balances })
|
|
|
|
|
|
|
|
|
|
const addr = [
|
|
|
|
|
"bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
|
|
|
|
|
"bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
const result = await bchjs.Electrumx.balance(addr)
|
|
|
|
|
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
|
|
|
|
|
|
|
|
assert.property(result, "success")
|
|
|
|
|
assert.equal(result.success, true)
|
|
|
|
|
|
|
|
|
|
assert.property(result, "balances")
|
|
|
|
|
assert.isArray(result.balances)
|
|
|
|
|
|
|
|
|
|
assert.property(result.balances[0], "address")
|
|
|
|
|
assert.property(result.balances[0], "balance")
|
|
|
|
|
assert.property(result.balances[0].balance, "confirmed")
|
|
|
|
|
assert.property(result.balances[0].balance, "unconfirmed")
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
describe(`#transactions`, () => {
|
|
|
|
|
it(`should throw an error for improper input`, async () => {
|
|
|
|
|
try {
|
|
|
|
|
const addr = 12345
|
|
|
|
|
|
|
|
|
|
await bchjs.Electrumx.transactions(addr)
|
|
|
|
|
assert.equal(true, false, "Unexpected result!")
|
|
|
|
|
} catch (err) {
|
|
|
|
|
// console.log(`err: `, err)
|
|
|
|
|
assert.include(
|
|
|
|
|
err.message,
|
|
|
|
|
`Input address must be a string or array of strings`
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
it(`should GET transactions for a single address`, async () => {
|
|
|
|
|
// Stub the network call.
|
|
|
|
|
sandbox.stub(axios, "get").resolves({ data: mockData.transaction })
|
|
|
|
|
|
|
|
|
|
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
|
|
|
|
|
|
|
|
|
|
const result = await bchjs.Electrumx.transactions(addr)
|
|
|
|
|
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
|
|
|
|
|
|
|
|
assert.property(result, "success")
|
|
|
|
|
assert.equal(result.success, true)
|
|
|
|
|
|
|
|
|
|
assert.property(result, "transactions")
|
|
|
|
|
assert.isArray(result.transactions)
|
|
|
|
|
assert.property(result.transactions[0], "height")
|
|
|
|
|
assert.property(result.transactions[0], "tx_hash")
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
it(`should POST transaction history for an array of addresses`, async () => {
|
|
|
|
|
// Stub the network call.
|
|
|
|
|
sandbox.stub(axios, "post").resolves({ data: mockData.transactions })
|
|
|
|
|
|
|
|
|
|
const addr = [
|
|
|
|
|
"bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
|
|
|
|
|
"bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
const result = await bchjs.Electrumx.transactions(addr)
|
|
|
|
|
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
|
|
|
|
|
|
|
|
assert.property(result, "success")
|
|
|
|
|
assert.equal(result.success, true)
|
|
|
|
|
|
|
|
|
|
assert.property(result, "transactions")
|
|
|
|
|
assert.isArray(result.transactions)
|
|
|
|
|
|
|
|
|
|
assert.property(result.transactions[0], "address")
|
|
|
|
|
assert.property(result.transactions[0], "transactions")
|
|
|
|
|
assert.isArray(result.transactions[0].transactions)
|
|
|
|
|
assert.property(result.transactions[0].transactions[0], "height")
|
|
|
|
|
assert.property(result.transactions[0].transactions[0], "tx_hash")
|
|
|
|
|
})
|
|
|
|
|
})
|
2020-08-04 22:58:22 +09:00
|
|
|
|
|
|
|
|
describe(`#unconfirmed`, () => {
|
|
|
|
|
it(`should throw an error for improper input`, async () => {
|
|
|
|
|
try {
|
|
|
|
|
const addr = 12345
|
|
|
|
|
|
|
|
|
|
await bchjs.Electrumx.unconfirmed(addr)
|
|
|
|
|
assert.equal(true, false, "Unexpected result!")
|
|
|
|
|
} catch (err) {
|
|
|
|
|
// console.log(`err: `, err)
|
|
|
|
|
assert.include(
|
|
|
|
|
err.message,
|
|
|
|
|
`Input address must be a string or array of strings`
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
it(`should GET unconfirmed utxos for a single address`, async () => {
|
|
|
|
|
// Stub the network call.
|
|
|
|
|
sandbox.stub(axios, "get").resolves({ data: mockData.unconfirmed })
|
|
|
|
|
|
|
|
|
|
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
|
|
|
|
|
|
|
|
|
|
const result = await bchjs.Electrumx.unconfirmed(addr)
|
|
|
|
|
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
|
|
|
|
|
|
|
|
assert.property(result, "success")
|
|
|
|
|
assert.equal(result.success, true)
|
|
|
|
|
|
|
|
|
|
assert.property(result, "utxos")
|
|
|
|
|
assert.isArray(result.utxos)
|
|
|
|
|
|
|
|
|
|
assert.property(result.utxos[0], "height")
|
|
|
|
|
assert.property(result.utxos[0], "tx_hash")
|
|
|
|
|
assert.property(result.utxos[0], "fee")
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
it(`should POST unconfirmed utxo details for an array of addresses`, async () => {
|
|
|
|
|
// Stub the network call.
|
|
|
|
|
sandbox.stub(axios, "post").resolves({ data: mockData.unconfirmedArray })
|
|
|
|
|
|
|
|
|
|
const addr = [
|
|
|
|
|
"bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
|
|
|
|
|
"bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
const result = await bchjs.Electrumx.unconfirmed(addr)
|
|
|
|
|
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
|
|
|
|
|
|
|
|
assert.property(result, "success")
|
|
|
|
|
assert.equal(result.success, true)
|
|
|
|
|
|
|
|
|
|
assert.property(result, "utxos")
|
|
|
|
|
assert.isArray(result.utxos)
|
|
|
|
|
|
|
|
|
|
assert.property(result.utxos[0], "utxos")
|
|
|
|
|
assert.isArray(result.utxos[0].utxos)
|
|
|
|
|
assert.property(result.utxos[0], "address")
|
|
|
|
|
|
|
|
|
|
assert.property(result.utxos[0].utxos[0], "height")
|
|
|
|
|
assert.property(result.utxos[0].utxos[0], "tx_hash")
|
|
|
|
|
assert.property(result.utxos[0].utxos[0], "fee")
|
|
|
|
|
})
|
|
|
|
|
})
|
2020-09-01 23:52:50 +09:00
|
|
|
|
|
|
|
|
describe(`#blockHeader`, () => {
|
|
|
|
|
it(`should throw an error for improper height input`, async () => {
|
|
|
|
|
try {
|
2020-10-11 15:39:17 -07:00
|
|
|
// Mock network calls.
|
|
|
|
|
sandbox.stub(axios, "get").rejects({
|
|
|
|
|
response: {
|
|
|
|
|
data: {
|
|
|
|
|
success: false,
|
|
|
|
|
error: "height must be a positive number"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
2020-09-01 23:52:50 +09:00
|
|
|
const height = -10
|
|
|
|
|
await bchjs.Electrumx.blockHeader(height)
|
2020-10-11 15:39:17 -07:00
|
|
|
|
2020-09-01 23:52:50 +09:00
|
|
|
assert.equal(true, false, "Unexpected result!")
|
|
|
|
|
} catch (err) {
|
|
|
|
|
// console.log(`err: `, err)
|
2020-10-11 15:39:17 -07:00
|
|
|
assert.include(err.message, `height must be a positive number`)
|
2020-09-01 23:52:50 +09:00
|
|
|
}
|
|
|
|
|
})
|
2020-09-11 21:08:13 +09:00
|
|
|
|
2020-09-01 23:52:50 +09:00
|
|
|
it(`should throw an error for improper count input`, async () => {
|
|
|
|
|
try {
|
2020-10-11 15:39:17 -07:00
|
|
|
// Mock network calls.
|
|
|
|
|
sandbox.stub(axios, "get").rejects({
|
|
|
|
|
response: {
|
|
|
|
|
data: {
|
|
|
|
|
success: false,
|
|
|
|
|
error: "count must be a positive number"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
2020-09-01 23:52:50 +09:00
|
|
|
const height = 42
|
|
|
|
|
const count = -10
|
|
|
|
|
|
|
|
|
|
await bchjs.Electrumx.blockHeader(height, count)
|
|
|
|
|
assert.equal(true, false, "Unexpected result!")
|
|
|
|
|
} catch (err) {
|
|
|
|
|
// console.log(`err: `, err)
|
2020-10-11 15:39:17 -07:00
|
|
|
assert.include(err.message, `count must be a positive number`)
|
2020-09-01 23:52:50 +09:00
|
|
|
}
|
|
|
|
|
})
|
2020-09-11 21:08:13 +09:00
|
|
|
|
2020-09-01 23:52:50 +09:00
|
|
|
it(`should GET block headers for a given height`, async () => {
|
|
|
|
|
// Stub the network call.
|
|
|
|
|
sandbox.stub(axios, "get").resolves({ data: mockData.blockHeaders })
|
|
|
|
|
|
|
|
|
|
const height = 42
|
|
|
|
|
|
|
|
|
|
const result = await bchjs.Electrumx.blockHeader(height)
|
|
|
|
|
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
|
|
|
assert.isArray(result)
|
|
|
|
|
assert.equal(result.length, 2)
|
|
|
|
|
})
|
|
|
|
|
})
|
2020-09-11 21:08:13 +09:00
|
|
|
|
|
|
|
|
describe(`#txData`, () => {
|
|
|
|
|
it(`should throw an error for improper input`, async () => {
|
|
|
|
|
try {
|
|
|
|
|
const txid = 12345
|
|
|
|
|
|
|
|
|
|
await bchjs.Electrumx.txData(txid)
|
|
|
|
|
assert.equal(true, false, "Unexpected result!")
|
|
|
|
|
} catch (err) {
|
|
|
|
|
// console.log(`err: `, err)
|
|
|
|
|
assert.include(
|
|
|
|
|
err.message,
|
|
|
|
|
`Input txId must be a string or array of strings`
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
it(`should GET details data for a single transaction`, async () => {
|
|
|
|
|
// Stub the network call.
|
|
|
|
|
sandbox.stub(axios, "get").resolves({ data: mockData.details })
|
|
|
|
|
|
2020-10-11 15:39:17 -07:00
|
|
|
const txid =
|
|
|
|
|
"4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251"
|
2020-09-11 21:08:13 +09:00
|
|
|
|
|
|
|
|
const result = await bchjs.Electrumx.txData(txid)
|
|
|
|
|
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
|
|
|
|
|
|
|
|
assert.property(result, "success")
|
|
|
|
|
assert.equal(result.success, true)
|
|
|
|
|
|
|
|
|
|
assert.property(result, "details")
|
|
|
|
|
assert.isObject(result.details)
|
|
|
|
|
|
|
|
|
|
assert.property(result.details, "blockhash")
|
|
|
|
|
assert.property(result.details, "hash")
|
|
|
|
|
assert.property(result.details, "hex")
|
|
|
|
|
assert.property(result.details, "vin")
|
|
|
|
|
assert.property(result.details, "vout")
|
|
|
|
|
assert.equal(result.details.hash, txid)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
it(`should POST details for an array of transactions`, async () => {
|
|
|
|
|
// Stub the network call.
|
|
|
|
|
sandbox.stub(axios, "post").resolves({ data: mockData.detailsArray })
|
|
|
|
|
|
|
|
|
|
const txids = [
|
|
|
|
|
"4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251",
|
|
|
|
|
"4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251"
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
const result = await bchjs.Electrumx.txData(txids)
|
|
|
|
|
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
|
|
|
|
|
|
|
|
assert.property(result, "success")
|
|
|
|
|
assert.equal(result.success, true)
|
|
|
|
|
|
|
|
|
|
assert.property(result, "transactions")
|
|
|
|
|
assert.isArray(result.transactions)
|
|
|
|
|
|
|
|
|
|
assert.property(result.transactions[0], "txid")
|
|
|
|
|
assert.property(result.transactions[0], "details")
|
|
|
|
|
|
|
|
|
|
assert.property(result.transactions[0].details, "blockhash")
|
|
|
|
|
assert.property(result.transactions[0].details, "hash")
|
|
|
|
|
assert.property(result.transactions[0].details, "hex")
|
|
|
|
|
assert.property(result.transactions[0].details, "vin")
|
|
|
|
|
assert.property(result.transactions[0].details, "vout")
|
|
|
|
|
|
|
|
|
|
assert.equal(result.transactions.length, 2, "2 outputs for 2 inputs")
|
|
|
|
|
})
|
|
|
|
|
})
|
2020-10-07 17:14:30 +09:00
|
|
|
describe(`#broadcast`, () => {
|
|
|
|
|
it(`should throw an error for improper input`, async () => {
|
|
|
|
|
try {
|
|
|
|
|
const txHex = 12345
|
|
|
|
|
|
|
|
|
|
await bchjs.Electrumx.broadcast(txHex)
|
|
|
|
|
assert.equal(true, false, "Unexpected result!")
|
|
|
|
|
} catch (err) {
|
|
|
|
|
// console.log(`err: `, err)
|
2020-10-11 15:39:17 -07:00
|
|
|
assert.include(err.message, `Input txHex must be a string.`)
|
2020-10-07 17:14:30 +09:00
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
it(`should broadcast a single transaction`, async () => {
|
|
|
|
|
// Stub the network call.
|
|
|
|
|
sandbox.stub(axios, "post").resolves({ data: mockData.broadcast })
|
|
|
|
|
|
|
|
|
|
const tx = mockData.details
|
|
|
|
|
const txid = tx.details.txid
|
|
|
|
|
const result = await bchjs.Electrumx.broadcast(tx.details.hex)
|
|
|
|
|
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
|
|
|
|
|
|
|
|
assert.property(result, "success")
|
|
|
|
|
assert.equal(result.success, true)
|
|
|
|
|
|
|
|
|
|
assert.property(result, "txid")
|
|
|
|
|
assert.equal(result.txid, txid)
|
|
|
|
|
})
|
|
|
|
|
})
|
2020-07-27 21:32:51 -07:00
|
|
|
})
|