UNPKG

@harmoniclabs/plu-ts-offchain

Version:

An embedded DSL for Cardano smart contracts creation coupled with a library for Cardano transactions, all in Typescript

892 lines (891 loc) 66.2 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; var __values = (this && this.__values) || function(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); }; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.splitStringByByteLength = exports.getScriptDataHash = exports.TxBuilder = void 0; var uint8array_utils_1 = require("@harmoniclabs/uint8array-utils"); var keepRelevant_1 = require("./keepRelevant.js"); var GenesisInfos_1 = require("./GenesisInfos.js"); var cardano_costmodels_ts_1 = require("@harmoniclabs/cardano-costmodels-ts"); var cardano_ledger_ts_1 = require("@harmoniclabs/cardano-ledger-ts"); var cbor_1 = require("@harmoniclabs/cbor"); var crypto_1 = require("@harmoniclabs/crypto"); var plutus_data_1 = require("@harmoniclabs/plutus-data"); var plutus_machine_1 = require("@harmoniclabs/plutus-machine"); var uplc_1 = require("@harmoniclabs/uplc"); var toOnChain_1 = require("../toOnChain/index.js"); var txBuild_1 = require("../txBuild/index.js"); var ints_1 = require("../utils/ints.js"); var obj_utils_1 = require("@harmoniclabs/obj-utils"); var TxBuilderRunner_1 = require("./TxBuilderRunner/TxBuilderRunner.js"); var CanBeData_1 = require("../utils/CanBeData.js"); var getSpendingPurposeData_1 = require("../toOnChain/getSpendingPurposeData.js"); var TxBuilderProtocolParams_1 = require("./TxBuilderProtocolParams.js"); var utils_1 = require("./utils.js"); var Rational_1 = require("../utils/Rational.js"); var stringify_1 = require("../utils/stringify.js"); // const scriptCache: { [x: string]: UPLCTerm } = {}; function getScriptLikeUplc(scriptLike) { return uplc_1.UPLCDecoder.parse(scriptLike.bytes, "flat").body; } var TxBuilder = /** @class */ (function () { function TxBuilder(protocolParamters, genesisInfos) { var _genesisInfos = undefined; var _setGenesisInfos = function (genInfos) { if (!(0, GenesisInfos_1.isGenesisInfos)(genInfos)) return; _genesisInfos = (0, obj_utils_1.freezeAll)((0, GenesisInfos_1.normalizedGenesisInfos)(genInfos)); }; _setGenesisInfos(genesisInfos); Object.defineProperties(this, { genesisInfos: { get: function () { return _genesisInfos; }, set: _setGenesisInfos, enumerable: true, configurable: false }, setGenesisInfos: { value: _setGenesisInfos, writable: false, enumerable: true, configurable: false } }); var pp = (0, TxBuilderProtocolParams_1.completeTxBuilderProtocolParams)(protocolParamters); (0, obj_utils_1.defineReadOnlyProperty)(this, "protocolParamters", (0, obj_utils_1.freezeAll)(protocolParamters)); var costmdls = pp.costModels; var costs = (0, cardano_costmodels_ts_1.isCostModelsV3)(costmdls.PlutusScriptV3) ? costmdls.PlutusScriptV3 : (0, cardano_costmodels_ts_1.isCostModelsV2)(costmdls.PlutusScriptV2) ? costmdls.PlutusScriptV2 : (0, cardano_costmodels_ts_1.isCostModelsV1)(costmdls.PlutusScriptV1) ? costmdls.PlutusScriptV1 : cardano_costmodels_ts_1.defaultV3Costs; (0, obj_utils_1.definePropertyIfNotPresent)(this, "cek", { // define as getter so that it can be reused without messing around things get: function () { return new plutus_machine_1.Machine(__assign({}, costs)); }, // set does nothing ( aka. readonly ) set: function () { }, enumerable: false, configurable: false }); } TxBuilder.prototype.runWithProvider = function (provider) { return new TxBuilderRunner_1.TxBuilderRunner(this, provider); }; TxBuilder.prototype.keepRelevant = function (requestedOutputSet, initialUTxOSet, minimumLovelaceRequired) { if (minimumLovelaceRequired === void 0) { minimumLovelaceRequired = 5000000; } return (0, keepRelevant_1.keepRelevant)(requestedOutputSet, initialUTxOSet, minimumLovelaceRequired); }; TxBuilder.prototype.calcLinearFee = function (tx) { return ((0, ints_1.forceBigUInt)(this.protocolParamters.txFeePerByte) * BigInt((tx instanceof cardano_ledger_ts_1.Tx ? tx.toCbor() : tx).toBuffer().length) + (0, ints_1.forceBigUInt)(this.protocolParamters.txFeeFixed)); }; TxBuilder.prototype.calcMinFee = function (tx) { var _a; var totRefScriptBytes = ((_a = tx.body.refInputs) !== null && _a !== void 0 ? _a : []) .reduce(function (sum, refIn) { if (refIn.resolved.refScript) return sum + BigInt(refIn.resolved.refScript.toCbor().toBuffer().length + 10 // second Cbor wrap ); return sum; }, BigInt(0)); var minRefScriptFee = this.protocolParamters.minfeeRefScriptCostPerByte ? (totRefScriptBytes * this.protocolParamters.minfeeRefScriptCostPerByte.num / this.protocolParamters.minfeeRefScriptCostPerByte.den) : (totRefScriptBytes * (0, Rational_1.cborFromRational)(cardano_ledger_ts_1.defaultProtocolParameters.minfeeRefScriptCostPerByte).num / (0, Rational_1.cborFromRational)(cardano_ledger_ts_1.defaultProtocolParameters.minfeeRefScriptCostPerByte).den); var minFeeMultiplier = (0, ints_1.forceBigUInt)(this.protocolParamters.txFeePerByte); var nVkeyWits = BigInt((0, utils_1.estimateMaxSignersNeeded)(tx)); var minFee = this.calcLinearFee(tx) + minRefScriptFee + // consider also vkeys witnesses to be added // each vkey witness has fixed size of 102 cbor bytes // (1 bytes cbor array tag (length 2)) + (34 cbor bytes of length 32) + (67 cbor bytes of length 64) // for a fixed length of 102 BigInt(102) * nVkeyWits * minFeeMultiplier + // we add some more bytes for the array tag BigInt(nVkeyWits < 24 ? 1 : (nVkeyWits < 256 ? 2 : 3)) * minFeeMultiplier; return minFee; }; TxBuilder.prototype.getMinimumOutputLovelaces = function (tx_out) { var size = BigInt(0); if (tx_out instanceof cardano_ledger_ts_1.TxOut) tx_out = tx_out.toCbor().toBuffer(); if (typeof tx_out === "string") size = BigInt(Math.ceil(tx_out.length / 2)); else if (!(tx_out instanceof Uint8Array)) { if ((0, obj_utils_1.isObject)(tx_out) && (0, obj_utils_1.hasOwn)(tx_out, "toBuffer") && typeof tx_out.toBuffer === "function") tx_out = tx_out.toBuffer(); if (!(tx_out instanceof Uint8Array)) tx_out = (0, uint8array_utils_1.fromHex)(tx_out.toString()); } if (tx_out instanceof Uint8Array) size = BigInt(tx_out.length); return BigInt(this.protocolParamters.utxoCostPerByte) * size; }; TxBuilder.prototype.minimizeLovelaces = function (out) { var o = out instanceof cardano_ledger_ts_1.TxOut ? out : (0, txBuild_1.txBuildOutToTxOut)(out); var minLovelaces = this.getMinimumOutputLovelaces(o); return new cardano_ledger_ts_1.TxOut({ address: o.address, value: cardano_ledger_ts_1.Value.add(cardano_ledger_ts_1.Value.sub(o.value, cardano_ledger_ts_1.Value.lovelaces(o.value.lovelaces)), cardano_ledger_ts_1.Value.lovelaces(minLovelaces)), datum: o.datum, refScript: o.refScript }); }; /** * * @param slotN number of the slot * @returns POSIX time in **milliseconds** */ TxBuilder.prototype.slotToPOSIX = function (slot, genesisInfos) { var gInfos = genesisInfos ? (0, GenesisInfos_1.normalizedGenesisInfos)(genesisInfos) : this.genesisInfos; if (gInfos === undefined) { throw new Error("can't convert slot to POSIX time because genesis infos are missing"); } return (0, toOnChain_1.slotToPOSIX)((0, ints_1.unsafeForceUInt)(slot), gInfos); }; /** * * @param POSIX POSIX time in milliseconds */ TxBuilder.prototype.posixToSlot = function (POSIX, genesisInfos) { var gInfos = genesisInfos ? (0, GenesisInfos_1.normalizedGenesisInfos)(genesisInfos) : this.genesisInfos; if (gInfos === undefined) { throw new Error("can't convert POSIX to slot time because genesis infos are missing"); } return (0, toOnChain_1.POSIXToSlot)((0, ints_1.unsafeForceUInt)(POSIX), gInfos); }; /** * here mainly for forward compability * * internally calls `buildSync` so really what `build` is doing is wrapping it in a `Promise` * * In future this method might implement multi-threading using `Worker`s */ TxBuilder.prototype.build = function (buildArgs, buildOpts) { if (buildOpts === void 0) { buildOpts = {}; } return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/, this.buildSync(buildArgs, buildOpts)]; }); }); }; /** * replaces the redeemers and clears vkeyWitnesses in the witness set * and re-computes the `scriptDataHash` in the body * * the input transaction is readonly and is not modified * * **A NEW TRANSACTION IS CREATED** with vkey witness set empty * (the new transaction is unsigned) * * to summarize, the new transaction differs in: * 1) `tx.body.scriptDataHash` * 2) `tx.witnesses.redeemers` * 3) `tx.witnesses.vkeyWitnesses` (empty) */ TxBuilder.prototype.overrideTxRedeemers = function (tx, newRedeemers, opts) { var _a; if (opts === void 0) { opts = { mustHaveV3: true }; } // datums passed by hash var datums = (_a = tx.witnesses.datums) !== null && _a !== void 0 ? _a : []; return new cardano_ledger_ts_1.Tx(__assign(__assign({}, tx), { body: new cardano_ledger_ts_1.TxBody(__assign(__assign({}, tx.body), { scriptDataHash: getScriptDataHash(tx.witnesses, (0, cardano_costmodels_ts_1.costModelsToLanguageViewCbor)(this.protocolParamters.costModels, opts).toBuffer()) })), witnesses: new cardano_ledger_ts_1.TxWitnessSet(__assign(__assign({}, tx.witnesses), { vkeyWitnesses: [], redeemers: newRedeemers })) })); }; TxBuilder.prototype.buildSync = function (buildArgs, _a) { var _b; var _c = _a === void 0 ? {} : _a, onScriptInvalid = _c.onScriptInvalid, onScriptResult = _c.onScriptResult; var _initBuild = this.initTxBuild(buildArgs); var // tx, scriptsToExec = _initBuild.scriptsToExec, datumsScriptData = _initBuild.datumsScriptData, languageViews = _initBuild.languageViews, totInputValue = _initBuild.totInputValue, requiredOutputValue = _initBuild.requiredOutputValue, outs = _initBuild.outs, change = _initBuild.change; var tx = _initBuild.tx; var minFee = _initBuild.minFee; var rdmrs = (_b = tx.witnesses.redeemers) !== null && _b !== void 0 ? _b : []; var nRdmrs = rdmrs.length; if (nRdmrs === 0) { this.assertMinOutLovelaces(tx.body.outputs); return tx; } ; var txOuts = new Array(outs.length + 1); var cek = this.cek; if (!(cek instanceof plutus_machine_1.Machine)) throw new Error("unable to construct transaction including scripts " + "if the protocol params are missing the script evaluation costs"); var executionUnitPrices = this.protocolParamters.executionUnitPrices; executionUnitPrices = Array.isArray(executionUnitPrices) ? executionUnitPrices : [ executionUnitPrices.priceMemory, executionUnitPrices.priceSteps, ]; var _d = __read(executionUnitPrices, 2), memRational = _d[0], cpuRational = _d[1]; memRational = typeof memRational === "number" ? cbor_1.CborPositiveRational.fromNumber(memRational) : memRational; cpuRational = typeof cpuRational === "number" ? cbor_1.CborPositiveRational.fromNumber(cpuRational) : cpuRational; // group by purpose so we can use the redeemer index to find the script var spendScriptsToExec = scriptsToExec.filter(function (elem) { return elem.rdmrTag === cardano_ledger_ts_1.TxRedeemerTag.Spend; }); var mintScriptsToExec = scriptsToExec.filter(function (elem) { return elem.rdmrTag === cardano_ledger_ts_1.TxRedeemerTag.Mint; }); var certScriptsToExec = scriptsToExec.filter(function (elem) { return elem.rdmrTag === cardano_ledger_ts_1.TxRedeemerTag.Cert; }); var withdrawScriptsToExec = scriptsToExec.filter(function (elem) { return elem.rdmrTag === cardano_ledger_ts_1.TxRedeemerTag.Withdraw; }); var voteScriptsToExec = scriptsToExec.filter(function (elem) { return elem.rdmrTag === cardano_ledger_ts_1.TxRedeemerTag.Voting; }); var proposeScriptsToExec = scriptsToExec.filter(function (elem) { return elem.rdmrTag === cardano_ledger_ts_1.TxRedeemerTag.Proposing; }); var maxRound = 3; var _isScriptValid = true; var fee = minFee; var prevFee; var _loop_1 = function (round) { prevFee = fee; var _e = (0, toOnChain_1.getTxInfos)(tx, this_1.genesisInfos), txInfosV1 = _e.v1, txInfosV2 = _e.v2, txInfosV3 = _e.v3; var totExBudget = new plutus_machine_1.ExBudget({ mem: 0, cpu: 0 }); var _loop_2 = function (i) { var rdmr = rdmrs[i]; var tag = rdmr.tag, rdmrData = rdmr.data, rdmr_idx = rdmr.index; // "+ 1" because we keep track of lovelaces even if in mint values these are 0 var index = rdmr_idx + (tag === cardano_ledger_ts_1.TxRedeemerTag.Mint ? 1 : 0); // const spendingPurpose = getSpendingPurposeData( rdmr, tx.body ); var onlyRedeemerArg = function (purposeScriptsToExec) { var _a; var script = (_a = purposeScriptsToExec.find(function (_a) { var idx = _a.index; return idx === index; })) === null || _a === void 0 ? void 0 : _a.script; if (script === undefined) throw new Error("missing script for " + (0, cardano_ledger_ts_1.txRedeemerTagToString)(tag) + " redeemer " + (index - 1)); var expectedVersion = (0, utils_1.scriptTypeToDataVersion)(script.type); if (typeof expectedVersion !== "string") throw new Error("unexpected redeemer for native script"); var ctxData = getCtx(script.type, (0, getSpendingPurposeData_1.getSpendingPurposeData)(rdmr, tx.body, expectedVersion), (0, getSpendingPurposeData_1.getScriptInfoData)(rdmr, tx.body, expectedVersion), rdmrData, txInfosV1, txInfosV2, txInfosV3); var isV2OrLess = (script.type === cardano_ledger_ts_1.ScriptType.PlutusV1 || script.type === cardano_ledger_ts_1.ScriptType.PlutusV2 || script.type === cardano_ledger_ts_1.ScriptType.NativeScript); var _b = cek.eval(isV2OrLess ? new uplc_1.Application(new uplc_1.Application(getScriptLikeUplc(script), uplc_1.UPLCConst.data(rdmrData)), uplc_1.UPLCConst.data(ctxData)) : new uplc_1.Application(getScriptLikeUplc(script), uplc_1.UPLCConst.data(ctxData))), result = _b.result, budgetSpent = _b.budgetSpent, logs = _b.logs; _isScriptValid = onEvaluationResult(i, totExBudget, rdmr, result, budgetSpent, logs, isV2OrLess ? [ rdmrData, ctxData ] : [ctxData], rdmrs, onScriptResult, onScriptInvalid); }; if (tag === cardano_ledger_ts_1.TxRedeemerTag.Spend) { var entry = spendScriptsToExec.find(function (_a) { var idx = _a.index; return idx === index; }); if (entry === undefined) throw new Error("missing script for spend redeemer " + index); var script = entry.script, datum = entry.datum; var isV2OrLess = script.type === cardano_ledger_ts_1.ScriptType.PlutusV1 || script.type === cardano_ledger_ts_1.ScriptType.PlutusV2; if (datum === undefined && isV2OrLess) throw new Error("missing datum for spend redeemer " + index); var expectedVersion = (0, utils_1.scriptTypeToDataVersion)(script.type); if (typeof expectedVersion !== "string") throw new Error("unexpected redeemer for native script"); var ctxData = getCtx(script.type, (0, getSpendingPurposeData_1.getSpendingPurposeData)(rdmr, tx.body, expectedVersion), (0, getSpendingPurposeData_1.getScriptInfoData)(rdmr, tx.body, expectedVersion, datum), rdmrData, txInfosV1, txInfosV2, txInfosV3); var _f = cek.eval(isV2OrLess ? new uplc_1.Application(new uplc_1.Application(new uplc_1.Application(getScriptLikeUplc(script), uplc_1.UPLCConst.data(datum)), uplc_1.UPLCConst.data(rdmrData)), uplc_1.UPLCConst.data(ctxData)) : new uplc_1.Application(getScriptLikeUplc(script), uplc_1.UPLCConst.data(ctxData))), result = _f.result, budgetSpent = _f.budgetSpent, logs = _f.logs; _isScriptValid = onEvaluationResult(i, totExBudget, rdmr, result, budgetSpent, logs, isV2OrLess ? [ datum, rdmrData, ctxData ] : [ctxData], rdmrs, onScriptResult, onScriptInvalid); } else if (tag === cardano_ledger_ts_1.TxRedeemerTag.Mint) onlyRedeemerArg(mintScriptsToExec); else if (tag === cardano_ledger_ts_1.TxRedeemerTag.Cert) onlyRedeemerArg(certScriptsToExec); else if (tag === cardano_ledger_ts_1.TxRedeemerTag.Withdraw) onlyRedeemerArg(withdrawScriptsToExec); else if (tag === cardano_ledger_ts_1.TxRedeemerTag.Voting) onlyRedeemerArg(voteScriptsToExec); else if (tag === cardano_ledger_ts_1.TxRedeemerTag.Proposing) onlyRedeemerArg(proposeScriptsToExec); else throw new Error("unrecoignized redeemer tag " + tag); }; for (var i = 0; i < nRdmrs; i++) { _loop_2(i); } minFee = this_1.calcMinFee(tx); fee = minFee + ((totExBudget.mem * memRational.num) / memRational.den) + ((totExBudget.cpu * cpuRational.num) / cpuRational.den) + // bigint division truncates always towards 0; // we don't like that so we add `1n` for both divisions ( + 2n ) BigInt(2); if (fee === prevFee) return "break"; // return last transaciton // reset for next loop // no need to reset if there's no next loop if (round === maxRound - 1) return "break"; for (var i = 0; i < outs.length; i++) { txOuts[i] = outs[i].clone(); } txOuts[txOuts.length - 1] = (new cardano_ledger_ts_1.TxOut({ address: change.address, value: cardano_ledger_ts_1.Value.sub(totInputValue, cardano_ledger_ts_1.Value.add(requiredOutputValue, cardano_ledger_ts_1.Value.lovelaces(fee))), datum: change.datum ? ((0, cardano_ledger_ts_1.canBeHash32)(change.datum) ? new cardano_ledger_ts_1.Hash32(change.datum) : (0, CanBeData_1.forceData)(change.datum)) : undefined, refScript: change.refScript })); var nextWitnesses = new cardano_ledger_ts_1.TxWitnessSet(__assign(__assign({}, tx.witnesses), { redeemers: rdmrs })); tx = new cardano_ledger_ts_1.Tx(__assign(__assign({}, tx), { body: new cardano_ledger_ts_1.TxBody(__assign(__assign({}, tx.body), { outputs: txOuts.slice(), fee: fee, scriptDataHash: getScriptDataHash(nextWitnesses, languageViews) })), witnesses: nextWitnesses, isScriptValid: _isScriptValid })); _isScriptValid = true; totExBudget = new plutus_machine_1.ExBudget({ mem: 0, cpu: 0 }); }; var this_1 = this; for (var round = 0; round < maxRound; round++) { var state_1 = _loop_1(round); if (state_1 === "break") break; } this.assertMinOutLovelaces(tx.body.outputs); return tx; }; TxBuilder.prototype.assertMinOutLovelaces = function (txOuts) { for (var i = 0; i < txOuts.length; i++) { var out = txOuts[i]; var minLovelaces = this.getMinimumOutputLovelaces(out); if (out.value.lovelaces < minLovelaces) throw new Error("tx output at index ".concat(i, " did not have enough lovelaces to meet the minimum allowed by protocol parameters.\n") + "output size: ".concat(out.toCbor().toBuffer().length, " bytes\n") + "protocol paramters \"utxoCostPerByte\": ".concat(this.protocolParamters.utxoCostPerByte, "\n") + "minimum lovelaces required: ".concat(minLovelaces.toString(), "\n") + "output lovelaces : ".concat(out.value.lovelaces.toString(), "\n") + "tx output: ".concat((0, stringify_1.stringify)(out.toJson(), undefined, 2))); } }; /** * extracts the important data from the input * and returns it in an easier way to opearte with * * if the transaction is simple enough (aka. it doesn't include plutus scripts) * this is all that either `build` or `buildSync` needs to do **/ TxBuilder.prototype.initTxBuild = function (buildArgs) { var _a = (0, txBuild_1.normalizeITxBuildArgs)(buildArgs), outputs = _a.outputs, requiredSigners = _a.requiredSigners, mints = _a.mints, invalidAfter = _a.invalidAfter, certificates = _a.certificates, withdrawals = _a.withdrawals, memo = _a.memo, metadata = _a.metadata, votingProcedures = _a.votingProcedures, proposalProcedures = _a.proposalProcedures, currentTreasuryValue = _a.currentTreasuryValue, paymentToTreasury = _a.paymentToTreasury, args = __rest(_a, ["outputs", "requiredSigners", "mints", "invalidAfter", "certificates", "withdrawals", "memo", "metadata", "votingProcedures", "proposalProcedures", "currentTreasuryValue", "paymentToTreasury"]); // mutable args var inputs = args.inputs, changeAddress = args.changeAddress, change = args.change, invalidBefore = args.invalidBefore, readonlyRefInputs = args.readonlyRefInputs, collaterals = args.collaterals, collateralReturn = args.collateralReturn; if (change) changeAddress = change.address; if (!changeAddress) throw new Error("missing changAddress and change entry while constructing a transaciton; unable to balance inputs and outpus"); if (!change) change = { address: changeAddress }; var network = changeAddress.network; if (!(0, GenesisInfos_1.isNormalizedGenesisInfos)(this.genesisInfos)) { this.setGenesisInfos(network === "mainnet" ? GenesisInfos_1.defaultMainnetGenesisInfos : GenesisInfos_1.defaultPreprodGenesisInfos); } var undef = void 0; // filter inputs so that are unique inputs = inputs.reduce(function (accum, input) { var samePresent = accum.some(function (_a) { var accumUtxo = _a.utxo; return eqUTxOByRef(accumUtxo, input.utxo); }); if (!samePresent) accum.push(input); return accum; }, []); // filter refIns so that are unique readonlyRefInputs = readonlyRefInputs === null || readonlyRefInputs === void 0 ? void 0 : readonlyRefInputs.reduce(function (accum, utxo) { var samePresent = accum.some(function (accumUtxo) { return eqUTxOByRef(accumUtxo, utxo); }); if (!samePresent) accum.push(utxo); return accum; }, []); var totInputValue = cardano_ledger_ts_1.Value.zero; var refIns = readonlyRefInputs !== null && readonlyRefInputs !== void 0 ? readonlyRefInputs : []; var outs = outputs !== null && outputs !== void 0 ? outputs : []; var requiredOutputValue = outs.reduce(function (acc, out) { return cardano_ledger_ts_1.Value.add(acc, out.value); }, cardano_ledger_ts_1.Value.zero); var vkeyWitnesses = []; var nativeScriptsWitnesses = []; var bootstrapWitnesses = []; var plutusV1ScriptsWitnesses = []; var datums = []; var plutusV2ScriptsWitnesses = []; var plutusV3ScriptsWitnesses = []; var dummyExecBudget = plutus_machine_1.ExBudget.maxCborSize; var spendRedeemers = []; var mintRedeemers = []; var certRedeemers = []; var withdrawRedeemers = []; var voteRedeemers = []; var proposeRedeemers = []; var scriptsToExec = []; /** * needed in `getScriptDataHash` to understand whoich cost model to transform in language view */ var _hasV1Scripts = false; /** * needed in `getScriptDataHash` to understand whoich cost model to transform in language view */ var _hasV2Scripts = false; /** * needed in `getScriptDataHash` to understand whoich cost model to transform in language view */ var _hasV3Scripts = false; function pushScriptToExec(idx, tag, script, datum) { if (script.type == cardano_ledger_ts_1.ScriptType.NativeScript) return; // keep track of exsisting csript versions if (!_hasV1Scripts && script.type === "PlutusScriptV1") { _hasV1Scripts = true; } else if (!_hasV2Scripts && script.type === "PlutusScriptV2") { _hasV2Scripts = true; } else if (!_hasV3Scripts && script.type === "PlutusScriptV3") { _hasV3Scripts = true; } scriptsToExec.push({ index: idx, rdmrTag: tag, script: { type: script.type, bytes: script.bytes, hash: script.hash.toString() }, datum: datum }); } function pushWitScript(script) { var t = script.type; if (t === "NativeScript") pushUniqueScript(nativeScriptsWitnesses, script); else if (t === "PlutusScriptV1") pushUniqueScript(plutusV1ScriptsWitnesses, script); else if (t === "PlutusScriptV2") pushUniqueScript(plutusV2ScriptsWitnesses, script); else if (t === "PlutusScriptV3") pushUniqueScript(plutusV3ScriptsWitnesses, script); } /** * @returns `Script` to execute */ function checkScriptAndPushIfInline(script) { var _a, _b; if ((0, obj_utils_1.hasOwn)(script, "inline")) { if ((0, obj_utils_1.hasOwn)(script, "ref")) throw new Error("multiple scripts specified"); pushWitScript(script.inline); return script.inline; } if ((0, obj_utils_1.hasOwn)(script, "ref")) { if ((0, obj_utils_1.hasOwn)(script, "inline")) throw new Error("multiple scripts specified"); var refScript = (_b = (_a = script.ref) === null || _a === void 0 ? void 0 : _a.resolved) === null || _b === void 0 ? void 0 : _b.refScript; if (refScript === (void 0)) throw new Error("script was specified to be a reference script " + "but the provided utxo is missing any attached script"); if (!refIns.some(function (u) { return eqUTxOByRef(u, script.ref); })) { refIns.push(script.ref); } return refScript; } throw new Error("unexpected execution flow 'checkScriptAndPushIfInline' in TxBuilder"); } /** * * @param datum * @param inlineDatum * @returns the `Data` of the datum */ function pushWitDatum(datum, inlineDatum, scriptType) { if (scriptType === cardano_ledger_ts_1.ScriptType.NativeScript) return undef; if (datum === "inline") datum = undef; if (scriptType === cardano_ledger_ts_1.ScriptType.PlutusV1 || scriptType === cardano_ledger_ts_1.ScriptType.PlutusV2) { if (datum === undef) { if (!(0, CanBeData_1.canBeData)(inlineDatum)) throw new Error("datum was specified to be inline; but inline datum is missing"); // no need to push to witnesses return (0, CanBeData_1.forceData)(inlineDatum); } else { var dat = (0, CanBeData_1.forceData)(datum); // add datum to witnesses // the node finds it trough the datum hash (on the utxo) datums.push(dat); return dat; } } if (datum === undef) { if ((0, CanBeData_1.canBeData)(inlineDatum)) { // no need to push to witnesses return (0, CanBeData_1.forceData)(inlineDatum); } if (inlineDatum instanceof cardano_ledger_ts_1.Hash32) throw new Error("datum hash specified on spending utxo, but resolved datum is missing"); return undef; } else if (inlineDatum instanceof cardano_ledger_ts_1.Hash32) { var dat = (0, CanBeData_1.forceData)(datum); // add datum to witnesses // the node finds it trough the datum hash (on the utxo) datums.push(dat); return dat; } return undef; } var isScriptValid = true; // `sort` mutates the array; so we `slice` (clone) first var sortedIns = inputs.slice().sort(function (a, b) { var ord = (0, uint8array_utils_1.lexCompare)(a.utxo.utxoRef.id.toBuffer(), b.utxo.utxoRef.id.toBuffer()); // if equal tx id order based on tx output index if (ord === 0) return a.utxo.utxoRef.index - b.utxo.utxoRef.index; // else order by tx id return ord; }); var _inputs = inputs.map(function (input) { var utxo = input.utxo, referenceScript = input.referenceScript, inputScript = input.inputScript, nativeScript = input.nativeScript; var addr = utxo.resolved.address; totInputValue = cardano_ledger_ts_1.Value.add(totInputValue, utxo.resolved.value); if (addr.paymentCreds.type === cardano_ledger_ts_1.CredentialType.Script && referenceScript === undef && inputScript === undef && nativeScript === undef) throw new Error("spending script utxo \"" + utxo.utxoRef.toString() + "\" without script source"); if (referenceScript !== undef) { if (inputScript !== undef || nativeScript !== undef) throw new Error("invalid input; multiple scripts specified"); var datum = referenceScript.datum, redeemer = referenceScript.redeemer, refUtxo_1 = referenceScript.refUtxo; var refScript = refUtxo_1.resolved.refScript; if (refScript === undefined) throw new Error("reference utxo specified (" + refUtxo_1.toString() + ") is missing an attached reference Script"); var sameRefPresent = refIns.find(function (u) { return eqUTxOByRef(u, refUtxo_1); }); if (sameRefPresent === undef) { refIns.push(refUtxo_1); } var dat = pushWitDatum(datum, utxo.resolved.datum, refScript.type); var i_1 = sortedIns.indexOf(input); if (i_1 < 0) throw new Error("input missing in sorted"); spendRedeemers.push(new cardano_ledger_ts_1.TxRedeemer({ data: (0, CanBeData_1.forceData)(redeemer), index: i_1, execUnits: dummyExecBudget.clone(), tag: cardano_ledger_ts_1.TxRedeemerTag.Spend })); pushScriptToExec(i_1, cardano_ledger_ts_1.TxRedeemerTag.Spend, refScript, dat); } if (inputScript !== undefined) { if (referenceScript !== undefined || nativeScript !== undef) throw new Error("invalid input; multiple scripts specified"); var datum = inputScript.datum, redeemer = inputScript.redeemer, script = inputScript.script; pushWitScript(script); var dat = pushWitDatum(datum, utxo.resolved.datum, script.type); var i_2 = sortedIns.indexOf(input); if (i_2 < 0) throw new Error("input missing in sorted"); spendRedeemers.push(new cardano_ledger_ts_1.TxRedeemer({ data: (0, CanBeData_1.forceData)(redeemer), index: i_2, execUnits: dummyExecBudget.clone(), tag: cardano_ledger_ts_1.TxRedeemerTag.Spend })); pushScriptToExec(i_2, cardano_ledger_ts_1.TxRedeemerTag.Spend, script, dat); } if (nativeScript instanceof cardano_ledger_ts_1.Script && nativeScript.type === cardano_ledger_ts_1.ScriptType.NativeScript) { if (referenceScript !== undefined || inputScript !== undef) throw new Error("invalid input; multiple scripts specified"); pushWitScript(nativeScript); } return new cardano_ledger_ts_1.TxIn(utxo); }); // good luck spending more than 4294.967295 ADA in fees // also 16.777215 ADA (3 bytes) is a lot; but CBOR only uses 2 or 4 bytes integers // and 2 are ~0.06 ADA (too low) so go for 4; var dummyFee = BigInt("0xffffffff"); var dummyOuts = outs.map(function (txO) { return txO.clone(); }); // add dummy change address output dummyOuts.push(new cardano_ledger_ts_1.TxOut({ address: change.address, // this value obviously doesn't make sense // however now we are not able to calculate it // because we are missing the minted value and eventual // values associated with certificates value: cardano_ledger_ts_1.Value.lovelaces(totInputValue.lovelaces), datum: change.datum ? (change.datum instanceof cardano_ledger_ts_1.Hash32 ? change.datum : (0, CanBeData_1.forceData)(change.datum)) : undef, refScript: change.refScript })); // index to be modified var dummyMintRedeemers = []; var _mint = mints === null || mints === void 0 ? void 0 : mints.reduce(function (accum, _a, i) { var script = _a.script, value = _a.value; var redeemer = script.redeemer; var policyId = value.policy; var toExec = checkScriptAndPushIfInline(script); dummyMintRedeemers.push([ policyId, toExec, new cardano_ledger_ts_1.TxRedeemer({ data: (0, CanBeData_1.forceData)(redeemer), index: i, execUnits: dummyExecBudget.clone(), tag: cardano_ledger_ts_1.TxRedeemerTag.Mint }) ]); return cardano_ledger_ts_1.Value.add(accum, new cardano_ledger_ts_1.Value([value])); }, cardano_ledger_ts_1.Value.zero); totInputValue = _mint instanceof cardano_ledger_ts_1.Value ? cardano_ledger_ts_1.Value.add(totInputValue, _mint) : totInputValue; function indexOfPolicy(policy) { var _a; var policyStr = policy.toString(); return (_a = _mint === null || _mint === void 0 ? void 0 : _mint.map.findIndex(function (entry) { return entry.policy.toString() === policyStr; })) !== null && _a !== void 0 ? _a : -1; } dummyMintRedeemers.forEach(function (_a) { var _b = __read(_a, 3), policy = _b[0], toExec = _b[1], dummyRdmr = _b[2]; var i = indexOfPolicy(policy); mintRedeemers.push(new cardano_ledger_ts_1.TxRedeemer({ data: dummyRdmr.data, index: i - 1, execUnits: dummyRdmr.execUnits, tag: cardano_ledger_ts_1.TxRedeemerTag.Mint })); pushScriptToExec(i, cardano_ledger_ts_1.TxRedeemerTag.Mint, toExec); }); var _certs = certificates === null || certificates === void 0 ? void 0 : certificates.map(function (_a, i) { var cert = _a.cert, script = _a.script; if (script !== undef) { certRedeemers.push(new cardano_ledger_ts_1.TxRedeemer({ data: (0, CanBeData_1.forceData)(script.redeemer), index: i, execUnits: dummyExecBudget.clone(), tag: cardano_ledger_ts_1.TxRedeemerTag.Cert })); var toExec = checkScriptAndPushIfInline(script); pushScriptToExec(i, cardano_ledger_ts_1.TxRedeemerTag.Cert, toExec); } return cert; }); var _wits = withdrawals === null || withdrawals === void 0 ? void 0 : withdrawals.sort(function (_a, _b) { var fst = _a.withdrawal; var snd = _b.withdrawal; return (0, uint8array_utils_1.lexCompare)(fst.rewardAccount instanceof cardano_ledger_ts_1.Hash28 ? fst.rewardAccount.toBuffer() : fst.rewardAccount.credentials.toBuffer(), snd.rewardAccount instanceof cardano_ledger_ts_1.Hash28 ? snd.rewardAccount.toBuffer() : snd.rewardAccount.credentials.toBuffer()); }).map(function (_a, i) { var withdrawal = _a.withdrawal, script = _a.script; if (script !== undef) { withdrawRedeemers.push(new cardano_ledger_ts_1.TxRedeemer({ data: (0, CanBeData_1.forceData)(script.redeemer), index: i, execUnits: dummyExecBudget.clone(), tag: cardano_ledger_ts_1.TxRedeemerTag.Withdraw })); var toExec = checkScriptAndPushIfInline(script); pushScriptToExec(i, cardano_ledger_ts_1.TxRedeemerTag.Withdraw, toExec); } return withdrawal; }); var i = 0; var _votingProcedures = Array.isArray(votingProcedures) ? new cardano_ledger_ts_1.VotingProcedures(votingProcedures === null || votingProcedures === void 0 ? void 0 : votingProcedures.map(function (_a) { var votingProcedure = _a.votingProcedure, script = _a.script; if (script !== undef) { voteRedeemers.push(new cardano_ledger_ts_1.TxRedeemer({ data: (0, CanBeData_1.forceData)(script.redeemer), index: i, execUnits: dummyExecBudget.clone(), tag: cardano_ledger_ts_1.TxRedeemerTag.Voting })); var toExec = checkScriptAndPushIfInline(script); pushScriptToExec(i, cardano_ledger_ts_1.TxRedeemerTag.Voting, toExec); i++; } return votingProcedure; })) : undef; i = 0; var _proposalProcedures = Array.isArray(proposalProcedures) ? proposalProcedures.map(function (_a) { var proposalProcedure = _a.proposalProcedure, script = _a.script; if (script !== undef) { proposeRedeemers.push(new cardano_ledger_ts_1.TxRedeemer({ data: (0, CanBeData_1.forceData)(script.redeemer), index: i, execUnits: dummyExecBudget.clone(), tag: cardano_ledger_ts_1.TxRedeemerTag.Proposing })); var toExec = checkScriptAndPushIfInline(script); pushScriptToExec(i, cardano_ledger_ts_1.TxRedeemerTag.Proposing, toExec); i++; } return new cardano_ledger_ts_1.ProposalProcedure(proposalProcedure); }) : undef; i = 0; var auxData = undef; var _metadata = metadata; if (memo !== undef) { _metadata = new cardano_ledger_ts_1.TxMetadata(__assign(__assign({}, _metadata === null || _metadata === void 0 ? void 0 : _metadata.metadata), { 674: new cardano_ledger_ts_1.TxMetadatumMap([ { k: new cardano_ledger_ts_1.TxMetadatumText("msg"), v: new cardano_ledger_ts_1.TxMetadatumList(splitStringByByteLength(memo, 64) .map(function (chunk) { return new cardano_ledger_ts_1.TxMetadatumText(chunk); })) } ]) })); } if (_metadata !== undef) { auxData = new cardano_ledger_ts_1.AuxiliaryData({ metadata: _metadata, }); } var redeemers = spendRedeemers .concat(mintRedeemers) .concat(withdrawRedeemers) .concat(certRedeemers) .concat(voteRedeemers) .concat(proposeRedeemers); var dummyTxWitnesses = new cardano_ledger_ts_1.TxWitnessSet({ vkeyWitnesses: vkeyWitnesses, bootstrapWitnesses: bootstrapWitnesses, datums: datums, redeemers: redeemers, nativeScripts: nativeScriptsWitnesses, plutusV1Scripts: plutusV1ScriptsWitnesses, plutusV2Scripts: plutusV2ScriptsWitnesses, plutusV3Scripts: plutusV3ScriptsWitnesses }); var datumsScriptData = datums.length > 0 ? Array.from(cbor_1.Cbor.encode(new cbor_1.CborArray(datums.map(plutus_data_1.dataToCborObj))).toBuffer()) : []; var languageViews = (0, cardano_costmodels_ts_1.costModelsToLanguageViewCbor)(this.protocolParamters.costModels, { mustHaveV1: _hasV1Scripts, mustHaveV2: _hasV2Scripts, mustHaveV3: _hasV3Scripts }).toBuffer(); invalidBefore = invalidBefore === undef ? undef : (0, ints_1.forceBigUInt)(invalidBefore); // if( invalidAfter !== undef ) // { // if( invalidBefore === undef ) invalidBefore = 0; // } if ((0, ints_1.canBeUInteger)(invalidBefore) && (0, ints_1.canBeUInteger)(invalidAfter)) { if (invalidBefore >= invalidAfter) throw new Error("invalid validity interval; invalidAfter: " + invalidAfter.toString() + "; was smaller (previous point in time) than invalidBefore:" + invalidBefore.toString()); } // assert collateral is present if needed if (scriptsToExec.filter(function (s) { return s.script.type !== "NativeScript"; }).length > 0) { if (!Array.isArray(collaterals) || collaterals.length <= 0) { collaterals = this.findCollaterals(_inputs); collateralReturn = undef; } if (collaterals.length <= 0) throw new Error("collaterals missing, and no input could be used"); var collateralValue = collaterals.reduce(function (accum, collateral) { return cardano_ledger_ts_1.Value.add(accum, collateral.resolved.value); }, cardano_ledger_ts_1.Value.zero); if (!cardano_ledger_ts_1.Value.isAdaOnly(collateralValue)) { if (!collateralReturn) { var addr = collaterals[0].resolved.address; collateralReturn = new cardano_ledger_ts_1.TxOut({ address: addr, value: collateralValue }); var minAda = this.getMinimumOutputLovelaces(collateralReturn); collateralReturn = new cardano_ledger_ts_1.TxOut({ address: addr,