1

I am consuming a script output and also create a new one at the same script address. The validator script requires the output producer to provide the datum value due to making assertions on it. Therefore, I would like to know how can I provide a datum value for creating an output using the cardano serialization lib and not just the datum hash!

The only thing I saw was something called TransactionBuilder.set_auxiliary_data() but I am not sure whether that fits what I need.

Thanks for any advice in the right direction.

Currently I am doing something like this which obviously only provides the datum hash - not the value.

txBuilder.add_output(
    TransactionOutputBuilder.new()
        .with_address(scriptAddress)
        .with_data_hash(hash_plutus_data(myDatum))
        .next()
        .with_value(Value.new(amount))
        .build()
);

2 Answers 2

1

Thanks to Sebastien, there is an open issue for this. Github Feature Request

Besides, one can attach the datum separately to the tx witness set, like so for example:

const datums = PlutusList.new();
datums.add(datumOfCurrentOutputToBeConsumed);
datums.add(datumOfNewOutputToBeCreated);

const transactionWitnessSet = TransactionWitnessSet.new();
transactionWitnessSet.set_plutus_data(datums);
0

I have the same issue and I write a comment in the cardano-serialization-lib repo. I hope it helps:

Reference: https://github.com/Emurgo/cardano-serialization-lib/issues/443#issuecomment-1195619916

There are two problems; first, the extra data isn't taken into account in the fee calculation and the second one is that you can't calculate automatically the script data hash with the tx builder if you are not calling a script redeemer.

For the fee calculation, I create a dummy WitnessSet and put the datums inside. When the witness set is ready, I use it to calculate the final length and I add this "extra fee" to the transaction builder configuration.

const plutusList = CSL.PlutusList.new()
selection.outputs.forEach(output => {
    if (output.plutusData) {
        plutusList.add(output.plutusData)
    }
})

const witness = CSL.TransactionWitnessSet.new()
witness.set_vkeys(CSL.Vkeywitnesses.new())
witness.set_plutus_data(plutusList)

const txBuilder = CSL.TransactionBuilder.new(CSL.TransactionBuilderConfigBuilder.new()
    .coins_per_utxo_word(CSL.BigNum.from_str(protocolParameters.coinsPerUtxoWord.toString()))
    .fee_algo(CSL.LinearFee.new(CSL.BigNum.from_str(protocolParameters.minFeeCoefficient.toString()),
        CSL.BigNum.from_str((protocolParameters.minFeeConstant + protocolParameters.minFeeCoefficient * witness.to_bytes().length).toString())))
    .key_deposit(CSL.BigNum.from_str(protocolParameters.stakeKeyDeposit.toString()))
    .max_tx_size(protocolParameters.maxTxSize)
    .max_value_size(protocolParameters.maxValueSize)
    .pool_deposit(CSL.BigNum.from_str(protocolParameters.poolDeposit.toString()))
    .build())

In the fee_algo method, I multiply wintess.to_bytes().length by minFeeCoefficient to add the extra fee necessary. The good part of this solution is that you can continue using the transaction builder as before.

The final step is to add the script data hash at the end just before calling buildTx(). The challenge is that you can't use the method calc_script_data_hash, so you have to calculate and set it. In my case, I use this lines:

if (plutusList.len() > 0 ) {
    const scriptDataHash = CSL.hash_script_data(CSL.Redeemers.new(), CSL.TxBuilderConstants.plutus_vasil_cost_models(), plutusList)
    txBuilder.set_script_data_hash(scriptDataHash)
}

txBuilder.add_change_if_needed(CSL.Address.from_bech32(address))

Remember to set the script data hash before calling add_change_if_needed, otherwise the hash will not be included in the fee.

Not the answer you're looking for? Browse other questions tagged or ask your own question.