cardano-serialization-lib icon indicating copy to clipboard operation
cardano-serialization-lib copied to clipboard

UTxO Balance Insufficient from add_inputs_from LargestFirstMultiAsset

Open TanyaMio opened this issue 2 years ago • 8 comments

I am trying to build a transaction that will send a token to a contract address. The transaction has 1 explicit output:

txBuilder.add_output(
    CardanoWasm.TransactionOutputBuilder
      .new()
      .with_address(contractAddress)
      .with_data_hash(CardanoWasm.hash_plutus_data(CardanoWasm.PlutusData.new_constr_plutus_data(datum)))
      .next()
      .with_asset_and_min_required_coin_by_utxo_cost(
        multiasset,
        CardanoWasm.DataCost.new_coins_per_byte(
          CardanoWasm.BigNum.from_str(protocolParameters.coins_per_utxo_size)
        )
      )
      .build()
  );

I am requesting wallet UTxOs from the wallet API. Here is the response:

[
    "82825820a37e3349c08374c5f96f46e26d72841acb6089e270d61c15d90e1aaaeaa3da6c0082583900c886f62c56c6671f6a5c37f43927b674a6e6258b2075ed59385b84cf5a66cb93faa190ea818790d69cd144f273fa64646c26f107ad157828821a001484d0a1581c39788d5355bce70fd1364021f395060f484e077129286308455ee34ea1446c65616601",
    "82825820a37e3349c08374c5f96f46e26d72841acb6089e270d61c15d90e1aaaeaa3da6c0182583900c886f62c56c6671f6a5c37f43927b674a6e6258b2075ed59385b84cf5a66cb93faa190ea818790d69cd144f273fa64646c26f107ad1578281a1db60187"
]

And the decoded values:

[
  [h'A37E3349C08374C5F96F46E26D72841ACB6089E270D61C15D90E1AAAEAA3DA6C', 0], 
  [
    h'00C886F62C56C6671F6A5C37F43927B674A6E6258B2075ED59385B84CF5A66CB93FAA190EA818790D69CD144F273FA64646C26F107AD157828',
    [1344720, {h'39788D5355BCE70FD1364021F395060F484E077129286308455EE34E': {h'6C656166': 1}}]
  ]
]

[
  [h'A37E3349C08374C5F96F46E26D72841ACB6089E270D61C15D90E1AAAEAA3DA6C', 1], 
  [
    h'00C886F62C56C6671F6A5C37F43927B674A6E6258B2075ED59385B84CF5A66CB93FAA190EA818790D69CD144F273FA64646C26F107AD157828', 
    498467207
  ]
]

From there I am creating a TransactionUnspentOutputs object:

let inputs = CardanoWasm.TransactionUnspentOutputs.new();
utxos.forEach(function(element) {
    let utxo = CardanoWasm.TransactionUnspentOutput.from_hex(element);
    inputs.add(utxo);
});

And if I check the result by comparing utxos.get(i) and inputs.get(i).to_hex() - the strings are identical. Which leads me to believe there is no error during type conversion.

Here is the screenshot of txBuilder.get_explicit_output().to_js_value(), utxos and inputs right before calling txBuilder.add_inputs_from(inputs, CardanoWasm.CoinSelectionStrategyCIP2.LargestFirstMultiAsset);

image

It should be working fine, since I have more than enough ADA in my wallet, and the token is there as well. But I am still getting the "UTxO Balance Insufficient" error. Is there any way to fix this?

TanyaMio avatar Mar 14 '23 08:03 TanyaMio

Hi @TanyaMio ! Could you provide full code to reproduce your error ?

lisicky avatar Mar 14 '23 09:03 lisicky

@lisicky I don't think I am able to share full code, since it's a company project. Is there a more specific place where the issue might be coming from? If there is, I will be able to share other snippets.

TanyaMio avatar Mar 15 '23 00:03 TanyaMio

@TanyaMio I had exactly the same issue, trying to mint a token and send it in the same transaction using the TransactionOutputBuilder. I guess it doesn't recognize the minted asset when using the MintBuilder, so it does not exist in the UTxO and therefor the "UTxO Balance Insufficient".

What works is this:

const txoBuilder = CardanoWasm.TransactionOutputBuilder.new();
const dataCost = CardanoWasm.DataCost.new_coins_per_byte(CardanoWasm.BigNum.from_str(protocolParameters.coins_per_utxo_size || '4310'));
const multiAsset = CardanoWasm.MultiAsset.from_json('{"' + policyId + '":{"' + cardanoAssetName.to_hex() + '":"' + mintAsset.quantity + '"}}');
const txo = txoBuilder.with_address(outputAddr).next().with_asset_and_min_required_coin_by_utxo_cost(multiAsset, dataCost);
txBuilder.add_mint_asset_and_output_min_required_coin(allScript, cardanoAssetName, CardanoWasm.Int.from_str(mintAsset.quantity), txo);

When cost are set in the txBuilder config, this also works:

const txoBuilder = CardanoWasm.TransactionOutputBuilder.new();
const txo = txoBuilder.with_address(outputAddr).next();
txBuilder.add_mint_asset_and_output_min_required_coin(allScript, cardanoAssetName, CardanoWasm.Int.from_str(mintAsset.quantity), txo);

Why it does not work with the MintBuilder is a mystery for me atm 🤷

kommander avatar Mar 17 '23 19:03 kommander

@TanyaMio without full example we can only try to guess. Call get_total_input and get_total_output from TransactionBuilder before calling add_inputs_from and provide cbor of both values that you get. Also you can try to create a fake input with huge amount of ada to exclude situation when you have not enough ada.

lisicky avatar Mar 19 '23 21:03 lisicky

@kommander under the hood add_mint_asset_and_output_min_required_coin uses the MintBuilder. Could you provide cbor of get_total_input and get_total_output result ? If you can provide an isolated code example to reproduce the problem it would be better.

lisicky avatar Mar 19 '23 21:03 lisicky

@lisicky thanks for looking into this. Here's the repro: https://github.com/kommander/csl-utxo-insufficient-balance-repro

kommander avatar Mar 19 '23 22:03 kommander

@kommander please check get_total_input and get_total_output values. Anyway, building manually by from_json can be tricky. And I recommend using it only for debugging because if cardano protocol is changed, it would be more difficult to find mistakes.

Example for you case, how you can build MultiAsset without from_json :

const multiAsset = CardanoWasm.MultiAsset.new();
const asset = CardanoWasm.Assets.new();
asset.insert(cardanoAssetName, BigNum.from_str(String(mintAsset.quantity)));
multiAsset.insert(allScript.hash(), asset);

lisicky avatar Mar 20 '23 09:03 lisicky

@lisicky Creating the MultiAsset manually using the CSL API works, no error. So it seems to be an issue with the MultiAsset.from_json like you assumed ✅

As the actual error happens when calling txBuilder.add_inputs_from, I can only get the total inputs/outputs directly before that, which are the same when using from_json and when creating the MultiAsset manually:

totalInputs {
  "coin": "0",
  "multiasset": {
    "b2a3ddf612558ffbf387fdbd2bc71a88cb20049399bee4ae30929c05": {
      "546573744173736574": "1000000"
    }
  }
}
totalOutputs {
  "coin": "1176630",
  "multiasset": {
    "b2a3ddf612558ffbf387fdbd2bc71a88cb20049399bee4ae30929c05": {
      "546573744173736574": "1000000"
    }
  }
}

kommander avatar Mar 20 '23 12:03 kommander

Close it because current conversation is not related to original topic

lisicky avatar Aug 28 '24 07:08 lisicky