Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement the ABI lookup support by enhancing the MoveStructType inte… #631

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
24 changes: 20 additions & 4 deletions src/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1185,8 +1185,22 @@ export type MoveStructId = `${string}::${string}::${string}`;
*/
export type MoveFunctionId = MoveStructId;

// TODO: Add support for looking up ABI to add proper typing
export type MoveStructType = {};
/**
* Represents a Move struct type with proper ABI support.
* This type allows for dynamic lookup of struct fields and their types from the ABI.
*/
export type MoveStructType = {
/** The fully qualified name of the struct in format address::module::name */
type: MoveStructId;
/** The fields of the struct as defined in the ABI */
fields: {
[key: string]: MoveType;
};
/** Optional generic type parameters */
genericTypeParams?: Array<MoveFunctionGenericTypeParam>;
/** The abilities of the struct as defined in the ABI */
abilities?: Array<MoveAbility>;
};

/**
* A union type that encompasses various data types used in Move, including primitive types, address types, object types, and
Expand Down Expand Up @@ -1225,7 +1239,7 @@ export type MoveType =
*
* `Object -> 0x${string}`
*
* `Vector -> Array<MoveValue>`
* `Vector -> Array<MoveValue> | { vec: MoveValue[] }`
*
* `Option -> MoveValue | null | undefined`
*/
Expand All @@ -1242,7 +1256,9 @@ export type MoveValue =
| MoveObjectType
| MoveStructId
| MoveOptionType
| Array<MoveValue>;
| Array<MoveValue>
| { vec: MoveValue[] }
| { [key: string]: MoveValue };

/**
* A string representation of a Move module, formatted as `module_name::function_name`.
Expand Down
121 changes: 121 additions & 0 deletions tests/unit/moveStructType.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// Copyright © Aptos Foundation
// SPDX-License-Identifier: Apache-2.0

/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-env jest */
import { MoveStructType, MoveAbility, MoveFunctionGenericTypeParam } from "../../src/types/types";

test("should create a basic Move struct type", () => {
const basicStruct: MoveStructType = {
type: "0x1::coin::CoinStore",
fields: {
coin: "0x1::coin::Coin",
frozen: "bool",
deposit_events: "0x1::event::EventHandle",
withdraw_events: "0x1::event::EventHandle",
},
};

expect(basicStruct.type).toBe("0x1::coin::CoinStore");
expect(basicStruct.fields).toBeDefined();
expect(Object.keys(basicStruct.fields).length).toBe(4);
expect(basicStruct.fields.coin).toBe("0x1::coin::Coin");
expect(basicStruct.fields.frozen).toBe("bool");
});

test("should create a Move struct type with generic parameters", () => {
const genericTypeParams: Array<MoveFunctionGenericTypeParam> = [
{
constraints: [MoveAbility.STORE, MoveAbility.DROP],
},
];

const genericStruct: MoveStructType = {
type: "0x1::option::Option",
fields: {
vec: "vector<T>",
},
genericTypeParams,
};

expect(genericStruct.genericTypeParams).toBeDefined();
expect(genericStruct.genericTypeParams?.length).toBe(1);
expect(genericStruct.genericTypeParams?.[0].constraints).toContain(MoveAbility.STORE);
expect(genericStruct.genericTypeParams?.[0].constraints).toContain(MoveAbility.DROP);
});

test("should create a Move struct type with abilities", () => {
const structWithAbilities: MoveStructType = {
type: "0x1::coin::Coin",
fields: {
value: "u64",
},
abilities: [MoveAbility.STORE, MoveAbility.KEY],
};

expect(structWithAbilities.abilities).toBeDefined();
expect(structWithAbilities.abilities?.length).toBe(2);
expect(structWithAbilities.abilities).toContain(MoveAbility.STORE);
expect(structWithAbilities.abilities).toContain(MoveAbility.KEY);
});

test("should handle complex struct type with nested fields", () => {
const complexStruct: MoveStructType = {
type: "0x1::account::Account",
fields: {
authentication_key: "vector<u8>",
sequence_number: "u64",
guid_creation_num: "u64",
coin_register_events: "0x1::event::EventHandle",
rotation_capability_offer: {
type: "0x1::account::CapabilityOffer",
fields: {
for: "address",
},
},
},
};

expect(complexStruct.type).toBe("0x1::account::Account");
expect(complexStruct.fields.authentication_key).toBe("vector<u8>");
expect((complexStruct.fields.rotation_capability_offer as MoveStructType).type).toBe(
"0x1::account::CapabilityOffer",
);
expect((complexStruct.fields.rotation_capability_offer as MoveStructType).fields.for).toBe("address");
});

test("should create a Move struct type with all optional properties", () => {
const fullStruct: MoveStructType = {
type: "0x1::table::Table",
fields: {
handle: "address",
length: "u64",
},
genericTypeParams: [
{
constraints: [MoveAbility.COPY, MoveAbility.DROP],
},
{
constraints: [MoveAbility.STORE],
},
],
abilities: [MoveAbility.STORE, MoveAbility.DROP],
};

expect(fullStruct).toMatchObject({
type: "0x1::table::Table",
fields: {
handle: "address",
length: "u64",
},
genericTypeParams: [
{
constraints: [MoveAbility.COPY, MoveAbility.DROP],
},
{
constraints: [MoveAbility.STORE],
},
],
abilities: [MoveAbility.STORE, MoveAbility.DROP],
});
});