From 1573e0bc4c081a0f21a3d42b6fe8703e2633f96e Mon Sep 17 00:00:00 2001 From: Chris Troutner Date: Wed, 26 Nov 2025 10:55:34 -0800 Subject: [PATCH 1/5] feat(REST URL): removing default REST URL anti-pattern. Error thrown if URL is not specified at startup --- package.json | 2 +- src/bch-js.js | 7 +++++-- src/electrumx.js | 2 ++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 609ffd4..3ffbf6f 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ ], "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: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/", diff --git a/src/bch-js.js b/src/bch-js.js index 8df5fb0..3d3a057 100644 --- a/src/bch-js.js +++ b/src/bch-js.js @@ -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,11 @@ 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.' + ) + } // Retrieve the Bearer token for simple token authentication. this.bearerToken = '' // default value. diff --git a/src/electrumx.js b/src/electrumx.js index e6a876d..df37dfb 100644 --- a/src/electrumx.js +++ b/src/electrumx.js @@ -534,6 +534,8 @@ class ElectrumX { */ async txData (txid) { try { + console.log('bch-js txData() restURL: ', this.restURL) + // Handle single transaction. if (typeof txid === 'string') { const response = await this.axios.get( From 13a7917d9b814e262d1fd02157e640517e0b3811 Mon Sep 17 00:00:00 2001 From: Chris Troutner Date: Wed, 26 Nov 2025 12:28:12 -0800 Subject: [PATCH 2/5] fix(rest URL): Normalizing URL so user can submit with or without trailing forward slash --- package.json | 11 +++++------ src/bch-js.js | 5 +++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 3ffbf6f..4132c9a 100644 --- a/package.json +++ b/package.json @@ -10,14 +10,13 @@ ], "main": "src/bch-js.js", "scripts": { - "test": "export RESTURL=http://localhost:5942/v6/ && 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: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: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/", "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" diff --git a/src/bch-js.js b/src/bch-js.js index 3d3a057..5b11c22 100644 --- a/src/bch-js.js +++ b/src/bch-js.js @@ -59,6 +59,11 @@ class BCHJS { ) } + // 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. if (config && config.bearerToken && config.bearerToken !== '') { From cc1809b24226474c934d84aa6417e3209edb2af9 Mon Sep 17 00:00:00 2001 From: Chris Troutner Date: Wed, 26 Nov 2025 13:15:07 -0800 Subject: [PATCH 3/5] fix(script.js): Trying to satisfy ESM, linter, and minify packager at the same time --- src/electrumx.js | 2 -- src/script.js | 13 ++++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/electrumx.js b/src/electrumx.js index df37dfb..e6a876d 100644 --- a/src/electrumx.js +++ b/src/electrumx.js @@ -534,8 +534,6 @@ class ElectrumX { */ async txData (txid) { try { - console.log('bch-js txData() restURL: ', this.restURL) - // Handle single transaction. if (typeof txid === 'string') { const response = await this.axios.get( diff --git a/src/script.js b/src/script.js index 2f039fc..d2e7bc7 100644 --- a/src/script.js +++ b/src/script.js @@ -1,7 +1,14 @@ +import { readFileSync } from 'fs' +import { fileURLToPath } from 'url' +import { dirname, join } from 'path' import Bitcoin from '@psf/bitcoincashjs-lib' -import { createRequire } from 'module' -const require = createRequire(import.meta.url) -const opcodes = require('@psf/bitcoincash-ops') + +// Import the bitcoincash-ops library using ESM methods that don't piss off +// the standard linter. +const __dirname = dirname(fileURLToPath(import.meta.url)) +const opcodes = JSON.parse( + readFileSync(join(__dirname, '../node_modules/@psf/bitcoincash-ops/index.json'), 'utf8') +) class Script { constructor () { From c02080d12a8eb354196ad33a741af60bf75d435e Mon Sep 17 00:00:00 2001 From: Chris Troutner Date: Wed, 26 Nov 2025 13:27:45 -0800 Subject: [PATCH 4/5] fix(scripts.js): Removing @psf/bitcoincash-ops as a dependency --- package-lock.json | 5 +- package.json | 1 - src/script.js | 134 ++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 127 insertions(+), 13 deletions(-) diff --git a/package-lock.json b/package-lock.json index de56b96..5846198 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,16 @@ { "name": "@psf/bch-js", - "version": "6.0.0", + "version": "7.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@psf/bch-js", - "version": "6.0.0", + "version": "7.0.0", "license": "MIT", "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", diff --git a/package.json b/package.json index 4132c9a..7af6ea9 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,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", diff --git a/src/script.js b/src/script.js index d2e7bc7..36e8c72 100644 --- a/src/script.js +++ b/src/script.js @@ -1,14 +1,130 @@ -import { readFileSync } from 'fs' -import { fileURLToPath } from 'url' -import { dirname, join } from 'path' import Bitcoin from '@psf/bitcoincashjs-lib' -// Import the bitcoincash-ops library using ESM methods that don't piss off -// the standard linter. -const __dirname = dirname(fileURLToPath(import.meta.url)) -const opcodes = JSON.parse( - readFileSync(join(__dirname, '../node_modules/@psf/bitcoincash-ops/index.json'), 'utf8') -) +// 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 () { From 4d94ad13ff6896d2ff75b14e7ffc65c378ab8e00 Mon Sep 17 00:00:00 2001 From: Chris Troutner Date: Wed, 26 Nov 2025 13:59:38 -0800 Subject: [PATCH 5/5] fix(getUsd): Updating endpoint --- src/price.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/price.js b/src/price.js index 7633cc5..3845187 100644 --- a/src/price.js +++ b/src/price.js @@ -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)}`)