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

add_change_if_needed not handling native assets in utxo

Open shroomist opened this issue 2 years ago • 32 comments

when add_change_if_needed is used along with add_mint_asset_and_output_min_required_coin, seems to be unable to balance transaction correctly when given a utxo that contains native assets (with nft metadata).

add_change_if_needed fails with

missing input for some native asset
txBuilder
        const policyId = Buffer.from(
          nativeScript.hash(0).to_bytes()
        ).toString('hex')

        const generalTxMeta = genMetadata(cslModule)(policyId, metadata)
        txBuilder.set_metadata(generalTxMeta)

        const assetName = AssetName.new(Buffer.from(assetNameStr, 'utf-8'))
        const assetNumber = Int.new_i32(assetNum)

        txBuilder.add_mint_asset_and_output_min_required_coin(
          nativeScript,
          assetName,
          assetNumber,
          addr
        )

        txBuilder.set_ttl(timelockExpirySlot)

        const [input] = utxos.map(u => ({
          utxo: u.input(),
          value: u.output().amount(),
        }))

        txBuilder.add_key_input(
          addr_keyhash,
          input.utxo,
          input.value
        )

        txBuilder.add_change_if_needed(addr)

        const tx = txBuilder.build_tx()

shroomist avatar Dec 09 '21 11:12 shroomist

Hi, @shroomist , provide full example of the sequence of calls to the builder please, so we can try to reproduce

vsubhuman avatar Dec 09 '21 11:12 vsubhuman

Updated with the code sample. Issue boils down to that I'm able to mint with some utxos and unable with some other.

shroomist avatar Dec 09 '21 18:12 shroomist

Having the same issue in some instances.

MartinSchere avatar Feb 10 '22 23:02 MartinSchere

@MartinSchere @shroomist can you provide the utxos where you aren't able to?

rooooooooob avatar Feb 10 '22 23:02 rooooooooob

I have run into the same issue trying to send an asset.

Here is two UTXOs on the testnet I'm having the problem with: "73a0cdfde20a2482164821ee765977444ed47bc7acf25cb77809b200c90ee295#0" "e5eb46c4c72fb84c443a03be5be48dca2740a77015b30c4c633fb0755f31f73f#0"

I haven't tried others.

bakon11 avatar Feb 16 '22 15:02 bakon11

Issue boils down to that I'm able to mint with some utxos and unable with some other.

@shroomist , the critical question there is what is the value of those inputs that you have problems minting with? In the provided example I see you are setting a single input - what is the value of that simple input and does it cover both the fee and the min-required-ada value that is being set to the output with the new asset AND the min-required-ada value that has to be included in the change when the assets from the input will be sent back to you as change?

vsubhuman avatar Feb 16 '22 19:02 vsubhuman

I have run into the same issue trying to send an asset.

Here is two UTXOs on the testnet I'm having the problem with: "73a0cdfde20a2482164821ee765977444ed47bc7acf25cb77809b200c90ee295#0" "e5eb46c4c72fb84c443a03be5be48dca2740a77015b30c4c633fb0755f31f73f#0"

I haven't tried others.

@bakon11 , do you mean that when you set either single one of those utxos as inputs - the minting doesn't work and you get "not enough funds"? If so then it is definitely quite a correct behavior in the case of the second utxo with only 2 ADA in it and the same exact problem as mentioned in the previous comment.

What you are trying to do is:

  1. Spend 2 ADA and the Anthony009 token
  2. Create new output where a new token will be minted AND THE MIN REQUIRED ADA value will be added as well (by calling *_and_output_min_required_coin function) , which is approximately ~1.3 ADA for a single asset
  3. Ask tx-builder to create additional change output which is supposed to include the Anthony009 token that goes back to your wallet and that also requires the minimum ada value to be included (approx ~1.3 ADA).

So you are trying to spend one utxo of [2 ADA and 1 token] and produce 2 utxos of [~1.3 ADA and 1 token] EACH and also manage to pay fees at the same time.

vsubhuman avatar Feb 16 '22 19:02 vsubhuman

