mirror of
https://github.com/Permissionless-Software-Foundation/bch-js.git
synced 2026-09-22 09:02:01 -07:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d5f7e6aa7f | ||
|
|
04e3346086 | ||
|
|
cb2a90fc93 | ||
|
|
66c2d3ab22 | ||
|
|
89d13fe241 | ||
|
|
ad0b1b5ddb | ||
|
|
ae30b89d68 | ||
|
|
2e88d26ff2 | ||
|
|
b1745d37e0 | ||
|
|
9733c07e04 | ||
|
|
430f5f015e | ||
|
|
9e76b34d05 | ||
|
|
61078b2e91 | ||
|
|
82733a7e1a | ||
|
|
3685ea1541 | ||
|
|
5f217af3e9 | ||
|
|
e2ca3cfb00 | ||
|
|
690520d72e | ||
|
|
36660f3bc9 | ||
|
|
80ee5c8d31 | ||
|
|
b7e04522ce | ||
|
|
19f243428d | ||
|
|
16079c8d04 | ||
|
|
6743ca5fa9 | ||
|
|
ec046d3ef7 | ||
|
|
85405d8e70 | ||
|
|
1989b72b2a | ||
|
|
f1f2bf42d9 | ||
|
|
348a073714 | ||
|
|
e822b91e2c | ||
|
|
29a5173036 | ||
|
|
0bffff6f9b | ||
|
|
8c603d3886 | ||
|
|
542e59461f | ||
|
|
0912aadc1a | ||
|
|
638804de42 | ||
|
|
fe33ba3381 | ||
|
|
6f913cf3ad | ||
|
|
4d94ad13ff | ||
|
|
c02080d12a | ||
|
|
cc1809b242 | ||
|
|
13a7917d9b | ||
|
|
1573e0bc4c |
@@ -40,6 +40,72 @@ the [psf-bch-api](https://github.com/Permissionless-Software-Foundation/psf-bch-
|
||||
- BCHN Mainnet REST API server: https://x402-bch.fullstack.cash/v7/
|
||||
- Check server status: https://metrics.fullstack.cash
|
||||
|
||||
## Configuration
|
||||
|
||||
bch-js can be configured through constructor options or environment variables. Configuration options passed to the constructor take precedence over environment variables.
|
||||
|
||||
### Constructor Options
|
||||
|
||||
When instantiating BCHJS, you can pass a configuration object:
|
||||
|
||||
```javascript
|
||||
import BCHJS from "@psf/bch-js"
|
||||
|
||||
const bchjs = new BCHJS({
|
||||
restURL: 'https://x402-bch.fullstack.cash/v5/',
|
||||
bearerToken: 'your-bearer-token',
|
||||
wif: 'your-private-key-wif',
|
||||
paymentAmountSats: 20000,
|
||||
bchServerURL: 'https://bch.fullstack.cash'
|
||||
})
|
||||
```
|
||||
|
||||
### Configuration Options
|
||||
|
||||
| Option | Type | Required | Default | Description |
|
||||
|--------|------|----------|---------|-------------|
|
||||
| `restURL` | string | Yes* | - | The REST API server URL for making API calls. Must include trailing slash. *Required unless `RESTURL` environment variable is set. |
|
||||
| `bearerToken` | string | No | `''` | Bearer token for authentication with the REST API server. |
|
||||
| `wif` | string | No | `''` | Private key in WIF format. When provided, enables automatic x402 payment handling. |
|
||||
| `paymentAmountSats` | number | No | `20000` | Default amount of satoshis to send when making x402 payments. |
|
||||
| `bchServerURL` | string | No | `'https://bch.fullstack.cash'` | BCH server URL used for broadcasting payment transactions to the blockchain. This is separate from `restURL` and is specifically for x402 payment processing. |
|
||||
|
||||
### Environment Variables
|
||||
|
||||
You can also configure bch-js using environment variables:
|
||||
|
||||
| Environment Variable | Config Option | Description |
|
||||
|---------------------|---------------|-------------|
|
||||
| `RESTURL` | `restURL` | REST API server URL for making API calls. |
|
||||
| `BCHJSBEARERTOKEN` | `bearerToken` | Bearer token for API authentication. |
|
||||
| `BCHJSWIF` | `wif` | Private key in WIF format for x402 payments. |
|
||||
| `BCHJSBCHSERVERURL` | `bchServerURL` | BCH server URL for x402 payment transactions. |
|
||||
|
||||
### Understanding restURL vs bchServerURL
|
||||
|
||||
These two configuration options serve different purposes:
|
||||
|
||||
- **`restURL`**: The REST API server used for all regular API calls (utxo queries, transaction history, etc.). This can be any bch-api compatible server, such as `https://x402-bch.fullstack.cash/v5/` or `https://bch.fullstack.cash/v5/`.
|
||||
|
||||
- **`bchServerURL`**: The BCH infrastructure server used specifically for broadcasting x402 payment transactions to the blockchain. This defaults to `https://bch.fullstack.cash` and should typically remain unchanged unless you have specific infrastructure requirements.
|
||||
|
||||
**Example Use Case**: Most users will use `https://x402-bch.fullstack.cash/v5/` as their `restURL` to access x402-protected APIs. However, when bch-js needs to make an x402 payment, it uses the `bchServerURL` (default: `https://bch.fullstack.cash`) to broadcast the payment transaction. This ensures payment transactions are sent through a reliable BCH infrastructure endpoint.
|
||||
|
||||
```javascript
|
||||
// Use x402-bch server for API calls, but bch.fullstack.cash for payments
|
||||
const bchjs = new BCHJS({
|
||||
restURL: 'https://x402-bch.fullstack.cash/v5/',
|
||||
wif: 'your-private-key-wif'
|
||||
// bchServerURL defaults to 'https://bch.fullstack.cash'
|
||||
})
|
||||
|
||||
// Or explicitly set both
|
||||
const bchjs2 = new BCHJS({
|
||||
restURL: 'https://x402-bch.fullstack.cash/v5/',
|
||||
bchServerURL: 'https://bch.fullstack.cash',
|
||||
wif: 'your-private-key-wif'
|
||||
})
|
||||
```
|
||||
|
||||
### Web Apps
|
||||
|
||||
|
||||
Generated
+739
-557
File diff suppressed because it is too large
Load Diff
+11
-10
@@ -2,7 +2,7 @@
|
||||
"name": "@psf/bch-js",
|
||||
"version": "7.0.0",
|
||||
"type": "module",
|
||||
"description": "A JavaScript library for working with Bitcoin Cash, eCash, and SLP Tokens",
|
||||
"description": "A JavaScript library for working with Bitcoin Cash and SLP Tokens",
|
||||
"author": "Chris Troutner <chris.troutner@gmail.com>",
|
||||
"contributors": [
|
||||
"Gabriel Cardona <gabriel@bitcoin.com>",
|
||||
@@ -10,14 +10,16 @@
|
||||
],
|
||||
"main": "src/bch-js.js",
|
||||
"scripts": {
|
||||
"test": "c8 mocha --trace-warnings --unhandled-rejections=strict --timeout 30000 test/unit/",
|
||||
"test": "export RESTURL=http://localhost:5942/v6 && c8 mocha --trace-warnings --unhandled-rejections=strict --timeout 30000 test/unit/",
|
||||
"test:custom": "export RESTURL=http://localhost:5942/v6 && c8 mocha --trace-warnings --unhandled-rejections=strict --timeout 60000 ${MOCHA_GREP:+--grep $MOCHA_GREP} test/unit/",
|
||||
"test:integration": "npm run test:integration:local:noauth",
|
||||
"test:integration:nft": "export RESTURL=https://bchn.fullstack.cash/v6/ && export IS_USING_FREE_TIER=true && mocha --timeout 30000 -g '#nft1' test/integration/slp.js",
|
||||
"test:integration:bchn": "export RESTURL=https://bchn.fullstack.cash/v6/ && export IS_USING_FREE_TIER=true && mocha --timeout 30000 test/integration/",
|
||||
"test:integration:local:noauth": "export RESTURL=http://localhost:5942/v6/ && mocha --timeout 30000 test/integration/",
|
||||
"test:integration:local:auth": "export RESTURL=http://5.78.147.3:5942/v6/ && export BCHJSBEARERTOKEN=temp01 && mocha --timeout 30000 test/integration/",
|
||||
"test:integration:decatur": "export RESTURL=http://192.168.2.127:5942/v6/ && mocha --timeout 30000 test/integration/",
|
||||
"test:integration:x402": "export RESTURL=http://localhost:5942/v6/ && export BCHJSWIF=L1eYaneXDDXy8VDig4Arwe8wYHbhtsA5wuQvwsKwhaYeneoZuKG4 && mocha --timeout 30000 test/integration/",
|
||||
"test:integration:fullstack:free": "export RESTURL=https://bch.fullstack.cash/v6 && mocha --timeout 60000 test/integration/",
|
||||
"test:integration:fullstack:x402": "export RESTURL=https://x402-bch.fullstack.cash/v6 && export BCHJSWIF=L1eYaneXDDXy8VDig4Arwe8wYHbhtsA5wuQvwsKwhaYeneoZuKG4 && mocha --timeout 120000 test/integration/",
|
||||
"test:integration:fullstack:auth": "export RESTURL=http://dev.fullstack.cash/v6 && export BCHJSBEARERTOKEN=test01 && mocha --timeout 30000 test/integration/",
|
||||
"test:integration:local:noauth": "export RESTURL=http://192.168.1.65:5942/v6 && mocha --timeout 30000 test/integration/",
|
||||
"test:integration:local:auth": "export RESTURL=http://192.168.1.115:5942/v6 && export BCHJSBEARERTOKEN=temp01 && mocha --timeout 30000 test/integration/",
|
||||
"test:integration:local:x402": "export RESTURL=http://localhost:5942/v6 && export BCHJSWIF=L1eYaneXDDXy8VDig4Arwe8wYHbhtsA5wuQvwsKwhaYeneoZuKG4 && mocha --timeout 1200000 test/integration/",
|
||||
"test:integration:decatur": "export RESTURL=http://192.168.1.65:5942/v6 && mocha --timeout 30000 test/integration/",
|
||||
"coverage": "nyc --reporter=html mocha --timeout 25000 test/unit/",
|
||||
"docs": "./node_modules/.bin/apidoc -i src/ -o docs && ./fix-docs-contrast.sh",
|
||||
"lint": "standard --env mocha --fix"
|
||||
@@ -31,7 +33,6 @@
|
||||
"dependencies": {
|
||||
"@chris.troutner/bip32-utils": "1.0.5",
|
||||
"@psf/bip21": "2.0.1",
|
||||
"@psf/bitcoincash-ops": "2.0.0",
|
||||
"@psf/bitcoincashjs-lib": "4.0.3",
|
||||
"@psf/coininfo": "4.0.0",
|
||||
"axios": "1.13.2",
|
||||
@@ -53,7 +54,7 @@
|
||||
"slp-mdm": "0.0.7",
|
||||
"slp-parser": "0.0.4",
|
||||
"wif": "2.0.6",
|
||||
"x402-bch-axios": "1.1.1"
|
||||
"x402-bch-axios": "2.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"apidoc": "1.2.0",
|
||||
|
||||
+28
-5
@@ -45,7 +45,6 @@ import Ecash from './ecash.js'
|
||||
// Indexers
|
||||
import Electrumx from './electrumx.js'
|
||||
import PsfSlpIndexer from './psf-slp-indexer.js'
|
||||
const DEFAULT_REST_API = 'https://api.fullstack.cash/v6/'
|
||||
|
||||
class BCHJS {
|
||||
constructor (config) {
|
||||
@@ -54,7 +53,16 @@ class BCHJS {
|
||||
this.restURL = config.restURL
|
||||
} else if (process.env.RESTURL && process.env.RESTURL !== '') {
|
||||
this.restURL = process.env.RESTURL
|
||||
} else this.restURL = DEFAULT_REST_API
|
||||
} else {
|
||||
throw new Error(
|
||||
'REST API URL is required. Provide config.restURL or set the RESTURL environment variable.'
|
||||
)
|
||||
}
|
||||
|
||||
// Normalize restURL to always have a trailing slash
|
||||
if (!this.restURL.endsWith('/')) {
|
||||
this.restURL = this.restURL + '/'
|
||||
}
|
||||
|
||||
// Retrieve the Bearer token for simple token authentication.
|
||||
this.bearerToken = '' // default value.
|
||||
@@ -78,8 +86,20 @@ class BCHJS {
|
||||
} else if (process.env.BCHJSWIF && process.env.BCHJSWIF !== '') {
|
||||
this.wif = process.env.BCHJSWIF
|
||||
}
|
||||
this.paymentAmountSats = (config && config.paymentAmountSats) || 2000 * 10
|
||||
this.bchServerURL = (config && config.bchServerURL) || 'https://free-bch.fullstack.cash'
|
||||
|
||||
// Most TXs cost about 250 sats. So we'll set the default to 25000 sats,
|
||||
// so the mining fee is 1% of the transaction.
|
||||
this.paymentAmountSats = (config && config.paymentAmountSats) || 25000
|
||||
|
||||
// BCH server URL for x402 payments (separate from REST API server)
|
||||
// This is used when broadcasting payment transactions to the blockchain
|
||||
if (config && config.bchServerURL && config.bchServerURL !== '') {
|
||||
this.bchServerURL = config.bchServerURL
|
||||
} else if (process.env.BCHJSBCHSERVERURL && process.env.BCHJSBCHSERVERURL !== '') {
|
||||
this.bchServerURL = process.env.BCHJSBCHSERVERURL
|
||||
} else {
|
||||
this.bchServerURL = 'https://bch.fullstack.cash/v6'
|
||||
}
|
||||
|
||||
const libConfig = {
|
||||
restURL: this.restURL,
|
||||
@@ -100,7 +120,10 @@ class BCHJS {
|
||||
axiosInstance = withPaymentInterceptor(
|
||||
axiosInstance,
|
||||
signer,
|
||||
{ bchServerURL: this.bchServerURL }
|
||||
{
|
||||
apiType: 'rest-api',
|
||||
bchServerURL: this.bchServerURL
|
||||
}
|
||||
)
|
||||
|
||||
libConfig.axios = axiosInstance
|
||||
|
||||
+97
-38
@@ -47,8 +47,11 @@ class Blockchain {
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
if (error.response && error.response.data) {
|
||||
const errorData = error.response.data
|
||||
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||
throw new Error(errorMessage)
|
||||
} else throw error
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,8 +108,11 @@ class Blockchain {
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
if (error.response && error.response.data) {
|
||||
const errorData = error.response.data
|
||||
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||
throw new Error(errorMessage)
|
||||
} else throw error
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,8 +161,11 @@ class Blockchain {
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
if (error.response && error.response.data) {
|
||||
const errorData = error.response.data
|
||||
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||
throw new Error(errorMessage)
|
||||
} else throw error
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,8 +198,11 @@ class Blockchain {
|
||||
console.log('Error in bch-js/blockchain.js/getBlockCount()')
|
||||
console.log('blockchain.js restURL: ', this.restURL)
|
||||
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
if (error.response && error.response.data) {
|
||||
const errorData = error.response.data
|
||||
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||
throw new Error(errorMessage)
|
||||
} else throw error
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,8 +234,11 @@ class Blockchain {
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
if (error.response && error.response.data) {
|
||||
const errorData = error.response.data
|
||||
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||
throw new Error(errorMessage)
|
||||
} else throw error
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,8 +302,13 @@ class Blockchain {
|
||||
|
||||
throw new Error('Input hash must be a string or array of strings.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
// console.log('Error in bch-js/blockchain.js/getBlockHeader() error: ', error)
|
||||
|
||||
if (error.response && error.response.data) {
|
||||
const errorData = error.response.data
|
||||
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||
throw new Error(errorMessage)
|
||||
} else throw error
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,8 +350,11 @@ class Blockchain {
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
if (error.response && error.response.data) {
|
||||
const errorData = error.response.data
|
||||
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||
throw new Error(errorMessage)
|
||||
} else throw error
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,8 +385,11 @@ class Blockchain {
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
if (error.response && error.response.data) {
|
||||
const errorData = error.response.data
|
||||
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||
throw new Error(errorMessage)
|
||||
} else throw error
|
||||
}
|
||||
}
|
||||
|
||||
@@ -378,8 +404,11 @@ class Blockchain {
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
if (error.response && error.response.data) {
|
||||
const errorData = error.response.data
|
||||
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||
throw new Error(errorMessage)
|
||||
} else throw error
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,8 +422,11 @@ class Blockchain {
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
if (error.response && error.response.data) {
|
||||
const errorData = error.response.data
|
||||
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||
throw new Error(errorMessage)
|
||||
} else throw error
|
||||
}
|
||||
}
|
||||
|
||||
@@ -505,8 +537,11 @@ class Blockchain {
|
||||
|
||||
throw new Error('Input must be a string or array of strings.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
if (error.response && error.response.data) {
|
||||
const errorData = error.response.data
|
||||
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||
throw new Error(errorMessage)
|
||||
} else throw error
|
||||
}
|
||||
}
|
||||
|
||||
@@ -541,8 +576,11 @@ class Blockchain {
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
if (error.response && error.response.data) {
|
||||
const errorData = error.response.data
|
||||
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||
throw new Error(errorMessage)
|
||||
} else throw error
|
||||
}
|
||||
}
|
||||
|
||||
@@ -588,8 +626,11 @@ class Blockchain {
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
if (error.response && error.response.data) {
|
||||
const errorData = error.response.data
|
||||
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||
throw new Error(errorMessage)
|
||||
} else throw error
|
||||
}
|
||||
}
|
||||
|
||||
@@ -642,8 +683,11 @@ class Blockchain {
|
||||
|
||||
return response.data
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
if (error.response && error.response.data) {
|
||||
const errorData = error.response.data
|
||||
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||
throw new Error(errorMessage)
|
||||
} else throw error
|
||||
}
|
||||
}
|
||||
|
||||
@@ -709,8 +753,11 @@ class Blockchain {
|
||||
|
||||
throw new Error('Input must be a string or array of strings.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
if (error.response && error.response.data) {
|
||||
const errorData = error.response.data
|
||||
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||
throw new Error(errorMessage)
|
||||
} else throw error
|
||||
}
|
||||
}
|
||||
|
||||
@@ -722,8 +769,11 @@ class Blockchain {
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
if (error.response && error.response.data) {
|
||||
const errorData = error.response.data
|
||||
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||
throw new Error(errorMessage)
|
||||
} else throw error
|
||||
}
|
||||
}
|
||||
|
||||
@@ -735,8 +785,11 @@ class Blockchain {
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
if (error.response && error.response.data) {
|
||||
const errorData = error.response.data
|
||||
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||
throw new Error(errorMessage)
|
||||
} else throw error
|
||||
}
|
||||
}
|
||||
|
||||
@@ -748,8 +801,11 @@ class Blockchain {
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
if (error.response && error.response.data) {
|
||||
const errorData = error.response.data
|
||||
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||
throw new Error(errorMessage)
|
||||
} else throw error
|
||||
}
|
||||
}
|
||||
|
||||
@@ -816,8 +872,11 @@ class Blockchain {
|
||||
|
||||
throw new Error('Input must be a string or array of strings.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
if (error.response && error.response.data) {
|
||||
const errorData = error.response.data
|
||||
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||
throw new Error(errorMessage)
|
||||
} else throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-3
@@ -6,7 +6,8 @@ class DSProof {
|
||||
constructor (config) {
|
||||
this.restURL = config.restURL
|
||||
this.authToken = config.authToken
|
||||
this.axios = axios
|
||||
// Use the shared axios instance if provided, otherwise fall back to axios
|
||||
this.axios = config.axios || axios
|
||||
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
@@ -61,8 +62,11 @@ class DSProof {
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
if (error.response && error.response.data) {
|
||||
const errorData = error.response.data
|
||||
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||
throw new Error(errorMessage)
|
||||
} else throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+37
-15
@@ -120,8 +120,11 @@ class ElectrumX {
|
||||
|
||||
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
|
||||
if (error.response && error.response.data) {
|
||||
const errorData = error.response.data
|
||||
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||
throw new Error(errorMessage)
|
||||
} else throw error
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,8 +207,11 @@ class ElectrumX {
|
||||
|
||||
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
|
||||
if (error.response && error.response.data) {
|
||||
const errorData = error.response.data
|
||||
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||
throw new Error(errorMessage)
|
||||
} else throw error
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,8 +311,11 @@ class ElectrumX {
|
||||
throw new Error('Input address must be a string or array of strings.')
|
||||
} catch (error) {
|
||||
// console.log('Error in transactions(): ', error)
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
if (error.response && error.response.data) {
|
||||
const errorData = error.response.data
|
||||
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||
throw new Error(errorMessage)
|
||||
} else throw error
|
||||
}
|
||||
}
|
||||
|
||||
@@ -397,8 +406,11 @@ class ElectrumX {
|
||||
|
||||
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
|
||||
if (error.response && error.response.data) {
|
||||
const errorData = error.response.data
|
||||
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||
throw new Error(errorMessage)
|
||||
} else throw error
|
||||
}
|
||||
}
|
||||
|
||||
@@ -453,9 +465,13 @@ class ElectrumX {
|
||||
} 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
|
||||
const errorData = error.response.data
|
||||
if (errorData.error) {
|
||||
throw new Error(errorData.error)
|
||||
} else {
|
||||
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.message || JSON.stringify(errorData))
|
||||
throw new Error(errorMessage)
|
||||
}
|
||||
} else {
|
||||
throw error
|
||||
}
|
||||
@@ -555,8 +571,11 @@ class ElectrumX {
|
||||
|
||||
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
|
||||
if (error.response && error.response.data) {
|
||||
const errorData = error.response.data
|
||||
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||
throw new Error(errorMessage)
|
||||
} else throw error
|
||||
}
|
||||
}
|
||||
|
||||
@@ -595,8 +614,11 @@ class ElectrumX {
|
||||
|
||||
throw new Error('Input txHex must be a string.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
if (error.response && error.response.data) {
|
||||
const errorData = error.response.data
|
||||
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||
throw new Error(errorMessage)
|
||||
} else throw error
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ class Price {
|
||||
async getUsd () {
|
||||
try {
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}price/usd`,
|
||||
`${this.restURL}price/bchusd`,
|
||||
this.axiosOptions
|
||||
)
|
||||
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
|
||||
|
||||
+23
-5
@@ -12,6 +12,7 @@ import axios from 'axios'
|
||||
// Local libraries
|
||||
import RawTransaction from './raw-transactions.js'
|
||||
import SlpUtils from './slp/utils.js'
|
||||
import Blockchain from './blockchain.js'
|
||||
|
||||
// let _this
|
||||
|
||||
@@ -31,6 +32,7 @@ class PsfSlpIndexer {
|
||||
// Encapsulate dependencies
|
||||
this.rawTransaction = new RawTransaction(config)
|
||||
this.slpUtils = new SlpUtils(config)
|
||||
this.blockchain = new Blockchain(config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,7 +68,7 @@ class PsfSlpIndexer {
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
if (error.response && error.response.data && error.response.data.error) throw new Error(error.response.data.error)
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
@@ -134,7 +136,7 @@ class PsfSlpIndexer {
|
||||
}
|
||||
throw new Error('Input address must be a string.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
if (error.response && error.response.data && error.response.data.error) throw new Error(error.response.data.error)
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
@@ -199,7 +201,7 @@ class PsfSlpIndexer {
|
||||
}
|
||||
throw new Error('Input tokenId must be a string.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
if (error.response && error.response.data && error.response.data.error) throw new Error(error.response.data.error)
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
@@ -317,6 +319,22 @@ class PsfSlpIndexer {
|
||||
const txDetails = await this.rawTransaction.getTxData(txid)
|
||||
// console.log(`txDetails: ${JSON.stringify(txDetails, null, 2)}`)
|
||||
|
||||
// Add blockheight, height, time, and blocktime to the txDetails object.
|
||||
if (txDetails.height === null) {
|
||||
// Get current block height and increment by 1
|
||||
const currentBlockHeight = await this.blockchain.getBlockCount()
|
||||
const estimatedHeight = currentBlockHeight + 1
|
||||
|
||||
// Set height and blockheight
|
||||
txDetails.height = estimatedHeight
|
||||
txDetails.blockheight = estimatedHeight
|
||||
|
||||
// Set time and blocktime to current unix timestamp
|
||||
const currentTime = Math.floor(Date.now() / 1000)
|
||||
txDetails.time = currentTime
|
||||
txDetails.blocktime = currentTime
|
||||
}
|
||||
|
||||
if (isInBlacklist) {
|
||||
txDetails.isValidSlp = null
|
||||
} else {
|
||||
@@ -427,7 +445,7 @@ class PsfSlpIndexer {
|
||||
}
|
||||
throw new Error('Input tokenId must be a string.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
if (error.response && error.response.data && error.response.data.error) throw new Error(error.response.data.error)
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
@@ -522,7 +540,7 @@ class PsfSlpIndexer {
|
||||
throw new Error('Input tokenId must be a string.')
|
||||
} catch (error) {
|
||||
// console.log('error: ', error)
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
if (error.response && error.response.data && error.response.data.error) throw new Error(error.response.data.error)
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
|
||||
+126
-3
@@ -1,7 +1,130 @@
|
||||
import Bitcoin from '@psf/bitcoincashjs-lib'
|
||||
import { createRequire } from 'module'
|
||||
const require = createRequire(import.meta.url)
|
||||
const opcodes = require('@psf/bitcoincash-ops')
|
||||
|
||||
// Inline opcodes data to avoid fs/import.meta issues in browser builds.
|
||||
// This data is from @psf/bitcoincash-ops/index.json
|
||||
const opcodes = {
|
||||
OP_FALSE: 0,
|
||||
OP_0: 0,
|
||||
OP_PUSHDATA1: 76,
|
||||
OP_PUSHDATA2: 77,
|
||||
OP_PUSHDATA4: 78,
|
||||
OP_1NEGATE: 79,
|
||||
OP_RESERVED: 80,
|
||||
OP_TRUE: 81,
|
||||
OP_1: 81,
|
||||
OP_2: 82,
|
||||
OP_3: 83,
|
||||
OP_4: 84,
|
||||
OP_5: 85,
|
||||
OP_6: 86,
|
||||
OP_7: 87,
|
||||
OP_8: 88,
|
||||
OP_9: 89,
|
||||
OP_10: 90,
|
||||
OP_11: 91,
|
||||
OP_12: 92,
|
||||
OP_13: 93,
|
||||
OP_14: 94,
|
||||
OP_15: 95,
|
||||
OP_16: 96,
|
||||
OP_NOP: 97,
|
||||
OP_VER: 98,
|
||||
OP_IF: 99,
|
||||
OP_NOTIF: 100,
|
||||
OP_VERIF: 101,
|
||||
OP_VERNOTIF: 102,
|
||||
OP_ELSE: 103,
|
||||
OP_ENDIF: 104,
|
||||
OP_VERIFY: 105,
|
||||
OP_RETURN: 106,
|
||||
OP_TOALTSTACK: 107,
|
||||
OP_FROMALTSTACK: 108,
|
||||
OP_2DROP: 109,
|
||||
OP_2DUP: 110,
|
||||
OP_3DUP: 111,
|
||||
OP_2OVER: 112,
|
||||
OP_2ROT: 113,
|
||||
OP_2SWAP: 114,
|
||||
OP_IFDUP: 115,
|
||||
OP_DEPTH: 116,
|
||||
OP_DROP: 117,
|
||||
OP_DUP: 118,
|
||||
OP_NIP: 119,
|
||||
OP_OVER: 120,
|
||||
OP_PICK: 121,
|
||||
OP_ROLL: 122,
|
||||
OP_ROT: 123,
|
||||
OP_SWAP: 124,
|
||||
OP_TUCK: 125,
|
||||
OP_CAT: 126,
|
||||
OP_SPLIT: 127,
|
||||
OP_NUM2BIN: 128,
|
||||
OP_BIN2NUM: 129,
|
||||
OP_SIZE: 130,
|
||||
OP_INVERT: 131,
|
||||
OP_AND: 132,
|
||||
OP_OR: 133,
|
||||
OP_XOR: 134,
|
||||
OP_EQUAL: 135,
|
||||
OP_EQUALVERIFY: 136,
|
||||
OP_RESERVED1: 137,
|
||||
OP_RESERVED2: 138,
|
||||
OP_1ADD: 139,
|
||||
OP_1SUB: 140,
|
||||
OP_2MUL: 141,
|
||||
OP_2DIV: 142,
|
||||
OP_NEGATE: 143,
|
||||
OP_ABS: 144,
|
||||
OP_NOT: 145,
|
||||
OP_0NOTEQUAL: 146,
|
||||
OP_ADD: 147,
|
||||
OP_SUB: 148,
|
||||
OP_MUL: 149,
|
||||
OP_DIV: 150,
|
||||
OP_MOD: 151,
|
||||
OP_LSHIFT: 152,
|
||||
OP_RSHIFT: 153,
|
||||
OP_BOOLAND: 154,
|
||||
OP_BOOLOR: 155,
|
||||
OP_NUMEQUAL: 156,
|
||||
OP_NUMEQUALVERIFY: 157,
|
||||
OP_NUMNOTEQUAL: 158,
|
||||
OP_LESSTHAN: 159,
|
||||
OP_GREATERTHAN: 160,
|
||||
OP_LESSTHANOREQUAL: 161,
|
||||
OP_GREATERTHANOREQUAL: 162,
|
||||
OP_MIN: 163,
|
||||
OP_MAX: 164,
|
||||
OP_WITHIN: 165,
|
||||
OP_RIPEMD160: 166,
|
||||
OP_SHA1: 167,
|
||||
OP_SHA256: 168,
|
||||
OP_HASH160: 169,
|
||||
OP_HASH256: 170,
|
||||
OP_CODESEPARATOR: 171,
|
||||
OP_CHECKSIG: 172,
|
||||
OP_CHECKSIGVERIFY: 173,
|
||||
OP_CHECKMULTISIG: 174,
|
||||
OP_CHECKMULTISIGVERIFY: 175,
|
||||
OP_NOP1: 176,
|
||||
OP_NOP2: 177,
|
||||
OP_CHECKLOCKTIMEVERIFY: 177,
|
||||
OP_NOP3: 178,
|
||||
OP_CHECKSEQUENCEVERIFY: 178,
|
||||
OP_NOP4: 179,
|
||||
OP_NOP5: 180,
|
||||
OP_NOP6: 181,
|
||||
OP_NOP7: 182,
|
||||
OP_NOP8: 183,
|
||||
OP_NOP9: 184,
|
||||
OP_NOP10: 185,
|
||||
OP_CHECKDATASIG: 186,
|
||||
OP_CHECKDATASIGVERIFY: 187,
|
||||
OP_REVERSEBYTES: 188,
|
||||
OP_PUBKEYHASH: 253,
|
||||
OP_PUBKEY: 254,
|
||||
OP_INVALIDOPCODE: 255
|
||||
}
|
||||
|
||||
class Script {
|
||||
constructor () {
|
||||
|
||||
@@ -20,6 +20,12 @@ class UTXO {
|
||||
this.psfSlpIndexer = new PsfSlpIndexer(config)
|
||||
this.BigNumber = BigNumber
|
||||
this.blockchain = new Blockchain(config)
|
||||
|
||||
// Bind 'this' object to all subfunctions.
|
||||
this.get = this.get.bind(this)
|
||||
this.hydrateTokenData = this.hydrateTokenData.bind(this)
|
||||
this.findBiggestUtxo = this.findBiggestUtxo.bind(this)
|
||||
this.isValid = this.isValid.bind(this)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -103,8 +103,8 @@ describe('#blockchain', () => {
|
||||
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')
|
||||
assert.instanceOf(err, Error)
|
||||
assert.include(err.message, 'Array too large')
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -171,8 +171,8 @@ describe('#blockchain', () => {
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
// console.log(`err: ${util.inspect(err)}`)
|
||||
assert.hasAnyKeys(err, ['error'])
|
||||
assert.include(err.error, 'Transaction not in mempool')
|
||||
assert.instanceOf(err, Error)
|
||||
assert.include(err.message, 'Transaction not in mempool')
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -241,8 +241,8 @@ describe('#blockchain', () => {
|
||||
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')
|
||||
assert.instanceOf(err, Error)
|
||||
assert.include(err.message, 'Array too large')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -73,8 +73,8 @@ describe('#ElectrumX', () => {
|
||||
// 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')
|
||||
assert.instanceOf(err, Error)
|
||||
assert.include(err.message, 'Array too large')
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -129,8 +129,8 @@ describe('#ElectrumX', () => {
|
||||
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ['error'])
|
||||
assert.include(err.error, 'Array too large')
|
||||
assert.instanceOf(err, Error)
|
||||
assert.include(err.message, 'Array too large')
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -187,8 +187,8 @@ describe('#ElectrumX', () => {
|
||||
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ['error'])
|
||||
assert.include(err.error, 'Array too large')
|
||||
assert.instanceOf(err, Error)
|
||||
assert.include(err.message, 'Array too large')
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -250,8 +250,8 @@ describe('#ElectrumX', () => {
|
||||
// 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')
|
||||
assert.instanceOf(err, Error)
|
||||
assert.include(err.message, 'Array too large')
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -345,8 +345,8 @@ describe('#ElectrumX', () => {
|
||||
// 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')
|
||||
assert.instanceOf(err, Error)
|
||||
assert.include(err.message, 'Array too large')
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -359,8 +359,9 @@ describe('#ElectrumX', () => {
|
||||
try {
|
||||
await bchjs.Electrumx.broadcast(txHex)
|
||||
} catch (err) {
|
||||
// console.error('err: ', err)
|
||||
assert.include(
|
||||
err.error,
|
||||
err.message,
|
||||
'the transaction was rejected by network rules'
|
||||
)
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ describe('#price', () => {
|
||||
})
|
||||
|
||||
describe('#getPsffppPrice', () => {
|
||||
it('should get the price of BCH in several currencies', async () => {
|
||||
it('should get the price to write 1MB to the PSFFPP', async () => {
|
||||
const result = await bchjs.Price.getPsffppPrice()
|
||||
// console.log(result)
|
||||
|
||||
|
||||
+30
-22
@@ -266,10 +266,15 @@ describe('#BitcoinCash', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('#bip38', () => {
|
||||
describe('#bip38', function () {
|
||||
// Increase timeout for BIP38 tests as they use CPU-intensive scrypt operations
|
||||
// Each encrypt/decrypt operation takes ~5-6 seconds in Node.js v22
|
||||
this.timeout(60000)
|
||||
|
||||
describe('#encryptBIP38', () => {
|
||||
fixtures.bip38.encrypt.mainnet.forEach(fixture => {
|
||||
it(`BIP 38 encrypt wif ${fixture.wif} with password ${fixture.password} on mainnet`, () => {
|
||||
it(`BIP 38 encrypt wif ${fixture.wif} with password ${fixture.password} on mainnet`, function () {
|
||||
this.timeout(60000)
|
||||
const encryptedKey = bchjs.BitcoinCash.encryptBIP38(
|
||||
fixture.wif,
|
||||
fixture.password
|
||||
@@ -278,20 +283,22 @@ describe('#BitcoinCash', () => {
|
||||
})
|
||||
})
|
||||
|
||||
fixtures.bip38.encrypt.testnet.forEach(fixture => {
|
||||
it(`BIP 38 encrypt wif ${fixture.wif} with password ${fixture.password} on testnet`, () => {
|
||||
const encryptedKey = bchjs.BitcoinCash.encryptBIP38(
|
||||
fixture.wif,
|
||||
fixture.password
|
||||
)
|
||||
assert.equal(encryptedKey, fixture.encryptedKey)
|
||||
})
|
||||
})
|
||||
// fixtures.bip38.encrypt.testnet.forEach(fixture => {
|
||||
// it(`BIP 38 encrypt wif ${fixture.wif} with password ${fixture.password} on testnet`, function () {
|
||||
// this.timeout(60000)
|
||||
// const encryptedKey = bchjs.BitcoinCash.encryptBIP38(
|
||||
// fixture.wif,
|
||||
// fixture.password
|
||||
// )
|
||||
// assert.equal(encryptedKey, fixture.encryptedKey)
|
||||
// })
|
||||
// })
|
||||
})
|
||||
|
||||
describe('#decryptBIP38', () => {
|
||||
fixtures.bip38.decrypt.mainnet.forEach(fixture => {
|
||||
it(`BIP 38 decrypt encrypted key ${fixture.encryptedKey} on mainnet`, () => {
|
||||
it(`BIP 38 decrypt encrypted key ${fixture.encryptedKey} on mainnet`, function () {
|
||||
this.timeout(60000)
|
||||
const wif = bchjs.BitcoinCash.decryptBIP38(
|
||||
fixture.encryptedKey,
|
||||
fixture.password,
|
||||
@@ -301,16 +308,17 @@ describe('#BitcoinCash', () => {
|
||||
})
|
||||
})
|
||||
|
||||
fixtures.bip38.decrypt.testnet.forEach(fixture => {
|
||||
it(`BIP 38 decrypt encrypted key ${fixture.encryptedKey} on testnet`, () => {
|
||||
const wif = bchjs.BitcoinCash.decryptBIP38(
|
||||
fixture.encryptedKey,
|
||||
fixture.password,
|
||||
'testnet'
|
||||
)
|
||||
assert.equal(wif, fixture.wif)
|
||||
})
|
||||
})
|
||||
// fixtures.bip38.decrypt.testnet.forEach(fixture => {
|
||||
// it(`BIP 38 decrypt encrypted key ${fixture.encryptedKey} on testnet`, function () {
|
||||
// this.timeout(60000)
|
||||
// const wif = bchjs.BitcoinCash.decryptBIP38(
|
||||
// fixture.encryptedKey,
|
||||
// fixture.password,
|
||||
// 'testnet'
|
||||
// )
|
||||
// assert.equal(wif, fixture.wif)
|
||||
// })
|
||||
// })
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -93,7 +93,7 @@ describe('#Blockchain', () => {
|
||||
await bchjs.Blockchain.getBlock(blockhash)
|
||||
assert2.fail('Unexpected result')
|
||||
} catch (err) {
|
||||
assert2.include(err, 'Test Error')
|
||||
assert2.include(err.message, 'Test Error')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -406,11 +406,6 @@
|
||||
"wif": "L1XHKhaBAfkr2FJQn3pTfCMxz652WYfmvKj8xDCHCEDV9tWGcbYj",
|
||||
"password": "1EBPIyj55eR8bVUov9",
|
||||
"encryptedKey": "6PYWWnBNfNpSqEJZKcfwbrYgTTdb9PNiGjQJ8r9V6cvsZNKLfcZD8YefQc"
|
||||
},
|
||||
{
|
||||
"wif": "L1phBREbhL4vb1uHHHCAse8bdGE5c7ic2PFjRxMawLzQCsiFVbvu",
|
||||
"password": "9GKVkabAHBMyAf",
|
||||
"encryptedKey": "6PYU2fDHRVF2194gKDGkbFbeu4mFgkWtVvg2RPd2Sp6KmZx3RCHFpgBB2G"
|
||||
}
|
||||
],
|
||||
"testnet": [
|
||||
@@ -432,11 +427,6 @@
|
||||
"wif": "L1XHKhaBAfkr2FJQn3pTfCMxz652WYfmvKj8xDCHCEDV9tWGcbYj",
|
||||
"password": "1EBPIyj55eR8bVUov9",
|
||||
"encryptedKey": "6PYWWnBNfNpSqEJZKcfwbrYgTTdb9PNiGjQJ8r9V6cvsZNKLfcZD8YefQc"
|
||||
},
|
||||
{
|
||||
"wif": "L1phBREbhL4vb1uHHHCAse8bdGE5c7ic2PFjRxMawLzQCsiFVbvu",
|
||||
"password": "9GKVkabAHBMyAf",
|
||||
"encryptedKey": "6PYU2fDHRVF2194gKDGkbFbeu4mFgkWtVvg2RPd2Sp6KmZx3RCHFpgBB2G"
|
||||
}
|
||||
],
|
||||
"testnet": [
|
||||
|
||||
@@ -43,14 +43,14 @@ describe('#PsfSlpIndexer', () => {
|
||||
try {
|
||||
// Stub the network call.
|
||||
const testErr = new Error()
|
||||
testErr.response = { data: { status: 422 } }
|
||||
testErr.response = { data: { error: 'Status 422' } }
|
||||
sandbox.stub(axios, 'get').throws(testErr)
|
||||
|
||||
await bchjs.PsfSlpIndexer.status()
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
assert.equal(err.status, 422)
|
||||
assert.equal(err.message, 'Status 422')
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -103,7 +103,7 @@ describe('#PsfSlpIndexer', () => {
|
||||
try {
|
||||
// Stub the network call.
|
||||
const testErr = new Error()
|
||||
testErr.response = { data: { status: 422 } }
|
||||
testErr.response = { data: { error: 'Status 422' } }
|
||||
sandbox.stub(axios, 'post').throws(testErr)
|
||||
|
||||
const addr = 'bitcoincash:qzmd5vxgh9m22m6fgvm57yd6kjnjl9qnwywsf3583n'
|
||||
@@ -112,7 +112,7 @@ describe('#PsfSlpIndexer', () => {
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
assert.equal(err.status, 422)
|
||||
assert.equal(err.message, 'Status 422')
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -174,7 +174,7 @@ describe('#PsfSlpIndexer', () => {
|
||||
try {
|
||||
// Stub the network call.
|
||||
const testErr = new Error()
|
||||
testErr.response = { data: { status: 422 } }
|
||||
testErr.response = { data: { error: 'Status 422' } }
|
||||
sandbox.stub(axios, 'post').throws(testErr)
|
||||
|
||||
const tokenId =
|
||||
@@ -182,7 +182,7 @@ describe('#PsfSlpIndexer', () => {
|
||||
await bchjs.PsfSlpIndexer.tokenStats(tokenId)
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
assert.equal(err.status, 422)
|
||||
assert.equal(err.message, 'Status 422')
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -399,7 +399,7 @@ describe('#PsfSlpIndexer', () => {
|
||||
try {
|
||||
// Stub the network call.
|
||||
const testErr = new Error()
|
||||
testErr.response = { data: { status: 422 } }
|
||||
testErr.response = { data: { error: 'Status 422' } }
|
||||
sandbox.stub(axios, 'post').throws(testErr)
|
||||
|
||||
const tokenId =
|
||||
@@ -407,7 +407,7 @@ describe('#PsfSlpIndexer', () => {
|
||||
await bchjs.PsfSlpIndexer.getTokenData(tokenId)
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
assert.equal(err.status, 422)
|
||||
assert.equal(err.message, 'Status 422')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
+109
-14
@@ -15,16 +15,21 @@ describe('#X402 Integration', () => {
|
||||
|
||||
describe('#Constructor Configuration', () => {
|
||||
it('should initialize without x402 by default', () => {
|
||||
const bchjs = new BCHJS()
|
||||
const bchjs = new BCHJS({
|
||||
restURL: 'http://localhost:3000/v5/'
|
||||
})
|
||||
|
||||
assert.strictEqual(bchjs.wif, '')
|
||||
assert.strictEqual(bchjs.paymentAmountSats, 20000)
|
||||
assert.strictEqual(bchjs.bchServerURL, 'https://free-bch.fullstack.cash')
|
||||
// assert.strictEqual(bchjs.paymentAmountSats, 10000)
|
||||
assert.strictEqual(typeof bchjs.paymentAmountSats, 'number')
|
||||
assert.ok(Number.isInteger(bchjs.paymentAmountSats) && bchjs.paymentAmountSats > 0)
|
||||
assert.strictEqual(bchjs.bchServerURL, 'https://bch.fullstack.cash/v6')
|
||||
})
|
||||
|
||||
it('should accept wif in config', () => {
|
||||
const testWif = 'L1eYaneXDDXy8VDig4Arwe8wYHbhtsA5wuQvwsKwhaYeneoZuKG4'
|
||||
const bchjs = new BCHJS({
|
||||
restURL: 'http://localhost:3000/v5/',
|
||||
wif: testWif
|
||||
})
|
||||
|
||||
@@ -33,6 +38,7 @@ describe('#X402 Integration', () => {
|
||||
|
||||
it('should accept paymentAmountSats in config', () => {
|
||||
const bchjs = new BCHJS({
|
||||
restURL: 'http://localhost:3000/v5/',
|
||||
paymentAmountSats: 5000
|
||||
})
|
||||
|
||||
@@ -42,6 +48,7 @@ describe('#X402 Integration', () => {
|
||||
it('should accept bchServerURL in config', () => {
|
||||
const customUrl = 'http://localhost:5000'
|
||||
const bchjs = new BCHJS({
|
||||
restURL: 'http://localhost:3000/v5/',
|
||||
bchServerURL: customUrl
|
||||
})
|
||||
|
||||
@@ -54,8 +61,10 @@ describe('#X402 Integration', () => {
|
||||
})
|
||||
|
||||
assert.strictEqual(bchjs.wif, '')
|
||||
assert.strictEqual(bchjs.paymentAmountSats, 20000)
|
||||
assert.strictEqual(bchjs.bchServerURL, 'https://free-bch.fullstack.cash')
|
||||
// assert.strictEqual(bchjs.paymentAmountSats, 10000)
|
||||
assert.strictEqual(typeof bchjs.paymentAmountSats, 'number')
|
||||
assert.ok(Number.isInteger(bchjs.paymentAmountSats) && bchjs.paymentAmountSats > 0)
|
||||
assert.strictEqual(bchjs.bchServerURL, 'https://bch.fullstack.cash/v6')
|
||||
})
|
||||
|
||||
it('should read WIF from BCHJSWIF environment variable', () => {
|
||||
@@ -64,7 +73,9 @@ describe('#X402 Integration', () => {
|
||||
process.env.BCHJSWIF = testWif
|
||||
|
||||
try {
|
||||
const bchjs = new BCHJS()
|
||||
const bchjs = new BCHJS({
|
||||
restURL: 'http://localhost:3000/v5/'
|
||||
})
|
||||
assert.strictEqual(bchjs.wif, testWif)
|
||||
} finally {
|
||||
// Restore original env value
|
||||
@@ -83,7 +94,10 @@ describe('#X402 Integration', () => {
|
||||
process.env.BCHJSWIF = envWif
|
||||
|
||||
try {
|
||||
const bchjs = new BCHJS({ wif: configWif })
|
||||
const bchjs = new BCHJS({
|
||||
restURL: 'http://localhost:3000/v5/',
|
||||
wif: configWif
|
||||
})
|
||||
assert.strictEqual(bchjs.wif, configWif)
|
||||
} finally {
|
||||
// Restore original env value
|
||||
@@ -94,29 +108,103 @@ describe('#X402 Integration', () => {
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('should read bchServerURL from BCHJSBCHSERVERURL environment variable', () => {
|
||||
const testUrl = 'https://custom-bch-server.example.com'
|
||||
const originalEnv = process.env.BCHJSBCHSERVERURL
|
||||
process.env.BCHJSBCHSERVERURL = testUrl
|
||||
|
||||
try {
|
||||
const bchjs = new BCHJS({
|
||||
restURL: 'http://localhost:3000/v5/'
|
||||
})
|
||||
assert.strictEqual(bchjs.bchServerURL, testUrl)
|
||||
} finally {
|
||||
// Restore original env value
|
||||
if (originalEnv === undefined) {
|
||||
delete process.env.BCHJSBCHSERVERURL
|
||||
} else {
|
||||
process.env.BCHJSBCHSERVERURL = originalEnv
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('should prefer config.bchServerURL over BCHJSBCHSERVERURL environment variable', () => {
|
||||
const configUrl = 'https://config-server.example.com'
|
||||
const envUrl = 'https://env-server.example.com'
|
||||
const originalEnv = process.env.BCHJSBCHSERVERURL
|
||||
process.env.BCHJSBCHSERVERURL = envUrl
|
||||
|
||||
try {
|
||||
const bchjs = new BCHJS({
|
||||
restURL: 'http://localhost:3000/v5/',
|
||||
bchServerURL: configUrl
|
||||
})
|
||||
assert.strictEqual(bchjs.bchServerURL, configUrl)
|
||||
} finally {
|
||||
// Restore original env value
|
||||
if (originalEnv === undefined) {
|
||||
delete process.env.BCHJSBCHSERVERURL
|
||||
} else {
|
||||
process.env.BCHJSBCHSERVERURL = originalEnv
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('should keep restURL and bchServerURL independent', () => {
|
||||
const customRestURL = 'https://x402-bch.fullstack.cash/v5/'
|
||||
const customBchServerURL = 'https://bch.fullstack.cash'
|
||||
const bchjs = new BCHJS({
|
||||
restURL: customRestURL,
|
||||
bchServerURL: customBchServerURL
|
||||
})
|
||||
|
||||
assert.strictEqual(bchjs.restURL, customRestURL)
|
||||
assert.strictEqual(bchjs.bchServerURL, customBchServerURL)
|
||||
// Verify they are different values
|
||||
assert.notStrictEqual(bchjs.restURL, bchjs.bchServerURL)
|
||||
})
|
||||
|
||||
it('should use default bchServerURL when restURL is customized', () => {
|
||||
const customRestURL = 'https://x402-bch.fullstack.cash/v5/'
|
||||
const bchjs = new BCHJS({
|
||||
restURL: customRestURL
|
||||
})
|
||||
|
||||
assert.strictEqual(bchjs.restURL, customRestURL)
|
||||
assert.strictEqual(bchjs.bchServerURL, 'https://bch.fullstack.cash/v6')
|
||||
})
|
||||
})
|
||||
|
||||
describe('#x402 Helper Functions', () => {
|
||||
it('should expose createSigner function', () => {
|
||||
const bchjs = new BCHJS()
|
||||
const bchjs = new BCHJS({
|
||||
restURL: 'http://localhost:3000/v5/'
|
||||
})
|
||||
|
||||
assert.strictEqual(typeof bchjs.x402.createSigner, 'function')
|
||||
})
|
||||
|
||||
it('should expose withPaymentInterceptor function', () => {
|
||||
const bchjs = new BCHJS()
|
||||
const bchjs = new BCHJS({
|
||||
restURL: 'http://localhost:3000/v5/'
|
||||
})
|
||||
|
||||
assert.strictEqual(typeof bchjs.x402.withPaymentInterceptor, 'function')
|
||||
})
|
||||
|
||||
it('should expose createPaymentHeader function', () => {
|
||||
const bchjs = new BCHJS()
|
||||
const bchjs = new BCHJS({
|
||||
restURL: 'http://localhost:3000/v5/'
|
||||
})
|
||||
|
||||
assert.strictEqual(typeof bchjs.x402.createPaymentHeader, 'function')
|
||||
})
|
||||
|
||||
it('should expose selectPaymentRequirements function', () => {
|
||||
const bchjs = new BCHJS()
|
||||
const bchjs = new BCHJS({
|
||||
restURL: 'http://localhost:3000/v5/'
|
||||
})
|
||||
|
||||
assert.strictEqual(typeof bchjs.x402.selectPaymentRequirements, 'function')
|
||||
})
|
||||
@@ -124,7 +212,9 @@ describe('#X402 Integration', () => {
|
||||
|
||||
describe('#Axios Instance', () => {
|
||||
it('should have axios available in sub-modules', () => {
|
||||
const bchjs = new BCHJS()
|
||||
const bchjs = new BCHJS({
|
||||
restURL: 'http://localhost:3000/v5/'
|
||||
})
|
||||
|
||||
// Check that sub-modules have axios available (from their own import or config)
|
||||
assert.ok(bchjs.Control.axios)
|
||||
@@ -138,6 +228,7 @@ describe('#X402 Integration', () => {
|
||||
it('should pass x402-wrapped axios instance when WIF is provided', () => {
|
||||
const testWif = 'L1eYaneXDDXy8VDig4Arwe8wYHbhtsA5wuQvwsKwhaYeneoZuKG4'
|
||||
const bchjs = new BCHJS({
|
||||
restURL: 'http://localhost:3000/v5/',
|
||||
wif: testWif
|
||||
})
|
||||
|
||||
@@ -151,7 +242,9 @@ describe('#X402 Integration', () => {
|
||||
|
||||
describe('#selectPaymentRequirements', () => {
|
||||
it('should select BCH utxo payment requirements from accepts array', () => {
|
||||
const bchjs = new BCHJS()
|
||||
const bchjs = new BCHJS({
|
||||
restURL: 'http://localhost:3000/v5/'
|
||||
})
|
||||
|
||||
const accepts = [
|
||||
{
|
||||
@@ -175,7 +268,9 @@ describe('#X402 Integration', () => {
|
||||
})
|
||||
|
||||
it('should throw an error when no BCH requirements found', () => {
|
||||
const bchjs = new BCHJS()
|
||||
const bchjs = new BCHJS({
|
||||
restURL: 'http://localhost:3000/v5/'
|
||||
})
|
||||
|
||||
const accepts = [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user