Skip to content

Commit

Permalink
feat(sui): init support for enum type (#136)
Browse files Browse the repository at this point in the history
  • Loading branch information
zfy0701 authored Jan 23, 2025
1 parent 7cd751d commit f1293db
Show file tree
Hide file tree
Showing 14 changed files with 6,300 additions and 155 deletions.
2 changes: 1 addition & 1 deletion examples/sui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"gen": "typemove-sui -t ./src/types ./src/abis"
},
"dependencies": {
"@mysten/sui": "~1.17.0",
"@mysten/sui": "~1.20.0",
"@typemove/move": "workspace:*",
"@typemove/sui": "workspace:*"
},
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
"@ls-lint/ls-lint": "^2.2.3",
"@types/chai": "^5.0.1",
"@types/node": "^22.0.0",
"@typescript-eslint/eslint-plugin": "^8.0.0",
"@typescript-eslint/parser": "^8.0.0",
"@typescript-eslint/eslint-plugin": "^8.21.0",
"@typescript-eslint/parser": "^8.21.0",
"chai": "^5.1.2",
"conventional-changelog-conventionalcommits": "^8.0.0",
"eslint": "^9.6.0",
Expand All @@ -37,7 +37,7 @@
"tslib": "^2.6.2",
"tsx": "^4.10.0",
"typedoc": "^0.27.0",
"typescript": "^5.4.5"
"typescript": "^5.7.3"
},
"engines": {
"node": ">=20"
Expand Down
1 change: 1 addition & 0 deletions packages/aptos/src/move-coder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export class MoveCoder extends AbstractMoveCoder<MoveModuleBytecode, Event | Mov
if (m) {
return m
}
this.accounts.add(module.abi.address)
m = toInternalModule(module)
this.loadInternal(m, address)
return m
Expand Down
3 changes: 2 additions & 1 deletion packages/aptos/src/to-internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ export function toInternalModule(module: MoveModuleBytecode): InternalMoveModule
address: abi.address,
exposedFunctions: abi.exposed_functions.map(toInternalFunction),
name: abi.name,
structs: abi.structs.map(toInternalStruct)
structs: abi.structs.map(toInternalStruct),
enums: []
}
}

Expand Down
51 changes: 50 additions & 1 deletion packages/move/src/abstract-move-coder.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { accountAddressString, moduleQname, SPLITTER, VECTOR_STR } from './utils.js'
import { DecodedStruct, matchType, parseMoveType, TypeDescriptor } from './types.js'
import { InternalMoveFunction, InternalMoveModule, InternalMoveStruct } from './internal-models.js'
import { InternalMoveEnum, InternalMoveFunction, InternalMoveModule, InternalMoveStruct } from './internal-models.js'
// import { bytesToBigInt } from '../utils/index.js'
import { ChainAdapter } from './chain-adapter.js'

export abstract class AbstractMoveCoder<ModuleType, StructType> {
protected moduleMapping = new Map<string, InternalMoveModule>()
protected accounts = new Set<string>()
private typeMapping = new Map<string, InternalMoveStruct>()
private enumMapping = new Map<string, InternalMoveEnum>()

private funcMapping = new Map<string, InternalMoveFunction>()
// network: string
adapter: ChainAdapter<ModuleType, StructType>
Expand Down Expand Up @@ -36,6 +39,11 @@ export abstract class AbstractMoveCoder<ModuleType, StructType> {
return
}
this.moduleMapping.set(moduleQname({ address: account, name: module.name }), module)
for (const enumType of module.enums) {
const key = [account, module.name, enumType.name].join(SPLITTER)
this.enumMapping.set(key, enumType)
}

for (const struct of module.structs) {
// TODO move to util
const key = [account, module.name, struct.name].join(SPLITTER)
Expand Down Expand Up @@ -73,6 +81,9 @@ export abstract class AbstractMoveCoder<ModuleType, StructType> {
if (struct) {
return struct
}
if (this.accounts.has(account)) {
throw new Error('Failed to load struct ' + type + ' for imported account')
}
let resp = this.requestMap.get(account)
if (!resp) {
resp = this.adapter.fetchModules(account).then((modules) => {
Expand All @@ -90,6 +101,35 @@ export abstract class AbstractMoveCoder<ModuleType, StructType> {
throw new Error('Failed to load function ' + type + ' type are not imported anywhere')
}

async maybeGetMoveEnum(type: string): Promise<InternalMoveEnum | undefined> {
const [account_, module, typeName] = type.split(SPLITTER)
const account = accountAddressString(account_)
type = [account, module, typeName].join(SPLITTER)

let enumType = this.enumMapping.get(type)
if (enumType) {
return enumType
}
if (this.accounts.has(account)) {
return undefined
}
let resp = this.requestMap.get(account)
if (!resp) {
resp = this.adapter.fetchModules(account).then((modules) => {
for (const m of modules) {
this.load(m, account)
}
})
this.requestMap.set(account, resp)
}
await resp
enumType = this.enumMapping.get(type)
if (enumType) {
return enumType
}
return undefined
}

async getMoveFunction(type: string): Promise<InternalMoveFunction> {
const [account_, module, typeName] = type.split(SPLITTER)
const account = accountAddressString(account_)
Expand All @@ -99,6 +139,9 @@ export abstract class AbstractMoveCoder<ModuleType, StructType> {
if (func) {
return func
}
if (this.accounts.has(account)) {
throw new Error('Failed to load function ' + type + ' for imported account')
}
let resp = this.requestMap.get(account)
if (!resp) {
resp = this.adapter
Expand Down Expand Up @@ -163,6 +206,12 @@ export abstract class AbstractMoveCoder<ModuleType, StructType> {
return res as any
}

// try enum type first
const enumType = await this.maybeGetMoveEnum(type.qname)
if (enumType) {
return data
}

// Process complex type
const struct = await this.getMoveStruct(type.qname)

Expand Down
53 changes: 49 additions & 4 deletions packages/move/src/codegen/abstract-codegen.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { InternalMoveFunction, InternalMoveModule, InternalMoveStruct } from '../internal-models.js'
import { InternalMoveEnum, InternalMoveFunction, InternalMoveModule, InternalMoveStruct } from '../internal-models.js'
import path from 'path'
import fs from 'fs'
import { AccountModulesImportInfo, AccountRegister } from '../account.js'
Expand Down Expand Up @@ -190,13 +190,16 @@ export abstract class AbstractCodegen<ModuleTypes, StructType> {
const events = Array.from(eventStructs.values())
.map((e) => this.generateForEvents(module, e))
.filter((s) => s !== '')
const enums = module.enums.map((e) => this.generateEnum(module, e))
const structs = module.structs.map((s) => this.generateStructs(module, s, eventTypes))
const callArgs = module.exposedFunctions.map((f) => this.generateCallArgsStructs(module, f))

const moduleName = normalizeToJSName(module.name)
return `
export namespace ${moduleName} {
${enums.join('\n')}
${structs.join('\n')}
${this.generateExtra(addressOverride, module)}
Expand All @@ -208,6 +211,49 @@ export abstract class AbstractCodegen<ModuleTypes, StructType> {
`
}

generateEnum(module: InternalMoveModule, enumType: InternalMoveEnum): string {
const enumName = normalizeToJSName(enumType.name)
const enumValues = Object.keys(enumType.variants)
.map((v) => `'${v}'`)
.join(' | ')

const typeParams = enumType.typeParams || []
const genericString = this.generateStructTypeParameters(enumType)
const genericStringAny = this.generateStructTypeParameters(enumType, true)

const typeParamApplyArg = typeParams
.map((v, idx) => {
return `arg${idx}: TypeDescriptor<T${idx}> = ANY_TYPE`
})
.join(',')
const typeParamApply = typeParams
.map((v, idx) => {
return `arg${idx}`
})
.join(',')

const typeDescriptor = `
export namespace ${enumName}{
export const TYPE_QNAME = '${module.address}::${module.name}::${enumType.name}'
const TYPE = new TypeDescriptor<${enumName}${genericStringAny}>(${enumName}.TYPE_QNAME)
export function type${genericString}(${typeParamApplyArg}): TypeDescriptor<${enumName}${genericString}> {
return TYPE.apply(${typeParamApply})
}
}
`
// TODO support fields
return `
export interface ${enumName} {
fields: {}
variant: ${enumValues}
}
${typeDescriptor}
`
}

generateStructs(module: InternalMoveModule, struct: InternalMoveStruct, events: Set<string>, typeOnly = false) {
const typeParams = struct.typeParams || []
const genericString = this.generateStructTypeParameters(struct)
Expand Down Expand Up @@ -249,8 +295,7 @@ export abstract class AbstractCodegen<ModuleTypes, StructType> {
let eventPayload = ''
if (events.has(moduleQname(module) + SPLITTER + struct.name)) {
eventPayload = `
export interface ${structName}Instance extends
TypedEventInstance<${structName}${genericStringAny}> {
export type ${structName}Instance = TypedEventInstance<${structName}${genericStringAny}> & {
${this.STRUCT_FIELD_NAME}_decoded: ${structName}${genericStringAny}
type_arguments: [${struct.typeParams.map((_) => 'string').join(', ')}]
}
Expand Down Expand Up @@ -293,7 +338,7 @@ export abstract class AbstractCodegen<ModuleTypes, StructType> {
return '[' + returnType + ']'
}

generateStructTypeParameters(struct: InternalMoveStruct, useAny = false) {
generateStructTypeParameters(struct: InternalMoveStruct | InternalMoveEnum, useAny = false) {
let genericString = ''

if (struct.typeParams && struct.typeParams.length > 0) {
Expand Down
10 changes: 10 additions & 0 deletions packages/move/src/internal-models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export interface InternalMoveModule {
name: string
exposedFunctions: InternalMoveFunction[]
structs: InternalMoveStruct[]
enums: InternalMoveEnum[]
}

export interface InternalMoveFunction {
Expand All @@ -26,6 +27,15 @@ export interface InternalMoveStruct {
fields: InternalMoveStructField[]
}

export interface InternalMoveEnum {
name: string
abilities: string[]
typeParams: InternalMoveTypeParam[]
variants: {
[key: string]: InternalMoveStructField[]
}
}

export interface InternalMoveStructField {
name: string
type: TypeDescriptor
Expand Down
2 changes: 1 addition & 1 deletion packages/sui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
},
"types": "./dist/cjs/index.d.ts",
"dependencies": {
"@mysten/sui": "~1.17.0",
"@mysten/sui": "~1.20.0",
"@typemove/move": "workspace:*",
"chalk": "^5.3.0",
"commander": "^12.0.0",
Expand Down
4 changes: 3 additions & 1 deletion packages/sui/src/move-coder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { BUILTIN_TYPES, parseMoveType } from '@typemove/move'
import { defaultMoveCoder } from '@typemove/sui'
import { dynamic_field } from './builtin/0x2'
import { sui_system_state_inner } from './builtin/0x3'
import { SuiEvent } from '@mysten/sui/client'

describe('Test move coder', () => {
test('decode upgraded struct', async () => {
Expand Down Expand Up @@ -45,6 +46,7 @@ describe('Test move coder', () => {
test('decode upgraded', async () => {
const coder = defaultMoveCoder()
const upgradedEvent = {
bcsEncoding: 'base58',
bcs: '2EEdtVSdQuBDwz8GqTfB83ac62AAy2maSVE9SqwUFpXdqSPGhRvrZz3WEyJavAhSmVtU86Y2AkkK5pSw6MYzcKsdowaso8N8B7Ur8XiZ9xienTkNzNTf7mmfgWJWMqpYVKkdbJTj76WNzJs5Sd6U3FzCzmg4y5EgW85knAoBZjzBwPUsQ3tMHDcihpX7wVtnEVttdzLnq3ZK97u1hAJSyDUrRVThpScej1kjjRLe2Up3mYYo7JsH8uhrq7bACkQKPCbK88d8arAUuYaMNw7zPSyn6yzyHoSnNUscbAVdfmn4ePb8DZTCw6dbAcUDPR82y5kWwzQC3NcYK5N4BX3w7UUhhrvPtdKM1e1isMnbWuMxXPhydQQD9RnJKfZTU54jdcWzwtQrDaGkuaVPUQvZ2ywVVav57ooS6Uf',
id: { txDigest: 'C9LuM3bJhAXg4whUa9DrszA8zTGEoptFGAmFvFs7H1mk', eventSeq: '1' },
packageId: '0xceab84acf6bf70f503c3b0627acaff6b3f84cee0f2d7ed53d00fa6c2a168d14f',
Expand All @@ -71,7 +73,7 @@ describe('Test move coder', () => {
}
}
}
}
} as SuiEvent

const res = await coder.decodeEvent(upgradedEvent)
})
Expand Down
1 change: 1 addition & 0 deletions packages/sui/src/move-coder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export class MoveCoder extends AbstractMoveCoder<
if (m && mDeclared) {
return m
}
this.accounts.add(module.address)
m = toInternalModule(module)
this.loadInternal(m, address)
return m
Expand Down
Loading

0 comments on commit f1293db

Please sign in to comment.