UNPKG

@kubectl/caminojs

Version:
818 lines 152 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.UTXOSet = exports.AssetAmountDestination = exports.UTXO = void 0; /** * @packageDocumentation * @module API-PlatformVM-UTXOs */ const buffer_1 = require("buffer/"); const bintools_1 = __importDefault(require("../../utils/bintools")); const bn_js_1 = __importDefault(require("bn.js")); const outputs_1 = require("./outputs"); const inputs_1 = require("./inputs"); const helperfunctions_1 = require("../../utils/helperfunctions"); const utxos_1 = require("../../common/utxos"); const constants_1 = require("./constants"); const tx_1 = require("./tx"); const exporttx_1 = require("../platformvm/exporttx"); const importtx_1 = require("../platformvm/importtx"); const basetx_1 = require("../platformvm/basetx"); const assetamount_1 = require("../../common/assetamount"); const validationtx_1 = require("./validationtx"); const createsubnettx_1 = require("./createsubnettx"); const serialization_1 = require("../../utils/serialization"); const errors_1 = require("../../utils/errors"); const constants_2 = require("../../utils/constants"); const networks_1 = __importDefault(require("../../utils/networks")); const _1 = require("."); const addsubnetvalidatortx_1 = require("../platformvm/addsubnetvalidatortx"); /** * @ignore */ const bintools = bintools_1.default.getInstance(); const serialization = serialization_1.Serialization.getInstance(); /** * Class for representing a single UTXO. */ class UTXO extends utxos_1.StandardUTXO { constructor() { super(...arguments); this._typeName = "UTXO"; this._typeID = undefined; } //serialize is inherited deserialize(fields, encoding = "hex") { super.deserialize(fields, encoding); this.output = (0, outputs_1.SelectOutputClass)(fields["output"]["_typeID"]); this.output.deserialize(fields["output"], encoding); } fromBuffer(bytes, offset = 0) { this.codecID = bintools.copyFrom(bytes, offset, offset + 2); offset += 2; this.txid = bintools.copyFrom(bytes, offset, offset + 32); offset += 32; this.outputidx = bintools.copyFrom(bytes, offset, offset + 4); offset += 4; this.assetID = bintools.copyFrom(bytes, offset, offset + 32); offset += 32; const outputid = bintools .copyFrom(bytes, offset, offset + 4) .readUInt32BE(0); offset += 4; this.output = (0, outputs_1.SelectOutputClass)(outputid); return this.output.fromBuffer(bytes, offset); } /** * Takes a base-58 string containing a [[UTXO]], parses it, populates the class, and returns the length of the StandardUTXO in bytes. * * @param serialized A base-58 string containing a raw [[UTXO]] * * @returns The length of the raw [[UTXO]] * * @remarks * unlike most fromStrings, it expects the string to be serialized in cb58 format */ fromString(serialized) { /* istanbul ignore next */ return this.fromBuffer(bintools.cb58Decode(serialized)); } /** * Returns a base-58 representation of the [[UTXO]]. * * @remarks * unlike most toStrings, this returns in cb58 serialization format */ toString() { /* istanbul ignore next */ return bintools.cb58Encode(this.toBuffer()); } clone() { const utxo = new UTXO(); utxo.fromBuffer(this.toBuffer()); return utxo; } create(codecID = constants_1.PlatformVMConstants.LATESTCODEC, txid = undefined, outputidx = undefined, assetID = undefined, output = undefined) { return new UTXO(codecID, txid, outputidx, assetID, output); } } exports.UTXO = UTXO; class AssetAmountDestination extends assetamount_1.StandardAssetAmountDestination { } exports.AssetAmountDestination = AssetAmountDestination; /** * Class representing a set of [[UTXO]]s. */ class UTXOSet extends utxos_1.StandardUTXOSet { constructor() { super(...arguments); this._typeName = "UTXOSet"; this._typeID = undefined; this.getConsumableUXTO = (asOf = (0, helperfunctions_1.UnixNow)(), stakeable = false) => { return this.getAllUTXOs().filter((utxo) => { if (stakeable) { // stakeable transactions can consume any UTXO. return true; } const output = utxo.getOutput(); if (!(output instanceof outputs_1.StakeableLockOut)) { // non-stakeable transactions can consume any UTXO that isn't locked. return true; } const stakeableOutput = output; if (stakeableOutput.getStakeableLocktime().lt(asOf)) { // If the stakeable outputs locktime has ended, then this UTXO can still // be consumed by a non-stakeable transaction. return true; } // This output is locked and can't be consumed by a non-stakeable // transaction. return false; }); }; this.getMinimumSpendable = (aad, asOf = (0, helperfunctions_1.UnixNow)(), locktime = new bn_js_1.default(0), threshold = 1, stakeable = false) => { let utxoArray = this.getConsumableUXTO(asOf, stakeable); let tmpUTXOArray = []; if (stakeable) { // If this is a stakeable transaction then have StakeableLockOut come before SECPTransferOutput // so that users first stake locked tokens before staking unlocked tokens utxoArray.forEach((utxo) => { // StakeableLockOuts if (utxo.getOutput().getTypeID() === 22) { tmpUTXOArray.push(utxo); } }); // Sort the StakeableLockOuts by StakeableLocktime so that the greatest StakeableLocktime are spent first tmpUTXOArray.sort((a, b) => { let stakeableLockOut1 = a.getOutput(); let stakeableLockOut2 = b.getOutput(); return (stakeableLockOut2.getStakeableLocktime().toNumber() - stakeableLockOut1.getStakeableLocktime().toNumber()); }); utxoArray.forEach((utxo) => { // SECPTransferOutputs if (utxo.getOutput().getTypeID() === 7) { tmpUTXOArray.push(utxo); } }); utxoArray = tmpUTXOArray; } // outs is a map from assetID to a tuple of (lockedStakeable, unlocked) // which are arrays of outputs. const outs = {}; // We only need to iterate over UTXOs until we have spent sufficient funds // to met the requested amounts. utxoArray.forEach((utxo, index) => { const assetID = utxo.getAssetID(); const assetKey = assetID.toString("hex"); const fromAddresses = aad.getSenders(); const output = utxo.getOutput(); if (!(output instanceof outputs_1.AmountOutput) || !aad.assetExists(assetKey) || !output.meetsThreshold(fromAddresses, asOf)) { // We should only try to spend fungible assets. // We should only spend {{ assetKey }}. // We need to be able to spend the output. return; } const assetAmount = aad.getAssetAmount(assetKey); if (assetAmount.isFinished()) { // We've already spent the needed UTXOs for this assetID. return; } if (!(assetKey in outs)) { // If this is the first time spending this assetID, we need to // initialize the outs object correctly. outs[`${assetKey}`] = { lockedStakeable: [], unlocked: [] }; } const amountOutput = output; // amount is the amount of funds available from this UTXO. const amount = amountOutput.getAmount(); // Set up the SECP input with the same amount as the output. let input = new inputs_1.SECPTransferInput(amount); let locked = false; if (amountOutput instanceof outputs_1.StakeableLockOut) { const stakeableOutput = amountOutput; const stakeableLocktime = stakeableOutput.getStakeableLocktime(); if (stakeableLocktime.gt(asOf)) { // Add a new input and mark it as being locked. input = new inputs_1.StakeableLockIn(amount, stakeableLocktime, new inputs_1.ParseableInput(input)); // Mark this UTXO as having been re-locked. locked = true; } } assetAmount.spendAmount(amount, locked); if (locked) { // Track the UTXO as locked. outs[`${assetKey}`].lockedStakeable.push(amountOutput); } else { // Track the UTXO as unlocked. outs[`${assetKey}`].unlocked.push(amountOutput); } // Get the indices of the outputs that should be used to authorize the // spending of this input. // TODO: getSpenders should return an array of indices rather than an // array of addresses. const spenders = amountOutput.getSpenders(fromAddresses, asOf); spenders.forEach((spender) => { const idx = amountOutput.getAddressIdx(spender); if (idx === -1) { // This should never happen, which is why the error is thrown rather // than being returned. If this were to ever happen this would be an // error in the internal logic rather having called this function with // invalid arguments. /* istanbul ignore next */ throw new errors_1.AddressError("Error - UTXOSet.getMinimumSpendable: no such " + `address in output: ${spender}`); } input.addSignatureIdx(idx, spender); }); const txID = utxo.getTxID(); const outputIdx = utxo.getOutputIdx(); const transferInput = new inputs_1.TransferableInput(txID, outputIdx, assetID, input); aad.addInput(transferInput); }); if (!aad.canComplete()) { // After running through all the UTXOs, we still weren't able to get all // the necessary funds, so this transaction can't be made. return new errors_1.InsufficientFundsError("Error - UTXOSet.getMinimumSpendable: insufficient " + "funds to create the transaction"); } // TODO: We should separate the above functionality into a single function // that just selects the UTXOs to consume. const zero = new bn_js_1.default(0); // assetAmounts is an array of asset descriptions and how much is left to // spend for them. const assetAmounts = aad.getAmounts(); assetAmounts.forEach((assetAmount) => { // change is the amount that should be returned back to the source of the // funds. const change = assetAmount.getChange(); // isStakeableLockChange is if the change is locked or not. const isStakeableLockChange = assetAmount.getStakeableLockChange(); // lockedChange is the amount of locked change that should be returned to // the sender const lockedChange = isStakeableLockChange ? change : zero.clone(); const assetID = assetAmount.getAssetID(); const assetKey = assetAmount.getAssetIDString(); const lockedOutputs = outs[`${assetKey}`].lockedStakeable; lockedOutputs.forEach((lockedOutput, i) => { const stakeableLocktime = lockedOutput.getStakeableLocktime(); const parseableOutput = lockedOutput.getTransferableOutput(); // We know that parseableOutput contains an AmountOutput because the // first loop filters for fungible assets. const output = parseableOutput.getOutput(); let outputAmountRemaining = output.getAmount(); // The only output that could generate change is the last output. // Otherwise, any further UTXOs wouldn't have needed to be spent. if (i == lockedOutputs.length - 1 && lockedChange.gt(zero)) { // update outputAmountRemaining to no longer hold the change that we // are returning. outputAmountRemaining = outputAmountRemaining.sub(lockedChange); // Create the inner output. const newChangeOutput = (0, outputs_1.SelectOutputClass)(output.getOutputID(), lockedChange, output.getAddresses(), output.getLocktime(), output.getThreshold()); // Wrap the inner output in the StakeableLockOut wrapper. let newLockedChangeOutput = (0, outputs_1.SelectOutputClass)(lockedOutput.getOutputID(), lockedChange, output.getAddresses(), output.getLocktime(), output.getThreshold(), stakeableLocktime, new outputs_1.ParseableOutput(newChangeOutput)); const transferOutput = new outputs_1.TransferableOutput(assetID, newLockedChangeOutput); aad.addChange(transferOutput); } // We know that outputAmountRemaining > 0. Otherwise, we would never // have consumed this UTXO, as it would be only change. // Create the inner output. const newOutput = (0, outputs_1.SelectOutputClass)(output.getOutputID(), outputAmountRemaining, output.getAddresses(), output.getLocktime(), output.getThreshold()); // Wrap the inner output in the StakeableLockOut wrapper. const newLockedOutput = (0, outputs_1.SelectOutputClass)(lockedOutput.getOutputID(), outputAmountRemaining, output.getAddresses(), output.getLocktime(), output.getThreshold(), stakeableLocktime, new outputs_1.ParseableOutput(newOutput)); const transferOutput = new outputs_1.TransferableOutput(assetID, newLockedOutput); aad.addOutput(transferOutput); }); // unlockedChange is the amount of unlocked change that should be returned // to the sender const unlockedChange = isStakeableLockChange ? zero.clone() : change; if (unlockedChange.gt(zero)) { const newChangeOutput = new outputs_1.SECPTransferOutput(unlockedChange, aad.getChangeAddresses(), zero.clone(), // make sure that we don't lock the change output. threshold); const transferOutput = new outputs_1.TransferableOutput(assetID, newChangeOutput); aad.addChange(transferOutput); } // totalAmountSpent is the total amount of tokens consumed. const totalAmountSpent = assetAmount.getSpent(); // stakeableLockedAmount is the total amount of locked tokens consumed. const stakeableLockedAmount = assetAmount.getStakeableLockSpent(); // totalUnlockedSpent is the total amount of unlocked tokens consumed. const totalUnlockedSpent = totalAmountSpent.sub(stakeableLockedAmount); // amountBurnt is the amount of unlocked tokens that must be burn. const amountBurnt = assetAmount.getBurn(); // totalUnlockedAvailable is the total amount of unlocked tokens available // to be produced. const totalUnlockedAvailable = totalUnlockedSpent.sub(amountBurnt); // unlockedAmount is the amount of unlocked tokens that should be sent. const unlockedAmount = totalUnlockedAvailable.sub(unlockedChange); if (unlockedAmount.gt(zero)) { const newOutput = new outputs_1.SECPTransferOutput(unlockedAmount, aad.getDestinations(), locktime, threshold); const transferOutput = new outputs_1.TransferableOutput(assetID, newOutput); aad.addOutput(transferOutput); } }); return undefined; }; /** * Creates an [[UnsignedTx]] wrapping a [[BaseTx]]. For more granular control, you may create your own * [[UnsignedTx]] wrapping a [[BaseTx]] manually (with their corresponding [[TransferableInput]]s and [[TransferableOutput]]s). * * @param networkID The number representing NetworkID of the node * @param blockchainID The {@link https://github.com/feross/buffer|Buffer} representing the BlockchainID for the transaction * @param amount The amount of the asset to be spent in its smallest denomination, represented as {@link https://github.com/indutny/bn.js/|BN}. * @param assetID {@link https://github.com/feross/buffer|Buffer} of the asset ID for the UTXO * @param toAddresses The addresses to send the funds * @param fromAddresses The addresses being used to send the funds from the UTXOs {@link https://github.com/feross/buffer|Buffer} * @param changeAddresses Optional. The addresses that can spend the change remaining from the spent UTXOs. Default: toAddresses * @param fee Optional. The amount of fees to burn in its smallest denomination, represented as {@link https://github.com/indutny/bn.js/|BN} * @param feeAssetID Optional. The assetID of the fees being burned. Default: assetID * @param memo Optional. Contains arbitrary data, up to 256 bytes * @param asOf Optional. The timestamp to verify the transaction against as a {@link https://github.com/indutny/bn.js/|BN} * @param locktime Optional. The locktime field created in the resulting outputs * @param threshold Optional. The number of signatures required to spend the funds in the resultant UTXO * * @returns An unsigned transaction created from the passed in parameters. * */ this.buildBaseTx = (networkID, blockchainID, amount, assetID, toAddresses, fromAddresses, changeAddresses = undefined, fee = undefined, feeAssetID = undefined, memo = undefined, asOf = (0, helperfunctions_1.UnixNow)(), locktime = new bn_js_1.default(0), threshold = 1) => { if (threshold > toAddresses.length) { /* istanbul ignore next */ throw new errors_1.ThresholdError("Error - UTXOSet.buildBaseTx: threshold is greater than number of addresses"); } if (typeof changeAddresses === "undefined") { changeAddresses = toAddresses; } if (typeof feeAssetID === "undefined") { feeAssetID = assetID; } const zero = new bn_js_1.default(0); if (amount.eq(zero)) { return undefined; } const aad = new AssetAmountDestination(toAddresses, fromAddresses, changeAddresses); if (assetID.toString("hex") === feeAssetID.toString("hex")) { aad.addAssetAmount(assetID, amount, fee); } else { aad.addAssetAmount(assetID, amount, zero); if (this._feeCheck(fee, feeAssetID)) { aad.addAssetAmount(feeAssetID, zero, fee); } } let ins = []; let outs = []; const minSpendableErr = this.getMinimumSpendable(aad, asOf, locktime, threshold); if (typeof minSpendableErr === "undefined") { ins = aad.getInputs(); outs = aad.getAllOutputs(); } else { throw minSpendableErr; } const baseTx = new basetx_1.BaseTx(networkID, blockchainID, outs, ins, memo); return new tx_1.UnsignedTx(baseTx); }; /** * Creates an unsigned ImportTx transaction. * * @param networkID The number representing NetworkID of the node * @param blockchainID The {@link https://github.com/feross/buffer|Buffer} representing the BlockchainID for the transaction * @param toAddresses The addresses to send the funds * @param fromAddresses The addresses being used to send the funds from the UTXOs {@link https://github.com/feross/buffer|Buffer} * @param changeAddresses Optional. The addresses that can spend the change remaining from the spent UTXOs. Default: toAddresses * @param importIns An array of [[TransferableInput]]s being imported * @param sourceChain A {@link https://github.com/feross/buffer|Buffer} for the chainid where the imports are coming from. * @param fee Optional. The amount of fees to burn in its smallest denomination, represented as {@link https://github.com/indutny/bn.js/|BN}. Fee will come from the inputs first, if they can. * @param feeAssetID Optional. The assetID of the fees being burned. * @param memo Optional contains arbitrary bytes, up to 256 bytes * @param asOf Optional. The timestamp to verify the transaction against as a {@link https://github.com/indutny/bn.js/|BN} * @param locktime Optional. The locktime field created in the resulting outputs * @param threshold Optional. The number of signatures required to spend the funds in the resultant UTXO * @returns An unsigned transaction created from the passed in parameters. * */ this.buildImportTx = (networkID, blockchainID, toAddresses, fromAddresses, changeAddresses, atomics, sourceChain = undefined, fee = undefined, feeAssetID = undefined, memo = undefined, asOf = (0, helperfunctions_1.UnixNow)(), locktime = new bn_js_1.default(0), threshold = 1) => { const zero = new bn_js_1.default(0); let ins = []; let outs = []; if (typeof fee === "undefined") { fee = zero.clone(); } const importIns = []; let feepaid = new bn_js_1.default(0); let feeAssetStr = feeAssetID.toString("hex"); for (let i = 0; i < atomics.length; i++) { const utxo = atomics[`${i}`]; const assetID = utxo.getAssetID(); const output = utxo.getOutput(); let amt = output.getAmount().clone(); let infeeamount = amt.clone(); let assetStr = assetID.toString("hex"); if (typeof feeAssetID !== "undefined" && fee.gt(zero) && feepaid.lt(fee) && assetStr === feeAssetStr) { feepaid = feepaid.add(infeeamount); if (feepaid.gte(fee)) { infeeamount = feepaid.sub(fee); feepaid = fee.clone(); } else { infeeamount = zero.clone(); } } const txid = utxo.getTxID(); const outputidx = utxo.getOutputIdx(); const input = new inputs_1.SECPTransferInput(amt); const xferin = new inputs_1.TransferableInput(txid, outputidx, assetID, input); const from = output.getAddresses(); const spenders = output.getSpenders(from, asOf); for (let j = 0; j < spenders.length; j++) { const idx = output.getAddressIdx(spenders[`${j}`]); if (idx === -1) { /* istanbul ignore next */ throw new errors_1.AddressError("Error - UTXOSet.buildImportTx: no such " + `address in output: ${spenders[`${j}`]}`); } xferin.getInput().addSignatureIdx(idx, spenders[`${j}`]); } importIns.push(xferin); //add extra outputs for each amount (calculated from the imported inputs), minus fees if (infeeamount.gt(zero)) { const spendout = (0, outputs_1.SelectOutputClass)(output.getOutputID(), infeeamount, toAddresses, locktime, threshold); const xferout = new outputs_1.TransferableOutput(assetID, spendout); outs.push(xferout); } } // get remaining fees from the provided addresses let feeRemaining = fee.sub(feepaid); if (feeRemaining.gt(zero) && this._feeCheck(feeRemaining, feeAssetID)) { const aad = new AssetAmountDestination(toAddresses, fromAddresses, changeAddresses); aad.addAssetAmount(feeAssetID, zero, feeRemaining); const minSpendableErr = this.getMinimumSpendable(aad, asOf, locktime, threshold); if (typeof minSpendableErr === "undefined") { ins = aad.getInputs(); outs = aad.getAllOutputs(); } else { throw minSpendableErr; } } const importTx = new importtx_1.ImportTx(networkID, blockchainID, outs, ins, memo, sourceChain, importIns); return new tx_1.UnsignedTx(importTx); }; /** * Creates an unsigned ExportTx transaction. * * @param networkID The number representing NetworkID of the node * @param blockchainID The {@link https://github.com/feross/buffer|Buffer} representing the BlockchainID for the transaction * @param amount The amount being exported as a {@link https://github.com/indutny/bn.js/|BN} * @param avaxAssetID {@link https://github.com/feross/buffer|Buffer} of the asset ID for AVAX * @param toAddresses An array of addresses as {@link https://github.com/feross/buffer|Buffer} who recieves the AVAX * @param fromAddresses An array of addresses as {@link https://github.com/feross/buffer|Buffer} who owns the AVAX * @param changeAddresses An array of addresses as {@link https://github.com/feross/buffer|Buffer} who gets the change leftover of the AVAX * @param destinationChain Optional. A {@link https://github.com/feross/buffer|Buffer} for the chainid where to send the asset. * @param fee Optional. The amount of fees to burn in its smallest denomination, represented as {@link https://github.com/indutny/bn.js/|BN} * @param feeAssetID Optional. The assetID of the fees being burned. * @param memo Optional contains arbitrary bytes, up to 256 bytes * @param asOf Optional. The timestamp to verify the transaction against as a {@link https://github.com/indutny/bn.js/|BN} * @param locktime Optional. The locktime field created in the resulting outputs * @param threshold Optional. The number of signatures required to spend the funds in the resultant UTXO * * @returns An unsigned transaction created from the passed in parameters. * */ this.buildExportTx = (networkID, blockchainID, amount, avaxAssetID, // TODO: rename this to amountAssetID toAddresses, fromAddresses, changeAddresses = undefined, destinationChain = undefined, fee = undefined, feeAssetID = undefined, memo = undefined, asOf = (0, helperfunctions_1.UnixNow)(), locktime = new bn_js_1.default(0), threshold = 1) => { let ins = []; let outs = []; let exportouts = []; if (typeof changeAddresses === "undefined") { changeAddresses = toAddresses; } const zero = new bn_js_1.default(0); if (amount.eq(zero)) { return undefined; } if (typeof feeAssetID === "undefined") { feeAssetID = avaxAssetID; } else if (feeAssetID.toString("hex") !== avaxAssetID.toString("hex")) { /* istanbul ignore next */ throw new errors_1.FeeAssetError("Error - UTXOSet.buildExportTx: " + `feeAssetID must match avaxAssetID`); } if (typeof destinationChain === "undefined") { destinationChain = bintools.cb58Decode(networks_1.default.getNetwork(networkID).X.blockchainID); } const aad = new AssetAmountDestination(toAddresses, fromAddresses, changeAddresses); if (avaxAssetID.toString("hex") === feeAssetID.toString("hex")) { aad.addAssetAmount(avaxAssetID, amount, fee); } else { aad.addAssetAmount(avaxAssetID, amount, zero); if (this._feeCheck(fee, feeAssetID)) { aad.addAssetAmount(feeAssetID, zero, fee); } } const minSpendableErr = this.getMinimumSpendable(aad, asOf, locktime, threshold); if (typeof minSpendableErr === "undefined") { ins = aad.getInputs(); outs = aad.getChangeOutputs(); exportouts = aad.getOutputs(); } else { throw minSpendableErr; } const exportTx = new exporttx_1.ExportTx(networkID, blockchainID, outs, ins, memo, destinationChain, exportouts); return new tx_1.UnsignedTx(exportTx); }; /** * Class representing an unsigned [[AddSubnetValidatorTx]] transaction. * * @param networkID Networkid, [[DefaultNetworkID]] * @param blockchainID Blockchainid, default undefined * @param fromAddresses An array of addresses as {@link https://github.com/feross/buffer|Buffer} who pays the fees in AVAX * @param changeAddresses An array of addresses as {@link https://github.com/feross/buffer|Buffer} who gets the change leftover from the fee payment * @param nodeID The node ID of the validator being added. * @param startTime The Unix time when the validator starts validating the Primary Network. * @param endTime The Unix time when the validator stops validating the Primary Network (and staked AVAX is returned). * @param weight The amount of weight for this subnet validator. * @param fee Optional. The amount of fees to burn in its smallest denomination, represented as {@link https://github.com/indutny/bn.js/|BN} * @param feeAssetID Optional. The assetID of the fees being burned. * @param memo Optional contains arbitrary bytes, up to 256 bytes * @param asOf Optional. The timestamp to verify the transaction against as a {@link https://github.com/indutny/bn.js/|BN} * @param subnetAuthCredentials Optional. An array of index and address to sign for each SubnetAuth. * * @returns An unsigned transaction created from the passed in parameters. */ this.buildAddSubnetValidatorTx = (networkID = constants_2.DefaultNetworkID, blockchainID, fromAddresses, changeAddresses, nodeID, startTime, endTime, weight, subnetID, fee = undefined, feeAssetID = undefined, memo = undefined, asOf = (0, helperfunctions_1.UnixNow)(), subnetAuthCredentials = []) => { let ins = []; let outs = []; const zero = new bn_js_1.default(0); const now = (0, helperfunctions_1.UnixNow)(); if (startTime.lt(now) || endTime.lte(startTime)) { throw new Error("UTXOSet.buildAddSubnetValidatorTx -- startTime must be in the future and endTime must come after startTime"); } if (this._feeCheck(fee, feeAssetID)) { const aad = new AssetAmountDestination(fromAddresses, fromAddresses, changeAddresses); aad.addAssetAmount(feeAssetID, zero, fee); const success = this.getMinimumSpendable(aad, asOf, undefined, undefined, true); if (typeof success === "undefined") { ins = aad.getInputs(); outs = aad.getAllOutputs(); } else { throw success; } } const addSubnetValidatorTx = new addsubnetvalidatortx_1.AddSubnetValidatorTx(networkID, blockchainID, outs, ins, memo, nodeID, startTime, endTime, weight, subnetID); subnetAuthCredentials.forEach((subnetAuthCredential) => { addSubnetValidatorTx.addSignatureIdx(subnetAuthCredential[0], subnetAuthCredential[1]); }); return new tx_1.UnsignedTx(addSubnetValidatorTx); }; /** * Class representing an unsigned [[AddDelegatorTx]] transaction. * * @param networkID Networkid, [[DefaultNetworkID]] * @param blockchainID Blockchainid, default undefined * @param avaxAssetID {@link https://github.com/feross/buffer|Buffer} of the asset ID for AVAX * @param toAddresses An array of addresses as {@link https://github.com/feross/buffer|Buffer} recieves the stake at the end of the staking period * @param fromAddresses An array of addresses as {@link https://github.com/feross/buffer|Buffer} who pays the fees and the stake * @param changeAddresses An array of addresses as {@link https://github.com/feross/buffer|Buffer} who gets the change leftover from the staking payment * @param nodeID The node ID of the validator being added. * @param startTime The Unix time when the validator starts validating the Primary Network. * @param endTime The Unix time when the validator stops validating the Primary Network (and staked AVAX is returned). * @param stakeAmount A {@link https://github.com/indutny/bn.js/|BN} for the amount of stake to be delegated in nAVAX. * @param rewardLocktime The locktime field created in the resulting reward outputs * @param rewardThreshold The number of signatures required to spend the funds in the resultant reward UTXO * @param rewardAddresses The addresses the validator reward goes. * @param fee Optional. The amount of fees to burn in its smallest denomination, represented as {@link https://github.com/indutny/bn.js/|BN} * @param feeAssetID Optional. The assetID of the fees being burned. * @param memo Optional contains arbitrary bytes, up to 256 bytes * @param asOf Optional. The timestamp to verify the transaction against as a {@link https://github.com/indutny/bn.js/|BN} * @param changeThreshold Optional. The number of signatures required to spend the funds in the change UTXO * * @returns An unsigned transaction created from the passed in parameters. */ this.buildAddDelegatorTx = (networkID = constants_2.DefaultNetworkID, blockchainID, avaxAssetID, toAddresses, fromAddresses, changeAddresses, nodeID, startTime, endTime, stakeAmount, rewardLocktime, rewardThreshold, rewardAddresses, fee = undefined, feeAssetID = undefined, memo = undefined, asOf = (0, helperfunctions_1.UnixNow)(), changeThreshold = 1) => { if (rewardThreshold > rewardAddresses.length) { /* istanbul ignore next */ throw new errors_1.ThresholdError("Error - UTXOSet.buildAddDelegatorTx: reward threshold is greater than number of addresses"); } if (typeof changeAddresses === "undefined") { changeAddresses = toAddresses; } let ins = []; let outs = []; let stakeOuts = []; const zero = new bn_js_1.default(0); const now = (0, helperfunctions_1.UnixNow)(); if (startTime.lt(now) || endTime.lte(startTime)) { throw new errors_1.TimeError("UTXOSet.buildAddDelegatorTx -- startTime must be in the future and endTime must come after startTime"); } const aad = new AssetAmountDestination(toAddresses, fromAddresses, changeAddresses); if (avaxAssetID.toString("hex") === feeAssetID.toString("hex")) { aad.addAssetAmount(avaxAssetID, stakeAmount, fee); } else { aad.addAssetAmount(avaxAssetID, stakeAmount, zero); if (this._feeCheck(fee, feeAssetID)) { aad.addAssetAmount(feeAssetID, zero, fee); } } const minSpendableErr = this.getMinimumSpendable(aad, asOf, undefined, changeThreshold, true); if (typeof minSpendableErr === "undefined") { ins = aad.getInputs(); outs = aad.getChangeOutputs(); stakeOuts = aad.getOutputs(); } else { throw minSpendableErr; } const rewardOutputOwners = new outputs_1.SECPOwnerOutput(rewardAddresses, rewardLocktime, rewardThreshold); const UTx = new validationtx_1.AddDelegatorTx(networkID, blockchainID, outs, ins, memo, nodeID, startTime, endTime, stakeAmount, stakeOuts, new outputs_1.ParseableOutput(rewardOutputOwners)); return new tx_1.UnsignedTx(UTx); }; /** * Class representing an unsigned [[AddValidatorTx]] transaction. * * @param networkID NetworkID, [[DefaultNetworkID]] * @param blockchainID BlockchainID, default undefined * @param avaxAssetID {@link https://github.com/feross/buffer|Buffer} of the asset ID for AVAX * @param toAddresses An array of addresses as {@link https://github.com/feross/buffer|Buffer} recieves the stake at the end of the staking period * @param fromAddresses An array of addresses as {@link https://github.com/feross/buffer|Buffer} who pays the fees and the stake * @param changeAddresses An array of addresses as {@link https://github.com/feross/buffer|Buffer} who gets the change leftover from the staking payment * @param nodeID The node ID of the validator being added. * @param startTime The Unix time when the validator starts validating the Primary Network. * @param endTime The Unix time when the validator stops validating the Primary Network (and staked AVAX is returned). * @param stakeAmount A {@link https://github.com/indutny/bn.js/|BN} for the amount of stake to be delegated in nAVAX. * @param rewardLocktime The locktime field created in the resulting reward outputs * @param rewardThreshold The number of signatures required to spend the funds in the resultant reward UTXO * @param rewardAddresses The addresses the validator reward goes. * @param delegationFee A number for the percentage of reward to be given to the validator when someone delegates to them. Must be between 0 and 100. * @param minStake A {@link https://github.com/indutny/bn.js/|BN} representing the minimum stake required to validate on this network. * @param fee Optional. The amount of fees to burn in its smallest denomination, represented as {@link https://github.com/indutny/bn.js/|BN} * @param feeAssetID Optional. The assetID of the fees being burned. * @param memo Optional contains arbitrary bytes, up to 256 bytes * @param asOf Optional. The timestamp to verify the transaction against as a {@link https://github.com/indutny/bn.js/|BN} * * @returns An unsigned transaction created from the passed in parameters. */ this.buildAddValidatorTx = (networkID = constants_2.DefaultNetworkID, blockchainID, avaxAssetID, toAddresses, fromAddresses, changeAddresses, nodeID, startTime, endTime, stakeAmount, rewardLocktime, rewardThreshold, rewardAddresses, delegationFee, fee = undefined, feeAssetID = undefined, memo = undefined, asOf = (0, helperfunctions_1.UnixNow)()) => { let ins = []; let outs = []; let stakeOuts = []; const zero = new bn_js_1.default(0); const now = (0, helperfunctions_1.UnixNow)(); if (startTime.lt(now) || endTime.lte(startTime)) { throw new errors_1.TimeError("UTXOSet.buildAddValidatorTx -- startTime must be in the future and endTime must come after startTime"); } if (delegationFee > 100 || delegationFee < 0) { throw new errors_1.TimeError("UTXOSet.buildAddValidatorTx -- startTime must be in the range of 0 to 100, inclusively"); } const aad = new AssetAmountDestination(toAddresses, fromAddresses, changeAddresses); if (avaxAssetID.toString("hex") === feeAssetID.toString("hex")) { aad.addAssetAmount(avaxAssetID, stakeAmount, fee); } else { aad.addAssetAmount(avaxAssetID, stakeAmount, zero); if (this._feeCheck(fee, feeAssetID)) { aad.addAssetAmount(feeAssetID, zero, fee); } } const minSpendableErr = this.getMinimumSpendable(aad, asOf, undefined, undefined, true); if (typeof minSpendableErr === "undefined") { ins = aad.getInputs(); outs = aad.getChangeOutputs(); stakeOuts = aad.getOutputs(); } else { throw minSpendableErr; } const rewardOutputOwners = new outputs_1.SECPOwnerOutput(rewardAddresses, rewardLocktime, rewardThreshold); const UTx = new validationtx_1.AddValidatorTx(networkID, blockchainID, outs, ins, memo, nodeID, startTime, endTime, stakeAmount, stakeOuts, new outputs_1.ParseableOutput(rewardOutputOwners), delegationFee); return new tx_1.UnsignedTx(UTx); }; /** * Class representing an unsigned [[CreateSubnetTx]] transaction. * * @param networkID Networkid, [[DefaultNetworkID]] * @param blockchainID Blockchainid, default undefined * @param fromAddresses The addresses being used to send the funds from the UTXOs {@link https://github.com/feross/buffer|Buffer} * @param changeAddresses The addresses that can spend the change remaining from the spent UTXOs. * @param subnetOwnerAddresses An array of {@link https://github.com/feross/buffer|Buffer} for the addresses to add to a subnet * @param subnetOwnerThreshold The number of owners's signatures required to add a validator to the network * @param fee Optional. The amount of fees to burn in its smallest denomination, represented as {@link https://github.com/indutny/bn.js/|BN} * @param feeAssetID Optional. The assetID of the fees being burned * @param memo Optional contains arbitrary bytes, up to 256 bytes * @param asOf Optional. The timestamp to verify the transaction against as a {@link https://github.com/indutny/bn.js/|BN} * * @returns An unsigned transaction created from the passed in parameters. */ this.buildCreateSubnetTx = (networkID = constants_2.DefaultNetworkID, blockchainID, fromAddresses, changeAddresses, subnetOwnerAddresses, subnetOwnerThreshold, fee = undefined, feeAssetID = undefined, memo = undefined, asOf = (0, helperfunctions_1.UnixNow)()) => { const zero = new bn_js_1.default(0); let ins = []; let outs = []; if (this._feeCheck(fee, feeAssetID)) { const aad = new AssetAmountDestination(fromAddresses, fromAddresses, changeAddresses); aad.addAssetAmount(feeAssetID, zero, fee); const minSpendableErr = this.getMinimumSpendable(aad, asOf, undefined, undefined); if (typeof minSpendableErr === "undefined") { ins = aad.getInputs(); outs = aad.getAllOutputs(); } else { throw minSpendableErr; } } const locktime = new bn_js_1.default(0); const subnetOwners = new outputs_1.SECPOwnerOutput(subnetOwnerAddresses, locktime, subnetOwnerThreshold); const createSubnetTx = new createsubnettx_1.CreateSubnetTx(networkID, blockchainID, outs, ins, memo, subnetOwners); return new tx_1.UnsignedTx(createSubnetTx); }; /** * Build an unsigned [[CreateChainTx]]. * * @param networkID Networkid, [[DefaultNetworkID]] * @param blockchainID Blockchainid, default undefined * @param fromAddresses The addresses being used to send the funds from the UTXOs {@link https://github.com/feross/buffer|Buffer} * @param changeAddresses The addresses that can spend the change remaining from the spent UTXOs. * @param subnetID Optional ID of the Subnet that validates this blockchain * @param chainName Optional A human readable name for the chain; need not be unique * @param vmID Optional ID of the VM running on the new chain * @param fxIDs Optional IDs of the feature extensions running on the new chain * @param genesisData Optional Byte representation of genesis state of the new chain * @param fee Optional. The amount of fees to burn in its smallest denomination, represented as {@link https://github.com/indutny/bn.js/|BN} * @param feeAssetID Optional. The assetID of the fees being burned * @param memo Optional contains arbitrary bytes, up to 256 bytes * @param asOf Optional. The timestamp to verify the transaction against as a {@link https://github.com/indutny/bn.js/|BN} * @param subnetAuthCredentials Optional. An array of index and address to sign for each SubnetAuth. * * @returns An unsigned CreateChainTx created from the passed in parameters. */ this.buildCreateChainTx = (networkID = constants_2.DefaultNetworkID, blockchainID, fromAddresses, changeAddresses, subnetID = undefined, chainName = undefined, vmID = undefined, fxIDs = undefined, genesisData = undefined, fee = undefined, feeAssetID = undefined, memo = undefined, asOf = (0, helperfunctions_1.UnixNow)(), subnetAuthCredentials = []) => { const zero = new bn_js_1.default(0); let ins = []; let outs = []; if (this._feeCheck(fee, feeAssetID)) { const aad = new AssetAmountDestination(fromAddresses, fromAddresses, changeAddresses); aad.addAssetAmount(feeAssetID, zero, fee); const minSpendableErr = this.getMinimumSpendable(aad, asOf, undefined, undefined); if (typeof minSpendableErr === "undefined") { ins = aad.getInputs(); outs = aad.getAllOutputs(); } else { throw minSpendableErr; } } const createChainTx = new _1.CreateChainTx(networkID, blockchainID, outs, ins, memo, subnetID, chainName, vmID, fxIDs, genesisData); subnetAuthCredentials.forEach((subnetAuthCredential) => { createChainTx.addSignatureIdx(subnetAuthCredential[0], subnetAuthCredential[1]); }); return new tx_1.UnsignedTx(createChainTx); }; } //serialize is inherited deserialize(fields, encoding = "hex") { super.deserialize(fields, encoding); let utxos = {}; for (let utxoid in fields["utxos"]) { let utxoidCleaned = serialization.decoder(utxoid, encoding, "base58", "base58"); utxos[`${utxoidCleaned}`] = new UTXO(); utxos[`${utxoidCleaned}`].deserialize(fields["utxos"][`${utxoid}`], encoding); } let addressUTXOs = {}; for (let address in fields["addressUTXOs"]) { let addressCleaned = serialization.decoder(address, encoding, "cb58", "hex"); let utxobalance = {}; for (let utxoid in fields["addressUTXOs"][`${address}`]) { let utxoidCleaned = serialization.decoder(utxoid, encoding, "base58", "base58"); utxobalance[`${utxoidCleaned}`] = serialization.decoder(fields["addressUTXOs"][`${address}`][`${utxoid}`], encoding, "decimalString", "BN"); } addressUTXOs[`${addressCleaned}`] = utxobalance; } this.utxos = utxos; this.addressUTXOs = addressUTXOs; } parseUTXO(utxo) { const utxovar = new UTXO(); // force a copy if (typeof utxo === "string") { utxovar.fromBuffer(bintools.cb58Decode(utxo)); } else if (utxo instanceof utxos_1.StandardUTXO) { utxovar.fromBuffer(utxo.toBuffer()); // forces a copy } else { /* istanbul ignore next */ throw new err