@kubectl/caminojs
Version:
Camino Platform JS Library
818 lines • 152 kB
JavaScript
"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