Skip to content

Conversation

@aorumbayev
Copy link
Collaborator

@aorumbayev aorumbayev commented Sep 2, 2025

App factory implementation following the AppClient

@aorumbayev aorumbayev changed the title feat: app factory initial version feat: app factory Sep 2, 2025
@aorumbayev aorumbayev marked this pull request as ready for review September 2, 2025 22:35
@aorumbayev aorumbayev requested a review from a team as a code owner September 2, 2025 22:35
@aorumbayev aorumbayev requested review from a team, lempira and neilcampbell and removed request for a team September 2, 2025 22:35
@aorumbayev aorumbayev force-pushed the feat/application-client branch from 6a166c7 to 6d27d07 Compare September 3, 2025 21:57
@aorumbayev aorumbayev requested a review from Copilot September 3, 2025 22:05
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces an app factory pattern for Algorand application deployment in the Rust crate, following the established patterns from Python and TypeScript implementations. The factory provides a high-level interface for creating, updating, and deploying applications using ARC-56 specifications.

Key changes:

  • New AppFactory struct with fluent API for application lifecycle management
  • Integration with existing AppDeployer for idempotent deployment operations
  • Enhanced AlgorandClient with persistent app deployer functionality

Reviewed Changes

Copilot reviewed 22 out of 23 changed files in this pull request and generated no comments.

Show a summary per file
File Description
crates/algokit_utils/src/applications/app_factory/ Core factory implementation with modular design (types, compilation, transaction builders, etc.)
crates/algokit_utils/src/applications/app_client/types.rs Changed AlgorandClient parameter to Arc for shared ownership
crates/algokit_utils/src/clients/algorand_client.rs Added persistent AppDeployer instance and app_deployer() accessor method
crates/algokit_utils/src/applications/app_deployer.rs Enhanced with extra program pages calculation and localnet retry logic
crates/algokit_utils/tests/applications/app_factory.rs Comprehensive test suite covering factory creation, deployment, and ABI scenarios

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@aorumbayev aorumbayev force-pushed the feat/application-client branch from 1be959c to fb7ee7f Compare September 4, 2025 16:20
@aorumbayev aorumbayev mentioned this pull request Sep 4, 2025
aorumbayev and others added 9 commits September 12, 2025 00:15
* wip - PR feedback

* wip - convert errors to snafu

* wip

* chore: replace utils CommonTransactionParams with macro

* chore(python/algokit_transact): bump version to 1.0.0-alpha.60 [skip ci]

* wip - converting string to error types

* chore: simplify add_app_method_call_internal

* chore: additional tweaks whilst implementing TS composer

* chore(python/algokit_transact): bump version to 1.0.0-alpha.61 [skip ci]

* chore: adjust transaction creator types, as they were previously a bit strange

* wip - fixing compile issues

* fix types for transaction_builder

* chore: tweaks to both transaction creator and client manager

* wip - map storage

* wip - app state

* wip - some clean up

* wip - fix compile issues

* make app state accessor better

* wip - box

* box done

* fix params_builder

* chore(python/algokit_transact): bump version to 1.0.0-alpha.62 [skip ci]

* fix up the app client

* wip - fix simulate

* fix simulate + send params

* clean up compilation.rs

* remove extract_abi_return_from_result

* wip - fixing tests

* wip - resolve compile error app_client tests

* wip - fixing tests

* chore: add default signer support to AppClientParams

* wip - structs

* fix field type + encode/decode logic

* test

* convert storage key to abi storage key

* convert storage map to abi storage map

* convert box to use abi storage key

* fix build

* wip- struct in default value

* convert default value

* fix up - it builds now

* wip - fixing tests

---------

Co-authored-by: engineering-ci[bot] <179917785+engineering-ci[bot]@users.noreply.github.com>
Co-authored-by: Neil Campbell <[email protected]>
Co-authored-by: Altynbek Orumbayev <[email protected]>
@aorumbayev aorumbayev force-pushed the feat/application-client branch from afe47d6 to 092606d Compare September 11, 2025 22:32
@aorumbayev aorumbayev marked this pull request as ready for review September 19, 2025 12:53

#[derive(Clone, Debug)]
pub struct AppFactoryMethodCallResult<T> {
inner: T,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For other part of the project, we are moving away from using nested structs, especially for public facing structs. For example, in this PR I removed the common_params from the send result. Do you think that we should do the same here too?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AppFactoryMethodCallResult acts as a thin wrapper on top of SendAppResult type plus adds the parsed arc56 returns. The derefs below the lines you mentioned ensure that everything from SendAppResult is accessible from the root of the AppFactoryMethodCallResult - the user does not have to do extra hops to .inner in this case. So not sure we want to tweak it since all send result fields are immediately accessible

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL about the power of deref. However, This section from the Rust docs makes me wonder if this is suitable for public facing types.

When to implement Deref or DerefMut
The same advice applies to both deref traits. In general, deref traits should be implemented if:

a value of the type transparently behaves like a value of the target type;
the implementation of the deref function is cheap; and
users of the type will not be surprised by any deref coercion behavior.

In general, deref traits should not be implemented if:

the deref implementations could fail unexpectedly; or
the type has methods that are likely to collide with methods on the target type; or
committing to deref coercion as part of the public API is not desirable.

Especially this bit or committing to deref coercion as part of the public API is not desirable.

I am fairly new to Rust but deref seems to create a hidden API surface. For example, I didn't know about it until you pointed out to me that I could access everything inside inner because the AppFactoryMethodCallResult implement the deref trait.
What do you think?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

considering that common params are removed in app client result types in https://github.com/algorandfoundation/algokit-core/pull/260/files - i considered using a macro for the app factory return types but ultimately the only change needed is extra arc56_return abivalue field - i ended up redeclaring fields instead of using deref or a macro

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, this is the most pragmatic approach

fn signer_mut(&mut self) -> &mut Option<Arc<dyn TransactionSigner>>;
}

fn set_default_signer_if_missing(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: maybe a better name for this method is set_signer_if_missing

Copy link
Collaborator Author

@aorumbayev aorumbayev Sep 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renamed to set_method_signer_if_missing which i think is slightly more explicit lmk if you are ok with this


#[derive(Clone, Debug)]
pub struct AppFactoryMethodCallResult<T> {
inner: T,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL about the power of deref. However, This section from the Rust docs makes me wonder if this is suitable for public facing types.

When to implement Deref or DerefMut
The same advice applies to both deref traits. In general, deref traits should be implemented if:

a value of the type transparently behaves like a value of the target type;
the implementation of the deref function is cheap; and
users of the type will not be surprised by any deref coercion behavior.

In general, deref traits should not be implemented if:

the deref implementations could fail unexpectedly; or
the type has methods that are likely to collide with methods on the target type; or
committing to deref coercion as part of the public API is not desirable.

Especially this bit or committing to deref coercion as part of the public API is not desirable.

I am fairly new to Rust but deref seems to create a hidden API surface. For example, I didn't know about it until you pointed out to me that I could access everything inside inner because the AppFactoryMethodCallResult implement the deref trait.
What do you think?

@aorumbayev aorumbayev merged commit c10195d into main Sep 23, 2025
14 checks passed
@aorumbayev aorumbayev deleted the feat/app-factory branch September 23, 2025 10:32
@engineering-ci
Copy link
Contributor

🎉 This PR is included in version 1.0.0-alpha.68 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants