-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
6438c55
commit ed44b85
Showing
2 changed files
with
125 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import { Coin } from '../src/wallet/coin'; | ||
import { CoinSelector } from '../src/wallet/coin-selector.ts'; | ||
import { Transaction } from 'bitcoinjs-lib'; | ||
|
||
describe('CoinSelector', () => { | ||
let coinSelector: CoinSelector; | ||
const feeRate: number = 5; | ||
|
||
beforeAll(() => { | ||
coinSelector = new CoinSelector(feeRate); | ||
}); | ||
|
||
it('should generate the correct cost of change', () => { | ||
// Fixed value for the cost of change based on the current feeRate. | ||
const correctCostOfChange = 495; | ||
|
||
// Assert the correctness of the CoinSelector result. | ||
expect(correctCostOfChange).toBe(coinSelector.costOfChange); | ||
}); | ||
|
||
it.each([ | ||
{ | ||
testName: 'should add change to the fee if it is dust', | ||
testCoinValues: [ | ||
1005, 9040, 6440, 2340, 7540, 3920, 5705, 9030, 1092, 5009, | ||
], | ||
expectedChange: 0, // Change will be zero when less than dust. | ||
expectedCoinCount: 10, // All the coins are going to be selected. | ||
}, | ||
{ | ||
testName: 'change should be considered when greater than dust', | ||
testCoinValues: [5000, 4000], | ||
txOutValue: 1000, // Less output so that the change is greater than dust. | ||
expectedChange: 2185, // expectedChange = totalSelectedCoin - (txOutValue + transactionFees). | ||
expectedCoinCount: 1, // One Coin will suffice for a 1000 sats output for this case. | ||
}, | ||
])( | ||
'%s', | ||
({ txOutValue, testCoinValues, expectedChange, expectedCoinCount }) => { | ||
const coins: Coin[] = []; | ||
let totalBalance: number = 0; | ||
|
||
// Calculate the total balance based on the fixed array of coin values. | ||
for (const value of testCoinValues) { | ||
const coin = new Coin({ value }); | ||
coins.push(coin); | ||
// Calculate the total balance by subtracting the spending fee. | ||
totalBalance += coin.value - coin.estimateSpendingFee(feeRate); | ||
} | ||
|
||
// Create a new Transaction | ||
const transaction: Transaction = new Transaction(); | ||
|
||
// Fixed fees for the transaction calculated based on the total size of the transaction and the change output size. | ||
// transactionFees = (virtualSize + changeOutputSize) * feeRate, P2WPKH output is 31 bytes. | ||
const transactionFees = 250; | ||
|
||
// txOutValue is not defined for the first test in order to demonstrate its calculation. | ||
if (!txOutValue) { | ||
// Fixed transaction output value that ensures the cost of change is dust. | ||
txOutValue = | ||
totalBalance - | ||
transactionFees - | ||
coinSelector.costOfChange + | ||
1; | ||
} | ||
|
||
// Set the transaction output value with a random output script. | ||
// Random hex string of 20 bytes and `0014${genRanHex}` will be a valid P2WPKH script. | ||
const genRanHex = (size: number) => | ||
[...Array(size)] | ||
.map(() => Math.floor(Math.random() * 16).toString(16)) | ||
.join(''); | ||
transaction.addOutput( | ||
Buffer.from(`0014${genRanHex(40)}`), // Ensure that the first parameter passed to addOutput is a Buffer. | ||
txOutValue, | ||
); | ||
|
||
// Select coins and change using the CoinSelector. | ||
const { coins: selectedCoins, change } = coinSelector.select( | ||
coins, | ||
transaction, | ||
); | ||
|
||
// Assert that the selected coins' size meets the expected count. | ||
expect(selectedCoins.length).toBe(expectedCoinCount); | ||
|
||
// Assert the change against the expected change condition. | ||
expect(change).toBe(expectedChange); | ||
}, | ||
); | ||
}); |