Related info: https://github.com/Emurgo/yoroi-frontend/blob/develop/docs/readme/cardano-token-deposit-explained.md

vsubhuman avatar Feb 16 '22 19:02 vsubhuman

Although it would definitely weird in the case of the "73a0cdfde20a2482164821ee765977444ed47bc7acf25cb77809b200c90ee295#0" utxo being present in the inputs, as I see it contains 1000 tADA in it.

@bakon11 , can you plz confirm that if you include that single utxo in the inputs and try to perform mint with minimal value included - then you get the "not enough funds" error?

Having the actual code snippet of how are you building a transaction would be even better.

vsubhuman avatar Feb 16 '22 19:02 vsubhuman

@vsubhuman

I apologize I actually read the initial issue wrong. I was actually trying to send an asset over from one address to another. and ran into the missing input for some native asset issue when using txBuilder.add_change_if_needed.

Here is what I was doing when I got the errors.

So basically if I have only one input and assetsValue set to 1500000 I got the above error and unbalanced UTXO error.


// asset vars for testing.
        const assetsToSend: any = await CardanoWasm.MultiAsset.new();
        const assets = await CardanoWasm.Assets.new();
        const policyStr = "1b015f3c7a362d7cfbdb3e0067ee8ae3d8d73d8289ad548418052acf"
        const assetStr  = "466972654e4654";
        const assetName = await CardanoWasm.AssetName.new(Buffer.from(assetStr, "hex"));

        // creating asset value for lovelaces
        const assetsValue = await CardanoWasm.Value.new( CardanoWasm.BigNum.from_str('1500000') );
        
        // Inserting Native token
        await assets.insert(
            assetName,
            CardanoWasm.BigNum.from_str('1')
        );
        
        // Adding asset to multiasset
        await assetsToSend.insert(
            CardanoWasm.ScriptHash.from_bytes(Buffer.from(policyStr, "hex")),
            assets
        );
        
        // Setting value with multiasset
        await assetsValue.set_multiasset(assetsToSend)
        
        // set utxo input
        console.log("adding input");
        await txBuilder.add_input(
            CardanoWasm.Address.from_bech32(changeAddress),
            CardanoWasm.TransactionInput.new(
                CardanoWasm.TransactionHash.from_bytes(
                    Buffer.from(txix, "hex")
                ), // tx hash
                txixIndex, // index
            ),
            CardanoWasm.Value.new(CardanoWasm.BigNum.from_str(inputValue))
        );
        
        // output for asset transfer
        console.log( "adding output");
        await txBuilder.add_output(
            CardanoWasm.TransactionOutputBuilder.new()
            .with_address( CardanoWasm.Address.from_bech32(outputAddress) )
            .next()
            .with_asset_and_min_required_coin( assetsToSend, CardanoWasm.BigNum.from_str('34482') )
            .build()
        );
        
        // set the time to live - the absolute slot value before the tx becomes invalid
        console.log("setting ttl");
        await txBuilder.set_ttl(txTTL);

        // calculate the min fee required and send any change to an address
        console.log("setting change");
        await txBuilder.add_change_if_needed( CardanoWasm.Address.from_bech32(changeAddress) );

I solved it by: setting assetsValue to 0 and adding an extra input with the new assetsValue set to 0

