@node-dlc/core
Version:
180 lines (143 loc) • 5.53 kB
text/typescript
import { Value } from '@node-dlc/bitcoin';
import { expect } from 'chai';
import { dualFees, dualFundingCoinSelect, UTXO } from '../../lib';
const getUtxos = (totalCollateral: bigint, numUtxos = 1) => {
const utxos: UTXO[] = [];
for (let i = 0; i < numUtxos; i++) {
utxos.push({
address: 'bcrt1qjzut0906d9sk4hml4k6sz6cssljktf4c7yl80f',
txid: 'c7bf12ac16aba1cf6c7769117294853453f7da3006363dfe4e8979847e32f7e1',
value: Math.ceil(Number(totalCollateral) / numUtxos),
vout: Math.floor(Math.random() * 11), // random integer between 0 and 10
});
}
return utxos;
};
describe('CoinSelect', () => {
describe('dualFundingCoinSelect', () => {
it('should select coins correctly for 5 UTXOs and feeRate 450', () => {
const feeRate = BigInt(450);
const numUtxos = 5;
const totalCollateral = Value.fromBitcoin(0.01);
const offerCollateral = Value.fromBitcoin(0.0075);
const utxos = getUtxos(totalCollateral.sats, numUtxos);
const { fee, inputs } = dualFundingCoinSelect(
utxos,
[offerCollateral.sats],
feeRate,
);
expect(fee).to.equal(BigInt(217350));
expect(inputs.length).to.equal(5);
});
it('should fail to select coins if fee is greater than sum of utxos', () => {
const feeRate = BigInt(450);
const numUtxos = 5;
const totalCollateral = Value.fromBitcoin(0.01);
const offerCollateral = Value.fromBitcoin(0.096);
const utxos = getUtxos(totalCollateral.sats, numUtxos);
const { fee, inputs } = dualFundingCoinSelect(
utxos,
[offerCollateral.sats],
feeRate,
);
expect(fee).to.equal(BigInt(94950));
expect(inputs.length).to.equal(0);
});
it('should fail to select coins if detrimental input', () => {
const feeRate = BigInt(450);
const numUtxos = 1;
const totalCollateral = Value.fromSats(30000);
const offerCollateral = Value.fromSats(20000);
const utxos = getUtxos(totalCollateral.sats, numUtxos);
const { fee, inputs } = dualFundingCoinSelect(
utxos,
[offerCollateral.sats],
feeRate,
);
expect(fee).to.equal(BigInt(94950));
expect(inputs.length).to.equal(0);
});
it('should prioritize utxo selection', () => {
const feeRate = BigInt(450);
const numUtxos = 5;
const totalCollateral = Value.fromBitcoin(0.01);
const offerCollateral = Value.fromBitcoin(0.0075);
const utxos = getUtxos(totalCollateral.sats, numUtxos);
utxos.push({
address: 'bcrt1qjzut0906d9sk4hml4k6sz6cssljktf4c7yl80f',
txid:
'c7bf12ac16aba1cf6c7769117294853453f7da3006363dfe4e8979847e32f7e1',
value: 10000,
vout: Math.floor(Math.random() * 11), // random integer between 0 and 10
});
const { fee, inputs } = dualFundingCoinSelect(
utxos,
[offerCollateral.sats],
feeRate,
);
expect(fee).to.equal(BigInt(217350));
expect(inputs.length).to.equal(5);
});
});
describe('Additional CoinSelect Tests', () => {
const feeRate = BigInt(450);
const totalCollateral = Value.fromBitcoin(0.01);
const offerCollateral = Value.fromBitcoin(0.0075);
it('should fail to select coins when all UTXOs are detrimental due to high fee rate', () => {
const highFeeRate = BigInt(10000); // An exaggerated fee rate to make the point
const utxos = getUtxos(totalCollateral.sats, 5);
const { fee, inputs } = dualFundingCoinSelect(
utxos,
[offerCollateral.sats],
highFeeRate,
);
expect(inputs.length).to.equal(0);
expect(fee).to.equal(BigInt(2110000));
});
it('should select all UTXOs when they are just enough to cover collateral and fees', () => {
const utxos = getUtxos(totalCollateral.sats, 5);
const { fee, inputs } = dualFundingCoinSelect(
utxos,
[offerCollateral.sats],
feeRate,
);
expect(inputs.length).to.equal(5);
expect(fee).to.equal(BigInt(217350));
});
it('should select UTXOs optimally from a mixed set', () => {
const mixedUtxos = [
...getUtxos(Value.fromBitcoin(0.005).sats, 2), // smaller UTXOs
...getUtxos(Value.fromBitcoin(0.02).sats, 3), // larger UTXOs
];
const { fee, inputs } = dualFundingCoinSelect(
mixedUtxos,
[offerCollateral.sats],
feeRate,
);
// Expecting it to select fewer, larger UTXOs over many small ones
expect(inputs.length).to.be.lessThan(5);
expect(fee).to.equal(BigInt(125550));
});
it('should handle an empty array of UTXOs correctly', () => {
const { fee, inputs } = dualFundingCoinSelect(
[],
[offerCollateral.sats],
feeRate,
);
expect(inputs.length).to.equal(0);
expect(fee).to.equal(dualFees(feeRate, 1, 1)); // The fee for an attempt with no inputs
});
it('should select fewer UTXOs with a very low fee rate', () => {
const lowFeeRate = BigInt(1); // An extremely low fee rate
const utxos = getUtxos(totalCollateral.sats, 10); // More UTXOs than needed
const { fee, inputs } = dualFundingCoinSelect(
utxos,
[offerCollateral.sats],
lowFeeRate,
);
// Expecting it to select fewer UTXOs due to the low cost of adding an input
expect(inputs.length).to.be.lessThan(10);
expect(fee).to.equal(BigInt(687));
});
});
});