Skip to content

Commit 584e73e

Browse files
authored
feat: update UTXO selection logic to require specific UTXOs and remove skipUtxoSelection option (#14)
1 parent 950a313 commit 584e73e

5 files changed

Lines changed: 83 additions & 32 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@onekeyfe/coinselect",
3-
"version": "3.1.15",
3+
"version": "3.1.16",
44
"description": "A transaction input selection module for bitcoin.",
55
"keywords": [
66
"coinselect",

test/fixtures/witness.js

Lines changed: 78 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -366,38 +366,90 @@ const fixtures = [
366366
shouldThrow: false
367367
},
368368
{
369-
description: 'skipUtxoSelection - coin control with specific inputs',
369+
description: 'required utxo - only required UTXOs are selected for small payment',
370370
feeRate: 10,
371371
inputs: [
372+
// UTXO 1: large, not required - should NOT be selected
372373
{
373-
txId: 'f46689066ac0493cc55920c3918163ccda6c64998d6c078c6254e1c00c36a332',
374+
txId: 'utxo1_large_not_required',
374375
vout: 0,
375-
value: 50000,
376-
amount: '50000',
376+
value: 100000,
377+
amount: '100000',
377378
confirmations: 100,
378379
own: true,
379380
coinbase: false,
380381
address: 'tb1qul5mzh5phe7xqyqek0nl42hflfrn7ugxck59jd',
381382
path: "m/84'/1'/0'/0/0"
382383
},
384+
// UTXO 2: small, required - MUST be selected
385+
{
386+
txId: 'utxo2_small_required',
387+
vout: 0,
388+
value: 5000,
389+
amount: '5000',
390+
confirmations: 200,
391+
own: true,
392+
coinbase: false,
393+
address: 'tb1qul5mzh5phe7xqyqek0nl42hflfrn7ugxck59jd',
394+
path: "m/84'/1'/0'/0/1",
395+
required: true
396+
},
397+
// UTXO 3: medium, not required - should NOT be selected
383398
{
384-
txId: 'a88d1066ac0493cc55920c3918163ccda6c64998d6c078c6254e1c00c36a332',
399+
txId: 'utxo3_medium_not_required',
385400
vout: 1,
386401
value: 30000,
387402
amount: '30000',
388-
confirmations: 200,
403+
confirmations: 150,
389404
own: true,
390405
coinbase: false,
391406
address: 'tb1qul5mzh5phe7xqyqek0nl42hflfrn7ugxck59jd',
392-
path: "m/84'/1'/0'/0/0"
407+
path: "m/84'/1'/0'/0/2"
408+
},
409+
// UTXO 4: small, required - MUST be selected
410+
{
411+
txId: 'utxo4_small_required',
412+
vout: 2,
413+
value: 3000,
414+
amount: '3000',
415+
confirmations: 300,
416+
own: true,
417+
coinbase: false,
418+
address: 'tb1qul5mzh5phe7xqyqek0nl42hflfrn7ugxck59jd',
419+
path: "m/84'/1'/0'/0/3",
420+
required: true
421+
},
422+
// UTXO 5: small, not required - should NOT be selected
423+
{
424+
txId: 'utxo5_small_not_required',
425+
vout: 0,
426+
value: 2000,
427+
amount: '2000',
428+
confirmations: 50,
429+
own: true,
430+
coinbase: false,
431+
address: 'tb1qul5mzh5phe7xqyqek0nl42hflfrn7ugxck59jd',
432+
path: "m/84'/1'/0'/0/4"
433+
},
434+
// UTXO 6: medium, not required - should NOT be selected
435+
{
436+
txId: 'utxo6_medium_not_required',
437+
vout: 1,
438+
value: 20000,
439+
amount: '20000',
440+
confirmations: 80,
441+
own: true,
442+
coinbase: false,
443+
address: 'tb1qul5mzh5phe7xqyqek0nl42hflfrn7ugxck59jd',
444+
path: "m/84'/1'/0'/0/5"
393445
}
394446
],
395447
outputs: [
396448
{
397449
type: 'payment',
398450
address: 'tb1quawu6eyfuechu3qhdeejnrzne9y7shr08u8zzt',
399-
value: 60000,
400-
amount: '60000'
451+
value: 1000,
452+
amount: '1000'
401453
}
402454
],
403455
network: testnet,
@@ -406,50 +458,51 @@ const fixtures = [
406458
path: "m/84'/1'/0'/0/0"
407459
},
408460
txType: 'p2wpkh',
409-
skipUtxoSelection: true,
410461
expected: {
411462
type: 'final',
412463
fee: '2090',
413464
feePerByte: '10',
414465
bytes: 209,
415466
max: undefined,
416-
totalSpent: '62090',
467+
totalSpent: '3090',
417468
inputs: [
418469
{
419-
txId: 'a88d1066ac0493cc55920c3918163ccda6c64998d6c078c6254e1c00c36a332',
420-
vout: 1,
421-
value: 30000,
470+
txId: 'utxo2_small_required',
471+
vout: 0,
472+
value: 5000,
422473
confirmations: 200,
423474
own: true,
424475
address: 'tb1qul5mzh5phe7xqyqek0nl42hflfrn7ugxck59jd',
425-
path: "m/84'/1'/0'/0/0",
476+
path: "m/84'/1'/0'/0/1",
426477
coinbase: false,
427-
amount: '30000'
478+
amount: '5000',
479+
required: true
428480
},
429481
{
430-
txId: 'f46689066ac0493cc55920c3918163ccda6c64998d6c078c6254e1c00c36a332',
431-
vout: 0,
432-
value: 50000,
433-
confirmations: 100,
482+
txId: 'utxo4_small_required',
483+
vout: 2,
484+
value: 3000,
485+
confirmations: 300,
434486
own: true,
435487
address: 'tb1qul5mzh5phe7xqyqek0nl42hflfrn7ugxck59jd',
436-
path: "m/84'/1'/0'/0/0",
488+
path: "m/84'/1'/0'/0/3",
437489
coinbase: false,
438-
amount: '50000'
490+
amount: '3000',
491+
required: true
439492
}
440493
],
441494
outputs: [
442495
{
443496
type: 'payment',
444497
address: 'tb1quawu6eyfuechu3qhdeejnrzne9y7shr08u8zzt',
445-
value: 60000,
446-
amount: '60000'
498+
value: 1000,
499+
amount: '1000'
447500
},
448501
{
449502
type: 'change',
450503
address: 'tb1qul5mzh5phe7xqyqek0nl42hflfrn7ugxck59jd',
451504
path: "m/84'/1'/0'/0/0",
452-
amount: '17910'
505+
amount: '4910'
453506
}
454507
],
455508
outputsPermutation: [0, 1]

test/witness.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ fixtures.forEach(function (f) {
2525
feeRate: f.feeRate,
2626
network: f.network,
2727
changeAddress: f.changeAddress,
28-
txType: f.txType,
29-
skipUtxoSelection: f.skipUtxoSelection
28+
txType: f.txType
3029
})
3130

3231
const compareOutputs = (actual, expected) => {

witness.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export interface IUtxo {
66
coinbase: boolean;
77
own: boolean;
88
confirmations: number;
9+
required?: boolean;
910
}
1011

1112
export interface IOutputPayment {

witness.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ module.exports = function coinSelect ({
88
network,
99
txType,
1010
baseFee = 0,
11-
dustThreshold = 546,
12-
skipUtxoSelection = false
11+
dustThreshold = 546
1312
}) {
1413
const result = composeTx({
1514
utxos,
@@ -20,8 +19,7 @@ module.exports = function coinSelect ({
2019
dustThreshold,
2120
changeAddress,
2221
network,
23-
baseFee,
24-
skipUtxoSelection
22+
baseFee
2523
})
2624

2725
if (result.type === 'error') {

0 commit comments

Comments
 (0)