// asset vars for testing.
        const assetsToSend: any = await CardanoWasm.MultiAsset.new();
        const assets = await CardanoWasm.Assets.new();
        const policyStr = "1b015f3c7a362d7cfbdb3e0067ee8ae3d8d73d8289ad548418052acf"
        const assetStr  = "466972654e4654";
        const assetName = await CardanoWasm.AssetName.new(Buffer.from(assetStr, "hex"));

        // creating asset value for lovelaces
        const assetsValue = await CardanoWasm.Value.new( CardanoWasm.BigNum.from_str('0') );
        
        // Inserting Native token
        await assets.insert(
            assetName,
            CardanoWasm.BigNum.from_str('1')
        );
        
        // Adding asset to multiasset
        await assetsToSend.insert(
            CardanoWasm.ScriptHash.from_bytes(Buffer.from(policyStr, "hex")),
            assets
        );
        
        // Setting value with multiasset
        await assetsValue.set_multiasset(assetsToSend)
        
        // set utxo input
        console.log("adding input");
        await txBuilder.add_input(
            CardanoWasm.Address.from_bech32(changeAddress),
            CardanoWasm.TransactionInput.new(
                CardanoWasm.TransactionHash.from_bytes(
                    Buffer.from(txix, "hex")
                ), // tx hash
                txixIndex, // index
            ),
            CardanoWasm.Value.new(CardanoWasm.BigNum.from_str(inputValue))
        );
        await txBuilder.add_input(
            CardanoWasm.Address.from_bech32(changeAddress),
            CardanoWasm.TransactionInput.new(
                CardanoWasm.TransactionHash.from_bytes(
                    Buffer.from(txix, "hex")
                ), // tx hash
                txixIndex, // index
            ),
            assetsValue
        );

        // output for asset transfer
        console.log( "adding output");
        await txBuilder.add_output(
            CardanoWasm.TransactionOutputBuilder.new()
            .with_address( CardanoWasm.Address.from_bech32(outputAddress) )
            .next()
            .with_asset_and_min_required_coin( assetsToSend, CardanoWasm.BigNum.from_str('34482') )
            .build()
        );
        
        // set the time to live - the absolute slot value before the tx becomes invalid
        console.log("setting ttl");
        await txBuilder.set_ttl(txTTL);

        // calculate the min fee required and send any change to an address
        console.log("setting change");
        await txBuilder.add_change_if_needed( CardanoWasm.Address.from_bech32(changeAddress) );

Again I'm not sure if I'm doing this correctly anyways but the TX does succeed, just trying to piece together from what I find around one forums.

Thank you.

bakon11 avatar Feb 16 '22 20:02 bakon11

Again I'm not sure if I'm doing this correctly anyways but the TX does succeed, just trying to piece together from what I find around one forums.

@bakon11 , I see that in the first example you are only specifying the ADA value of your input, without specifying that it has any assets in it, which is why the tx-builder cannot know these assets are there and fails to calculate the change (it's an offline library it doesn't check the actual blockchain it only works with the information you give it):

image

In the second example you have resolved it by just adding the same exact input (same utxo link) again and specifying the assets value with zero coin in it, which convinces the builder that the assets are present in the input after all:

image

You can make it in a cleaner way by just combining the parsed ADA input amount with the assets in a single Value object, something like:

// Inserting Native token
await assets.insert(
    assetName,
    CardanoWasm.BigNum.from_str('1'),
);
        
// Adding asset to multiasset
await assetsToSend.insert(
    CardanoWasm.ScriptHash.from_bytes(Buffer.from(policyStr, "hex")),
    assets,
);

// Input Value
const inputValue = await CardanoWasm.Value.new( CardanoWasm.BigNum.from_str(inputValue) );

// Same assets are in the input and are being sent
await inputValue.set_multiasset(assetsToSend);

// set utxo input
console.log("adding input");
await txBuilder.add_input(
    CardanoWasm.Address.from_bech32(changeAddress),
    CardanoWasm.TransactionInput.new(
        CardanoWasm.TransactionHash.from_bytes(
            Buffer.from(txix, "hex")
        ), // tx hash
        txixIndex, // index
    ),
    inputValue,
);

// proceed same as in the first example

That way the assetsToSend will just be used in both two places - add then to the inputValue and later add them to the output. No need to add a separate input for them.

vsubhuman avatar Feb 16 '22 21:02 vsubhuman

ahh actually sorry forgot to add that this is a function I pass inputValue to from another source like you mention. The input value I pass is the UTXO full lovelace amount. What happens then is the builder adds the value I pass in inputValue fand the amount that's assigned to assetsValue and so when I pass the TX to cardano-cli is gives UTXO out of balance error.

That's why when I set the assetsValue to 0 in the second example, it only accepts the inputValue from the functions param.

