UNPKG

@node-dlc/core

Version:
180 lines (143 loc) 5.53 kB
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)); }); }); });