import { AbstractMoveCoder, InternalMoveModule, parseMoveType, TypeDescriptor } from '@typemove/move' import { TypedEventInstance, TypedFunctionPayload, TypedMoveResource } from './models.js' import { AptosChainAdapter } from './aptos-chain-adapter.js' import { toInternalModule } from './to-internal.js' import { Aptos, AptosConfig, EntryFunctionPayloadResponse, Event, MoveModuleBytecode, MoveResource, MoveValue, Network } from '@aptos-labs/ts-sdk' export class MoveCoder extends AbstractMoveCoder { constructor( client: Aptos, readonly ignoreObjectInnerField: boolean = false ) { super(new AptosChainAdapter(client)) } load(module: MoveModuleBytecode, address: string): InternalMoveModule { if (!module.abi) { throw Error('Module without abi') } let m = this.moduleMapping.get(module.abi.address + '::' + module.abi.name) // if (this.contains(module.abi.address, module.abi.name)) { // return // } if (m) { return m } this.accounts.add(module.abi.address) m = toInternalModule(module) this.loadInternal(m, address) return m } decodeEvent(event: Event): Promise | undefined> { // TODO fix type return this.decodedStruct(event) } filterAndDecodeEvents(type: string | TypeDescriptor, resources: Event[]): Promise[]> { if (typeof type === 'string') { type = parseMoveType(type) } // TODO fix type return this.filterAndDecodeStruct(type, resources) } decodeResource(res: MoveResource): Promise | undefined> { return this.decodedStruct(res) } protected async decode(data: any, type: TypeDescriptor): Promise { switch (type.qname) { case '0x1::object::Object': if (this.ignoreObjectInnerField && typeof data === 'string') { return data } if (typeof data === 'object' && data?.inner !== undefined && typeof data?.inner === 'string') { return data.inner } } return super.decode(data, type) } filterAndDecodeResources( type: string | TypeDescriptor, resources: MoveResource[] ): Promise[]> { if (typeof type === 'string') { type = parseMoveType(type) } return this.filterAndDecodeStruct(type, resources) } async decodeFunctionPayload>( payload: EntryFunctionPayloadResponse ): Promise> { const func = await this.getMoveFunction(payload.function) const params = this.adapter.getMeaningfulFunctionParams(func.params) const argumentsDecoded = await this.decodeArray(payload.arguments, params) return { ...payload, arguments_decoded: argumentsDecoded } as TypedFunctionPayload } toMoveValue(value: any): MoveValue { switch (typeof value) { case 'boolean': return value case 'number': return value case 'bigint': return value.toString() case 'object': if (Array.isArray(value)) { return value.map(this.toMoveValue) } return value default: return value.toString() } } } const DEFAULT_CONFIG = new AptosConfig({ network: Network.MAINNET }) const CODER_MAP = new Map() export function defaultMoveCoder(config = DEFAULT_CONFIG): MoveCoder { const configKey = config.fullnode ? config.fullnode : config.network let coder = CODER_MAP.get(configKey) if (!coder) { coder = new MoveCoder(new Aptos(config)) CODER_MAP.set(configKey, coder) } return coder }