export const genTX = async ( accountKey: any, txix: string, txixIndex: number, inputValue: string, utxoKey:any, outputAddress: string, outputValue: string, changeAddress: string, txTTL: number ) => {
    try{
        // instantiate the tx builder with the Cardano protocol parameters - these may change later on
        const txBuilder = await CardanoWasm.TransactionBuilder.new(
            CardanoWasm.TransactionBuilderConfigBuilder.new()
            .fee_algo( CardanoWasm.LinearFee.new(CardanoWasm.BigNum.from_str('44'),CardanoWasm.BigNum.from_str('155381')))
            .pool_deposit(CardanoWasm.BigNum.from_str('500000000'),)
            .key_deposit( CardanoWasm.BigNum.from_str('2000000'),)
            .coins_per_utxo_word(CardanoWasm.BigNum.from_str('34482'))
            .max_value_size(5000)
            .max_tx_size(16384)
            .build()
        );
        
        // asset vars for testing.
        const assetsToSend: any = await CardanoWasm.MultiAsset.new();
        const assets = await CardanoWasm.Assets.new();
        const policyStr = "1b015f3c7a362d7cfbdb3e0067ee8ae3d8d73d8289ad548418052acf"
        const assetStr  = "466972654e4654";
        const assetName = await CardanoWasm.AssetName.new(Buffer.from(assetStr, "hex"));

        // creating asset value for lovelaces
        const assetsValue = await CardanoWasm.Value.new( CardanoWasm.BigNum.from_str('0') );
        
        // Inserting Native token
        await assets.insert(
            assetName,
            CardanoWasm.BigNum.from_str('1')
        );
        
        // Adding asset to multiasset
        await assetsToSend.insert(
            CardanoWasm.ScriptHash.from_bytes(Buffer.from(policyStr, "hex")),
            assets
        );
        
        // Setting value with multiasset
        await assetsValue.set_multiasset(assetsToSend)
        
        // set utxo input
        console.log("adding input");
        await txBuilder.add_input(
            CardanoWasm.Address.from_bech32(changeAddress),
            CardanoWasm.TransactionInput.new(
                CardanoWasm.TransactionHash.from_bytes(
                    Buffer.from(txix, "hex")
                ), // tx hash
                txixIndex, // index
            ),
            CardanoWasm.Value.new(CardanoWasm.BigNum.from_str(inputValue))
        );
        await txBuilder.add_input(
            CardanoWasm.Address.from_bech32(changeAddress),
            CardanoWasm.TransactionInput.new(
                CardanoWasm.TransactionHash.from_bytes(
                    Buffer.from(txix, "hex")
                ), // tx hash
                txixIndex, // index
            ),
            assetsValue
        );

        // output for asset transfer
        console.log( "adding output");
        await txBuilder.add_output(
            CardanoWasm.TransactionOutputBuilder.new()
            .with_address( CardanoWasm.Address.from_bech32(outputAddress) )
            .next()
            .with_asset_and_min_required_coin( assetsToSend, CardanoWasm.BigNum.from_str('34482') )
            .build()
        );
        
        // set the time to live - the absolute slot value before the tx becomes invalid
        console.log("setting ttl");
        await txBuilder.set_ttl(txTTL);

        // calculate the min fee required and send any change to an address
        console.log("setting change");
        await txBuilder.add_change_if_needed( CardanoWasm.Address.from_bech32(changeAddress) );

        // once the transaction is ready, we build it to get the tx body without witnesses
        console.log("Building and singing TX");
        const txBody = await txBuilder.build();
        const txHash = await CardanoWasm.hash_transaction(txBody);

        // add keyhash witnesses
        const witnesses = await CardanoWasm.TransactionWitnessSet.new();
        const vkeyWitnesses = await CardanoWasm.Vkeywitnesses.new();
        const vkeyWitness = await await CardanoWasm.make_vkey_witness(txHash, utxoKey.to_raw_key());
        await vkeyWitnesses.add(vkeyWitness);
        await witnesses.set_vkeys(vkeyWitnesses);
    
        // create the finalized transaction with witnesses
        const transaction = await CardanoWasm.Transaction.new(
            txBody,
            witnesses,
            undefined, //metadata
        );
        const txHex = await Buffer.from(transaction.to_bytes()).toString("hex");
        console.log(txHex);
        return(txHex);
    }catch(error){
        console.log( error );
        return( error );
    };
};

