@aptos-labs/ts-sdk
Version:
Aptos TypeScript SDK
748 lines (746 loc) • 28.4 kB
JavaScript
// Copyright © Aptos Foundation
// SPDX-License-Identifier: Apache-2.0
import { Bool, U128, U16, U256, U32, U64, U8, I8, I16, I32, I64, I128, I256 } from "./movePrimitives.js";
import { Serializable, serializeEntryFunctionBytesCompat } from "../serializer.js";
import { Deserializer } from "../deserializer.js";
import { ScriptTransactionArgumentVariants } from "../../types/index.js";
import { Hex } from "../../core/hex.js";
import { TEXT_ENCODER } from "../../utils/const.js";
/**
* This class is the Aptos Typescript SDK representation of a Move `vector<T>`,
* where `T` represents either a primitive type (`bool`, `u8`, `u64`, ...)
* or a BCS-serializable struct itself.
*
* It is a BCS-serializable, array-like type that contains an array of values of type `T`,
* where `T` is a class that implements `Serializable`.
*
* The purpose of this class is to facilitate easy construction of BCS-serializable
* Move `vector<T>` types.
*
* @example
* // in Move: `vector<u8> [1, 2, 3, 4];`
* const vecOfU8s = new MoveVector<U8>([new U8(1), new U8(2), new U8(3), new U8(4)]);
* // in Move: `std::bcs::to_bytes(vector<u8> [1, 2, 3, 4]);`
* const bcsBytes = vecOfU8s.toUint8Array();
*
* // vector<vector<u8>> [ vector<u8> [1], vector<u8> [1, 2, 3, 4], vector<u8> [5, 6, 7, 8] ];
* const vecOfVecs = new MoveVector<MoveVector<U8>>([
* new MoveVector<U8>([new U8(1)]),
* MoveVector.U8([1, 2, 3, 4]),
* MoveVector.U8([5, 6, 7, 8]),
* ]);
*
* // vector<Option<u8>> [ std::option::some<u8>(1), std::option::some<u8>(2) ];
* const vecOfOptionU8s = new MoveVector<MoveOption<U8>>([
* MoveOption.U8(1),
* MoveOption.U8(2),
* ]);
*
* // vector<MoveString> [ std::string::utf8(b"hello"), std::string::utf8(b"world") ];
* const vecOfStrings = new MoveVector([new MoveString("hello"), new MoveString("world")]);
* const vecOfStrings2 = MoveVector.MoveString(["hello", "world"]);
*
* @param values an Array<T> of values where T is a class that implements Serializable
* @returns a `MoveVector<T>` with the values `values`
* @group Implementation
* @category BCS
*/
export class MoveVector extends Serializable {
values;
/**
* Initializes a new instance of the class with an optional value.
* This constructor sets up the internal vector based on the provided value.
*
* @param values - The initial value to be stored in the vector, or null to initialize an empty vector.
* @group Implementation
* @category BCS
*/
constructor(values) {
super();
this.values = values;
}
/**
* Serializes the current instance into a byte sequence suitable for entry functions.
* This allows the data to be properly formatted for transmission or storage.
* Uses serializeAsBytes when available, with a fallback for older Serializer versions.
*
* @param serializer - The serializer instance used to serialize the byte sequence.
* @group Implementation
* @category BCS
*/
serializeForEntryFunction(serializer) {
serializeEntryFunctionBytesCompat(serializer, this);
}
/**
* NOTE: This function will only work when the inner values in the `MoveVector` are `U8`s.
* @param serializer
* @group Implementation
* @category BCS
*/
/**
* Serialize the string as a fixed byte string without the length prefix for use in a script function.
* @param serializer - The serializer used to convert the byte vector into a format suitable for a script function.
* @group Implementation
* @category BCS
*/
serializeForScriptFunction(serializer) {
// This checks if the type of a non-empty vector is of type other than U8. If so, we use the Serialized
// transaction argument type to serialize the argument.
if (this.values[0] !== undefined && !(this.values[0] instanceof U8)) {
const serialized = new Serialized(this.bcsToBytes());
serialized.serializeForScriptFunction(serializer);
return;
}
serializer.serializeU32AsUleb128(ScriptTransactionArgumentVariants.U8Vector);
serializer.serialize(this);
}
/**
* Factory method to generate a MoveVector<U8> from a `number` or `undefined`.
*
* This method allows you to create a MoveVector that encapsulates a U8 value, enabling you to handle optional U8 values
* effectively.
*
* @param values - The values used to fill the MoveVector. If `values` is undefined or null, the resulting MoveVector's
* `.isSome()` method will return false.
* @returns A MoveVector<U8> with an inner value `value`.
*
* @example
* ```typescript
* const v = MoveVector.U8([1, 2, 3, 4]);
* ```
* @group Implementation
* @category BCS
*/
static U8(values) {
let numbers;
if (Array.isArray(values) && values.length === 0) {
// Handle empty array, since it won't have a "first value"
numbers = [];
}
else if (Array.isArray(values) && typeof values[0] === "number") {
numbers = values;
}
else if (typeof values === "string") {
const hex = Hex.fromHexInput(values);
numbers = Array.from(hex.toUint8Array());
}
else if (values instanceof Uint8Array) {
numbers = Array.from(values);
}
else {
throw new Error("Invalid input type, must be an number[], Uint8Array, or hex string");
}
return new MoveVector(numbers.map((v) => new U8(v)));
}
/**
* Factory method to generate a MoveOption<U16> from a `number` or `null`.
*
* This method allows you to create a MoveVector that can either hold a U16 value or be empty.
*
* @param values - The value used to fill the MoveVector. If `value` is null or undefined, the resulting MoveVector's
* `.isSome()` method will return false.
* @returns A MoveVector<U16> with an inner value `value`.
* @example
* ```typescript
* const v = MoveVector.U16([1, 2, 3, 4]);
* ```
* @group Implementation
* @category BCS
*/
static U16(values) {
return new MoveVector(values.map((v) => new U16(v)));
}
/**
* Factory method to generate a MoveVector<U32> from a `number` or `null`.
*
* This method allows you to create a MoveVector that can either hold a U32 value or be empty.
*
* @param values - The value used to fill the MoveVector. If `value` is null or undefined,
* the resulting MoveVector's .isSome() method will return false.
* @returns A MoveVector<U32> with an inner value `value`.
*
* @example
* ```
* const v = MoveVector.U32([1, 2, 3, 4]);
* ```
* @group Implementation
* @category BCS
*/
static U32(values) {
return new MoveVector(values.map((v) => new U32(v)));
}
/**
* Factory method to generate a MoveVector<U64> from a number, bigint, or null/undefined.
* This allows for the creation of an optional U64 value that can be checked for presence.
*
* @param values - The value used to fill the MoveVector. If `value` is undefined or null, the resulting MoveVector's
* `.isSome()` method will return false.
* @returns A MoveVector<U64> with an inner value `value`.
*
* @example
* ```typescript
* const v = MoveVector.U64([1, 2, 3, 4]);
* ```
* @group Implementation
* @category BCS
*/
static U64(values) {
return new MoveVector(values.map((v) => new U64(v)));
}
/**
* Factory method to generate a MoveVector<U128> from a number, bigint, or undefined.
*
* @param values - The value used to fill the MoveVector. If `value` is undefined, the resulting MoveVector's `.isSome()`
* method will return false.
* @returns A MoveVector<U128> with an inner value `value`.
*
* @example
* ```typescript
* const v = MoveVector.U128([1, 2, 3, 4]);
* ```
* @group Implementation
* @category BCS
*/
static U128(values) {
return new MoveVector(values.map((v) => new U128(v)));
}
/**
* Factory method to generate a MoveVector<U256> from a number, bigint, or null/undefined.
* This allows for the creation of an optional U256 value, enabling checks for presence or absence of a value.
*
* @param values - The value used to fill the MoveVector. If `value` is undefined or null,
* the resulting MoveVector's .isSome() method will return false.
* @returns A MoveVector<U256> with an inner value `value`.
*
* @example
* ```typescript
* const v = MoveVector.U256([1, 2, 3, 4]);
* ```
* @group Implementation
* @category BCS
*/
static U256(values) {
return new MoveVector(values.map((v) => new U256(v)));
}
/**
* Factory method to generate a MoveVector<Bool> from a `boolean` or `undefined`.
* This method allows you to create an optional boolean value that can be used in various contexts where a boolean may or may
* not be present.
*
* @param values - The value used to fill the MoveVector. If `value` is undefined, the resulting MoveVector's .isSome() method
* will return false.
* @returns A MoveVector<Bool> with an inner value `value`.
*
* @example
* * const v = MoveVector.Bool([true, false, true, false]);
* @group Implementation
* @category BCS
*/
static Bool(values) {
return new MoveVector(values.map((v) => new Bool(v)));
}
/**
* Factory method to generate a MoveVector<I8> from an array of numbers.
*
* @param values - The values used to fill the MoveVector.
* @returns A MoveVector<I8> with the inner values.
*
* @example
* ```typescript
* const v = MoveVector.I8([-1, 0, 1, 127]);
* ```
* @group Implementation
* @category BCS
*/
static I8(values) {
return new MoveVector(values.map((v) => new I8(v)));
}
/**
* Factory method to generate a MoveVector<I16> from an array of numbers.
*
* @param values - The values used to fill the MoveVector.
* @returns A MoveVector<I16> with the inner values.
*
* @example
* ```typescript
* const v = MoveVector.I16([-1, 0, 1, 32767]);
* ```
* @group Implementation
* @category BCS
*/
static I16(values) {
return new MoveVector(values.map((v) => new I16(v)));
}
/**
* Factory method to generate a MoveVector<I32> from an array of numbers.
*
* @param values - The values used to fill the MoveVector.
* @returns A MoveVector<I32> with the inner values.
*
* @example
* ```typescript
* const v = MoveVector.I32([-1, 0, 1, 2147483647]);
* ```
* @group Implementation
* @category BCS
*/
static I32(values) {
return new MoveVector(values.map((v) => new I32(v)));
}
/**
* Factory method to generate a MoveVector<I64> from an array of numbers or bigints.
*
* @param values - The values used to fill the MoveVector.
* @returns A MoveVector<I64> with the inner values.
*
* @example
* ```typescript
* const v = MoveVector.I64([-1n, 0n, 1n, 9223372036854775807n]);
* ```
* @group Implementation
* @category BCS
*/
static I64(values) {
return new MoveVector(values.map((v) => new I64(v)));
}
/**
* Factory method to generate a MoveVector<I128> from an array of numbers or bigints.
*
* @param values - The values used to fill the MoveVector.
* @returns A MoveVector<I128> with the inner values.
*
* @example
* ```typescript
* const v = MoveVector.I128([-1n, 0n, 1n]);
* ```
* @group Implementation
* @category BCS
*/
static I128(values) {
return new MoveVector(values.map((v) => new I128(v)));
}
/**
* Factory method to generate a MoveVector<I256> from an array of numbers or bigints.
*
* @param values - The values used to fill the MoveVector.
* @returns A MoveVector<I256> with the inner values.
*
* @example
* ```typescript
* const v = MoveVector.I256([-1n, 0n, 1n]);
* ```
* @group Implementation
* @category BCS
*/
static I256(values) {
return new MoveVector(values.map((v) => new I256(v)));
}
/**
* Factory method to generate a MoveVector<MoveString> from a `string` or `undefined`.
* This function creates a MoveVector that encapsulates a MoveString if the provided value is not null or undefined.
*
* @param values - The value used to fill the MoveVector. If `value` is undefined, the resulting MoveVector's .isSome() method
* will return false.
* @returns A MoveVector<MoveString> with an inner value `value`.
*
* @example
* const v = MoveVector.MoveString(["hello", "world"]);
* @group Implementation
* @category BCS
*/
static MoveString(values) {
return new MoveVector(values.map((v) => new MoveString(v)));
}
serialize(serializer) {
serializer.serializeVector(this.values);
}
/**
* Deserialize a MoveVector of type T, specifically where T is a Serializable and Deserializable type.
*
* NOTE: This only works with a depth of one. Generics will not work.
*
* NOTE: This will not work with types that aren't of the Serializable class.
*
* If you're looking for a more flexible deserialization function, you can use the deserializeVector function
* in the Deserializer class.
*
* @example
* const vec = MoveVector.deserialize(deserializer, U64);
* @param deserializer the Deserializer instance to use, with bytes loaded into it already.
* @param cls the class to typecast the input values to, must be a Serializable and Deserializable type.
* @returns a MoveVector of the corresponding class T
*
* @group Implementation
* @category BCS
*/
static deserialize(deserializer, cls) {
const length = deserializer.deserializeUleb128AsU32();
const values = new Array();
for (let i = 0; i < length; i += 1) {
values.push(cls.deserialize(deserializer));
}
return new MoveVector(values);
}
}
/**
* Represents a serialized data structure that encapsulates a byte array.
* This class extends the Serializable class and provides methods for serialization
* and deserialization of byte data, as well as converting to a MoveVector.
*
* @extends Serializable
* @group Implementation
* @category BCS
*/
export class Serialized extends Serializable {
value;
constructor(value) {
super();
this.value = Hex.fromHexInput(value).toUint8Array();
}
serialize(serializer) {
serializer.serializeBytes(this.value);
}
serializeForEntryFunction(serializer) {
this.serialize(serializer);
}
serializeForScriptFunction(serializer) {
serializer.serializeU32AsUleb128(ScriptTransactionArgumentVariants.Serialized);
this.serialize(serializer);
}
static deserialize(deserializer) {
return new Serialized(deserializer.deserializeBytes());
}
/**
* Deserialize the bytecode into a MoveVector of the specified type.
* This function allows you to convert serialized data into a usable MoveVector format.
*
* @param cls - The class type of the elements in the MoveVector.
* @group Implementation
* @category BCS
*/
toMoveVector(cls) {
const deserializer = new Deserializer(this.bcsToBytes());
deserializer.deserializeUleb128AsU32();
const vec = deserializer.deserializeVector(cls);
return new MoveVector(vec);
}
}
/**
* Represents a string value that can be serialized and deserialized.
* This class extends the Serializable base class and provides methods
* for serializing the string in different contexts, such as for entry
* functions and script functions.
*
* @extends Serializable
* @group Implementation
* @category BCS
*/
export class MoveString extends Serializable {
value;
constructor(value) {
super();
this.value = value;
}
serialize(serializer) {
serializer.serializeStr(this.value);
}
serializeForEntryFunction(serializer) {
serializeEntryFunctionBytesCompat(serializer, this);
}
serializeForScriptFunction(serializer) {
// Serialize the string as a fixed byte string, i.e., without the length prefix
const fixedStringBytes = TEXT_ENCODER.encode(this.value);
// Put those bytes into a vector<u8> and serialize it as a script function argument
const vectorU8 = MoveVector.U8(fixedStringBytes);
vectorU8.serializeForScriptFunction(serializer);
}
static deserialize(deserializer) {
return new MoveString(deserializer.deserializeStr());
}
}
export class MoveOption extends Serializable {
vec;
value;
constructor(value) {
super();
if (typeof value !== "undefined" && value !== null) {
this.vec = new MoveVector([value]);
}
else {
this.vec = new MoveVector([]);
}
[this.value] = this.vec.values;
}
serializeForEntryFunction(serializer) {
serializeEntryFunctionBytesCompat(serializer, this);
}
/**
* Retrieves the inner value of the MoveOption.
*
* This method is inspired by Rust's `Option<T>.unwrap()`, where attempting to unwrap a `None` value results in a panic.
* This method will throw an error if the value is not present.
*
* @example
* const option = new MoveOption<Bool>(new Bool(true));
* const value = option.unwrap(); // Returns the Bool instance
*
* @throws {Error} Throws an error if the MoveOption does not contain a value.
*
* @returns {T} The contained value if present.
* @group Implementation
* @category BCS
*/
unwrap() {
if (!this.isSome()) {
throw new Error("Called unwrap on a MoveOption with no value");
}
else {
return this.vec.values[0];
}
}
/**
* Check if the MoveOption has a value.
*
* @returns {boolean} Returns true if there is exactly one value in the MoveOption.
* @group Implementation
* @category BCS
*/
isSome() {
return this.vec.values.length === 1;
}
serialize(serializer) {
// serialize 0 or 1
// if 1, serialize the value
this.vec.serialize(serializer);
}
/**
* Factory method to generate a MoveOption<U8> from a `number` or `undefined`.
*
* @example
* MoveOption.U8(1).isSome() === true;
* MoveOption.U8().isSome() === false;
* MoveOption.U8(undefined).isSome() === false;
* @param value the value used to fill the MoveOption. If `value` is undefined
* the resulting MoveOption's .isSome() method will return false.
* @returns a MoveOption<U8> with an inner value `value`
* @group Implementation
* @category BCS
*/
static U8(value) {
return new MoveOption(value !== null && value !== undefined ? new U8(value) : undefined);
}
/**
* Factory method to generate a MoveOption<U16> from a `number` or `undefined`.
*
* @example
* MoveOption.U16(1).isSome() === true;
* MoveOption.U16().isSome() === false;
* MoveOption.U16(undefined).isSome() === false;
* @param value the value used to fill the MoveOption. If `value` is undefined
* the resulting MoveOption's .isSome() method will return false.
* @returns a MoveOption<U16> with an inner value `value`
* @group Implementation
* @category BCS
*/
static U16(value) {
return new MoveOption(value !== null && value !== undefined ? new U16(value) : undefined);
}
/**
* Factory method to generate a MoveOption<U32> from a `number` or `undefined`.
*
* @example
* MoveOption.U32(1).isSome() === true;
* MoveOption.U32().isSome() === false;
* MoveOption.U32(undefined).isSome() === false;
* @param value the value used to fill the MoveOption. If `value` is undefined
* the resulting MoveOption's .isSome() method will return false.
* @returns a MoveOption<U32> with an inner value `value`
* @group Implementation
* @category BCS
*/
static U32(value) {
return new MoveOption(value !== null && value !== undefined ? new U32(value) : undefined);
}
/**
* Factory method to generate a MoveOption<U64> from a `number` or a `bigint` or `undefined`.
*
* @example
* MoveOption.U64(1).isSome() === true;
* MoveOption.U64().isSome() === false;
* MoveOption.U64(undefined).isSome() === false;
* @param value the value used to fill the MoveOption. If `value` is undefined
* the resulting MoveOption's .isSome() method will return false.
* @returns a MoveOption<U64> with an inner value `value`
* @group Implementation
* @category BCS
*/
static U64(value) {
return new MoveOption(value !== null && value !== undefined ? new U64(value) : undefined);
}
/**
* Factory method to generate a MoveOption<U128> from a `number` or a `bigint` or `undefined`.
*
* @example
* MoveOption.U128(1).isSome() === true;
* MoveOption.U128().isSome() === false;
* MoveOption.U128(undefined).isSome() === false;
* @param value the value used to fill the MoveOption. If `value` is undefined
* the resulting MoveOption's .isSome() method will return false.
* @returns a MoveOption<U128> with an inner value `value`
* @group Implementation
* @category BCS
*/
static U128(value) {
return new MoveOption(value !== null && value !== undefined ? new U128(value) : undefined);
}
/**
* Factory method to generate a MoveOption<U256> from a `number` or a `bigint` or `undefined`.
*
* @example
* MoveOption.U256(1).isSome() === true;
* MoveOption.U256().isSome() === false;
* MoveOption.U256(undefined).isSome() === false;
* @param value the value used to fill the MoveOption. If `value` is undefined
* the resulting MoveOption's .isSome() method will return false.
* @returns a MoveOption<U256> with an inner value `value`
* @group Implementation
* @category BCS
*/
static U256(value) {
return new MoveOption(value !== null && value !== undefined ? new U256(value) : undefined);
}
/**
* Factory method to generate a MoveOption<Bool> from a `boolean` or `undefined`.
*
* @example
* MoveOption.Bool(true).isSome() === true;
* MoveOption.Bool().isSome() === false;
* MoveOption.Bool(undefined).isSome() === false;
* @param value the value used to fill the MoveOption. If `value` is undefined
* the resulting MoveOption's .isSome() method will return false.
* @returns a MoveOption<Bool> with an inner value `value`
* @group Implementation
* @category BCS
*/
static Bool(value) {
return new MoveOption(value !== null && value !== undefined ? new Bool(value) : undefined);
}
/**
* Factory method to generate a MoveOption<I8> from a `number` or `undefined`.
*
* @example
* MoveOption.I8(1).isSome() === true;
* MoveOption.I8().isSome() === false;
* MoveOption.I8(undefined).isSome() === false;
* @param value the value used to fill the MoveOption. If `value` is undefined
* the resulting MoveOption's .isSome() method will return false.
* @returns a MoveOption<I8> with an inner value `value`
* @group Implementation
* @category BCS
*/
static I8(value) {
return new MoveOption(value !== null && value !== undefined ? new I8(value) : undefined);
}
/**
* Factory method to generate a MoveOption<I16> from a `number` or `undefined`.
*
* @example
* MoveOption.I16(1).isSome() === true;
* MoveOption.I16().isSome() === false;
* MoveOption.I16(undefined).isSome() === false;
* @param value the value used to fill the MoveOption. If `value` is undefined
* the resulting MoveOption's .isSome() method will return false.
* @returns a MoveOption<I16> with an inner value `value`
* @group Implementation
* @category BCS
*/
static I16(value) {
return new MoveOption(value !== null && value !== undefined ? new I16(value) : undefined);
}
/**
* Factory method to generate a MoveOption<I32> from a `number` or `undefined`.
*
* @example
* MoveOption.I32(1).isSome() === true;
* MoveOption.I32().isSome() === false;
* MoveOption.I32(undefined).isSome() === false;
* @param value the value used to fill the MoveOption. If `value` is undefined
* the resulting MoveOption's .isSome() method will return false.
* @returns a MoveOption<I32> with an inner value `value`
* @group Implementation
* @category BCS
*/
static I32(value) {
return new MoveOption(value !== null && value !== undefined ? new I32(value) : undefined);
}
/**
* Factory method to generate a MoveOption<I64> from a `number` or a `bigint` or `undefined`.
*
* @example
* MoveOption.I64(1).isSome() === true;
* MoveOption.I64().isSome() === false;
* MoveOption.I64(undefined).isSome() === false;
* @param value the value used to fill the MoveOption. If `value` is undefined
* the resulting MoveOption's .isSome() method will return false.
* @returns a MoveOption<I64> with an inner value `value`
* @group Implementation
* @category BCS
*/
static I64(value) {
return new MoveOption(value !== null && value !== undefined ? new I64(value) : undefined);
}
/**
* Factory method to generate a MoveOption<I128> from a `number` or a `bigint` or `undefined`.
*
* @example
* MoveOption.I128(1).isSome() === true;
* MoveOption.I128().isSome() === false;
* MoveOption.I128(undefined).isSome() === false;
* @param value the value used to fill the MoveOption. If `value` is undefined
* the resulting MoveOption's .isSome() method will return false.
* @returns a MoveOption<I128> with an inner value `value`
* @group Implementation
* @category BCS
*/
static I128(value) {
return new MoveOption(value !== null && value !== undefined ? new I128(value) : undefined);
}
/**
* Factory method to generate a MoveOption<I256> from a `number` or a `bigint` or `undefined`.
*
* @example
* MoveOption.I256(1).isSome() === true;
* MoveOption.I256().isSome() === false;
* MoveOption.I256(undefined).isSome() === false;
* @param value the value used to fill the MoveOption. If `value` is undefined
* the resulting MoveOption's .isSome() method will return false.
* @returns a MoveOption<I256> with an inner value `value`
* @group Implementation
* @category BCS
*/
static I256(value) {
return new MoveOption(value !== null && value !== undefined ? new I256(value) : undefined);
}
/**
* Factory method to generate a MoveOption<MoveString> from a `string` or `undefined`.
*
* @example
* MoveOption.MoveString("hello").isSome() === true;
* MoveOption.MoveString("").isSome() === true;
* MoveOption.MoveString().isSome() === false;
* MoveOption.MoveString(undefined).isSome() === false;
* @param value the value used to fill the MoveOption. If `value` is undefined
* the resulting MoveOption's .isSome() method will return false.
* @returns a MoveOption<MoveString> with an inner value `value`
* @group Implementation
* @category BCS
*/
static MoveString(value) {
return new MoveOption(value !== null && value !== undefined ? new MoveString(value) : undefined);
}
static deserialize(deserializer, cls) {
const vector = MoveVector.deserialize(deserializer, cls);
return new MoveOption(vector.values[0]);
}
}
//# sourceMappingURL=moveStructs.js.map