ckb-cell / rgbpp-sdk

Utilities for Bitcoin and RGB++ asset integration
ISC License
52 stars 14 forks source link

Handling Mixed Address UTXOs with Change Addresses #243

Open Dawn-githup opened 2 weeks ago

Dawn-githup commented 2 weeks ago

Description

Currently, when changeIndex is not null, the change in satoshis is returned to:

This works fine for single addresses but seems a bit odd when dealing with mixed address UTXOs.

Example Scenario

Let's illustrate with a real-world example:

  1. You need to pay 50 units.
  2. You only have 30 units.
  3. You borrow 20 units from me.
  4. I lend you a 50-unit note.
  5. You should return 30 units back to me as change.

Problem

In the context of UTXOs, if the borrowed 50-unit note is from a different address (mixed address UTXO), the system should be able to handle this by correctly returning the change to the lender’s address.

Proposal

To handle this scenario effectively, we suggest discussing whether to remove the restriction on changeAddress. This would allow the system to dynamically allocate the change to the appropriate address based on the UTXOs involved.

This adjustment will ensure that the returned change correctly reflects the source addresses, thereby improving the handling of mixed address UTXOs.


ShookLyngs commented 1 week ago

The current logic of the sendRbf() API suggests that when the changeIndex is specified, the change satoshi should always be returned to the original change address from the original transaction, which makes sense because it's how the original transaction was intended. Ref: https://github.com/ckb-cell/rgbpp-sdk/blob/develop/packages/btc/src/api/sendRbf.ts#L82-L88

if (changeAddress && changeAddress !== outputs[changeIndex].address) {
  throw TxBuildError.withComment(
    ErrorCodes.INVALID_CHANGE_OUTPUT,
    `The address of outputs[${changeIndex}] does not match the specified changeAddress, expected: ${changeAddress}, actual: ${outputs[changeIndex].address}`,
  );
}

However, from another perspective, if the RBF transaction is sponsored by another address, it is also reasonable to return the change to the RBF sponsor instead of the original change address, since the RBF sponsor may provide a large UTXO to the RBF transaction. In this situation, by removing the restriction for the changeAddress option when changeIndex !== undefined, users can freely decide which address the change should be returned to.

Worth mentioning, though, the RBF transaction can be fairly complex:

  1. TX_1=sendBtc(), from=A
  2. TX_2=sendRbf(TX_1), from=B
  3. TX_3=sendRbf(TX_2), from=C
Flouse commented 1 week ago

However, from another perspective, if the RBF transaction is sponsored by another address, it is also reasonable to return the change to the RBF sponsor instead of the original change address, since the RBF sponsor may provide a large UTXO to the RBF transaction.

Usually, the RBF sponsor and the original change address are managed by the same private_key. I thought they belongs to one user.

ShookLyngs commented 1 week ago

Another option is to do nothing about it, because the restriction mentioned above only applies when changeIndex is not undefined. This means if the user leaves the changeIndex option empty, then the changeAddress option is customizable, and the change satoshi of the RBF transaction can be returned to the RBF sponsor.

Basically the restriction ensures that the change output to the original change address exists in the RBF transaction.