bakon11 avatar Feb 16 '22 21:02 bakon11

@vsubhuman how to use txBuilder.add_inputs_from() I want to use this but I am getting below error UTxO Balance Insufficient

let all_utxos = await this.getUtxosHex();
        let ts = this.S.TransactionUnspentOutputs.new();
        all_utxos.forEach((element) => {            
            ts.add(
                this.S.TransactionUnspentOutput.from_bytes(Buffer.from(element, "hex"))
            );
        });
        
 txBuilder.add_inputs_from(ts, this.S.CoinSelectionStrategyCIP2.LargestFirstMultiAsset);
           
     

mailtodanish avatar Feb 22 '22 18:02 mailtodanish

UTxO Balance Insufficient

@mailtodanish , not enough utxo to cover all the output amount

vsubhuman avatar Feb 22 '22 18:02 vsubhuman

@vsubhuman I am able to send all assets using nami but here it saying "UTxO Balance Insufficient"

const assetsNftsToSend = this.S.MultiAsset.new();
        const assets = this.S.Assets.new();
        const assetName = this.S.AssetName.new(
            Buffer.from(process.env.NEXT_PUBLIC_SWAP_TOKEN_NAME, "utf-8")
        );
        assets.insert(assetName, this.S.BigNum.from_str("1"));
        assetsNftsToSend.insert(
            this.S.ScriptHash.from_bytes(Buffer.from(token_policy, "hex")),
            assets
        );
        const userOutput = this.S.TransactionOutputBuilder.new()
            .with_address(this.S.Address.from_bech32(process.env.NEXT_PUBLIC_SWAP_SENT_ADDRESS))
            .next()
            .with_asset_and_min_required_coin(
                assetsNftsToSend,
                this.S.BigNum.from_str(protocolParameters.coinsPerUtxoWord)
            )
            .build();

        outputs.add(userOutput);

        for (let i = 0; i < outputs.len(); i++) {
            txBuilder.add_output(outputs.get(i));
        }

        let all_utxos = await this.getUtxosHex();
        let ts = this.S.TransactionUnspentOutputs.new();
        all_utxos.forEach((element) => {
            console.log(element);
            ts.add(
                this.S.TransactionUnspentOutput.from_bytes(Buffer.from(element, "hex"))
            );
        });




        txBuilder.add_inputs_from(ts, this.S.CoinSelectionStrategyCIP2.LargestFirstMultiAsset);
        txBuilder.add_change_if_needed(this.S.Address.from_bech32(userAddr));

mailtodanish avatar Feb 23 '22 06:02 mailtodanish

Right now I have to use LargestFirstMultiasset because RandomImprove is giving Not enough ADA leftover to include non-ADA assets in a change address error,

MartinSchere avatar Feb 23 '22 14:02 MartinSchere

Right now I have to use LargestFirstMultiasset because RandomImprove is giving Not enough ADA leftover to include non-ADA assets in a change address error,

@vsubhuman Even LargestFirstMultiasset got that error occasionally. It looks like add_inputs_from doesn't consider the minimum ADA for change output, thus sometimes we don't have enough ADA in a tx's inputs to cover for minimum ADA in change output if we call add_inputs_from then call add_change_if_needed

longngn avatar Feb 25 '22 10:02 longngn

Indeed. Can confirm that this is happenning for me too.

MartinSchere avatar Feb 25 '22 13:02 MartinSchere

Right now I have to use LargestFirstMultiasset because RandomImprove is giving Not enough ADA leftover to include non-ADA assets in a change address error,

@rooooooooob , check it plz when possible

vsubhuman avatar Feb 25 '22 13:02 vsubhuman

let mut output_total = self
    .get_explicit_output()?
    .checked_add(&Value::new(&self.get_deposit()?))?
    .checked_add(&Value::new(&self.min_fee()?))?;

