Skip to content

add_change_if_needed() puts all the change into fees when issuing a delegation certificate #712

@wutzebaer

Description

@wutzebaer

Hi i'm trying to build a transaction which stakes to a pool with cardano-serialization-lib.

Sometimes it uses a utxo like this, wich has about 7ada. This should be enough, fee should only be about 0.2 ada.

But instead of returning the ada add_change_if_needed() puts all the change into the fee. The Transaction is valid, but has too much fees.

The output 0 has no tokens: https://cardanoscan.io/transaction/81aceed33f0ff4560579a41cac8355e6e908633f8b5906f21453568064ab4b6a?tab=utxo

Currently i run CoinSelectionStrategyCIP2.RandomImproveMultiAsset in a loop until it selects inputs where add_change_if_needed() results in txBuilder.get_total_output().to_js_value().coin != "0" but it feels buggy.

I'm using

"node_modules/@emurgo/cardano-serialization-lib-browser": {
  "version": "13.2.1",
  "resolved": "https://registry.npmjs.org/@emurgo/cardano-serialization-lib-browser/-/cardano-serialization-lib-browser-13.2.1.tgz",
  "integrity": "sha512-7RfX1gI16Vj2DgCp/ZoXqyLAakWo6+X95ku/rYGbVzuS/1etrlSiJmdbmdm+eYmszMlGQjrtOJQeVLXoj4L/Ag=="
},

Here is a working example:

const txBuilderConfig = TransactionBuilderConfigBuilder.new()
  .fee_algo(LinearFee.new(BigNum.from_str("44"), BigNum.from_str("155381")))
  .coins_per_utxo_byte(BigNum.from_str("34482"))
  .pool_deposit(BigNum.from_str("500000000"))
  .key_deposit(BigNum.from_str("2000000"))
  .max_value_size(5000)
  .max_tx_size(16384)
  .build();

const testTransaction = () => {
  const changeAddressFromWallet =
    "0184b1feb9c705e664caae0e093ddfd6372dc23b93c62eda05cbbe890a072b585b21c3bfd5e01e775504704af98de330ed4d5a16d3e0186805";
  const rawUtxosFromWallet = [
    "8282582081aceed33f0ff4560579a41cac8355e6e908633f8b5906f21453568064ab4b6a00825839018bd0faf6a901fab1ba4f2325d3ece418cc38f8fbcc360a4a897773fd072b585b21c3bfd5e01e775504704af98de330ed4d5a16d3e01868051a006f28ab",
  ];

  // change address
  const changeAddress = Address.from_bytes(
    Buffer.from(changeAddressFromWallet, "hex")
  );

  // parse utxos
  const utxos = rawUtxosFromWallet.map((ru) => {
    return TransactionUnspentOutput.from_bytes(Buffer.from(ru, "hex"));
  });

  // create transaction unspent outputs
  const transactionUnspentOutputs = TransactionUnspentOutputs.new();
  for (const utxo of utxos) {
    transactionUnspentOutputs.add(utxo);
  }

  const txBuilder = TransactionBuilder.new(txBuilderConfig);

  // build delegation certificate
  const poolKeyHash = Ed25519KeyHash.from_bech32("pool180fejev4xgwe2y53ky0pxvgxr3wcvkweu6feq5mdljfzcsmtg6u");
  const rewardAddressHash = "e1072b585b21c3bfd5e01e775504704af98de330ed4d5a16d3e0186805";
  const address = Address.from_bytes(Buffer.from(rewardAddressHash, "hex"));
  const rewardAddress = RewardAddress.from_address(address)!;
  const stakeCredential = rewardAddress.payment_cred();
  const stakeDelegation = StakeDelegation.new(stakeCredential, poolKeyHash);
  const delegationCert = Certificate.new_stake_delegation(stakeDelegation);
  const certificates = Certificates.new();
  certificates.add(delegationCert);

  txBuilder.set_certs(certificates);

  txBuilder.add_inputs_from(
    transactionUnspentOutputs,
    CoinSelectionStrategyCIP2.RandomImproveMultiAsset
  );

  txBuilder.add_change_if_needed(changeAddress);

  console.log(txBuilder.get_fee_if_set()?.to_js_value())
  console.log(txBuilder.get_total_output().to_js_value().coin)

  return txBuilder.build_tx();
};

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions