Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: handle edge case when change amount is below minimum capacity #313

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions packages/ckb/src/rgbpp/btc-transfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -382,18 +382,30 @@ export const appendIssuerCellToBtcBatchTransferToSign = async ({

let actualInputsCapacity = BigInt(sumInputsCapacity);
const txFee = MAX_FEE;
if (actualInputsCapacity <= sumOutputsCapacity) {
let changeCapacity = actualInputsCapacity - sumOutputsCapacity;
while (changeCapacity < MIN_CAPACITY) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you use a while loop? How do you return from the loop?

Copy link
Collaborator

@duanyytop duanyytop Feb 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if the changeCapacity < MIN_CAPACITY is true, throwing an error is enough for issuers.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initially I mistook txFee for fee rate - I thought the loop ensures sufficient capacity to cover increasing transaction fees as the transaction size grows with each new input from collectInputs. As actualInputsCapacity accumulates in the loop, changeCapacity gradually increases until it either exceeds MIN_CAPACITY for normal exit, or throws CapacityNotEnoughError when available cells are insufficient.

Upon closer inspection after reading your comments, I realize a while loop is unnecessary since txFee is set to a sufficiently large MAX_FEE constant. A simple if statement would be adequate here.

Despite its name, appendIssuerCellToBtcBatchTransferToSign serves as a general fee supplement method in offline mode. Perhaps we should collect additional issuer's cells as inputs to cover tx fee whenever possible, instead of throwing an error. Please let me know your thoughts.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. The MAX_FEE is 0.2CKB, and it is enough for almost transactions.
  2. If the issuer's balance is not enough for collecting, the loop does not work.
  3. I think you could provide a capacity estimate function for the issuer before collecting cells.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point! I'll try to implement it later.

const needCapacity = sumOutputsCapacity - actualInputsCapacity + MIN_CAPACITY;
const { inputs, sumInputsCapacity: sumEmptyCapacity } = collector.collectInputs(emptyCells, needCapacity, txFee);
rawTx.inputs = [...rawTx.inputs, ...inputs];
actualInputsCapacity += sumEmptyCapacity;
changeCapacity = actualInputsCapacity - sumOutputsCapacity;
}

let changeCapacity = actualInputsCapacity - sumOutputsCapacity;
const changeOutput = {
lock: issuerLock,
capacity: append0x(changeCapacity.toString(16)),
};
const secp256k1CellDep = getSecp256k1CellDep(isMainnet);
if (
!rawTx.cellDeps.some(
({ outPoint }) =>
outPoint &&
outPoint.txHash === secp256k1CellDep.outPoint!.txHash &&
outPoint.index === secp256k1CellDep.outPoint!.index,
)
) {
rawTx.cellDeps = [...rawTx.cellDeps, secp256k1CellDep];
}
rawTx.outputs = [...rawTx.outputs, changeOutput];
rawTx.outputsData = [...rawTx.outputsData, '0x'];

Expand Down
Loading