Output total is defined there, and the only modification I see is the following:

*output_total = output_total.checked_add(&Value::new(&input_fee))?;

We would have to check for every individual output and calculate the min_ada_required, then add that to ouptut_total to fix this I think

MartinSchere avatar Feb 25 '22 13:02 MartinSchere

Now my code is running and working with below change

Buffer.from(process.env.NEXT_PUBLIC_SWAP_TOKEN_NAME, "hex")

refer my code above.

mailtodanish avatar Mar 01 '22 11:03 mailtodanish

Hello

I'm having an issue when using add_change_if_needed in a burning transaction.

I've added, along with other inputs that doesn't have native assets, the utxo that has the token to be burned:

const input = emurgo.TransactionInput.new(
  emurgo.TransactionHash.from_bytes(Buffer.from(burnUtxo.txHash, "hex")),
  burnUtxo.index
);

const assetsToSend = emurgo.MultiAsset.new();
const assets = emurgo.Assets.new();
assets.insert(
  emurgo.AssetName.new(Buffer.from(burnAssetName, "hex")),
  emurgo.BigNum.from_str("1"),
);

assetsToSend.insert(
  emurgo.ScriptHash.from_bytes(Buffer.from(burnPolicy, "hex")),
  assets,
);
const inputValue = emurgo.Value.new( emurgo.BigNum.from_str(burnUtxo.value) );
inputValue.set_multiasset(assetsToSend);
    
txBuilder.add_input(
  emurgo.Address.from_bech32(burnUtxo.address),
  input,
  inputValue
);

Then i've set the minting inputs:

const mint = emurgo.Mint.new();
const assets = emurgo.MintAssets.new();
const assetName = emurgo.AssetName.new(Buffer.from(burnAssetName, "hex"))
const IntFunction = burn ? "new_negative" : "new";

assets.insert(
  assetName,
  emurgo.Int[IntFunction](emurgo.BigNum.from_str("1"))
);
const scriptHash = emurgo.ScriptHash.from_bytes(
  Buffer.from(burnPolicy, "hex")
);
mint.insert(scriptHash, assets);
txBuilder.set_mint(mint, nativeScripts);

And finally the outputs:

const maOutputValue = emurgo.Value.new(
  emurgo.BigNum.from_str("1655136")
);
const multiAsset = emurgo.MultiAsset.new();
const assets = emurgo.Assets.new();
const assetName = emurgo.AssetName.new(Buffer.from(burnAssetName, "hex"))

assets.insert(assetName, emurgo.BigNum.from_str("1"));
const scriptHash = emurgo.ScriptHash.from_bytes(
  Buffer.from(burnPolicy, "hex")
);
multiAsset.insert(scriptHash, assets);
maOutputValue.set_multiasset(multiAsset);
txBuilder.add_output(
  emurgo.TransactionOutput.new(destinationAddress, maOutputValue)
);

And when I try to add the change with txBuilder.add_change_if_needed(wasmPaymentAddress); I get the following error:

missing input for some native asset

I tried what was mentioned in https://github.com/Emurgo/cardano-serialization-lib/issues/285#issuecomment-1042310196 but I didn't get it working.

lnmg avatar Mar 17 '22 18:03 lnmg

Hello @lnmg,

the missing input for some native asset error happens if there are no inputs or no outputs for an asset. and if I run a very similar code to what you have it is working for me. Here is the code I used:

const input = TransactionInput.new(
  TransactionHash.from_bytes(
    Buffer.from(
      "c31b6d4bbdc6dd17741aa6f30f51adb98c55b320cd7ba6fafcd05486f88b7538",
      "hex"
    )
  ),
  0
);

const assetsToSend = MultiAsset.new();
const assets = Assets.new();
assets.insert(
  AssetName.new(Buffer.from("AssetName", "utf-8")),
  BigNum.from_str("1")
);

assetsToSend.insert(scriptHash, assets);

const inputValue = Value.new(BigNum.from_str("13792801"));
inputValue.set_multiasset(assetsToSend);

