@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
JavaScript
"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,