@aptos-labs/ts-sdk
Version:
Aptos TypeScript SDK
668 lines • 28.1 kB
JavaScript
// Copyright © Aptos Foundation
// SPDX-License-Identifier: Apache-2.0
import { Serializable } from "../../bcs/serializer.js";
import { EntryFunctionBytes } from "../../bcs/serializable/entryFunctionBytes.js";
import { Bool, U128, U16, U256, U32, U64, U8, I8, I16, I32, I64, I128, I256, } from "../../bcs/serializable/movePrimitives.js";
import { MoveVector, Serialized } from "../../bcs/serializable/moveStructs.js";
import { AccountAddress } from "../../core/index.js";
import { Ciphertext } from "../../core/crypto/encryption/ciphertext.js";
import { ClaimedEntryFunction } from "./encryptedPayload.js";
import { Identifier } from "./identifier.js";
import { ModuleId } from "./moduleId.js";
import { MultiSigTransactionPayloadVariants, ScriptTransactionArgumentVariants, TransactionExecutableVariants, TransactionExtraConfigVariants, TransactionInnerPayloadVariants, TransactionPayloadVariants, } from "../../types/index.js";
import { TypeTag } from "../typeTag/index.js";
/**
* Deserialize a Script Transaction Argument.
* This function retrieves and deserializes various types of script transaction arguments based on the provided deserializer.
*
* @param deserializer - The deserializer used to read the script transaction argument.
* @returns The deserialized script transaction argument.
* @throws Error if the variant index is unknown.
* @group Implementation
* @category Transactions
*/
export function deserializeFromScriptArgument(deserializer) {
// index enum variant
const index = deserializer.deserializeUleb128AsU32();
switch (index) {
case ScriptTransactionArgumentVariants.U8:
return U8.deserialize(deserializer);
case ScriptTransactionArgumentVariants.U64:
return U64.deserialize(deserializer);
case ScriptTransactionArgumentVariants.U128:
return U128.deserialize(deserializer);
case ScriptTransactionArgumentVariants.Address:
return AccountAddress.deserialize(deserializer);
case ScriptTransactionArgumentVariants.U8Vector:
return MoveVector.deserialize(deserializer, U8);
case ScriptTransactionArgumentVariants.Bool:
return Bool.deserialize(deserializer);
case ScriptTransactionArgumentVariants.U16:
return U16.deserialize(deserializer);
case ScriptTransactionArgumentVariants.U32:
return U32.deserialize(deserializer);
case ScriptTransactionArgumentVariants.U256:
return U256.deserialize(deserializer);
case ScriptTransactionArgumentVariants.Serialized:
return Serialized.deserialize(deserializer);
case ScriptTransactionArgumentVariants.I8:
return I8.deserialize(deserializer);
case ScriptTransactionArgumentVariants.I16:
return I16.deserialize(deserializer);
case ScriptTransactionArgumentVariants.I32:
return I32.deserialize(deserializer);
case ScriptTransactionArgumentVariants.I64:
return I64.deserialize(deserializer);
case ScriptTransactionArgumentVariants.I128:
return I128.deserialize(deserializer);
case ScriptTransactionArgumentVariants.I256:
return I256.deserialize(deserializer);
default:
throw new Error(`Unknown variant index for ScriptTransactionArgument: ${index}`);
}
}
/**
* Represents a supported Transaction Payload that can be serialized and deserialized.
*
* This class serves as a base for different types of transaction payloads, allowing for
* their serialization into a format suitable for transmission and deserialization back
* into their original form.
* @group Implementation
* @category Transactions
*/
export class TransactionPayload extends Serializable {
/**
* Deserialize a Transaction Payload
* @group Implementation
* @category Transactions
*/
/**
* Deserializes a multisig transaction payload from the provided deserializer.
* This function enables the reconstruction of a MultiSigTransactionPayload object from its serialized form.
*
* @param deserializer - The deserializer instance used to read the serialized data.
* @group Implementation
* @category Transactions
*/
static deserialize(deserializer) {
// index enum variant
const index = deserializer.deserializeUleb128AsU32();
switch (index) {
case TransactionPayloadVariants.Script:
return TransactionPayloadScript.load(deserializer);
case TransactionPayloadVariants.EntryFunction:
return TransactionPayloadEntryFunction.load(deserializer);
case TransactionPayloadVariants.Multisig:
return TransactionPayloadMultiSig.load(deserializer);
case TransactionPayloadVariants.Payload:
return TransactionInnerPayload.deserialize(deserializer);
case TransactionPayloadVariants.EncryptedPayload:
return TransactionPayloadEncryptedPayload.load(deserializer);
default:
throw new Error(`Unknown variant index for TransactionPayload: ${index}`);
}
}
}
/**
* Represents a transaction payload script that can be serialized and deserialized.
*
* This class encapsulates a script that defines the logic for a transaction payload.
*
* @extends TransactionPayload
* @group Implementation
* @category Transactions
*/
export class TransactionPayloadScript extends TransactionPayload {
script;
/**
* Initializes a multi-sig account transaction with the provided payload.
*
* @param script - The payload of the multi-sig transaction. This can only be an EntryFunction for now, but Script might be
* supported in the future.
* @group Implementation
* @category Transactions
*/
constructor(script) {
super();
this.script = script;
}
/**
* Serializes the transaction payload, enabling future support for multiple types of inner transaction payloads.
*
* @param serializer - The serializer instance used to serialize the transaction data.
* @group Implementation
* @category Transactions
*/
serialize(serializer) {
serializer.serializeU32AsUleb128(TransactionPayloadVariants.Script);
this.script.serialize(serializer);
}
/**
* Loads a MultiSig transaction payload from the provided deserializer.
* This function helps in reconstructing a MultiSig transaction payload from its serialized form.
*
* @param deserializer - The deserializer used to read the serialized data.
* @group Implementation
* @category Transactions
*/
static load(deserializer) {
const script = Script.deserialize(deserializer);
return new TransactionPayloadScript(script);
}
}
/**
* Represents a transaction payload entry function that can be serialized and deserialized.
*
* @extends TransactionPayload
* @group Implementation
* @category Transactions
*/
export class TransactionPayloadEntryFunction extends TransactionPayload {
entryFunction;
constructor(entryFunction) {
super();
this.entryFunction = entryFunction;
}
serialize(serializer) {
serializer.serializeU32AsUleb128(TransactionPayloadVariants.EntryFunction);
this.entryFunction.serialize(serializer);
}
static load(deserializer) {
const entryFunction = EntryFunction.deserialize(deserializer);
return new TransactionPayloadEntryFunction(entryFunction);
}
}
/**
* Represents a multi-signature transaction payload that can be serialized and deserialized.
* @group Implementation
* @category Transactions
*/
export class TransactionPayloadMultiSig extends TransactionPayload {
multiSig;
constructor(multiSig) {
super();
this.multiSig = multiSig;
}
serialize(serializer) {
serializer.serializeU32AsUleb128(TransactionPayloadVariants.Multisig);
this.multiSig.serialize(serializer);
}
static load(deserializer) {
const value = MultiSig.deserialize(deserializer);
return new TransactionPayloadMultiSig(value);
}
}
/**
* Represents an entry function that can be serialized and deserialized.
* This class encapsulates the details required to invoke a function within a module,
* including the module name, function name, type arguments, and function arguments.
*
* @param module_name - Fully qualified module name in the format "account_address::module_name" (e.g., "0x1::coin").
* @param function_name - The name of the function (e.g., "transfer").
* @param type_args - Type arguments required by the Move function.
* @param args - Arguments to the Move function.
* @group Implementation
* @category Transactions
*/
export class EntryFunction {
module_name;
function_name;
type_args;
args;
/**
* Contains the payload to run a function within a module.
* @param module_name Fully qualified module name in format "account_address::module_name" e.g. "0x1::coin"
* @param function_name The function name. e.g "transfer"
* @param type_args Type arguments that move function requires.
*
* @example
* A coin transfer function has one type argument "CoinType".
* ```
* public entry fun transfer<CoinType>(from: &signer, to: address, amount: u64)
* ```
* @param args arguments to the move function.
*
* @example
* A coin transfer function has three arguments "from", "to" and "amount".
* ```
* public entry fun transfer<CoinType>(from: &signer, to: address, amount: u64)
* ```
* @group Implementation
* @category Transactions
*/
constructor(module_name, function_name, type_args, args) {
this.module_name = module_name;
this.function_name = function_name;
this.type_args = type_args;
this.args = args;
}
/**
* Build an EntryFunction payload from raw primitive values.
*
* @param module_id - Fully qualified module name in the format "AccountAddress::module_id", e.g., "0x1::coin".
* @param function_name - The name of the function to be called.
* @param type_args - Type arguments that the Move function requires.
* @param args - Arguments to the Move function.
*
* @example
* A coin transfer function has one type argument "CoinType".
* ```
* public(script) fun transfer<CoinType>(from: &signer, to: address, amount: u64)
* ```
*
* A coin transfer function has three arguments "from", "to", and "amount".
* ```
* public(script) fun transfer<CoinType>(from: &signer, to: address, amount: u64)
* ```
*
* @returns EntryFunction
* @group Implementation
* @category Transactions
*/
static build(module_id, function_name, type_args, args) {
return new EntryFunction(ModuleId.fromStr(module_id), new Identifier(function_name), type_args, args);
}
serialize(serializer) {
this.module_name.serialize(serializer);
this.function_name.serialize(serializer);
serializer.serializeVector(this.type_args);
serializer.serializeU32AsUleb128(this.args.length);
this.args.forEach((item) => {
item.serializeForEntryFunction(serializer);
});
}
/**
* Deserializes an entry function payload with the arguments represented as EntryFunctionBytes instances.
* @see EntryFunctionBytes
*
* NOTE: When you deserialize an EntryFunction payload with this method, the entry function
* arguments are populated into the deserialized instance as type-agnostic, raw fixed bytes
* in the form of the EntryFunctionBytes class.
*
* In order to correctly deserialize these arguments as their actual type representations, you
* must know the types of the arguments beforehand and deserialize them yourself individually.
*
* One way you could achieve this is by using the ABIs for an entry function and deserializing each
* argument as its given, corresponding type.
*
* @param deserializer
* @returns A deserialized EntryFunction payload for a transaction.
*
* @group Implementation
* @category Transactions
*/
static deserialize(deserializer) {
const module_name = ModuleId.deserialize(deserializer);
const function_name = Identifier.deserialize(deserializer);
const type_args = deserializer.deserializeVector(TypeTag);
const length = deserializer.deserializeUleb128AsU32();
const args = new Array();
for (let i = 0; i < length; i += 1) {
const fixedBytesLength = deserializer.deserializeUleb128AsU32();
const fixedBytes = EntryFunctionBytes.deserialize(deserializer, fixedBytesLength);
args.push(fixedBytes);
}
return new EntryFunction(module_name, function_name, type_args, args);
}
}
/**
* Discriminants of Rust `EncryptedPayload`. Only `Encrypted` is produced or accepted client-side;
* `FailedDecryption` and `Decrypted` are listed for wire-format reference.
*/
var EncryptedPayloadVariants;
(function (EncryptedPayloadVariants) {
EncryptedPayloadVariants[EncryptedPayloadVariants["Encrypted"] = 0] = "Encrypted";
EncryptedPayloadVariants[EncryptedPayloadVariants["FailedDecryption"] = 1] = "FailedDecryption";
EncryptedPayloadVariants[EncryptedPayloadVariants["Decrypted"] = 2] = "Decrypted";
})(EncryptedPayloadVariants || (EncryptedPayloadVariants = {}));
/**
* `EncryptedPayload::Encrypted` as a `TransactionPayload`. BCS:
* variant tag (5) | inner tag (0) | Ciphertext | TransactionExtraConfig | 32-byte payload_hash | u64 epoch | Option<ClaimedEntryFunction>.
*/
export class TransactionPayloadEncryptedPayload extends TransactionPayload {
ciphertext;
extraConfig;
payloadHash;
/** Epoch hint matching the node's per-epoch encryption key (see aptos-core `EncryptedInner`). */
encryptionEpoch;
claimedEntryFunction;
constructor(ciphertext, extraConfig, payloadHash, encryptionEpoch, claimedEntryFunction) {
super();
if (payloadHash.length !== 32) {
throw new Error("payloadHash must be 32 bytes");
}
this.ciphertext = ciphertext;
this.extraConfig = extraConfig;
this.payloadHash = payloadHash;
this.encryptionEpoch = encryptionEpoch;
this.claimedEntryFunction = claimedEntryFunction;
}
serialize(serializer) {
serializer.serializeU32AsUleb128(TransactionPayloadVariants.EncryptedPayload);
serializer.serializeU32AsUleb128(EncryptedPayloadVariants.Encrypted);
this.ciphertext.serialize(serializer);
this.extraConfig.serialize(serializer);
serializer.serializeFixedBytes(this.payloadHash);
serializer.serializeU64(this.encryptionEpoch);
serializer.serializeOption(this.claimedEntryFunction);
}
static load(deserializer) {
const variant = deserializer.deserializeUleb128AsU32();
if (variant !== EncryptedPayloadVariants.Encrypted) {
throw new Error(`Only EncryptedPayload::Encrypted (variant 0) is supported on the client, got ${variant}`);
}
const ciphertext = Ciphertext.deserialize(deserializer);
const extraConfig = TransactionExtraConfig.deserialize(deserializer);
const payloadHash = deserializer.deserializeFixedBytes(32);
const encryptionEpoch = deserializer.deserializeU64();
const claimedEntryFunction = deserializer.deserializeOption(ClaimedEntryFunction);
return new TransactionPayloadEncryptedPayload(ciphertext, extraConfig, payloadHash, encryptionEpoch, claimedEntryFunction);
}
}
/**
* Represents a Script that can be serialized and deserialized.
* Scripts contain the Move bytecode payload that can be submitted to the Aptos chain for execution.
* @group Implementation
* @category Transactions
*/
export class Script {
/**
* The move module bytecode
* @group Implementation
* @category Transactions
*/
bytecode;
/**
* The type arguments that the bytecode function requires.
* @group Implementation
* @category Transactions
*/
type_args;
/**
* The arguments that the bytecode function requires.
* @group Implementation
* @category Transactions
*/
args;
/**
* Scripts contain the Move bytecodes payload that can be submitted to Aptos chain for execution.
*
* @param bytecode The move module bytecode
* @param type_args The type arguments that the bytecode function requires.
*
* @example
* A coin transfer function has one type argument "CoinType".
* ```
* public(script) fun transfer<CoinType>(from: &signer, to: address, amount: u64)
* ```
* @param args The arguments that the bytecode function requires.
*
* @example
* A coin transfer function has three arguments "from", "to" and "amount".
* ```
* public(script) fun transfer<CoinType>(from: &signer, to: address, amount: u64)
* ```
* @group Implementation
* @category Transactions
*/
constructor(bytecode, type_args, args) {
this.bytecode = bytecode;
this.type_args = type_args;
this.args = args;
}
serialize(serializer) {
serializer.serializeBytes(this.bytecode);
serializer.serializeVector(this.type_args);
serializer.serializeU32AsUleb128(this.args.length);
this.args.forEach((item) => {
item.serializeForScriptFunction(serializer);
});
}
static deserialize(deserializer) {
const bytecode = deserializer.deserializeBytes();
const type_args = deserializer.deserializeVector(TypeTag);
const length = deserializer.deserializeUleb128AsU32();
const args = new Array();
for (let i = 0; i < length; i += 1) {
// Note that we deserialize directly to the Move value, not its Script argument representation.
// We are abstracting away the Script argument representation because knowing about it is
// functionally useless.
const scriptArgument = deserializeFromScriptArgument(deserializer);
args.push(scriptArgument);
}
return new Script(bytecode, type_args, args);
}
}
/**
* Represents a MultiSig account that can be serialized and deserialized.
*
* This class encapsulates the functionality to manage multi-signature transactions, including the address of the
* multi-sig account and the associated transaction payload.
* @group Implementation
* @category Transactions
*/
export class MultiSig {
multisig_address;
transaction_payload;
/**
* Contains the payload to run a multi-sig account transaction.
*
* @param multisig_address The multi-sig account address the transaction will be executed as.
*
* @param transaction_payload The payload of the multi-sig transaction. This is optional when executing a multi-sig
* transaction whose payload is already stored on chain.
* @group Implementation
* @category Transactions
*/
constructor(multisig_address, transaction_payload) {
this.multisig_address = multisig_address;
this.transaction_payload = transaction_payload;
}
serialize(serializer) {
this.multisig_address.serialize(serializer);
// Options are encoded with an extra u8 field before the value - 0x0 is none and 0x1 is present.
// We use serializeBool below to create this prefix value.
if (this.transaction_payload === undefined) {
serializer.serializeBool(false);
}
else {
serializer.serializeBool(true);
this.transaction_payload.serialize(serializer);
}
}
static deserialize(deserializer) {
const multisig_address = AccountAddress.deserialize(deserializer);
const payloadPresent = deserializer.deserializeBool();
let transaction_payload;
if (payloadPresent) {
transaction_payload = MultiSigTransactionPayload.deserialize(deserializer);
}
return new MultiSig(multisig_address, transaction_payload);
}
}
/**
* Represents a multi-signature transaction payload that can be serialized and deserialized.
* This class is designed to encapsulate the transaction payload for multi-sig account transactions
* as defined in the `multisig_account.move` module. Future enhancements may allow support for script
* payloads as the `multisig_account.move` module evolves.
* @group Implementation
* @category Transactions
*/
export class MultiSigTransactionPayload extends Serializable {
transaction_payload;
/**
* Contains the payload to run a multi-sig account transaction.
*
* @param transaction_payload The payload of the multi-sig transaction.
* This can be an EntryFunction or a Script.
* @group Implementation
* @category Transactions
*/
constructor(transaction_payload) {
super();
this.transaction_payload = transaction_payload;
}
serialize(serializer) {
if (this.transaction_payload instanceof EntryFunction) {
serializer.serializeU32AsUleb128(MultiSigTransactionPayloadVariants.EntryFunction);
}
else if (this.transaction_payload instanceof Script) {
serializer.serializeU32AsUleb128(MultiSigTransactionPayloadVariants.Script);
}
else {
throw new Error("Unsupported multisig transaction payload type");
}
this.transaction_payload.serialize(serializer);
}
static deserialize(deserializer) {
const variant = deserializer.deserializeUleb128AsU32();
switch (variant) {
case MultiSigTransactionPayloadVariants.EntryFunction:
return new MultiSigTransactionPayload(EntryFunction.deserialize(deserializer));
case MultiSigTransactionPayloadVariants.Script:
return new MultiSigTransactionPayload(Script.deserialize(deserializer));
default:
throw new Error(`Unknown MultisigTransactionPayload variant: ${variant}`);
}
}
}
/**
* Represents any transaction payload that can be submitted to the Aptos chain for execution.
*
* This is specifically required for orderless transactions, but can be used for any transaction payload.
*/
export class TransactionInnerPayload extends TransactionPayload {
static deserialize(deserializer) {
// index enum variant
const index = deserializer.deserializeUleb128AsU32();
switch (index) {
case TransactionInnerPayloadVariants.V1:
return TransactionInnerPayloadV1.load(deserializer);
default:
throw new Error(`Unknown variant index for TransactionInnerPayload: ${index}`);
}
}
}
export class TransactionInnerPayloadV1 extends TransactionInnerPayload {
executable;
extra_config;
constructor(executable, extra_config) {
super();
this.executable = executable;
this.extra_config = extra_config;
}
serialize(serializer) {
// This payload must be serialized as a top level TransactionPayload, so we add that here
serializer.serializeU32AsUleb128(TransactionPayloadVariants.Payload);
// V1 is serialized as 0
serializer.serializeU32AsUleb128(TransactionInnerPayloadVariants.V1);
this.executable.serialize(serializer);
this.extra_config.serialize(serializer);
}
static load(deserializer) {
const executable = TransactionExecutable.deserialize(deserializer);
const extra_config = TransactionExtraConfig.deserialize(deserializer);
return new TransactionInnerPayloadV1(executable, extra_config);
}
}
export class TransactionExecutable {
static deserialize(deserializer) {
// index enum variant
const index = deserializer.deserializeUleb128AsU32();
switch (index) {
case TransactionExecutableVariants.Script:
return TransactionExecutableScript.load(deserializer);
case TransactionExecutableVariants.EntryFunction:
return TransactionExecutableEntryFunction.load(deserializer);
case TransactionExecutableVariants.Empty:
return TransactionExecutableEmpty.load(deserializer);
case TransactionExecutableVariants.Encrypted:
return TransactionExecutableEncrypted.load(deserializer);
default:
throw new Error(`Unknown variant index for TransactionExecutable: ${index}`);
}
}
}
export class TransactionExecutableScript extends TransactionExecutable {
script;
constructor(script) {
super();
this.script = script;
}
serialize(serializer) {
serializer.serializeU32AsUleb128(TransactionExecutableVariants.Script);
this.script.serialize(serializer);
}
static load(deserializer) {
const script = Script.deserialize(deserializer);
return new TransactionExecutableScript(script);
}
}
export class TransactionExecutableEntryFunction extends TransactionExecutable {
entryFunction;
constructor(entryFunction) {
super();
this.entryFunction = entryFunction;
}
serialize(serializer) {
serializer.serializeU32AsUleb128(TransactionExecutableVariants.EntryFunction);
this.entryFunction.serialize(serializer);
}
static load(deserializer) {
const entryFunction = EntryFunction.deserialize(deserializer);
return new TransactionExecutableEntryFunction(entryFunction);
}
}
export class TransactionExecutableEmpty extends TransactionExecutable {
serialize(serializer) {
serializer.serializeU32AsUleb128(TransactionExecutableVariants.Empty);
}
static load(_) {
return new TransactionExecutableEmpty();
}
}
/**
* Server-side sentinel variant the fullnode places in a decrypted transaction.
* The SDK never constructs this; it exists only for deserialization completeness.
* @internal
*/
export class TransactionExecutableEncrypted extends TransactionExecutable {
serialize(serializer) {
serializer.serializeU32AsUleb128(TransactionExecutableVariants.Encrypted);
}
static load(_) {
return new TransactionExecutableEncrypted();
}
}
export class TransactionExtraConfig extends Serializable {
static deserialize(deserializer) {
// index enum variant
const index = deserializer.deserializeUleb128AsU32();
switch (index) {
case TransactionExtraConfigVariants.V1:
return TransactionExtraConfigV1.load(deserializer);
default:
throw new Error(`Unknown variant index for TransactionExtraConfig: ${index}`);
}
}
}
export class TransactionExtraConfigV1 extends TransactionExtraConfig {
multisigAddress;
replayProtectionNonce;
constructor(multisigAddress, replayProtectionNonce) {
super();
this.multisigAddress = multisigAddress;
this.replayProtectionNonce = replayProtectionNonce !== undefined ? BigInt(replayProtectionNonce) : undefined;
}
serialize(serializer) {
serializer.serializeU32AsUleb128(TransactionExtraConfigVariants.V1);
serializer.serializeOption(this.multisigAddress);
serializer.serializeOption(this.replayProtectionNonce !== undefined ? new U64(this.replayProtectionNonce) : undefined);
}
static load(deserializer) {
const multisigAddress = deserializer.deserializeOption(AccountAddress);
const replayProtectionNonce = deserializer.deserializeOption(U64);
return new TransactionExtraConfigV1(multisigAddress, replayProtectionNonce?.value);
}
}
//# sourceMappingURL=transactionPayload.js.map