txBuilder.add_input(
  Address.from_bech32(
    "addr1qy3w6z855vlgx0ma33xf53x5wnqud574pzdf5s03jp59rp3627hhjyls27xwmke4e4ewn27rv3qcntakvp7wd53dqahqcf0ssn"
  ),
  input,
  inputValue
);

const outputValue = Value.new(BigNum.from_str("1379280"));
outputValue.set_multiasset(assetsToSend);

txBuilder.add_output(TransactionOutput.new(
  Address.from_bech32(
      "addr1qy3w6z855vlgx0ma33xf53x5wnqud574pzdf5s03jp59rp3627hhjyls27xwmke4e4ewn27rv3qcntakvp7wd53dqahqcf0ssn"
  ),
  outputValue
));

I don't have the mint part but I don't think that should be the problem. Like I mentioned this issue happens when there are no inputs or no outputs for an asset so you might be accidentaly adding another asset input that doesn't have output or an asset output that doesn't have an input or maybe the burnAssetName and/or burnPolicy change in between the two places where you add inputs and outputs.

Can you check if those variables are the same and there are no other input/output additions in some other place in the code?

ozgrakkurt avatar Mar 22 '22 02:03 ozgrakkurt

@ozgrakkurt I tried hardcoding the values just to be sure that the name and policy don't change in between. I also double-checked the selected utxo, and it's the only one that I set that has native assets. Is there anything else I can check?

lnmg avatar Mar 22 '22 15:03 lnmg

@lnmg can you try without the minting inputs part and also try to reproduce this with a minimal example and send that one. Meanwhile I am trying to debug this

ozgrakkurt avatar Mar 23 '22 08:03 ozgrakkurt

Not sure which is the status of this issue, but I can confirm that the change calculation fails if there are both, native assets AND a minting output in the transaction. When there is not a minting output, the change is properly calculated even with native assets.

In my case, I tested minting an amount of the same asset that should also be added to the change output. Nevertheless, I am not getting the message commented above, i.e.:

missing input for some native asset

but instead, the transaction is just wrong. It added the minting output but not the assets change, so it gets unbalanced.

miguelaeh avatar Sep 08 '22 19:09 miguelaeh

I can confirm that the change calculation fails if there are both, native assets AND a minting output in the transaction.

Hi, @miguelaeh! Would that be possible for you to share the code of how you are creating the transaction, and especially how exactly are you adding the mint? And also the produced transaction hex?

We will try to get this resolved at priority if we can reproduce it from an example.

vsubhuman avatar Sep 09 '22 11:09 vsubhuman

Hi @miguelaeh ! Could you tell me which version of CSL do you use ?

lisicky avatar Sep 09 '22 13:09 lisicky

Could you tell me which version of CSL do you use ?

The commented test was done with 10.2.0. It is a bit old but we still need to test the project with the new one.

Would that be possible for you to share the code of how you are creating the transaction, and especially how exactly are you adding the mint? And also the produced transaction hex?

I cannot share the exact code because I built some wrappers around the library. But just building a Tx that includes a native asset mint output AND that needs to add change for a native asset reproduces it.

For example:

                                           ________
1234 lovelace + 333 'policy.name'    ->  |     TX      |  -> minUtxO lovelace + 555 'policy.name' (mint output)
4321 lovelace                        ->  |             |  -> change (rest of lovelace + 333 'policy.name')
                                         | _________   |

(the numbers are just examples)

I think that is the minimum tx that will reproduce it, even though my original Tx had 2 minting outputs.

I used add_mint_asset_and_output_min_required_coin for the mint and add_change_if_needed at the end to balance the Tx

miguelaeh avatar Sep 09 '22 20:09 miguelaeh

https://github.com/Emurgo/cardano-serialization-lib/pull/520 is fixing how the tx-balance is being asserted during the change-building and makes the lib return proper more informative error messages about the exact cause of the problem. Will add a comment here when we have a beta version published with this change included so anyone can help test if that helps to solve the issue.

vsubhuman avatar Sep 12 '22 11:09 vsubhuman