mirror of
https://github.com/Permissionless-Software-Foundation/bch-js.git
synced 2026-09-21 16:51:59 -07:00
Added x402 support
This commit is contained in:
Generated
+1107
-209
File diff suppressed because it is too large
Load Diff
+2
-1
@@ -51,7 +51,8 @@
|
||||
"satoshi-bitcoin": "1.0.5",
|
||||
"slp-mdm": "0.0.7",
|
||||
"slp-parser": "0.0.4",
|
||||
"wif": "2.0.6"
|
||||
"wif": "2.0.6",
|
||||
"x402-bch-axios": "1.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"apidoc": "1.2.0",
|
||||
|
||||
@@ -9,6 +9,15 @@
|
||||
// bch-api mainnet.
|
||||
// const DEFAULT_REST_API = "http://localhost:3000/v5/"
|
||||
|
||||
// Global npm libraries
|
||||
import axios from 'axios'
|
||||
import {
|
||||
createSigner,
|
||||
withPaymentInterceptor,
|
||||
createPaymentHeader,
|
||||
selectPaymentRequirements
|
||||
} from 'x402-bch-axios'
|
||||
|
||||
// local deps
|
||||
import BitcoinCash from './bitcoincash.js'
|
||||
import Crypto from './crypto.js'
|
||||
@@ -61,11 +70,37 @@ class BCHJS {
|
||||
this.authToken = `Bearer ${this.bearerToken}`
|
||||
}
|
||||
|
||||
// x402 payment configuration
|
||||
// If a WIF private key is provided, enable x402 automatic payment handling
|
||||
this.wif = (config && config.wif) || ''
|
||||
this.paymentAmountSats = (config && config.paymentAmountSats) || 2000
|
||||
this.bchServerURL = (config && config.bchServerURL) || 'http://free-bch.fullstack.cash'
|
||||
|
||||
const libConfig = {
|
||||
restURL: this.restURL,
|
||||
authToken: this.authToken
|
||||
}
|
||||
|
||||
// If WIF is provided, create an axios instance with x402 payment interceptor
|
||||
// Otherwise, let sub-modules use their own axios import for backwards compatibility
|
||||
if (this.wif) {
|
||||
let axiosInstance = axios.create({
|
||||
baseURL: this.restURL,
|
||||
headers: {
|
||||
authorization: this.authToken
|
||||
}
|
||||
})
|
||||
|
||||
const signer = createSigner(this.wif, this.paymentAmountSats)
|
||||
axiosInstance = withPaymentInterceptor(
|
||||
axiosInstance,
|
||||
signer,
|
||||
{ bchServerURL: this.bchServerURL }
|
||||
)
|
||||
|
||||
libConfig.axios = axiosInstance
|
||||
}
|
||||
|
||||
// ElectrumX indexer
|
||||
this.Electrumx = new Electrumx(libConfig)
|
||||
|
||||
@@ -102,6 +137,14 @@ class BCHJS {
|
||||
this.eCash = new Ecash()
|
||||
|
||||
this.PsfSlpIndexer = new PsfSlpIndexer(libConfig)
|
||||
|
||||
// Expose x402 helper functions for advanced use cases
|
||||
this.x402 = {
|
||||
createSigner,
|
||||
withPaymentInterceptor,
|
||||
createPaymentHeader,
|
||||
selectPaymentRequirements
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+26
-24
@@ -11,6 +11,8 @@ class Blockchain {
|
||||
constructor (config) {
|
||||
this.restURL = config.restURL
|
||||
this.authToken = config.authToken
|
||||
// Use the shared axios instance if provided, otherwise fall back to axios
|
||||
this.axios = config.axios || axios
|
||||
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
@@ -39,7 +41,7 @@ class Blockchain {
|
||||
*/
|
||||
async getBestBlockHash () {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}full-node/blockchain/getBestBlockHash`,
|
||||
this.axiosOptions
|
||||
)
|
||||
@@ -93,7 +95,7 @@ class Blockchain {
|
||||
if (!blockhash || typeof blockhash !== 'string') {
|
||||
throw new Error('blockhash must be a string')
|
||||
}
|
||||
const response = await axios.post(
|
||||
const response = await this.axios.post(
|
||||
`${this.restURL}full-node/blockchain/getblock`,
|
||||
{
|
||||
blockhash,
|
||||
@@ -147,7 +149,7 @@ class Blockchain {
|
||||
*/
|
||||
async getBlockchainInfo () {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}full-node/blockchain/getBlockchainInfo`,
|
||||
this.axiosOptions
|
||||
)
|
||||
@@ -178,7 +180,7 @@ class Blockchain {
|
||||
*/
|
||||
async getBlockCount () {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}full-node/blockchain/getBlockCount`,
|
||||
this.axiosOptions
|
||||
)
|
||||
@@ -214,7 +216,7 @@ class Blockchain {
|
||||
if (typeof height !== 'string') height = JSON.stringify(height)
|
||||
|
||||
try {
|
||||
const response = await axios.get(
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}full-node/blockchain/getBlockHash/${height}`,
|
||||
this.axiosOptions
|
||||
)
|
||||
@@ -261,7 +263,7 @@ class Blockchain {
|
||||
try {
|
||||
// Handle single hash.
|
||||
if (typeof hash === 'string') {
|
||||
const response = await axios.get(
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}full-node/blockchain/getBlockHeader/${hash}?verbose=${verbose}`,
|
||||
this.axiosOptions
|
||||
)
|
||||
@@ -271,7 +273,7 @@ class Blockchain {
|
||||
// Handle array of hashes.
|
||||
} else if (Array.isArray(hash)) {
|
||||
// Dev note: must use axios.post for unit test stubbing.
|
||||
const response = await axios.post(
|
||||
const response = await this.axios.post(
|
||||
`${this.restURL}full-node/blockchain/getBlockHeader`,
|
||||
{
|
||||
hashes: hash,
|
||||
@@ -322,7 +324,7 @@ class Blockchain {
|
||||
*/
|
||||
async getChainTips () {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}full-node/blockchain/getChainTips`,
|
||||
this.axiosOptions
|
||||
)
|
||||
@@ -354,7 +356,7 @@ class Blockchain {
|
||||
*/
|
||||
async getDifficulty () {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}full-node/blockchain/getDifficulty`,
|
||||
this.axiosOptions
|
||||
)
|
||||
@@ -370,7 +372,7 @@ class Blockchain {
|
||||
if (typeof txid !== 'string') txid = JSON.stringify(txid)
|
||||
|
||||
try {
|
||||
const response = await axios.get(
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}full-node/blockchain/getMempoolAncestors/${txid}?verbose=${verbose}`,
|
||||
this.axiosOptions
|
||||
)
|
||||
@@ -385,7 +387,7 @@ class Blockchain {
|
||||
if (typeof txid !== 'string') txid = JSON.stringify(txid)
|
||||
|
||||
try {
|
||||
const response = await axios.get(
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}full-node/blockchain/getMempoolDescendants/${txid}?verbose=${verbose}`,
|
||||
this.axiosOptions
|
||||
)
|
||||
@@ -482,7 +484,7 @@ class Blockchain {
|
||||
|
||||
try {
|
||||
if (typeof txid === 'string') {
|
||||
const response = await axios.get(
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}full-node/blockchain/getMempoolEntry/${txid}`,
|
||||
this.axiosOptions
|
||||
)
|
||||
@@ -490,7 +492,7 @@ class Blockchain {
|
||||
return response.data
|
||||
} else if (Array.isArray(txid)) {
|
||||
// Dev note: must use axios.post for unit test stubbing.
|
||||
const response = await axios.post(
|
||||
const response = await this.axios.post(
|
||||
`${this.restURL}full-node/blockchain/getMempoolEntry`,
|
||||
{
|
||||
txids: txid
|
||||
@@ -533,7 +535,7 @@ class Blockchain {
|
||||
*/
|
||||
async getMempoolInfo () {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}full-node/blockchain/getMempoolInfo`,
|
||||
this.axiosOptions
|
||||
)
|
||||
@@ -580,7 +582,7 @@ class Blockchain {
|
||||
*/
|
||||
async getRawMempool (verbose = false) {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}full-node/blockchain/getRawMempool?vebose=${verbose}`,
|
||||
this.axiosOptions
|
||||
)
|
||||
@@ -624,11 +626,11 @@ class Blockchain {
|
||||
}
|
||||
|
||||
// Send the request to the REST API.
|
||||
// const response = await axios.get(
|
||||
// const response = await this.axios.get(
|
||||
// `${this.restURL}blockchain/getTxOut/${txid}/${n}?includeMempool=${includeMempool}`,
|
||||
// this.axiosOptions
|
||||
// )
|
||||
const response = await axios.post(
|
||||
const response = await this.axios.post(
|
||||
`${this.restURL}full-node/blockchain/getTxOut`,
|
||||
{
|
||||
txid,
|
||||
@@ -688,13 +690,13 @@ class Blockchain {
|
||||
const path = `${this.restURL}full-node/blockchain/getTxOutProof/${txids}`
|
||||
// if (blockhash) path = `${path}?blockhash=${blockhash}`
|
||||
|
||||
const response = await axios.get(path, this.axiosOptions)
|
||||
const response = await this.axios.get(path, this.axiosOptions)
|
||||
return response.data
|
||||
|
||||
// Array of txids.
|
||||
} else if (Array.isArray(txids)) {
|
||||
// Dev note: must use axios.post for unit test stubbing.
|
||||
const response = await axios.post(
|
||||
const response = await this.axios.post(
|
||||
`${this.restURL}full-node/blockchain/getTxOutProof`,
|
||||
{
|
||||
txids
|
||||
@@ -714,7 +716,7 @@ class Blockchain {
|
||||
|
||||
async preciousBlock (blockhash) {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}full-node/blockchain/preciousBlock/${blockhash}`,
|
||||
this.axiosOptions
|
||||
)
|
||||
@@ -727,7 +729,7 @@ class Blockchain {
|
||||
|
||||
async pruneBlockchain (height) {
|
||||
try {
|
||||
const response = await axios.post(
|
||||
const response = await this.axios.post(
|
||||
`${this.restURL}full-node/blockchain/pruneBlockchain/${height}`,
|
||||
this.axiosOptions
|
||||
)
|
||||
@@ -740,7 +742,7 @@ class Blockchain {
|
||||
|
||||
async verifyChain (checklevel = 3, nblocks = 6) {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}full-node/blockchain/verifyChain?checklevel=${checklevel}&nblocks=${nblocks}`,
|
||||
this.axiosOptions
|
||||
)
|
||||
@@ -792,7 +794,7 @@ class Blockchain {
|
||||
try {
|
||||
// Single block
|
||||
if (typeof proof === 'string') {
|
||||
const response = await axios.get(
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}full-node/blockchain/verifyTxOutProof/${proof}`,
|
||||
this.axiosOptions
|
||||
)
|
||||
@@ -801,7 +803,7 @@ class Blockchain {
|
||||
// Array of hashes.
|
||||
} else if (Array.isArray(proof)) {
|
||||
// Dev note: must use axios.post for unit test stubbing.
|
||||
const response = await axios.post(
|
||||
const response = await this.axios.post(
|
||||
`${this.restURL}full-node/blockchain/verifyTxOutProof`,
|
||||
{
|
||||
proofs: proof
|
||||
|
||||
+4
-2
@@ -10,6 +10,8 @@ class Control {
|
||||
constructor (config) {
|
||||
this.restURL = config.restURL
|
||||
this.authToken = config.authToken
|
||||
// Use the shared axios instance if provided, otherwise fall back to axios
|
||||
this.axios = config.axios || axios
|
||||
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
@@ -66,7 +68,7 @@ class Control {
|
||||
*/
|
||||
async getNetworkInfo () {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}full-node/control/getNetworkInfo`,
|
||||
this.axiosOptions
|
||||
)
|
||||
@@ -79,7 +81,7 @@ class Control {
|
||||
|
||||
async getMemoryInfo () {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}full-node/control/getMemoryInfo`,
|
||||
this.axiosOptions
|
||||
)
|
||||
|
||||
+14
-12
@@ -15,6 +15,8 @@ class ElectrumX {
|
||||
constructor (config) {
|
||||
this.restURL = config.restURL
|
||||
this.authToken = config.authToken
|
||||
// Use the shared axios instance if provided, otherwise fall back to axios
|
||||
this.axios = config.axios || axios
|
||||
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
@@ -97,7 +99,7 @@ class ElectrumX {
|
||||
|
||||
// Handle single address.
|
||||
if (typeof address === 'string') {
|
||||
const response = await axios.get(
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}fulcrum/utxos/${address}`,
|
||||
this.axiosOptions
|
||||
)
|
||||
@@ -105,7 +107,7 @@ class ElectrumX {
|
||||
|
||||
// Handle array of addresses.
|
||||
} else if (Array.isArray(address)) {
|
||||
const response = await axios.post(
|
||||
const response = await this.axios.post(
|
||||
`${this.restURL}fulcrum/utxos`,
|
||||
{
|
||||
addresses: address
|
||||
@@ -181,7 +183,7 @@ class ElectrumX {
|
||||
try {
|
||||
// Handle single address.
|
||||
if (typeof address === 'string') {
|
||||
const response = await axios.get(
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}fulcrum/balance/${address}`,
|
||||
this.axiosOptions
|
||||
)
|
||||
@@ -189,7 +191,7 @@ class ElectrumX {
|
||||
|
||||
// Handle array of addresses.
|
||||
} else if (Array.isArray(address)) {
|
||||
const response = await axios.post(
|
||||
const response = await this.axios.post(
|
||||
`${this.restURL}fulcrum/balance`,
|
||||
{
|
||||
addresses: address
|
||||
@@ -279,7 +281,7 @@ class ElectrumX {
|
||||
try {
|
||||
// Handle single address.
|
||||
if (typeof address === 'string') {
|
||||
const response = await axios.get(
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}fulcrum/transactions/${address}/${allTxs}`,
|
||||
this.axiosOptions
|
||||
)
|
||||
@@ -287,7 +289,7 @@ class ElectrumX {
|
||||
|
||||
// Handle array of addresses.
|
||||
} else if (Array.isArray(address)) {
|
||||
const response = await axios.post(
|
||||
const response = await this.axios.post(
|
||||
`${this.restURL}fulcrum/transactions`,
|
||||
{
|
||||
addresses: address,
|
||||
@@ -374,7 +376,7 @@ class ElectrumX {
|
||||
try {
|
||||
// Handle single address.
|
||||
if (typeof address === 'string') {
|
||||
const response = await axios.get(
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}fulcrum/unconfirmed/${address}`,
|
||||
this.axiosOptions
|
||||
)
|
||||
@@ -382,7 +384,7 @@ class ElectrumX {
|
||||
|
||||
// Handle array of addresses.
|
||||
} else if (Array.isArray(address)) {
|
||||
const response = await axios.post(
|
||||
const response = await this.axios.post(
|
||||
`${this.restURL}fulcrum/unconfirmed`,
|
||||
{
|
||||
addresses: address
|
||||
@@ -443,7 +445,7 @@ class ElectrumX {
|
||||
*/
|
||||
async blockHeader (height, count = 1) {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}fulcrum/block/headers/${height}?count=${count}`,
|
||||
this.axiosOptions
|
||||
)
|
||||
@@ -534,13 +536,13 @@ class ElectrumX {
|
||||
try {
|
||||
// Handle single transaction.
|
||||
if (typeof txid === 'string') {
|
||||
const response = await axios.get(
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}fulcrum/tx/data/${txid}`,
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
} else if (Array.isArray(txid)) {
|
||||
const response = await axios.post(
|
||||
const response = await this.axios.post(
|
||||
`${this.restURL}fulcrum/tx/data`,
|
||||
{
|
||||
txids: txid
|
||||
@@ -582,7 +584,7 @@ class ElectrumX {
|
||||
async broadcast (txHex) {
|
||||
try {
|
||||
if (typeof txHex === 'string') {
|
||||
const response = await axios.post(
|
||||
const response = await this.axios.post(
|
||||
`${this.restURL}fulcrum/tx/broadcast`,
|
||||
{ txHex },
|
||||
this.axiosOptions
|
||||
|
||||
+3
-1
@@ -9,7 +9,6 @@ let _this
|
||||
class Encryption {
|
||||
constructor (config) {
|
||||
this.restURL = config.restURL
|
||||
this.axios = axios
|
||||
this.authToken = config.authToken
|
||||
|
||||
this.axiosOptions = {
|
||||
@@ -18,6 +17,9 @@ class Encryption {
|
||||
}
|
||||
}
|
||||
|
||||
// Use the shared axios instance if provided, otherwise fall back to axios
|
||||
this.axios = config.axios || axios
|
||||
|
||||
_this = this
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -6,6 +6,8 @@ class Generating {
|
||||
constructor (config) {
|
||||
this.restURL = config.restURL
|
||||
this.authToken = config.authToken
|
||||
// Use the shared axios instance if provided, otherwise fall back to axios
|
||||
this.axios = config.axios || axios
|
||||
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
@@ -16,7 +18,7 @@ class Generating {
|
||||
|
||||
async generateToAddress (blocks, address, maxtries = 1000000) {
|
||||
try {
|
||||
const response = await axios.post(
|
||||
const response = await this.axios.post(
|
||||
`${this.restURL}generating/generateToAddress/${blocks}/${address}?maxtries=${maxtries}`,
|
||||
this.axiosOptions
|
||||
)
|
||||
|
||||
+6
-4
@@ -6,6 +6,8 @@ class Mining {
|
||||
constructor (config) {
|
||||
this.restURL = config.restURL
|
||||
this.authToken = config.authToken
|
||||
// Use the shared axios instance if provided, otherwise fall back to axios
|
||||
this.axios = config.axios || axios
|
||||
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
@@ -16,7 +18,7 @@ class Mining {
|
||||
|
||||
async getBlockTemplate (templateRequest) {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}mining/getBlockTemplate/${templateRequest}`,
|
||||
this.axiosOptions
|
||||
)
|
||||
@@ -29,7 +31,7 @@ class Mining {
|
||||
|
||||
async getMiningInfo () {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}mining/getMiningInfo`,
|
||||
this.axiosOptions
|
||||
)
|
||||
@@ -42,7 +44,7 @@ class Mining {
|
||||
|
||||
async getNetworkHashps (nblocks = 120, height = 1) {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}mining/getNetworkHashps?nblocks=${nblocks}&height=${height}`,
|
||||
this.axiosOptions
|
||||
)
|
||||
@@ -58,7 +60,7 @@ class Mining {
|
||||
if (parameters) path = `${path}?parameters=${parameters}`
|
||||
|
||||
try {
|
||||
const response = await axios.post(path, this.axiosOptions)
|
||||
const response = await this.axios.post(path, this.axiosOptions)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
|
||||
+2
-1
@@ -13,7 +13,8 @@ class Price {
|
||||
}
|
||||
}
|
||||
|
||||
this.axios = axios
|
||||
// Use the shared axios instance if provided, otherwise fall back to axios
|
||||
this.axios = config.axios || axios
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,6 +19,8 @@ class PsfSlpIndexer {
|
||||
constructor (config = {}) {
|
||||
this.restURL = config.restURL
|
||||
this.authToken = config.authToken
|
||||
// Use the shared axios instance if provided, otherwise fall back to axios
|
||||
this.axios = config.axios || axios
|
||||
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
@@ -58,7 +60,7 @@ class PsfSlpIndexer {
|
||||
*/
|
||||
async status () {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}slp/status`,
|
||||
this.axiosOptions
|
||||
)
|
||||
@@ -123,7 +125,7 @@ class PsfSlpIndexer {
|
||||
|
||||
// Handle single address.
|
||||
if (typeof address === 'string') {
|
||||
const response = await axios.post(
|
||||
const response = await this.axios.post(
|
||||
`${this.restURL}slp/address`,
|
||||
{ address },
|
||||
this.axiosOptions
|
||||
@@ -188,7 +190,7 @@ class PsfSlpIndexer {
|
||||
try {
|
||||
// Handle single address.
|
||||
if (typeof tokenId === 'string') {
|
||||
const response = await axios.post(
|
||||
const response = await this.axios.post(
|
||||
`${this.restURL}slp/token`,
|
||||
{ tokenId, withTxHistory },
|
||||
this.axiosOptions
|
||||
@@ -280,7 +282,7 @@ class PsfSlpIndexer {
|
||||
|
||||
// Handle single address.
|
||||
if (typeof txid === 'string') {
|
||||
const response = await axios.post(
|
||||
const response = await this.axios.post(
|
||||
`${this.restURL}slp/txid`,
|
||||
{ txid },
|
||||
this.axiosOptions
|
||||
@@ -415,7 +417,7 @@ class PsfSlpIndexer {
|
||||
|
||||
// Handle single address.
|
||||
if (typeof tokenId === 'string') {
|
||||
const response = await axios.post(
|
||||
const response = await this.axios.post(
|
||||
// 'https://bchn.fullstack.cash/v5/psf/slp/token/data/',
|
||||
url,
|
||||
{ tokenId, withTxHistory },
|
||||
@@ -508,7 +510,7 @@ class PsfSlpIndexer {
|
||||
|
||||
// Handle single address.
|
||||
if (typeof tokenId === 'string') {
|
||||
const response = await axios.post(
|
||||
const response = await this.axios.post(
|
||||
// 'https://bchn.fullstack.cash/v5/psf/slp/token/data/',
|
||||
url,
|
||||
{ tokenId, updateCache },
|
||||
|
||||
@@ -13,7 +13,8 @@ class RawTransactions {
|
||||
}
|
||||
}
|
||||
|
||||
this.axios = axios
|
||||
// Use the shared axios instance if provided, otherwise fall back to axios
|
||||
this.axios = config.axios || axios
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,7 +83,7 @@ class RawTransactions {
|
||||
try {
|
||||
// Single hex
|
||||
if (typeof hex === 'string') {
|
||||
const response = await axios.get(
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}full-node/rawtransactions/decodeRawTransaction/${hex}`,
|
||||
this.axiosOptions
|
||||
)
|
||||
@@ -99,7 +100,7 @@ class RawTransactions {
|
||||
},
|
||||
headers: this.axiosOptions.headers
|
||||
}
|
||||
const response = await axios(options)
|
||||
const response = await this.axios(options)
|
||||
|
||||
return response.data
|
||||
}
|
||||
@@ -150,7 +151,7 @@ class RawTransactions {
|
||||
|
||||
try {
|
||||
if (typeof script === 'string') {
|
||||
const response = await axios.get(
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}full-node/rawtransactions/decodeScript/${script}`,
|
||||
this.axiosOptions
|
||||
)
|
||||
@@ -165,7 +166,7 @@ class RawTransactions {
|
||||
},
|
||||
headers: this.axiosOptions.headers
|
||||
}
|
||||
const response = await axios(options)
|
||||
const response = await this.axios(options)
|
||||
|
||||
return response.data
|
||||
}
|
||||
@@ -249,7 +250,7 @@ class RawTransactions {
|
||||
// 'getRawTransaction() this.axiosOptions: ',
|
||||
// this.axiosOptions
|
||||
// )
|
||||
const response = await axios.get(
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}full-node/rawtransactions/getRawTransaction/${txid}?verbose=${verbose}`,
|
||||
this.axiosOptions
|
||||
)
|
||||
@@ -266,7 +267,7 @@ class RawTransactions {
|
||||
},
|
||||
headers: this.axiosOptions.headers
|
||||
}
|
||||
const response = await axios(options)
|
||||
const response = await this.axios(options)
|
||||
|
||||
return response.data
|
||||
}
|
||||
|
||||
+2
-1
@@ -14,7 +14,8 @@ class Utils {
|
||||
this.restURL = config.restURL
|
||||
this.slpParser = slpParser
|
||||
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: {
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
import assert from 'assert'
|
||||
import sinon from 'sinon'
|
||||
import BCHJS from '../../src/bch-js.js'
|
||||
|
||||
describe('#X402 Integration', () => {
|
||||
let sandbox
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore()
|
||||
})
|
||||
|
||||
describe('#Constructor Configuration', () => {
|
||||
it('should initialize without x402 by default', () => {
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
assert.strictEqual(bchjs.wif, '')
|
||||
assert.strictEqual(bchjs.paymentAmountSats, 2000)
|
||||
assert.strictEqual(bchjs.bchServerURL, 'http://free-bch.fullstack.cash')
|
||||
})
|
||||
|
||||
it('should accept wif in config', () => {
|
||||
const testWif = 'L1eYaneXDDXy8VDig4Arwe8wYHbhtsA5wuQvwsKwhaYeneoZuKG4'
|
||||
const bchjs = new BCHJS({
|
||||
wif: testWif
|
||||
})
|
||||
|
||||
assert.strictEqual(bchjs.wif, testWif)
|
||||
})
|
||||
|
||||
it('should accept paymentAmountSats in config', () => {
|
||||
const bchjs = new BCHJS({
|
||||
paymentAmountSats: 5000
|
||||
})
|
||||
|
||||
assert.strictEqual(bchjs.paymentAmountSats, 5000)
|
||||
})
|
||||
|
||||
it('should accept bchServerURL in config', () => {
|
||||
const customUrl = 'http://localhost:5000'
|
||||
const bchjs = new BCHJS({
|
||||
bchServerURL: customUrl
|
||||
})
|
||||
|
||||
assert.strictEqual(bchjs.bchServerURL, customUrl)
|
||||
})
|
||||
|
||||
it('should use default values when config options are not provided', () => {
|
||||
const bchjs = new BCHJS({
|
||||
restURL: 'http://localhost:3000/v6/'
|
||||
})
|
||||
|
||||
assert.strictEqual(bchjs.wif, '')
|
||||
assert.strictEqual(bchjs.paymentAmountSats, 2000)
|
||||
assert.strictEqual(bchjs.bchServerURL, 'http://free-bch.fullstack.cash')
|
||||
})
|
||||
})
|
||||
|
||||
describe('#x402 Helper Functions', () => {
|
||||
it('should expose createSigner function', () => {
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
assert.strictEqual(typeof bchjs.x402.createSigner, 'function')
|
||||
})
|
||||
|
||||
it('should expose withPaymentInterceptor function', () => {
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
assert.strictEqual(typeof bchjs.x402.withPaymentInterceptor, 'function')
|
||||
})
|
||||
|
||||
it('should expose createPaymentHeader function', () => {
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
assert.strictEqual(typeof bchjs.x402.createPaymentHeader, 'function')
|
||||
})
|
||||
|
||||
it('should expose selectPaymentRequirements function', () => {
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
assert.strictEqual(typeof bchjs.x402.selectPaymentRequirements, 'function')
|
||||
})
|
||||
})
|
||||
|
||||
describe('#Axios Instance', () => {
|
||||
it('should have axios available in sub-modules', () => {
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
// Check that sub-modules have axios available (from their own import or config)
|
||||
assert.ok(bchjs.Control.axios)
|
||||
assert.ok(bchjs.Blockchain.axios)
|
||||
assert.ok(bchjs.Mining.axios)
|
||||
assert.ok(bchjs.Electrumx.axios)
|
||||
assert.ok(bchjs.RawTransactions.axios)
|
||||
assert.ok(bchjs.Price.axios)
|
||||
})
|
||||
|
||||
it('should pass x402-wrapped axios instance when WIF is provided', () => {
|
||||
const testWif = 'L1eYaneXDDXy8VDig4Arwe8wYHbhtsA5wuQvwsKwhaYeneoZuKG4'
|
||||
const bchjs = new BCHJS({
|
||||
wif: testWif
|
||||
})
|
||||
|
||||
// All modules should have the same wrapped axios instance
|
||||
assert.ok(bchjs.Control.axios)
|
||||
assert.ok(bchjs.Blockchain.axios)
|
||||
// When WIF is provided, the axios instances should be the same wrapped instance
|
||||
assert.strictEqual(bchjs.Control.axios, bchjs.Blockchain.axios)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#selectPaymentRequirements', () => {
|
||||
it('should select BCH utxo payment requirements from accepts array', () => {
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
const accepts = [
|
||||
{
|
||||
scheme: 'exact',
|
||||
network: 'base-sepolia',
|
||||
maxAmountRequired: '10000'
|
||||
},
|
||||
{
|
||||
scheme: 'utxo',
|
||||
network: 'bch',
|
||||
minAmountRequired: '1000',
|
||||
payTo: 'bitcoincash:qqlrzp23w08434twmvr4fxw672whkjy0py26r63g3d'
|
||||
}
|
||||
]
|
||||
|
||||
const result = bchjs.x402.selectPaymentRequirements(accepts)
|
||||
|
||||
assert.strictEqual(result.scheme, 'utxo')
|
||||
assert.strictEqual(result.network, 'bch')
|
||||
assert.strictEqual(result.minAmountRequired, '1000')
|
||||
})
|
||||
|
||||
it('should throw an error when no BCH requirements found', () => {
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
const accepts = [
|
||||
{
|
||||
scheme: 'exact',
|
||||
network: 'base-sepolia',
|
||||
maxAmountRequired: '10000'
|
||||
}
|
||||
]
|
||||
|
||||
assert.throws(() => {
|
||||
bchjs.x402.selectPaymentRequirements(accepts)
|
||||
}, /No BCH payment requirements found/)
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user