Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
14 changes: 12 additions & 2 deletions packages/extension/src/providers/bitcoin/libs/utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { BitcoinNetworkInfo, HaskoinUnspentType } from '../types';
import { address as BTCAddress } from 'bitcoinjs-lib';
import { GasPriceTypes } from '@/providers/common/types';
import { fromBase } from '@enkryptcom/utils';
import { fromBase, toBase } from '@enkryptcom/utils';
import BigNumber from 'bignumber.js';
import { BitcoinNetwork } from '../types/bitcoin-network';
import { BTCTxInfo } from '../ui/types';
Expand All @@ -15,6 +15,16 @@ const isAddress = (address: string, network: BitcoinNetworkInfo): boolean => {
}
};

/**
* The network's dust limit in base units.
*
* Nodes will not relay a transaction that carries an output below this, so a
* change output worth less than the limit cannot be added to a transaction. It
* has to be left behind as fee instead.
*/
const getDustThreshold = (network: BitcoinNetwork): number =>
Number(toBase(network.dust.toString(), network.decimals));

const getTxInfo = (
utxos: HaskoinUnspentType[],
ordinalUTXO?: HaskoinUnspentType,
Expand Down Expand Up @@ -101,4 +111,4 @@ const getGasCostValues = async (
};
return gasCostValues;
};
export { isAddress, getGasCostValues, getTxInfo };
export { isAddress, getGasCostValues, getTxInfo, getDustThreshold };
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// @vitest-environment node
//
// The bitcoin provider tests run in the node environment: bitcoinjs-lib checks
// Buffer values against Uint8Array, and under jsdom the two come from different
// realms.
import { describe, it, expect } from 'vitest';
import bitcoinNetworks from '../networks';
import { getDustThreshold } from '../libs/utils';

describe('Should report the dust limit in base units', () => {
it('should convert each network limit from whole coins', () => {
// 0.00000546 BTC
expect(getDustThreshold(bitcoinNetworks.bitcoin)).to.be.eq(546);
expect(getDustThreshold(bitcoinNetworks.bitcoinTest)).to.be.eq(546);
// 0.0001 LTC, an order of magnitude above the bitcoin limit
expect(getDustThreshold(bitcoinNetworks.litecoin)).to.be.eq(10000);
// 0.01 DOGE
expect(getDustThreshold(bitcoinNetworks.dogecoin)).to.be.eq(1000000);
});

it('should classify a change remainder against the limit', () => {
const litecoin = getDustThreshold(bitcoinNetworks.litecoin);
// the amount of change a small litecoin send is left with
expect(750 >= litecoin).to.be.eq(false);
expect(litecoin - 1 >= litecoin).to.be.eq(false);
expect(litecoin >= litecoin).to.be.eq(true);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,11 @@ import Browser from 'webextension-polyfill';
import { ProviderName } from '@/types/provider';
import PublicKeyRing from '@/libs/keyring/public-keyring';

import { getGasCostValues, isAddress } from '../../libs/utils';
import {
getDustThreshold,
getGasCostValues,
isAddress,
} from '../../libs/utils';
import BitcoinAPI from '@/providers/bitcoin/libs/api';
import { calculateSizeBasedOnType } from '../libs/tx-size';
import { HaskoinUnspentType } from '../../types';
Expand Down Expand Up @@ -517,7 +521,9 @@ const sendAction = async () => {
});
}
const remainder = UTXOBalance.value.sub(toAmount).sub(currentFee);
if (remainder.gtn(0)) {
// Change worth less than the dust limit cannot be paid out: the node would
// reject the whole transaction as non standard. Leave it as fee instead.
if (remainder.gten(getDustThreshold(props.network as BitcoinNetwork))) {
txInfo.outputs.push({
address: props.network.displayAddress(addressFrom.value),
value: remainder.toNumber(),
Expand Down
9 changes: 7 additions & 2 deletions packages/extension/src/ui/action/views/swap/libs/swap-txs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ import { ApiPromise } from '@polkadot/api';
import { TransactionType } from '../types';
import { BitcoinNetwork } from '@/providers/bitcoin/types/bitcoin-network';
import BitcoinAPI from '@/providers/bitcoin/libs/api';
import { getTxInfo as getBTCTxInfo } from '@/providers/bitcoin/libs/utils';
import {
getTxInfo as getBTCTxInfo,
getDustThreshold,
} from '@/providers/bitcoin/libs/utils';
import { toBN } from 'web3-utils';
import { BTCTxInfo } from '@/providers/bitcoin/ui/types';

Expand Down Expand Up @@ -58,7 +61,9 @@ export const getBitcoinNativeTransaction = async (
address: tx.to,
value: toAmount.toNumber(),
});
if (remainder > 0) {
// Change worth less than the dust limit cannot be paid out: the node would
// reject the whole transaction as non standard. Leave it as fee instead.
if (remainder >= getDustThreshold(network)) {
txInfo.outputs.push({
address: network.displayAddress(tx.from),
value: remainder,
Expand Down