1

I have locked ADA and assets into a script. I want to use the last transaction output and the ADA of a wallet as inputs and I want to have an output with some extra ADA locked and the datum changed

const settings = {
  protocolParams: {
    linearFee: {
      minFeeA: "44",
      minFeeB: "155381",
    },
    minUtxo: "4310",
    poolDeposit: "500000000",
    keyDeposit: "2000000",
    maxValSize: 5000,
    maxTxSize: 16384,
    priceMem: 0.0577,
    priceStep: 0.0000721,
    coinsPerUtxoByte: "4310",
  }
};
    const initTransactionBuilder = () => {
        const { protocolParams } = settings;
        const txBuilder = TransactionBuilder.new(
        TransactionBuilderConfigBuilder.new()
        .fee_algo(LinearFee.new(BigNum.from_str(protocolParams.linearFee.minFeeA), BigNum.from_str(protocolParams.linearFee.minFeeB)))
        .pool_deposit(BigNum.from_str(protocolParams.poolDeposit))
        .key_deposit(BigNum.from_str(protocolParams.keyDeposit))
        .coins_per_utxo_byte(BigNum.from_str(protocolParams.coinsPerUtxoByte))
        .max_value_size(protocolParams.maxValSize)
        .max_tx_size(protocolParams.maxTxSize)
        .prefer_pure_change(true)
        .build()
        );
        return txBuilder
    };
    const buildRedeemAdaFromPlutusScript = async (walletApi,
        { transactionIdLocked, transactionIndxLocked, lovelaceLocked, manualFee, CollatUtxos, newDatumStr, datumStr }) => {
        const txBuilder = initTransactionBuilder();
        const ScriptAddress = Address.from_bech32(settings.smartContract.addressScriptBech32);
        const shelleyChangeAddress = Address.from_bech32(await walletApi.getChangeAddress());

        let multiAsset = MultiAsset.new();
        let assets = Assets.new()
        assets.insert(
        AssetName.new(Buffer.from(assetNameHex, "hex")),
        BigNum.from_str(assetAmountToSend.toString()) 
        );
        multiAsset.insert(
        ScriptHash.from_bytes(Buffer.from(assetPolicyIdHex, "hex")), 
        assets
        );

        const outputVal = 2 * lovelaceLocked - Number(manualFee);
        const outputValStr = outputVal.toString();

        let txOutputScriptBuilder = TransactionOutputBuilder.new();
        txOutputScriptBuilder = txOutputScriptBuilder.with_address(ScriptAddress);
        const dataHash = hash_plutus_data(PlutusData.new_integer(BigInt.from_str(newDatumStr)));
        txOutputScriptBuilder = txOutputScriptBuilder.with_data_hash(dataHash)
        txOutputScriptBuilder = txOutputScriptBuilder.next();
        txOutputScriptBuilder = txOutputScriptBuilder.with_coin_and_asset(BigNum.from_str(outputValStr), multiAsset)
        const txOutputScript = txOutputScriptBuilder.build();
        txBuilder.add_output(txOutputScript)
    
        txBuilder.add_input(
        ScriptAddress,
        TransactionInput.new(
            TransactionHash.from_bytes(Buffer.from(transactionIdLocked, "hex")),
            transactionIndxLocked.toString()),
            Value.new_with_assets(BigNum.from_str(lovelaceLocked.toString()), multiAsset)
        );

        const { txOutputs: txUnspentOutputs } = await walletApi.getUtxos();
        txBuilder.add_inputs_from(txUnspentOutputs, 2)
        txBuilder.add_change_if_needed(shelleyChangeAddress)
    
        
        txBuilder.set_fee(BigNum.from_str(Number(manualFee).toString()));
        const txBody = txBuilder.build();

        const scripts = PlutusScripts.new();
        scripts.add(PlutusScript.from_bytes(Buffer.from(settings.smartContract.plutusScriptCborHex, "hex")));

        const collateral = CollatUtxos;
        const inputs = TransactionInputs.new();
        collateral.forEach((utxo) => {
            inputs.add(utxo.input());
        });

        const datum = PlutusData.new_integer(BigInt.from_str(datumStr));

        const redeemers = Redeemers.new();
        const redeemer = Redeemer.new(
        RedeemerTag.new_spend(),
        BigNum.from_str("0"),
        datum,
        ExUnits.new(
            BigNum.from_str("7000000"),
            BigNum.from_str("3000000000")
        )
        );
        redeemers.add(redeemer);
        const datums = PlutusList.new();
        datums.add(datum);

        const transactionWitnessSet = TransactionWitnessSet.new();
        transactionWitnessSet.set_plutus_scripts(scripts);
        transactionWitnessSet.set_plutus_data(datums);
        transactionWitnessSet.set_redeemers(redeemers);
        const cost_model_vals = [
        205665, 812, 1, 1, 1000, 571, 0, 1, 1000, 24177, 4, 1, 1000, 32, 117366,
        10475, 4, 23000, 100, 23000, 100, 23000, 100, 23000, 100, 23000, 100, 23000,
        100, 100, 100, 23000, 100, 19537, 32, 175354, 32, 46417, 4, 221973, 511, 0, 1,
        89141, 32, 497525, 14068, 4, 2, 196500, 453240, 220, 0, 1, 1, 1000, 28662, 4,
        2, 245000, 216773, 62, 1, 1060367, 12586, 1, 208512, 421, 1, 187000, 1000,
        52998, 1, 80436, 32, 43249, 32, 1000, 32, 80556, 1, 57667, 4, 1000, 10,
        197145, 156, 1, 197145, 156, 1, 204924, 473, 1, 208896, 511, 1, 52467, 32,
        64832, 32, 65493, 32, 22558, 32, 16563, 32, 76511, 32, 196500, 453240, 220, 0,
        1, 1, 69522, 11687, 0, 1, 60091, 32, 196500, 453240, 220, 0, 1, 1, 196500,
        453240, 220, 0, 1, 1, 806990, 30482, 4, 1927926, 82523, 4, 265318, 0, 4, 0,
        85931, 32, 205665, 812, 1, 1, 41182, 32, 212342, 32, 31220, 32, 32696, 32,
        43357, 32, 32247, 32, 38314, 32, 9462713, 1021, 10,
        ];
        const costModel = CostModel.new();
        cost_model_vals.forEach((x, i) => costModel.set(i, Int.new_i32(x)));
        const costModels = Costmdls.new();
        costModels.insert(Language.new_plutus_v1(), costModel);
        const scriptDataHash = hash_script_data(redeemers, costModels, datums);
        txBody.set_script_data_hash(scriptDataHash);
        txBody.set_collateral(inputs);
        const baseAddress = BaseAddress.from_address(shelleyChangeAddress);
        const requiredSigners = Ed25519KeyHashes.new();
        requiredSigners.add(baseAddress.payment_cred().to_keyhash());
        txBody.set_required_signers(requiredSigners);
        const tx = Transaction.new(
        txBody,
        TransactionWitnessSet.from_bytes(transactionWitnessSet.to_bytes())
        );
        let txVkeyWitnesses = await walletApi.api.signTx(Buffer.from(tx.to_bytes(), "utf8").toString("hex"), true);
        txVkeyWitnesses = TransactionWitnessSet.from_bytes(Buffer.from(txVkeyWitnesses, "hex"));
        transactionWitnessSet.set_vkeys(txVkeyWitnesses.vkeys());
        const signedTx = Transaction.new(
        tx.body(),
        transactionWitnessSet
        );
        const submittedTxHash = await walletApi.api.submitTx(Buffer.from(signedTx.to_bytes(), "utf8").toString("hex"));
        return { submittedTxHash };
    };

Error:

""transaction submit error ShelleyTxValidationError ShelleyBasedEraBabbage (ApplyTxError [UtxowFailure (UtxoFailure (FromAlonzoUtxoFail (ValueNotConservedUTxO (Value 2258970370 (fromList [(PolicyID {policyID = ScriptHash \"9560a89a549f66bb02c4a04525e8e367283f566ec0e34e1a31cf3aa2\"},fromList [(4a616c61436f696e,999962)])])) (Value 2259870370 (fromList [(PolicyID {policyID = ScriptHash \"9560a89a549f66bb02c4a04525e8e367283f566ec0e34e1a31cf3aa2\"},fromList [(4a616c61436f696e,999962)])])))))])""
1
  • 1
    From the error message it looks like your input value is not equal your output value minus fees, so I suggest checking the Tx inputs.
    – Will
    Aug 3, 2022 at 7:06

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.