UNPKG

@stricahq/typhonjs

Version:

Pure JS Cardano Wallet library

721 lines (720 loc) 33.1 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Transaction = void 0; const buffer_1 = require("buffer"); const cbors = __importStar(require("@stricahq/cbors")); const bignumber_js_1 = __importDefault(require("bignumber.js")); const lodash_1 = __importDefault(require("lodash")); const helpers_1 = require("../utils/helpers"); const types_1 = require("../types"); const encoder_1 = require("../utils/encoder"); const crypto_1 = require("../utils/crypto"); const utils_1 = require("../utils/utils"); const transactionBuilder_1 = __importDefault(require("./helpers/transactionBuilder")); const paymentTransaction_1 = require("./helpers/paymentTransaction"); const internal_types_1 = require("../internal-types"); class Transaction { constructor({ protocolParams }) { this.inputs = []; this.referenceInputs = []; this.outputs = []; this.certificates = []; this.withdrawals = []; this.requiredWitnesses = new Map(); this.requiredNativeScriptWitnesses = new Map(); this.fee = new bignumber_js_1.default(5000000); this.witnesses = []; this.plutusScriptMap = new Map(); this.nativeScriptList = []; this.collaterals = []; this.requiredSigners = new Map(); this.plutusDataList = []; this._isPlutusV1Transaction = false; this._isPlutusV2Transaction = false; this._isPlutusV3Transaction = false; this.mints = []; this.votingProcedures = []; this.proposalProcedures = []; this._protocolParams = protocolParams; } get protocolParams() { return this._protocolParams; } getTTL() { return this.ttl; } setTTL(ttl) { this.ttl = ttl; } getValidityIntervalStart() { return this.validityIntervalStart; } setValidityIntervalStart(validityIntervalStart) { this.validityIntervalStart = validityIntervalStart; } addInput(input) { if (input.address.paymentCredential.type === types_1.HashType.ADDRESS) { this.requiredWitnesses.set(input.address.paymentCredential.hash.toString("hex"), input.address.paymentCredential.bipPath); } else if (input.address.paymentCredential.type === types_1.HashType.SCRIPT) { if (input.address.paymentCredential.plutusScript) { this.plutusScriptMap.set(input.address.paymentCredential.plutusScript.cborHex, input.address.paymentCredential.plutusScript.type); if (input.address.paymentCredential.plutusScript.type === types_1.PlutusScriptType.PlutusScriptV1) { this._isPlutusV1Transaction = true; } if (input.address.paymentCredential.plutusScript.type === types_1.PlutusScriptType.PlutusScriptV2) { this._isPlutusV2Transaction = true; } if (input.address.paymentCredential.plutusScript.type === types_1.PlutusScriptType.PlutusScriptV3) { this._isPlutusV3Transaction = true; } } else if (input.address.paymentCredential.nativeScript) { const nativeScript = input.address.paymentCredential.nativeScript; const pubKeyHashList = (0, helpers_1.getPubKeyHashListFromNativeScript)(nativeScript); for (const pkh of pubKeyHashList) { this.requiredNativeScriptWitnesses.set(pkh, undefined); } this.nativeScriptList.push(nativeScript); } } if (input.plutusData) { this.plutusDataList.push(input.plutusData); } this.inputs.push(input); } addReferenceInput(input) { if (input.address && input.address.paymentCredential.type === types_1.HashType.SCRIPT && input.address.paymentCredential.plutusScript) { if (input.address.paymentCredential.plutusScript.type === types_1.PlutusScriptType.PlutusScriptV1) { this._isPlutusV1Transaction = true; } if (input.address.paymentCredential.plutusScript.type === types_1.PlutusScriptType.PlutusScriptV2) { this._isPlutusV2Transaction = true; } if (input.address.paymentCredential.plutusScript.type === types_1.PlutusScriptType.PlutusScriptV3) { this._isPlutusV3Transaction = true; } } this.referenceInputs.push(input); } addRequiredSigner(credential) { this.requiredSigners.set(credential.hash.toString("hex"), credential.bipPath); } addCollateral(input) { if (input.address.paymentCredential.type === types_1.HashType.ADDRESS) { this.requiredWitnesses.set(input.address.paymentCredential.hash.toString("hex"), input.address.paymentCredential.bipPath); } this.collaterals.push(input); } addMint(mint) { this.mints.push(mint); if (mint.plutusScript) { this.plutusScriptMap.set(mint.plutusScript.cborHex, mint.plutusScript.type); if (mint.plutusScript.type === types_1.PlutusScriptType.PlutusScriptV1) { this._isPlutusV1Transaction = true; } if (mint.plutusScript.type === types_1.PlutusScriptType.PlutusScriptV2) { this._isPlutusV2Transaction = true; } if (mint.plutusScript.type === types_1.PlutusScriptType.PlutusScriptV3) { this._isPlutusV3Transaction = true; } } else if (mint.nativeScript) { // used to guesstimate fees by required pkh witnesses inside nativescript // this flow can be improved in future version const pubKeyHashList = (0, helpers_1.getPubKeyHashListFromNativeScript)(mint.nativeScript); for (const pkh of pubKeyHashList) { this.requiredNativeScriptWitnesses.set(pkh, undefined); } this.nativeScriptList.push(mint.nativeScript); } } /** * The method will add a certificate to the transaction to be included in cbor * This method will automatically scan and include each unique required witnesses in the map * to help sign the transaction * @param certificate a certificate to include in the transaction */ addCertificate(certificate) { switch (certificate.type) { case types_1.CertificateType.STAKE_DELEGATION: { if (certificate.cert.stakeCredential.type === types_1.HashType.ADDRESS) { this.requiredWitnesses.set(certificate.cert.stakeCredential.hash.toString("hex"), certificate.cert.stakeCredential.bipPath); } break; } case types_1.CertificateType.STAKE_REGISTRATION: { if (certificate.cert.stakeCredential.type === types_1.HashType.ADDRESS) { this.requiredWitnesses.set(certificate.cert.stakeCredential.hash.toString("hex"), certificate.cert.stakeCredential.bipPath); } break; } case types_1.CertificateType.STAKE_DE_REGISTRATION: { if (certificate.cert.stakeCredential.type === types_1.HashType.ADDRESS) { this.requiredWitnesses.set(certificate.cert.stakeCredential.hash.toString("hex"), certificate.cert.stakeCredential.bipPath); } break; } case types_1.CertificateType.STAKE_KEY_REGISTRATION: { if (certificate.cert.stakeCredential.type === types_1.HashType.ADDRESS) { this.requiredWitnesses.set(certificate.cert.stakeCredential.hash.toString("hex"), certificate.cert.stakeCredential.bipPath); } break; } case types_1.CertificateType.STAKE_KEY_DE_REGISTRATION: { if (certificate.cert.stakeCredential.type === types_1.HashType.ADDRESS) { this.requiredWitnesses.set(certificate.cert.stakeCredential.hash.toString("hex"), certificate.cert.stakeCredential.bipPath); } break; } case types_1.CertificateType.VOTE_DELEGATION: { if (certificate.cert.stakeCredential.type === types_1.HashType.ADDRESS) { this.requiredWitnesses.set(certificate.cert.stakeCredential.hash.toString("hex"), certificate.cert.stakeCredential.bipPath); } break; } case types_1.CertificateType.STAKE_VOTE_DELEG: { if (certificate.cert.stakeCredential.type === types_1.HashType.ADDRESS) { this.requiredWitnesses.set(certificate.cert.stakeCredential.hash.toString("hex"), certificate.cert.stakeCredential.bipPath); } break; } case types_1.CertificateType.STAKE_REG_DELEG: { if (certificate.cert.stakeCredential.type === types_1.HashType.ADDRESS) { this.requiredWitnesses.set(certificate.cert.stakeCredential.hash.toString("hex"), certificate.cert.stakeCredential.bipPath); } break; } case types_1.CertificateType.VOTE_REG_DELEG: { if (certificate.cert.stakeCredential.type === types_1.HashType.ADDRESS) { this.requiredWitnesses.set(certificate.cert.stakeCredential.hash.toString("hex"), certificate.cert.stakeCredential.bipPath); } break; } case types_1.CertificateType.STAKE_VOTE_REG_DELEG: { if (certificate.cert.stakeCredential.type === types_1.HashType.ADDRESS) { this.requiredWitnesses.set(certificate.cert.stakeCredential.hash.toString("hex"), certificate.cert.stakeCredential.bipPath); } break; } case types_1.CertificateType.DREP_REG: { if (certificate.cert.dRepCredential.type === types_1.HashType.ADDRESS) { this.requiredWitnesses.set(certificate.cert.dRepCredential.hash.toString("hex"), certificate.cert.dRepCredential.bipPath); } break; } case types_1.CertificateType.DREP_DE_REG: { if (certificate.cert.dRepCredential.type === types_1.HashType.ADDRESS) { this.requiredWitnesses.set(certificate.cert.dRepCredential.hash.toString("hex"), certificate.cert.dRepCredential.bipPath); } break; } case types_1.CertificateType.DREP_UPDATE: { if (certificate.cert.dRepCredential.type === types_1.HashType.ADDRESS) { this.requiredWitnesses.set(certificate.cert.dRepCredential.hash.toString("hex"), certificate.cert.dRepCredential.bipPath); } break; } default: break; } this.certificates.push(certificate); } addOutput(output) { const uOutput = output; uOutput.tokens = (0, helpers_1.sortTokens)(uOutput.tokens); this.outputs.push(uOutput); if (uOutput.plutusData) { this.plutusDataList.push(uOutput.plutusData); } } addWithdrawal(withdrawal) { if (withdrawal.rewardAccount.stakeCredential.type === types_1.HashType.ADDRESS) { this.requiredWitnesses.set(withdrawal.rewardAccount.stakeCredential.hash.toString("hex"), withdrawal.rewardAccount.stakeCredential.bipPath); } this.withdrawals.push(withdrawal); } // add voting procedure to the transaction, used to vote on a governance proposal addVotingProcedure(votingProcedure) { if (votingProcedure.voter.key.type === types_1.HashType.ADDRESS) { this.requiredWitnesses.set(votingProcedure.voter.key.hash.toString("hex"), votingProcedure.voter.key.bipPath); } this.votingProcedures.push(votingProcedure); } addProposalProcedure(proposalProcedure) { // no additional signatures required to submit a governance action this.proposalProcedures.push(proposalProcedure); } setCollateralOutput(output) { const uOutput = output; uOutput.tokens = (0, helpers_1.sortTokens)(uOutput.tokens); this.collateralOutput = uOutput; if (uOutput.plutusData) { this.plutusDataList.push(uOutput.plutusData); } } getCollateralOutput() { return this.collateralOutput; } setTotalCollateral(amount) { this.totalCollateral = amount; } getTotalCollateral() { return this.totalCollateral; } setDonationAmount(amount) { this.donationAmount = amount; } getDonationAmount() { return this.donationAmount; } setTreasuryAmount(amount) { this.treasuryAmount = amount; } getTreasuryAmount() { return this.treasuryAmount; } /** * This method will encode the transaction body to be included in the cbor */ encodeTransactionBody({ extraOutputs, scriptDataHash, }) { const encodedBody = new Map(); encodedBody.set(internal_types_1.TransactionBodyItemType.INPUTS, (0, encoder_1.encodeInputs)(this.inputs)); let trxOutputs = this.outputs; if (extraOutputs && extraOutputs.length > 0) { trxOutputs = trxOutputs.concat(extraOutputs); } encodedBody.set(internal_types_1.TransactionBodyItemType.OUTPUTS, (0, encoder_1.encodeOutputs)(trxOutputs)); encodedBody.set(internal_types_1.TransactionBodyItemType.FEE, this.fee); if (this.ttl !== undefined) { encodedBody.set(internal_types_1.TransactionBodyItemType.TTL, this.ttl); } if (this.certificates.length > 0) { encodedBody.set(internal_types_1.TransactionBodyItemType.CERTIFICATES, (0, encoder_1.encodeCertificates)(this.certificates)); } if (this.withdrawals.length > 0) { encodedBody.set(internal_types_1.TransactionBodyItemType.WITHDRAWALS, (0, encoder_1.encodeWithdrawals)(this.withdrawals)); } if (this.auxiliaryData) { const encodedAuxiliaryData = (0, encoder_1.encodeAuxiliaryData)(this.auxiliaryData); const auxiliaryDataCbor = cbors.Encoder.encode(encodedAuxiliaryData); const auxiliaryDataHash = (0, crypto_1.hash32)(auxiliaryDataCbor); encodedBody.set(internal_types_1.TransactionBodyItemType.AUXILIARY_DATA_HASH, auxiliaryDataHash); } if (this.validityIntervalStart !== undefined) { encodedBody.set(internal_types_1.TransactionBodyItemType.VALIDITY_INTERVAL_START, this.validityIntervalStart); } if (!lodash_1.default.isEmpty(this.mints)) { encodedBody.set(internal_types_1.TransactionBodyItemType.MINT, (0, encoder_1.encodeMint)(this.mints)); } if (scriptDataHash) { encodedBody.set(internal_types_1.TransactionBodyItemType.SCRIPT_DATA_HASH, scriptDataHash); } if (!lodash_1.default.isEmpty(this.collaterals)) { encodedBody.set(internal_types_1.TransactionBodyItemType.COLLATERAL_INPUTS, (0, encoder_1.encodeCollaterals)(this.collaterals)); } const requiredSigners = Array.from(this.requiredSigners.keys()); if (!lodash_1.default.isEmpty(requiredSigners)) { encodedBody.set(internal_types_1.TransactionBodyItemType.REQUIRED_SIGNERS, requiredSigners.map((key) => buffer_1.Buffer.from(key, "hex"))); } if (this.collateralOutput) { encodedBody.set(internal_types_1.TransactionBodyItemType.COLLATERAL_OUTPUT, (0, encoder_1.encodeOutput)(this.collateralOutput)); } if (this.totalCollateral) { encodedBody.set(internal_types_1.TransactionBodyItemType.TOTAL_COLLATERAL, this.totalCollateral); } if (!lodash_1.default.isEmpty(this.referenceInputs)) { encodedBody.set(internal_types_1.TransactionBodyItemType.REFERENCE_INPUTS, (0, encoder_1.encodeInputs)(this.referenceInputs)); } if (!lodash_1.default.isEmpty(this.votingProcedures)) { encodedBody.set(internal_types_1.TransactionBodyItemType.VOTING_PROCEDURES, (0, encoder_1.encodeVotingProcedures)(this.votingProcedures)); } if (!lodash_1.default.isEmpty(this.proposalProcedures)) { encodedBody.set(internal_types_1.TransactionBodyItemType.PROPOSAL_PROCEDURES, (0, encoder_1.encodeProposalProcedures)(this.proposalProcedures)); } if (this.donationAmount) { encodedBody.set(internal_types_1.TransactionBodyItemType.DONATION_AMOUNT, this.donationAmount); } if (this.treasuryAmount) { encodedBody.set(internal_types_1.TransactionBodyItemType.TREASURY_AMOUNT, this.treasuryAmount); } return encodedBody; } transactionFee(size) { return new bignumber_js_1.default(size) .times(this._protocolParams.minFeeA) .plus(this._protocolParams.minFeeB) .integerValue(bignumber_js_1.default.ROUND_CEIL); } contractFee() { let totalMem = 0; let totalSteps = 0; for (const input of this.inputs) { if (input.redeemer) { totalMem += input.redeemer.exUnits.mem; totalSteps += input.redeemer.exUnits.steps; } } for (const mint of this.mints) { if (mint.redeemer) { totalMem += mint.redeemer.exUnits.mem; totalSteps += mint.redeemer.exUnits.steps; } } const memPrice = new bignumber_js_1.default(totalMem).times(this._protocolParams.priceMem); const stepsPrice = new bignumber_js_1.default(totalSteps).times(this._protocolParams.priceSteps); return memPrice.plus(stepsPrice).integerValue(bignumber_js_1.default.ROUND_CEIL); } calculateRefScriptFee() { // sizeIncrement and multiplier are fixed numbers in cardano node const sizeIncrement = 25600; const multiplier = 1.2; const minFeeRefScriptCostPerByte = this._protocolParams.minFeeRefScriptCostPerByte; const calculate = (acc, curTierPrice, size) => { if (size < sizeIncrement) { return curTierPrice.multipliedBy(size).plus(acc).integerValue(bignumber_js_1.default.ROUND_FLOOR); } const acc_ = curTierPrice.multipliedBy(sizeIncrement).plus(acc); return calculate(acc_, curTierPrice.multipliedBy(multiplier), size - sizeIncrement); }; const getNSSize = (nativeScript) => { const encodedNativeScript = cbors.Encoder.encode((0, encoder_1.encodeNativeScript)(nativeScript)); return encodedNativeScript.length; }; const getPSSize = (plutusScriptHex) => { return buffer_1.Buffer.from(plutusScriptHex, "hex").length; }; let totalRefScriptSize = 0; for (const input of this.inputs) { if (input.nativeScript) { totalRefScriptSize += getNSSize(input.nativeScript); } if (input.plutusScript) { totalRefScriptSize += getPSSize(input.plutusScript.cborHex); } } for (const input of this.referenceInputs) { if (input.nativeScript) { totalRefScriptSize += getNSSize(input.nativeScript); } if (input.plutusScript) { totalRefScriptSize += getPSSize(input.plutusScript.cborHex); } } if (totalRefScriptSize > 0) { return calculate(new bignumber_js_1.default(0), minFeeRefScriptCostPerByte, totalRefScriptSize); } return new bignumber_js_1.default(0); } calculateTxSize(extraOutputs) { const combinedRequiredWitnesses = new Map(); for (const [key, value] of this.requiredNativeScriptWitnesses.entries()) { combinedRequiredWitnesses.set(key, value); } for (const [key, value] of this.requiredSigners.entries()) { combinedRequiredWitnesses.set(key, value); } for (const [key, value] of this.requiredWitnesses.entries()) { combinedRequiredWitnesses.set(key, value); } const dummyWitnesses = []; for (const [index] of Array.from(combinedRequiredWitnesses.keys()).entries()) { dummyWitnesses.push({ publicKey: buffer_1.Buffer.alloc(32, index), signature: buffer_1.Buffer.alloc(64), }); } const encodedWitnesses = (0, encoder_1.encodeWitnesses)(dummyWitnesses, this.inputs, this.plutusDataList, this.plutusScriptMap, this.nativeScriptList, this.mints); const scriptDataHash = (0, helpers_1.generateScriptDataHash)(this._protocolParams.languageView, encodedWitnesses, this._isPlutusV1Transaction, this._isPlutusV2Transaction, this._isPlutusV3Transaction); const encodedBody = this.encodeTransactionBody({ extraOutputs, scriptDataHash }); const transaction = [ encodedBody, encodedWitnesses, true, this.auxiliaryData ? (0, encoder_1.encodeAuxiliaryData)(this.auxiliaryData) : null, ]; const cborTrx = cbors.Encoder.encode(transaction); return cborTrx.length; } calculateFee(extraOutputs) { const txSize = this.calculateTxSize(extraOutputs); const txFee = this.transactionFee(txSize); const contractFee = this.contractFee(); // introduced in Conway era const refScriptFee = this.calculateRefScriptFee(); return txFee.plus(contractFee).plus(refScriptFee); } setFee(fee) { this.fee = fee; } getFee() { return this.fee; } calculateMinUtxoAmountBabbage(output) { return (0, utils_1.calculateMinUtxoAmountBabbage)(output, this._protocolParams.utxoCostPerByte); } addWitness(witness) { this.witnesses.push(witness); } getTransactionHash() { const encodedWitnesses = (0, encoder_1.encodeWitnesses)(this.witnesses, this.inputs, this.plutusDataList, this.plutusScriptMap, this.nativeScriptList, this.mints); const scriptDataHash = (0, helpers_1.generateScriptDataHash)(this._protocolParams.languageView, encodedWitnesses, this._isPlutusV1Transaction, this._isPlutusV2Transaction, this._isPlutusV3Transaction); const encodedBody = this.encodeTransactionBody({ scriptDataHash }); const cborBody = cbors.Encoder.encode(encodedBody); return (0, crypto_1.hash32)(cborBody); } getAuxiliaryData() { return this.auxiliaryData; } getAuxiliaryDataHashHex() { if (this.auxiliaryData) { const encodedAuxiliaryData = (0, encoder_1.encodeAuxiliaryData)(this.auxiliaryData); const auxiliaryDataCbor = cbors.Encoder.encode(encodedAuxiliaryData); return (0, crypto_1.hash32)(auxiliaryDataCbor).toString("hex"); } return undefined; } buildTransaction() { const encodedWitnesses = (0, encoder_1.encodeWitnesses)(this.witnesses, this.inputs, this.plutusDataList, this.plutusScriptMap, this.nativeScriptList, this.mints); const scriptDataHash = (0, helpers_1.generateScriptDataHash)(this._protocolParams.languageView, encodedWitnesses, this._isPlutusV1Transaction, this._isPlutusV2Transaction, this._isPlutusV3Transaction); const encodedBody = this.encodeTransactionBody({ scriptDataHash }); const transaction = [ encodedBody, encodedWitnesses, true, this.auxiliaryData ? (0, encoder_1.encodeAuxiliaryData)(this.auxiliaryData) : null, ]; const cborTrx = cbors.Encoder.encode(transaction); const trxBodyCbor = cbors.Encoder.encode(encodedBody); const hash = (0, crypto_1.hash32)(trxBodyCbor).toString("hex"); return { hash, payload: cborTrx.toString("hex"), }; } getInputs() { return this.inputs; } getCertificates() { return this.certificates; } getMints() { const tokens = []; for (const mint of this.mints) { for (const asset of mint.assets) { tokens.push({ policyId: mint.policyId, assetName: asset.assetName, amount: asset.amount, }); } } const sortedTokens = (0, helpers_1.sortTokens)(tokens); return (0, lodash_1.default)(sortedTokens) .groupBy((token) => token.policyId) .map((tokens, policyId) => ({ policyId, assets: tokens.map((t) => ({ assetName: t.assetName, amount: t.amount })), })) .value(); } getMintTokens() { const tokens = []; for (const mint of this.mints) { for (const asset of mint.assets) { if (asset.amount.isPositive()) { tokens.push({ policyId: mint.policyId, assetName: asset.assetName, amount: asset.amount, }); } } } return tokens; } getBurnTokens() { const tokens = []; for (const mint of this.mints) { for (const asset of mint.assets) { if (asset.amount.isNegative()) { tokens.push({ policyId: mint.policyId, assetName: asset.assetName, amount: asset.amount.abs(), }); } } } return tokens; } getInputAmount() { let inputTokens = []; let ada = new bignumber_js_1.default(0); lodash_1.default.forEach(this.inputs, (input) => { inputTokens = inputTokens.concat(input.tokens); ada = ada.plus(input.amount); }); inputTokens = lodash_1.default.concat(inputTokens, this.getMintTokens()); return { ada, tokens: (0, helpers_1.getUniqueTokens)(inputTokens), }; } getCollaterals() { return this.collaterals; } getScriptIntegrityHash() { const encodedWitnesses = (0, encoder_1.encodeWitnesses)(this.witnesses, this.inputs, this.plutusDataList, this.plutusScriptMap, this.nativeScriptList, this.mints); const scriptDataHash = (0, helpers_1.generateScriptDataHash)(this._protocolParams.languageView, encodedWitnesses, this._isPlutusV1Transaction, this._isPlutusV2Transaction, this._isPlutusV3Transaction); return scriptDataHash; } getCollateralAmount() { const ada = this.collaterals.reduce((sum, collateral) => sum.plus(collateral.amount), new bignumber_js_1.default(0)); return ada; } getOutputs() { return this.outputs; } getOutputAmount() { let outputTokens = []; let ada = new bignumber_js_1.default(0); lodash_1.default.forEach(this.outputs, (output) => { outputTokens = outputTokens.concat(output.tokens); ada = ada.plus(output.amount); }); outputTokens = lodash_1.default.concat(outputTokens, this.getBurnTokens()); return { ada, tokens: (0, helpers_1.getUniqueTokens)(outputTokens), }; } /** * This method scans the certificates and proposal procedures added in the transaction * to calculate additional ADA required for transaction validity. * 1. stake key registration deposit ADA * 2. proposal procedure deposit ADA * 3. donation amount * @returns additional ADA required for a valid transaction */ getAdditionalOutputAda() { const depositInCerts = lodash_1.default.reduce(this.certificates, (result, cert) => { if (cert.type === types_1.CertificateType.STAKE_REGISTRATION) { // legacy stake registration cert, use deposit value from protocol param return result.plus(this._protocolParams.stakeKeyDeposit); } if (cert.type === types_1.CertificateType.STAKE_KEY_REGISTRATION) { return result.plus(cert.cert.deposit); } return result; }, new bignumber_js_1.default(0)); const depositInProposalProcedure = lodash_1.default.reduce(this.proposalProcedures, (result, pp) => { return result.plus(pp.deposit); }, new bignumber_js_1.default(0)); const donationAmount = this.donationAmount || new bignumber_js_1.default(0); return depositInCerts.plus(depositInProposalProcedure).plus(donationAmount); } /** * This method scans the certificates added in the transaction to calculate * additional ADA available in inputs as part of the deposit refund. * Essentially ADA to be considered as additional input due to deposit refunds. * @returns additional ADA available as input */ getAdditionalInputAda() { const certDeposit = lodash_1.default.reduce(this.certificates, (result, cert) => { if (cert.type === types_1.CertificateType.STAKE_DE_REGISTRATION) { // legacy stake de registration certificate, use deposit value from protocol params return result.plus(this._protocolParams.stakeKeyDeposit); } if (cert.type === types_1.CertificateType.STAKE_KEY_DE_REGISTRATION) { return result.plus(cert.cert.deposit); } return result; }, new bignumber_js_1.default(0)); const withdrawalAda = lodash_1.default.reduce(this.withdrawals, (result, withdrawal) => { return result.plus(withdrawal.amount); }, new bignumber_js_1.default(0)); return certDeposit.plus(withdrawalAda); } getWithdrawals() { return this.withdrawals; } getRequiredWitnesses() { return this.requiredWitnesses; } getRequiredNativeScriptWitnesses() { return this.requiredNativeScriptWitnesses; } getRequiredSigners() { return this.requiredSigners; } getVotingProcedures() { return this.votingProcedures; } getProposalProcedures() { return this.proposalProcedures; } setAuxiliaryData(auxData) { this.auxiliaryData = auxData; } isPlutusTransaction() { return (this._isPlutusV1Transaction || this._isPlutusV2Transaction || this._isPlutusV3Transaction); } /** * Function to prepare transaction automatically * There are other helper methods for preparing transactions that use this method * This method should be used when you know what you are doing * sets required inputs, * fees, * change etc * resulting transaction is the final tx that can be built for signing */ prepareTransaction({ inputs, changeAddress, collateralInputs = [], }) { return (0, transactionBuilder_1.default)({ transaction: this, inputs, changeAddress, collateralInputs }); } /** * Function for a simple send ADA transaction * Provide necessary outputs, and available inputs, returns a final tx */ paymentTransaction({ inputs, outputs, changeAddress, auxiliaryData, ttl, }) { return (0, paymentTransaction_1.paymentTransaction)({ inputs, outputs, changeAddress, auxiliaryData, ttl, protocolParams: this.protocolParams, }); } } exports.Transaction = Transaction; exports.default = Transaction;