mirror of
https://github.com/Permissionless-Software-Foundation/bch-js.git
synced 2026-09-22 00:52:01 -07:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a50ace320b | ||
|
|
b1d583cfe4 | ||
|
|
0b86a19726 | ||
|
|
eb3bc7bcff | ||
|
|
c5361e0516 | ||
|
|
54d9233f41 | ||
|
|
37a5f0e6fa | ||
|
|
2180b14e1f | ||
|
|
40e1704572 | ||
|
|
9539119c57 | ||
|
|
b397381c7d | ||
|
|
6cdb9a0867 | ||
|
|
01f45d7103 | ||
|
|
ba38d3e107 | ||
|
|
cbb0d0a8ca | ||
|
|
7ec8442540 | ||
|
|
be3094fc77 | ||
|
|
d35f0e5473 | ||
|
|
79088fc68d | ||
|
|
fe84729737 | ||
|
|
2ec72e73c1 | ||
|
|
a2c121bf3b | ||
|
|
fd6f58fd45 | ||
|
|
e8b2f88ff5 | ||
|
|
4a11db7c45 | ||
|
|
af118f8a62 | ||
|
|
1f41b67e3b | ||
|
|
054fb9c14e | ||
|
|
1fd4095dcb | ||
|
|
0eb1f74ba1 | ||
|
|
1a13c41c22 | ||
|
|
8b6952b1d4 | ||
|
|
73dd2c010d | ||
|
|
70743876d2 | ||
|
|
ab51afb2a8 | ||
|
|
8a59374831 | ||
|
|
32b8efa7a2 | ||
|
|
b0bdc50193 | ||
|
|
0a897f19bb | ||
|
|
d8e746acd9 | ||
|
|
47bd0d66bc | ||
|
|
6a4a861c07 | ||
|
|
caee2db99e | ||
|
|
392f51b166 | ||
|
|
8facfd69ac | ||
|
|
7f1b87215c | ||
|
|
662e53aaa2 | ||
|
|
98fc4b9530 | ||
|
|
de8c8e6284 | ||
|
|
739bdf1f34 | ||
|
|
b207a1639e | ||
|
|
a169c0f7d0 | ||
|
|
65cf49adf0 | ||
|
|
65104d60ad | ||
|
|
fd0a1a6af2 | ||
|
|
25299e2f6e | ||
|
|
b184c080f1 |
+1
-1
@@ -27,4 +27,4 @@ deploy:
|
||||
provider: script
|
||||
skip_cleanup: true
|
||||
script:
|
||||
- npx semantic-release
|
||||
- npx semantic-release && ./deploy-production.sh
|
||||
|
||||
Executable
+14
@@ -0,0 +1,14 @@
|
||||
# Triggers a webhook to update the staging server at staging.fullstack.cash.
|
||||
|
||||
#!/bin/bash
|
||||
#echo $DEPLOY_SECRET
|
||||
|
||||
echo "Deploy to production...."
|
||||
|
||||
export DATA="{\"ref\":\"$DEPLOY_SECRET\"}"
|
||||
|
||||
#echo $DATA
|
||||
|
||||
curl -X POST http://fullstack.cash:9000/hooks/bch-js -H "Content-Type: application/json" -d $DATA
|
||||
|
||||
echo "...Finished deploying to production."
|
||||
+2
-1
@@ -14,8 +14,9 @@
|
||||
"test:integration:local": "RESTURL=http://localhost:3000/v3/ mocha --timeout 30000 test/integration",
|
||||
"test:integration:testnet:local": "RESTURL=http://localhost:4000/v3/ mocha --timeout 30000 test/integration/testnet",
|
||||
"test:integration:free": "bash test/integration/test-free-tier.sh",
|
||||
"test:integration:free:bchn": "bash test/integration/test-free-tier-bchn.sh",
|
||||
"test:integration:free:testnet": "bash test/integration/testnet/test-free-tier.sh",
|
||||
"test:temp": "mocha --timeout 30000 test/integration/testnet/ninsight.js",
|
||||
"test:temp": "mocha --timeout 30000 -g '#price' test/integration/",
|
||||
"test:integration:api": "RESTURL=https://api.fullstack.cash/v3/ mocha --timeout 30000 test/integration",
|
||||
"coverage": "nyc report --reporter=text-lcov | coveralls",
|
||||
"coverage:report": "nyc --reporter=html mocha --timeout 25000 test/unit/",
|
||||
|
||||
+17
-17
@@ -14,7 +14,7 @@ class Address {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Address.toLegacyAddress() toLegacyAddress() - Convert to Legacy Address
|
||||
* @api Address.toLegacyAddress() toLegacyAddress()
|
||||
* @apiName toLegacyAddress
|
||||
* @apiGroup Address
|
||||
* @apiDescription Convert cashaddr to legacy address format
|
||||
@@ -73,7 +73,7 @@ class Address {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Address.toCashAddress() toCashAddress() - Convert to bitcoincash: format
|
||||
* @api Address.toCashAddress() toCashAddress()
|
||||
* @apiName toCashAddress
|
||||
* @apiGroup Address
|
||||
* @apiDescription Convert legacy to cashAddress format
|
||||
@@ -120,7 +120,7 @@ class Address {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Address.hash160ToLegacy() hash160ToLegacy() - Convert hash160 to legacy address.
|
||||
* @api Address.hash160ToLegacy() hash160ToLegacy()
|
||||
* @apiName hash160ToLegacy
|
||||
* @apiGroup Address
|
||||
* @apiDescription Convert hash160 to legacy address.
|
||||
@@ -146,7 +146,7 @@ class Address {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Address.hash160ToCash() hash160ToCash() - Convert hash160 to cash address.
|
||||
* @api Address.hash160ToCash() hash160ToCash()
|
||||
* @apiName hash160ToCash
|
||||
* @apiGroup Address
|
||||
* @apiDescription Convert hash160 to cash address.
|
||||
@@ -255,7 +255,7 @@ class Address {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Address.isLegacyAddress() isLegacyAddress() - Detect if legacy address.
|
||||
* @api Address.isLegacyAddress() isLegacyAddress()
|
||||
* @apiName isLegacyAddress
|
||||
* @apiGroup Address
|
||||
* @apiDescription Detect if legacy base58check encoded address.
|
||||
@@ -291,7 +291,7 @@ class Address {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Address.isCashAddress() isCashAddress() - Detect if cashAddr address.
|
||||
* @api Address.isCashAddress() isCashAddress()
|
||||
* @apiName isCashAddress
|
||||
* @apiGroup Address
|
||||
* @apiDescription Detect if cashAddr encoded address.
|
||||
@@ -326,7 +326,7 @@ class Address {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Address.isHash160() isHash160() - Detect if an addess is a hash160.
|
||||
* @api Address.isHash160() isHash160()
|
||||
* @apiName isHash160
|
||||
* @apiGroup Address
|
||||
* @apiDescription Detect if an addess is a hash160.
|
||||
@@ -345,7 +345,7 @@ class Address {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Address.isMainnetAddress() isMainnetAddress() - Detect if mainnet address.
|
||||
* @api Address.isMainnetAddress() isMainnetAddress()
|
||||
* @apiName isMainnetAddress
|
||||
* @apiGroup Address
|
||||
* @apiDescription Detect if mainnet address .
|
||||
@@ -384,7 +384,7 @@ class Address {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Address.isTestnetAddress() isTestnetAddress() - Detect if testnet address.
|
||||
* @api Address.isTestnetAddress() isTestnetAddress()
|
||||
* @apiName isTestnetAddress
|
||||
* @apiGroup Address
|
||||
* @apiDescription Detect if testnet address.
|
||||
@@ -422,7 +422,7 @@ class Address {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Address.isRegTestAddress() isRegTestAddress() - Detect if regtest address.
|
||||
* @api Address.isRegTestAddress() isRegTestAddress()
|
||||
* @apiName isRegTestAddress
|
||||
* @apiGroup Address
|
||||
* @apiDescription Detect if regtest address.
|
||||
@@ -461,7 +461,7 @@ class Address {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Address.isP2PKHAddress() isP2PKHAddress() - Detect if p2pkh address.
|
||||
* @api Address.isP2PKHAddress() isP2PKHAddress()
|
||||
* @apiName isP2PKHAddress
|
||||
* @apiGroup Address
|
||||
* @apiDescription Detect if p2pkh address.
|
||||
@@ -498,7 +498,7 @@ class Address {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Address.isP2SHAddress() isP2SHAddress() - Detect if p2sh address.
|
||||
* @api Address.isP2SHAddress() isP2SHAddress()
|
||||
* @apiName isP2SHAddress
|
||||
* @apiGroup Address
|
||||
* @apiDescription Detect if p2sh address.
|
||||
@@ -534,7 +534,7 @@ class Address {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Address.detectAddressFormat() detectAddressFormat() - Detect address format.
|
||||
* @api Address.detectAddressFormat() detectAddressFormat()
|
||||
* @apiName detectAddressFormat
|
||||
* @apiGroup Address
|
||||
* @apiDescription Detect address format.
|
||||
@@ -572,7 +572,7 @@ class Address {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Address.detectAddressNetwork() detectAddressNetwork() - Detect address network.
|
||||
* @api Address.detectAddressNetwork() detectAddressNetwork()
|
||||
* @apiName detectAddressNetwork
|
||||
* @apiGroup Address
|
||||
* @apiDescription Detect address network.
|
||||
@@ -622,7 +622,7 @@ class Address {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Address.detectAddressType() detectAddressType() - Detect address type.
|
||||
* @api Address.detectAddressType() detectAddressType()
|
||||
* @apiName detectAddressType
|
||||
* @apiGroup Address
|
||||
* @apiDescription Detect address type.
|
||||
@@ -660,7 +660,7 @@ class Address {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Address.fromXPub() fromXPub() - Generates an address (xpub).
|
||||
* @api Address.fromXPub() fromXPub()
|
||||
* @apiName fromXPub
|
||||
* @apiGroup Address
|
||||
* @apiDescription Generates an address for an extended public key (xpub).
|
||||
@@ -698,7 +698,7 @@ class Address {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Address.fromOutputScript() fromOutputScript() - Detect an addess from an OutputScript..
|
||||
* @api Address.fromOutputScript() fromOutputScript()
|
||||
* @apiName fromOutputScript
|
||||
* @apiGroup Address
|
||||
* @apiDescription Detect an addess from an OutputScript..
|
||||
|
||||
+1
-1
@@ -90,7 +90,7 @@ class BCHJS {
|
||||
this.Generating = new Generating(libConfig)
|
||||
this.HDNode = new HDNode(this.Address)
|
||||
this.Mnemonic = new Mnemonic(this.Address)
|
||||
this.Price = new Price()
|
||||
this.Price = new Price(libConfig)
|
||||
this.Script = new Script()
|
||||
this.TransactionBuilder = TransactionBuilder
|
||||
this.TransactionBuilder.setAddress(this.Address)
|
||||
|
||||
+12
-12
@@ -15,7 +15,7 @@ class BitcoinCash {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api BitcoinCash.toSatoshi() toSatoshi() - Converting Bitcoin Cash units to satoshi units.
|
||||
* @api BitcoinCash.toSatoshi() toSatoshi()
|
||||
* @apiName toSatoshi
|
||||
* @apiGroup BitcoinCash
|
||||
* @apiDescription
|
||||
@@ -48,7 +48,7 @@ class BitcoinCash {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api BitcoinCash.toBitcoinCash() toBitcoinCash() - Converting satoshi units to Bitcoin Cash units.
|
||||
* @api BitcoinCash.toBitcoinCash() toBitcoinCash()
|
||||
* @apiName toBitcoinCash
|
||||
* @apiGroup BitcoinCash
|
||||
* @apiDescription
|
||||
@@ -81,7 +81,7 @@ class BitcoinCash {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api BitcoinCash.toBits() toBits() - Converting satoshi units to Bits denomination.
|
||||
* @api BitcoinCash.toBits() toBits()
|
||||
* @apiName toBits
|
||||
* @apiGroup BitcoinCash
|
||||
* @apiDescription
|
||||
@@ -133,7 +133,7 @@ class BitcoinCash {
|
||||
// }
|
||||
|
||||
/**
|
||||
* @api BitcoinCash.signMessageWithPrivKey() signMessageWithPrivKey() - Sign message with private key.
|
||||
* @api BitcoinCash.signMessageWithPrivKey() signMessageWithPrivKey()
|
||||
* @apiName signMessageWithPrivKey
|
||||
* @apiGroup BitcoinCash
|
||||
* @apiDescription
|
||||
@@ -165,7 +165,7 @@ class BitcoinCash {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api BitcoinCash.verifyMessage() verifyMessage() - Verify message.
|
||||
* @api BitcoinCash.verifyMessage() verifyMessage()
|
||||
* @apiName verifyMessage
|
||||
* @apiGroup BitcoinCash
|
||||
* @apiDescription
|
||||
@@ -189,7 +189,7 @@ class BitcoinCash {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api BitcoinCash.encodeBase58Check() encodeBase58Check() - Encodes hex string as base58Check.
|
||||
* @api BitcoinCash.encodeBase58Check() encodeBase58Check()
|
||||
* @apiName encodeBase58Check
|
||||
* @apiGroup BitcoinCash
|
||||
* @apiDescription
|
||||
@@ -227,7 +227,7 @@ class BitcoinCash {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api BitcoinCash.decodeBase58Check() decodeBase58Check() - Decodes base58Check encoded string to hex.
|
||||
* @api BitcoinCash.decodeBase58Check() decodeBase58Check()
|
||||
* @apiName decodeBase58Check
|
||||
* @apiGroup BitcoinCash
|
||||
* @apiDescription
|
||||
@@ -265,7 +265,7 @@ class BitcoinCash {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api BitcoinCash.encodeBIP21() encodeBIP21() - Encodes address and options as BIP21 uri.
|
||||
* @api BitcoinCash.encodeBIP21() encodeBIP21()
|
||||
* @apiName encodeBIP21
|
||||
* @apiGroup BitcoinCash
|
||||
* @apiDescription
|
||||
@@ -306,7 +306,7 @@ class BitcoinCash {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api BitcoinCash.decodeBIP21() decodeBIP21() - Decodes BIP21 uri.
|
||||
* @api BitcoinCash.decodeBIP21() decodeBIP21()
|
||||
* @apiName decodeBIP21
|
||||
* @apiGroup BitcoinCash
|
||||
* @apiDescription
|
||||
@@ -340,7 +340,7 @@ class BitcoinCash {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api BitcoinCash.getByteCount() getByteCount() - Get byte count of transaction.
|
||||
* @api BitcoinCash.getByteCount() getByteCount()
|
||||
* @apiName getByteCount
|
||||
* @apiGroup BitcoinCash
|
||||
* @apiDescription
|
||||
@@ -458,7 +458,7 @@ class BitcoinCash {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api BitcoinCash.encryptBIP38() encryptBIP38() - BIP38 encrypt privkey WIFs.
|
||||
* @api BitcoinCash.encryptBIP38() encryptBIP38()
|
||||
* @apiName encryptBIP38
|
||||
* @apiGroup BitcoinCash
|
||||
* @apiDescription
|
||||
@@ -486,7 +486,7 @@ class BitcoinCash {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api BitcoinCash.decryptBIP38() decryptBIP38() - BIP38 encrypt privkey WIFs.
|
||||
* @api BitcoinCash.decryptBIP38() decryptBIP38()
|
||||
* @apiName decryptBIP38
|
||||
* @apiGroup BitcoinCash
|
||||
* @apiDescription
|
||||
|
||||
+3
-3
@@ -24,7 +24,7 @@ class Blockbook {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Blockbook.balance() balance() - Balance about an address.
|
||||
* @api Blockbook.balance() balance()
|
||||
* @apiName Blockbook Balance
|
||||
* @apiGroup Blockbook
|
||||
* @apiDescription Return Balance about an address.
|
||||
@@ -221,7 +221,7 @@ class Blockbook {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Blockbook.utxo() utxo() - Get list of uxto for address.
|
||||
* @api Blockbook.utxo() utxo()
|
||||
* @apiName Blockbook Utxo
|
||||
* @apiGroup Blockbook
|
||||
* @apiDescription Return list of uxto for address.
|
||||
@@ -307,7 +307,7 @@ class Blockbook {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Blockbook.tx() tx() - Get details on a transaction.
|
||||
* @api Blockbook.tx() tx()
|
||||
* @apiName Blockbook Tx
|
||||
* @apiGroup Blockbook
|
||||
* @apiDescription Get details on a transaction.
|
||||
|
||||
+14
-14
@@ -23,7 +23,7 @@ class Blockchain {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Blockchain.getBestBlockHash() getBestBlockHash() - Returns the hash of the best (tip) block in the longest blockchain.
|
||||
* @api Blockchain.getBestBlockHash() getBestBlockHash()
|
||||
* @apiName getBestBlockHash
|
||||
* @apiGroup Blockchain
|
||||
* @apiDescription
|
||||
@@ -54,7 +54,7 @@ class Blockchain {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Blockchain.getBlock() getBlock() - Return information about block hash.
|
||||
* @api Blockchain.getBlock() getBlock()
|
||||
* @apiName getBlock
|
||||
* @apiGroup Blockchain
|
||||
* @apiDescription
|
||||
@@ -102,7 +102,7 @@ class Blockchain {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Blockchain.getBlockchainInfo() getBlockchainInfo() - Returns an object containing various state info regarding blockchain processing.
|
||||
* @api Blockchain.getBlockchainInfo() getBlockchainInfo()
|
||||
* @apiName getBlockchainInfo
|
||||
* @apiGroup Blockchain
|
||||
* @apiDescription
|
||||
@@ -152,7 +152,7 @@ class Blockchain {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Blockchain.getBlockCount() getBlockCount() - Returns the number of blocks in the longest blockchain.
|
||||
* @api Blockchain.getBlockCount() getBlockCount()
|
||||
* @apiName getBlockCount
|
||||
* @apiGroup Blockchain
|
||||
* @apiDescription
|
||||
@@ -183,7 +183,7 @@ class Blockchain {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Blockchain.getBlockHash() getBlockHash() - Returns hash of block in best-block-chain at height provided.
|
||||
* @api Blockchain.getBlockHash() getBlockHash()
|
||||
* @apiName getBlockHash
|
||||
* @apiGroup Blockchain
|
||||
* @apiDescription
|
||||
@@ -216,7 +216,7 @@ class Blockchain {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Blockchain.getBlockHeader() getBlockHeader() - Return information about blockheader hash.
|
||||
* @api Blockchain.getBlockHeader() getBlockHeader()
|
||||
* @apiName getBlockHeader
|
||||
* @apiGroup Blockchain
|
||||
* @apiDescription
|
||||
@@ -281,7 +281,7 @@ class Blockchain {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Blockchain.getChainTips() getChainTips() - Return information about all known tips in the block tree.
|
||||
* @api Blockchain.getChainTips() getChainTips()
|
||||
* @apiName getChainTips
|
||||
* @apiGroup Blockchain
|
||||
* @apiDescription
|
||||
@@ -324,7 +324,7 @@ class Blockchain {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Blockchain.getDifficulty() getDifficulty() - Returns the proof-of-work difficulty as a multiple of the minimum difficulty.
|
||||
* @api Blockchain.getDifficulty() getDifficulty()
|
||||
* @apiName getDifficulty
|
||||
* @apiGroup Blockchain
|
||||
* @apiDescription
|
||||
@@ -387,7 +387,7 @@ class Blockchain {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Blockchain.getMempoolEntry() getMempoolEntry() - Returns mempool data for given transaction.
|
||||
* @api Blockchain.getMempoolEntry() getMempoolEntry()
|
||||
* @apiName getMempoolEntry
|
||||
* @apiGroup Blockchain
|
||||
* @apiDescription
|
||||
@@ -499,7 +499,7 @@ class Blockchain {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Blockchain.getMempoolInfo() getMempoolInfo() - Returns details on the active state of the TX memory pool.
|
||||
* @api Blockchain.getMempoolInfo() getMempoolInfo()
|
||||
* @apiName getMempoolInfo
|
||||
* @apiGroup Blockchain
|
||||
* @apiDescription
|
||||
@@ -535,7 +535,7 @@ class Blockchain {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Blockchain.getRawMempool() getRawMempool() - Returns all transaction ids in memory pool as a json array of string transaction ids.
|
||||
* @api Blockchain.getRawMempool() getRawMempool()
|
||||
* @apiName getRawMempool
|
||||
* @apiGroup Blockchain
|
||||
* @apiDescription
|
||||
@@ -582,7 +582,7 @@ class Blockchain {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Blockchain.getTxOut() getTxOut() - Returns details about an unspent transaction output.
|
||||
* @api Blockchain.getTxOut() getTxOut()
|
||||
* @apiName getTxOut
|
||||
* @apiGroup Blockchain
|
||||
* @apiDescription
|
||||
@@ -634,7 +634,7 @@ class Blockchain {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Blockchain.getTxOutProof() getTxOutProof() - Returns a hex-encoded proof that "txid" was included in a block.
|
||||
* @api Blockchain.getTxOutProof() getTxOutProof()
|
||||
* @apiName getTxOutProof
|
||||
* @apiGroup Blockchain
|
||||
* @apiDescription
|
||||
@@ -740,7 +740,7 @@ class Blockchain {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Blockchain.verifyTxOutProof() verifyTxOutProof() - Verifies that a proof points to a transaction in a block.
|
||||
* @api Blockchain.verifyTxOutProof() verifyTxOutProof()
|
||||
* @apiName verifyTxOutProof
|
||||
* @apiGroup Blockchain
|
||||
* @apiDescription
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ class Control {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Control.getNetworkInfo() getNetworkInfo() - Get Network info
|
||||
* @api Control.getNetworkInfo() getNetworkInfo()
|
||||
* @apiName getNetworkInfo
|
||||
* @apiGroup Control
|
||||
* @apiDescription Returns an object containing various network info.
|
||||
|
||||
+5
-5
@@ -3,7 +3,7 @@ const Bitcoin = require("bitcoincashjs-lib")
|
||||
|
||||
class Crypto {
|
||||
/**
|
||||
* @api Crypto.sha256() sha256() - Utility for creating sha256 hash.
|
||||
* @api Crypto.sha256() sha256()
|
||||
* @apiName sha256
|
||||
* @apiGroup Crypto
|
||||
* @apiDescription Utility for creating sha256 hash digests of data
|
||||
@@ -31,7 +31,7 @@ class Crypto {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Crypto.ripemd160() ripemd160()-Utility for creating ripemd160 hash.
|
||||
* @api Crypto.ripemd160() ripemd160()
|
||||
* @apiName ripemd160
|
||||
* @apiGroup Crypto
|
||||
* @apiDescription Utility for creating ripemd160 hash digests of data
|
||||
@@ -57,7 +57,7 @@ class Crypto {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Crypto.hash256() hash256() - Utility for creating double sha256 hash.
|
||||
* @api Crypto.hash256() hash256()
|
||||
* @apiName hash256
|
||||
* @apiGroup Crypto
|
||||
* @apiDescription Utility for creating double sha256 hash digests of data.
|
||||
@@ -83,7 +83,7 @@ class Crypto {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Crypto.hash160() hash160() - Utility for creating ripemd160(sha256()) hash.
|
||||
* @api Crypto.hash160() hash160()
|
||||
* @apiName hash160
|
||||
* @apiGroup Crypto
|
||||
* @apiDescription Utility for creating ripemd160(sha256()) hash digests of data.
|
||||
@@ -109,7 +109,7 @@ class Crypto {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Crypto.randomBytes() randomBytes() - Generates cryptographically strong pseudo-random data.
|
||||
* @api Crypto.randomBytes() randomBytes()
|
||||
* @apiName randomBytes
|
||||
* @apiGroup Crypto
|
||||
* @apiDescription Generates cryptographically strong pseudo-random data. The size argument is a number indicating the number of bytes to generate.
|
||||
|
||||
+6
-6
@@ -6,7 +6,7 @@ class ECPair {
|
||||
ECPair._address = address
|
||||
}
|
||||
/**
|
||||
* @api Ecpair.fromWIF() fromWIF() - Generates an ECPair from a private key in wallet import format (WIF).
|
||||
* @api Ecpair.fromWIF() fromWIF()
|
||||
* @apiName fromWIF
|
||||
* @apiGroup ECPair
|
||||
* @apiDescription Generates an ECPair from a private key in wallet import format (WIF). Follow these steps to go from a private key to a WIF. This method only works with a compressed private key.
|
||||
@@ -35,7 +35,7 @@ class ECPair {
|
||||
return Bitcoin.ECPair.fromWIF(privateKeyWIF, bitcoincashBitcoinJSLib)
|
||||
}
|
||||
/**
|
||||
* @api Ecpair.toWIF() toWIF() - Gets a private key in wallet import format from an ECPair.
|
||||
* @api Ecpair.toWIF() toWIF()
|
||||
* @apiName toWIF
|
||||
* @apiGroup ECPair
|
||||
* @apiDescription Gets a private key in wallet import format from an ECPair.
|
||||
@@ -69,7 +69,7 @@ class ECPair {
|
||||
return ecpair.verify(buffer, signature)
|
||||
}
|
||||
/**
|
||||
* @api Ecpair.fromPublicKey() fromPublicKey() - Generates an ECPair from a public key buffer.
|
||||
* @api Ecpair.fromPublicKey() fromPublicKey()
|
||||
* @apiName fromPublicKey
|
||||
* @apiGroup ECPair
|
||||
* @apiDescription Generates an ECPair from a public key buffer.
|
||||
@@ -87,7 +87,7 @@ class ECPair {
|
||||
return Bitcoin.ECPair.fromPublicKeyBuffer(pubkeyBuffer)
|
||||
}
|
||||
/**
|
||||
* @api Ecpair.toPublicKey() toPublicKey() - Get the public key of an ECPair as a buffer.
|
||||
* @api Ecpair.toPublicKey() toPublicKey()
|
||||
* @apiName toPublicKey
|
||||
* @apiGroup ECPair
|
||||
* @apiDescription Get the public key of an ECPair as a buffer.
|
||||
@@ -109,7 +109,7 @@ class ECPair {
|
||||
return ecpair.getPublicKeyBuffer()
|
||||
}
|
||||
/**
|
||||
* @api Ecpair.toLegacyAddress() toLegacyAddress() - Get legacy address of ECPair.
|
||||
* @api Ecpair.toLegacyAddress() toLegacyAddress()
|
||||
* @apiName toLegacyAddress
|
||||
* @apiGroup ECPair
|
||||
* @apiDescription Get legacy address of ECPair.
|
||||
@@ -135,7 +135,7 @@ class ECPair {
|
||||
return ecpair.getAddress()
|
||||
}
|
||||
/**
|
||||
* @api Ecpair.toCashAddress() toCashAddress() - Get cash address of ECPair.
|
||||
* @api Ecpair.toCashAddress() toCashAddress()
|
||||
* @apiName toCashAddress
|
||||
* @apiGroup ECPair
|
||||
* @apiDescription Get cash address of ECPair.
|
||||
|
||||
+293
-3
@@ -24,7 +24,7 @@ class ElectrumX {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Electrumx.utxo() utxo() - Get a list of uxto for an address.
|
||||
* @api Electrumx.utxo() utxo()
|
||||
* @apiName ElectrumX Utxo
|
||||
* @apiGroup ElectrumX
|
||||
* @apiDescription Return a list of uxtos for an address.
|
||||
@@ -119,7 +119,7 @@ class ElectrumX {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Electrumx.balance() balance() - Get the balance for an address.
|
||||
* @api Electrumx.balance() balance()
|
||||
* @apiName ElectrumX Balance
|
||||
* @apiGroup ElectrumX
|
||||
* @apiDescription Return a list of balances for an address.
|
||||
@@ -203,7 +203,7 @@ class ElectrumX {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Electrumx.transactions() transactions() - Get the transaction history for an address.
|
||||
* @api Electrumx.transactions() transactions()
|
||||
* @apiName ElectrumX Transactions
|
||||
* @apiGroup ElectrumX
|
||||
* @apiDescription Return a transaction history for an address.
|
||||
@@ -299,6 +299,296 @@ class ElectrumX {
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Electrumx.unconfirmed() unconfirmed()
|
||||
* @apiName ElectrumX Unconfirmed
|
||||
* @apiGroup ElectrumX
|
||||
* @apiDescription Return a list of unconfirmed uxtos (mempool) for an address.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* (async () => {
|
||||
* try {
|
||||
* let mempool = await bchjs.Electrumx.unconfirmed('bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9');
|
||||
* console.log(mempool);
|
||||
* } catch(error) {
|
||||
* console.error(error)
|
||||
* }
|
||||
* })()
|
||||
*
|
||||
* mempool = {
|
||||
* "success": true,
|
||||
* "utxos": [
|
||||
* {
|
||||
* "height": 602405,
|
||||
* "tx_hash": "2b37bdb3b63dd0bca720437754a36671431a950e684b64c44ea910ea9d5297c7",
|
||||
* "fee": 24310
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
*
|
||||
* (async () => {
|
||||
* try {
|
||||
* let mempool = await bchjs.Electrumx.unconfirmed(['bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf', 'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v']);
|
||||
* console.log(mempool);
|
||||
* } catch(error) {
|
||||
* console.error(error)
|
||||
* }
|
||||
* })()
|
||||
*
|
||||
* mempool = {
|
||||
* "success": true,
|
||||
* "utxos": [
|
||||
* {
|
||||
* "utxos": [
|
||||
* {
|
||||
* "height": 604392,
|
||||
* "tx_hash": "7774e449c5a3065144cefbc4c0c21e6b69c987f095856778ef9f45ddd8ae1a41",
|
||||
* "fee": 24310
|
||||
* },
|
||||
* {
|
||||
* "height": 630834,
|
||||
* "tx_hash": "4fe60a51e0d8f5134bfd8e5f872d6e502d7f01b28a6afebb27f4438a4f638d53",
|
||||
* "fee": 3000
|
||||
* }
|
||||
* ],
|
||||
* "address": "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
|
||||
* },
|
||||
* {
|
||||
* "utxos": [],
|
||||
* "address": "bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
*
|
||||
*/
|
||||
async unconfirmed(address) {
|
||||
try {
|
||||
// Handle single address.
|
||||
if (typeof address === "string") {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}electrumx/unconfirmed/${address}`,
|
||||
_this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
|
||||
// Handle array of addresses.
|
||||
} else if (Array.isArray(address)) {
|
||||
const response = await axios.post(
|
||||
`${this.restURL}electrumx/unconfirmed`,
|
||||
{
|
||||
addresses: address
|
||||
},
|
||||
_this.axiosOptions
|
||||
)
|
||||
|
||||
return response.data
|
||||
}
|
||||
|
||||
throw new Error(`Input address must be a string or array of strings.`)
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Electrumx.blockHeader() blockHeader()
|
||||
* @apiName ElectrumX Block headers
|
||||
* @apiGroup ElectrumX
|
||||
* @apiDescription Return block headers for a given height
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* (async () => {
|
||||
* try {
|
||||
* let headers = await bchjs.Electrumx.blockHeaders(42);
|
||||
* console.log(headers);
|
||||
* } catch(error) {
|
||||
* console.error(error)
|
||||
* }
|
||||
* })()
|
||||
*
|
||||
* headers = {
|
||||
* "success": true,
|
||||
* "headers": [
|
||||
* "010000008b52bbd72c2f49569059f559c1b1794de5192e4f7d6d2b03c7482bad0000000083e4f8a9d502ed0c419075c1abb5d56f878a2e9079e5612bfb76a2dc37d9c42741dd6849ffff001d2b909dd6",
|
||||
* "01000000f528fac1bcb685d0cd6c792320af0300a5ce15d687c7149548904e31000000004e8985a786d864f21e9cbb7cbdf4bc9265fe681b7a0893ac55a8e919ce035c2f85de6849ffff001d385ccb7c"
|
||||
* ]
|
||||
* }
|
||||
*
|
||||
* (async () => {
|
||||
* try {
|
||||
* let headers = await bchjs.Electrumx.blockHeaders(42, 1);
|
||||
* console.log(headers);
|
||||
* } catch(error) {
|
||||
* console.error(error)
|
||||
* }
|
||||
* })()
|
||||
*
|
||||
* headers = {
|
||||
* "success": true,
|
||||
* "headers": [
|
||||
* "010000008b52bbd72c2f49569059f559c1b1794de5192e4f7d6d2b03c7482bad0000000083e4f8a9d502ed0c419075c1abb5d56f878a2e9079e5612bfb76a2dc37d9c42741dd6849ffff001d2b909dd6"
|
||||
* ]
|
||||
* }
|
||||
*
|
||||
*/
|
||||
async blockHeader(height, count = 1) {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}electrumx/block/headers/${height}?count=${count}`,
|
||||
_this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
// console.log("error: ", error)
|
||||
if (error.response && error.response.data) {
|
||||
if (error.response && error.response.data)
|
||||
throw new Error(error.response.data.error)
|
||||
else throw error.response.data
|
||||
} else {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Electrumx.txData() txData()
|
||||
* @apiName ElectrumX txData
|
||||
* @apiGroup ElectrumX
|
||||
* @apiDescription Returns an object with transaction details of the TXID
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* (async () => {
|
||||
* try {
|
||||
* let result = await bchjs.Electrumx.txData('4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251')
|
||||
* console.log(result);
|
||||
* } catch(error) {
|
||||
* console.error(error)
|
||||
* }
|
||||
* })()
|
||||
*
|
||||
* result = {
|
||||
* "success": true,
|
||||
* "details": {
|
||||
* "blockhash": "0000000000000000002aaf94953da3b487317508ebd1003a1d75d6d6ec2e75cc",
|
||||
* "blocktime": 1578327094,
|
||||
* "confirmations": 31861,
|
||||
* "hash": "4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251",
|
||||
* ...
|
||||
* "vin": [
|
||||
* {
|
||||
* "scriptSig": {
|
||||
* ...
|
||||
* "vout": [
|
||||
* {
|
||||
* "n": 0,
|
||||
* "scriptPubKey": {
|
||||
* "addresses": [
|
||||
* "bitcoincash: pqvfecpwxvj53ayqfwkxtjaxsgpvnklcyg8xewk9hl"
|
||||
* ],
|
||||
* }
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* (async () => {
|
||||
* try {
|
||||
* let result = await bchjs.Electrumx.txData(['4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251', '4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251'])
|
||||
* console.log(result);
|
||||
* } catch(error) {
|
||||
* console.error(error)
|
||||
* }
|
||||
* })()
|
||||
*
|
||||
* result = {
|
||||
* "transactions": [
|
||||
* {
|
||||
* "txid": "4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251",
|
||||
* "details": {
|
||||
* "blockhash": "0000000000000000002aaf94953da3b487317508ebd1003a1d75d6d6ec2e75cc",
|
||||
* "blocktime": 1578327094,
|
||||
* "confirmations": 31861,
|
||||
* "hash": "4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251",
|
||||
* ...
|
||||
* }
|
||||
* },
|
||||
* {
|
||||
* "txid": "4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251",
|
||||
* "details": {
|
||||
* "blockhash": "0000000000000000002aaf94953da3b487317508ebd1003a1d75d6d6ec2e75cc",
|
||||
* "blocktime": 1578327094,
|
||||
* ...
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
*/
|
||||
async txData(txid) {
|
||||
try {
|
||||
// Handle single transaction.
|
||||
if (typeof txid === "string") {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}electrumx/tx/data/${txid}`,
|
||||
_this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
} else if (Array.isArray(txid)) {
|
||||
const response = await axios.post(
|
||||
`${this.restURL}electrumx/tx/data`,
|
||||
{
|
||||
txids: txid
|
||||
},
|
||||
_this.axiosOptions
|
||||
)
|
||||
|
||||
return response.data
|
||||
}
|
||||
|
||||
throw new Error(`Input txId must be a string or array of strings.`)
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Electrumx.broadcast() broadcast()
|
||||
* @apiName ElectrumX Broadcast
|
||||
* @apiGroup ElectrumX
|
||||
* @apiDescription Broadcast a raw transaction and return the transaction ID on success or error on failure.
|
||||
*
|
||||
* (async () => {
|
||||
* try {
|
||||
* const txHex = "020000000265d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667010000006441dd1dd72770cadede1a7fd0363574846c48468a398ddfa41a9677c74cac8d2652b682743725a3b08c6c2021a629011e11a264d9036e9d5311e35b5f4937ca7b4e4121020797d8fd4d2fa6fd7cdeabe2526bfea2b90525d6e8ad506ec4ee3c53885aa309ffffffff65d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667000000006441347d7f218c11c04487c1ad8baac28928fb10e5054cd4494b94d078cfa04ccf68e064fb188127ff656c0b98e9ce87f036d183925d0d0860605877d61e90375f774121028a53f95eb631b460854fc836b2e5d31cad16364b4dc3d970babfbdcc3f2e4954ffffffff035ac355000000000017a914189ce02e332548f4804bac65cba68202c9dbf822878dfd0800000000001976a914285bb350881b21ac89724c6fb6dc914d096cd53b88acf9ef3100000000001976a91445f1f1c4a9b9419a5088a3e9c24a293d7a150e6488ac00000000"
|
||||
* let result = await bchjs.Electrumx.broadcast(txHex)
|
||||
* console.log(result);
|
||||
* } catch(error) {
|
||||
* console.error(error)
|
||||
* }
|
||||
* })()
|
||||
*
|
||||
* result = {
|
||||
* "success": true,
|
||||
* "txid": "..."
|
||||
* }
|
||||
*/
|
||||
async broadcast(txHex) {
|
||||
try {
|
||||
if (typeof txHex === "string") {
|
||||
const response = await axios.post(
|
||||
`${this.restURL}electrumx/tx/broadcast`,
|
||||
{ txHex },
|
||||
_this.axiosOptions
|
||||
)
|
||||
|
||||
return response.data
|
||||
}
|
||||
|
||||
throw new Error(`Input txHex must be a string.`)
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ElectrumX
|
||||
|
||||
+21
-21
@@ -9,7 +9,7 @@ class HDNode {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api HDNode.fromSeed() fromSeed() - Create HDNode from Seed Buffer.
|
||||
* @api HDNode.fromSeed() fromSeed()
|
||||
* @apiName fromSeed
|
||||
* @apiGroup HDNode
|
||||
* @apiDescription
|
||||
@@ -46,7 +46,7 @@ class HDNode {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api HDNode.toLegacyAddress() toLegacyAddress() - Get legacy address of HDNode.
|
||||
* @api HDNode.toLegacyAddress() toLegacyAddress()
|
||||
* @apiName toLegacyAddress
|
||||
* @apiGroup HDNode
|
||||
* @apiDescription
|
||||
@@ -80,7 +80,7 @@ class HDNode {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api HDNode.toCashAddress() toCashAddress() - Get cash address of HDNode
|
||||
* @api HDNode.toCashAddress() toCashAddress()
|
||||
* @apiName toCashAddress
|
||||
* @apiGroup HDNode
|
||||
* @apiDescription
|
||||
@@ -114,9 +114,9 @@ class HDNode {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api SLP.HDNode.toSLPAddress() toSLPAddress() - Get slp address of HDNode.
|
||||
* @api SLP.HDNode.toSLPAddress() toSLPAddress()
|
||||
* @apiName toSLPAddress
|
||||
* @apiGroup SLP
|
||||
* @apiGroup HDNode
|
||||
* @apiDescription Get slp address of HDNode.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
@@ -148,7 +148,7 @@ class HDNode {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api HDNode.toWIF() toWIF() - Get private key in wallet import format (WIF) of HDNode.
|
||||
* @api HDNode.toWIF() toWIF()
|
||||
* @apiName toWIF
|
||||
* @apiGroup HDNode
|
||||
* @apiDescription
|
||||
@@ -182,7 +182,7 @@ class HDNode {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api HDNode.toXPub() toXPub() - Get extended public key of HDNode.
|
||||
* @api HDNode.toXPub() toXPub()
|
||||
* @apiName toXPub
|
||||
* @apiGroup HDNode
|
||||
* @apiDescription
|
||||
@@ -216,7 +216,7 @@ class HDNode {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api HDNode.toXPriv() toXPriv() - Get extended private key of HDNode.
|
||||
* @api HDNode.toXPriv() toXPriv()
|
||||
* @apiName toXPriv
|
||||
* @apiGroup HDNode
|
||||
* @apiDescription
|
||||
@@ -250,7 +250,7 @@ class HDNode {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api HDNode.toKeyPair() toKeyPair() - Get the ECPair of an HDNode.
|
||||
* @api HDNode.toKeyPair() toKeyPair()
|
||||
* @apiName toKeyPair
|
||||
* @apiGroup HDNode
|
||||
* @apiDescription
|
||||
@@ -282,7 +282,7 @@ class HDNode {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api HDNode.toPublicKey() toPublicKey() - Get the public key of an HDNode as a buffer.
|
||||
* @api HDNode.toPublicKey() toPublicKey()
|
||||
* @apiName toPublicKey
|
||||
* @apiGroup HDNode
|
||||
* @apiDescription
|
||||
@@ -316,7 +316,7 @@ class HDNode {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api HDNode.fromXPriv() fromXPriv() - Generate HDNode from extended private key.
|
||||
* @api HDNode.fromXPriv() fromXPriv()
|
||||
* @apiName fromXPriv
|
||||
* @apiGroup HDNode
|
||||
* @apiDescription
|
||||
@@ -339,7 +339,7 @@ class HDNode {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api HDNode.fromXPub() fromXPub() - Generate HDNode from extended public key.
|
||||
* @api HDNode.fromXPub() fromXPub()
|
||||
* @apiName fromXPub
|
||||
* @apiGroup HDNode
|
||||
* @apiDescription
|
||||
@@ -362,7 +362,7 @@ class HDNode {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api HDNode.derivePath() derivePath() - Derive child HDNode from path.
|
||||
* @api HDNode.derivePath() derivePath()
|
||||
* @apiName derivePath
|
||||
* @apiGroup HDNode
|
||||
* @apiDescription
|
||||
@@ -383,7 +383,7 @@ class HDNode {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api HDNode.derive() derive() - Derive non hardened child HDNode.
|
||||
* @api HDNode.derive() derive()
|
||||
* @apiName derive
|
||||
* @apiGroup HDNode
|
||||
* @apiDescription
|
||||
@@ -404,7 +404,7 @@ class HDNode {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api HDNode.deriveHardened() deriveHardened() - Derive hardened child HDNode.
|
||||
* @api HDNode.deriveHardened() deriveHardened()
|
||||
* @apiName deriveHardened
|
||||
* @apiGroup HDNode
|
||||
* @apiDescription
|
||||
@@ -425,7 +425,7 @@ class HDNode {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api HDNode.sign() sign() - Sign 32 byte hash encoded as a buffer.
|
||||
* @api HDNode.sign() sign()
|
||||
* @apiName sign
|
||||
* @apiGroup HDNode
|
||||
* @apiDescription
|
||||
@@ -455,7 +455,7 @@ class HDNode {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api HDNode.verify() verify() - Verify signed 32 byte hash encoded as a buffer.
|
||||
* @api HDNode.verify() verify()
|
||||
* @apiName verify
|
||||
* @apiGroup HDNode
|
||||
* @apiDescription
|
||||
@@ -499,7 +499,7 @@ class HDNode {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api HDNode.isPublic() isPublic() - Check if an HDNode can only derive public keys and children.
|
||||
* @api HDNode.isPublic() isPublic()
|
||||
* @apiName isPublic
|
||||
* @apiGroup HDNode
|
||||
* @apiDescription
|
||||
@@ -535,7 +535,7 @@ class HDNode {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api HDNode.isPrivate() isPrivate() - Check if an HDNode can derive both public and private keys and children.
|
||||
* @api HDNode.isPrivate() isPrivate()
|
||||
* @apiName isPrivate
|
||||
* @apiGroup HDNode
|
||||
* @apiDescription
|
||||
@@ -571,7 +571,7 @@ class HDNode {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api HDNode.toIdentifier() toIdentifier() - hash160 of Node’s public key.
|
||||
* @api HDNode.toIdentifier() toIdentifier()
|
||||
* @apiName toIdentifier
|
||||
* @apiGroup HDNode
|
||||
* @apiDescription
|
||||
@@ -607,7 +607,7 @@ class HDNode {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api HDNode.createAccount() createAccount() - Create BIP32 account.
|
||||
* @api HDNode.createAccount() createAccount()
|
||||
* @apiName createAccount
|
||||
* @apiGroup HDNode
|
||||
* @apiDescription
|
||||
|
||||
+5
-5
@@ -53,7 +53,7 @@ class IPFS {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api IPFS.createFileModelServer() createFileModelServer() - Create a file model
|
||||
* @api IPFS.createFileModelServer() createFileModelServer()
|
||||
* @apiName createFileModelServer()
|
||||
* @apiGroup IPFS
|
||||
* @apiDescription Creates a new model on the server. If successful, will
|
||||
@@ -131,7 +131,7 @@ class IPFS {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api IPFS.uploadFileServer() uploadFileServer() - Upload a file to IPFS
|
||||
* @api IPFS.uploadFileServer() uploadFileServer()
|
||||
* @apiName uploadFile()
|
||||
* @apiGroup IPFS
|
||||
* @apiDescription Upload a file to the FullStack.cash IPFS server. If
|
||||
@@ -219,7 +219,7 @@ class IPFS {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api IPFS.getStatus() getStatus() - Check status of file upload
|
||||
* @api IPFS.getStatus() getStatus()
|
||||
* @apiName getStatus()
|
||||
* @apiGroup IPFS
|
||||
* @apiDescription Gets the status of the uploaded file. Will return an object
|
||||
@@ -271,7 +271,7 @@ class IPFS {
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @api IPFS.createFileModelWeb() createFileModelWeb() - Create a file model
|
||||
* @api IPFS.createFileModelWeb() createFileModelWeb()
|
||||
* @apiName createFileModelWeb()
|
||||
* @apiGroup IPFS
|
||||
* @apiDescription Creates a new model on the server. If successful, will
|
||||
@@ -348,7 +348,7 @@ class IPFS {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api IPFS.uploadFileWeb() uploadFileWeb() - Upload a file to IPFS
|
||||
* @api IPFS.uploadFileWeb() uploadFileWeb()
|
||||
* @apiName uploadFileWeb()
|
||||
* @apiGroup IPFS
|
||||
* @apiDescription Upload a file to the FullStack.cash IPFS server. If
|
||||
|
||||
+8
-8
@@ -10,7 +10,7 @@ class Mnemonic {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Mnemonic.generate() generate() - Generate BIP39 mnemonic from entropy.
|
||||
* @api Mnemonic.generate() generate()
|
||||
* @apiName generate
|
||||
* @apiGroup Mnemonic
|
||||
* @apiDescription
|
||||
@@ -50,7 +50,7 @@ class Mnemonic {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Mnemonic.fromEntropy() fromEntropy() - Create mnemonic from entropy.
|
||||
* @api Mnemonic.fromEntropy() fromEntropy()
|
||||
* @apiName fromEntropy
|
||||
* @apiGroup Mnemonic
|
||||
* @apiDescription
|
||||
@@ -104,7 +104,7 @@ class Mnemonic {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Mnemonic.toEntropy() toEntropy() - Turn mnemonic to entropy.
|
||||
* @api Mnemonic.toEntropy() toEntropy()
|
||||
* @apiName toEntropy
|
||||
* @apiGroup Mnemonic
|
||||
* @apiDescription
|
||||
@@ -141,7 +141,7 @@ class Mnemonic {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Mnemonic.validate() validate() - Validate mnemonic.
|
||||
* @api Mnemonic.validate() validate()
|
||||
* @apiName validate
|
||||
* @apiGroup Mnemonic
|
||||
* @apiDescription
|
||||
@@ -181,7 +181,7 @@ class Mnemonic {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Mnemonic.toSeed() toSeed() - Create root seed from mnemonic
|
||||
* @api Mnemonic.toSeed() toSeed()
|
||||
* @apiName toSeed
|
||||
* @apiGroup Mnemonic
|
||||
* @apiDescription
|
||||
@@ -208,7 +208,7 @@ class Mnemonic {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Mnemonic.wordLists() wordLists() - Return mnemonic word lists.
|
||||
* @api Mnemonic.wordLists() wordLists()
|
||||
* @apiName wordLists
|
||||
* @apiGroup Mnemonic
|
||||
* @apiDescription
|
||||
@@ -234,7 +234,7 @@ class Mnemonic {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Mnemonic.toKeypairs() toKeypairs() - Returns an array of privateKeyWIF/publicAddress pairs.
|
||||
* @api Mnemonic.toKeypairs() toKeypairs()
|
||||
* @apiName toKeypairs
|
||||
* @apiGroup Mnemonic
|
||||
* @apiDescription
|
||||
@@ -290,7 +290,7 @@ class Mnemonic {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Mnemonic.findNearestWord() findNearestWord() - Returns nearest matching word from provided word list.
|
||||
* @api Mnemonic.findNearestWord() findNearestWord()
|
||||
* @apiName findNearestWord
|
||||
* @apiGroup Mnemonic
|
||||
* @apiDescription
|
||||
|
||||
+2
-2
@@ -31,7 +31,7 @@ class Ninsight {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Ninsight.utxo() utxo() - Get list of uxto for address.
|
||||
* @api Ninsight.utxo() utxo()
|
||||
* @apiName Ninsight Utxo
|
||||
* @apiGroup Ninsight
|
||||
* @apiDescription Return list of uxto for address.
|
||||
@@ -69,7 +69,7 @@ class Ninsight {
|
||||
// Handle single address.
|
||||
if (typeof address === "string") {
|
||||
const response = await axios.post(
|
||||
`${this.ninsightURL}/address/utxo/${address}`,
|
||||
`${this.ninsightURL}/address/utxo`,
|
||||
{
|
||||
addresses: [address]
|
||||
},
|
||||
|
||||
+3
-3
@@ -23,7 +23,7 @@ class OpenBazaar {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api OpenBazaar.balance() balance() - Balance about an address.
|
||||
* @api OpenBazaar.balance() balance()
|
||||
* @apiName OpenBazaar Balance
|
||||
* @apiGroup OpenBazaar
|
||||
* @apiDescription Return Balance about an address.
|
||||
@@ -83,7 +83,7 @@ class OpenBazaar {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api OpenBazaar.utxo() utxo() - Get list of uxto for address.
|
||||
* @api OpenBazaar.utxo() utxo()
|
||||
* @apiName OpenBazaar Utxo
|
||||
* @apiGroup OpenBazaar
|
||||
* @apiDescription Return list of uxto for address.
|
||||
@@ -135,7 +135,7 @@ class OpenBazaar {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api OpenBazaar.tx() tx() - Get details on a transaction.
|
||||
* @api OpenBazaar.tx() tx()
|
||||
* @apiName OpenBazaar Tx
|
||||
* @apiGroup OpenBazaar
|
||||
* @apiDescription Get details on a transaction.
|
||||
|
||||
+125
-22
@@ -1,32 +1,135 @@
|
||||
const axios = require("axios")
|
||||
/**
|
||||
* @api price.current() current() - Get current price.
|
||||
* @apiName Price.
|
||||
* @apiGroup Price
|
||||
* @apiDescription Return current price of BCH in multiple currencies.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
*(async () => {
|
||||
* try {
|
||||
* let current = await bchjs.Price.current('usd');
|
||||
* console.log(current);
|
||||
* } catch(error) {
|
||||
* console.error(error)
|
||||
* }
|
||||
*})()
|
||||
*
|
||||
* // 26681
|
||||
*/
|
||||
|
||||
let _this
|
||||
|
||||
class Price {
|
||||
constructor(config) {
|
||||
_this = this
|
||||
|
||||
if (config) {
|
||||
this.restURL = config.restURL
|
||||
this.apiToken = config.apiToken
|
||||
}
|
||||
|
||||
// Add JWT token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: `Token ${this.apiToken}`
|
||||
}
|
||||
}
|
||||
|
||||
this.axios = axios
|
||||
}
|
||||
|
||||
/**
|
||||
* @api price.current() current()
|
||||
* @apiName Price.
|
||||
* @apiGroup Price
|
||||
* @apiDescription Return current price of BCH in multiple currencies.
|
||||
* This endpoint will be deprecated in favor of getUSD. It uses the Bitcoin.com
|
||||
* price feed.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
*(async () => {
|
||||
* try {
|
||||
* let current = await bchjs.Price.current('usd');
|
||||
* console.log(current);
|
||||
* } catch(err) {
|
||||
* console.err(err)
|
||||
* }
|
||||
*})()
|
||||
*
|
||||
* // 26681
|
||||
*/
|
||||
async current(currency = "usd") {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
const response = await this.axios.get(
|
||||
`https://index-api.bitcoin.com/api/v0/cash/price/${currency.toLowerCase()}`
|
||||
)
|
||||
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
|
||||
|
||||
return response.data.price
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
} catch (err) {
|
||||
if (err.response && err.response.data) throw err.response.data
|
||||
else throw err
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api price.getUsd() getUsd()
|
||||
* @apiName Price getUsd()
|
||||
* @apiGroup Price
|
||||
* @apiDescription Return current price of BCH in USD.
|
||||
* This endpoint gets the USD price of BCH from the Coinbase API. The price
|
||||
* comes from bch-api, so it has a better chance of working in Tor.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
*(async () => {
|
||||
* try {
|
||||
* let current = await bchjs.Price.getUsd();
|
||||
* console.log(current);
|
||||
* } catch(err) {
|
||||
* console.err(err)
|
||||
* }
|
||||
*})()
|
||||
*
|
||||
* // 266.81
|
||||
*/
|
||||
async getUsd() {
|
||||
try {
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}price/usd`,
|
||||
_this.axiosOptions
|
||||
)
|
||||
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
|
||||
|
||||
return response.data.usd
|
||||
} catch (err) {
|
||||
if (err.response && err.response.data) throw err.response.data
|
||||
else throw err
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api price.rates() rates()
|
||||
* @apiName Price rates()
|
||||
* @apiGroup Price
|
||||
* @apiDescription Return current price of BCH in several different currencies.
|
||||
* This endpoint gets the price of BCH from the Coinbase API in many different
|
||||
* currencies. The price
|
||||
* comes from bch-api, so it has a better chance of working in Tor.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
*(async () => {
|
||||
* try {
|
||||
* let current = await bchjs.Price.rates();
|
||||
* console.log(current);
|
||||
* } catch(err) {
|
||||
* console.err(err)
|
||||
* }
|
||||
*})()
|
||||
*
|
||||
* {
|
||||
* AED: "915.049218",
|
||||
* AFN: "19144.48874646",
|
||||
* ALGO: "826.6633482661356600405",
|
||||
* ...
|
||||
* ZRX: "644.844402797695193656",
|
||||
* ZWL: "80215.03"
|
||||
* }
|
||||
*/
|
||||
async rates() {
|
||||
try {
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}price/rates`,
|
||||
_this.axiosOptions
|
||||
)
|
||||
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
|
||||
|
||||
return response.data
|
||||
} catch (err) {
|
||||
if (err.response && err.response.data) throw err.response.data
|
||||
else throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ class RawTransactions {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api RawTransactions.decodeRawTransaction() decodeRawTransaction() - Return an Array of JSON objects representing the serialized, hex-encoded transactions.
|
||||
* @api RawTransactions.decodeRawTransaction() decodeRawTransaction()
|
||||
* @apiName decodeRawTransaction
|
||||
* @apiGroup RawTransactions
|
||||
* @apiDescription
|
||||
@@ -115,7 +115,7 @@ class RawTransactions {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api RawTransactions.decodeScript() decodeScript() - Decode hex-encoded scripts.
|
||||
* @api RawTransactions.decodeScript() decodeScript()
|
||||
* @apiName decodeScript
|
||||
* @apiGroup RawTransactions
|
||||
* @apiDescription
|
||||
@@ -182,7 +182,7 @@ class RawTransactions {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api RawTransactions.getRawTransaction() getRawTransaction() - Return the raw transaction data.
|
||||
* @api RawTransactions.getRawTransaction() getRawTransaction()
|
||||
* @apiName getRawTransaction
|
||||
* @apiGroup RawTransactions
|
||||
* @apiDescription
|
||||
@@ -279,7 +279,7 @@ class RawTransactions {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api RawTransactions.sendRawTransaction() sendRawTransaction() - Submits raw transaction (serialized, hex-encoded) to local node and network.
|
||||
* @api RawTransactions.sendRawTransaction() sendRawTransaction()
|
||||
* @apiName sendRawTransaction
|
||||
* @apiGroup RawTransactions
|
||||
* @apiDescription
|
||||
|
||||
+11
-11
@@ -14,7 +14,7 @@ class Schnorr {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Schnorr.sign() sign() - Sign a 32-byte message with the private key, returning a 64-byte signature.
|
||||
* @api Schnorr.sign() sign()
|
||||
* @apiName sign
|
||||
* @apiGroup Schnorr
|
||||
* @apiDescription
|
||||
@@ -41,7 +41,7 @@ class Schnorr {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Schnorr.verify() verify() - Verify a 64-byte signature of a 32-byte message against the public key.
|
||||
* @api Schnorr.verify() verify()
|
||||
* @apiName verify
|
||||
* @apiGroup Schnorr
|
||||
* @apiDescription
|
||||
@@ -73,7 +73,7 @@ class Schnorr {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Schnorr.batchVerify() batchVerify() - Verify a list of 64-byte signatures as a batch operation.
|
||||
* @api Schnorr.batchVerify() batchVerify()
|
||||
* @apiName batchVerify
|
||||
* @apiGroup Schnorr
|
||||
* @apiDescription
|
||||
@@ -135,7 +135,7 @@ class Schnorr {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Schnorr.nonInteractive() nonInteractive() - Aggregates multiple signatures of different private keys
|
||||
* @api Schnorr.nonInteractive() nonInteractive()
|
||||
* @apiName nonInteractive
|
||||
* @apiGroup Schnorr
|
||||
* @apiDescription
|
||||
@@ -184,7 +184,7 @@ class Schnorr {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Schnorr.computeEll() computeEll() - Generate ell which is the hash over all public keys participating in a session.
|
||||
* @api Schnorr.computeEll() computeEll()
|
||||
* @apiName computeEll
|
||||
* @apiGroup Schnorr
|
||||
* @apiDescription
|
||||
@@ -258,7 +258,7 @@ class Schnorr {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Schnorr.publicKeyCombine() publicKeyCombine() - Creates a special rogue-key-resistant.
|
||||
* @api Schnorr.publicKeyCombine() publicKeyCombine()
|
||||
* @apiName publicKeyCombine
|
||||
* @apiGroup Schnorr
|
||||
* @apiDescription
|
||||
@@ -276,7 +276,7 @@ class Schnorr {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Schnorr.sessionInitialize() sessionInitialize() - Creates a signing session.
|
||||
* @api Schnorr.sessionInitialize() sessionInitialize()
|
||||
* @apiName sessionInitialize
|
||||
* @apiGroup Schnorr
|
||||
* @apiDescription
|
||||
@@ -315,7 +315,7 @@ class Schnorr {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Schnorr.sessionNonceCombine() sessionNonceCombine() - Combines multiple nonces R_i into the combined nonce R.
|
||||
* @api Schnorr.sessionNonceCombine() sessionNonceCombine()
|
||||
* @apiName sessionNonceCombine
|
||||
* @apiGroup Schnorr
|
||||
* @apiDescription
|
||||
@@ -360,7 +360,7 @@ class Schnorr {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Schnorr.partialSign() partialSign() - Creates a partial signature s_i for a participant.
|
||||
* @api Schnorr.partialSign() partialSign()
|
||||
* @apiName partialSign
|
||||
* @apiGroup Schnorr
|
||||
* @apiDescription
|
||||
@@ -392,7 +392,7 @@ class Schnorr {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Schnorr.partialSignatureVerify() partialSignatureVerify() - Verifies a partial signature s_i against the participant's public key P_i.
|
||||
* @api Schnorr.partialSignatureVerify() partialSignatureVerify()
|
||||
* @apiName partialSignatureVerify
|
||||
* @apiGroup Schnorr
|
||||
* @apiDescription
|
||||
@@ -445,7 +445,7 @@ class Schnorr {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Schnorr.partialSignaturesCombine() partialSignaturesCombine() - Combines multiple partial signatures into a Schnorr signature.
|
||||
* @api Schnorr.partialSignaturesCombine() partialSignaturesCombine()
|
||||
* @apiName partialSignaturesCombine
|
||||
* @apiGroup Schnorr
|
||||
* @apiDescription
|
||||
|
||||
+11
-11
@@ -14,7 +14,7 @@ class Address extends BCHJSAddress {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api SLP.Address.toSLPAddress() toSLPAddress() - Converting to slpAddress format.
|
||||
* @api SLP.Address.toSLPAddress() toSLPAddress()
|
||||
* @apiName toSLPAddress
|
||||
* @apiGroup SLP
|
||||
* @apiDescription Converting legacy or cashaddr to slpAddress format.
|
||||
@@ -60,7 +60,7 @@ class Address extends BCHJSAddress {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api SLP.Address.toCashAddress() toCashAddress() - Converting to cashAddress format.
|
||||
* @api SLP.Address.toCashAddress() toCashAddress()
|
||||
* @apiName toCashAddress
|
||||
* @apiGroup SLP
|
||||
* @apiDescription Converting legacy or slpaddr to cashAddress format.
|
||||
@@ -106,7 +106,7 @@ class Address extends BCHJSAddress {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api SLP.Address.toLegacyAddress() toLegacyAddress() - Converting to legacy address format.
|
||||
* @api SLP.Address.toLegacyAddress() toLegacyAddress()
|
||||
* @apiName toLegacyAddress
|
||||
* @apiGroup SLP
|
||||
* @apiDescription Converting cashaddr or slpaddr to legacy address format.
|
||||
@@ -164,7 +164,7 @@ class Address extends BCHJSAddress {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api SLP.Address.isSLPAddress() isSLPAddress() - Detect if slpAddr encoded address.
|
||||
* @api SLP.Address.isSLPAddress() isSLPAddress()
|
||||
* @apiName isSLPAddress
|
||||
* @apiGroup SLP
|
||||
* @apiDescription Detect if slpAddr encoded address.
|
||||
@@ -201,7 +201,7 @@ class Address extends BCHJSAddress {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api SLP.Address.isMainnetAddress() isMainnetAddress() - Detect if mainnet address.
|
||||
* @api SLP.Address.isMainnetAddress() isMainnetAddress()
|
||||
* @apiName isMainnetAddress
|
||||
* @apiGroup SLP
|
||||
* @apiDescription Detect if mainnet address.
|
||||
@@ -255,7 +255,7 @@ class Address extends BCHJSAddress {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api SLP.Address.isTestnetAddress() isTestnetAddress() - Detect if testnet address.
|
||||
* @api SLP.Address.isTestnetAddress() isTestnetAddress()
|
||||
* @apiName isTestnetAddress
|
||||
* @apiGroup SLP
|
||||
* @apiDescription Detect if testnet address.
|
||||
@@ -307,7 +307,7 @@ class Address extends BCHJSAddress {
|
||||
return bchAddress.isTestnetAddress(cashAddr)
|
||||
}
|
||||
/**
|
||||
* @api SLP.Address.isP2PKHAddress() isP2PKHAddress() - Detect if p2pkh address.
|
||||
* @api SLP.Address.isP2PKHAddress() isP2PKHAddress()
|
||||
* @apiName isP2PKHAddress
|
||||
* @apiGroup SLP
|
||||
* @apiDescription Detect if p2pkh address.
|
||||
@@ -359,7 +359,7 @@ class Address extends BCHJSAddress {
|
||||
return bchAddress.isP2PKHAddress(cashAddr)
|
||||
}
|
||||
/**
|
||||
* @api SLP.Address.isP2SHAddress() isP2SHAddress() - Detect if p2sh address.
|
||||
* @api SLP.Address.isP2SHAddress() isP2SHAddress()
|
||||
* @apiName isP2SHAddress
|
||||
* @apiGroup SLP
|
||||
* @apiDescription Detect if p2sh address.
|
||||
@@ -411,7 +411,7 @@ class Address extends BCHJSAddress {
|
||||
return bchAddress.isP2SHAddress(cashAddr)
|
||||
}
|
||||
/**
|
||||
* @api SLP.Address.detectAddressFormat() detectAddressFormat() - Detect address format.
|
||||
* @api SLP.Address.detectAddressFormat() detectAddressFormat()
|
||||
* @apiName detectAddressFormat
|
||||
* @apiGroup SLP
|
||||
* @apiDescription Detect address format.
|
||||
@@ -464,7 +464,7 @@ class Address extends BCHJSAddress {
|
||||
return bchAddress.detectAddressFormat(address)
|
||||
}
|
||||
/**
|
||||
* @api SLP.Address.detectAddressNetwork() detectAddressNetwork() - Detect address network.
|
||||
* @api SLP.Address.detectAddressNetwork() detectAddressNetwork()
|
||||
* @apiName detectAddressNetwork
|
||||
* @apiGroup SLP
|
||||
* @apiDescription Detect address network.
|
||||
@@ -516,7 +516,7 @@ class Address extends BCHJSAddress {
|
||||
return bchAddress.detectAddressNetwork(cashAddr)
|
||||
}
|
||||
/**
|
||||
* @api SLP.Address.detectAddressType() detectAddressType() - Detect address type.
|
||||
* @api SLP.Address.detectAddressType() detectAddressType()
|
||||
* @apiName detectAddressType
|
||||
* @apiGroup SLP
|
||||
* @apiDescription Detect address type.
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ class ECPair extends BCHJSECPair {
|
||||
}
|
||||
*/
|
||||
/**
|
||||
* @api SLP.ECPair.toSLPAddress() toSLPAddress() - Get slp address of ECPair.
|
||||
* @api SLP.ECPair.toSLPAddress() toSLPAddress()
|
||||
* @apiName toSLPAddress
|
||||
* @apiGroup SLP
|
||||
* @apiDescription Get slp address of ECPair.
|
||||
|
||||
+322
-100
@@ -1,10 +1,10 @@
|
||||
const axios = require("axios")
|
||||
const slpParser = require("slp-parser")
|
||||
|
||||
const Script = require("../script")
|
||||
const scriptLib = new Script()
|
||||
// const Script = require("../script")
|
||||
// const scriptLib = new Script()
|
||||
|
||||
const BigNumber = require("bignumber.js")
|
||||
// const BigNumber = require("bignumber.js")
|
||||
|
||||
let _this
|
||||
|
||||
@@ -194,7 +194,7 @@ class Utils {
|
||||
path = `${this.restURL}slp/list`
|
||||
}
|
||||
|
||||
//console.log(`path: ${path}`)
|
||||
// console.log(`path: ${path}`)
|
||||
|
||||
try {
|
||||
let response
|
||||
@@ -316,7 +316,7 @@ class Utils {
|
||||
return response.data
|
||||
}
|
||||
|
||||
throw new Error(`Input address must be a string or array of strings.`)
|
||||
throw new Error("Input address must be a string or array of strings.")
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
throw error
|
||||
@@ -370,84 +370,6 @@ class Utils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api SLP.Utils.balance() balance()
|
||||
* @apiName balance
|
||||
* @apiGroup SLP Utils
|
||||
* @apiDescription Return single balance for an address by token id.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
*
|
||||
* // single balance for SLP Address
|
||||
* (async () => {
|
||||
* try {
|
||||
* let balance = await bchjs.SLP.Utils.balance(
|
||||
* "simpleledger:qr5agtachyxvrwxu76vzszan5pnvuzy8duhv4lxrsk",
|
||||
* "df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb"
|
||||
* );
|
||||
* console.log(balance);
|
||||
* } catch (error) {
|
||||
* console.error(error);
|
||||
* }
|
||||
* })();
|
||||
*
|
||||
* // returns
|
||||
* // { tokenId:
|
||||
* // 'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb',
|
||||
* // balance: '617',
|
||||
* // decimalCount: 8 }
|
||||
*
|
||||
* // single balance for Cash Address
|
||||
* (async () => {
|
||||
* try {
|
||||
* let balance = await bchjs.SLP.Utils.balance(
|
||||
* "bitcoincash:qr5agtachyxvrwxu76vzszan5pnvuzy8dumh7ynrwg",
|
||||
* "df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb"
|
||||
* );
|
||||
* console.log(balance);
|
||||
* } catch (error) {
|
||||
* console.error(error);
|
||||
* }
|
||||
* })();
|
||||
*
|
||||
* // returns
|
||||
* // { tokenId:
|
||||
* // 'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb',
|
||||
* // balance: '617',
|
||||
* // decimalCount: 8 }
|
||||
*
|
||||
* // single balance for Legacy Address
|
||||
* (async () => {
|
||||
* try {
|
||||
* let balance = await bchjs.SLP.Utils.balance(
|
||||
* "1DwQqpWc8pzaRydCmiJsPdoqCzmjSQQbp8",
|
||||
* "467969e067f5612863d0bf2daaa70dede2c6be03abb6fd401c5ef6e1e1f1f5c5"
|
||||
* );
|
||||
* console.log(balance);
|
||||
* } catch (error) {
|
||||
* console.error(error);
|
||||
* }
|
||||
* })();
|
||||
*
|
||||
* // returns
|
||||
* // { tokenId:
|
||||
* // '467969e067f5612863d0bf2daaa70dede2c6be03abb6fd401c5ef6e1e1f1f5c5',
|
||||
* // balance: '1234',
|
||||
* // decimalCount: 2 }
|
||||
*/
|
||||
// Retrieve a balance for a specific address and token ID
|
||||
async balance(address, tokenId) {
|
||||
const path = `${this.restURL}slp/balance/${address}/${tokenId}`
|
||||
|
||||
try {
|
||||
const response = await axios.get(path, _this.axiosOptions)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api SLP.Utils.validateTxid() validateTxid()
|
||||
* @apiName validateTxid
|
||||
@@ -533,6 +455,66 @@ class Utils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api SLP.Utils.validateTxid2() validateTxid2()
|
||||
* @apiName validateTxid2
|
||||
* @apiGroup SLP Utils
|
||||
* @apiDescription Validate that txid is an SLP transaction.
|
||||
*
|
||||
* This second validatoin version uses the slp-validate slp library. It is
|
||||
* much slower and less efficient than SLPDB and is prone to time-outs for
|
||||
* tokens with large DAGs. However, it operates independently of SLPDB and
|
||||
* is a great second validation option, particularly when SLPDB returns 'null'
|
||||
* values.
|
||||
*
|
||||
* Due to the inefficiency of this call, only a single TXID can be input at a
|
||||
* time. This call will throw an error if the input is an array.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
*
|
||||
* // validate single SLP txid
|
||||
* (async () => {
|
||||
* try {
|
||||
* let validated = await bchjs.SLP.Utils.validateTxid(
|
||||
* "df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb"
|
||||
* );
|
||||
* console.log(validated);
|
||||
* } catch (error) {
|
||||
* console.error(error);
|
||||
* }
|
||||
* })();
|
||||
*
|
||||
* // returns
|
||||
* [ { txid:
|
||||
* 'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb',
|
||||
* valid: true } ]
|
||||
*/
|
||||
async validateTxid2(txid) {
|
||||
try {
|
||||
// console.log(`txid: ${JSON.stringify(txid, null, 2)}`)
|
||||
|
||||
if (
|
||||
!txid ||
|
||||
txid === "" ||
|
||||
typeof txid !== "string" ||
|
||||
txid.length !== 64
|
||||
)
|
||||
throw new Error("txid must be 64 character string.")
|
||||
|
||||
const path = `${this.restURL}slp/validateTxid2/${txid}`
|
||||
|
||||
const response = await axios.get(path, _this.axiosOptions)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
|
||||
if (error.error && error.error.indexOf("Network error") > -1)
|
||||
throw new Error("slp-validate timed out")
|
||||
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api SLP.Utils.tokenStats() tokenStats()
|
||||
* @apiName tokenStats
|
||||
@@ -718,7 +700,7 @@ class Utils {
|
||||
typeof txid !== "string" ||
|
||||
txid.length !== 64
|
||||
)
|
||||
throw new Error(`txid string must be included.`)
|
||||
throw new Error("txid string must be included.")
|
||||
|
||||
// console.log(`this.restURL: ${this.restURL}`)
|
||||
const path = `${this.restURL}slp/txDetails/${txid}`
|
||||
@@ -740,6 +722,9 @@ class Utils {
|
||||
* Similar to decodeOpReturn(), except decodeOpReturn2() uses the slp-parser
|
||||
* library maintained by JT Freeman. Outputs have slightly different format.
|
||||
*
|
||||
* If optional associative array parameter cache is used, will cache and
|
||||
* reuse responses for the same input.
|
||||
*
|
||||
* Throws an error if given a non-SLP txid.
|
||||
*
|
||||
* In a future version of bch-js, this method will replace the origonal
|
||||
@@ -772,11 +757,26 @@ class Utils {
|
||||
* }
|
||||
*/
|
||||
// Reimplementation of decodeOpReturn() using slp-parser.
|
||||
async decodeOpReturn(txid) {
|
||||
async decodeOpReturn(txid, cache = null) {
|
||||
// The cache object is an in-memory cache (JS Object) that can be passed
|
||||
// into this function. It helps if multiple vouts from the same TXID are
|
||||
// being evaluated. In that case, it can significantly reduce the number
|
||||
// of API calls.
|
||||
// To use: add the output of this function to the cache object:
|
||||
// cache[txid] = returnValue
|
||||
// Then pass that cache object back into this function every time its called.
|
||||
if (cache) {
|
||||
if (!(cache instanceof Object))
|
||||
throw new Error("decodeOpReturn cache parameter must be Object")
|
||||
|
||||
const cachedVal = cache[txid]
|
||||
if (cachedVal) return cachedVal
|
||||
}
|
||||
|
||||
try {
|
||||
// Validate the txid input.
|
||||
if (!txid || txid === "" || typeof txid !== "string")
|
||||
throw new Error(`txid string must be included.`)
|
||||
throw new Error("txid string must be included.")
|
||||
|
||||
// Retrieve the transaction object from the full node.
|
||||
const path = `${this.restURL}rawtransactions/getRawTransaction/${txid}?verbose=true`
|
||||
@@ -824,8 +824,11 @@ class Utils {
|
||||
}
|
||||
// console.log(`tokenData: ${JSON.stringify(tokenData, null, 2)}`)
|
||||
|
||||
if (cache) cache[txid] = tokenData
|
||||
|
||||
return tokenData
|
||||
} catch (error) {
|
||||
// console.log('decodeOpReturn error: ', error)
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
throw error
|
||||
}
|
||||
@@ -844,18 +847,20 @@ class Utils {
|
||||
* set to false.
|
||||
* If the UTXO is part of an SLP transaction, it will return the UTXO object
|
||||
* with additional SLP information attached. An `isValid` property will be included.
|
||||
* If its value is true, the UTXO is a valid SLP UTXO. If the value is null,
|
||||
* then SLPDB has not yet processed that txid and validity has not been confirmed.
|
||||
* If its value is true, the UTXO is a valid SLP UTXO.
|
||||
* If the isValid value is null,
|
||||
* then SLPDB has not yet processed that txid and validity has not been confirmed,
|
||||
* or a 429 rate-limit error was enountered during the processing of the request.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
*
|
||||
* (async () => {
|
||||
* try {
|
||||
* const utxos = await bchjs.Blockbook.utxos(`bitcoincash:qpcqs0n5xap26un2828n55gan2ylj7wavvzeuwdx05`)
|
||||
* const utxos = await bchjs.Electrumx.utxo(`bitcoincash:qpcqs0n5xap26un2828n55gan2ylj7wavvzeuwdx05`)
|
||||
*
|
||||
* const utxoInfo = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
||||
*
|
||||
* console.log(`utxoInfo: ${JSON.stringify(isSLPUtxo,null,2)}`)
|
||||
* console.log(`utxoInfo: ${JSON.stringify(utxoInfo, null, 2)}`)
|
||||
* } catch (error) {
|
||||
* console.error(error)
|
||||
* }
|
||||
@@ -888,8 +893,12 @@ class Utils {
|
||||
// CT 5/31/20: Refactored to use slp-parse library.
|
||||
async tokenUtxoDetails(utxos) {
|
||||
try {
|
||||
// utxo list may have duplicate tx_hash, varying tx_pos
|
||||
// only need to call decodeOpReturn once for those
|
||||
const decodeOpReturnCache = {}
|
||||
const cachedTxValidation = {}
|
||||
// Throw error if input is not an array.
|
||||
if (!Array.isArray(utxos)) throw new Error(`Input must be an array.`)
|
||||
if (!Array.isArray(utxos)) throw new Error("Input must be an array.")
|
||||
|
||||
// Loop through each element in the array and validate the input before
|
||||
// further processing.
|
||||
@@ -945,15 +954,33 @@ class Utils {
|
||||
// If there is no OP_RETURN, mark the UTXO as false.
|
||||
let slpData = false
|
||||
try {
|
||||
slpData = await this.decodeOpReturn(utxo.txid)
|
||||
slpData = await this.decodeOpReturn(utxo.txid, decodeOpReturnCache)
|
||||
// console.log(`slpData: ${JSON.stringify(slpData, null, 2)}`)
|
||||
} catch (err) {
|
||||
// console.log(`error: `, err)
|
||||
// console.log(`error from decodeOpReturn(${utxo.txid}): `, err)
|
||||
|
||||
// An error will be thrown if the txid is not SLP.
|
||||
// Mark as false and continue the loop.
|
||||
// outAry.push(false)
|
||||
utxo.isValid = false
|
||||
outAry.push(utxo)
|
||||
// If error is for some other reason, like a 429 error, mark utxo as 'null'
|
||||
// to display the unknown state.
|
||||
if (
|
||||
!err.message ||
|
||||
(err.message.indexOf("scriptpubkey not op_return") === -1 &&
|
||||
err.message.indexOf("lokad id") === -1)
|
||||
) {
|
||||
// console.log(`error from decodeOpReturn(${utxo.txid}): `, err)
|
||||
|
||||
utxo.isValid = null
|
||||
outAry.push(utxo)
|
||||
|
||||
// If error is thrown because there is no OP_RETURN, then it's not
|
||||
// an SLP UTXO.
|
||||
// Mark as false and continue the loop.
|
||||
} else {
|
||||
utxo.isValid = false
|
||||
outAry.push(utxo)
|
||||
}
|
||||
|
||||
// Halt the execution of the loop and increase to the next index.
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -1013,7 +1040,10 @@ class Utils {
|
||||
|
||||
// If UTXO passes validation, then return formatted token data.
|
||||
else {
|
||||
const genesisData = await this.decodeOpReturn(slpData.tokenId)
|
||||
const genesisData = await this.decodeOpReturn(
|
||||
slpData.tokenId,
|
||||
decodeOpReturnCache
|
||||
)
|
||||
// console.log(`genesisData: ${JSON.stringify(genesisData, null, 2)}`)
|
||||
|
||||
// Minting Baton
|
||||
@@ -1061,7 +1091,10 @@ class Utils {
|
||||
|
||||
// If UTXO passes validation, then return formatted token data.
|
||||
else {
|
||||
const genesisData = await this.decodeOpReturn(slpData.tokenId)
|
||||
const genesisData = await this.decodeOpReturn(
|
||||
slpData.tokenId,
|
||||
decodeOpReturnCache
|
||||
)
|
||||
// console.log(`genesisData: ${JSON.stringify(genesisData, null, 2)}`)
|
||||
|
||||
// console.log(`utxo: ${JSON.stringify(utxo, null, 2)}`)
|
||||
@@ -1088,7 +1121,11 @@ class Utils {
|
||||
|
||||
// Finally, validate the SLP txid with SLPDB.
|
||||
if (outAry[i].tokenType) {
|
||||
const isValid = await this.validateTxid(utxo.txid)
|
||||
var isValid = cachedTxValidation[utxo.txid]
|
||||
if (isValid == null) {
|
||||
isValid = await this.validateTxid(utxo.txid)
|
||||
cachedTxValidation[utxo.txid] = isValid
|
||||
}
|
||||
// console.log(`isValid: ${JSON.stringify(isValid, null, 2)}`)
|
||||
|
||||
outAry[i].isValid = isValid[0].valid
|
||||
@@ -1101,6 +1138,191 @@ class Utils {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api SLP.Utils.hydrateUtxos() hydrateUtxos()
|
||||
* @apiName hydrateUtxos
|
||||
* @apiGroup SLP Utils
|
||||
* @apiDescription Hydrate a UTXO with SLP token metadata.
|
||||
*
|
||||
* The same as tokenUtxoDetails(), but uses bch-api to do the heavy lifting,
|
||||
* which greatly reduces the number of API calls.
|
||||
*
|
||||
* Expects an array of UTXO objects as input. Returns an array of equal size.
|
||||
* Returns UTXO data hydrated with token information.
|
||||
* If the
|
||||
* UTXO does not belong to a SLP transaction, it will return an `isValid` property
|
||||
* set to false.
|
||||
* If the UTXO is part of an SLP transaction, it will return the UTXO object
|
||||
* with additional SLP information attached. An `isValid` property will be included.
|
||||
* If its value is true, the UTXO is a valid SLP UTXO. \
|
||||
* If the isValid value is null,
|
||||
* then SLPDB has not yet processed that txid and validity has not been confirmed,
|
||||
* or a 429 rate-limit error was enountered during the processing of the request.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
*
|
||||
* (async () => {
|
||||
* try {
|
||||
* const utxos = await bchjs.Electrumx.utxo([
|
||||
* "bitcoincash:qq6mvsm7l92d77zpymmltvaw09p5uzghyuyx7spygg",
|
||||
* "bitcoincash:qpjdrs8qruzh8xvusdfmutjx62awcepnhyperm3g89",
|
||||
* "bitcoincash:qzygn28zpgeemnptkn26xzyuzzfu9l8f9vfvq7kptk"
|
||||
* ])
|
||||
*
|
||||
* const utxoInfo = await bchjs.SLP.Utils.hydrateUtxos(utxos.utxos)
|
||||
*
|
||||
* console.log(`${JSON.stringify(utxoInfo, null, 2)}`)
|
||||
* } catch (error) {
|
||||
* console.error(error)
|
||||
* }
|
||||
* })()
|
||||
*
|
||||
* // returns
|
||||
* {
|
||||
* "slpUtxos": [
|
||||
* {
|
||||
* "utxos": [
|
||||
* {
|
||||
* "height": 654522,
|
||||
* "tx_hash": "516e763932061f9e868652d727045b714db1ecac459e84cd52b5b4cb39572ecc",
|
||||
* "tx_pos": 0,
|
||||
* "value": 6000,
|
||||
* "satoshis": 6000,
|
||||
* "txid": "516e763932061f9e868652d727045b714db1ecac459e84cd52b5b4cb39572ecc",
|
||||
* "vout": 0,
|
||||
* "isValid": false
|
||||
* }
|
||||
* ],
|
||||
* "address": "bitcoincash:qq6mvsm7l92d77zpymmltvaw09p5uzghyuyx7spygg"
|
||||
* },
|
||||
* {
|
||||
* "utxos": [
|
||||
* {
|
||||
* "height": 654522,
|
||||
* "tx_hash": "8ec01d851d9df9fb4b4331275e2ff680257c224100d0081cec6fbeedf982f738",
|
||||
* "tx_pos": 1,
|
||||
* "value": 546,
|
||||
* "satoshis": 546,
|
||||
* "txid": "8ec01d851d9df9fb4b4331275e2ff680257c224100d0081cec6fbeedf982f738",
|
||||
* "vout": 1,
|
||||
* "utxoType": "token",
|
||||
* "transactionType": "send",
|
||||
* "tokenId": "a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2",
|
||||
* "tokenTicker": "TROUT",
|
||||
* "tokenName": "Trout's test token",
|
||||
* "tokenDocumentUrl": "troutsblog.com",
|
||||
* "tokenDocumentHash": "",
|
||||
* "decimals": 2,
|
||||
* "tokenType": 1,
|
||||
* "tokenQty": 10,
|
||||
* "isValid": true
|
||||
* }
|
||||
* ],
|
||||
* "address": "bitcoincash:qpjdrs8qruzh8xvusdfmutjx62awcepnhyperm3g89"
|
||||
* },
|
||||
* {
|
||||
* "utxos": [
|
||||
* {
|
||||
* "height": 654522,
|
||||
* "tx_hash": "072a1e2c2d5f1309bf4eef7f88684e4ecd544a903b386b07f3e04b91b13d8af1",
|
||||
* "tx_pos": 0,
|
||||
* "value": 6999,
|
||||
* "satoshis": 6999,
|
||||
* "txid": "072a1e2c2d5f1309bf4eef7f88684e4ecd544a903b386b07f3e04b91b13d8af1",
|
||||
* "vout": 0,
|
||||
* "isValid": false
|
||||
* },
|
||||
* {
|
||||
* "height": 654522,
|
||||
* "tx_hash": "a72db6a0883ecb8e379f317231b2571e41e041b7b1107e3e54c2e0b3386ac6ca",
|
||||
* "tx_pos": 1,
|
||||
* "value": 546,
|
||||
* "satoshis": 546,
|
||||
* "txid": "a72db6a0883ecb8e379f317231b2571e41e041b7b1107e3e54c2e0b3386ac6ca",
|
||||
* "vout": 1,
|
||||
* "utxoType": "token",
|
||||
* "transactionType": "send",
|
||||
* "tokenId": "6201f3efe486c577433622817b99645e1d473cd3882378f9a0efc128ab839a82",
|
||||
* "tokenTicker": "VALENTINE",
|
||||
* "tokenName": "Valentine day token",
|
||||
* "tokenDocumentUrl": "fullstack.cash",
|
||||
* "tokenDocumentHash": "",
|
||||
* "decimals": 2,
|
||||
* "tokenType": 1,
|
||||
* "tokenQty": 5,
|
||||
* "isValid": true
|
||||
* }
|
||||
* ],
|
||||
* "address": "bitcoincash:qzygn28zpgeemnptkn26xzyuzzfu9l8f9vfvq7kptk"
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
*
|
||||
* (async () => {
|
||||
* try {
|
||||
* const utxos = [
|
||||
* {
|
||||
* utxos: [
|
||||
* {
|
||||
* txid: "d56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56",
|
||||
* vout: 3,
|
||||
* value: "6816",
|
||||
* height: 606848,
|
||||
* confirmations: 13,
|
||||
* satoshis: 6816
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
* ]
|
||||
*
|
||||
* const utxoInfo = await bchjs.SLP.Utils.hydrateUtxos(utxos)
|
||||
*
|
||||
* console.log(`${JSON.stringify(utxoInfo, null, 2)}`)
|
||||
* } catch (error) {
|
||||
* console.error(error)
|
||||
* }
|
||||
* })()
|
||||
*
|
||||
* // returns
|
||||
* {
|
||||
* "slpUtxos": [
|
||||
* {
|
||||
* "utxos": [
|
||||
* {
|
||||
* "txid": "d56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56",
|
||||
* "vout": 3,
|
||||
* "value": "6816",
|
||||
* "height": 606848,
|
||||
* "confirmations": 13,
|
||||
* "satoshis": 6816,
|
||||
* "isValid": false
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
* ]
|
||||
*/
|
||||
// Same as tokenUtxoDetails(), but reduces API calls by having bch-api server
|
||||
// do the heavy lifting.
|
||||
async hydrateUtxos(utxos) {
|
||||
try {
|
||||
// Throw error if input is not an array.
|
||||
if (!Array.isArray(utxos)) throw new Error("Input must be an array.")
|
||||
|
||||
const response = await axios.post(
|
||||
`${this.restURL}slp/hydrateUtxos`,
|
||||
{
|
||||
utxos: utxos
|
||||
},
|
||||
_this.axiosOptions
|
||||
)
|
||||
|
||||
return response.data
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Utils
|
||||
|
||||
@@ -37,7 +37,7 @@ class TransactionBuilder {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Transaction-Builder.addInput() addInput() - Add input to transaction.
|
||||
* @api Transaction-Builder.addInput() addInput()
|
||||
* @apiName AddInput
|
||||
* @apiGroup TransactionBuilder
|
||||
* @apiDescription Add input to transaction.
|
||||
@@ -66,7 +66,7 @@ class TransactionBuilder {
|
||||
this.p2shInput = true
|
||||
}
|
||||
/**
|
||||
* @api Transaction-Builder.addOutput() addOutput() - Add output to transaction.
|
||||
* @api Transaction-Builder.addOutput() addOutput()
|
||||
* @apiName AddOutput
|
||||
* @apiGroup TransactionBuilder
|
||||
* @apiDescription Add output to transaction.
|
||||
@@ -90,7 +90,7 @@ class TransactionBuilder {
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @api Transaction-Builder.setLockTime() setLockTime() - Set locktime.
|
||||
* @api Transaction-Builder.setLockTime() setLockTime()
|
||||
* @apiName SetLockTime
|
||||
* @apiGroup TransactionBuilder
|
||||
* @apiDescription Set locktime.
|
||||
@@ -108,7 +108,7 @@ class TransactionBuilder {
|
||||
this.transaction.setLockTime(locktime)
|
||||
}
|
||||
/**
|
||||
* @api Transaction-Builder.sign() sign() - Sign transaction..
|
||||
* @api Transaction-Builder.sign() sign()
|
||||
* @apiName Sign.
|
||||
* @apiGroup TransactionBuilder
|
||||
* @apiDescription Sign transaction. It creates the unlocking script needed to spend an input. Each input has its own script and thus 'sign' must be called for each input even if the keyPair is the same..
|
||||
@@ -145,7 +145,7 @@ class TransactionBuilder {
|
||||
)
|
||||
}
|
||||
/**
|
||||
* @api Transaction-Builder.build() build() - Build transaction.
|
||||
* @api Transaction-Builder.build() build()
|
||||
* @apiName Build.
|
||||
* @apiGroup TransactionBuilder
|
||||
* @apiDescription Build transaction.
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ class Util {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api util.validateAddress() validateAddress() - Get information about the given bitcoin address.
|
||||
* @api util.validateAddress() validateAddress()
|
||||
* @apiName Validate Address.
|
||||
* @apiGroup Util
|
||||
* @apiDescription Return information about the given bitcoin address.
|
||||
|
||||
@@ -178,4 +178,176 @@ describe(`#ElectrumX`, () => {
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#unconfirmed`, () => {
|
||||
// These tests won't work because unconfirmed transactions are transient in nature.
|
||||
/*
|
||||
it(`should GET unconfirmed UTXOs (mempool) for a single address`, async () => {
|
||||
const addr = "bitcoincash:qqy6qwk3wpne95hhv8uzwr4cn8m7c06cqgchl77dnv"
|
||||
|
||||
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 request for unconfirmed UTXOs (mempool) for an array of addresses`, async () => {
|
||||
const addr = [
|
||||
"bitcoincash:qqy6qwk3wpne95hhv8uzwr4cn8m7c06cqgchl77dnv",
|
||||
"bitcoincash:qpyrtsl9msdu2klgfpcmn2v5r22w9rk24g8pal74ts"
|
||||
]
|
||||
|
||||
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")
|
||||
})
|
||||
*/
|
||||
|
||||
it(`should throw error on array size rate limit`, async () => {
|
||||
try {
|
||||
const addr = []
|
||||
for (let i = 0; i < 25; i++)
|
||||
addr.push("bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf")
|
||||
|
||||
await bchjs.Electrumx.unconfirmed(addr)
|
||||
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#blockHeader`, () => {
|
||||
it(`should GET block headers for given height and count`, async () => {
|
||||
const height = 42
|
||||
const count = 2
|
||||
|
||||
const result = await bchjs.Electrumx.blockHeader(height, count)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
assert.property(result, "success")
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "headers")
|
||||
assert.isArray(result.headers)
|
||||
assert.equal(result.headers.length, 2)
|
||||
})
|
||||
|
||||
it(`should GET block headers for given height with default count = 1`, async () => {
|
||||
const height = 42
|
||||
|
||||
const result = await bchjs.Electrumx.blockHeader(height)
|
||||
assert.property(result, "success")
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "headers")
|
||||
assert.isArray(result.headers)
|
||||
assert.equal(result.headers.length, 1)
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#txData`, () => {
|
||||
it(`should GET details for a single transaction`, async () => {
|
||||
const txid =
|
||||
"4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251"
|
||||
|
||||
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 () => {
|
||||
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")
|
||||
})
|
||||
|
||||
it(`should throw error on array size rate limit`, async () => {
|
||||
try {
|
||||
const txids = []
|
||||
for (let i = 0; i < 25; i++) {
|
||||
txids.push(
|
||||
"4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251"
|
||||
)
|
||||
}
|
||||
|
||||
await bchjs.Electrumx.txData(txids)
|
||||
|
||||
console.log(`result: ${util.inspect(result)}`)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#broadcast`, () => {
|
||||
it(`should broadcast a single transaction`, async () => {
|
||||
const txHex =
|
||||
"020000000265d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667010000006441dd1dd72770cadede1a7fd0363574846c48468a398ddfa41a9677c74cac8d2652b682743725a3b08c6c2021a629011e11a264d9036e9d5311e35b5f4937ca7b4e4121020797d8fd4d2fa6fd7cdeabe2526bfea2b90525d6e8ad506ec4ee3c53885aa309ffffffff65d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667000000006441347d7f218c11c04487c1ad8baac28928fb10e5054cd4494b94d078cfa04ccf68e064fb188127ff656c0b98e9ce87f036d183925d0d0860605877d61e90375f774121028a53f95eb631b460854fc836b2e5d31cad16364b4dc3d970babfbdcc3f2e4954ffffffff035ac355000000000017a914189ce02e332548f4804bac65cba68202c9dbf822878dfd0800000000001976a914285bb350881b21ac89724c6fb6dc914d096cd53b88acf9ef3100000000001976a91445f1f1c4a9b9419a5088a3e9c24a293d7a150e6488ac00000000"
|
||||
|
||||
try {
|
||||
await bchjs.Electrumx.broadcast(txHex)
|
||||
} catch (err) {
|
||||
assert.property(err, "success")
|
||||
assert.equal(err.success, false)
|
||||
assert.include(err.error, "Missing inputs")
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -17,21 +17,21 @@ describe(`#Ninsight`, () => {
|
||||
const result = await bchjs.Ninsight.utxo(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "utxos")
|
||||
assert.property(result, "legacyAddress")
|
||||
assert.property(result, "cashAddress")
|
||||
assert.property(result, "slpAddress")
|
||||
assert.property(result, "scriptPubKey")
|
||||
assert.property(result, "asm")
|
||||
assert.property(result[0], "utxos")
|
||||
assert.property(result[0], "legacyAddress")
|
||||
assert.property(result[0], "cashAddress")
|
||||
assert.property(result[0], "slpAddress")
|
||||
assert.property(result[0], "scriptPubKey")
|
||||
assert.property(result[0], "asm")
|
||||
|
||||
assert.isArray(result.utxos)
|
||||
assert.isArray(result[0].utxos)
|
||||
|
||||
assert.property(result.utxos[0], "txid")
|
||||
assert.property(result.utxos[0], "vout")
|
||||
assert.property(result.utxos[0], "amount")
|
||||
assert.property(result.utxos[0], "satoshis")
|
||||
assert.property(result.utxos[0], "height")
|
||||
assert.property(result.utxos[0], "confirmations")
|
||||
assert.property(result[0].utxos[0], "txid")
|
||||
assert.property(result[0].utxos[0], "vout")
|
||||
assert.property(result[0].utxos[0], "amount")
|
||||
assert.property(result[0].utxos[0], "satoshis")
|
||||
assert.property(result[0].utxos[0], "height")
|
||||
assert.property(result[0].utxos[0], "confirmations")
|
||||
})
|
||||
|
||||
it(`should POST utxo details for an array of addresses`, async () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const assert = require("assert")
|
||||
const assert = require("chai").assert
|
||||
const BCHJS = require("../../src/bch-js")
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
@@ -11,4 +11,23 @@ describe("#price", () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#getUsd", () => {
|
||||
it("should get the USD price of BCH", async () => {
|
||||
const result = await bchjs.Price.getUsd()
|
||||
// console.log(result)
|
||||
|
||||
assert.isNumber(result)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#rates", () => {
|
||||
it("should get the price of BCH in several currencies", async () => {
|
||||
const result = await bchjs.Price.rates()
|
||||
// console.log(result)
|
||||
|
||||
assert.property(result, "USD")
|
||||
assert.property(result, "CAD")
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -271,7 +271,7 @@ describe("#rawtransaction", () => {
|
||||
//console.log(`err: ${util.inspect(err)}`)
|
||||
|
||||
assert.hasAllKeys(err, ["error"])
|
||||
assert.include(err.error, "Missing inputs")
|
||||
assert.include(err.error, "bad-txns-inputs-missingorspent (code 16)")
|
||||
}
|
||||
})
|
||||
|
||||
@@ -288,7 +288,7 @@ describe("#rawtransaction", () => {
|
||||
// console.log(`err: ${util.inspect(err)}`)
|
||||
|
||||
assert.hasAllKeys(err, ["error"])
|
||||
assert.include(err.error, "Missing inputs")
|
||||
assert.include(err.error, "bad-txns-inputs-missingorspent (code 16)")
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
+172
-1
@@ -6,7 +6,7 @@ const chai = require("chai")
|
||||
const assert = chai.assert
|
||||
|
||||
const BCHJS = require("../../src/bch-js")
|
||||
const bchjs = new BCHJS()
|
||||
let bchjs
|
||||
|
||||
// Inspect utility used for debugging.
|
||||
const util = require("util")
|
||||
@@ -25,6 +25,8 @@ describe(`#SLP`, () => {
|
||||
beforeEach(async () => {
|
||||
// Introduce a delay so that the BVT doesn't trip the rate limits.
|
||||
await sleep(1000)
|
||||
|
||||
bchjs = new BCHJS()
|
||||
})
|
||||
|
||||
describe("#util", () => {
|
||||
@@ -437,6 +439,30 @@ describe(`#SLP`, () => {
|
||||
assert.equal(data[0].isValid, false)
|
||||
assert.equal(data[1].isValid, false)
|
||||
})
|
||||
|
||||
it("should handle a dust attack", async () => {
|
||||
// it("#dustattack", async () => {
|
||||
const utxos = [
|
||||
{
|
||||
height: 655965,
|
||||
tx_hash:
|
||||
"a675af87dcd8d39be782737aa52e0076b52eb2f5ce355ffcb5567a64dd96b77e",
|
||||
tx_pos: 151,
|
||||
value: 547,
|
||||
satoshis: 547,
|
||||
txid:
|
||||
"a675af87dcd8d39be782737aa52e0076b52eb2f5ce355ffcb5567a64dd96b77e",
|
||||
vout: 151,
|
||||
address: "bitcoincash:qq4dw3sm8qvglspy6w2qg0u2ugsy9zcfcqrpeflwww",
|
||||
hdIndex: 11
|
||||
}
|
||||
]
|
||||
|
||||
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
||||
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
||||
|
||||
assert.equal(data[0].isValid, false)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#balancesForAddress", () => {
|
||||
@@ -492,6 +518,151 @@ describe(`#SLP`, () => {
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe("#hydrateUtxos", () => {
|
||||
it("should throw an error if input is not an array", async () => {
|
||||
try {
|
||||
const utxos = 1234
|
||||
|
||||
await bchjs.SLP.Utils.hydrateUtxos(utxos)
|
||||
|
||||
assert.equal(true, false, "Uh oh. Code path should not end here.")
|
||||
} catch (err) {
|
||||
// console.log(`Error: `, err)
|
||||
assert.include(err.message, `Input must be an array.`)
|
||||
}
|
||||
})
|
||||
|
||||
it("should hydrate UTXOs", async () => {
|
||||
const utxos = [
|
||||
{
|
||||
utxos: [
|
||||
{
|
||||
txid:
|
||||
"d56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56",
|
||||
vout: 3,
|
||||
value: "6816",
|
||||
height: 606848,
|
||||
confirmations: 13,
|
||||
satoshis: 6816
|
||||
},
|
||||
{
|
||||
txid:
|
||||
"d56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56",
|
||||
vout: 2,
|
||||
value: "546",
|
||||
height: 606848,
|
||||
confirmations: 13,
|
||||
satoshis: 546
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
const result = await bchjs.SLP.Utils.hydrateUtxos(utxos)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
// Test the general structure of the output.
|
||||
assert.isArray(result.slpUtxos)
|
||||
assert.equal(result.slpUtxos.length, 1)
|
||||
assert.equal(result.slpUtxos[0].utxos.length, 2)
|
||||
|
||||
// Test the non-slp UTXO.
|
||||
assert.property(result.slpUtxos[0].utxos[0], "txid")
|
||||
assert.property(result.slpUtxos[0].utxos[0], "vout")
|
||||
assert.property(result.slpUtxos[0].utxos[0], "value")
|
||||
assert.property(result.slpUtxos[0].utxos[0], "height")
|
||||
assert.property(result.slpUtxos[0].utxos[0], "confirmations")
|
||||
assert.property(result.slpUtxos[0].utxos[0], "satoshis")
|
||||
assert.property(result.slpUtxos[0].utxos[0], "isValid")
|
||||
assert.equal(result.slpUtxos[0].utxos[0].isValid, false)
|
||||
|
||||
// Test the slp UTXO.
|
||||
assert.property(result.slpUtxos[0].utxos[1], "txid")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "vout")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "value")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "height")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "confirmations")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "satoshis")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "isValid")
|
||||
assert.equal(result.slpUtxos[0].utxos[1].isValid, true)
|
||||
assert.property(result.slpUtxos[0].utxos[1], "transactionType")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "tokenId")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "tokenTicker")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "tokenName")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "tokenDocumentUrl")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "tokenDocumentHash")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "decimals")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "tokenType")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "tokenQty")
|
||||
})
|
||||
|
||||
it("should process data directly from Electrumx", async () => {
|
||||
const addrs = [
|
||||
"bitcoincash:qq6mvsm7l92d77zpymmltvaw09p5uzghyuyx7spygg",
|
||||
"bitcoincash:qpjdrs8qruzh8xvusdfmutjx62awcepnhyperm3g89",
|
||||
"bitcoincash:qzygn28zpgeemnptkn26xzyuzzfu9l8f9vfvq7kptk"
|
||||
]
|
||||
|
||||
const utxos = await bchjs.Electrumx.utxo(addrs)
|
||||
// console.log(`utxos: ${JSON.stringify(utxos, null, 2)}`)
|
||||
|
||||
const result = await bchjs.SLP.Utils.hydrateUtxos(utxos.utxos)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
// Test the general structure of the output.
|
||||
assert.isArray(result.slpUtxos)
|
||||
assert.equal(result.slpUtxos.length, 3)
|
||||
assert.equal(result.slpUtxos[0].utxos.length, 1)
|
||||
assert.equal(result.slpUtxos[1].utxos.length, 1)
|
||||
assert.equal(result.slpUtxos[2].utxos.length, 2)
|
||||
|
||||
try {
|
||||
// Test the expected values.
|
||||
assert.equal(result.slpUtxos[0].utxos[0].isValid, false)
|
||||
assert.equal(result.slpUtxos[1].utxos[0].isValid, true)
|
||||
assert.equal(result.slpUtxos[1].utxos[0].tokenTicker, "TROUT")
|
||||
assert.equal(result.slpUtxos[2].utxos[0].isValid, false)
|
||||
assert.equal(result.slpUtxos[2].utxos[1].isValid, true)
|
||||
assert.equal(result.slpUtxos[2].utxos[1].tokenTicker, "VALENTINE")
|
||||
} catch (err) {
|
||||
console.error(
|
||||
'The hydrateUtxos call may hitting rate limits, or SLPDB may be having issues if "isValid" results are "null"'
|
||||
)
|
||||
console.log("Error: ", err)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("#validateTxid2", () => {
|
||||
it("should invalidate a known invalid TXID", async () => {
|
||||
const txid =
|
||||
"f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a"
|
||||
|
||||
const result = await bchjs.SLP.Utils.validateTxid2(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "txid")
|
||||
assert.equal(result.txid, txid)
|
||||
|
||||
assert.property(result, "isValid")
|
||||
assert.equal(result.isValid, false)
|
||||
})
|
||||
|
||||
it("should validate a known valid TXID", async () => {
|
||||
const txid =
|
||||
"3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488"
|
||||
|
||||
const result = await bchjs.SLP.Utils.validateTxid2(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "txid")
|
||||
assert.equal(result.txid, txid)
|
||||
|
||||
assert.property(result, "isValid")
|
||||
assert.equal(result.isValid, true)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#tokentype1", () => {
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
export RESTURL=https://bchn-free-main.fullstack.cash/v3/
|
||||
#export RESTURL=http://localhost:3000/v3/
|
||||
|
||||
cd test/integration/
|
||||
mocha --timeout 30000 blockchain.js control.js electrumx.js ninsight.js openbazaar.js price.js rawtransaction.js slp.js util.js
|
||||
@@ -182,4 +182,171 @@ describe(`#ElectrumX`, () => {
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#unconfirmed`, () => {
|
||||
// These tests won't work because unconfirmed transactions are transient in nature.
|
||||
/*
|
||||
it(`should GET unconfirmed UTXOs (mempool) for a single address`, async () => {
|
||||
const addr = "bchtest:qp25k20dgcljrz4hkdz43partam3j5httyprjp23qd"
|
||||
|
||||
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 () => {
|
||||
const addr = [
|
||||
"bchtest:qp25k20dgcljrz4hkdz43partam3j5httyprjp23qd",
|
||||
"bchtest:qpkl3xylrjx4jup6m66e7zg7whlaucsxeudxeqawdj"
|
||||
]
|
||||
|
||||
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")
|
||||
})
|
||||
*/
|
||||
|
||||
it(`should throw error on array size rate limit`, async () => {
|
||||
try {
|
||||
const addr = []
|
||||
for (let i = 0; i < 25; i++)
|
||||
addr.push("bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2")
|
||||
|
||||
await bchjs.Electrumx.unconfirmed(addr)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#blockHeader`, () => {
|
||||
it(`should GET block headers for given height and count`, async () => {
|
||||
const height = 42
|
||||
const count = 2
|
||||
|
||||
const result = await bchjs.Electrumx.blockHeader(height, count)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
assert.property(result, "success")
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "headers")
|
||||
assert.isArray(result.headers)
|
||||
assert.equal(result.headers.length, 2)
|
||||
})
|
||||
|
||||
it(`should GET block headers for given height with default count = 1`, async () => {
|
||||
const height = 42
|
||||
|
||||
const result = await bchjs.Electrumx.blockHeader(height)
|
||||
assert.property(result, "success")
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "headers")
|
||||
assert.isArray(result.headers)
|
||||
assert.equal(result.headers.length, 1)
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#txData`, () => {
|
||||
it(`should GET details for a single transaction`, async () => {
|
||||
const txid = "76d2ee0ebd8b978742f6478ff9a12f478c34e4cee0a2b919059101d961bd01ee"
|
||||
|
||||
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 () => {
|
||||
const txids = [
|
||||
"76d2ee0ebd8b978742f6478ff9a12f478c34e4cee0a2b919059101d961bd01ee",
|
||||
"76d2ee0ebd8b978742f6478ff9a12f478c34e4cee0a2b919059101d961bd01ee"
|
||||
]
|
||||
|
||||
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")
|
||||
})
|
||||
|
||||
it(`should throw error on array size rate limit`, async () => {
|
||||
try {
|
||||
const txids = []
|
||||
for (let i = 0; i < 25; i++)
|
||||
txids.push("76d2ee0ebd8b978742f6478ff9a12f478c34e4cee0a2b919059101d961bd01ee")
|
||||
|
||||
await bchjs.Electrumx.txData(txids)
|
||||
|
||||
console.log(`result: ${util.inspect(result)}`)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#broadcast`, () => {
|
||||
it(`should broadcast a single transaction`, async () => {
|
||||
const txHex = "020000000265d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667010000006441dd1dd72770cadede1a7fd0363574846c48468a398ddfa41a9677c74cac8d2652b682743725a3b08c6c2021a629011e11a264d9036e9d5311e35b5f4937ca7b4e4121020797d8fd4d2fa6fd7cdeabe2526bfea2b90525d6e8ad506ec4ee3c53885aa309ffffffff65d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667000000006441347d7f218c11c04487c1ad8baac28928fb10e5054cd4494b94d078cfa04ccf68e064fb188127ff656c0b98e9ce87f036d183925d0d0860605877d61e90375f774121028a53f95eb631b460854fc836b2e5d31cad16364b4dc3d970babfbdcc3f2e4954ffffffff035ac355000000000017a914189ce02e332548f4804bac65cba68202c9dbf822878dfd0800000000001976a914285bb350881b21ac89724c6fb6dc914d096cd53b88acf9ef3100000000001976a91445f1f1c4a9b9419a5088a3e9c24a293d7a150e6488ac00000000"
|
||||
|
||||
try {
|
||||
await bchjs.Electrumx.broadcast(txHex)
|
||||
} catch (err) {
|
||||
assert.property(err, "success")
|
||||
assert.equal(err.success, false)
|
||||
assert.include(err.error, "Missing inputs")
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -17,21 +17,21 @@ describe(`#Ninsight`, () => {
|
||||
const result = await bchjs.Ninsight.utxo(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "utxos")
|
||||
assert.property(result, "legacyAddress")
|
||||
assert.property(result, "cashAddress")
|
||||
assert.property(result, "slpAddress")
|
||||
assert.property(result, "scriptPubKey")
|
||||
assert.property(result, "asm")
|
||||
assert.property(result[0], "utxos")
|
||||
assert.property(result[0], "legacyAddress")
|
||||
assert.property(result[0], "cashAddress")
|
||||
assert.property(result[0], "slpAddress")
|
||||
assert.property(result[0], "scriptPubKey")
|
||||
assert.property(result[0], "asm")
|
||||
|
||||
assert.isArray(result.utxos)
|
||||
assert.isArray(result[0].utxos)
|
||||
|
||||
assert.property(result.utxos[0], "txid")
|
||||
assert.property(result.utxos[0], "vout")
|
||||
assert.property(result.utxos[0], "amount")
|
||||
assert.property(result.utxos[0], "satoshis")
|
||||
assert.property(result.utxos[0], "height")
|
||||
assert.property(result.utxos[0], "confirmations")
|
||||
assert.property(result[0].utxos[0], "txid")
|
||||
assert.property(result[0].utxos[0], "vout")
|
||||
assert.property(result[0].utxos[0], "amount")
|
||||
assert.property(result[0].utxos[0], "satoshis")
|
||||
assert.property(result[0].utxos[0], "height")
|
||||
assert.property(result[0].utxos[0], "confirmations")
|
||||
})
|
||||
|
||||
it(`should POST utxo details for an array of addresses`, async () => {
|
||||
|
||||
@@ -89,7 +89,7 @@ describe(`#SLP`, () => {
|
||||
}
|
||||
})
|
||||
|
||||
it(`should fetch all balances for address: simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9`, async () => {
|
||||
it(`should fetch all balances for address: slptest:qz0kc67pm4emjyr3gaaa2wstdaykg9m4yqwlzpj3w9`, async () => {
|
||||
// Mock the call to rest.bitcoin.com
|
||||
if (process.env.TEST === "unit") {
|
||||
sandbox
|
||||
@@ -139,6 +139,60 @@ describe(`#SLP`, () => {
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe("#tokenUtxoDetails", () => {
|
||||
it("should hydrate UTXOs", async () => {
|
||||
const bchAddr = bchjs.SLP.Address.toCashAddress(
|
||||
"slptest:qz0kc67pm4emjyr3gaaa2wstdaykg9m4yqwlzpj3w9"
|
||||
)
|
||||
|
||||
const utxos = await bchjs.Electrumx.utxo([bchAddr])
|
||||
// console.log(`utxos: ${JSON.stringify(utxos, null, 2)}`)
|
||||
|
||||
const utxoInfo = await bchjs.SLP.Utils.tokenUtxoDetails(
|
||||
utxos.utxos[0].utxos
|
||||
)
|
||||
// console.log(`utxoInfo: ${JSON.stringify(utxoInfo, null, 2)}`)
|
||||
|
||||
assert.isArray(utxoInfo)
|
||||
|
||||
// first UTXO should be a PSF test token.
|
||||
assert.equal(utxoInfo[0].isValid, true)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#hydrateUtxos", () => {
|
||||
// This test will error out if the LOCAL_RESTURL settings is not set properly
|
||||
// in bch-api.
|
||||
it("should hydrate UTXOs", async () => {
|
||||
const bchAddr = bchjs.SLP.Address.toCashAddress(
|
||||
"slptest:qz0kc67pm4emjyr3gaaa2wstdaykg9m4yqwlzpj3w9"
|
||||
)
|
||||
|
||||
const utxos = await bchjs.Electrumx.utxo([bchAddr])
|
||||
// console.log(`utxos: ${JSON.stringify(utxos, null, 2)}`)
|
||||
|
||||
const utxoInfo = await bchjs.SLP.Utils.hydrateUtxos(utxos.utxos)
|
||||
// console.log(`utxoInfo: ${JSON.stringify(utxoInfo, null, 2)}`)
|
||||
|
||||
assert.isArray(utxoInfo.slpUtxos[0].utxos)
|
||||
|
||||
// first UTXO should be a PSF test token.
|
||||
assert.equal(utxoInfo.slpUtxos[0].utxos[0].isValid, true)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#validateTxid2", () => {
|
||||
it("should validate a token txid", async () => {
|
||||
const txid =
|
||||
"ad28116e0818339342dddfc5f58ca8a5379ceb9679b4e4cbd72f4de905415ec1"
|
||||
|
||||
const validated = await bchjs.SLP.Utils.validateTxid(txid)
|
||||
// console.log(validated)
|
||||
|
||||
assert.equal(validated[0].valid, true)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// Promise-based sleep function
|
||||
|
||||
@@ -6,3 +6,4 @@ export NETWORK=testnet
|
||||
|
||||
cd test/integration/testnet/
|
||||
mocha --timeout 30000 blockchain.js control.js electrumx.js openbazaar.js rawtransaction.js slp.js util.js
|
||||
#mocha --timeout 30000 blockchain.js
|
||||
|
||||
@@ -196,4 +196,226 @@ describe(`#ElectrumX`, () => {
|
||||
assert.property(result.transactions[0].transactions[0], "tx_hash")
|
||||
})
|
||||
})
|
||||
|
||||
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")
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#blockHeader`, () => {
|
||||
it(`should throw an error for improper height input`, async () => {
|
||||
try {
|
||||
// Mock network calls.
|
||||
sandbox.stub(axios, "get").rejects({
|
||||
response: {
|
||||
data: {
|
||||
success: false,
|
||||
error: "height must be a positive number"
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const height = -10
|
||||
await bchjs.Electrumx.blockHeader(height)
|
||||
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
// console.log(`err: `, err)
|
||||
assert.include(err.message, `height must be a positive number`)
|
||||
}
|
||||
})
|
||||
|
||||
it(`should throw an error for improper count input`, async () => {
|
||||
try {
|
||||
// Mock network calls.
|
||||
sandbox.stub(axios, "get").rejects({
|
||||
response: {
|
||||
data: {
|
||||
success: false,
|
||||
error: "count must be a positive number"
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const height = 42
|
||||
const count = -10
|
||||
|
||||
await bchjs.Electrumx.blockHeader(height, count)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
// console.log(`err: `, err)
|
||||
assert.include(err.message, `count must be a positive number`)
|
||||
}
|
||||
})
|
||||
|
||||
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)
|
||||
})
|
||||
})
|
||||
|
||||
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 })
|
||||
|
||||
const txid =
|
||||
"4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251"
|
||||
|
||||
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")
|
||||
})
|
||||
})
|
||||
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)
|
||||
assert.include(err.message, `Input txHex must be a string.`)
|
||||
}
|
||||
})
|
||||
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)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -119,11 +119,153 @@ const transactions = {
|
||||
]
|
||||
}
|
||||
|
||||
const unconfirmed = {
|
||||
success: true,
|
||||
utxos: [
|
||||
{
|
||||
height: 602405,
|
||||
tx_hash:
|
||||
"2b37bdb3b63dd0bca720437754a36671431a950e684b64c44ea910ea9d5297c7",
|
||||
fee: 34100
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const unconfirmedArray = {
|
||||
success: true,
|
||||
utxos: [
|
||||
{
|
||||
utxos: [
|
||||
{
|
||||
height: 604392,
|
||||
tx_hash:
|
||||
"7774e449c5a3065144cefbc4c0c21e6b69c987f095856778ef9f45ddd8ae1a41",
|
||||
fee: 34210
|
||||
},
|
||||
{
|
||||
height: 630834,
|
||||
tx_hash:
|
||||
"4fe60a51e0d8f5134bfd8e5f872d6e502d7f01b28a6afebb27f4438a4f638d53",
|
||||
value: 3000
|
||||
}
|
||||
],
|
||||
address: "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
|
||||
},
|
||||
{
|
||||
utxos: [],
|
||||
address: "bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const blockHeaders = [
|
||||
'010000008b52bbd72c2f49569059f559c1b1794de5192e4f7d6d2b03c7482bad0000000083e4f8a9d502ed0c419075c1abb5d56f878a2e9079e5612bfb76a2dc37d9c42741dd6849ffff001d2b909dd6',
|
||||
'01000000f528fac1bcb685d0cd6c792320af0300a5ce15d687c7149548904e31000000004e8985a786d864f21e9cbb7cbdf4bc9265fe681b7a0893ac55a8e919ce035c2f85de6849ffff001d385ccb7c'
|
||||
]
|
||||
|
||||
const txDetails = {
|
||||
blockhash: '0000000000000000002aaf94953da3b487317508ebd1003a1d75d6d6ec2e75cc',
|
||||
blocktime: 1578327094,
|
||||
confirmations: 31861,
|
||||
hash: '4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251',
|
||||
hex: '020000000265d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667010000006441dd1dd72770cadede1a7fd0363574846c48468a398ddfa41a9677c74cac8d2652b682743725a3b08c6c2021a629011e11a264d9036e9d5311e35b5f4937ca7b4e4121020797d8fd4d2fa6fd7cdeabe2526bfea2b90525d6e8ad506ec4ee3c53885aa309ffffffff65d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667000000006441347d7f218c11c04487c1ad8baac28928fb10e5054cd4494b94d078cfa04ccf68e064fb188127ff656c0b98e9ce87f036d183925d0d0860605877d61e90375f774121028a53f95eb631b460854fc836b2e5d31cad16364b4dc3d970babfbdcc3f2e4954ffffffff035ac355000000000017a914189ce02e332548f4804bac65cba68202c9dbf822878dfd0800000000001976a914285bb350881b21ac89724c6fb6dc914d096cd53b88acf9ef3100000000001976a91445f1f1c4a9b9419a5088a3e9c24a293d7a150e6488ac00000000',
|
||||
locktime: 0,
|
||||
size: 392,
|
||||
time: 1578327094,
|
||||
txid: '4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251',
|
||||
version: 2,
|
||||
vin: [
|
||||
{
|
||||
scriptSig: {
|
||||
asm: 'dd1dd72770cadede1a7fd0363574846c48468a398ddfa41a9677c74cac8d2652b682743725a3b08c6c2021a629011e11a264d9036e9d5311e35b5f4937ca7b4e[ALL|FORKID] 020797d8fd4d2fa6fd7cdeabe2526bfea2b90525d6e8ad506ec4ee3c53885aa309',
|
||||
hex: '41dd1dd72770cadede1a7fd0363574846c48468a398ddfa41a9677c74cac8d2652b682743725a3b08c6c2021a629011e11a264d9036e9d5311e35b5f4937ca7b4e4121020797d8fd4d2fa6fd7cdeabe2526bfea2b90525d6e8ad506ec4ee3c53885aa309'
|
||||
},
|
||||
sequence: 4294967295,
|
||||
txid: '6796672c8f0342770e3d4ac2a3b0e4494daeb7af7997f3518a0c8402f43ed165',
|
||||
vout: 1
|
||||
},
|
||||
{
|
||||
scriptSig: {
|
||||
asm: '347d7f218c11c04487c1ad8baac28928fb10e5054cd4494b94d078cfa04ccf68e064fb188127ff656c0b98e9ce87f036d183925d0d0860605877d61e90375f77[ALL|FORKID] 028a53f95eb631b460854fc836b2e5d31cad16364b4dc3d970babfbdcc3f2e4954',
|
||||
hex: '41347d7f218c11c04487c1ad8baac28928fb10e5054cd4494b94d078cfa04ccf68e064fb188127ff656c0b98e9ce87f036d183925d0d0860605877d61e90375f774121028a53f95eb631b460854fc836b2e5d31cad16364b4dc3d970babfbdcc3f2e4954'
|
||||
},
|
||||
sequence: 4294967295,
|
||||
txid: '6796672c8f0342770e3d4ac2a3b0e4494daeb7af7997f3518a0c8402f43ed165',
|
||||
vout: 0
|
||||
}
|
||||
],
|
||||
vout: [
|
||||
{
|
||||
n: 0,
|
||||
scriptPubKey: {
|
||||
addresses: ['bitcoincash: pqvfecpwxvj53ayqfwkxtjaxsgpvnklcyg8xewk9hl'],
|
||||
asm: 'OP_HASH160 189ce02e332548f4804bac65cba68202c9dbf822 OP_EQUAL',
|
||||
hex: 'a914189ce02e332548f4804bac65cba68202c9dbf82287',
|
||||
reqSigs: 1,
|
||||
type: 'scripthash'
|
||||
},
|
||||
value: 0.0562057
|
||||
},
|
||||
{
|
||||
n: 1,
|
||||
scriptPubKey: {
|
||||
addresses: ['bitcoincash: qq59hv6s3qdjrtyfwfxxldkuj9xsjmx48vrz882knz'],
|
||||
asm: 'OP_DUP OP_HASH160 285bb350881b21ac89724c6fb6dc914d096cd53b OP_EQUALVERIFY OP_CHECKSIG',
|
||||
hex: '76a914285bb350881b21ac89724c6fb6dc914d096cd53b88ac',
|
||||
reqSigs: 1,
|
||||
type: 'pubkeyhash'
|
||||
},
|
||||
value: 0.00589197
|
||||
},
|
||||
{
|
||||
n: 2,
|
||||
scriptPubKey: {
|
||||
addresses: ['bitcoincash: qpzlruwy4xu5rxjs3z37nsj29y7h59gwvsu4ddp0u4'],
|
||||
asm: 'OP_DUP OP_HASH160 45f1f1c4a9b9419a5088a3e9c24a293d7a150e64 OP_EQUALVERIFY OP_CHECKSIG',
|
||||
hex: '76a91445f1f1c4a9b9419a5088a3e9c24a293d7a150e6488ac',
|
||||
reqSigs: 1,
|
||||
type: 'pubkeyhash'
|
||||
},
|
||||
value: 0.03272697
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const details = {
|
||||
success: true,
|
||||
details: txDetails
|
||||
}
|
||||
|
||||
const detailsArray = {
|
||||
success: true,
|
||||
transactions: [
|
||||
{
|
||||
txid: txDetails.txid,
|
||||
details: txDetails
|
||||
},
|
||||
{
|
||||
txid: txDetails.txid,
|
||||
details: txDetails
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const broadcast = {
|
||||
success: true,
|
||||
txid: txDetails.txid
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
utxo,
|
||||
utxos,
|
||||
balance,
|
||||
balances,
|
||||
transaction,
|
||||
transactions
|
||||
transactions,
|
||||
unconfirmed,
|
||||
unconfirmedArray,
|
||||
blockHeaders,
|
||||
details,
|
||||
detailsArray,
|
||||
broadcast
|
||||
}
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
Mocks for price.
|
||||
*/
|
||||
|
||||
const mockRates = {
|
||||
AED: "915.049218",
|
||||
AFN: "19144.48874646",
|
||||
ALGO: "826.6633482661356600405",
|
||||
ALL: "26221.96098759",
|
||||
AMD: "119977.82663822",
|
||||
ANG: "446.841810455",
|
||||
AOA: "162269.774275",
|
||||
ARS: "19322.704621",
|
||||
ATOM: "45.5920571010248851205",
|
||||
AUD: "353.78913716",
|
||||
AWG: "448.407",
|
||||
AZN: "424.1182875",
|
||||
BAL: "18.9361216125975755781",
|
||||
BAM: "413.75759465",
|
||||
BAND: "40.84187228461349099275",
|
||||
BAT: "1169.75444148879972951",
|
||||
BBD: "498.23",
|
||||
BCH: "1.0",
|
||||
BDT: "21107.92000745",
|
||||
BGN: "413.93197515",
|
||||
BHD: "93.93578597",
|
||||
BIF: "481540.76228735",
|
||||
BMD: "249.115",
|
||||
BND: "337.84677362",
|
||||
BOB: "1718.851399565",
|
||||
BRL: "1396.737982",
|
||||
BSD: "249.115",
|
||||
BSV: "1.555324933590611026515",
|
||||
BTC: "0.021265",
|
||||
BTN: "18249.513962505",
|
||||
BWP: "2848.17713393",
|
||||
BYN: "637.963336685",
|
||||
BYR: "6379633.36685000049823",
|
||||
BZD: "501.752236985",
|
||||
CAD: "328.80838319",
|
||||
CDF: "488848.679106575",
|
||||
CGLD: "121.0412516398620018305",
|
||||
CHF: "226.8989243",
|
||||
CLF: "7.110489445",
|
||||
CLP: "196202.978234955",
|
||||
CNH: "1664.25510705",
|
||||
CNY: "1666.429881",
|
||||
COMP: "2.4706436576415750709",
|
||||
COP: "958730.858397465",
|
||||
CRC: "150173.845981",
|
||||
CUC: "248.997666835",
|
||||
CVE: "23541.3675",
|
||||
CZK: "5770.848621",
|
||||
DAI: "247.0463573269230002455",
|
||||
DASH: "3.327367317363110236645",
|
||||
DJF: "44315.31795969",
|
||||
DKK: "1575.7370741",
|
||||
DOP: "14529.76988648",
|
||||
DZD: "32107.28592277",
|
||||
EEK: "3640.489633465",
|
||||
EGP: "3911.404438",
|
||||
EOS: "96.6873665825732601419",
|
||||
ERN: "3736.727740265",
|
||||
ETB: "9302.454572035",
|
||||
ETC: "44.91795888928957612395",
|
||||
ETH: "0.6574429621419051422355",
|
||||
EUR: "211.595",
|
||||
FJD: "533.11855575",
|
||||
FKP: "192.55642863",
|
||||
GBP: "192.87",
|
||||
GEL: "804.64145",
|
||||
GGP: "192.55642863",
|
||||
GHS: "1448.776859925",
|
||||
GIP: "192.55642863",
|
||||
GMD: "12891.70125",
|
||||
GNF: "2438630.43574976",
|
||||
GTQ: "1936.689014855",
|
||||
GYD: "52047.88891278",
|
||||
HKD: "1930.67861725",
|
||||
HNL: "6126.43736492",
|
||||
HRK: "1605.40119007",
|
||||
HTG: "15682.48428085",
|
||||
HUF: "77261.419177275",
|
||||
IDR: "3666848.2425",
|
||||
ILS: "843.29662455",
|
||||
IMP: "192.55642863",
|
||||
INR: "18275.43761675",
|
||||
IQD: "297176.65680577",
|
||||
ISK: "34639.44075",
|
||||
JEP: "192.55642863",
|
||||
JMD: "36261.061070375",
|
||||
JOD: "176.622535",
|
||||
JPY: "26304.9247525",
|
||||
KES: "27093.7474",
|
||||
KGS: "20240.23303148",
|
||||
KHR: "1021526.66327067",
|
||||
KMF: "104678.164103975",
|
||||
KNC: "275.5392102643512742545",
|
||||
KRW: "284115.6575",
|
||||
KWD: "76.196555935",
|
||||
KYD: "207.44852333",
|
||||
KZT: "106578.169689505",
|
||||
LAK: "2300372.70137523",
|
||||
LBP: "376426.60931701",
|
||||
LINK: "22.8704181013371177476",
|
||||
LKR: "45903.840861165",
|
||||
LRC: "1428.4116972477063306",
|
||||
LRD: "48689.521020355",
|
||||
LSL: "4093.68786226",
|
||||
LTC: "5.182877353583689269445",
|
||||
LTL: "803.357262175",
|
||||
LVL: "163.484459015",
|
||||
LYD: "340.470203685",
|
||||
MAD: "2290.86403115",
|
||||
MDL: "4231.74490411",
|
||||
MGA: "978918.42727237",
|
||||
MKD: "13034.71219274",
|
||||
MKR: "0.43727565410331105846",
|
||||
MMK: "321367.16219401",
|
||||
MNT: "706980.17312004",
|
||||
MOP: "1987.157222705",
|
||||
MRO: "88934.055",
|
||||
MTL: "170.32939187",
|
||||
MUR: "9942.18014823",
|
||||
MVR: "3836.371",
|
||||
MWK: "187533.350248305",
|
||||
MXN: "5285.574344805",
|
||||
MYR: "1033.2044625",
|
||||
MZN: "18168.45667469",
|
||||
NAD: "4120.3621",
|
||||
NGN: "95465.8503",
|
||||
NIO: "8675.07065117",
|
||||
NMR: "8.6886689628111785348",
|
||||
NOK: "2328.95371465",
|
||||
NPR: "29198.52701022",
|
||||
NZD: "378.934057915",
|
||||
OMG: "74.27621574882972595255",
|
||||
OMR: "95.913509955",
|
||||
OXT: "1023.479868529169993565",
|
||||
PAB: "249.115",
|
||||
PEN: "892.41413087",
|
||||
PGK: "870.976539545",
|
||||
PHP: "12100.979598855",
|
||||
PKR: "40413.26181118",
|
||||
PLN: "968.71705891",
|
||||
PYG: "1750259.579863715",
|
||||
QAR: "907.08999375",
|
||||
REN: "758.802924154736515935",
|
||||
REP: "18.2168190127970744169",
|
||||
REPV2: "18.225711080673967324",
|
||||
RON: "1032.33256",
|
||||
RSD: "24895.307525",
|
||||
RUB: "19351.4774035",
|
||||
RWF: "243426.179717085",
|
||||
SAR: "934.309544225",
|
||||
SBD: "2013.0584566",
|
||||
SCR: "4561.388071665",
|
||||
SEK: "2201.10291435",
|
||||
SGD: "338.356712025",
|
||||
SHP: "192.55642863",
|
||||
SLL: "2482430.971263275",
|
||||
SOS: "144000.839307095",
|
||||
SRD: "3525.97371",
|
||||
SSP: "32449.7199",
|
||||
STD: "5232524.31108792",
|
||||
SVC: "2178.147216215",
|
||||
SZL: "4091.741526765",
|
||||
THB: "7785.4665375",
|
||||
TJS: "2568.96954016",
|
||||
TMT: "871.9025",
|
||||
TND: "686.00043125",
|
||||
TOP: "578.0165522",
|
||||
TRY: "1963.587954325",
|
||||
TTD: "1689.460313635",
|
||||
TWD: "7158.9423125",
|
||||
TZS: "577510.41827928",
|
||||
UAH: "7061.44019619",
|
||||
UGX: "931508.2111739",
|
||||
UMA: "30.09543944427665349095",
|
||||
UNI: "79.18593747516647884725",
|
||||
USD: "249.115",
|
||||
USDC: "249.115",
|
||||
UYU: "10688.478117885",
|
||||
UZS: "2582693.606121005",
|
||||
VEF: "61901998.996866715",
|
||||
VES: "112695476.713406465",
|
||||
VND: "5773814.12282902",
|
||||
VUV: "28486.73470656",
|
||||
WST: "653.35042289",
|
||||
XAF: "138884.3079243",
|
||||
XAG: "10.22661168355",
|
||||
XAU: "0.1312935696",
|
||||
XCD: "673.24574325",
|
||||
XDR: "176.50246157",
|
||||
XLM: "2936.20532162536435083",
|
||||
XOF: "138884.3079243",
|
||||
XPD: "0.1061030608",
|
||||
XPF: "25265.84267069",
|
||||
XPT: "0.2910211253",
|
||||
XRP: "1014.931757995518373565",
|
||||
XTZ: "113.8135051169590628124",
|
||||
YER: "62365.930534515",
|
||||
YFI: "0.0178703370267443543872",
|
||||
ZAR: "4122.31765275",
|
||||
ZEC: "3.87305659203980154283",
|
||||
ZMK: "1308619.842149325",
|
||||
ZMW: "5027.95231667",
|
||||
ZRX: "644.844402797695193656",
|
||||
ZWL: "80215.03"
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
mockRates
|
||||
}
|
||||
+49
-18
@@ -1,28 +1,59 @@
|
||||
const chai = require("chai")
|
||||
const assert = require("assert")
|
||||
const assert = require("chai").assert
|
||||
const BCHJS = require("../../src/bch-js")
|
||||
const bchjs = new BCHJS()
|
||||
const axios = require("axios")
|
||||
const sinon = require("sinon")
|
||||
|
||||
const mockDataLib = require("./fixtures/price-mocks")
|
||||
let mockData
|
||||
|
||||
describe("#Price", () => {
|
||||
let sandbox
|
||||
let bchjs
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox()
|
||||
|
||||
bchjs = new BCHJS()
|
||||
|
||||
mockData = Object.assign({}, mockDataLib)
|
||||
})
|
||||
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
describe("#current", () => {
|
||||
describe("#single currency", () => {
|
||||
let sandbox
|
||||
beforeEach(() => (sandbox = sinon.createSandbox()))
|
||||
afterEach(() => sandbox.restore())
|
||||
it("should get current price for single currency", async () => {
|
||||
sandbox
|
||||
.stub(bchjs.Price.axios, "get")
|
||||
.resolves({ data: { price: 24905 } })
|
||||
|
||||
it("should get current price for single currency", done => {
|
||||
const data = 46347
|
||||
const resolved = new Promise(r => r({ data: data }))
|
||||
sandbox.stub(axios, "get").returns(resolved)
|
||||
const result = await bchjs.Price.current("usd")
|
||||
// console.log(result)
|
||||
|
||||
bchjs.Price.current("usd")
|
||||
.then(result => {
|
||||
assert.deepEqual(data.price, result)
|
||||
})
|
||||
.then(done, done)
|
||||
})
|
||||
assert.isNumber(result)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#getUsd", () => {
|
||||
it("should get the USD price of BCH", async () => {
|
||||
sandbox.stub(bchjs.Price.axios, "get").resolves({ data: { usd: 249.87 } })
|
||||
|
||||
const result = await bchjs.Price.getUsd()
|
||||
// console.log(result)
|
||||
|
||||
assert.isNumber(result)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#rates", () => {
|
||||
it("should get the price of BCH in several currencies", async () => {
|
||||
sandbox
|
||||
.stub(bchjs.Price.axios, "get")
|
||||
.resolves({ data: mockData.mockRates })
|
||||
|
||||
const result = await bchjs.Price.rates()
|
||||
// console.log(result)
|
||||
|
||||
assert.property(result, "USD")
|
||||
assert.property(result, "CAD")
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
+184
-16
@@ -231,22 +231,6 @@ describe("#SLP Utils", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("#balance", () => {
|
||||
it(`should fetch balance of single token for address: simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9`, async () => {
|
||||
// Mock the call to the REST API
|
||||
if (process.env.TEST === "unit")
|
||||
sandbox.stub(axios, "get").resolves({ data: mockData.mockBalance })
|
||||
|
||||
const balance = await slp.Utils.balance(
|
||||
"simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9",
|
||||
"df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb"
|
||||
)
|
||||
//console.log(`balance: ${JSON.stringify(balance, null, 2)}`)
|
||||
|
||||
assert2.hasAllKeys(balance, ["tokenId", "balance", "balanceString"])
|
||||
})
|
||||
})
|
||||
|
||||
describe("#validateTxid", () => {
|
||||
it(`should validate slp txid`, async () => {
|
||||
// Mock the call to the REST API
|
||||
@@ -1711,6 +1695,76 @@ describe("#SLP Utils", () => {
|
||||
|
||||
assert2.equal(data[2].isValid, false)
|
||||
})
|
||||
|
||||
it("should return null value when 429 recieved", async () => {
|
||||
const utxos = [
|
||||
{
|
||||
height: 654522,
|
||||
tx_hash:
|
||||
"072a1e2c2d5f1309bf4eef7f88684e4ecd544a903b386b07f3e04b91b13d8af1",
|
||||
tx_pos: 0,
|
||||
value: 6999,
|
||||
satoshis: 6999,
|
||||
txid:
|
||||
"072a1e2c2d5f1309bf4eef7f88684e4ecd544a903b386b07f3e04b91b13d8af1",
|
||||
vout: 0
|
||||
},
|
||||
{
|
||||
height: 654522,
|
||||
tx_hash:
|
||||
"a72db6a0883ecb8e379f317231b2571e41e041b7b1107e3e54c2e0b3386ac6ca",
|
||||
tx_pos: 1,
|
||||
value: 546,
|
||||
satoshis: 546,
|
||||
txid:
|
||||
"a72db6a0883ecb8e379f317231b2571e41e041b7b1107e3e54c2e0b3386ac6ca",
|
||||
vout: 1
|
||||
}
|
||||
]
|
||||
|
||||
sandbox.stub(slp.Utils, "decodeOpReturn").rejects({
|
||||
error:
|
||||
"Too many requests. Your limits are currently 3 requests per minute. Increase rate limits at https://fullstack.cash"
|
||||
})
|
||||
|
||||
const data = await slp.Utils.tokenUtxoDetails(utxos)
|
||||
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
||||
|
||||
// Values should be 'null' to signal that a determination could not be made
|
||||
// due to a throttling issue.
|
||||
assert.equal(data[0].isValid, null)
|
||||
assert.equal(data[1].isValid, null)
|
||||
})
|
||||
|
||||
// it("should handle a dust attack", async () => {
|
||||
it("#dustattack", async () => {
|
||||
// Mock external dependencies.
|
||||
// Stub the calls to decodeOpReturn.
|
||||
sandbox
|
||||
.stub(slp.Utils, "decodeOpReturn")
|
||||
.rejects(new Error("lokad id wrong size"))
|
||||
|
||||
const utxos = [
|
||||
{
|
||||
height: 655965,
|
||||
tx_hash:
|
||||
"a675af87dcd8d39be782737aa52e0076b52eb2f5ce355ffcb5567a64dd96b77e",
|
||||
tx_pos: 151,
|
||||
value: 547,
|
||||
satoshis: 547,
|
||||
txid:
|
||||
"a675af87dcd8d39be782737aa52e0076b52eb2f5ce355ffcb5567a64dd96b77e",
|
||||
vout: 151,
|
||||
address: "bitcoincash:qq4dw3sm8qvglspy6w2qg0u2ugsy9zcfcqrpeflwww",
|
||||
hdIndex: 11
|
||||
}
|
||||
]
|
||||
|
||||
const data = await slp.Utils.tokenUtxoDetails(utxos)
|
||||
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
||||
|
||||
assert.equal(data[0].isValid, false)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#txDetails", () => {
|
||||
@@ -1776,4 +1830,118 @@ describe("#SLP Utils", () => {
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe("#hydrateUtxos", () => {
|
||||
it("should throw an error if input is not an array", async () => {
|
||||
try {
|
||||
const utxos = 1234
|
||||
|
||||
await slp.Utils.hydrateUtxos(utxos)
|
||||
|
||||
assert2.equal(true, false, "Uh oh. Code path should not end here.")
|
||||
} catch (err) {
|
||||
// console.log(`Error: `, err)
|
||||
assert2.include(err.message, `Input must be an array.`)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("#validateTxid2", () => {
|
||||
it("should throw an error if the input is an array", async () => {
|
||||
try {
|
||||
const txid = [
|
||||
"f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a"
|
||||
]
|
||||
|
||||
await slp.Utils.validateTxid2(txid)
|
||||
|
||||
assert2.equal(true, false, "Unexpected result")
|
||||
} catch (err) {
|
||||
// console.log("err: ", err)
|
||||
assert2.include(err.message, "txid must be 64 character string")
|
||||
}
|
||||
})
|
||||
|
||||
it("should throw an error for a malformed txid", async () => {
|
||||
try {
|
||||
const txid =
|
||||
"f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783"
|
||||
|
||||
await slp.Utils.validateTxid2(txid)
|
||||
|
||||
assert2.equal(true, false, "Unexpected result")
|
||||
} catch (err) {
|
||||
// console.log("err: ", err)
|
||||
assert2.include(err.message, "txid must be 64 character string")
|
||||
}
|
||||
})
|
||||
|
||||
it("should invalidate a known invalid TXID", async () => {
|
||||
const txid =
|
||||
"f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a"
|
||||
|
||||
// Mock live network calls.
|
||||
sandbox.stub(axios, "get").resolves({
|
||||
data: {
|
||||
txid: txid,
|
||||
isValid: false,
|
||||
msg: ""
|
||||
}
|
||||
})
|
||||
|
||||
const result = await slp.Utils.validateTxid2(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert2.property(result, "txid")
|
||||
assert2.equal(result.txid, txid)
|
||||
|
||||
assert2.property(result, "isValid")
|
||||
assert2.equal(result.isValid, false)
|
||||
})
|
||||
|
||||
it("should validate a known valid TXID", async () => {
|
||||
const txid =
|
||||
"3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488"
|
||||
|
||||
// Mock live network calls.
|
||||
sandbox.stub(axios, "get").resolves({
|
||||
data: {
|
||||
txid: txid,
|
||||
isValid: true,
|
||||
msg: ""
|
||||
}
|
||||
})
|
||||
|
||||
const result = await slp.Utils.validateTxid2(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert2.property(result, "txid")
|
||||
assert2.equal(result.txid, txid)
|
||||
|
||||
assert2.property(result, "isValid")
|
||||
assert2.equal(result.isValid, true)
|
||||
})
|
||||
|
||||
// slp-validate can take a long time. bch-api cuts it off if it fails to
|
||||
// return is less than 10 seconds. This test case handle this situation.
|
||||
it("should handle timeout errors", async () => {
|
||||
try {
|
||||
const txid =
|
||||
"eacb1085dfa296fef6d4ae2c0f4529a1bef096dd2325bdcc6dcb5241b3bdb579"
|
||||
|
||||
// Mock live network calls.
|
||||
sandbox.stub(axios, "get").rejects({
|
||||
error:
|
||||
"Network error: Could not communicate with full node or other external service."
|
||||
})
|
||||
|
||||
await slp.Utils.validateTxid2(txid)
|
||||
|
||||
assert2.equal(true, false, "Unexpected result")
|
||||
} catch (err) {
|
||||
// console.log("err: ", err)
|
||||
assert2.include(err.message, "slp-validate timed out")
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user