diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..dceda2d7 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,3 @@ +{ + "semi": false +} \ No newline at end of file diff --git a/examples/applications/wallet/check-balance/check-balance.js b/examples/applications/wallet/check-balance/check-balance.js index 7a56094c..5e0ecc15 100644 --- a/examples/applications/wallet/check-balance/check-balance.js +++ b/examples/applications/wallet/check-balance/check-balance.js @@ -3,27 +3,26 @@ with the create-wallet example. */ +const BITBOX = require("../../../../lib/BITBOX").BITBOX + // Set NETWORK to either testnet or mainnet const NETWORK = `testnet` -// Instantiate bitbox. -const bitboxLib = "../../../lib/BITBOX" -const BITBOX = require(bitboxLib).BITBOX - -// Instantiate SLP based on the network. -let bitbox -if (NETWORK === `mainnet`) - bitbox = new BITBOX({ restURL: `https://rest.bitcoin.com/v2/` }) -else bitbox = new BITBOX({ restURL: `https://trest.bitcoin.com/v2/` }) +// Instantiate BITBOX based on the network. +const bitbox = + NETWORK === `mainnet` + ? new BITBOX({ restURL: `https://rest.bitcoin.com/v2/` }) + : new BITBOX({ restURL: `https://trest.bitcoin.com/v2/` }) // Open the wallet generated with create-wallet. +let walletInfo try { - var walletInfo = require(`../create-wallet/wallet.json`) + walletInfo = require(`../create-wallet/wallet.json`) } catch (err) { console.log( `Could not open wallet.json. Generate a wallet with create-wallet first.` ) - process.exit(0) + process.exit(1) } // Get the balance of the wallet. @@ -36,7 +35,7 @@ async function getBalance() { console.log(balance) } catch (err) { console.error(`Error in getBalance: `, err) - throw err + process.exit(1) } } getBalance() diff --git a/examples/applications/wallet/consolidate-dust/consolidate-dust.js b/examples/applications/wallet/consolidate-dust/consolidate-dust.js index 83a44cf0..f3295482 100644 --- a/examples/applications/wallet/consolidate-dust/consolidate-dust.js +++ b/examples/applications/wallet/consolidate-dust/consolidate-dust.js @@ -3,27 +3,26 @@ a single UTXO. */ +const BITBOX = require("../../../../lib/BITBOX").BITBOX + // Set NETWORK to either testnet or mainnet const NETWORK = `testnet` -// Instantiate bitbox. -const bitboxLib = "../../../lib/BITBOX" -const BITBOX = require(bitboxLib).BITBOX - -// Instantiate SLP based on the network. -let bitbox -if (NETWORK === `mainnet`) - bitbox = new BITBOX({ restURL: `https://rest.bitcoin.com/v2/` }) -else bitbox = new BITBOX({ restURL: `https://trest.bitcoin.com/v2/` }) +// Instantiate BITBOX based on the network. +const bitbox = + NETWORK === `mainnet` + ? new BITBOX({ restURL: `https://rest.bitcoin.com/v2/` }) + : new BITBOX({ restURL: `https://trest.bitcoin.com/v2/` }) // Open the wallet generated with create-wallet. +let walletInfo try { - var walletInfo = require(`../create-wallet/wallet.json`) + walletInfo = require(`../create-wallet/wallet.json`) } catch (err) { console.log( `Could not open wallet.json. Generate a wallet with create-wallet first.` ) - process.exit(0) + process.exit(1) } const SEND_ADDR = walletInfo.cashAddress @@ -31,10 +30,7 @@ const SEND_MNEMONIC = walletInfo.mnemonic async function consolidateDust() { try { - // instance of transaction builder - if (NETWORK === `mainnet`) - var transactionBuilder = new bitbox.TransactionBuilder() - else var transactionBuilder = new bitbox.TransactionBuilder("testnet") + const transactionBuilder = new bitbox.TransactionBuilder(NETWORK) const dust = 546 let sendAmount = 0 @@ -43,26 +39,23 @@ async function consolidateDust() { const u = await bitbox.Address.utxo(SEND_ADDR) // Loop through each UTXO assigned to this address. - for (let i = 0; i < u.utxos.length; i++) { - const thisUtxo = u.utxos[i] - + u.utxos.forEach(utxo => { // If the UTXO is dust... - if (thisUtxo.satoshis <= dust) { - inputs.push(thisUtxo) - - sendAmount += thisUtxo.satoshis + if (utxo.satoshis <= dust) { + inputs.push(utxo) + sendAmount += utxo.satoshis // ..Add the utxo as an input to the transaction. - transactionBuilder.addInput(thisUtxo.txid, thisUtxo.vout) + transactionBuilder.addInput(utxo.txid, utxo.vout) } - } + }) if (inputs.length === 0) { console.log(`No dust found in the wallet address.`) - return + process.exit(0) } - // get byte count to calculate fee. paying 1.2 sat/byte + // get byte count to calculate fee. paying 1.0 sat/byte const byteCount = bitbox.BitcoinCash.getByteCount( { P2PKH: inputs.length }, { P2PKH: 1 } @@ -78,7 +71,7 @@ async function consolidateDust() { console.log( `Transaction fee costs more combined dust. Can't send transaction.` ) - return + process.exit(1) } // add output w/ address and amount to send @@ -104,10 +97,11 @@ async function consolidateDust() { // build tx const tx = transactionBuilder.build() + // output rawhex const hex = tx.toHex() console.log(`TX hex: ${hex}`) - console.log(` `) + console.log() // Broadcast transation to the network const broadcast = await bitbox.RawTransactions.sendRawTransaction([hex]) @@ -119,18 +113,12 @@ async function consolidateDust() { consolidateDust() // Generate a change address from a Mnemonic of a private key. -function changeAddrFromMnemonic(mnemonic) { - // root seed buffer +function changeAddrFromMnemonic(mnemonic, network) { const rootSeed = bitbox.Mnemonic.toSeed(mnemonic) - - // master HDNode - const masterHDNode = bitbox.HDNode.fromSeed(rootSeed, "testnet") - - // HDNode of BIP44 account + const masterHDNode = bitbox.HDNode.fromSeed(rootSeed, network) const account = bitbox.HDNode.derivePath(masterHDNode, "m/44'/145'/0'") // derive the first external change address HDNode which is going to spend utxo const change = bitbox.HDNode.derivePath(account, "0/0") - return change } diff --git a/examples/applications/wallet/consolidate-utxos/consolidate-utxos.js b/examples/applications/wallet/consolidate-utxos/consolidate-utxos.js index acb8d4ab..5edf6d40 100644 --- a/examples/applications/wallet/consolidate-utxos/consolidate-utxos.js +++ b/examples/applications/wallet/consolidate-utxos/consolidate-utxos.js @@ -2,27 +2,26 @@ Consolidate all UTXOs in an address into a single UTXO */ +const BITBOX = require("../../../../lib/BITBOX").BITBOX + // Set NETWORK to either testnet or mainnet const NETWORK = `testnet` -// Instantiate bitbox. -const bitboxLib = "../../../lib/BITBOX" -const BITBOX = require(bitboxLib).BITBOX - -// Instantiate SLP based on the network. -let bitbox -if (NETWORK === `mainnet`) - bitbox = new BITBOX({ restURL: `https://rest.bitcoin.com/v2/` }) -else bitbox = new BITBOX({ restURL: `https://trest.bitcoin.com/v2/` }) +// Instantiate BITBOX based on the network. +const bitbox = + NETWORK === `mainnet` + ? new BITBOX({ restURL: `https://rest.bitcoin.com/v2/` }) + : new BITBOX({ restURL: `https://trest.bitcoin.com/v2/` }) // Open the wallet generated with create-wallet. +let walletInfo try { - var walletInfo = require(`../create-wallet/wallet.json`) + walletInfo = require(`../create-wallet/wallet.json`) } catch (err) { console.log( `Could not open wallet.json. Generate a wallet with create-wallet first.` ) - process.exit(0) + process.exit(1) } const SEND_ADDR = walletInfo.cashAddress @@ -30,10 +29,7 @@ const SEND_MNEMONIC = walletInfo.mnemonic async function consolidateDust() { try { - // instance of transaction builder - if (NETWORK === `mainnet`) - var transactionBuilder = new bitbox.TransactionBuilder() - else var transactionBuilder = new bitbox.TransactionBuilder("testnet") + const transactionBuilder = new bitbox.TransactionBuilder(NETWORK) let sendAmount = 0 const inputs = [] @@ -41,18 +37,13 @@ async function consolidateDust() { const u = await bitbox.Address.utxo(SEND_ADDR) // Loop through each UTXO assigned to this address. - for (let i = 0; i < u.utxos.length; i++) { - const thisUtxo = u.utxos[i] - - inputs.push(thisUtxo) - - sendAmount += thisUtxo.satoshis - - // ..Add the utxo as an input to the transaction. - transactionBuilder.addInput(thisUtxo.txid, thisUtxo.vout) - } + u.utxos.forEach(utxo => { + inputs.push(utxo) + sendAmount += utxo.satoshis + transactionBuilder.addInput(utxo.txid, utxo.vout) + }) - // get byte count to calculate fee. paying 1.2 sat/byte + // get byte count to calculate fee. paying 1.0 sat/byte const byteCount = bitbox.BitcoinCash.getByteCount( { P2PKH: inputs.length }, { P2PKH: 1 } @@ -68,7 +59,7 @@ async function consolidateDust() { console.log( `Transaction fee costs more combined UTXOs. Can't send transaction.` ) - return + process.exit(1) } // add output w/ address and amount to send @@ -94,10 +85,11 @@ async function consolidateDust() { // build tx const tx = transactionBuilder.build() + // output rawhex const hex = tx.toHex() - //console.log(`TX hex: ${hex}`) - console.log(` `) + console.log(`TX hex: ${hex}`) + console.log() // Broadcast transation to the network const txid = await bitbox.RawTransactions.sendRawTransaction([hex]) @@ -111,18 +103,12 @@ async function consolidateDust() { consolidateDust() // Generate a change address from a Mnemonic of a private key. -function changeAddrFromMnemonic(mnemonic) { - // root seed buffer +function changeAddrFromMnemonic(mnemonic, network) { const rootSeed = bitbox.Mnemonic.toSeed(mnemonic) - - // master HDNode - const masterHDNode = bitbox.HDNode.fromSeed(rootSeed, "testnet") - - // HDNode of BIP44 account + const masterHDNode = bitbox.HDNode.fromSeed(rootSeed, network) const account = bitbox.HDNode.derivePath(masterHDNode, "m/44'/145'/0'") // derive the first external change address HDNode which is going to spend utxo const change = bitbox.HDNode.derivePath(account, "0/0") - return change } diff --git a/examples/applications/wallet/create-wallet/create-wallet.js b/examples/applications/wallet/create-wallet/create-wallet.js index a0f49d52..770cc03f 100644 --- a/examples/applications/wallet/create-wallet/create-wallet.js +++ b/examples/applications/wallet/create-wallet/create-wallet.js @@ -3,20 +3,17 @@ will be used in future examples. */ +const fs = require("fs") +const BITBOX = require("../../../../lib/BITBOX").BITBOX + // Set NETWORK to either testnet or mainnet const NETWORK = `testnet` -// Instantiate bitbox. -const bitboxLib = "../../../lib/BITBOX" -const BITBOX = require(bitboxLib).BITBOX - -// Instantiate SLP based on the network. -let bitbox -if (NETWORK === `mainnet`) - bitbox = new BITBOX({ restURL: `https://rest.bitcoin.com/v2/` }) -else bitbox = new BITBOX({ restURL: `https://trest.bitcoin.com/v2/` }) - -const fs = require("fs") +// Instantiate BITBOX based on the network. +const bitbox = + NETWORK === `mainnet` + ? new BITBOX({ restURL: `https://rest.bitcoin.com/v2/` }) + : new BITBOX({ restURL: `https://trest.bitcoin.com/v2/` }) const lang = "english" // Set the language of the wallet. @@ -29,6 +26,7 @@ const mnemonic = bitbox.Mnemonic.generate( 128, bitbox.Mnemonic.wordLists()[lang] ) + console.log("BIP44 $BCH Wallet") outStr += "BIP44 $BCH Wallet\n" console.log(`128 bit ${lang} BIP39 Mnemonic: `, mnemonic) @@ -39,9 +37,7 @@ outObj.mnemonic = mnemonic const rootSeed = bitbox.Mnemonic.toSeed(mnemonic) // master HDNode -let masterHDNode -if (NETWORK === `mainnet`) masterHDNode = bitbox.HDNode.fromSeed(rootSeed) -else masterHDNode = bitbox.HDNode.fromSeed(rootSeed, "testnet") // Testnet +const masterHDNode = bitbox.HDNode.fromSeed(rootSeed, NETWORK) // HDNode of BIP44 account console.log(`BIP44 Account: "m/44'/145'/0'"`) diff --git a/examples/low-level/utxo-address/get-utxos.js b/examples/applications/wallet/get-utxos/get-utxos.js similarity index 61% rename from examples/low-level/utxo-address/get-utxos.js rename to examples/applications/wallet/get-utxos/get-utxos.js index 68f60b4e..23515a66 100644 --- a/examples/low-level/utxo-address/get-utxos.js +++ b/examples/applications/wallet/get-utxos/get-utxos.js @@ -3,27 +3,26 @@ with the create-wallet example. */ +const BITBOX = require("../../../../lib/BITBOX").BITBOX + // Set NETWORK to either testnet or mainnet const NETWORK = `testnet` -// Instantiate bitbox. -const bitboxLib = "../../../lib/BITBOX" -const BITBOX = require(bitboxLib).BITBOX - -// Instantiate SLP based on the network. -let bitbox -if (NETWORK === `mainnet`) - bitbox = new BITBOX({ restURL: `https://rest.bitcoin.com/v2/` }) -else bitbox = new BITBOX({ restURL: `https://trest.bitcoin.com/v2/` }) +// Instantiate BITBOX based on the network. +const bitbox = + NETWORK === `mainnet` + ? new BITBOX({ restURL: `https://rest.bitcoin.com/v2/` }) + : new BITBOX({ restURL: `https://trest.bitcoin.com/v2/` }) // Open the wallet generated with create-wallet. +let walletInfo try { - var walletInfo = require(`../../applications/wallet/create-wallet/wallet.json`) + walletInfo = require(`../create-wallet/wallet.json`) } catch (err) { console.log( `Could not open wallet.json. Generate a wallet with create-wallet first.` ) - process.exit(0) + process.exit(1) } const ADDR = walletInfo.cashAddress diff --git a/examples/low-level/utxo-address/package.json b/examples/applications/wallet/get-utxos/package.json similarity index 100% rename from examples/low-level/utxo-address/package.json rename to examples/applications/wallet/get-utxos/package.json diff --git a/examples/applications/wallet/send-WIF/send-wif.js b/examples/applications/wallet/send-WIF/send-wif.js index 301a47d4..ad10b5df 100644 --- a/examples/applications/wallet/send-WIF/send-wif.js +++ b/examples/applications/wallet/send-WIF/send-wif.js @@ -4,32 +4,32 @@ Send 1000 satoshis to RECV_ADDR. */ +const BITBOX = require("../../../../lib/BITBOX").BITBOX + // Set NETWORK to either testnet or mainnet const NETWORK = `testnet` -// Replace the address below with the address you want to send the BCH to. -let RECV_ADDR = `` -const SATOSHIS_TO_SEND = 1000 - -// Instantiate bitbox. -const bitboxLib = "../../../lib/BITBOX" -const BITBOX = require(bitboxLib).BITBOX -// Instantiate SLP based on the network. -let bitbox -if (NETWORK === `mainnet`) - bitbox = new BITBOX({ restURL: `https://rest.bitcoin.com/v2/` }) -else bitbox = new BITBOX({ restURL: `https://trest.bitcoin.com/v2/` }) +// Instantiate BITBOX based on the network. +const bitbox = + NETWORK === `mainnet` + ? new BITBOX({ restURL: `https://rest.bitcoin.com/v2/` }) + : new BITBOX({ restURL: `https://trest.bitcoin.com/v2/` }) // Open the wallet generated with create-wallet. +let walletInfo try { - var walletInfo = require(`../create-wallet/wallet.json`) + walletInfo = require(`../create-wallet/wallet.json`) } catch (err) { console.log( `Could not open wallet.json. Generate a wallet with create-wallet first.` ) - process.exit(0) + process.exit(1) } +// Replace the address below with the address you want to send the BCH to. +let RECV_ADDR = `` +const SATOSHIS_TO_SEND = 1000 + const SEND_ADDR = walletInfo.cashAddress const SEND_WIF = walletInfo.WIF @@ -58,14 +58,10 @@ async function sendBch() { console.log(`Balance of recieving address ${RECV_ADDR} is ${balance2} BCH.`) const u = await bitbox.Address.utxo(SEND_ADDR) - //console.log(`u: ${JSON.stringify(u, null, 2)}`) const utxo = findBiggestUtxo(u.utxos) console.log(`utxo: ${JSON.stringify(utxo, null, 2)}`) - // instance of transaction builder - if (NETWORK === `mainnet`) - var transactionBuilder = new bitbox.TransactionBuilder() - else var transactionBuilder = new bitbox.TransactionBuilder("testnet") + const transactionBuilder = new bitbox.TransactionBuilder(NETWORK) const satoshisToSend = SATOSHIS_TO_SEND const originalAmount = utxo.satoshis @@ -110,7 +106,7 @@ async function sendBch() { // output rawhex const hex = tx.toHex() console.log(`TX hex: ${hex}`) - console.log(` `) + console.log() // Broadcast transation to the network const txidStr = await bitbox.RawTransactions.sendRawTransaction([hex]) @@ -126,11 +122,9 @@ sendBch() // Get the balance in BCH of a BCH address. async function getBCHBalance(addr, verbose) { try { - const result = await bitbox.Address.details(addr) - - if (verbose) console.log(result) + const bchBalance = await bitbox.Address.details(addr) - const bchBalance = result + if (verbose) console.log(bchBalance) return bchBalance.balance } catch (err) { @@ -145,7 +139,7 @@ function findBiggestUtxo(utxos) { let largestAmount = 0 let largestIndex = 0 - for (var i = 0; i < utxos.length; i++) { + for (let i = 0; i < utxos.length; i++) { const thisUtxo = utxos[i] if (thisUtxo.satoshis > largestAmount) { diff --git a/examples/applications/wallet/send-all/send-all.js b/examples/applications/wallet/send-all/send-all.js index 9f25f063..6e0ffc9a 100644 --- a/examples/applications/wallet/send-all/send-all.js +++ b/examples/applications/wallet/send-all/send-all.js @@ -2,41 +2,40 @@ Send all BCH from one address to another. Similar to consolidating UTXOs. */ +const BITBOX = require("../../../../lib/BITBOX").BITBOX + // Set NETWORK to either testnet or mainnet const NETWORK = `testnet` -// Set the address below to the address that should recieve the BCH. -const RECV_ADDR = `bchtest:qqmd9unmhkpx4pkmr6fkrr8rm6y77vckjvqe8aey35` - -// Instantiate bitbox. -const bitboxLib = "../../../lib/BITBOX" -const BITBOX = require(bitboxLib).BITBOX - -// Instantiate SLP based on the network. -let bitbox -if (NETWORK === `mainnet`) - bitbox = new BITBOX({ restURL: `https://rest.bitcoin.com/v2/` }) -else bitbox = new BITBOX({ restURL: `https://trest.bitcoin.com/v2/` }) +// Instantiate BITBOX based on the network. +const bitbox = + NETWORK === `mainnet` + ? new BITBOX({ restURL: `https://rest.bitcoin.com/v2/` }) + : new BITBOX({ restURL: `https://trest.bitcoin.com/v2/` }) // Open the wallet generated with create-wallet. +let walletInfo try { - var walletInfo = require(`../create-wallet/wallet.json`) + walletInfo = require(`../create-wallet/wallet.json`) } catch (err) { console.log( `Could not open wallet.json. Generate a wallet with create-wallet first.` ) - process.exit(0) + process.exit(1) } +// Set the address below to the address that should receive the BCH. +let RECV_ADDR = `` + const SEND_ADDR = walletInfo.cashAddress const SEND_MNEMONIC = walletInfo.mnemonic -async function consolidateDust() { +async function sendAll() { try { - // instance of transaction builder - if (NETWORK === `mainnet`) - var transactionBuilder = new bitbox.TransactionBuilder() - else var transactionBuilder = new bitbox.TransactionBuilder("testnet") + // Send the money back to yourself if the users hasn't specified a destination. + if (RECV_ADDR === "") RECV_ADDR = SEND_ADDR + + const transactionBuilder = new bitbox.TransactionBuilder(NETWORK) let sendAmount = 0 const inputs = [] @@ -44,18 +43,13 @@ async function consolidateDust() { const u = await bitbox.Address.utxo(SEND_ADDR) // Loop through each UTXO assigned to this address. - for (let i = 0; i < u.utxos.length; i++) { - const thisUtxo = u.utxos[i] - - inputs.push(thisUtxo) - - sendAmount += thisUtxo.satoshis - - // ..Add the utxo as an input to the transaction. - transactionBuilder.addInput(thisUtxo.txid, thisUtxo.vout) - } + u.utxos.forEach(utxo => { + inputs.push(utxo) + sendAmount += utxo.satoshis + transactionBuilder.addInput(utxo.txid, utxo.vout) + }) - // get byte count to calculate fee. paying 1.2 sat/byte + // get byte count to calculate fee. paying 1.0 sat/byte const byteCount = bitbox.BitcoinCash.getByteCount( { P2PKH: inputs.length }, { P2PKH: 1 } @@ -71,7 +65,7 @@ async function consolidateDust() { console.log( `Transaction fee costs more combined UTXOs. Can't send transaction.` ) - return + process.exit(1) } // add output w/ address and amount to send @@ -97,10 +91,11 @@ async function consolidateDust() { // build tx const tx = transactionBuilder.build() + // output rawhex const hex = tx.toHex() - //console.log(`TX hex: ${hex}`) - console.log(` `) + console.log(`TX hex: ${hex}`) + console.log() // Broadcast transation to the network const txid = await bitbox.RawTransactions.sendRawTransaction([hex]) @@ -111,23 +106,15 @@ async function consolidateDust() { console.log(`error: `, err) } } -consolidateDust() +sendAll() // Generate a change address from a Mnemonic of a private key. -function changeAddrFromMnemonic(mnemonic) { - // root seed buffer +function changeAddrFromMnemonic(mnemonic, network) { const rootSeed = bitbox.Mnemonic.toSeed(mnemonic) - - // master HDNode - let masterHDNode - if (NETWORK === `mainnet`) masterHDNode = bitbox.HDNode.fromSeed(rootSeed) - else masterHDNode = bitbox.HDNode.fromSeed(rootSeed, "testnet") - - // HDNode of BIP44 account + const masterHDNode = bitbox.HDNode.fromSeed(rootSeed, network) const account = bitbox.HDNode.derivePath(masterHDNode, "m/44'/145'/0'") // derive the first external change address HDNode which is going to spend utxo const change = bitbox.HDNode.derivePath(account, "0/0") - return change } diff --git a/examples/applications/wallet/send-bch/send-bch.js b/examples/applications/wallet/send-bch/send-bch.js index dc449473..906620f0 100644 --- a/examples/applications/wallet/send-bch/send-bch.js +++ b/examples/applications/wallet/send-bch/send-bch.js @@ -2,37 +2,40 @@ Send 1000 satoshis to RECV_ADDR. */ +const BITBOX = require("../../../../lib/BITBOX").BITBOX + // Set NETWORK to either testnet or mainnet const NETWORK = `testnet` -// Replace the address below with the address you want to send the BCH to. -const RECV_ADDR = `` -const SATOSHIS_TO_SEND = 1000 -// Instantiate bitbox. -const bitboxLib = "../../../lib/BITBOX" -const BITBOX = require(bitboxLib).BITBOX - -// Instantiate SLP based on the network. -let bitbox -if (NETWORK === `mainnet`) - bitbox = new BITBOX({ restURL: `https://rest.bitcoin.com/v2/` }) -else bitbox = new BITBOX({ restURL: `https://trest.bitcoin.com/v2/` }) +// Instantiate BITBOX based on the network. +const bitbox = + NETWORK === `mainnet` + ? new BITBOX({ restURL: `https://rest.bitcoin.com/v2/` }) + : new BITBOX({ restURL: `https://trest.bitcoin.com/v2/` }) // Open the wallet generated with create-wallet. +let walletInfo try { - var walletInfo = require(`../create-wallet/wallet.json`) + walletInfo = require(`../create-wallet/wallet.json`) } catch (err) { console.log( `Could not open wallet.json. Generate a wallet with create-wallet first.` ) - process.exit(0) + process.exit(1) } +// Replace the address below with the address you want to send the BCH to. +let RECV_ADDR = `` +const SATOSHIS_TO_SEND = 1000 + const SEND_ADDR = walletInfo.cashAddress const SEND_MNEMONIC = walletInfo.mnemonic async function sendBch() { try { + // Send the money back to yourself if the users hasn't specified a destination. + if (RECV_ADDR === "") RECV_ADDR = SEND_ADDR + // Get the balance of the sending address. const balance = await getBCHBalance(SEND_ADDR, false) console.log(`balance: ${JSON.stringify(balance, null, 2)}`) @@ -41,7 +44,7 @@ async function sendBch() { // Exit if the balance is zero. if (balance <= 0.0) { console.log(`Balance of sending address is zero. Exiting.`) - process.exit(0) + process.exit(1) } const SEND_ADDR_LEGACY = bitbox.Address.toLegacyAddress(SEND_ADDR) @@ -50,17 +53,13 @@ async function sendBch() { console.log(`Receiver Legacy Address: ${RECV_ADDR_LEGACY}`) const balance2 = await getBCHBalance(RECV_ADDR, false) - console.log(`Balance of recieving address ${RECV_ADDR} is ${balance2} BCH.`) + console.log(`Balance of receiving address ${RECV_ADDR} is ${balance2} BCH.`) const u = await bitbox.Address.utxo(SEND_ADDR) - //console.log(`u: ${JSON.stringify(u, null, 2)}`) const utxo = findBiggestUtxo(u.utxos) console.log(`utxo: ${JSON.stringify(utxo, null, 2)}`) - // instance of transaction builder - if (NETWORK === `mainnet`) - var transactionBuilder = new bitbox.TransactionBuilder() - else var transactionBuilder = new bitbox.TransactionBuilder("testnet") + const transactionBuilder = new bitbox.TransactionBuilder(NETWORK) const satoshisToSend = SATOSHIS_TO_SEND const originalAmount = utxo.satoshis @@ -109,7 +108,7 @@ async function sendBch() { // output rawhex const hex = tx.toHex() console.log(`TX hex: ${hex}`) - console.log(` `) + console.log() // Broadcast transation to the network const txidStr = await bitbox.RawTransactions.sendRawTransaction([hex]) @@ -123,32 +122,22 @@ async function sendBch() { sendBch() // Generate a change address from a Mnemonic of a private key. -function changeAddrFromMnemonic(mnemonic) { - // root seed buffer +function changeAddrFromMnemonic(mnemonic, network) { const rootSeed = bitbox.Mnemonic.toSeed(mnemonic) - - // master HDNode - let masterHDNode - if (NETWORK === `mainnet`) masterHDNode = bitbox.HDNode.fromSeed(rootSeed) - else masterHDNode = bitbox.HDNode.fromSeed(rootSeed, "testnet") - - // HDNode of BIP44 account + const masterHDNode = bitbox.HDNode.fromSeed(rootSeed, network) const account = bitbox.HDNode.derivePath(masterHDNode, "m/44'/145'/0'") // derive the first external change address HDNode which is going to spend utxo const change = bitbox.HDNode.derivePath(account, "0/0") - return change } // Get the balance in BCH of a BCH address. async function getBCHBalance(addr, verbose) { try { - const result = await bitbox.Address.details(addr) - - if (verbose) console.log(result) + const bchBalance = await bitbox.Address.details(addr) - const bchBalance = result + if (verbose) console.log(bchBalance) return bchBalance.balance } catch (err) { @@ -163,7 +152,7 @@ function findBiggestUtxo(utxos) { let largestAmount = 0 let largestIndex = 0 - for (var i = 0; i < utxos.length; i++) { + for (let i = 0; i < utxos.length; i++) { const thisUtxo = utxos[i] if (thisUtxo.satoshis > largestAmount) { diff --git a/examples/low-level/OP_RETURN/op_return.js b/examples/low-level/OP_RETURN/op_return.js index 0068e739..c10fddd9 100644 --- a/examples/low-level/OP_RETURN/op_return.js +++ b/examples/low-level/OP_RETURN/op_return.js @@ -3,8 +3,7 @@ */ // Instantiate bitbox. -const bitboxLib = "../../../lib/BITBOX" -const BITBOX = require(bitboxLib).BITBOX +const BITBOX = require("../../../lib/BITBOX").BITBOX const bitbox = new BITBOX() // Choose a transaction to parse for OP_Return @@ -13,80 +12,67 @@ const bitbox = new BITBOX() const txid = `5b81b332c8fa5a2b2e77bb928bd18072af4485f02a7325d346f1f28cf3d4a6bb` // Short msg example (<20 char) -//const txid = `d887132e3408f8d10e9b82bec447ca12e485cb6160af88d9b14f22ba865f6793` +// const txid = `d887132e3408f8d10e9b82bec447ca12e485cb6160af88d9b14f22ba865f6793` -function parseOP_RETURN(txid) { +async function parseOP_RETURN(txid) { console.log(`Parsing transaction ${txid} for messages in OP_RETURN...`) console.log(``) // Get transaction details from txid - bitbox.Transaction.details(txid).then( - tx => { - // You may wish to log this tx info to the console to inspect and plan your parsing function - // console.log(tx) - - // Begin parsing transaction - - // Initialize an array to store any OP_Return messages - let messages = [] - - // Iterate over outputs looking for OP_Return outputs - - for (let i=0; i < tx.vout.length; i++) { - - // If this is an OP_Return output - if (typeof tx.vout[i].scriptPubKey.addresses === 'undefined') { - - let message = '' - let fromAsm = '' - let decoded = '' - - //Pretty print your raw transaction data to the console - //console.log(JSON.stringify(tx, null, 2)) - - try { - // Decode the OP_Return message - message = tx.vout[i].scriptPubKey.asm - - // If length is <= 20 characters, translate from hex - if (message.length <= 20) { - message = tx.vout[i].scriptPubKey.hex - message = message.substring(4) - message = "OP_RETURN " + message - } - - fromAsm = bitbox.Script.fromASM(message) - decoded = bitbox.Script.decode(fromAsm) - message = decoded[1].toString('ascii') - - // Add this decoded OP_Return message to an array, in case multiple outputs have OP_Return messages - messages.push(message) - } - catch(err) { - console.log(`Error in parsing OP_RETURN:`) - console.log(err) - } - } - } - - if (messages.length === 1) { - console.log(`Message found!`) - console.log(``) - console.log(`Message: ${messages[0]}`) - } - else { - console.log(`${messages.length} messages found!`) - console.log(``) - for (let j=0; j < messages.length; j++) { - console.log(`Message ${j+1} of ${messages.length+1}: ${messages[j]}`) - } - } - }, - err => { - console.log('Error in bitbox.Transaction.details(${txid}):') + let tx + try { + tx = await bitbox.Transaction.details(txid) + } catch (err) { + console.log(`Error in bitbox.Transaction.details(${txid}):`) + console.log(err) + process.exit(1) + } + + // You may wish to log this tx info to the console to inspect and plan your parsing function + // console.log(tx) + + // Initialize an array to store any OP_Return messages + const messages = [] + + // Iterate over outputs looking for OP_Return outputs + tx.vout.forEach(vout => { + // Skip if this is not an OP_Return output + if (typeof vout.scriptPubKey.addresses !== `undefined`) return + + // Pretty print your raw transaction data to the console + // console.log(JSON.stringify(tx, null, 2)) + + try { + // Decode the OP_Return message + let message = vout.scriptPubKey.asm + + // If length is <= 20 characters, translate from hex + if (message.length <= 20) + message = `OP_RETURN ${vout.scriptPubKey.hex.substring(4)}` + + const fromAsm = bitbox.Script.fromASM(message) + const decoded = bitbox.Script.decode(fromAsm) + message = decoded[1].toString(`ascii`) + + // Add this decoded OP_Return message to an array, in case multiple outputs have OP_Return messages + messages.push(message) + } catch (err) { + console.log(`Error in parsing OP_RETURN:`) console.log(err) + process.exit(1) } - ) + }) + + if (messages.length === 1) { + console.log(`Message found!`) + console.log() + console.log(`Message: ${messages[0]}`) + } else { + console.log(`${messages.length} messages found!`) + console.log() + for (let j = 0; j < messages.length; j++) + console.log(`Message ${j + 1} of ${messages.length + 1}: ${messages[j]}`) + } } -parseOP_RETURN(txid) \ No newline at end of file +parseOP_RETURN(txid) diff --git a/examples/low-level/address-details/address-details.js b/examples/low-level/address-details/address-details.js index 82ec7438..5d9524a6 100644 --- a/examples/low-level/address-details/address-details.js +++ b/examples/low-level/address-details/address-details.js @@ -4,8 +4,7 @@ */ // Instantiate bitbox. -const bitboxLib = "../../../lib/BITBOX" -const BITBOX = require(bitboxLib).BITBOX +const BITBOX = require("../../../lib/BITBOX").BITBOX const bitbox = new BITBOX({ restURL: "https://trest.bitcoin.com/v2/" }) const ADDR = `bchtest:qr45kxqda7yw8atztvkc4ckqnrlhmp0kvsep4p345q` diff --git a/lib/Blockchain.ts b/lib/Blockchain.ts index 5589e7ad..b9415c7c 100644 --- a/lib/Blockchain.ts +++ b/lib/Blockchain.ts @@ -153,9 +153,7 @@ export class Blockchain { try { const response: AxiosResponse = await axios.get( - `${ - this.restURL - }blockchain/getMempoolAncestors/${txid}?verbose=${verbose}` + `${this.restURL}blockchain/getMempoolAncestors/${txid}?verbose=${verbose}` ) return response.data } catch (error) { @@ -173,9 +171,7 @@ export class Blockchain { try { const response: AxiosResponse = await axios.get( - `${ - this.restURL - }blockchain/getMempoolDescendants/${txid}?verbose=${verbose}` + `${this.restURL}blockchain/getMempoolDescendants/${txid}?verbose=${verbose}` ) return response.data } catch (error) { @@ -239,18 +235,27 @@ export class Blockchain { } } + // Returns details about an unspent transaction output. public async getTxOut( txid: string, n: any, include_mempool: boolean = true ): Promise { - // TODO confirm this works + // Input validation + if (typeof txid !== "string" || txid.length !== 64) + throw new Error(`txid needs to be a proper transaction ID`) + + if (isNaN(n)) throw new Error(`n must be an integer`) + + if (typeof include_mempool !== "boolean") + throw new Error(`include_mempool input must be of type boolean`) + try { - const response: AxiosResponse = await axios.get( - `${ - this.restURL - }blockchain/getTxOut/${txid}/n?include_mempool=${include_mempool}` - ) + const path: string = `${this.restURL}blockchain/getTxOut/${txid}/${n}?include_mempool=${include_mempool}` + // console.log(`path: ${path}`) + + const response: AxiosResponse = await axios.get(path) + return response.data } catch (error) { if (error.response && error.response.data) throw error.response.data @@ -322,9 +327,7 @@ export class Blockchain { ): Promise { try { const response: AxiosResponse = await axios.get( - `${ - this.restURL - }blockchain/verifyChain?checklevel=${checklevel}&nblocks=${nblocks}` + `${this.restURL}blockchain/verifyChain?checklevel=${checklevel}&nblocks=${nblocks}` ) return response.data } catch (error) { diff --git a/lib/Util.ts b/lib/Util.ts index da92ff1d..6cd975c5 100644 --- a/lib/Util.ts +++ b/lib/Util.ts @@ -1,13 +1,5 @@ -// imports import axios, { AxiosResponse } from "axios" -import { AddressDetailsResult, AddressUtxoResult, utxo } from "bitcoin-com-rest" -import * as bcl from "bitcoincashjs-lib" -import { Address } from "./Address" import { REST_URL } from "./BITBOX" -import { BitcoinCash } from "./BitcoinCash" -import { ECPair } from "./ECPair" -import { RawTransactions } from "./RawTransactions" -import { TransactionBuilder } from "./TransactionBuilder" export interface AddressDetails { isvalid: boolean @@ -23,16 +15,8 @@ export interface AddressDetails { export class Util { public restURL: string - public address: Address - public ecPair: ECPair - public bitcoinCash: BitcoinCash - public rawTransactions: RawTransactions constructor(restURL: string = REST_URL) { this.restURL = restURL - this.address = new Address(restURL) - this.ecPair = new ECPair(this.address) - this.bitcoinCash = new BitcoinCash(this.address) - this.rawTransactions = new RawTransactions(restURL) } public async validateAddress( address: string | string[] @@ -61,106 +45,4 @@ export class Util { else throw error } } - // Sweep a private key in compressed WIF format and sends funds to another - // address. - // Passing in optional balanceOnly flag will return just the balance without - // actually moving the funds. - // Or 0 if no funds are found, otherwise: - // Returns an object containing the amount of BCH swept from address, - // and the txid of the generated transaction that swept the funds. - async sweep(wif: string, toAddr: string, balanceOnly: boolean = false) { - try { - // Input validation - if (!wif || wif === "") { - throw new Error( - `wif private key must be included in Compressed WIF format.` - ) - } - // Input validation - if (!balanceOnly) { - if (!toAddr || toAddr === "") { - throw new Error( - `Address to receive swept funds must be included unless balanceOnly flag is true.` - ) - } - } - // Generate a keypair from the WIF. - const keyPair: bcl.ECPair = this.ecPair.fromWIF(wif) - - // Generate the public address associated with the private key. - const fromAddr: string = this.ecPair.toCashAddress(keyPair) - - // Check the BCH balance of that public address. - const details = (await this.address.details( - fromAddr - )) as AddressDetailsResult - const balance: number = details.balance - - // If balance is zero or balanceOnly flag is passed in, exit. - if (balance === 0 || balanceOnly) return balance - - // Get UTXOs associated with public address. - const u = (await this.address.utxo(fromAddr)) as AddressUtxoResult - const utxos: utxo[] = u.utxos - - // Prepare to generate a transaction to sweep funds. - - const transactionBuilder: TransactionBuilder = new TransactionBuilder( - this.address.detectAddressNetwork(fromAddr) - ) - let originalAmount: number = 0 - - // Add all UTXOs to the transaction inputs. - for (let i: number = 0; i < utxos.length; i++) { - const utxo: utxo = utxos[i] - originalAmount = originalAmount + utxo.satoshis - transactionBuilder.addInput(utxo.txid, utxo.vout) - } - - if (originalAmount < 1) - throw new Error(`Original amount is zero. No BCH to send.`) - - // get byte count to calculate fee. paying 1.1 sat/byte - const byteCount: number = this.bitcoinCash.getByteCount( - { P2PKH: utxos.length }, - { P2PKH: 1 } - ) - const fee: number = Math.ceil(1.1 * byteCount) - - // amount to send to receiver. It's the original amount - 1 sat/byte for tx size - const sendAmount: number = originalAmount - fee - - // add output w/ address and amount to send - transactionBuilder.addOutput( - this.address.toLegacyAddress(toAddr), - sendAmount - ) - - // Loop through each input and sign it with the private key. - let redeemScript: undefined - for (let i: number = 0; i < utxos.length; i++) { - const utxo = utxos[i] - transactionBuilder.sign( - i, - keyPair, - redeemScript, - transactionBuilder.hashTypes.SIGHASH_ALL, - utxo.satoshis - ) - } - - // build tx - const tx: any = transactionBuilder.build() - - // output rawhex - const hex: string = tx.toHex() - - // Broadcast the transaction to the BCH network. - let txid: string = await this.rawTransactions.sendRawTransaction(hex) - return txid - } catch (error) { - if (error.response && error.response.data) throw error.response.data - else throw error - } - } } diff --git a/package.json b/package.json index c12df039..5bdde140 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bitbox-sdk", - "version": "8.8.0", + "version": "8.10.1", "description": "BITBOX SDK for Bitcoin Cash", "author": "Gabriel Cardona ", "contributors": [ @@ -69,7 +69,7 @@ "@types/wif": "^2.0.1", "chai": "^4.1.2", "coveralls": "^3.0.2", - "eslint": "^5.5.0", + "eslint": "^5.16.0", "eslint-config-prettier": "^3.0.1", "eslint-plugin-node": "7.0.1", "eslint-plugin-prettier": "^2.6.2", @@ -78,7 +78,7 @@ "node-mocks-http": "^1.7.0", "nyc": "^14.1.1", "prettier": "^1.14.2", - "semantic-release": "^15.13.3", + "semantic-release": "^15.13.31", "sinon": "^4.5.0", "source-map-support": "^0.5.12", "ts-node": "^8.1.0", diff --git a/test/integration/address.js b/test/integration/address.js index 61782511..2536f17c 100644 --- a/test/integration/address.js +++ b/test/integration/address.js @@ -120,7 +120,7 @@ describe(`#address`, () => { describe(`#utxo`, () => { it(`should GET utxos for a single address`, async () => { - const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf" + const addr = "bitcoincash:qqm8uru433pjygm7q8przw9qw9pacvmvx5cngmqmue" const result = await bitbox.Address.utxo(addr) //console.log(`result: ${JSON.stringify(result, null, 2)}`) @@ -130,7 +130,8 @@ describe(`#address`, () => { "legacyAddress", "cashAddress", "scriptPubKey", - "slpAddress" + "slpAddress", + "asm" ]) assert.isArray(result.utxos) assert.hasAnyKeys(result.utxos[0], [ @@ -145,12 +146,12 @@ describe(`#address`, () => { it(`should GET utxo details for an array of addresses`, async () => { const addr = [ - "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf", + "bitcoincash:qqm8uru433pjygm7q8przw9qw9pacvmvx5cngmqmue", "bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v" ] const result = await bitbox.Address.utxo(addr) - //console.log(`result: ${JSON.stringify(result, null, 2)}`) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) assert.isArray(result) assert.hasAllKeys(result[0], [ @@ -158,7 +159,8 @@ describe(`#address`, () => { "legacyAddress", "cashAddress", "scriptPubKey", - "slpAddress" + "slpAddress", + "asm" ]) assert.isArray(result[0].utxos) assert.hasAnyKeys(result[0].utxos[0], [ @@ -215,7 +217,8 @@ describe(`#address`, () => { "legacyAddress", "cashAddress", "scriptPubKey", - "slpAddress" + "slpAddress", + "asm" ]) assert.isArray(result.utxos) }) @@ -235,7 +238,8 @@ describe(`#address`, () => { "legacyAddress", "cashAddress", "scriptPubKey", - "slpAddress" + "slpAddress", + "asm" ]) assert.isArray(result[0].utxos) }) diff --git a/test/integration/blockchain.js b/test/integration/blockchain.js index 7b401466..2d61c692 100644 --- a/test/integration/blockchain.js +++ b/test/integration/blockchain.js @@ -205,13 +205,46 @@ describe(`#blockchain`, () => { }) }) + describe(`#getTxOut`, () => { + it(`should get information on valid utxo`, async () => { + const txid = `91874bf385a36d54f06c2154b34bce887a03b99540bfddaa17ac78ebc65202d0` + + const result = await bitbox.Blockchain.getTxOut(txid, 0, true) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.hasAllKeys(result, [ + "bestblock", + "confirmations", + "value", + "scriptPubKey", + "coinbase" + ]) + assert.hasAllKeys(result.scriptPubKey, [ + "asm", + "hex", + "reqSigs", + "type", + "addresses" + ]) + }) + + it(`should return null for a spent utxo`, async () => { + const txid = `8db6dd4f8a5bb1308541d4a6d4ecdae6c65426679e79f783638ce32b2fb0725b` + + const result = await bitbox.Blockchain.getTxOut(txid, 0, true) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.equal(result, null) + }) + }) + describe(`#getTxOutProof`, () => { it(`should get single tx out proof`, async () => { const txid = "03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7" const result = await bitbox.Blockchain.getTxOutProof(txid) - //console.log(`result: ${JSON.stringify(result, null, 2)}`) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) assert.isString(result) }) @@ -223,7 +256,7 @@ describe(`#blockchain`, () => { ] const result = await bitbox.Blockchain.getTxOutProof(txid) - //console.log(`result: ${JSON.stringify(result, null, 2)}`) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) assert.isArray(result) assert.isString(result[0]) diff --git a/test/integration/other/README.md b/test/integration/other/README.md new file mode 100644 index 00000000..5c8068af --- /dev/null +++ b/test/integration/other/README.md @@ -0,0 +1,8 @@ +# Other Integration Tests + +This directory holds stand-alone integration tests that should not be part of +the integration test suite. + +An example of a test that fits this criteria are rate limit tests. Rate limit +tests are complex, require a solid internet connection, and can easily disrupt +other tests. For those reasons, it is better to run them on their own. diff --git a/test/integration/transaction.js b/test/integration/transaction.js index d36476f3..94b086b9 100644 --- a/test/integration/transaction.js +++ b/test/integration/transaction.js @@ -87,7 +87,7 @@ describe(`#Transaction`, () => { // console.log(`result: ${util.inspect(result)}`) assert.equal(false, false, "Unexpected result!") } catch (err) { - console.log(`err: ${util.inspect(err)}`) + // console.log(`err: ${util.inspect(err)}`) assert.hasAnyKeys(err, ["error"]) assert.include(err.error, "Array too large") diff --git a/test/integration/util.js b/test/integration/util.js index d7bb6da2..e2af5e2c 100644 --- a/test/integration/util.js +++ b/test/integration/util.js @@ -44,7 +44,7 @@ describe(`#util`, () => { assert.equal(result.isvalid, false) }) - it(`should return validate valid address`, async () => { + it(`should return a valid address`, async () => { const address = `bitcoincash:qp4k8fjtgunhdr7yq30ha4peuwupzan2vcnwrmpy0z` const result = await bitbox.Util.validateAddress(address) @@ -54,8 +54,6 @@ describe(`#util`, () => { "isvalid", "address", "scriptPubKey", - "ismine", - "iswatchonly", "isscript" ]) assert.equal(result.isvalid, true) @@ -75,8 +73,6 @@ describe(`#util`, () => { "isvalid", "address", "scriptPubKey", - "ismine", - "iswatchonly", "isscript" ]) }) @@ -112,19 +108,4 @@ describe(`#util`, () => { } }) }) - - describe("#sweep", () => { - it("should return balance only", async () => { - const wif = "L287yGQj4DB4fbUKSV7DMHsyGQs1qh2E3EYJ21P88mXNKaFvmNWk" - const result = await bitbox.Util.sweep(wif, "abc123", true) - console.log(`result: ${result}`) - }) - - it("should sweep funds", async () => { - const wif = "L287yGQj4DB4fbUKSV7DMHsyGQs1qh2E3EYJ21P88mXNKaFvmNWk" - const toAddr = "bitcoincash:qqjes5sxwneywmnzqndvs6p3l9rp55a2ug0e6e6s0a" - const result = await bitbox.Util.sweep(wif, toAddr) - console.log(`result: ${result}`) - }) - }) }) diff --git a/test/integration/z9-rate-limits.js b/test/integration/z9-rate-limits.js deleted file mode 100644 index 6e9c4653..00000000 --- a/test/integration/z9-rate-limits.js +++ /dev/null @@ -1,53 +0,0 @@ -/* - This test file should be run last as it will trigger the rate limits in - rest.bitcoin.com and no more calls to rest will be possible for about 1 minute - after this test is run. -*/ - -const chai = require("chai") -const assert = chai.assert - -const BITBOX = require("../../lib/BITBOX").BITBOX -let bitbox = new BITBOX() - -if (process.env.SERVER === "local") - bitbox = new BITBOX({ restURL: "http://localhost:3000/v2/" }) -if (process.env.SERVER === "stage") - bitbox = new BITBOX({ restURL: "https://rest.btctest.net/v2/" }) - -// Inspect utility used for debugging. -const util = require("util") -util.inspect.defaultOptions = { - showHidden: true, - colors: true, - depth: 3 -} - -describe("#rate-limits", () => { - it("should throw an error when RPM rate limits are triggered", async () => { - try { - const promises = [] - for (let i = 0; i < 300; i++) { - const promise = bitbox.Control.getInfo() - promises.push(promise) - } - - const temp = await Promise.all(promises) - - // console.log(`temp: ${util.inspect(temp)}`) - assert.equal(true, false, "Unexpected result!") - } catch (err) { - // Expected error response - if (err.error) { - assert.hasAnyKeys(err, ["error"]) - assert.include(err.error, "Too many requests") - - // Handle other types of error response. - } else { - console.log(`Unexpected error:`) - // console.log(`err: ${util.inspect(err)}`) - assert.equal(true, false, "Unexpected error") - } - } - }) -}) diff --git a/test/unit/Blockchain.ts b/test/unit/Blockchain.ts index dcb9f465..4ce9f2fa 100644 --- a/test/unit/Blockchain.ts +++ b/test/unit/Blockchain.ts @@ -8,6 +8,8 @@ import { REST_URL } from "../../lib/BITBOX" import * as util from "util" import { BlockHeaderResult } from "bitcoin-com-rest" +const mockData = require("./mocks/blockchain-mock") + // consts const bitbox: BITBOX = new BITBOX() const assert: Chai.AssertStatic = chai.assert @@ -347,7 +349,6 @@ describe("#Blockchain", (): void => { }) describe("#getTxOut", (): void => { - // TODO finish this test let sandbox: any beforeEach(() => (sandbox = sinon.sandbox.create())) afterEach(() => sandbox.restore()) @@ -355,19 +356,54 @@ describe("#Blockchain", (): void => { result: {} } - it("should get TODO", done => { - const resolved = new Promise(r => r({ data: data })) - sandbox.stub(axios, "get").returns(resolved) + it("should throw an error for improper txid.", async () => { + try { + await bitbox.Blockchain.getTxOut("badtxid", 0) + } catch (err) { + assert.include(err.message, "txid needs to be a proper transaction ID") + } + }) - bitbox.Blockchain.getTxOut( - "daf58932cb91619304dd4cbd03c7202e89ad7d6cbd6e2209e5f64ce3b6ed7c88", + it("should throw an error if vout is not an integer.", async () => { + try { + await bitbox.Blockchain.getTxOut( + "daf58932cb91619304dd4cbd03c7202e89ad7d6cbd6e2209e5f64ce3b6ed7c88", 'a' + ) + } catch (err) { + assert.include(err.message, "n must be an integer") + } + }) + + it("should get information on an unspent tx", async () => { + sandbox.stub(axios, "get").resolves({ data: mockData.txOutUnspent }) + + const result = await bitbox.Blockchain.getTxOut( + "62a3ea958a463a372bc0caf2c374a7f60be9c624be63a0db8db78f05809df6d8", 0, true ) - .then((result: any) => { - assert.deepEqual(data, result) - }) - .then(done, done) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.hasAllKeys(result, [ + "bestblock", + "confirmations", + "value", + "scriptPubKey", + "coinbase" + ]) + }) + + it("should get information on a spent tx", async () => { + sandbox.stub(axios, "get").resolves({ data: null }) + + const result = await bitbox.Blockchain.getTxOut( + "87380e52d151856b23173d6d8a3db01b984c6b50f77ea045a5a1cf4f54497871", + 0, + true + ) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.equal(result, null) }) }) diff --git a/test/unit/mocks/blockchain-mock.js b/test/unit/mocks/blockchain-mock.js index 1e73c0b4..17b7c43a 100644 --- a/test/unit/mocks/blockchain-mock.js +++ b/test/unit/mocks/blockchain-mock.js @@ -31,5 +31,21 @@ module.exports = { "0000002086a4a3161f9ba2174883ec0b93acceac3b2f37b36ed1f90000000000000000009cb02406d1094ecf3e0b4c0ca7c585125e721147c39daf6b48c90b512741e13a12333e5cb38705180f441d8c7100000008fee9b60f1edb57e5712839186277ed39e0a004a32be9096ee47472efde8eae62f789f9d7a9f59d0ea7093dea1e0c65ff0b953f1d8cf3d47f92e732ca0295f603c272d5f4a63509f7a887f2549d78af7444aa0ecbb4f66d9cbe13bc6a89f59e05a199df8325d490818ffefe6b6321d32d7496a68580459836c0183f89082fc1b491cc91b23ecdcaa4c347bf599a62904d61f1c15b400ebbd5c90149010c139d9c1e31b774b796977393a238080ab477e1d240d0c4f155d36f519668f49bae6bd8cd5b8e40522edf76faa09cca6188d83ff13af6967cc6a569d1a5e9aeb1fdb7f531ddd2d0cbb81879741d5f38166ac1932136264366a4065cc96a42e41f96294f02df01", verifiedProof: - "03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7" + "03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7", + + txOutUnspent: { + bestblock: + "000000000000000000b441e02f5b1b9f5b3def961047afcc6f2f5636c952705e", + confirmations: 2, + value: 0.00006, + scriptPubKey: { + asm: + "OP_DUP OP_HASH160 d19fae66b685f5c3633c0db0600313918347225f OP_EQUALVERIFY OP_CHECKSIG", + hex: "76a914d19fae66b685f5c3633c0db0600313918347225f88ac", + reqSigs: 1, + type: "pubkeyhash", + addresses: ["bitcoincash:qrgeltnxk6zltsmr8sxmqcqrzwgcx3eztusrwgf0x3"] + }, + coinbase: false + } }