@harmoniclabs/buildooor
Version:
Cardano transaction builder in typescript
1,397 lines • 75.3 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");
var getScript_1 = require("./utils/getScript.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
+ 2 // for good measure
) +
(0, ints_1.forceBigUInt)(this.protocolParamters.txFeeFixed));
};
TxBuilder.prototype.calcMinFee = function (tx, minimum) {
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
// we also add 2 for possible unwanted encoding
BigInt(104) * nVkeyWits * minFeeMultiplier +
// we add some more bytes for the array tag
BigInt(nVkeyWits < 24 ? 1 : (nVkeyWits < 256 ? 2 : 4)) * minFeeMultiplier;
if (!(0, ints_1.canBeUInteger)(minimum))
return minFee;
var min = (0, ints_1.forceBigUInt)(minimum);
return minFee < min ? min : 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);
// overestimating the size a bit
return BigInt(this.protocolParamters.utxoCostPerByte) * (size + BigInt(10));
};
TxBuilder.prototype.addMinLovelacesIfMissing = function (txOut) {
if (txOut.value.lovelaces > 0)
return txOut.clone();
return this.minimizeLovelaces({
address: txOut.address,
value: cardano_ledger_ts_1.Value.add(cardano_ledger_ts_1.Value.lovelaces(this.getMinimumOutputLovelaces(txOut) + BigInt(1000000)), txOut.value),
datum: txOut.datum,
refScript: txOut.refScript
});
};
TxBuilder.prototype.minimizeLovelaces = function (out, increment) {
if (increment === void 0) { increment = 0; }
increment = BigInt(typeof increment === "number" ? increment :
typeof increment === "bigint" ? increment :
0);
var o = out instanceof cardano_ledger_ts_1.TxOut ? out : (0, txBuild_1.txBuildOutToTxOut)(out);
var minLovelaces = (this.getMinimumOutputLovelaces(o) +
// somehow we always underestimate a tiny bit
(BigInt(32) * BigInt(this.protocolParamters.utxoCostPerByte)));
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 + increment)),
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, script.hash.toString(), 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, script.hash.toString(), 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, buildArgs.fee);
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] = this_1.addMinLovelacesIfMissing(outs[i]);
}
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.validatePhaseTwoVerbose = function (tx) {
var txBody = tx.body;
var rdmrs = tx.witnesses.redeemers;
if (!Array.isArray(rdmrs) || rdmrs.length === 0)
return [];
var nRdmrs = rdmrs.length;
var evalResults = [];
var cek = this.cek;
if (!(cek instanceof plutus_machine_1.Machine))
throw new Error("protocol params are missing the script evaluation costs");
var executionUnitPrices = this.protocolParamters.executionUnitPrices;
executionUnitPrices = Array.isArray(executionUnitPrices) ? executionUnitPrices : [
executionUnitPrices.priceMemory,
executionUnitPrices.priceSteps,
];
var _a = __read(executionUnitPrices, 2), memRational = _a[0], cpuRational = _a[1];
memRational = typeof memRational === "number" ? cbor_1.CborPositiveRational.fromNumber(memRational) : memRational;
cpuRational = typeof cpuRational === "number" ? cbor_1.CborPositiveRational.fromNumber(cpuRational) : cpuRational;
var _b = (0, toOnChain_1.getTxInfos)(tx, this.genesisInfos), txInfosV1 = _b.v1, txInfosV2 = _b.v2, txInfosV3 = _b.v3;
var _loop_3 = 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);
var onlyRedeemerArg = function (script) {
if (!(script instanceof cardano_ledger_ts_1.Script)) {
evalResults.push({
result: new uplc_1.ErrorUPLC("missig script"),
budgetSpent: new plutus_machine_1.ExBudget({ mem: 0, cpu: 0 }),
logs: [],
rdmr: rdmr,
isV2OrLess: false
});
return;
}
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);
evalResults.push(__assign(__assign({}, cek.eval(isV2OrLess ?
new uplc_1.Application(new uplc_1.Application((0, uplc_1.parseUPLC)(script.bytes).body, uplc_1.UPLCConst.data(rdmrData)), uplc_1.UPLCConst.data(ctxData)) :
new uplc_1.Application((0, uplc_1.parseUPLC)(script.bytes).body, uplc_1.UPLCConst.data(ctxData)))), { rdmr: rdmr, isV2OrLess: isV2OrLess }));
};
if (tag === cardano_ledger_ts_1.TxRedeemerTag.Spend) {
var entry = (0, getScript_1.getSpendingScript)(tx, index);
if (!entry) {
evalResults.push({
result: new uplc_1.ErrorUPLC("missig script"),
budgetSpent: new plutus_machine_1.ExBudget({ mem: 0, cpu: 0 }),
logs: [],
rdmr: rdmr,
isV2OrLess: false
});
return "continue";
}
;
var script = entry.script, datum = entry.datum;
// TODO: check if this is correct
// I'm assuming native scripts are phase 1
if (script.type === cardano_ledger_ts_1.ScriptType.NativeScript)
return "continue";
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);
evalResults.push(__assign(__assign({}, cek.eval(isV2OrLess ?
new uplc_1.Application(new uplc_1.Application(new uplc_1.Application((0, uplc_1.parseUPLC)(script.bytes).body, uplc_1.UPLCConst.data(datum)), uplc_1.UPLCConst.data(rdmrData)), uplc_1.UPLCConst.data(ctxData)) :
new uplc_1.Application((0, uplc_1.parseUPLC)(script.bytes).body, uplc_1.UPLCConst.data(ctxData)))), { rdmr: rdmr, isV2OrLess: isV2OrLess }));
return "continue";
}
else if (tag === cardano_ledger_ts_1.TxRedeemerTag.Mint)
onlyRedeemerArg((0, getScript_1.getMintingScript)(tx, index));
else if (tag === cardano_ledger_ts_1.TxRedeemerTag.Cert)
onlyRedeemerArg((0, getScript_1.getCeritficateScript)(tx, index));
else if (tag === cardano_ledger_ts_1.TxRedeemerTag.Withdraw)
onlyRedeemerArg((0, getScript_1.getWithdrawalScript)(tx, index));
else if (tag === cardano_ledger_ts_1.TxRedeemerTag.Voting)
onlyRedeemerArg((0, getScript_1.getVotingScript)(tx, index));
else if (tag === cardano_ledger_ts_1.TxRedeemerTag.Proposing)
onlyRedeemerArg((0, getScript_1.getProposingScript)(tx, index));
else
return "continue";
};
for (var i = 0; i < nRdmrs; i++) {
_loop_3(i);
} // for loop over redeemers
return evalResults;
};
TxBuilder.prototype.validatePhaseTwo = function (tx) {
var totExBudget = new plutus_machine_1.ExBudget({ mem: 0, cpu: 0 });
var results = this.validatePhaseTwoVerbose(tx);
return results.every(function (_a) {
var result = _a.result, budgetSpent = _a.budgetSpent, logs = _a.logs, isV2OrLess = _a.isV2OrLess, rdmr = _a.rdmr;
var successExec = isV2OrLess ?
!(result instanceof uplc_1.ErrorUPLC) :
( // v3 requires to return unit
result instanceof plutus_machine_1.CEKConst
&& Array.isArray(result.type)
&& result.type.length === 1
&& result.type[0] === uplc_1.ConstTyTag.unit
&& result.value === undefined);
if (!successExec)
return false;
if (budgetSpent.cpu > rdmr.execUnits.cpu
|| budgetSpent.mem > rdmr.execUnits.mem)
return false;
totExBudget.add(rdmr.execUnits);
return true;
})
&& totExBudget.cpu <= this.protocolParamters.maxTxExecutionUnits.cpu
&& totExBudget.mem <= this.protocolParamters.maxTxExecutionUnits.mem;
};
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 _this = this;
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: totInputValue.clone(),
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;
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,
value: cardano_ledger_ts_1.Value.sub(collateralValue, cardano_ledger_ts_1.Value.lovelaces(collateralValue.lovelaces - minAda))
});
}
var realCollValue = cardano_ledger_ts_1.Value.sub(collateralValue, collateralReturn.value);
if (!cardano_ledger_ts_1.Value.isAdaOnly(realCollValue))
throw new Error("total collateral value was including non-ADA value;\n" +
"total collateral value was: ".concat((0, stringify_1.stringify)(realCollValue.toJson(), undef, 2)));
}
}
var dummyTx = new cardano_ledger_ts_1.Tx({
body: new cardano_ledger_ts_1.TxBody({
inputs: _inputs,
outputs: dummyOuts,
fee: dummyFee,
mint: _mint,
certs: _certs,
withdrawals: _wits,
refInputs: refIns.length === 0 ? undef : refIns.map(function (refIn) { return refIn instanceof cardano_ledger_ts_1.TxIn ? refIn : new cardano_ledger_ts_1.TxIn(refIn); }),
// protocolUpdate: protocolUpdateProposal,
requiredSigners: requiredSigners,
collateralInputs: collaterals,
collateralReturn: collateralReturn === undef ?
undef :
(0, txBuild_1.txBuildOutToTxOut)(collateralReturn),
totCollateral: undef,
validityIntervalStart: invalidBefore === undef ?
undef :
(0, ints_1.forceBigUInt)(invalidBefore),
ttl: invalidAfter === undef ?
undef :
(0, ints_1.forceBigUInt)(invalidAfter),
auxDataHash: auxData === null || auxData === void 0 ? void 0 : auxData.hash,
scriptDataHash: getScriptDataHash(dummyTxWitnesses, languageViews),
network: network,
votingProcedures: _votingProcedures,
proposalProcedures: _proposalProcedures,
currentTreasuryValue: currentTreasuryValue,
donation: paymentToTreasury,
}),
witnesses: dummyTxWitnesses,
auxiliaryData: auxData,
isScriptValid: isScriptValid
});
var minFee = this.calcMinFee(dummyTx, args.fee);
var txOuts = new Array(outs.length + 1);
outs.forEach(function (txO, i) { return txOuts[i] = _this.addMinLovelacesIfMissing(txO); });
var changeOutput = 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(minFee))),
datum: change.datum ? (change.datum instanceof cardano_ledger_ts_1.Hash32 ?
change.datum :
(0, CanBeData_1.forceData)(change.datum)) : undef,
refScript: change.refScript
});
txOuts[txOuts.length - 1] = changeOutput;
this.assertCorrectChangeOutput(changeOutput);
var tx = new cardano_ledger_ts_1.Tx(__assign(__assign({}, dummyTx), { body: new cardano_ledger_ts_1.TxBody(__assign(__assign({}, dummyTx.body), { outputs: txOuts, fee: minFee })) }));
return {
tx: tx,
scriptsToExec: scriptsToExec,
minFee: minFee,
datumsScriptData: datumsScriptData,
languageViews: languageViews,
totInputValue: totInputValue,
requiredOutputValue: requiredOutputValue,
outs: outs,
change: change,
};
};
TxBuilder.prototype.assertCorrectChangeOutput = function (changeOutput) {
var e_1, _a, e_2, _b;
if (changeOutput.value.lovelaces < 0)
throw new Error("not enough input lovelaces to cover the output value and fee");
try {
for (var _c = __values(changeOutput.value), _d = _c.next(); !_d.done; _d = _c.next()) {
var _e = _d.value, assets = _e.assets, policy = _e.policy;
if (policy === "")
continue;
try {
for (var assets_1 = (e_2 = void 0, __values(assets)), assets_1_1 = assets_1.next(); !assets_1_1.done; assets_1_1 = assets_1.next()) {
var _f = assets_1_1.value, quantity = _f.quantity, name_1 = _f.name;
if (quantity < 0) {
console.dir(changeOutput.value.toJson(), { depth: Infinity });
throw new Error("not enough ".concat(policy.toString(), ".").concat((0, uint8array_utils_1.toHex)(name_1), " in input to cover the total output"));
}
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (assets_1_1 && !assets_1_1.done && (_b = assets_1.return)) _b.call(assets_1);
}
finally { if (e_2) throw e_2.error; }
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
}
finally { if (e_1) throw e_1.error; }
}
};
TxBuilder.prototype.findCollaterals = function (utxos, targetCollateralLovelaces) {
var e_3, _a, e_4, _b;
var _c;
if (targetCollateralLovelaces === void 0) { targetCollateralLovelaces = 10000000; }
var grouped = {};
var pkhs = [];
try {
for (var utxos_1 = __values(utxos), utxos_1_1 = utxos_1.next(); !utxos_1_1.done; utxos_1_1 = utxos_1.next()) {
var u = utxos_1_1.value;
var creds = u.resolved.address.paymentCreds;
if (creds.type === cardano_ledger_ts_1.CredentialType.Script)
continue;
var pkh = creds.hash.toString();
if (!Array.isArray(grouped[pkh])) {
grouped[pkh] = [];
pkhs.push(pkh);
}
grouped[pkh].push(u);
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (utxos_1_1 && !utxos_1_1.done && (_a = utxos_1.return)) _a.call(utxos_1);
}
finally { if (e_3) throw e_3.error; }
}
if (pkhs.length === 0)
return [];
for (var i = 0; i < pkhs.length; i++) {
var pkh = pkhs[i];
grouped[pkh] = grouped[pkh]
.sort(function (a, b) { return -Number(a.resolved.value.lovelaces - b.resolved.value.lovelaces); })
.slice(0, Number((_c = this.protocolParamters.maxCollateralInputs) !== null && _c !== void 0 ? _c : 3));
}
var maxPkh = pkhs.shift();
var maxLove = grouped[maxPkh].reduce(function (a, b) { return a + b.resolved.value.lovelaces; }, BigInt(0));
try {
for (var pkhs_1 = __values(pkhs), pkhs_1_1 = pkhs_1.next(); !pkhs_1_1.done; pkhs_1_1 = pkhs_1.next()) {
var pkh = pkhs_1_1.value;
var love = grouped[pkh].reduce(function (a, b) { return a + b.resolved.value.lovelaces; }, BigInt(0));
if (love > maxLove) {
maxPkh = pkh;
maxLove = love;
}
}
}
catch (e_4_1) { e_4 = { error: e_4_1 }; }
finally {
try {
if (pkhs_1_1 && !pkhs_1_1.done && (_b = pkhs_1.return)) _b.call(pkhs_1);
}
finally { if (e_4) throw e_4.error; }
}
var collaterals = grouped[maxPkh];
targetCollateralLovelaces = BigInt(targetCollateralLovelaces);
if (targetCollateralLovelaces < 0)
targetCollateralLovelaces = -targetCollateralLovelaces;
var filtered = collaterals.filter(function (u) { return u.resolved.value.lovelaces >= targetCollateralLovelaces; });
if (filtered.length === 0)
return collaterals;
// try to reduce the number of utxo collaterals and collateral value.
return [filtered[filtered.length - 1]];
};
return TxBuilder;
}());
exports.TxBuilder = TxBuilder;
function eqUTxOByRef(a, b) {
return a === b || a.utxoRef === b.utxoRef || (a.utxoRef.index === b.utxoRef.index &&
a.utxoRef.id.toString() === b.utxoRef.id.toString());
}
function pushUniqueScript(arr, toPush) {
var hashToPush = toPush.hash.toString();
if (!arr.some(function (script) { return script.hash.toString() === hashToPush; }))
arr.push(toPush);
}
function getCtx(scriptType, spendingPurpose, scriptInfo, redeemerData, txInfosV1, txInfosV2, txInfosV3) {
if (scriptType === cardano_ledger_ts_1.ScriptType.PlutusV3) {
return new plutus_data_1.DataConstr(0, [
txInfosV3,
redeemerData,
scriptInfo
]);
}
else if (scriptType === cardano_ledger_ts_1.ScriptType.PlutusV2) {
if (txInfosV2 === undefined)
throw new Error("plutus script v2 included in a v3 transaction");
return new plutus_data_1.DataConstr(0, [
txInfosV2,
spendingPurpose
]);
}
else if (scriptType === cardano_ledger_ts_1.ScriptType.PlutusV1) {
if (txInfosV1 === undefined)
throw new Error("plutus script v1 included in a v2 or v3 transaction");
return new plutus_data_1.DataConstr(0, [
txInfosV1,
spendingPurpose
]);
}
else
throw new Error("unexpected native script execution");
}
function onEvaluationResult(i, totExBudget, rdmr, result, budgetSpent, logs, callArgs, rdmrs, scritHashStr, onScriptResult, onScriptInvalid) {
var _isScriptValid = true;
if (typeof onScriptResult === "function")
onScriptResult(rdmr.clone(), result, budgetSpent.clone(), logs.slice(), callArgs.map(function (d) { return d.clone(); }), scritHashStr);
if (result instanceof uplc_1.ErrorUPLC ||
(function (resultKeys) {
return resultKeys.includes("msg") &&
resultKeys.includes("addInfos");
})(Object.keys(result))) {
if (typeof onScriptInvalid === "function") {
onScriptInvalid(rdmr.clone(), logs.slice(), callArgs.map(function (d) { return d.clone(); }));
// _isScriptValid = false;
}
else {
var callArgsStr = (callArgs
.map(function (d, i) {
return i.toString() + ": " + (0, plutus_data_1.dataToCbor)(d).toString();
})
.join("\n"));
var errorMsg = result === null || result === void 0 ? void 0 : result.msg;
var addInfosStr = "<error while serializing additional infos>";
try {
addInfosStr = (0, stringify_1.stringify)(result === null || result === void 0 ? void 0 : result.addInfos, function (k, v) {
if ((0, uint8array_utils_1.isUint8Array)(v))
return (0, uint8array_utils_1.toHex)(v);
if (typeof v === "bigint")
return v.toString();
return v;
});
}
catch (_a) { }
throw new Error("script '".concat(scritHashStr, "' consumed with ").concat((0, cardano_ledger_ts_1.txRedeemerTagToString)(rdmr.tag), " redemer ") +
"and index '".concat(rdmr.index.toString(), "'\n\n") +
"called with data arguments:\n".concat(callArgsStr, "\n\n") +
"failed with \n" +
"error message: ".concat(errorMsg, "\n") +
"additional infos: ".concat(addInfosStr, "\n") +
"script execution logs: [".concat(logs.toString(), "]\n"));
}
}
rdmrs[i] = new cardano_ledger_ts_1.TxRedeemer(__assign(__assign({}, rdmr), { execUnits: budgetSpent }));
totExBudget.add(budgetSpent);
return _isScriptValid;
}
;
function findWitnessKey(map, n) {
var _a;
var res = (_a = map.map.find(function (_a) {
var k = _a.k;
return k instanceof cbor_1.CborUInt && Number(k.num) === n;
})) === null || _a === void 0 ? void 0 : _a.v;
if (!(res instanceof cbor_1.CborArray))
return undefined;
if (res.array.length === 0)
return undefined;
return res;
}
function getScriptDataHash(witnesses, languageViews) {
var undef = void 0;
var cbor = witnesses.toCborObj();
if (!(cbor instanceof cbor_1.CborMap))
return undef;
var rdmrs = findWitnessKey(cbor, 5);
var dats = findWitnessKey(cbor, 4);
if (rdmrs === undef &&
dats === undef)
return undef;
var scriptData;
if (rdmrs === undef &&
dats !== undef) {
/* (Deprecated)
; Finally, note that in the case that a transaction includes datums but does not
; include any redeemers, the script data format becomes (in hex):
; [ 80 | datums | A0 ]
; corresponding to a CBOR empty list and an empty map (our apologies).
*/
/* Post Babbage:
; [ A0 | datums | A0 ]
*/
scriptData = new Uint8Array(__spreadArray(__spreadArray([
0xa0
], __read(cbor_1.Cbor.encode(dats).toBuffer()), false), [
0xa0
], false));
}
else {
var rdmrsBuff = rdmrs ? cbor_1.Cbor.encode(rdmrs).toBuffer() : new Uint8Array([0x80]);
var datsBuff = dats ? cbor_1.Cbor.encode(dats).toBuffer() : new Uint8Array([]);
scriptData = new Uint8Array(rdmrsBuff.length + datsBuff.length + languageViews.length);
scriptData.set(rdmrsBuff, 0);
scriptData.set(datsBuff, rdmrsBuff.length);
scriptData.set(languageViews, rdmrsBuff.length + datsBuff.length);
}
return new cardano_ledger_ts_1.ScriptDataHash(Uint8Array.from((0, crypto_1.blake2b_256)(scriptData)));
}
exports.getScriptDataHash = getScriptDataHash;
// Helper function to get byte length of a string using UTF-8 encoding
// const getByteLength = (str: string): number => {
// return new TextEncoder().encode(str).length;
// };
function getByteLength(str) {
return (0, uint8array_utils_1.fromUtf8)(str).length;
}
/**
* Claude prompt (yes I'm lazy):
*
* write a typescript function that given a string and a number,
* returns an array of strings whose length IN BYTES is at most the second parameter,
* if a utf 8 char is present at the intersection
* of the two chunks IT MUST STAY INTACT and it will be part of the following chunk.
*
* @example
* const exampleString = "Hello, 🌍! This is a test.";
* const maxChunkBytes = 10;
* const result = splitStringByByteLength(exampleString, maxChunkBytes);
* console.log(result); // ["Hello, ", "🌍! This", " is a test", "."]
*/
function splitStringByByteLength(input, maxByteLength) {
var e_5, _a;
if (maxByteLength === void 0) { maxByteLength = 64; }
// If input is empty or max byte length is 0, return empty array
if (!input || maxByteLength <= 0)
return [];
var chunks = [];
var currentChunk = '';
try {
for (var input_1 = __values(input), input_1_1 = input_1.next(); !input_1_1.done; input_1_1 = input_1.next()) {
var char = input_1_1.value;
var potentialChunk = currentChunk + char;
var potentialChunkByteLength = getByteLength(potentialChunk);
// If adding this character would exceed max byte length
if (potentialChunkByteLength > maxByteLength) {
// Push current chunk and start a new one
if (currentChunk) {
chunks.push(currentChunk);
currentChunk = '';
}
}
// Add character to current chunk
currentChunk += char;
}
}
catch (e_5_1) { e_5 = { error: e_5_1 }; }
finally {
try {
if (input_1_1 && !input_1_1.done && (_a = input_1.return)) _a.call(input_1);
}
finally { if (e_5) throw e_5.error; }
}
// Add final chunk if not empty
if (currentChunk) {
chunks.push(currentChunk);
}
return chunks;
}
exports.splitStringByByteLength = splitStringByByteLength;