Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(DOGE/DASH): transfering funds doesn't work after bitcoinjs-lib upgrade #552

Merged
merged 5 commits into from
Nov 9, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 31 additions & 22 deletions src/lib/bitcoin/bitcoin-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,65 +2,72 @@ import BtcBaseApi from './btc-base-api'
import { Cryptos } from '../constants'

export default class BitcoinApi extends BtcBaseApi {
constructor (passphrase) {
constructor(passphrase) {
super(Cryptos.BTC, passphrase)
}

/**
* @override
*/
getBalance () {
getBalance() {
return this._get(`/address/${this.address}`).then(
data => (data.chain_stats.funded_txo_sum - data.chain_stats.spent_txo_sum) / this.multiplier
(data) => (data.chain_stats.funded_txo_sum - data.chain_stats.spent_txo_sum) / this.multiplier
)
}

/** @override */
getFee () {
getFee() {
return 0
}

/** Returns last block height */
getHeight () {
return this._get('/blocks/tip/height').then(data => Number(data) || 0)
getHeight() {
return this._get('/blocks/tip/height').then((data) => Number(data) || 0)
}

/** @override */
sendTransaction (txHex) {
return this._getClient().post('/tx', txHex).then(response => response.data)
sendTransaction(txHex) {
return this._getClient()
.post('/tx', txHex)
.then((response) => response.data)
}

/** @override */
getTransaction (txid) {
return this._get(`/tx/${txid}`).then(x => this._mapTransaction(x))
getTransaction(txid) {
return this._get(`/tx/${txid}`).then((x) => this._mapTransaction(x))
}

/** @override */
getTransactions ({ toTx = '' }) {
getTransactions({ toTx = '' }) {
let url = `/address/${this.address}/txs`
if (toTx) {
url += `/chain/${toTx}`
}
return this._get(url).then(transactions => transactions.map(x => this._mapTransaction(x)))
return this._get(url).then((transactions) => transactions.map((x) => this._mapTransaction(x)))
}

/** @override */
getUnspents () {
return this._get(`/address/${this.address}/utxo`).then(outputs =>
outputs.map(x => ({ txid: x.txid, amount: x.value, vout: x.vout }))
getTransactionHex(txid) {
return this._get(`/tx/${txid}/hex`)
}

/** @override */
getUnspents() {
return this._get(`/address/${this.address}/utxo`).then((outputs) =>
outputs.map((x) => ({ txid: x.txid, amount: x.value, vout: x.vout }))
)
}

getFeeRate () {
return this._get('/fee-estimates').then(estimates => estimates['2'])
getFeeRate() {
return this._get('/fee-estimates').then((estimates) => estimates['2'])
}

/** @override */
_mapTransaction (tx) {
_mapTransaction(tx) {
const mapped = super._mapTransaction({
...tx,
vin: tx.vin.map(x => ({ ...x, addr: x.prevout.scriptpubkey_address })),
vout: tx.vout.map(x => ({
vin: tx.vin.map((x) => ({ ...x, addr: x.prevout.scriptpubkey_address })),
vout: tx.vout.map((x) => ({
...x,
scriptPubKey: { addresses: [x.scriptpubkey_address] }
})),
Expand All @@ -77,7 +84,9 @@ export default class BitcoinApi extends BtcBaseApi {
}

/** Executes a GET request to the API */
_get (url, params) {
return this._getClient().get(url, { params }).then(response => response.data)
_get(url, params) {
return this._getClient()
.get(url, { params })
.then((response) => response.data)
}
}
11 changes: 7 additions & 4 deletions src/lib/bitcoin/btc-base-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as bitcoin from 'bitcoinjs-lib'
import axios from 'axios'

import networks from './networks'
import { getRandomNodeUrl } from "@/config/utils";
import { getRandomNodeUrl } from '@/config/utils'
import BigNumber from '../bignumber'
import { isPositiveNumber } from '@/lib/numericHelpers'
import { CryptosInfo } from '../constants'
Expand Down Expand Up @@ -88,8 +88,7 @@ export default class BtcBaseApi {

// populate unspents with full transaction in HEX
for (const unspent of unspents) {
const txHex = await this._get(`/tx/${unspent.txid}/hex`)
unspent.txHex = txHex
unspent.txHex = await this.getTransactionHex(unspent.txid)
}

const hex = this._buildTransaction(address, amount, unspents, fee)
Expand Down Expand Up @@ -120,6 +119,10 @@ export default class BtcBaseApi {
return Promise.resolve(null)
}

getTransactionHex(txid) {
return Promise.resolve(null)
}

/**
* Retrieves transactions for the specified address
* @abstract
Expand Down Expand Up @@ -198,7 +201,7 @@ export default class BtcBaseApi {
}

/** Picks a client for a random API endpoint */
_getClient () {
_getClient() {
const url = getRandomNodeUrl(this._crypto.toLowerCase())
if (!this._clients[url]) {
this._clients[url] = createClient(url)
Expand Down
64 changes: 36 additions & 28 deletions src/lib/bitcoin/dash-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import BtcBaseApi from './btc-base-api'
import { Cryptos } from '../constants'

class DashApiError extends Error {
constructor (method, error) {
constructor(method, error) {
super('Dash API returned an error')

this.code = 'DASH_API'
Expand All @@ -16,55 +16,61 @@ class DashApiError extends Error {
}

export default class DashApi extends BtcBaseApi {
constructor (passphrase) {
constructor(passphrase) {
super(Cryptos.DASH, passphrase)
}

/**
* @override
*/
getBalance () {
return this._invoke('getaddressbalance', [this.address])
.then(result => Number(result.balance) / this.multiplier)
getBalance() {
return this._invoke('getaddressbalance', [this.address]).then(
(result) => Number(result.balance) / this.multiplier
)
}

/** @override */
sendTransaction (txHex) {
sendTransaction(txHex) {
return this._invoke('sendrawtransaction', [txHex])
}

/** @override */
getTransaction (txid) {
return this._invoke('getrawtransaction', [txid, true])
.then(result => this._mapTransaction(result))
getTransaction(txid) {
return this._invoke('getrawtransaction', [txid, true]).then((result) =>
this._mapTransaction(result)
)
}

/** @override */
getTransactions (options) {
async getTransactionHex(txid) {
RealGoodProgrammer marked this conversation as resolved.
Show resolved Hide resolved
return await this._invoke('getrawtransaction', [txid, false])
}

/** @override */
getTransactions(options) {
return this._invoke('getaddresstxids', [this._address])
.then(txids => {
.then((txids) => {
const excludes = options.excludes || []
return txids
.filter(x => !excludes.includes(x))
.map(x => ({
.filter((x) => !excludes.includes(x))
.map((x) => ({
method: 'getrawtransaction',
params: [x, true]
}))
})
.then(calls => this._invokeMany(calls))
.then(results => results
.filter(x => !x.error && x.result)
.map(x => this._mapTransaction(x.result))
.then((calls) => this._invokeMany(calls))
.then((results) =>
results.filter((x) => !x.error && x.result).map((x) => this._mapTransaction(x.result))
)
.then(items => ({ hasMore: false, items }))
.then((items) => ({ hasMore: false, items }))
}

/** @override */
getUnspents () {
return this._invoke('getaddressutxos', [this.address]).then(result => {
getUnspents() {
return this._invoke('getaddressutxos', [this.address]).then((result) => {
if (!Array.isArray(result)) return []

return result.map(x => ({
return result.map((x) => ({
txid: x.txid,
amount: x.satoshis,
vout: x.outputIndex
Expand All @@ -73,10 +79,10 @@ export default class DashApi extends BtcBaseApi {
}

/** @override */
_mapTransaction (tx) {
_mapTransaction(tx) {
return super._mapTransaction({
...tx,
vin: tx.vin.map(x => ({ ...x, addr: x.address }))
vin: tx.vin.map((x) => ({ ...x, addr: x.address }))
})
}

Expand All @@ -86,16 +92,18 @@ export default class DashApi extends BtcBaseApi {
* @param {object | Array<any>} params method params
* @returns {Promise<any>} method result
*/
_invoke (method, params) {
return this._getClient().post('/', { method, params })
_invoke(method, params) {
return this._getClient()
.post('/', { method, params })
.then(({ data }) => {
if (data.error) throw new DashApiError(method, data.error)
return data.result
})
}

_invokeMany (calls) {
return this._getClient().post('/', calls)
.then(response => response.data)
_invokeMany(calls) {
return this._getClient()
.post('/', calls)
.then((response) => response.data)
}
}
Loading