@mysten/sui
Version:
Sui TypeScript API(Work in Progress)
482 lines (481 loc) • 14.7 kB
JavaScript
import { fromBase64, toBase64 } from "@mysten/bcs";
import {
array,
bigint,
boolean,
check,
integer,
is,
lazy,
literal,
nullable,
nullish,
number,
object,
optional,
parse,
pipe,
string,
union,
unknown
} from "valibot";
import { TypeTagSerializer } from "../../bcs/index.js";
import { JsonU64, ObjectID, safeEnum, TransactionData } from "./internal.js";
const ObjectRef = object({
digest: string(),
objectId: string(),
version: union([pipe(number(), integer()), string(), bigint()])
});
const ObjectArg = safeEnum({
ImmOrOwned: ObjectRef,
Shared: object({
objectId: ObjectID,
initialSharedVersion: JsonU64,
mutable: boolean()
}),
Receiving: ObjectRef
});
const NormalizedCallArg = safeEnum({
Object: ObjectArg,
Pure: array(pipe(number(), integer()))
});
const TransactionInput = union([
object({
kind: literal("Input"),
index: pipe(number(), integer()),
value: unknown(),
type: optional(literal("object"))
}),
object({
kind: literal("Input"),
index: pipe(number(), integer()),
value: unknown(),
type: literal("pure")
})
]);
const TransactionExpiration = union([
object({ Epoch: pipe(number(), integer()) }),
object({ None: nullable(literal(true)) })
]);
const StringEncodedBigint = pipe(
union([number(), string(), bigint()]),
check((val) => {
if (!["string", "number", "bigint"].includes(typeof val)) return false;
try {
BigInt(val);
return true;
} catch {
return false;
}
})
);
const TypeTag = union([
object({ bool: nullable(literal(true)) }),
object({ u8: nullable(literal(true)) }),
object({ u64: nullable(literal(true)) }),
object({ u128: nullable(literal(true)) }),
object({ address: nullable(literal(true)) }),
object({ signer: nullable(literal(true)) }),
object({ vector: lazy(() => TypeTag) }),
object({ struct: lazy(() => StructTag) }),
object({ u16: nullable(literal(true)) }),
object({ u32: nullable(literal(true)) }),
object({ u256: nullable(literal(true)) })
]);
const StructTag = object({
address: string(),
module: string(),
name: string(),
typeParams: array(TypeTag)
});
const GasConfig = object({
budget: optional(StringEncodedBigint),
price: optional(StringEncodedBigint),
payment: optional(array(ObjectRef)),
owner: optional(string())
});
const TransactionArgumentTypes = [
TransactionInput,
object({ kind: literal("GasCoin") }),
object({ kind: literal("Result"), index: pipe(number(), integer()) }),
object({
kind: literal("NestedResult"),
index: pipe(number(), integer()),
resultIndex: pipe(number(), integer())
})
];
const TransactionArgument = union([...TransactionArgumentTypes]);
const MoveCallTransaction = object({
kind: literal("MoveCall"),
target: pipe(
string(),
check((target) => target.split("::").length === 3)
),
typeArguments: array(string()),
arguments: array(TransactionArgument)
});
const TransferObjectsTransaction = object({
kind: literal("TransferObjects"),
objects: array(TransactionArgument),
address: TransactionArgument
});
const SplitCoinsTransaction = object({
kind: literal("SplitCoins"),
coin: TransactionArgument,
amounts: array(TransactionArgument)
});
const MergeCoinsTransaction = object({
kind: literal("MergeCoins"),
destination: TransactionArgument,
sources: array(TransactionArgument)
});
const MakeMoveVecTransaction = object({
kind: literal("MakeMoveVec"),
type: union([object({ Some: TypeTag }), object({ None: nullable(literal(true)) })]),
objects: array(TransactionArgument)
});
const PublishTransaction = object({
kind: literal("Publish"),
modules: array(array(pipe(number(), integer()))),
dependencies: array(string())
});
const UpgradeTransaction = object({
kind: literal("Upgrade"),
modules: array(array(pipe(number(), integer()))),
dependencies: array(string()),
packageId: string(),
ticket: TransactionArgument
});
const TransactionTypes = [
MoveCallTransaction,
TransferObjectsTransaction,
SplitCoinsTransaction,
MergeCoinsTransaction,
PublishTransaction,
UpgradeTransaction,
MakeMoveVecTransaction
];
const TransactionType = union([...TransactionTypes]);
const SerializedTransactionDataV1 = object({
version: literal(1),
sender: optional(string()),
expiration: nullish(TransactionExpiration),
gasConfig: GasConfig,
inputs: array(TransactionInput),
transactions: array(TransactionType)
});
function serializeV1TransactionData(transactionData) {
const inputs = transactionData.inputs.map(
(input, index) => {
if (input.Object) {
return {
kind: "Input",
index,
value: {
Object: input.Object.ImmOrOwnedObject ? {
ImmOrOwned: input.Object.ImmOrOwnedObject
} : input.Object.Receiving ? {
Receiving: {
digest: input.Object.Receiving.digest,
version: input.Object.Receiving.version,
objectId: input.Object.Receiving.objectId
}
} : {
Shared: {
mutable: input.Object.SharedObject.mutable,
initialSharedVersion: input.Object.SharedObject.initialSharedVersion,
objectId: input.Object.SharedObject.objectId
}
}
},
type: "object"
};
}
if (input.Pure) {
return {
kind: "Input",
index,
value: {
Pure: Array.from(fromBase64(input.Pure.bytes))
},
type: "pure"
};
}
if (input.UnresolvedPure) {
return {
kind: "Input",
type: "pure",
index,
value: input.UnresolvedPure.value
};
}
if (input.UnresolvedObject) {
return {
kind: "Input",
type: "object",
index,
value: input.UnresolvedObject.objectId
};
}
throw new Error("Invalid input");
}
);
return {
version: 1,
sender: transactionData.sender ?? void 0,
expiration: transactionData.expiration?.$kind === "Epoch" ? { Epoch: Number(transactionData.expiration.Epoch) } : transactionData.expiration ? { None: true } : null,
gasConfig: {
owner: transactionData.gasData.owner ?? void 0,
budget: transactionData.gasData.budget ?? void 0,
price: transactionData.gasData.price ?? void 0,
payment: transactionData.gasData.payment ?? void 0
},
inputs,
transactions: transactionData.commands.map((command) => {
if (command.MakeMoveVec) {
return {
kind: "MakeMoveVec",
type: command.MakeMoveVec.type === null ? { None: true } : { Some: TypeTagSerializer.parseFromStr(command.MakeMoveVec.type) },
objects: command.MakeMoveVec.elements.map(
(arg) => convertTransactionArgument(arg, inputs)
)
};
}
if (command.MergeCoins) {
return {
kind: "MergeCoins",
destination: convertTransactionArgument(command.MergeCoins.destination, inputs),
sources: command.MergeCoins.sources.map((arg) => convertTransactionArgument(arg, inputs))
};
}
if (command.MoveCall) {
return {
kind: "MoveCall",
target: `${command.MoveCall.package}::${command.MoveCall.module}::${command.MoveCall.function}`,
typeArguments: command.MoveCall.typeArguments,
arguments: command.MoveCall.arguments.map(
(arg) => convertTransactionArgument(arg, inputs)
)
};
}
if (command.Publish) {
return {
kind: "Publish",
modules: command.Publish.modules.map((mod) => Array.from(fromBase64(mod))),
dependencies: command.Publish.dependencies
};
}
if (command.SplitCoins) {
return {
kind: "SplitCoins",
coin: convertTransactionArgument(command.SplitCoins.coin, inputs),
amounts: command.SplitCoins.amounts.map((arg) => convertTransactionArgument(arg, inputs))
};
}
if (command.TransferObjects) {
return {
kind: "TransferObjects",
objects: command.TransferObjects.objects.map(
(arg) => convertTransactionArgument(arg, inputs)
),
address: convertTransactionArgument(command.TransferObjects.address, inputs)
};
}
if (command.Upgrade) {
return {
kind: "Upgrade",
modules: command.Upgrade.modules.map((mod) => Array.from(fromBase64(mod))),
dependencies: command.Upgrade.dependencies,
packageId: command.Upgrade.package,
ticket: convertTransactionArgument(command.Upgrade.ticket, inputs)
};
}
throw new Error(`Unknown transaction ${Object.keys(command)}`);
})
};
}
function convertTransactionArgument(arg, inputs) {
if (arg.$kind === "GasCoin") {
return { kind: "GasCoin" };
}
if (arg.$kind === "Result") {
return { kind: "Result", index: arg.Result };
}
if (arg.$kind === "NestedResult") {
return { kind: "NestedResult", index: arg.NestedResult[0], resultIndex: arg.NestedResult[1] };
}
if (arg.$kind === "Input") {
return inputs[arg.Input];
}
throw new Error(`Invalid argument ${Object.keys(arg)}`);
}
function transactionDataFromV1(data) {
return parse(TransactionData, {
version: 2,
sender: data.sender ?? null,
expiration: data.expiration ? "Epoch" in data.expiration ? { Epoch: data.expiration.Epoch } : { None: true } : null,
gasData: {
owner: data.gasConfig.owner ?? null,
budget: data.gasConfig.budget?.toString() ?? null,
price: data.gasConfig.price?.toString() ?? null,
payment: data.gasConfig.payment?.map((ref) => ({
digest: ref.digest,
objectId: ref.objectId,
version: ref.version.toString()
})) ?? null
},
inputs: data.inputs.map((input) => {
if (input.kind === "Input") {
if (is(NormalizedCallArg, input.value)) {
const value = parse(NormalizedCallArg, input.value);
if (value.Object) {
if (value.Object.ImmOrOwned) {
return {
Object: {
ImmOrOwnedObject: {
objectId: value.Object.ImmOrOwned.objectId,
version: String(value.Object.ImmOrOwned.version),
digest: value.Object.ImmOrOwned.digest
}
}
};
}
if (value.Object.Shared) {
return {
Object: {
SharedObject: {
mutable: value.Object.Shared.mutable ?? null,
initialSharedVersion: value.Object.Shared.initialSharedVersion,
objectId: value.Object.Shared.objectId
}
}
};
}
if (value.Object.Receiving) {
return {
Object: {
Receiving: {
digest: value.Object.Receiving.digest,
version: String(value.Object.Receiving.version),
objectId: value.Object.Receiving.objectId
}
}
};
}
throw new Error("Invalid object input");
}
return {
Pure: {
bytes: toBase64(new Uint8Array(value.Pure))
}
};
}
if (input.type === "object") {
return {
UnresolvedObject: {
objectId: input.value
}
};
}
return {
UnresolvedPure: {
value: input.value
}
};
}
throw new Error("Invalid input");
}),
commands: data.transactions.map((transaction) => {
switch (transaction.kind) {
case "MakeMoveVec":
return {
MakeMoveVec: {
type: "Some" in transaction.type ? TypeTagSerializer.tagToString(transaction.type.Some) : null,
elements: transaction.objects.map((arg) => parseV1TransactionArgument(arg))
}
};
case "MergeCoins": {
return {
MergeCoins: {
destination: parseV1TransactionArgument(transaction.destination),
sources: transaction.sources.map((arg) => parseV1TransactionArgument(arg))
}
};
}
case "MoveCall": {
const [pkg, mod, fn] = transaction.target.split("::");
return {
MoveCall: {
package: pkg,
module: mod,
function: fn,
typeArguments: transaction.typeArguments,
arguments: transaction.arguments.map((arg) => parseV1TransactionArgument(arg))
}
};
}
case "Publish": {
return {
Publish: {
modules: transaction.modules.map((mod) => toBase64(Uint8Array.from(mod))),
dependencies: transaction.dependencies
}
};
}
case "SplitCoins": {
return {
SplitCoins: {
coin: parseV1TransactionArgument(transaction.coin),
amounts: transaction.amounts.map((arg) => parseV1TransactionArgument(arg))
}
};
}
case "TransferObjects": {
return {
TransferObjects: {
objects: transaction.objects.map((arg) => parseV1TransactionArgument(arg)),
address: parseV1TransactionArgument(transaction.address)
}
};
}
case "Upgrade": {
return {
Upgrade: {
modules: transaction.modules.map((mod) => toBase64(Uint8Array.from(mod))),
dependencies: transaction.dependencies,
package: transaction.packageId,
ticket: parseV1TransactionArgument(transaction.ticket)
}
};
}
}
throw new Error(`Unknown transaction ${Object.keys(transaction)}`);
})
});
}
function parseV1TransactionArgument(arg) {
switch (arg.kind) {
case "GasCoin": {
return { GasCoin: true };
}
case "Result":
return { Result: arg.index };
case "NestedResult": {
return { NestedResult: [arg.index, arg.resultIndex] };
}
case "Input": {
return { Input: arg.index };
}
}
}
export {
NormalizedCallArg,
ObjectRef,
SerializedTransactionDataV1,
StructTag,
TransactionArgument,
TypeTag,
serializeV1TransactionData,
transactionDataFromV1
};
//# sourceMappingURL=v1.js.map