Skip to content

Change should greater than dust when alwaysChange#135

Open
akashiceth wants to merge 1 commit intopaulmillr:mainfrom
akashiceth:main
Open

Change should greater than dust when alwaysChange#135
akashiceth wants to merge 1 commit intopaulmillr:mainfrom
akashiceth:main

Conversation

@akashiceth
Copy link
Copy Markdown

Change smaller than dust is meaningless. When alwaysChange: true, the change should be greater than dust.

import * as btc from "@scure/btc-signer";
import { hex } from "@scure/base";

const P2PKH_SCRIPT = hex.decode(
    "76a914168b992bcfc44050310b3a94bd0771136d0b28d188ac"
);

async function main() {
    const requiredInputs = [
        {
            txid: new Uint8Array(32).fill(0xaa),
            index: 0,
            witnessUtxo: {
                script: P2PKH_SCRIPT,
                amount: 2835324n,
            },
        },
        {
            txid: new Uint8Array(32).fill(0xbb),
            index: 0,
            witnessUtxo: {
                script: P2PKH_SCRIPT,
                amount: 205887n,
            },
        },
        {
            txid: new Uint8Array(32).fill(0xcc),
            index: 0,
            witnessUtxo: {
                script: P2PKH_SCRIPT,
                amount: 5000n,
            },
        }
    ];


    const outputs = [
        {
            address: "134D6gYy8DsR5m4416BnmgASuMBqKvogQh",
            amount: 760286n,
        },
        {
            address: "134D6gYy8DsR5m4416BnmgASuMBqKvogQh",
            amount: 760286n,
        },
        {
            address: "134D6gYy8DsR5m4416BnmgASuMBqKvogQh",
            amount: 760286n,
        },
        {
            address: "134D6gYy8DsR5m4416BnmgASuMBqKvogQh",
            amount: 760286n,
        },
    ];

    const selection = selectUTXO(requiredInputs, outputs, "default", {
        alwaysChange: true,
        feePerByte: 0n,
        allowSameUtxo: false,
        allowLegacyWitnessUtxo: true,
        disableScriptCheck: true,
        createTx: false, 
        changeAddress: "134D6gYy8DsR5m4416BnmgASuMBqKvogQh",
    });

    if (!selection) {
        console.log("No selection");
        return;
    }

    selection.inputs.forEach((inp, idx) => {
        const { txid, index, witnessUtxo } = inp;
        console.log(
            `  #${idx}: txid=${hex.encode(txid!)} amount=${witnessUtxo?.amount
            }`
        );
    });

    selection.outputs.forEach((inp, idx) => {
        const { address, amount } = inp;
        console.log(
            `  #${idx}: address=${address} amount=${amount
            }`
        );
    });
}

main().catch((err) => console.error(err));

The example above will change 67 sat, but it would be better to change 5067 sat

@paulmillr
Copy link
Copy Markdown
Owner

Could you add some tests?

@akashiceth
Copy link
Copy Markdown
Author

Could you add some tests?

Tests added, but the GitHub Action failed. However all tests passed on my local side when I run npm run test:node20.

@paulmillr
Copy link
Copy Markdown
Owner

Hmm why can't you simply use alwaysChange: false?

@akashiceth
Copy link
Copy Markdown
Author

akashiceth commented Nov 1, 2025

Hmm why can't you simply use alwaysChange: false?

One of our use cases is: Three parties partially sign a PSBT. Two of the parties partially sign their own inputs and outputs, while the last party verifies them, pays the fees, and submits the transaction. When alwaysChange is set to false, the first two parties will not change outputs that are smaller than the dust; instead, they will use this intended change to pay the transaction fees.

The "alwaysChange" here isn't quite as "always" as it claims—it fails to change when the output is less than dust.

@paulmillr
Copy link
Copy Markdown
Owner

The current behavior works properly for ordinals. It wouldn't work if this is changed.

Your use case is nevertheless valid. I think the new feature should be under the new flag. Do you have a naming idea?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants