diff --git a/src/types/app-client.ts b/src/types/app-client.ts index 4fde28c8..1e4bdae6 100644 --- a/src/types/app-client.ts +++ b/src/types/app-client.ts @@ -61,6 +61,7 @@ import { AppSpec, arc32ToArc56 } from './app-spec' import { AppCallMethodCall, AppCallParams, + AppCreateMethodCall, AppDeleteMethodCall, AppDeleteParams, AppMethodCall, @@ -260,9 +261,9 @@ export interface FundAppAccountParams { /** Source maps for an Algorand app */ export interface AppSourceMaps { /** The source map of the approval program */ - approvalSourceMap: SourceMapExport + approvalSourceMap: algosdk.ProgramSourceMap /** The source map of the clear program */ - clearSourceMap: SourceMapExport + clearSourceMap: algosdk.ProgramSourceMap } export interface SourceMapExport { @@ -353,7 +354,14 @@ export type CallOnComplete = { /** AppClient common parameters for a bare app call */ export type AppClientBareCallParams = Expand< - Omit<CommonAppCallParams, 'appId' | 'sender' | 'onComplete'> & { + Omit<CommonAppCallParams, 'appId' | 'sender'> & { + /** The address of the account sending the transaction, if undefined then the app client's defaultSender is used. */ + sender?: Address | string + } +> + +export type AppClientBareCreateParams = Expand< + Omit<CommonAppCallParams, 'appId' | 'sender'> & { /** The address of the account sending the transaction, if undefined then the app client's defaultSender is used. */ sender?: Address | string } @@ -1193,6 +1201,15 @@ export class AppClient { OnApplicationComplete.UpdateApplicationOC, ) as AppUpdateParams }, + create: async (params?: AppClientBareCallParams & AppClientCompilationParams) => { + return this.getBareParams( + { + ...params, + ...(await this.compile(params)), + }, + params?.onComplete, + ) as AppUpdateParams + }, /** Return params for an opt-in call */ optIn: (params?: AppClientBareCallParams) => { return this.getBareParams(params, OnApplicationComplete.OptInOC) as AppCallParams @@ -1222,6 +1239,9 @@ export class AppClient { update: async (params?: AppClientBareCallParams & AppClientCompilationParams) => { return this._algorand.createTransaction.appUpdate(await this.params.bare.update(params)) }, + create: async (params?: AppClientBareCallParams & AppClientCompilationParams) => { + return this._algorand.createTransaction.appCreate(await this.params.bare.update(params)) + }, /** Returns a transaction for an opt-in call */ optIn: (params?: AppClientBareCallParams) => { return this._algorand.createTransaction.appCall(this.params.bare.optIn(params)) @@ -1255,6 +1275,16 @@ export class AppClient { ...(compiled as Partial<AppCompilationResult>), } }, + create: async (params?: AppClientBareCallParams & AppClientCompilationParams & SendParams) => { + const compiled = await this.compile(params) + const results = { + ...(await this._algorand.send.appCreate(await this.params.bare.create(params))), + ...(compiled as Partial<AppCompilationResult>), + } + + this._appId = results.appId + return results + }, /** Signs and sends an opt-in call */ optIn: (params?: AppClientBareCallParams & SendParams) => { return this._algorand.send.appCall(this.params.bare.optIn(params)) @@ -1307,6 +1337,19 @@ export class AppClient { OnApplicationComplete.UpdateApplicationOC, )) satisfies AppUpdateMethodCall }, + create: async (params: AppClientMethodCallParams & AppClientCompilationParams) => { + if (params.onComplete === OnApplicationComplete.ClearStateOC) { + throw new Error(`Cannot create with an OnComplete value of ${params.onComplete}`) + } + + return (await this.getABIParams( + { + ...params, + ...(await this.compile(params)), + }, + params.onComplete, + )) satisfies AppCreateMethodCall + }, /** * Return params for an opt-in ABI call * @param params The parameters for the opt-in ABI method call @@ -1364,6 +1407,24 @@ export class AppClient { ...(compiled as Partial<AppCompilationResult>), } }, + /** + * Sign and send transactions for an update ABI call, including deploy-time TEAL template replacements and compilation if provided + * @param params The parameters for the update ABI method call + * @returns The result of sending the update ABI method call + */ + create: async (params: AppClientMethodCallParams & AppClientCompilationParams & SendParams) => { + const compiled = await this.compile(params) + const results = { + ...(await this.processMethodCallReturn( + this._algorand.send.appCreateMethodCall(await this.params.create({ ...params })), + getArc56Method(params.method, this._appSpec), + )), + ...(compiled as Partial<AppCompilationResult>), + } + + this._appId = results.appId + return results + }, /** * Sign and send transactions for an opt-in ABI call * @param params The parameters for the opt-in ABI method call @@ -1477,6 +1538,9 @@ export class AppClient { update: async (params: AppClientMethodCallParams & AppClientCompilationParams) => { return this._algorand.createTransaction.appUpdateMethodCall(await this.params.update(params)) }, + create: async (params: AppClientMethodCallParams & AppClientCompilationParams) => { + return this._algorand.createTransaction.appCreateMethodCall(await this.params.update(params)) + }, /** * Return transactions for an opt-in ABI call * @param params The parameters for the opt-in ABI method call @@ -1534,7 +1598,7 @@ export class AppClient { private getBareParams< TParams extends { sender?: Address | string; signer?: TransactionSigner | TransactionSignerAccount } | undefined, TOnComplete extends OnApplicationComplete, - >(params: TParams, onComplete: TOnComplete) { + >(params: TParams, onComplete?: TOnComplete) { return { ...params, appId: this._appId, @@ -1552,7 +1616,7 @@ export class AppClient { args?: AppClientMethodCallParams['args'] }, TOnComplete extends OnApplicationComplete, - >(params: TParams, onComplete: TOnComplete) { + >(params: TParams, onComplete?: TOnComplete) { const sender = this.getSender(params.sender) const method = getArc56Method(params.method, this._appSpec) const args = await this.getABIArgsWithDefaultValues(params.method, params.args, sender) diff --git a/src/types/app-deployer.ts b/src/types/app-deployer.ts index 11db70a2..c2881437 100644 --- a/src/types/app-deployer.ts +++ b/src/types/app-deployer.ts @@ -25,6 +25,7 @@ import { } from './composer' import { Expand } from './expand' import { ConfirmedTransactionResult, SendParams } from './transaction' +import { AppClient } from './app-client' /** Params to specify an update transaction for an app deployment */ export type DeployAppUpdateParams = Expand<Omit<AppUpdateParams, 'appId' | 'approvalProgram' | 'clearStateProgram'>> @@ -252,18 +253,18 @@ export class AppDeployer { ) const result = await ('method' in updateParams ? this._transactionSender.appUpdateMethodCall({ + ...updateParams, + ...sendParams, appId: existingApp.appId, approvalProgram, clearStateProgram, - ...updateParams, - ...sendParams, }) : this._transactionSender.appUpdate({ + ...updateParams, + ...sendParams, appId: existingApp.appId, approvalProgram, clearStateProgram, - ...updateParams, - ...sendParams, })) const appMetadata: AppMetadata = { appId: existingApp.appId, @@ -300,9 +301,9 @@ export class AppDeployer { } const createIndex = await composer.count() if ('method' in deleteParams) { - composer.addAppDeleteMethodCall({ appId: existingApp.appId, ...deleteParams }) + composer.addAppDeleteMethodCall({ ...deleteParams, appId: existingApp.appId }) } else { - composer.addAppDelete({ appId: existingApp.appId, ...deleteParams }) + composer.addAppDelete({ ...deleteParams, appId: existingApp.appId }) } const result = await composer.send({ ...sendParams }) const confirmation = result.confirmations.at(createIndex - 1)! diff --git a/src/types/app-factory.ts b/src/types/app-factory.ts index 445a5b0d..a6dff028 100644 --- a/src/types/app-factory.ts +++ b/src/types/app-factory.ts @@ -1,46 +1,20 @@ import algosdk, { Address } from 'algosdk' -import { TransactionSignerAccount } from './account' import { type AlgorandClient } from './algorand-client' -import { - AppCompilationResult, - AppReturn, - DELETABLE_TEMPLATE_NAME, - SendAppTransactionResult, - TealTemplateParams, - UPDATABLE_TEMPLATE_NAME, -} from './app' -import { - ABIStruct, - Arc56Contract, - Arc56Method, - getABIDecodedValue, - getABITupleFromABIStruct, - getArc56Method, - getArc56ReturnValue, -} from './app-arc56' +import { AppCompilationResult, DELETABLE_TEMPLATE_NAME, TealTemplateParams, UPDATABLE_TEMPLATE_NAME } from './app' +import { Arc56Contract, getArc56Method, getArc56ReturnValue } from './app-arc56' import { AppClient, AppClientBareCallParams, AppClientCompilationParams, AppClientMethodCallParams, - AppClientParams, AppSourceMaps, + CloneAppClientParams, ResolveAppClientByCreatorAndName, } from './app-client' -import { - AppDeployParams, - DeployAppDeleteMethodCall, - DeployAppDeleteParams, - DeployAppUpdateMethodCall, - DeployAppUpdateParams, -} from './app-deployer' +import { AppDeployParams } from './app-deployer' import { AppSpec } from './app-spec' -import { AppCreateMethodCall, AppCreateParams, AppMethodCall, AppMethodCallTransactionArgument, CommonAppCallParams } from './composer' import { Expand } from './expand' -import { SendParams } from './transaction' -import SourceMap = algosdk.ProgramSourceMap import OnApplicationComplete = algosdk.OnApplicationComplete -import ABIValue = algosdk.ABIValue import TransactionSigner = algosdk.TransactionSigner /** Parameters to create an app client */ @@ -122,17 +96,6 @@ export type CreateSchema = { extraProgramPages?: number } -/** Params to specify a bare (raw) create call for an app */ -export type AppFactoryCreateParams = Expand<AppClientBareCallParams & AppClientCompilationParams & CreateOnComplete & CreateSchema> - -/** Params to specify a create method call for an app */ -export type AppFactoryCreateMethodCallParams = Expand< - AppClientMethodCallParams & AppClientCompilationParams & CreateOnComplete & CreateSchema -> - -/** Params to get an app client by ID from an app factory. */ -export type AppFactoryAppClientParams = Expand<Omit<AppClientParams, 'algorand' | 'appSpec'>> - /** Params to get an app client by creator address and name from an app factory. */ export type AppFactoryResolveAppClientByCreatorAndNameParams = Expand<Omit<ResolveAppClientByCreatorAndName, 'algorand' | 'appSpec'>> @@ -178,10 +141,7 @@ export class AppFactory { private _updatable?: boolean private _deletable?: boolean - private _approvalSourceMap: SourceMap | undefined - private _clearSourceMap: SourceMap | undefined - - private _paramsMethods: ReturnType<AppFactory['getParamsMethods']> + private _appClient: AppClient /** * Create a new app factory. @@ -204,7 +164,13 @@ export class AppFactory { this._deployTimeParams = params.deployTimeParams this._updatable = params.updatable this._deletable = params.deletable - this._paramsMethods = this.getParamsMethods() + this._appClient = new AppClient({ + appId: 0n, + appSpec: this._appSpec, + algorand: this._algorand, + defaultSender: this._defaultSender, + defaultSigner: this._defaultSigner, + }) } /** The name of the app (from the ARC-32 / ARC-56 app spec or override). */ @@ -238,7 +204,16 @@ export class AppFactory { * ``` */ get params() { - return this._paramsMethods + return { + create: this._appClient.params.create, + deployUpdate: this._appClient.params.update, + deployDelete: this._appClient.params.delete, + bare: { + create: this._appClient.params.bare.create, + deployUpdate: this._appClient.params.bare.update, + deployDelete: this._appClient.params.bare.delete, + }, + } } /** Create transactions for the current app */ @@ -252,7 +227,7 @@ export class AppFactory { * @param params The parameters to create the create call transaction * @returns The create call transaction */ - create: async (params?: AppFactoryCreateParams) => { + create: async (params?: Parameters<typeof AppClient.prototype.params.bare.create>[0]) => { return this._algorand.createTransaction.appCreate(await this.params.bare.create(params)) }, }, @@ -264,11 +239,23 @@ export class AppFactory { * @param params The parameters to create the create call transaction * @returns The create call transaction */ - create: async (params: AppFactoryCreateMethodCallParams) => { + create: async (params: Parameters<typeof AppClient.prototype.params.create>[0]) => { return this._algorand.createTransaction.appCreateMethodCall(await this.params.create(params)) }, } + private defaultCreateParams() { + return { + deployTimeParams: this._deployTimeParams, + schema: { + globalByteSlices: this._appSpec.state.schema.global.bytes, + globalInts: this._appSpec.state.schema.global.ints, + localByteSlices: this._appSpec.state.schema.local.bytes, + localInts: this._appSpec.state.schema.local.ints, + }, + } + } + /** Send transactions to the current app */ readonly send = { /** Send bare (raw) transactions for the current app */ @@ -281,23 +268,11 @@ export class AppFactory { * @param params The parameters to create the app * @returns The app client and the result of the creation transaction */ - create: async (params?: AppFactoryCreateParams & SendParams) => { - const updatable = params?.updatable ?? this._updatable - const deletable = params?.deletable ?? this._deletable - const deployTimeParams = params?.deployTimeParams ?? this._deployTimeParams - const compiled = await this.compile({ deployTimeParams, updatable, deletable }) - const result = await this.handleCallErrors(async () => ({ - ...(await this._algorand.send.appCreate(await this.params.bare.create({ ...params, updatable, deletable, deployTimeParams }))), - return: undefined, - })) + create: async (params?: Parameters<typeof AppClient.prototype.send.bare.create>[0]) => { + const appClient = this._appClient.clone({}) return { - appClient: this.getAppClientById({ - appId: result.appId, - }), - result: { - ...result, - ...(compiled as Partial<AppCompilationResult>), - }, + result: await appClient.send.bare.create({ ...this.defaultCreateParams(), ...params }), + appClient, } }, }, @@ -310,25 +285,11 @@ export class AppFactory { * @param params The parameters to create the app * @returns The app client and the result of the creation transaction */ - create: async (params: AppFactoryCreateMethodCallParams & SendParams) => { - const updatable = params?.updatable ?? this._updatable - const deletable = params?.deletable ?? this._deletable - const deployTimeParams = params?.deployTimeParams ?? this._deployTimeParams - const compiled = await this.compile({ deployTimeParams, updatable, deletable }) - const result = await this.handleCallErrors(async () => - this.parseMethodCallReturn( - this._algorand.send.appCreateMethodCall(await this.params.create({ ...params, updatable, deletable, deployTimeParams })), - getArc56Method(params.method, this._appSpec), - ), - ) + create: async (params: Parameters<typeof AppClient.prototype.send.create>[0]) => { + const appClient = this._appClient.clone({}) return { - appClient: this.getAppClientById({ - appId: result.appId, - }), - result: { - ...result, - ...(compiled as Partial<AppCompilationResult>), - }, + result: await appClient.send.create({ ...this.defaultCreateParams(), ...params }), + appClient, } }, } @@ -372,26 +333,21 @@ export class AppFactory { public async deploy(params: AppFactoryDeployParams) { const updatable = params.updatable ?? this._updatable ?? this.getDeployTimeControl('updatable') const deletable = params.deletable ?? this._deletable ?? this.getDeployTimeControl('deletable') - const deployTimeParams = params.deployTimeParams ?? this._deployTimeParams + const deployTimeParams = { ...(params.deployTimeParams ?? this._deployTimeParams) } - // Compile using a appID 0 AppClient so we can register the error handler and use the programs - // to identify the app within the error handler (because we can't use app ID 0) - const tempAppClient = this.getAppClientById({ appId: 0n }) - const compiled = await tempAppClient.compile({ deployTimeParams, updatable, deletable }) + const compiled = await this._appClient.compile({ deployTimeParams, updatable, deletable }) const deployResult = await this._algorand.appDeployer.deploy({ ...params, createParams: await (params.createParams && 'method' in params.createParams - ? this.params.create({ ...params.createParams, updatable, deletable, deployTimeParams }) - : this.params.bare.create({ ...params.createParams, updatable, deletable, deployTimeParams })), - updateParams: - params.updateParams && 'method' in params.updateParams - ? this.params.deployUpdate(params.updateParams) - : this.params.bare.deployUpdate(params.updateParams), - deleteParams: - params.deleteParams && 'method' in params.deleteParams - ? this.params.deployDelete(params.deleteParams) - : this.params.bare.deployDelete(params.deleteParams), + ? this.params.create({ ...this.defaultCreateParams(), ...params.createParams, updatable, deletable, deployTimeParams }) + : this.params.bare.create({ ...this.defaultCreateParams(), ...params.createParams, updatable, deletable, deployTimeParams })), + updateParams: await (params.updateParams && 'method' in params.updateParams + ? this.params.deployUpdate({ ...params.updateParams, updatable, deletable, deployTimeParams }) + : this.params.bare.deployUpdate({ ...params.updateParams, updatable, deletable, deployTimeParams })), + deleteParams: await (params.deleteParams && 'method' in params.deleteParams + ? this.params.deployDelete(params.deleteParams) + : this.params.bare.deployDelete(params.deleteParams)), metadata: { name: params.appName ?? this._appName, version: this._version, @@ -399,7 +355,7 @@ export class AppFactory { deletable, }, }) - const appClient = this.getAppClientById({ + const appClient = this._appClient.clone({ appId: deployResult.appId, appName: params.appName, }) @@ -441,17 +397,8 @@ export class AppFactory { * const appClient = factory.getAppClientById({ appId: 12345n }) * ``` */ - public getAppClientById(params: AppFactoryAppClientParams) { - return new AppClient({ - ...params, - algorand: this._algorand, - appSpec: this._appSpec, - appName: params.appName ?? this._appName, - defaultSender: params.defaultSender ?? this._defaultSender, - defaultSigner: params.defaultSigner ?? this._defaultSigner, - approvalSourceMap: params.approvalSourceMap ?? this._approvalSourceMap, - clearSourceMap: params.clearSourceMap ?? this._clearSourceMap, - }) + public getAppClientById(params: CloneAppClientParams & Required<Pick<CloneAppClientParams, 'appId'>>) { + return this._appClient.clone(params) } /** @@ -474,8 +421,8 @@ export class AppFactory { appSpec: this._appSpec, appName: params.appName ?? this._appName, defaultSender: params.defaultSender ?? this._defaultSender, - approvalSourceMap: params.approvalSourceMap ?? this._approvalSourceMap, - clearSourceMap: params.clearSourceMap ?? this._clearSourceMap, + approvalSourceMap: params.approvalSourceMap ?? this._appClient.exportSourceMaps().approvalSourceMap, + clearSourceMap: params.clearSourceMap ?? this._appClient.exportSourceMaps().clearSourceMap, }) } @@ -486,12 +433,8 @@ export class AppFactory { * @param isClearStateProgram Whether or not the code was running the clear state program (defaults to approval program) * @returns The new error, or if there was no logic error or source map then the wrapped error with source details */ - exposeLogicError(e: Error, isClearStateProgram?: boolean): Error { - return AppClient.exposeLogicError(e, this._appSpec, { - isClearStateProgram, - approvalSourceMap: this._approvalSourceMap, - clearSourceMap: this._clearSourceMap, - }) + async exposeLogicError(e: Error, isClearStateProgram?: boolean): Promise<Error> { + return await this._appClient.exposeLogicError(e, isClearStateProgram) } /** @@ -499,16 +442,7 @@ export class AppFactory { * @returns The source maps */ exportSourceMaps(): AppSourceMaps { - if (!this._approvalSourceMap || !this._clearSourceMap) { - throw new Error( - "Unable to export source maps; they haven't been loaded into this client - you need to call create, update, or deploy first", - ) - } - - return { - approvalSourceMap: this._approvalSourceMap, - clearSourceMap: this._clearSourceMap, - } + return this._appClient.exportSourceMaps() } /** @@ -516,8 +450,7 @@ export class AppFactory { * @param sourceMaps The source maps to import */ importSourceMaps(sourceMaps: AppSourceMaps) { - this._approvalSourceMap = new SourceMap(sourceMaps.approvalSourceMap) - this._clearSourceMap = new SourceMap(sourceMaps.clearSourceMap) + this._appClient.importSourceMaps(sourceMaps) } private getDeployTimeControl(control: 'updatable' | 'deletable'): boolean | undefined { @@ -534,74 +467,6 @@ export class AppFactory { ) } - private getParamsMethods() { - return { - /** Return params for a create ABI call, including deploy-time TEAL template replacements and compilation if provided */ - create: async (params: AppFactoryCreateMethodCallParams) => { - const compiled = await this.compile({ ...params, deployTimeParams: params.deployTimeParams ?? this._deployTimeParams }) - return this.getABIParams( - { - ...params, - deployTimeParams: params.deployTimeParams ?? this._deployTimeParams, - schema: params.schema ?? { - globalByteSlices: this._appSpec.state.schema.global.bytes, - globalInts: this._appSpec.state.schema.global.ints, - localByteSlices: this._appSpec.state.schema.local.bytes, - localInts: this._appSpec.state.schema.local.ints, - }, - approvalProgram: compiled.approvalProgram, - clearStateProgram: compiled.clearStateProgram, - }, - params.onComplete ?? OnApplicationComplete.NoOpOC, - ) satisfies AppCreateMethodCall - }, - /** Return params for a deployment update ABI call */ - deployUpdate: (params: AppClientMethodCallParams) => { - return this.getABIParams(params, OnApplicationComplete.UpdateApplicationOC) satisfies DeployAppUpdateMethodCall - }, - /** Return params for a deployment delete ABI call */ - deployDelete: (params: AppClientMethodCallParams) => { - return this.getABIParams(params, OnApplicationComplete.DeleteApplicationOC) satisfies DeployAppDeleteMethodCall - }, - bare: { - /** Return params for a create bare call, including deploy-time TEAL template replacements and compilation if provided */ - create: async (params?: AppFactoryCreateParams) => { - return this.getBareParams( - { - ...params, - deployTimeParams: params?.deployTimeParams ?? this._deployTimeParams, - schema: params?.schema ?? { - globalByteSlices: this._appSpec.state.schema.global.bytes, - globalInts: this._appSpec.state.schema.global.ints, - localByteSlices: this._appSpec.state.schema.local.bytes, - localInts: this._appSpec.state.schema.local.ints, - }, - ...(await this.compile({ ...params, deployTimeParams: params?.deployTimeParams ?? this._deployTimeParams })), - }, - params?.onComplete ?? OnApplicationComplete.NoOpOC, - ) satisfies AppCreateParams - }, - /** Return params for a deployment update bare call */ - deployUpdate: (params?: AppClientBareCallParams) => { - return this.getBareParams(params, OnApplicationComplete.UpdateApplicationOC) satisfies DeployAppUpdateParams - }, - /** Return params for a deployment delete bare call */ - deployDelete: (params?: AppClientBareCallParams) => { - return this.getBareParams(params, OnApplicationComplete.DeleteApplicationOC) satisfies DeployAppDeleteParams - }, - }, - } - } - - /** Make the given call and catch any errors, augmenting with debugging information before re-throwing. */ - private async handleCallErrors<TResult>(call: () => Promise<TResult>) { - try { - return await call() - } catch (e) { - throw this.exposeLogicError(e as Error) - } - } - /** * Compiles the approval and clear state programs (if TEAL templates provided), * performing any provided deploy-time parameter replacement and stores @@ -618,109 +483,6 @@ export class AppFactory { * ``` */ public async compile(compilation?: AppClientCompilationParams) { - const result = await AppClient.compile(this._appSpec, this._algorand.app, compilation) - - if (result.compiledApproval) { - this._approvalSourceMap = result.compiledApproval.sourceMap - } - if (result.compiledClear) { - this._clearSourceMap = result.compiledClear.sourceMap - } - - return result - } - - private getBareParams< - TParams extends { sender?: Address | string; signer?: TransactionSigner | TransactionSignerAccount } | undefined, - TOnComplete extends OnApplicationComplete, - >(params: TParams, onComplete: TOnComplete) { - return { - ...params, - sender: this.getSender(params?.sender), - signer: this.getSigner(params?.sender, params?.signer), - onComplete, - } - } - - private getABIParams< - TParams extends { - method: string - sender?: Address | string - signer?: TransactionSigner | TransactionSignerAccount - args?: AppClientMethodCallParams['args'] - }, - TOnComplete extends OnApplicationComplete, - >(params: TParams, onComplete: TOnComplete) { - return { - ...params, - sender: this.getSender(params.sender), - signer: this.getSigner(params.sender, params.signer), - method: getArc56Method(params.method, this._appSpec), - args: this.getCreateABIArgsWithDefaultValues(params.method, params.args), - onComplete, - } - } - - private getCreateABIArgsWithDefaultValues( - methodNameOrSignature: string, - args: AppClientMethodCallParams['args'] | undefined, - ): AppMethodCall<CommonAppCallParams>['args'] { - const m = getArc56Method(methodNameOrSignature, this._appSpec) - return args?.map((a, i) => { - const arg = m.args[i] - if (a !== undefined) { - // If a struct then convert to tuple for the underlying call - return arg.struct && typeof a === 'object' && !Array.isArray(a) - ? getABITupleFromABIStruct(a as ABIStruct, this._appSpec.structs[arg.struct], this._appSpec.structs) - : (a as ABIValue | AppMethodCallTransactionArgument) - } - const defaultValue = arg.defaultValue - if (defaultValue) { - switch (defaultValue.source) { - case 'literal': - return getABIDecodedValue(Buffer.from(defaultValue.data, 'base64'), m.method.args[i].type, this._appSpec.structs) as ABIValue - default: - throw new Error(`Can't provide default value for ${defaultValue.source} for a contract creation call`) - } - } - throw new Error(`No value provided for required argument ${arg.name ?? `arg${i + 1}`} in call to method ${m.name}`) - }) - } - - /** Returns the sender for a call, using the `defaultSender` - * if none provided and throws an error if neither provided */ - private getSender(sender: string | Address | undefined): Address { - if (!sender && !this._defaultSender) { - throw new Error(`No sender provided and no default sender present in app factory for call to app ${this._appName}`) - } - return typeof sender === 'string' ? Address.fromString(sender) : (sender ?? this._defaultSender!) - } - - /** Returns the signer for a call, using the provided signer or the `defaultSigner` - * if no signer was provided and the sender resolves to the default sender, the call will use default signer - * or `undefined` otherwise (so the signer is resolved from `AlgorandClient`) */ - private getSigner( - sender: Address | string | undefined, - signer: TransactionSigner | TransactionSignerAccount | undefined, - ): TransactionSigner | TransactionSignerAccount | undefined { - return signer ?? (!sender || sender === this._defaultSender ? this._defaultSigner : undefined) - } - - /** - * Checks for decode errors on the SendAppTransactionResult and maps the return value to the specified type - * on the ARC-56 method. - * - * If the return type is a struct then the struct will be returned. - * - * @param result The SendAppTransactionResult to be mapped - * @param method The method that was called - * @returns The smart contract response with an updated return value - */ - async parseMethodCallReturn< - TReturn extends Uint8Array | ABIValue | ABIStruct | undefined, - TResult extends SendAppTransactionResult = SendAppTransactionResult, - >(result: Promise<TResult> | TResult, method: Arc56Method): Promise<Omit<TResult, 'return'> & AppReturn<TReturn>> { - const resultValue = await result - return { ...resultValue, return: getArc56ReturnValue(resultValue.return, method, this._appSpec.structs) } + return this._appClient.compile(compilation) } }