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)
   }
 }