@hashgraph/sdk
Version:
699 lines (698 loc) • 25.2 kB
TypeScript
/**
* @typedef {import("bignumber.js").default} BigNumber
*/
/**
* @typedef {import("../schedule/ScheduleCreateTransaction.js").default} ScheduleCreateTransaction
* @typedef {import("../PrivateKey.js").default} PrivateKey
* @typedef {import("../channel/Channel.js").default} Channel
* @typedef {import("../client/Client.js").default<*, *>} Client
* @typedef {import("../Signer.js").Signer} Signer
*/
export const DEFAULT_AUTO_RENEW_PERIOD: Long;
export const DEFAULT_RECORD_THRESHOLD: Hbar;
export const CHUNK_SIZE: 1024;
/**
* @type {Map<NonNullable<HieroProto.proto.TransactionBody["data"]>, (transactions: HieroProto.proto.ITransaction[], signedTransactions: HieroProto.proto.ISignedTransaction[], transactionIds: TransactionId[], nodeIds: AccountId[], bodies: HieroProto.proto.TransactionBody[]) => Transaction>}
*/
export const TRANSACTION_REGISTRY: Map<NonNullable<HieroProto.proto.TransactionBody["data"]>, (transactions: HieroProto.proto.ITransaction[], signedTransactions: HieroProto.proto.ISignedTransaction[], transactionIds: TransactionId[], nodeIds: AccountId[], bodies: HieroProto.proto.TransactionBody[]) => Transaction>;
/**
* Base class for all transactions that may be submitted to Hedera.
*
* @abstract
* @augments {Executable<HieroProto.proto.ITransaction, HieroProto.proto.ITransactionResponse, TransactionResponse>}
*/
export default class Transaction extends Executable<HieroProto.proto.ITransaction, HieroProto.proto.ITransactionResponse, TransactionResponse> {
/**
* Deserialize a transaction from bytes. The bytes can either be a `proto.Transaction` or
* `proto.TransactionList`.
*
* @param {Uint8Array} bytes
* @returns {Transaction}
*/
static fromBytes(bytes: Uint8Array): Transaction;
/**
* This method is called by each `*Transaction._fromProtobuf()` method. It does
* all the finalization before the user gets hold of a complete `Transaction`
*
* @template {Transaction} TransactionT
* @param {TransactionT} transaction
* @param {HieroProto.proto.ITransaction[]} transactions
* @param {HieroProto.proto.ISignedTransaction[]} signedTransactions
* @param {TransactionId[]} transactionIds
* @param {AccountId[]} nodeIds
* @param {HieroProto.proto.ITransactionBody[]} bodies
* @returns {TransactionT}
*/
static _fromProtobufTransactions<TransactionT extends Transaction>(transaction: TransactionT, transactions: HieroProto.proto.ITransaction[], signedTransactions: HieroProto.proto.ISignedTransaction[], transactionIds: TransactionId[], nodeIds: AccountId[], bodies: HieroProto.proto.ITransactionBody[]): TransactionT;
constructor();
/**
* List of proto transactions that have been built from this SDK
* transaction.
*
* This is a 2-D array built into one, meaning to
* get to the next row you'd index into this array `row * rowLength + column`
* where `rowLength` is `nodeAccountIds.length`
*
* @internal
* @type {List<HieroProto.proto.ITransaction | null>}
*/
_transactions: List<HieroProto.proto.ITransaction | null>;
/**
* List of proto transactions that have been built from this SDK
* transaction.
*
* This is a 2-D array built into one, meaning to
* get to the next row you'd index into this array `row * rowLength + column`
* where `rowLength` is `nodeAccountIds.length`
*
* @internal
* @type {List<HieroProto.proto.ISignedTransaction>}
*/
_signedTransactions: List<HieroProto.proto.ISignedTransaction>;
/**
* Set of public keys (as string) who have signed this transaction so
* we do not allow them to sign it again.
*
* @internal
* @type {Set<string>}
*/
_signerPublicKeys: Set<string>;
/**
* The transaction valid duration
*
* @private
* @type {number}
*/
private _transactionValidDuration;
/**
* The default max transaction fee for this particular transaction type.
* Most transactions use the default of 2 Hbars, but some requests such
* as `TokenCreateTransaction` need to use a different default value.
*
* @protected
* @type {Hbar}
*/
protected _defaultMaxTransactionFee: Hbar;
/**
* The maximum custom fee that the user is willing to pay for the message. If left empty, the user is willing to pay any custom fee.
* If used with a transaction type that does not support custom fee limits, the transaction will fail.
* @type {CustomFeeLimit[]}
*/
_customFeeLimits: CustomFeeLimit[];
/**
* The max transaction fee on the request. This field is what users are able
* to set, not the `defaultMaxTransactionFee`. The purpose of this field is
* to allow us to determine if the user set the field explicitly, or if we're
* using the default max transation fee for the request.
*
* @private
* @type {Hbar | null}
*/
private _maxTransactionFee;
/**
* The transaction's memo
*
* @private
* @type {string}
*/
private _transactionMemo;
/**
* The list of transaction IDs. This list will almost always be of length 1.
* The only time this list will be a different length is for chunked transactions.
* The only two chunked transactions supported right now are `FileAppendTransaction`
* and `TopicMessageSubmitTransaction`
*
* @protected
* @type {List<TransactionId>}
*/
protected _transactionIds: List<TransactionId>;
/**
* A list of public keys that will be added to the requests signatures
*
* @private
* @type {PublicKey[]}
*/
private _publicKeys;
/**
* The list of signing function 1-1 with `_publicKeys` which sign the request.
* The reason this list allows `null` is because if we go from bytes into
* a transaction, then we know the public key, but we don't have the signing function.
*
* @private
* @type {(((message: Uint8Array) => Promise<Uint8Array>) | null)[]}
*/
private _transactionSigners;
/**
* Determine if we should regenerate transaction IDs when we receive `TRANSACITON_EXPIRED`
*
* @private
* @type {?boolean}
*/
private _regenerateTransactionId;
/**
* The key used to sign the batch transaction
*
* @private
* @type {Key | null}
*/
private _batchKey;
/**
* Whether the transaction is throttled
*
* @private
* @type {boolean}
*/
private _isThrottled;
/**
* Convert this transaction a `ScheduleCreateTransaction`
*
* @returns {ScheduleCreateTransaction}
*/
schedule(): ScheduleCreateTransaction;
/**
* @description Batchify method is used to mark a transaction as part of a batch transaction or make it so-called inner transaction.
* The Transaction will be frozen and signed by the operator of the client.
*
* @param {import("../client/Client.js").default<Channel, *>} client
* @param {Key} batchKey
* @returns {Promise<this>}
*/
batchify(client: import("../client/Client.js").default<Channel, any>, batchKey: Key): Promise<this>;
/**
* Set the node account IDs
*
* @override
* @param {AccountId[]} nodeIds
* @returns {this}
*/
override setNodeAccountIds(nodeIds: AccountId[]): this;
/**
* Get the transaction valid duration
*
* @returns {number}
*/
get transactionValidDuration(): number;
/**
* Protobuf encoding has specific rules about how data is serialized
* Different fields take different amounts of space depending on their values
* The actual wire format size can only be determined after encoding
*
* @returns {Promise<number>}
*/
get size(): Promise<number>;
/**
* Get the transaction body size
* Protobuf encoding has specific rules about how data is serialized
* Different fields take different amounts of space depending on their values
* The actual wire format size can only be determined after encoding
*
* @returns {number}
*/
get bodySize(): number;
/**
* Sets the duration (in seconds) that this transaction is valid for.
*
* This is defaulted to 120 seconds (from the time its executed).
*
* @param {number} validDuration
* @returns {this}
*/
setTransactionValidDuration(validDuration: number): this;
/**
* Get the max transaction fee
*
* @returns {?Hbar}
*/
get maxTransactionFee(): Hbar | null;
/**
* Set the maximum transaction fee the operator (paying account)
* is willing to pay.
*
* @param {number | string | Long | BigNumber | Hbar} maxTransactionFee
* @returns {this}
*/
setMaxTransactionFee(maxTransactionFee: number | string | Long | BigNumber | Hbar): this;
/**
* Is transaction ID regeneration enabled
*
* @returns {?boolean}
*/
get regenerateTransactionId(): boolean | null;
/**
* Set the maximum transaction fee the operator (paying account)
* is willing to pay.
*
* @param {boolean} regenerateTransactionId
* @returns {this}
*/
setRegenerateTransactionId(regenerateTransactionId: boolean): this;
/**
* Get the transaction memo
*
* @returns {string}
*/
get transactionMemo(): string;
/**
* Set a note or description to be recorded in the transaction
* record (maximum length of 100 bytes).
*
* @param {string} transactionMemo
* @returns {this}
*/
setTransactionMemo(transactionMemo: string): this;
/**
* Get the curent transaction ID
*
* @returns {?TransactionId}
*/
get transactionId(): TransactionId | null;
/**
* Set the ID for this transaction.
*
* The transaction ID includes the operator's account ( the account paying the transaction
* fee). If two transactions have the same transaction ID, they won't both have an effect. One
* will complete normally and the other will fail with a duplicate transaction status.
*
* Normally, you should not use this method. Just before a transaction is executed, a
* transaction ID will be generated from the operator on the client.
*
* @param {TransactionId} transactionId
* @returns {this}
*/
setTransactionId(transactionId: TransactionId): this;
/**
* How many chunk sizes are expected
* @abstract
* @internal
* @returns {number}
*/
getRequiredChunks(): number;
/**
* Get the body sizes for all chunks in a Chunked transaction.
* For transactions with multiple chunks (like large topic message submissions),
* this returns an array containing the size of each chunk's transaction body.
* The size is calculated by encoding the transaction body to protobuf format.
*
* @returns {number[]} An array of body sizes, where each element represents
* the size in bytes of a chunk's transaction body
*
*/
get bodySizeAllChunks(): number[];
/**
* Sign the transaction with the private key
* **NOTE**: This is a thin wrapper around `.signWith()`
*
* @param {PrivateKey} privateKey
* @returns {Promise<this>}
*/
sign(privateKey: PrivateKey): Promise<this>;
/**
* Sign the transaction with the public key and signer function
*
* If sign on demand is enabled no signing will be done immediately, instead
* the private key signing function and public key are saved to be used when
* a user calls an exit condition method (not sure what a better name for this is)
* such as `toBytes[Async]()`, `getTransactionHash[PerNode]()` or `execute()`.
*
* @param {PublicKey} publicKey
* @param {(message: Uint8Array) => Promise<Uint8Array>} transactionSigner
* @returns {Promise<this>}
*/
signWith(publicKey: PublicKey, transactionSigner: (message: Uint8Array) => Promise<Uint8Array>): Promise<this>;
/**
* Sign the transaction with the client operator. This is a thin wrapper
* around `.signWith()`
*
* **NOTE**: If client does not have an operator set, this method will throw
*
* @param {import("../client/Client.js").default<Channel, *>} client
* @returns {Promise<this>}
*/
signWithOperator(client: import("../client/Client.js").default<Channel, any>): Promise<this>;
/**
* Resets the transaction to its initial state
* @param {Client} client
*/
_resetTransaction(client: Client): void;
/**
* @deprecated - Using uint8array and uint8array[] as signaturemap is deprecated,
* use SignatureMap insted.
* @overload
* @param { PublicKey } publicKey
* @param { Uint8Array | Uint8Array[] } signatureMap
* @returns {this}
*/
addSignature(publicKey: PublicKey, signatureMap: Uint8Array | Uint8Array[]): this;
/**
* @overload
* @param {PublicKey} publicKey
* @param { SignatureMap } signatureMap
* @returns {this}
*/
addSignature(publicKey: PublicKey, signatureMap: SignatureMap): this;
/**
* Add a signature explicitly
* This method supports both single and multiple signatures. A single signature will be applied to all transactions,
*
* While an array of signatures must correspond to each transaction individually.
*
* @param {PublicKey} publicKey
* @param {Uint8Array | Uint8Array[]} signature
* @returns {this}
*/
_addSignatureLegacy(publicKey: PublicKey, signature: Uint8Array | Uint8Array[]): this;
/**
* Get the current signatures on the request
* **NOTE**: Does NOT support sign on demand
* @returns {SignatureMapLegacy}
*/
getSignaturesLegacy(): SignatureMapLegacy;
/**
* This method removes all signatures from the transaction based on the public key provided.
*
* @param {PublicKey} publicKey - The public key associated with the signature to remove.
* @returns {Uint8Array[]} The removed signatures.
*/
removeSignature(publicKey: PublicKey): Uint8Array[];
/**
* This method clears all signatures from the transaction and returns them in a specific format.
*
* It will call collectSignatures to get the removed signatures, then clear all signatures
* from the internal tracking.
*
* @returns { Map<PublicKey, Uint8Array[] | Uint8Array> } The removed signatures in the specified format.
*/
removeAllSignatures(): Map<PublicKey, Uint8Array[] | Uint8Array>;
/**
* @deprecated - Use the legacy=flag instead to use the modern approach
* @overload
* @param {true} legacy
* @returns {SignatureMapLegacy}
*/
getSignatures(legacy: true): SignatureMapLegacy;
/**
* @overload
* @param {false} [legacy]
* @returns {SignatureMap}
*/
getSignatures(legacy?: false | undefined): SignatureMap;
/**
* Get the current signatures on the request
*
* **NOTE**: Supports sign on demand
*
* @returns {Promise<SignatureMap>}
*/
getSignaturesAsync(): Promise<SignatureMap>;
/**
* Not sure why this is called `setTransactionId()` when it doesn't set anything...
* FIXME: Remove this?
*/
_setTransactionId(): void;
/**
* Set the node account IDs using the client
*
* @param {?import("../client/Client.js").default<Channel, *>} client
*/
_setNodeAccountIds(client: import("../client/Client.js").default<Channel, any> | null): void;
/**
* @description Set the key that will sign the batch of which this Transaction is a part of.
* @param {Key} batchKey
* @returns {this}
*/
setBatchKey(batchKey: Key): this;
/**
* @description Get the key that will sign the batch of which this Transaction is a part of.
* @returns {Key | null | undefined}
*/
get batchKey(): Key | null | undefined;
/**
* Returns a List of SignableNodeTransactionBodyBytes for each node the transaction is intended for.
* These are the canonical bytes that must be signed externally (e.g., via HSM).
*
* @returns {SignableNodeTransactionBodyBytes[]}
*/
get signableNodeBodyBytesList(): SignableNodeTransactionBodyBytes[];
/**
* Build all the signed transactions from the node account IDs
*
* @private
*/
private _buildSignedTransactions;
/**
* Build all the signed transactions from the node account IDs
*
* @internal
*/
_buildIncompleteTransactions(): void;
/**
* Freeze this transaction from future modification to prepare for
* signing or serialization.
*
* @returns {this}
*/
freeze(): this;
/**
* @param {?AccountId} accountId
*/
_freezeWithAccountId(accountId: AccountId | null): void;
_operatorAccountId: AccountId | null | undefined;
/**
* Freeze this transaction from further modification to prepare for
* signing or serialization.
*
* Will use the `Client`, if available, to generate a default Transaction ID and select 1/3
* nodes to prepare this transaction for.
*
* @param {?import("../client/Client.js").default<Channel, *>} client
* @returns {this}
*/
freezeWith(client: import("../client/Client.js").default<Channel, any> | null): this;
/**
* Sign the transaction using a signer
*
* This is part of the signature provider feature
*
* @param {Signer} signer
* @returns {Promise<this>}
*/
signWithSigner(signer: Signer): Promise<this>;
/**
* Freeze the transaction using a signer
*
* This is part of the signature provider feature.
*
* @param {Signer} signer
* @returns {Promise<this>}
*/
freezeWithSigner(signer: Signer): Promise<this>;
/**
* Serialize the transaction into bytes
*
* **NOTE**: Supports sign on demand
*
* @returns {Promise<Uint8Array>}
*/
toBytesAsync(): Promise<Uint8Array>;
/**
* Get the transaction hash
*
* @returns {Promise<Uint8Array>}
*/
getTransactionHash(): Promise<Uint8Array>;
/**
* Get all the transaction hashes
*
* @returns {Promise<TransactionHashMap>}
*/
getTransactionHashPerNode(): Promise<TransactionHashMap>;
/**
* Is transaction frozen
*
* @returns {boolean}
*/
isFrozen(): boolean;
/**
* @param {Client} client
*/
_validateChecksums(client: Client): void;
/**
* Sign a `proto.SignedTransaction` with all the keys
*
* @private
* @returns {Promise<HieroProto.proto.ISignedTransaction>}
*/
private _signTransaction;
/**
* Construct a new transaction ID at the current index
*
* @private
*/
private _buildNewTransactionIdList;
/**
* Build each signed transaction in a loop
*
* @internal
*/
_buildAllTransactions(): void;
/**
* Build and and sign each transaction in a loop
*
* This method is primary used in the exist condition methods
* which are not `execute()`, e.g. `toBytesAsync()` and `getSignaturesAsync()`
*
* @private
*/
private _buildAllTransactionsAsync;
/**
* Build a transaction at a particular index
*
* @internal
* @param {number} index
*/
_buildTransaction(index: number): void;
/**
* Build a trransaction using the current index, where the current
* index is determined by `this._nodeAccountIds.index` and
* `this._transactionIds.index`
*
* @private
* @returns {Promise<HieroProto.proto.ITransaction>}
*/
private _buildTransactionAsync;
/**
* Make a signed transaction given a node account ID
*
* @internal
* @param {?AccountId} nodeId
* @returns {HieroProto.proto.ISignedTransaction}
*/
_makeSignedTransaction(nodeId: AccountId | null): HieroProto.proto.ISignedTransaction;
/**
* Make a protobuf transaction body
*
* @private
* @param {?AccountId} nodeId
* @returns {HieroProto.proto.ITransactionBody}
*/
private _makeTransactionBody;
/**
* This method returns a key for the `data` field in a transaction body.
* Each transaction overwrite this to make sure when we build the transaction body
* we set the right data field.
*
* @abstract
* @protected
* @returns {NonNullable<HieroProto.proto.TransactionBody["data"]>}
*/
protected _getTransactionDataCase(): NonNullable<HieroProto.proto.TransactionBody["data"]>;
/**
* Make a scheduled transaction body
* FIXME: Should really call this `makeScheduledTransactionBody` to be consistent
*
* @internal
* @returns {HieroProto.proto.ISchedulableTransactionBody}
*/
_getScheduledTransactionBody(): HieroProto.proto.ISchedulableTransactionBody;
/**
* Make the transaction body data.
*
* @abstract
* @protected
* @returns {object}
*/
protected _makeTransactionData(): object;
/**
* FIXME: Why do we have `isFrozen` and `_isFrozen()`?
*
* @protected
* @returns {boolean}
*/
protected _isFrozen(): boolean;
/**
* Require the transaction to NOT be frozen
*
* @internal
*/
_requireNotFrozen(): void;
/**
* Require the transaction to have sign on demand disabled
*
* @internal
*/
_requireNotSignOnDemand(): void;
/**
* Require the transaction to be frozen
*
* @internal
*/
_requireFrozen(): void;
/**
* Require the transaction to have a single node account ID set
*
* @internal
* @protected
*/
protected _requireOneNodeAccountId(): void;
/**
* @param {HieroProto.proto.Transaction} request
* @returns {Uint8Array}
*/
_requestToBytes(request: HieroProto.proto.Transaction): Uint8Array;
/**
* @param {HieroProto.proto.TransactionResponse} response
* @returns {Uint8Array}
*/
_responseToBytes(response: HieroProto.proto.TransactionResponse): Uint8Array;
/**
* Removes all signatures from a transaction and collects the removed signatures.
*
* @param {HieroProto.proto.ISignedTransaction} transaction - The transaction object to process.
* @param {string} publicKeyHex - The hexadecimal representation of the public key.
* @returns {Uint8Array[]} An array of removed signatures.
*/
_removeSignaturesFromTransaction(transaction: HieroProto.proto.ISignedTransaction, publicKeyHex: string): Uint8Array[];
/**
* Determines whether a signature should be removed based on the provided public key.
*
* @param {HieroProto.proto.ISignaturePair} sigPair - The signature pair object that contains
* the public key prefix and signature to be evaluated.
* @param {string} publicKeyHex - The hexadecimal representation of the public key to compare against.
* @returns {boolean} `true` if the public key prefix in the signature pair matches the provided public key,
* indicating that the signature should be removed; otherwise, `false`.
*/
_shouldRemoveSignature: (sigPair: HieroProto.proto.ISignaturePair, publicKeyHex: string) => boolean;
/**
* Collects all signatures from signed transactions and returns them in a format keyed by PublicKey.
*
* @returns { Map<PublicKey, Uint8Array[]> } The collected signatures keyed by PublicKey.
*/
_collectSignaturesByPublicKey(): Map<PublicKey, Uint8Array[]>;
}
/**
* This is essentially a registry/cache for a callback that creates a `ScheduleCreateTransaction`
*
* @type {(() => ScheduleCreateTransaction)[]}
*/
export const SCHEDULE_CREATE_TRANSACTION: (() => ScheduleCreateTransaction)[];
export type BigNumber = import("bignumber.js").default;
export type ScheduleCreateTransaction = import("../schedule/ScheduleCreateTransaction.js").default;
export type PrivateKey = import("../PrivateKey.js").default;
export type Channel = import("../channel/Channel.js").default;
export type Client = import("../client/Client.js").default<any, any>;
export type Signer = import("../Signer.js").Signer;
import Long from "long";
import Hbar from "../Hbar.js";
import * as HieroProto from "@hashgraph/proto";
import TransactionId from "./TransactionId.js";
import AccountId from "../account/AccountId.js";
import TransactionResponse from "./TransactionResponse.js";
import Executable from "../Executable.js";
import List from "./List.js";
import CustomFeeLimit from "./CustomFeeLimit.js";
import Key from "../Key.js";
import PublicKey from "../PublicKey.js";
import SignatureMap from "./SignatureMap.js";
import SignatureMapLegacy from "./SignatureMapLegacy.js";
import SignableNodeTransactionBodyBytes from "./SignableNodeTransactionBodyBytes.js";
import TransactionHashMap from "./TransactionHashMap.js";