diff --git a/CHANGELOG.md b/CHANGELOG.md index d73f90a38..41a73889f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ All notable changes to the Aptos TypeScript SDK will be captured in this file. T - Add `transferFungibleAsset` function to easily generate a transaction to transfer a fungible asset from sender's primary store to recipient's primary store - [`Breaking`] `AccountAddress.fromRelaxed` is now `AccountAddress.from`, and a new `AccountAddress.fromStrict` has the old functionality. - Implement transaction management worker layer to manage transaction submission for a single account with a high throughput +- [`Fixed`] Allow for Uint8Array to be passed as a `vector` argument on entry functions +- [`Fixed`] Allow for raw vectors to be passed as arguments with encoded types within them for Remote ABI on entry functions e.g. [AccountAddress] ## 0.0.7 (2023-11-16) diff --git a/src/transactions/transactionBuilder/helpers.ts b/src/transactions/transactionBuilder/helpers.ts index 578317565..c79e2cdba 100644 --- a/src/transactions/transactionBuilder/helpers.ts +++ b/src/transactions/transactionBuilder/helpers.ts @@ -8,7 +8,7 @@ import { InputScriptData, SimpleEntryFunctionArgumentTypes, } from "../types"; -import { Bool, FixedBytes, MoveString, U128, U16, U256, U32, U64, U8 } from "../../bcs"; +import { Bool, FixedBytes, MoveOption, MoveString, MoveVector, U128, U16, U256, U32, U64, U8 } from "../../bcs"; import { AccountAddress } from "../../core"; import { MoveFunction, MoveFunctionId } from "../../types"; @@ -32,17 +32,39 @@ export function isNull(arg: SimpleEntryFunctionArgumentTypes): arg is null | und return arg === null || arg === undefined; } +export function isEncodedEntryFunctionArgument( + arg: EntryFunctionArgumentTypes | SimpleEntryFunctionArgumentTypes, +): arg is EntryFunctionArgumentTypes { + return ( + isBcsBool(arg) || + isBcsU8(arg) || + isBcsU16(arg) || + isBcsU32(arg) || + isBcsU64(arg) || + isBcsU128(arg) || + isBcsU256(arg) || + isBcsAddress(arg) || + isBcsString(arg) || + isBcsFixedBytes(arg) || + arg instanceof MoveVector || + arg instanceof MoveOption + ); +} + export function isBcsBool(arg: EntryFunctionArgumentTypes | SimpleEntryFunctionArgumentTypes): arg is Bool { return arg instanceof Bool; } + export function isBcsAddress( arg: EntryFunctionArgumentTypes | SimpleEntryFunctionArgumentTypes, ): arg is AccountAddress { return arg instanceof AccountAddress; } + export function isBcsString(arg: EntryFunctionArgumentTypes | SimpleEntryFunctionArgumentTypes): arg is MoveString { return arg instanceof MoveString; } + export function isBcsFixedBytes(arg: EntryFunctionArgumentTypes | SimpleEntryFunctionArgumentTypes): arg is FixedBytes { return arg instanceof FixedBytes; } @@ -50,18 +72,23 @@ export function isBcsFixedBytes(arg: EntryFunctionArgumentTypes | SimpleEntryFun export function isBcsU8(arg: EntryFunctionArgumentTypes | SimpleEntryFunctionArgumentTypes): arg is U8 { return arg instanceof U8; } + export function isBcsU16(arg: EntryFunctionArgumentTypes | SimpleEntryFunctionArgumentTypes): arg is U16 { return arg instanceof U16; } + export function isBcsU32(arg: EntryFunctionArgumentTypes | SimpleEntryFunctionArgumentTypes): arg is U32 { return arg instanceof U32; } + export function isBcsU64(arg: EntryFunctionArgumentTypes | SimpleEntryFunctionArgumentTypes): arg is U64 { return arg instanceof U64; } + export function isBcsU128(arg: EntryFunctionArgumentTypes | SimpleEntryFunctionArgumentTypes): arg is U128 { return arg instanceof U128; } + export function isBcsU256(arg: EntryFunctionArgumentTypes | SimpleEntryFunctionArgumentTypes): arg is U256 { return arg instanceof U256; } diff --git a/src/transactions/transactionBuilder/remoteAbi.ts b/src/transactions/transactionBuilder/remoteAbi.ts index d9a99d4a4..06101a333 100644 --- a/src/transactions/transactionBuilder/remoteAbi.ts +++ b/src/transactions/transactionBuilder/remoteAbi.ts @@ -12,7 +12,6 @@ import { findFirstNonSignerArg, isBcsAddress, isBcsBool, - isBcsFixedBytes, isBcsString, isBcsU128, isBcsU16, @@ -21,6 +20,7 @@ import { isBcsU64, isBcsU8, isBool, + isEncodedEntryFunctionArgument, isLargeNumber, isNull, isNumber, @@ -104,28 +104,25 @@ export function convertArgument( throw new Error(`Too many arguments for '${functionName}', expected ${functionAbi.parameters.length}`); } + const param = functionAbi.parameters[position]; + return checkOrConvertArgument(arg, param, position, genericTypeParams); +} + +export function checkOrConvertArgument( + arg: SimpleEntryFunctionArgumentTypes | EntryFunctionArgumentTypes, + param: TypeTag, + position: number, + genericTypeParams: Array, +) { // If the argument is bcs encoded, we can just use it directly - if ( - isBcsBool(arg) || - isBcsU8(arg) || - isBcsU16(arg) || - isBcsU32(arg) || - isBcsU64(arg) || - isBcsU128(arg) || - isBcsU256(arg) || - isBcsAddress(arg) || - isBcsString(arg) || - isBcsFixedBytes(arg) || - arg instanceof MoveVector || - arg instanceof MoveOption - ) { + if (isEncodedEntryFunctionArgument(arg)) { // Ensure the type matches the ABI - checkType(functionAbi, arg, position); + checkType(param, arg, position); return arg; } // If it is not BCS encoded, we will need to convert it with the ABI - return parseArg(arg, functionAbi.parameters[position], position, genericTypeParams); + return parseArg(arg, param, position, genericTypeParams); } /** @@ -198,19 +195,30 @@ function parseArg( throw new Error(`Generic argument ${param.toString()} is invalid for argument ${position}`); } - parseArg(arg, genericTypeParams[genericIndex], position, genericTypeParams); + checkOrConvertArgument(arg, genericTypeParams[genericIndex], position, genericTypeParams); } // We have to special case some vectors for Vector if (param.isVector()) { // Check special case for Vector - if (param.value.isU8() && isString(arg)) { - // TODO: Improve message when hex is invalid - return MoveVector.U8(Hex.fromHexInput(arg).toUint8Array()); + if (param.value.isU8()) { + if (isString(arg)) { + try { + return MoveVector.U8(Hex.fromHexInput(arg).toUint8Array()); + } catch (e: any) { + // This is a bit of a hack to not reuse code, but also have a better error message + throw new Error(`vector must be passed in as a hex string or a Uint8array, type '${param.toString()}'`); + } + } + if (arg instanceof Uint8Array) { + return MoveVector.U8(arg); + } } + // TODO: Support Uint16Array, Uint32Array, BigUint64Array? + if (Array.isArray(arg)) { - return new MoveVector(arg.map((item) => parseArg(item, param.value, position, genericTypeParams))); + return new MoveVector(arg.map((item) => checkOrConvertArgument(item, param.value, position, genericTypeParams))); } throw new Error(`Type mismatch for argument ${position}, type '${param.toString()}'`); @@ -239,7 +247,7 @@ function parseArg( return new MoveOption(null); } - return new MoveOption(parseArg(arg, param.value.typeArgs[0], position, genericTypeParams)); + return new MoveOption(checkOrConvertArgument(arg, param.value.typeArgs[0], position, genericTypeParams)); } throw new Error(`Unsupported struct input type for argument ${position}, type '${param.toString()}'`); @@ -250,12 +258,11 @@ function parseArg( /** * Checks that the type of an already BCS encoded argument matches the ABI - * @param functionAbi + * @param param * @param arg * @param position */ -function checkType(functionAbi: EntryFunctionABI, arg: EntryFunctionArgumentTypes, position: number) { - const param = functionAbi.parameters[position]; +function checkType(param: TypeTag, arg: EntryFunctionArgumentTypes, position: number) { if (param.isBool()) { if (isBcsBool(arg)) { return; diff --git a/src/transactions/transactionBuilder/transactionBuilder.ts b/src/transactions/transactionBuilder/transactionBuilder.ts index 00c6587ea..da96182c9 100644 --- a/src/transactions/transactionBuilder/transactionBuilder.ts +++ b/src/transactions/transactionBuilder/transactionBuilder.ts @@ -171,12 +171,7 @@ export function generateTransactionPayloadWithABI( // Send it as multi sig if it's a multisig payload if ("multisigAddress" in args) { - let multisigAddress: AccountAddress; - if (typeof args.multisigAddress === "string") { - multisigAddress = AccountAddress.from(args.multisigAddress); - } else { - multisigAddress = args.multisigAddress; - } + const multisigAddress = AccountAddress.from(args.multisigAddress); return new TransactionPayloadMultisig( new MultiSig(multisigAddress, new MultisigTransactionPayload(entryFunctionPayload)), ); diff --git a/src/transactions/types.ts b/src/transactions/types.ts index 4924a34ef..e45a9f3e8 100644 --- a/src/transactions/types.ts +++ b/src/transactions/types.ts @@ -30,7 +30,7 @@ export type SimpleEntryFunctionArgumentTypes = | null // To support optional empty | undefined // To support optional empty | Uint8Array - | Array; + | Array; /** * Entry function arguments to be used when building a raw transaction using BCS serialized arguments @@ -115,7 +115,7 @@ export type InputEntryFunctionDataWithRemoteABI = InputEntryFunctionData & { apt * The data needed to generate a Multi Sig payload */ export type InputMultiSigData = { - multisigAddress: AccountAddress; + multisigAddress: AccountAddressInput; } & InputEntryFunctionData; /**