I am trying to implement the Unlocking of NFT from an "always true" smart contract. I am using the Cardano serialization library for this. I can lock the NFT successfully, but when i unlock the NFT then i get the issue of Fee imbalancing issue i think. Maybe i am missing something and stuck on this.
I am facing this error
""transaction submit error ShelleyTxValidationError ShelleyBasedEraBabbage (ApplyTxError [UtxowFailure (UtxoFailure (FromAlonzoUtxoFail (ValueNotConservedUTxO (Value 1297310 (fromList [(PolicyID {policyID = ScriptHash \"80786e0ffb709cf2da414f0496be530a129c23f18c7a493abbf8589c\"},fromList [(61727445796573,1)])])) (Value 2050770 (fromList [(PolicyID {policyID = ScriptHash \"80786e0ffb709cf2da414f0496be530a129c23f18c7a493abbf8589c\"},fromList [(61727445796573,1)])])))))])""
Given below is my code for unlocking NFT.
assetName = undefined,
assetPolicyId = undefined,
storeWalletSelected = undefined,
transactionHashLocked = undefined
) {
const txBuilder = await this.initTransactionBuilder();
const ScriptAddress = this.sLib.Address.from_bech32(this.addressScriptBech32);
const walletAddress = await this.getAddress()
const shelleyChangeAddress = this.sLib.Address.from_bech32(walletAddress)
const protocolParams = this.getProtocolParameters();
let multiAsset = this.sLib.MultiAsset.new();
let assets = this.sLib.Assets.new()
assets.insert(
this.sLib.AssetName.new(Buffer.from(assetName, "hex")), // Asset Name
this.sLib.BigNum.from_str(this.assetAmountToSend.toString()) // How much to send
);
multiAsset.insert(
this.sLib.ScriptHash.from_bytes(Buffer.from(assetPolicyId, "hex")), // PolicyID
assets
);
txBuilder.add_input(
ScriptAddress,
this.sLib.TransactionInput.new(
this.sLib.TransactionHash.from_bytes(Buffer.from(transactionHashLocked, "hex")),
this.transactionIndxLocked.toString()),
this.sLib.Value.new_from_assets(multiAsset)
) // how much lovelace is at that UTXO
txBuilder.set_fee(this.sLib.BigNum.from_str(Number(this.manualFee).toString()))
const scripts = this.sLib.PlutusScripts.new();
scripts.add(this.sLib.PlutusScript.from_bytes(Buffer.from(this.plutusScriptCborHex, "hex"))); //from cbor of plutus script
// Add outputs
const outputValStr = Number(this.manualFee).toString();
let txOutputBuilder = this.sLib.TransactionOutputBuilder.new();
txOutputBuilder = txOutputBuilder.with_address(shelleyChangeAddress);
txOutputBuilder = txOutputBuilder.next();
txOutputBuilder = txOutputBuilder.with_asset_and_min_required_coin(
multiAsset,
this.sLib.BigNum.from_str(protocolParams.coinsPerUtxoWord)
)
const txOutput = txOutputBuilder.build();
txBuilder.add_output(txOutput)
// once the transaction is ready, we build it to get the tx body without witnesses
const txBody = txBuilder.build();
const collateral = await this.getCollateral(storeWalletSelected);
const inputs = this.sLib.TransactionInputs.new();
collateral.forEach((utxo) => inputs.add(utxo.input()) );
let datums = this.sLib.PlutusList.new();
// datums.add(PlutusData.from_bytes(Buffer.from(this.state.datumStr, "utf8")))
datums.add(this.sLib.PlutusData.new_integer(
this.sLib.BigInt.from_str(this.datumStr)))
const redeemers = this.sLib.Redeemers.new();
const data = this.sLib.PlutusData.new_constr_plutus_data(
this.sLib.ConstrPlutusData.new(
this.sLib.BigNum.from_str("0"),
this.sLib.PlutusList.new()
)
);
const redeemer = this.sLib.Redeemer.new(
this.sLib.RedeemerTag.new_spend(),
this.sLib.BigNum.from_str("0"),
data,
this.sLib.ExUnits.new(
this.sLib.BigNum.from_str("7000000"),
this.sLib.BigNum.from_str("3000000000")
)
);
redeemers.add(redeemer)
//Tx witness
const transactionWitnessSet = this.sLib.TransactionWitnessSet.new();
transactionWitnessSet.set_plutus_scripts(scripts)
transactionWitnessSet.set_plutus_data(datums)
transactionWitnessSet.set_redeemers(redeemers)
const costModel = this.sLib.TxBuilderConstants.plutus_vasil_cost_models().get(this.sLib.Language.new_plutus_v1())
const costModels = this.sLib.Costmdls.new();
costModels.insert(this.sLib.Language.new_plutus_v1(), costModel);
const scriptDataHash = this.sLib.hash_script_data(redeemers, costModels, datums);
txBody.set_script_data_hash(scriptDataHash);
txBody.set_collateral(inputs)
const baseAddress = this.sLib.BaseAddress.from_address(shelleyChangeAddress)
const requiredSigners = this.sLib.Ed25519KeyHashes.new();
requiredSigners.add(baseAddress.payment_cred().to_keyhash())
txBody.set_required_signers(requiredSigners);
const tx = this.sLib.Transaction.new(
txBody,
this.sLib.TransactionWitnessSet.from_bytes(transactionWitnessSet.to_bytes())
)
let txVkeyWitnesses = await this.wallet.signTx(Buffer.from(tx.to_bytes(), "utf8").toString("hex"), true);
txVkeyWitnesses = this.sLib.TransactionWitnessSet.from_bytes(Buffer.from(txVkeyWitnesses, "hex"));
transactionWitnessSet.set_vkeys(txVkeyWitnesses.vkeys());
const signedTx = this.sLib.Transaction.new(tx.body(), transactionWitnessSet);
const submittedTxHash = await this.wallet.submitTx(Buffer.from(signedTx.to_bytes(), "utf8").toString("hex"));
console.log('Tx Hash NFT Reedemed: ', submittedTxHash);
return submittedTxHash
}
The protocol Parameters used in this are
getProtocolParameters () {
return {
linearFee: {
minFeeA: "44",
minFeeB: "155381",
},
minUtxo: "34482",
poolDeposit: "500000000",
keyDeposit: "2000000",
maxValSize: 5000,
maxTxSize: 16384,
priceMem: 0.0577,
priceStep: 0.0000721,
coinsPerUtxoWord: "34482",
}
}
The manual fee variable is
this.manualFee = 900000
Kindly suggest me some solution if you find any.