@@ -23,9 +23,9 @@ import {
2323 FunctionABI ,
2424 TypeArgument ,
2525} from "../types" ;
26- import { Bool , MoveOption , MoveString , MoveVector , U128 , U16 , U256 , U32 , U64 , U8 } from "../../bcs" ;
26+ import { Bool , FixedBytes , MoveOption , MoveString , MoveVector , U128 , U16 , U256 , U32 , U64 , U8 } from "../../bcs" ;
2727import { AccountAddress } from "../../core" ;
28- import { getModule } from "../../internal/utils " ;
28+ import { getModule } from "../../internal/account " ;
2929import {
3030 findFirstNonSignerArg ,
3131 isBcsAddress ,
@@ -45,7 +45,7 @@ import {
4545 throwTypeMismatch ,
4646 convertNumber ,
4747} from "./helpers" ;
48- import { CallArgument , MoveFunction } from "../../types" ;
48+ import { CallArgument , MoveFunction , MoveModule } from "../../types" ;
4949
5050const TEXT_ENCODER = new TextEncoder ( ) ;
5151
@@ -69,6 +69,24 @@ export function standardizeTypeTags(typeArguments?: Array<TypeArgument>): Array<
6969 ) ;
7070}
7171
72+ /**
73+ * Fetches the ABI of a specified module from the on-chain module ABI.
74+ *
75+ * @param moduleAddress - The address of the module from which to fetch the ABI.
76+ * @param moduleName - The name of the module containing the ABI.
77+ * @param aptosConfig - The configuration settings for Aptos.
78+ * @group Implementation
79+ * @category Transactions
80+ */
81+ export async function fetchModuleAbi (
82+ moduleAddress : string ,
83+ moduleName : string ,
84+ aptosConfig : AptosConfig ,
85+ ) : Promise < MoveModule | undefined > {
86+ const moduleBytecode = await getModule ( { aptosConfig, accountAddress : moduleAddress , moduleName } ) ;
87+ return moduleBytecode . abi ;
88+ }
89+
7290/**
7391 * Fetches the ABI of a specified function from the on-chain module ABI. This function allows you to access the details of a
7492 * specific function within a module.
@@ -86,22 +104,13 @@ export async function fetchFunctionAbi(
86104 functionName : string ,
87105 aptosConfig : AptosConfig ,
88106) : Promise < MoveFunction | undefined > {
89- // This fetch from the API is currently cached
90- const module = await getModule ( { aptosConfig, accountAddress : moduleAddress , moduleName } ) ;
91-
92- if ( module . abi ) {
93- return module . abi . exposed_functions . find ( ( func ) => func . name === functionName ) ;
94- }
95-
96- return undefined ;
107+ const moduleAbi = await fetchModuleAbi ( moduleAddress , moduleName , aptosConfig ) ;
108+ if ( ! moduleAbi ) throw new Error ( `Could not find module ABI for '${ moduleAddress } ::${ moduleName } '` ) ;
109+ return moduleAbi . exposed_functions . find ( ( func ) => func . name === functionName ) ;
97110}
98111
99112/**
100- * Fetches a function ABI from the on-chain module ABI. It doesn't validate whether it's a view or entry function.
101- * @param moduleAddress
102- * @param moduleName
103- * @param functionName
104- * @param aptosConfig
113+ * @deprecated Use `fetchFunctionAbi` instead and manually parse the type tags.
105114 */
106115export async function fetchMoveFunctionAbi (
107116 moduleAddress : string ,
@@ -220,15 +229,14 @@ export async function fetchViewFunctionAbi(
220229}
221230
222231/**
223- * Converts a entry function argument into CallArgument, if necessary.
224- * This function checks the provided argument against the expected parameter type and converts it accordingly.
232+ * @deprecated Handle this inline
225233 *
226- * @param functionName - The name of the function for which the argument is being converted.
227- * @param functionAbi - The ABI (Application Binary Interface) of the function, which defines its parameters.
228- * @param argument - The argument to be converted, which can be of various types. If the argument is already
229- * CallArgument returned from TransactionComposer it would be returned immediately.
230- * @param position - The index of the argument in the function's parameter list.
231- * @param genericTypeParams - An array of type tags for any generic type parameters.
234+ * @example
235+ * ```typescript
236+ * const callArgument = argument instanceof CallArgument ? argument : CallArgument.newBytes(
237+ * convertArgument(functionName, functionAbi, argument, position, genericTypeParams).bcsToBytes()
238+ * );
239+ * ```
232240 */
233241export function convertCallArgument (
234242 argument : CallArgument | EntryFunctionArgumentTypes | SimpleEntryFunctionArgumentTypes ,
@@ -250,27 +258,54 @@ export function convertCallArgument(
250258 * This function checks the provided argument against the expected parameter type and converts it accordingly.
251259 *
252260 * @param functionName - The name of the function for which the argument is being converted.
253- * @param functionAbi - The ABI (Application Binary Interface) of the function, which defines its parameters.
261+ * @param functionAbiOrModuleAbi - The ABI (Application Binary Interface) of the function, which defines its parameters.
254262 * @param arg - The argument to be converted, which can be of various types.
255263 * @param position - The index of the argument in the function's parameter list.
256264 * @param genericTypeParams - An array of type tags for any generic type parameters.
265+ * @param options - Options for the conversion process.
266+ * @param options.allowUnknownStructs - If true, unknown structs will be allowed and converted to a `FixedBytes`.
257267 * @group Implementation
258268 * @category Transactions
259269 */
260270export function convertArgument (
261271 functionName : string ,
262- functionAbi : FunctionABI ,
272+ functionAbiOrModuleAbi : MoveModule | FunctionABI ,
263273 arg : EntryFunctionArgumentTypes | SimpleEntryFunctionArgumentTypes ,
264274 position : number ,
265275 genericTypeParams : Array < TypeTag > ,
276+ options ?: { allowUnknownStructs ?: boolean } ,
266277) {
267- // Ensure not too many arguments
268- if ( position >= functionAbi . parameters . length ) {
269- throw new Error ( `Too many arguments for '${ functionName } ', expected ${ functionAbi . parameters . length } ` ) ;
278+ let param : TypeTag ;
279+
280+ if ( "exposed_functions" in functionAbiOrModuleAbi ) {
281+ const functionAbi = functionAbiOrModuleAbi . exposed_functions . find ( ( func ) => func . name === functionName ) ;
282+ if ( ! functionAbi ) {
283+ throw new Error (
284+ `Could not find function ABI for '${ functionAbiOrModuleAbi . address } ::${ functionAbiOrModuleAbi . name } ::${ functionName } '` ,
285+ ) ;
286+ }
287+
288+ if ( position >= functionAbi . params . length ) {
289+ throw new Error ( `Too many arguments for '${ functionName } ', expected ${ functionAbi . params . length } ` ) ;
290+ }
291+
292+ param = parseTypeTag ( functionAbi . params [ position ] , { allowGenerics : true } ) ;
293+ } else {
294+ if ( position >= functionAbiOrModuleAbi . parameters . length ) {
295+ throw new Error ( `Too many arguments for '${ functionName } ', expected ${ functionAbiOrModuleAbi . parameters . length } ` ) ;
296+ }
297+
298+ param = functionAbiOrModuleAbi . parameters [ position ] ;
270299 }
271300
272- const param = functionAbi . parameters [ position ] ;
273- return checkOrConvertArgument ( arg , param , position , genericTypeParams ) ;
301+ return checkOrConvertArgument (
302+ arg ,
303+ param ,
304+ position ,
305+ genericTypeParams ,
306+ "exposed_functions" in functionAbiOrModuleAbi ? functionAbiOrModuleAbi : undefined ,
307+ options ,
308+ ) ;
274309}
275310
276311/**
@@ -289,6 +324,8 @@ export function checkOrConvertArgument(
289324 param : TypeTag ,
290325 position : number ,
291326 genericTypeParams : Array < TypeTag > ,
327+ moduleAbi ?: MoveModule ,
328+ options ?: { allowUnknownStructs ?: boolean } ,
292329) {
293330 // If the argument is bcs encoded, we can just use it directly
294331 if ( isEncodedEntryFunctionArgument ( arg ) ) {
@@ -301,6 +338,8 @@ export function checkOrConvertArgument(
301338 * @param typeArgs - The expected type arguments.
302339 * @param arg - The argument to be checked.
303340 * @param position - The position of the argument in the context of the check.
341+ * @param moduleAbi - The ABI of the module containing the function, used for type checking.
342+ * This will typically have information about structs, enums, and other types.
304343 * @group Implementation
305344 * @category Transactions
306345 */
@@ -309,7 +348,7 @@ export function checkOrConvertArgument(
309348 }
310349
311350 // If it is not BCS encoded, we will need to convert it with the ABI
312- return parseArg ( arg , param , position , genericTypeParams ) ;
351+ return parseArg ( arg , param , position , genericTypeParams , moduleAbi , options ) ;
313352}
314353
315354/**
@@ -321,6 +360,10 @@ export function checkOrConvertArgument(
321360 * @param param - The type tag that defines the expected type of the argument.
322361 * @param position - The position of the argument in the function call, used for error reporting.
323362 * @param genericTypeParams - An array of type tags for generic type parameters, used when the parameter type is generic.
363+ * @param moduleAbi - The ABI of the module containing the function, used for type checking.
364+ * This will typically have information about structs, enums, and other types.
365+ * @param options - Options for the conversion process.
366+ * @param options.allowUnknownStructs - If true, unknown structs will be allowed and converted to a `FixedBytes`.
324367 * @group Implementation
325368 * @category Transactions
326369 */
@@ -329,6 +372,8 @@ function parseArg(
329372 param : TypeTag ,
330373 position : number ,
331374 genericTypeParams : Array < TypeTag > ,
375+ moduleAbi ?: MoveModule ,
376+ options ?: { allowUnknownStructs ?: boolean } ,
332377) : EntryFunctionArgumentTypes {
333378 if ( param . isBool ( ) ) {
334379 if ( isBool ( arg ) ) {
@@ -403,7 +448,7 @@ function parseArg(
403448 throw new Error ( `Generic argument ${ param . toString ( ) } is invalid for argument ${ position } ` ) ;
404449 }
405450
406- return checkOrConvertArgument ( arg , genericTypeParams [ genericIndex ] , position , genericTypeParams ) ;
451+ return checkOrConvertArgument ( arg , genericTypeParams [ genericIndex ] , position , genericTypeParams , moduleAbi ) ;
407452 }
408453
409454 // We have to special case some vectors for Vector<u8>
@@ -433,7 +478,9 @@ function parseArg(
433478 // TODO: Support Uint16Array, Uint32Array, BigUint64Array?
434479
435480 if ( Array . isArray ( arg ) ) {
436- return new MoveVector ( arg . map ( ( item ) => checkOrConvertArgument ( item , param . value , position , genericTypeParams ) ) ) ;
481+ return new MoveVector (
482+ arg . map ( ( item ) => checkOrConvertArgument ( item , param . value , position , genericTypeParams , moduleAbi ) ) ,
483+ ) ;
437484 }
438485
439486 throw new Error ( `Type mismatch for argument ${ position } , type '${ param . toString ( ) } '` ) ;
@@ -454,6 +501,13 @@ function parseArg(
454501 }
455502 throwTypeMismatch ( "string | AccountAddress" , position ) ;
456503 }
504+ // Handle known enum types from Aptos framework
505+ if ( param . isDelegationKey ( ) || param . isRateLimiter ( ) ) {
506+ if ( arg instanceof Uint8Array ) {
507+ return new FixedBytes ( arg ) ;
508+ }
509+ throwTypeMismatch ( "Uint8Array" , position ) ;
510+ }
457511
458512 if ( param . isOption ( ) ) {
459513 if ( isEmptyOption ( arg ) ) {
@@ -490,7 +544,25 @@ function parseArg(
490544 return new MoveOption < MoveString > ( null ) ;
491545 }
492546
493- return new MoveOption ( checkOrConvertArgument ( arg , param . value . typeArgs [ 0 ] , position , genericTypeParams ) ) ;
547+ return new MoveOption (
548+ checkOrConvertArgument ( arg , param . value . typeArgs [ 0 ] , position , genericTypeParams , moduleAbi ) ,
549+ ) ;
550+ }
551+
552+ // We are assuming that fieldless structs are enums, and therefore we cannot typecheck any further due
553+ // to limited information from the ABI. This does not work for structs on other modules.
554+ const structDefinition = moduleAbi ?. structs . find ( ( s ) => s . name === param . value . name . identifier ) ;
555+ if ( structDefinition ?. fields . length === 0 && arg instanceof Uint8Array ) {
556+ return new FixedBytes ( arg ) ;
557+ }
558+
559+ if ( arg instanceof Uint8Array && options ?. allowUnknownStructs ) {
560+ // eslint-disable-next-line no-console
561+ console . warn (
562+ // eslint-disable-next-line max-len
563+ `Unsupported struct input type for argument ${ position } . Continuing since 'allowUnknownStructs' is enabled.` ,
564+ ) ;
565+ return new FixedBytes ( arg ) ;
494566 }
495567
496568 throw new Error ( `Unsupported struct input type for argument ${ position } , type '${ param . toString ( ) } '` ) ;
0 commit comments