UNPKG

@bsv/sdk

Version:

BSV Blockchain Software Development Kit

182 lines 6.28 kB
import { defaultHttpClient } from '../http/DefaultHttpClient.js'; import Random from '../../primitives/Random.js'; import { toHex } from '../../primitives/utils.js'; function defaultDeploymentId() { return `ts-sdk-${toHex(Random(16))}`; } /** * Represents an ARC transaction broadcaster. */ export default class ARC { URL; apiKey; deploymentId; callbackUrl; callbackToken; headers; httpClient; constructor(URL, config) { this.URL = URL; if (typeof config === 'string') { this.apiKey = config; this.httpClient = defaultHttpClient(); this.deploymentId = defaultDeploymentId(); this.callbackToken = undefined; this.callbackUrl = undefined; } else { const configObj = config ?? {}; const { apiKey, deploymentId, httpClient, callbackToken, callbackUrl, headers } = configObj; this.apiKey = apiKey; this.httpClient = httpClient ?? defaultHttpClient(); this.deploymentId = deploymentId ?? defaultDeploymentId(); this.callbackToken = callbackToken; this.callbackUrl = callbackUrl; this.headers = headers; } } /** * Constructs a dictionary of the default & supplied request headers. */ requestHeaders() { const headers = { 'Content-Type': 'application/json', 'XDeployment-ID': this.deploymentId }; if (this.apiKey != null && this.apiKey !== '') { headers.Authorization = `Bearer ${this.apiKey}`; } if (this.callbackUrl != null && this.callbackUrl !== '') { headers['X-CallbackUrl'] = this.callbackUrl; } if (this.callbackToken != null && this.callbackToken !== '') { headers['X-CallbackToken'] = this.callbackToken; } if (this.headers != null) { for (const key in this.headers) { headers[key] = this.headers[key]; } } return headers; } /** * Broadcasts a transaction via ARC. * * @param {Transaction} tx - The transaction to be broadcasted. * @returns {Promise<BroadcastResponse | BroadcastFailure>} A promise that resolves to either a success or failure response. */ async broadcast(tx) { let rawTx; try { rawTx = tx.toHexEF(); } catch (error) { if (error.message === 'All inputs must have source transactions when serializing to EF format') { rawTx = tx.toHex(); } else { throw error; } } const requestOptions = { method: 'POST', headers: this.requestHeaders(), data: { rawTx } }; try { const response = await this.httpClient.request(`${this.URL}/v1/tx`, requestOptions); if (response.ok) { const { txid, extraInfo, txStatus, competingTxs } = response.data; const broadcastRes = { status: 'success', txid, message: `${txStatus} ${extraInfo}` }; if (competingTxs != null) { broadcastRes.competingTxs = competingTxs; } return broadcastRes; } else { const st = typeof response.status; const r = { status: 'error', code: st === 'number' || st === 'string' ? response.status.toString() : 'ERR_UNKNOWN', description: 'Unknown error' }; let d = response.data; if (typeof d === 'string') { try { d = JSON.parse(response.data); } catch { // Intentionally left empty } } if (typeof d === 'object') { if (d !== null) { r.more = d; } if ((d != null) && typeof d.txid === 'string') { r.txid = d.txid; } if ((d != null) && 'detail' in d && typeof d.detail === 'string') { r.description = d.detail; } } return r; } } catch (error) { return { status: 'error', code: '500', description: typeof error.message === 'string' ? error.message : 'Internal Server Error' }; } } /** * Broadcasts multiple transactions via ARC. * Handles mixed responses where some transactions succeed and others fail. * * @param {Transaction[]} txs - Array of transactions to be broadcasted. * @returns {Promise<Array<object>>} A promise that resolves to an array of objects. */ async broadcastMany(txs) { const rawTxs = txs.map((tx) => { try { return { rawTx: tx.toHexEF() }; } catch (error) { if (error.message === 'All inputs must have source transactions when serializing to EF format') { return { rawTx: tx.toHex() }; } throw error; } }); const requestOptions = { method: 'POST', headers: this.requestHeaders(), data: rawTxs }; try { const response = await this.httpClient.request(`${this.URL}/v1/txs`, requestOptions); return response.data; } catch (error) { const errorResponse = { status: 'error', code: '500', description: typeof error.message === 'string' ? error.message : 'Internal Server Error' }; return txs.map(() => errorResponse); } } } //# sourceMappingURL=ARC.js.map