This is page 34 of 74. Use http://codebase.md/goplausible/algorand-mcp?lines=false&page={x} to view the full context.
# Directory Structure
```
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── llms-install.md
├── llms.txt
├── package.json
├── packages
│ ├── client
│ │ ├── .env.example
│ │ ├── package.json
│ │ ├── README.md
│ │ ├── src
│ │ │ ├── env.ts
│ │ │ ├── index.ts
│ │ │ └── LocalWallet.ts
│ │ └── tsconfig.json
│ └── server
│ ├── .env.example
│ ├── API specs
│ │ ├── algod_api.json
│ │ ├── indexer_api.json
│ │ ├── mcp.json
│ │ ├── nfd_api.json
│ │ ├── ultrade_api.json
│ │ ├── vestige_api.json
│ │ └── vestige_free_api.json
│ ├── Dockerfile
│ ├── jest.config.js
│ ├── package.json
│ ├── README.md
│ ├── smithery.yaml
│ ├── src
│ │ ├── algorand-client.ts
│ │ ├── env.ts
│ │ ├── index.ts
│ │ ├── resources
│ │ │ ├── index.ts
│ │ │ ├── knowledge
│ │ │ │ ├── ARCs.txt
│ │ │ │ ├── developers-algokit-architecture-decisions.txt
│ │ │ │ ├── developers-algokit-cli.txt
│ │ │ │ ├── developers-algokit-utils-python.txt
│ │ │ │ ├── developers-algokit-utils-typescript.txt
│ │ │ │ ├── developers-clis.txt
│ │ │ │ ├── developers-details.txt
│ │ │ │ ├── developers-liquid-auth.txt
│ │ │ │ ├── developers-nodes.txt
│ │ │ │ ├── developers-puya.txt
│ │ │ │ ├── developers-python.txt
│ │ │ │ ├── developers-sdks-js.txt
│ │ │ │ ├── developers-sdks-python.txt
│ │ │ │ ├── developers-tealscript.txt
│ │ │ │ ├── developers.txt
│ │ │ │ ├── index.ts
│ │ │ │ ├── taxonomy
│ │ │ │ │ ├── algokit-cli:README.md
│ │ │ │ │ ├── algokit:cli:algokit.md
│ │ │ │ │ ├── algokit:cli:architecture-decisions:2022-11-14_sandbox-approach.md
│ │ │ │ │ ├── algokit:cli:architecture-decisions:2022-11-22_beaker-testing-strategy.md
│ │ │ │ │ ├── algokit:cli:architecture-decisions:2023-01-11_beaker_productionisation_review.md
│ │ │ │ │ ├── algokit:cli:architecture-decisions:2023-01-11_brew_install.md
│ │ │ │ │ ├── algokit:cli:architecture-decisions:2023-01-12_smart-contract-deployment.md
│ │ │ │ │ ├── algokit:cli:architecture-decisions:2023-06-06_frontend-templates.md
│ │ │ │ │ ├── algokit:cli:architecture-decisions:2023-07-19_advanced_generate_command.md
│ │ │ │ │ ├── algokit:cli:architecture-decisions:2024-01-13_native_binaries.md
│ │ │ │ │ ├── algokit:cli:architecture-decisions:2024-01-23_init-wizard-v2.md
│ │ │ │ │ ├── algokit:cli:architecture-decisions:2024-01-31_binary_distribution.md
│ │ │ │ │ ├── algokit:cli:architecture-decisions:2024-03-06_local_dev_ui_packaging.md
│ │ │ │ │ ├── algokit:cli:articles:output_stability.md
│ │ │ │ │ ├── algokit:cli:cli:index.md
│ │ │ │ │ ├── algokit:cli:features:compile.md
│ │ │ │ │ ├── algokit:cli:features:completions.md
│ │ │ │ │ ├── algokit:cli:features:config.md
│ │ │ │ │ ├── algokit:cli:features:dispenser.md
│ │ │ │ │ ├── algokit:cli:features:doctor.md
│ │ │ │ │ ├── algokit:cli:features:explore.md
│ │ │ │ │ ├── algokit:cli:features:generate.md
│ │ │ │ │ ├── algokit:cli:features:goal.md
│ │ │ │ │ ├── algokit:cli:features:init.md
│ │ │ │ │ ├── algokit:cli:features:localnet.md
│ │ │ │ │ ├── algokit:cli:features:project:bootstrap.md
│ │ │ │ │ ├── algokit:cli:features:project:deploy.md
│ │ │ │ │ ├── algokit:cli:features:project:link.md
│ │ │ │ │ ├── algokit:cli:features:project:list.md
│ │ │ │ │ ├── algokit:cli:features:project:run.md
│ │ │ │ │ ├── algokit:cli:features:project.md
│ │ │ │ │ ├── algokit:cli:features:tasks:analyze.md
│ │ │ │ │ ├── algokit:cli:features:tasks:ipfs.md
│ │ │ │ │ ├── algokit:cli:features:tasks:mint.md
│ │ │ │ │ ├── algokit:cli:features:tasks:nfd.md
│ │ │ │ │ ├── algokit:cli:features:tasks:opt.md
│ │ │ │ │ ├── algokit:cli:features:tasks:send.md
│ │ │ │ │ ├── algokit:cli:features:tasks:sign.md
│ │ │ │ │ ├── algokit:cli:features:tasks:transfer.md
│ │ │ │ │ ├── algokit:cli:features:tasks:vanity_address.md
│ │ │ │ │ ├── algokit:cli:features:tasks:wallet.md
│ │ │ │ │ ├── algokit:cli:features:tasks.md
│ │ │ │ │ ├── algokit:cli:tutorials:algokit-template.md
│ │ │ │ │ ├── algokit:cli:tutorials:intro.md
│ │ │ │ │ ├── algokit:cli:tutorials:smart-contracts.md
│ │ │ │ │ ├── algokit:docs:testnet_api.md
│ │ │ │ │ ├── algokit:lora:README.md
│ │ │ │ │ ├── algokit:README.md
│ │ │ │ │ ├── algokit:utils:python:markdown:apidocs:algokit_utils:algokit_utils.md
│ │ │ │ │ ├── algokit:utils:python:markdown:capabilities:account.md
│ │ │ │ │ ├── algokit:utils:python:markdown:capabilities:app-client.md
│ │ │ │ │ ├── algokit:utils:python:markdown:capabilities:app-deploy.md
│ │ │ │ │ ├── algokit:utils:python:markdown:capabilities:client.md
│ │ │ │ │ ├── algokit:utils:python:markdown:capabilities:debugger.md
│ │ │ │ │ ├── algokit:utils:python:markdown:capabilities:dispenser-client.md
│ │ │ │ │ ├── algokit:utils:python:markdown:capabilities:transfer.md
│ │ │ │ │ ├── algokit:utils:python:markdown:index.md
│ │ │ │ │ ├── algokit:utils:python:README.md
│ │ │ │ │ ├── algokit:utils:python:source:capabilities:account.md
│ │ │ │ │ ├── algokit:utils:python:source:capabilities:app-client.md
│ │ │ │ │ ├── algokit:utils:python:source:capabilities:app-deploy.md
│ │ │ │ │ ├── algokit:utils:python:source:capabilities:client.md
│ │ │ │ │ ├── algokit:utils:python:source:capabilities:debugger.md
│ │ │ │ │ ├── algokit:utils:python:source:capabilities:dispenser-client.md
│ │ │ │ │ ├── algokit:utils:python:source:capabilities:transfer.md
│ │ │ │ │ ├── algokit:utils:python:source:index.md
│ │ │ │ │ ├── algokit:utils:typescript:capabilities:account.md
│ │ │ │ │ ├── algokit:utils:typescript:capabilities:algorand-client.md
│ │ │ │ │ ├── algokit:utils:typescript:capabilities:amount.md
│ │ │ │ │ ├── algokit:utils:typescript:capabilities:app-client.md
│ │ │ │ │ ├── algokit:utils:typescript:capabilities:app-deploy.md
│ │ │ │ │ ├── algokit:utils:typescript:capabilities:app.md
│ │ │ │ │ ├── algokit:utils:typescript:capabilities:asset.md
│ │ │ │ │ ├── algokit:utils:typescript:capabilities:client.md
│ │ │ │ │ ├── algokit:utils:typescript:capabilities:debugging.md
│ │ │ │ │ ├── algokit:utils:typescript:capabilities:dispenser-client.md
│ │ │ │ │ ├── algokit:utils:typescript:capabilities:event-emitter.md
│ │ │ │ │ ├── algokit:utils:typescript:capabilities:indexer.md
│ │ │ │ │ ├── algokit:utils:typescript:capabilities:testing.md
│ │ │ │ │ ├── algokit:utils:typescript:capabilities:transaction-composer.md
│ │ │ │ │ ├── algokit:utils:typescript:capabilities:transaction.md
│ │ │ │ │ ├── algokit:utils:typescript:capabilities:transfer.md
│ │ │ │ │ ├── algokit:utils:typescript:capabilities:typed-app-clients.md
│ │ │ │ │ ├── algokit:utils:typescript:code:classes:testing.TestLogger.md
│ │ │ │ │ ├── algokit:utils:typescript:code:classes:testing.TransactionLogger.md
│ │ │ │ │ ├── algokit:utils:typescript:code:classes:types_account_manager.AccountManager.md
│ │ │ │ │ ├── algokit:utils:typescript:code:classes:types_account.MultisigAccount.md
│ │ │ │ │ ├── algokit:utils:typescript:code:classes:types_account.SigningAccount.md
│ │ │ │ │ ├── algokit:utils:typescript:code:classes:types_algo_http_client_with_retry.AlgoHttpClientWithRetry.md
│ │ │ │ │ ├── algokit:utils:typescript:code:classes:types_algorand_client_transaction_creator.AlgorandClientTransactionCreator.md
│ │ │ │ │ ├── algokit:utils:typescript:code:classes:types_algorand_client_transaction_sender.AlgorandClientTransactionSender.md
│ │ │ │ │ ├── algokit:utils:typescript:code:classes:types_algorand_client.AlgorandClient.md
│ │ │ │ │ ├── algokit:utils:typescript:code:classes:types_amount.AlgoAmount.md
│ │ │ │ │ ├── algokit:utils:typescript:code:classes:types_app_arc56.Arc56Method.md
│ │ │ │ │ ├── algokit:utils:typescript:code:classes:types_app_client.AppClient.md
│ │ │ │ │ ├── algokit:utils:typescript:code:classes:types_app_client.ApplicationClient.md
│ │ │ │ │ ├── algokit:utils:typescript:code:classes:types_app_deployer.AppDeployer.md
│ │ │ │ │ ├── algokit:utils:typescript:code:classes:types_app_factory.AppFactory.md
│ │ │ │ │ ├── algokit:utils:typescript:code:classes:types_app_manager.AppManager.md
│ │ │ │ │ ├── algokit:utils:typescript:code:classes:types_asset_manager.AssetManager.md
│ │ │ │ │ ├── algokit:utils:typescript:code:classes:types_async_event_emitter.AsyncEventEmitter.md
│ │ │ │ │ ├── algokit:utils:typescript:code:classes:types_client_manager.ClientManager.md
│ │ │ │ │ ├── algokit:utils:typescript:code:classes:types_composer.TransactionComposer.md
│ │ │ │ │ ├── algokit:utils:typescript:code:classes:types_config.UpdatableConfig.md
│ │ │ │ │ ├── algokit:utils:typescript:code:classes:types_dispenser_client.TestNetDispenserApiClient.md
│ │ │ │ │ ├── algokit:utils:typescript:code:classes:types_kmd_account_manager.KmdAccountManager.md
│ │ │ │ │ ├── algokit:utils:typescript:code:classes:types_logic_error.LogicError.md
│ │ │ │ │ ├── algokit:utils:typescript:code:enums:types_app.OnSchemaBreak.md
│ │ │ │ │ ├── algokit:utils:typescript:code:enums:types_app.OnUpdate.md
│ │ │ │ │ ├── algokit:utils:typescript:code:enums:types_indexer.AccountStatus.md
│ │ │ │ │ ├── algokit:utils:typescript:code:enums:types_indexer.ApplicationOnComplete.md
│ │ │ │ │ ├── algokit:utils:typescript:code:enums:types_indexer.SignatureType.md
│ │ │ │ │ ├── algokit:utils:typescript:code:enums:types_lifecycle_events.EventType.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_account_manager.EnsureFundedResult.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_account.AccountConfig.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_account.TransactionSignerAccount.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_algorand_client_interface.AlgorandClientInterface.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_arc56.Arc56Contract.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_arc56.Event.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_arc56.Method.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_arc56.ProgramSourceInfo.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_arc56.StorageKey.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_arc56.StorageMap.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_arc56.StructField.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_client.AppClientCallABIArgs.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_client.AppClientCallCoreParams.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_client.AppClientCompilationParams.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_client.AppClientCompilationResult.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_client.AppClientDeployCallInterfaceParams.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_client.AppClientDeployCoreParams.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_client.AppClientDeployParams.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_client.AppClientParams.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_client.AppSourceMaps.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_client.FundAppAccountParams.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_client.ResolveAppById.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_client.ResolveAppByIdBase.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_client.SourceMapExport.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_deployer.AppLookup.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_deployer.AppMetadata.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_factory.AppFactoryParams.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_manager.AppInformation.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_manager.BoxReference.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_manager.BoxValueRequestParams.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_manager.BoxValuesRequestParams.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_spec.AppSources.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_spec.AppSpec.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_spec.CallConfig.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_spec.DeclaredSchemaValueSpec.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_spec.Hint.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_spec.ReservedSchemaValueSpec.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_spec.Schema.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_spec.SchemaSpec.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_spec.StateSchemaSpec.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app_spec.Struct.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app.AppCallParams.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app.AppCallTransactionResultOfType.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app.AppCompilationResult.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app.AppDeploymentParams.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app.AppDeployMetadata.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app.AppLookup.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app.AppMetadata.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app.AppReference.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app.AppState.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app.AppStorageSchema.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app.BoxName.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app.BoxReference.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app.BoxValueRequestParams.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app.BoxValuesRequestParams.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app.CompiledTeal.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app.CoreAppCallArgs.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app.CreateAppParams.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app.RawAppCallArgs.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app.TealTemplateParams.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_app.UpdateAppParams.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_asset_manager.AssetInformation.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_asset_manager.BulkAssetOptInOutResult.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_asset.AssetBulkOptInOutParams.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_asset.AssetOptInParams.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_asset.AssetOptOutParams.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_asset.CreateAssetParams.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_client_manager.AlgoSdkClients.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_client_manager.TypedAppClient.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_client_manager.TypedAppFactory.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_composer.BuiltTransactions.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_config.Config.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_debugging.AVMTracesEventData.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_debugging.TealSourceDebugEventData.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_debugging.TealSourcesDebugEventData.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_dispenser_client.DispenserFundResponse.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_dispenser_client.DispenserLimitResponse.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_dispenser_client.TestNetDispenserApiClientParams.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_indexer.LookupAssetHoldingsOptions.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_logic_error.LogicErrorDetails.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_network_client.AlgoClientConfig.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_network_client.AlgoConfig.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_network_client.NetworkDetails.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_testing.AlgoKitLogCaptureFixture.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_testing.AlgorandFixture.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_testing.AlgorandFixtureConfig.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_testing.AlgorandTestAutomationContext.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_testing.GetTestAccountParams.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_testing.LogSnapshotConfig.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_transaction.AtomicTransactionComposerToSend.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_transaction.ConfirmedTransactionResult.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_transaction.ConfirmedTransactionResults.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_transaction.SendAtomicTransactionComposerResults.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_transaction.SendParams.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_transaction.SendTransactionParams.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_transaction.SendTransactionResult.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_transaction.SendTransactionResults.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_transaction.TransactionGroupToSend.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_transaction.TransactionToSign.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_transfer.AlgoRekeyParams.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_transfer.AlgoTransferParams.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_transfer.EnsureFundedParams.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_transfer.EnsureFundedReturnType.md
│ │ │ │ │ ├── algokit:utils:typescript:code:interfaces:types_transfer.TransferAssetParams.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:index.indexer.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:index.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:testing.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_account_manager_spec.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_account_manager.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_account.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_algo_http_client_with_retry.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_algorand_client_asset_spec.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_algorand_client_interface.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_algorand_client_spec.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_algorand_client_transaction_creator.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_algorand_client_transaction_sender.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_algorand_client_transfer_spec.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_algorand_client.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_amount_spec.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_amount.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_app_arc56.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_app_client_spec.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_app_client.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_app_deployer.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_app_factory_and_client_spec.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_app_factory.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_app_manager.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_app_spec.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_app.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_asset_manager.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_asset.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_async_event_emitter_spec.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_async_event_emitter.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_client_manager_spec.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_client_manager.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_composer.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_config.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_debugging.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_dispenser_client_spec.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_dispenser_client.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_expand.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_indexer.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_kmd_account_manager.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_lifecycle_events.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_logging.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_logic_error.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_network_client.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_testing.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_transaction.md
│ │ │ │ │ ├── algokit:utils:typescript:code:modules:types_transfer.md
│ │ │ │ │ ├── algokit:utils:typescript:code:README.md
│ │ │ │ │ ├── algokit:utils:typescript:README.md
│ │ │ │ │ ├── algokit:utils:typescript:v7-migration.md
│ │ │ │ │ ├── algokit:utils:typescript:v8-migration.md
│ │ │ │ │ ├── ARCs:ARC-template.md
│ │ │ │ │ ├── ARCs:assets:arc-0012:README.md
│ │ │ │ │ ├── ARCs:assets:arc-0034:TemplateForm.md
│ │ │ │ │ ├── ARCs:assets:arc-0062:README.md
│ │ │ │ │ ├── ARCs:pages:nfts.md
│ │ │ │ │ ├── ARCs:pages:wallets.md
│ │ │ │ │ ├── ARCs:README.md
│ │ │ │ │ ├── ARCs:specs:arc-0000.md
│ │ │ │ │ ├── ARCs:specs:arc-0001.md
│ │ │ │ │ ├── ARCs:specs:arc-0002.md
│ │ │ │ │ ├── ARCs:specs:arc-0003.md
│ │ │ │ │ ├── ARCs:specs:arc-0004.md
│ │ │ │ │ ├── ARCs:specs:arc-0005.md
│ │ │ │ │ ├── ARCs:specs:arc-0006.md
│ │ │ │ │ ├── ARCs:specs:arc-0007.md
│ │ │ │ │ ├── ARCs:specs:arc-0008.md
│ │ │ │ │ ├── ARCs:specs:arc-0009.md
│ │ │ │ │ ├── ARCs:specs:arc-0010.md
│ │ │ │ │ ├── ARCs:specs:arc-0011.md
│ │ │ │ │ ├── ARCs:specs:arc-0012.md
│ │ │ │ │ ├── ARCs:specs:arc-0015.md
│ │ │ │ │ ├── ARCs:specs:arc-0016.md
│ │ │ │ │ ├── ARCs:specs:arc-0018.md
│ │ │ │ │ ├── ARCs:specs:arc-0019.md
│ │ │ │ │ ├── ARCs:specs:arc-0020.md
│ │ │ │ │ ├── ARCs:specs:arc-0021.md
│ │ │ │ │ ├── ARCs:specs:arc-0022.md
│ │ │ │ │ ├── ARCs:specs:arc-0023.md
│ │ │ │ │ ├── ARCs:specs:arc-0025.md
│ │ │ │ │ ├── ARCs:specs:arc-0026.md
│ │ │ │ │ ├── ARCs:specs:arc-0028.md
│ │ │ │ │ ├── ARCs:specs:arc-0032.md
│ │ │ │ │ ├── ARCs:specs:arc-0033.md
│ │ │ │ │ ├── ARCs:specs:arc-0034.md
│ │ │ │ │ ├── ARCs:specs:arc-0035.md
│ │ │ │ │ ├── ARCs:specs:arc-0036.md
│ │ │ │ │ ├── ARCs:specs:arc-0042.md
│ │ │ │ │ ├── ARCs:specs:arc-0047.md
│ │ │ │ │ ├── ARCs:specs:arc-0048.md
│ │ │ │ │ ├── ARCs:specs:arc-0049.md
│ │ │ │ │ ├── ARCs:specs:arc-0054.md
│ │ │ │ │ ├── ARCs:specs:arc-0055.md
│ │ │ │ │ ├── ARCs:specs:arc-0056.md
│ │ │ │ │ ├── ARCs:specs:arc-0059.md
│ │ │ │ │ ├── ARCs:specs:arc-0062.md
│ │ │ │ │ ├── ARCs:specs:arc-0065.md
│ │ │ │ │ ├── ARCs:specs:arc-0069.md
│ │ │ │ │ ├── ARCs:specs:arc-0072.md
│ │ │ │ │ ├── ARCs:specs:arc-0073.md
│ │ │ │ │ ├── ARCs:specs:arc-0074.md
│ │ │ │ │ ├── ARCs:specs:arc-0076.md
│ │ │ │ │ ├── ARCs:specs:arc-0078.md
│ │ │ │ │ ├── ARCs:specs:arc-0079.md
│ │ │ │ │ ├── ARCs:specs:arc-0200.md
│ │ │ │ │ ├── clis_index.md
│ │ │ │ │ ├── developer:docs:about.md
│ │ │ │ │ ├── developer:docs:clis:algokey:algokey.md
│ │ │ │ │ ├── developer:docs:clis:algokey:generate.md
│ │ │ │ │ ├── developer:docs:clis:algokey:import.md
│ │ │ │ │ ├── developer:docs:clis:algokey:multisig:append-auth-addr.md
│ │ │ │ │ ├── developer:docs:clis:algokey:multisig:multisig.md
│ │ │ │ │ ├── developer:docs:clis:algokey:part:info.md
│ │ │ │ │ ├── developer:docs:clis:algokey:part:part.md
│ │ │ │ │ ├── developer:docs:clis:algokey:part:reparent.md
│ │ │ │ │ ├── developer:docs:clis:algokey:sign.md
│ │ │ │ │ ├── developer:docs:clis:conduit:conduit.md
│ │ │ │ │ ├── developer:docs:clis:conduit:init.md
│ │ │ │ │ ├── developer:docs:clis:conduit:list:exporters.md
│ │ │ │ │ ├── developer:docs:clis:conduit:list:importers.md
│ │ │ │ │ ├── developer:docs:clis:conduit:list:list.md
│ │ │ │ │ ├── developer:docs:clis:conduit:list:processors.md
│ │ │ │ │ ├── developer:docs:clis:diagcfg:diagcfg.md
│ │ │ │ │ ├── developer:docs:clis:diagcfg:metric:disable.md
│ │ │ │ │ ├── developer:docs:clis:diagcfg:metric:enable.md
│ │ │ │ │ ├── developer:docs:clis:diagcfg:metric:metric.md
│ │ │ │ │ ├── developer:docs:clis:diagcfg:metric:status.md
│ │ │ │ │ ├── developer:docs:clis:diagcfg:telemetry:disable.md
│ │ │ │ │ ├── developer:docs:clis:diagcfg:telemetry:enable.md
│ │ │ │ │ ├── developer:docs:clis:diagcfg:telemetry:endpoint.md
│ │ │ │ │ ├── developer:docs:clis:diagcfg:telemetry:name.md
│ │ │ │ │ ├── developer:docs:clis:diagcfg:telemetry:status.md
│ │ │ │ │ ├── developer:docs:clis:diagcfg:telemetry:telemetry.md
│ │ │ │ │ ├── developer:docs:clis:goal:node:restart.md
│ │ │ │ │ ├── developer:docs:clis:goal:node:start.md
│ │ │ │ │ ├── developer:docs:clis:goal:node:status.md
│ │ │ │ │ ├── developer:docs:clis:goal:node:stop.md
│ │ │ │ │ ├── developer:docs:clis:goal:node:wait.md
│ │ │ │ │ ├── developer:docs:clis:goal:protocols.md
│ │ │ │ │ ├── developer:docs:clis:goal:report.md
│ │ │ │ │ ├── developer:docs:clis:goal:version.md
│ │ │ │ │ ├── developer:docs:clis:goal:wallet:list.md
│ │ │ │ │ ├── developer:docs:clis:goal:wallet:new.md
│ │ │ │ │ ├── developer:docs:clis:goal:wallet:wallet.md
│ │ │ │ │ ├── developer:docs:clis:indexer:api-config.md
│ │ │ │ │ ├── developer:docs:clis:indexer:daemon.md
│ │ │ │ │ ├── developer:docs:clis:indexer:indexer.md
│ │ │ │ │ ├── developer:docs:clis:indexer:util:util.md
│ │ │ │ │ ├── developer:docs:clis:indexer:util:validator.md
│ │ │ │ │ ├── developer:docs:clis:kmd.md
│ │ │ │ │ ├── developer:docs:clis:tealdbg:debug.md
│ │ │ │ │ ├── developer:docs:clis:tealdbg:remote.md
│ │ │ │ │ ├── developer:docs:clis:tealdbg:tealdbg.md
│ │ │ │ │ ├── developer:docs:details:accounts:create.md
│ │ │ │ │ ├── developer:docs:details:accounts:index.md
│ │ │ │ │ ├── developer:docs:details:accounts:rekey.md
│ │ │ │ │ ├── developer:docs:details:algorand_consensus.md
│ │ │ │ │ ├── developer:docs:details:algorand-networks:betanet.md
│ │ │ │ │ ├── developer:docs:details:algorand-networks:index.md
│ │ │ │ │ ├── developer:docs:details:algorand-networks:mainnet.md
│ │ │ │ │ ├── developer:docs:details:algorand-networks:testnet.md
│ │ │ │ │ ├── developer:docs:details:asa.md
│ │ │ │ │ ├── developer:docs:details:atc.md
│ │ │ │ │ ├── developer:docs:details:atomic_transfers.md
│ │ │ │ │ ├── developer:docs:details:conduit.md
│ │ │ │ │ ├── developer:docs:details:crust.md
│ │ │ │ │ ├── developer:docs:details:dapps:avm:index.md
│ │ │ │ │ ├── developer:docs:details:dapps:avm:teal:guidelines.md
│ │ │ │ │ ├── developer:docs:details:dapps:avm:teal:index.md
│ │ │ │ │ ├── developer:docs:details:dapps:avm:teal:jsonspec.md
│ │ │ │ │ ├── developer:docs:details:dapps:avm:teal:opcodes:index.md
│ │ │ │ │ ├── developer:docs:details:dapps:avm:teal:opcodes:v1.md
│ │ │ │ │ ├── developer:docs:details:dapps:avm:teal:opcodes:v10.md
│ │ │ │ │ ├── developer:docs:details:dapps:avm:teal:opcodes:v2.md
│ │ │ │ │ ├── developer:docs:details:dapps:avm:teal:opcodes:v3.md
│ │ │ │ │ ├── developer:docs:details:dapps:avm:teal:opcodes:v4.md
│ │ │ │ │ ├── developer:docs:details:dapps:avm:teal:opcodes:v5.md
│ │ │ │ │ ├── developer:docs:details:dapps:avm:teal:opcodes:v6.md
│ │ │ │ │ ├── developer:docs:details:dapps:avm:teal:opcodes:v7.md
│ │ │ │ │ ├── developer:docs:details:dapps:avm:teal:opcodes:v8.md
│ │ │ │ │ ├── developer:docs:details:dapps:avm:teal:opcodes:v9.md
│ │ │ │ │ ├── developer:docs:details:dapps:avm:teal:specification.md
│ │ │ │ │ ├── developer:docs:details:dapps:smart-contracts:ABI:index.md
│ │ │ │ │ ├── developer:docs:details:dapps:smart-contracts:apps:create.md
│ │ │ │ │ ├── developer:docs:details:dapps:smart-contracts:apps:index.md
│ │ │ │ │ ├── developer:docs:details:dapps:smart-contracts:apps:innertx.md
│ │ │ │ │ ├── developer:docs:details:dapps:smart-contracts:apps:state.md
│ │ │ │ │ ├── developer:docs:details:dapps:smart-contracts:apps:txs.md
│ │ │ │ │ ├── developer:docs:details:dapps:smart-contracts:debugging.md
│ │ │ │ │ ├── developer:docs:details:dapps:smart-contracts:frontend:apps.md
│ │ │ │ │ ├── developer:docs:details:dapps:smart-contracts:frontend:smartsigs.md
│ │ │ │ │ ├── developer:docs:details:dapps:smart-contracts:guidelines.md
│ │ │ │ │ ├── developer:docs:details:dapps:smart-contracts:index.md
│ │ │ │ │ ├── developer:docs:details:dapps:smart-contracts:smartsigs:index.md
│ │ │ │ │ ├── developer:docs:details:dapps:smart-contracts:smartsigs:modes.md
│ │ │ │ │ ├── developer:docs:details:dapps:smart-contracts:smartsigs:walkthrough.md
│ │ │ │ │ ├── developer:docs:details:dapps:writing-contracts:beaker.md
│ │ │ │ │ ├── developer:docs:details:dapps:writing-contracts:pyteal.md
│ │ │ │ │ ├── developer:docs:details:dapps:writing-contracts:python.md
│ │ │ │ │ ├── developer:docs:details:encoding.md
│ │ │ │ │ ├── developer:docs:details:ethereum_to_algorand.md
│ │ │ │ │ ├── developer:docs:details:index.md
│ │ │ │ │ ├── developer:docs:details:indexer.md
│ │ │ │ │ ├── developer:docs:details:parameter_tables.md
│ │ │ │ │ ├── developer:docs:details:stateproofs:index.md
│ │ │ │ │ ├── developer:docs:details:stateproofs:light_client.md
│ │ │ │ │ ├── developer:docs:details:technical_faq.md
│ │ │ │ │ ├── developer:docs:details:transactions:index.md
│ │ │ │ │ ├── developer:docs:details:transactions:offline_transactions.md
│ │ │ │ │ ├── developer:docs:details:transactions:payment_prompts.md
│ │ │ │ │ ├── developer:docs:details:transactions:signatures.md
│ │ │ │ │ ├── developer:docs:details:transactions:transactions.md
│ │ │ │ │ ├── developer:docs:details:useful_resources.md
│ │ │ │ │ ├── developer:docs:get-started:algokit.md
│ │ │ │ │ ├── developer:docs:get-started:basics:what_is_blockchain.md
│ │ │ │ │ ├── developer:docs:get-started:basics:whats_a_dapp.md
│ │ │ │ │ ├── developer:docs:get-started:basics:where_to_start.md
│ │ │ │ │ ├── developer:docs:get-started:basics:why_algorand.md
│ │ │ │ │ ├── developer:docs:get-started:tokenization:ft.md
│ │ │ │ │ ├── developer:docs:get-started:tokenization:nft.md
│ │ │ │ │ ├── developer:docs:index.md
│ │ │ │ │ ├── developer:docs:rest-apis:algod.md
│ │ │ │ │ ├── developer:docs:rest-apis:indexer.md
│ │ │ │ │ ├── developer:docs:rest-apis:kmd.md
│ │ │ │ │ ├── developer:docs:rest-apis:restendpoints.md
│ │ │ │ │ ├── developer:docs:run-a-node:operations:catchup.md
│ │ │ │ │ ├── developer:docs:run-a-node:operations:switch_networks.md
│ │ │ │ │ ├── developer:docs:run-a-node:participate:generate_keys.md
│ │ │ │ │ ├── developer:docs:run-a-node:participate:index.md
│ │ │ │ │ ├── developer:docs:run-a-node:participate:offline.md
│ │ │ │ │ ├── developer:docs:run-a-node:participate:online.md
│ │ │ │ │ ├── developer:docs:run-a-node:participate:renew.md
│ │ │ │ │ ├── developer:docs:run-a-node:reference:artifacts.md
│ │ │ │ │ ├── developer:docs:run-a-node:reference:config.md
│ │ │ │ │ ├── developer:docs:run-a-node:reference:relay.md
│ │ │ │ │ ├── developer:docs:run-a-node:reference:telemetry-config.md
│ │ │ │ │ ├── developer:docs:run-a-node:setup:indexer.md
│ │ │ │ │ ├── developer:docs:run-a-node:setup:install.md
│ │ │ │ │ ├── developer:docs:run-a-node:setup:node-troubleshooting.md
│ │ │ │ │ ├── developer:docs:run-a-node:setup:types.md
│ │ │ │ │ ├── developer:docs:sdks:go:index.md
│ │ │ │ │ ├── developer:docs:sdks:index.md
│ │ │ │ │ ├── developer:docs:sdks:java:index.md
│ │ │ │ │ ├── developer:docs:sdks:javascript:index.md
│ │ │ │ │ ├── developer:docs:sdks:python:index.md
│ │ │ │ │ ├── developer:python:code:example:accounts.md
│ │ │ │ │ ├── developer:python:code:example:arc4_types.md
│ │ │ │ │ ├── developer:python:code:example:assets.md
│ │ │ │ │ ├── developer:python:code:example:box_storage.md
│ │ │ │ │ ├── developer:python:code:example:control_flow.md
│ │ │ │ │ ├── developer:python:code:example:crypto:merkle_tree.md
│ │ │ │ │ ├── developer:python:code:example:defi:amm.md
│ │ │ │ │ ├── developer:python:code:example:defi:auction.md
│ │ │ │ │ ├── developer:python:code:example:defi:htlc_logicsig.md
│ │ │ │ │ ├── developer:python:code:example:defi:marketplace.md
│ │ │ │ │ ├── developer:python:code:example:events:arc28_events.md
│ │ │ │ │ ├── developer:python:code:example:global_storage.md
│ │ │ │ │ ├── developer:python:code:example:governance:simple_voting.md
│ │ │ │ │ ├── developer:python:code:example:hello_world.md
│ │ │ │ │ ├── developer:python:code:example:inner_transactions.md
│ │ │ │ │ ├── developer:python:code:example:local_storage.md
│ │ │ │ │ ├── developer:python:code:example:nft:proof_of_attendance.md
│ │ │ │ │ ├── developer:python:code:example:privacy:zk_whitelist.md
│ │ │ │ │ ├── developer:python:code:example:scratch_storage.md
│ │ │ │ │ ├── developer:python:code:example:self_payment.md
│ │ │ │ │ ├── developer:python:code:example:struct_in_box.md
│ │ │ │ │ ├── developer:python:code:example:subsidize_app_call.md
│ │ │ │ │ ├── developer:python:code:example:transactions.md
│ │ │ │ │ ├── developer:python:code:example:utility:calculator.md
│ │ │ │ │ ├── devportal-code-examples:projects:python-contract-examples:README.md
│ │ │ │ │ ├── devportal-code-examples:README.md
│ │ │ │ │ ├── docs:.walletconnect:index.md
│ │ │ │ │ ├── docs:.walletconnect:walletconnect-schema.md
│ │ │ │ │ ├── docs:README.md
│ │ │ │ │ ├── docs:scripts:example_tracker:example_list.md
│ │ │ │ │ ├── docs:scripts:README.md
│ │ │ │ │ ├── index.md
│ │ │ │ │ ├── liquid_auth_index.md
│ │ │ │ │ ├── liquid-auth:ARCHITECTURE.md
│ │ │ │ │ ├── liquid-auth:decisions:1-Service-Authentication.md
│ │ │ │ │ ├── liquid-auth:decisions:2-Bidirectional-Communication.md
│ │ │ │ │ ├── liquid-auth:decisions:3-Peer-to-Peer-Signaling.md
│ │ │ │ │ ├── liquid-auth:decisions:4-Fido-Extension.md
│ │ │ │ │ ├── liquid-auth:decisions:README.md
│ │ │ │ │ ├── liquid-auth:docs:architecture.md
│ │ │ │ │ ├── liquid-auth:docs:clients:android:provider-service:authenticate.md
│ │ │ │ │ ├── liquid-auth:docs:clients:android:provider-service:register.md
│ │ │ │ │ ├── liquid-auth:docs:clients:browser:authentication.md
│ │ │ │ │ ├── liquid-auth:docs:clients:browser:example.md
│ │ │ │ │ ├── liquid-auth:docs:introduction.md
│ │ │ │ │ ├── liquid-auth:docs:README.md
│ │ │ │ │ ├── liquid-auth:docs:server:environment-variables.md
│ │ │ │ │ ├── liquid-auth:docs:server:integrations.md
│ │ │ │ │ ├── liquid-auth:docs:server:introduction.md
│ │ │ │ │ ├── liquid-auth:docs:server:running-locally.md
│ │ │ │ │ ├── liquid-auth:README.md
│ │ │ │ │ ├── liquid-auth:SEQUENCE.md
│ │ │ │ │ ├── liquid-auth:services:liquid-auth-api-js:src:assertion:assertion.controller.post.request.md
│ │ │ │ │ ├── liquid-auth:services:liquid-auth-api-js:src:assertion:assertion.controller.post.response.md
│ │ │ │ │ ├── liquid-auth:services:liquid-auth-api-js:src:attestation:attestation.controller.post.request.md
│ │ │ │ │ ├── liquid-auth:services:liquid-auth-api-js:src:auth:auth.controller.get.user.md
│ │ │ │ │ ├── liquid-auth:sites:express-dapp:README.md
│ │ │ │ │ ├── liquid-auth:VISION.md
│ │ │ │ │ ├── puya_index.md
│ │ │ │ │ ├── puya:docs:algopy_testing:index.md
│ │ │ │ │ ├── puya:docs:api-algopy.arc4.md
│ │ │ │ │ ├── puya:docs:api-algopy.gtxn.md
│ │ │ │ │ ├── puya:docs:api-algopy.itxn.md
│ │ │ │ │ ├── puya:docs:api-algopy.md
│ │ │ │ │ ├── puya:docs:api-algopy.op.md
│ │ │ │ │ ├── puya:docs:api.md
│ │ │ │ │ ├── puya:docs:compiler.md
│ │ │ │ │ ├── puya:docs:index.md
│ │ │ │ │ ├── puya:docs:language-guide.md
│ │ │ │ │ ├── puya:docs:lg-arc28.md
│ │ │ │ │ ├── puya:docs:lg-arc4.md
│ │ │ │ │ ├── puya:docs:lg-builtins.md
│ │ │ │ │ ├── puya:docs:lg-calling-apps.md
│ │ │ │ │ ├── puya:docs:lg-compile.md
│ │ │ │ │ ├── puya:docs:lg-control.md
│ │ │ │ │ ├── puya:docs:lg-errors.md
│ │ │ │ │ ├── puya:docs:lg-logs.md
│ │ │ │ │ ├── puya:docs:lg-modules.md
│ │ │ │ │ ├── puya:docs:lg-opcode-budget.md
│ │ │ │ │ ├── puya:docs:lg-ops.md
│ │ │ │ │ ├── puya:docs:lg-storage.md
│ │ │ │ │ ├── puya:docs:lg-structure.md
│ │ │ │ │ ├── puya:docs:lg-transactions.md
│ │ │ │ │ ├── puya:docs:lg-types.md
│ │ │ │ │ ├── puya:docs:lg-unsupported-python-features.md
│ │ │ │ │ ├── puya:docs:principles.md
│ │ │ │ │ ├── puya:examples:auction:README.md
│ │ │ │ │ ├── puya:python:testing:docs:algopy.md
│ │ │ │ │ ├── puya:python:testing:docs:api.md
│ │ │ │ │ ├── puya:python:testing:docs:coverage.md
│ │ │ │ │ ├── puya:python:testing:docs:examples.md
│ │ │ │ │ ├── puya:python:testing:docs:faq.md
│ │ │ │ │ ├── puya:python:testing:docs:index.md
│ │ │ │ │ ├── puya:python:testing:docs:testing-guide:arc4-types.md
│ │ │ │ │ ├── puya:python:testing:docs:testing-guide:avm-types.md
│ │ │ │ │ ├── puya:python:testing:docs:testing-guide:concepts.md
│ │ │ │ │ ├── puya:python:testing:docs:testing-guide:contract-testing.md
│ │ │ │ │ ├── puya:python:testing:docs:testing-guide:index.md
│ │ │ │ │ ├── puya:python:testing:docs:testing-guide:opcodes.md
│ │ │ │ │ ├── puya:python:testing:docs:testing-guide:signature-testing.md
│ │ │ │ │ ├── puya:python:testing:docs:testing-guide:state-management.md
│ │ │ │ │ ├── puya:python:testing:docs:testing-guide:subroutines.md
│ │ │ │ │ ├── puya:python:testing:docs:testing-guide:transactions.md
│ │ │ │ │ ├── puya:python:testing:examples:README.md
│ │ │ │ │ ├── puya:python:testing:README.md
│ │ │ │ │ ├── puya:README.md
│ │ │ │ │ ├── puya:src:puya:ARCHITECTURE.md
│ │ │ │ │ ├── puya:src:puyapy:_typeshed:README.md
│ │ │ │ │ ├── puya:src:puyapy:_vendor:mypy:typeshed:stdlib:_typeshed:README.md
│ │ │ │ │ ├── puya:src:puyapy:awst_build:README.md
│ │ │ │ │ ├── puya:stubs:README.md
│ │ │ │ │ ├── puya:tests:test_expected_output:README.md
│ │ │ │ │ ├── puya:typescript:docs:architecture-decisions:2024-05-21_primitive-bytes-and-strings.md
│ │ │ │ │ ├── puya:typescript:docs:architecture-decisions:2024-05-21_primitive-integer-types.md
│ │ │ │ │ ├── puya:typescript:docs:README.md
│ │ │ │ │ ├── puya:typescript:packages:algo-ts:readme.md
│ │ │ │ │ ├── puya:typescript:README.md
│ │ │ │ │ ├── SDKs:javascript:classes:ABIAddressType.md
│ │ │ │ │ ├── SDKs:javascript:classes:ABIArrayDynamicType.md
│ │ │ │ │ ├── SDKs:javascript:classes:ABIArrayStaticType.md
│ │ │ │ │ ├── SDKs:javascript:classes:ABIBoolType.md
│ │ │ │ │ ├── SDKs:javascript:classes:ABIByteType.md
│ │ │ │ │ ├── SDKs:javascript:classes:ABIContract.md
│ │ │ │ │ ├── SDKs:javascript:classes:ABIInterface.md
│ │ │ │ │ ├── SDKs:javascript:classes:ABIMethod.md
│ │ │ │ │ ├── SDKs:javascript:classes:ABIStringType.md
│ │ │ │ │ ├── SDKs:javascript:classes:ABITupleType.md
│ │ │ │ │ ├── SDKs:javascript:classes:ABIType.md
│ │ │ │ │ ├── SDKs:javascript:classes:ABIUfixedType.md
│ │ │ │ │ ├── SDKs:javascript:classes:ABIUintType.md
│ │ │ │ │ ├── SDKs:javascript:classes:Algodv2.md
│ │ │ │ │ ├── SDKs:javascript:classes:AtomicTransactionComposer.md
│ │ │ │ │ ├── SDKs:javascript:classes:DryrunResult.md
│ │ │ │ │ ├── SDKs:javascript:classes:Indexer.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.Account.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.AccountParticipation.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.AccountResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.AccountsResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.AccountStateDelta.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.Application.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.ApplicationLocalState.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.ApplicationLocalStatesResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.ApplicationLogData.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.ApplicationLogsResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.ApplicationParams.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.ApplicationResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.ApplicationsResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.ApplicationStateSchema.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.Asset.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.AssetBalancesResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.AssetHolding.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.AssetHoldingsResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.AssetParams.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.AssetResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.AssetsResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.Block.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.BlockRewards.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.BlockUpgradeState.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.BlockUpgradeVote.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.Box.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.BoxDescriptor.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.BoxesResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.ErrorResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.EvalDelta.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.EvalDeltaKeyValue.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.HashFactory.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.HealthCheck.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.IndexerStateProofMessage.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.MerkleArrayProof.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.MiniAssetHolding.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.ParticipationUpdates.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.StateProofFields.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.StateProofParticipant.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.StateProofReveal.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.StateProofSignature.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.StateProofSigSlot.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.StateProofTracking.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.StateProofVerifier.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.StateSchema.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.TealKeyValue.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.TealValue.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.Transaction.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.TransactionApplication.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.TransactionAssetConfig.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.TransactionAssetFreeze.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.TransactionAssetTransfer.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.TransactionKeyreg.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.TransactionPayment.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.TransactionResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.TransactionSignature.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.TransactionSignatureLogicsig.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.TransactionSignatureMultisig.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.TransactionSignatureMultisigSubsignature.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.TransactionsResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:indexerModels.TransactionStateProof.md
│ │ │ │ │ ├── SDKs:javascript:classes:Kmd.md
│ │ │ │ │ ├── SDKs:javascript:classes:LogicSig.md
│ │ │ │ │ ├── SDKs:javascript:classes:LogicSigAccount.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.Account.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.AccountApplicationResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.AccountAssetHolding.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.AccountAssetResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.AccountAssetsInformationResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.AccountParticipation.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.AccountStateDelta.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.AppCallLogs.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.Application.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.ApplicationInitialStates.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.ApplicationKVStorage.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.ApplicationLocalReference.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.ApplicationLocalState.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.ApplicationParams.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.ApplicationStateOperation.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.ApplicationStateSchema.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.Asset.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.AssetHolding.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.AssetHoldingReference.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.AssetParams.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.AvmKeyValue.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.AvmValue.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.BlockHashResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.BlockLogsResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.BlockResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.BlockTxidsResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.Box.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.BoxDescriptor.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.BoxesResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.BoxReference.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.BuildVersion.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.CompileResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.DisassembleResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.DryrunRequest.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.DryrunResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.DryrunSource.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.DryrunState.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.DryrunTxnResult.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.ErrorResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.EvalDelta.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.EvalDeltaKeyValue.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.GetBlockTimeStampOffsetResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.GetSyncRoundResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.KvDelta.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.LedgerStateDeltaForTransactionGroup.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.LightBlockHeaderProof.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.NodeStatusResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.PendingTransactionResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.PendingTransactionsResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.PostTransactionsResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.ScratchChange.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.SimulateInitialStates.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.SimulateRequest.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.SimulateRequestTransactionGroup.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.SimulateResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.SimulateTraceConfig.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.SimulateTransactionGroupResult.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.SimulateTransactionResult.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.SimulateUnnamedResourcesAccessed.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.SimulationEvalOverrides.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.SimulationOpcodeTraceUnit.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.SimulationTransactionExecTrace.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.StateProof.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.StateProofMessage.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.SupplyResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.TealKeyValue.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.TealValue.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.TransactionGroupLedgerStateDeltasForRoundResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.TransactionParametersResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.TransactionProofResponse.md
│ │ │ │ │ ├── SDKs:javascript:classes:modelsv2.Version.md
│ │ │ │ │ ├── SDKs:javascript:classes:SourceMap.md
│ │ │ │ │ ├── SDKs:javascript:classes:Transaction.md
│ │ │ │ │ ├── SDKs:javascript:enums:ABIReferenceType.md
│ │ │ │ │ ├── SDKs:javascript:enums:ABITransactionType.md
│ │ │ │ │ ├── SDKs:javascript:enums:AtomicTransactionComposerStatus.md
│ │ │ │ │ ├── SDKs:javascript:enums:IntDecoding.md
│ │ │ │ │ ├── SDKs:javascript:enums:OnApplicationComplete.md
│ │ │ │ │ ├── SDKs:javascript:enums:TransactionType.md
│ │ │ │ │ ├── SDKs:javascript:examples:README.md
│ │ │ │ │ ├── SDKs:javascript:FAQ.md
│ │ │ │ │ ├── SDKs:javascript:interfaces:ABIContractNetworkInfo.md
│ │ │ │ │ ├── SDKs:javascript:interfaces:ABIContractNetworks.md
│ │ │ │ │ ├── SDKs:javascript:interfaces:ABIContractParams.md
│ │ │ │ │ ├── SDKs:javascript:interfaces:ABIInterfaceParams.md
│ │ │ │ │ ├── SDKs:javascript:interfaces:ABIMethodArgParams.md
│ │ │ │ │ ├── SDKs:javascript:interfaces:ABIMethodParams.md
│ │ │ │ │ ├── SDKs:javascript:interfaces:ABIMethodReturnParams.md
│ │ │ │ │ ├── SDKs:javascript:interfaces:ABIResult.md
│ │ │ │ │ ├── SDKs:javascript:interfaces:Account.md
│ │ │ │ │ ├── SDKs:javascript:interfaces:Address.md
│ │ │ │ │ ├── SDKs:javascript:interfaces:AlgodTokenHeader.md
│ │ │ │ │ ├── SDKs:javascript:interfaces:BaseHTTPClient.md
│ │ │ │ │ ├── SDKs:javascript:interfaces:BaseHTTPClientError.md
│ │ │ │ │ ├── SDKs:javascript:interfaces:BaseHTTPClientResponse.md
│ │ │ │ │ ├── SDKs:javascript:interfaces:BoxReference.md
│ │ │ │ │ ├── SDKs:javascript:interfaces:CustomTokenHeader.md
│ │ │ │ │ ├── SDKs:javascript:interfaces:EncodedAssetParams.md
│ │ │ │ │ ├── SDKs:javascript:interfaces:EncodedBoxReference.md
│ │ │ │ │ ├── SDKs:javascript:interfaces:EncodedGlobalStateSchema.md
│ │ │ │ │ ├── SDKs:javascript:interfaces:EncodedLocalStateSchema.md
│ │ │ │ │ ├── SDKs:javascript:interfaces:EncodedLogicSig.md
│ │ │ │ │ ├── SDKs:javascript:interfaces:EncodedLogicSigAccount.md
│ │ │ │ │ ├── SDKs:javascript:interfaces:EncodedMultisig.md
│ │ │ │ │ ├── SDKs:javascript:interfaces:EncodedSignedTransaction.md
│ │ │ │ │ ├── SDKs:javascript:interfaces:EncodedSubsig.md
│ │ │ │ │ ├── SDKs:javascript:interfaces:EncodedTransaction.md
│ │ │ │ │ ├── SDKs:javascript:interfaces:IndexerTokenHeader.md
│ │ │ │ │ ├── SDKs:javascript:interfaces:KMDTokenHeader.md
│ │ │ │ │ ├── SDKs:javascript:interfaces:MultisigMetadata.md
│ │ │ │ │ ├── SDKs:javascript:interfaces:SignedTransaction.md
│ │ │ │ │ ├── SDKs:javascript:interfaces:SuggestedParams.md
│ │ │ │ │ ├── SDKs:javascript:interfaces:TransactionParams.md
│ │ │ │ │ ├── SDKs:javascript:interfaces:TransactionWithSigner.md
│ │ │ │ │ ├── SDKs:javascript:modules:indexerModels.md
│ │ │ │ │ ├── SDKs:javascript:modules:modelsv2.md
│ │ │ │ │ ├── SDKs:javascript:modules.md
│ │ │ │ │ ├── SDKs:javascript:README.md
│ │ │ │ │ ├── SDKs:python:algosdk:v2client:harness:README.md
│ │ │ │ │ ├── SDKs:python:examples:README.md
│ │ │ │ │ ├── SDKs:python:README.md
│ │ │ │ │ ├── tealscript:examples_amm_README.md
│ │ │ │ │ ├── tealscript:examples_auction_README.md
│ │ │ │ │ ├── tealscript:examples_big_box_README.md
│ │ │ │ │ ├── tealscript:examples_itxns_README.md
│ │ │ │ │ ├── tealscript:examples_lsig_with_app_README.md
│ │ │ │ │ ├── tealscript:examples_reti_README.md
│ │ │ │ │ ├── tealscript:FEATURES.md
│ │ │ │ │ ├── tealscript:guides_atomic_txn.md
│ │ │ │ │ ├── tealscript:guides_features.md
│ │ │ │ │ ├── tealscript:guides_getting_started.md
│ │ │ │ │ ├── tealscript:guides_inner_transactions.md
│ │ │ │ │ ├── tealscript:guides_lifecycle.md
│ │ │ │ │ ├── tealscript:guides_math.md
│ │ │ │ │ ├── tealscript:guides_methods.md
│ │ │ │ │ ├── tealscript:guides_multiple_contracts.md
│ │ │ │ │ ├── tealscript:guides_pyteal.md
│ │ │ │ │ ├── tealscript:guides_storage.md
│ │ │ │ │ ├── tealscript:guides_Supported Types_arrays.md
│ │ │ │ │ ├── tealscript:guides_Supported Types_numbers.md
│ │ │ │ │ ├── TEALScript:README.md
│ │ │ │ │ ├── tealscript:tests_test_package_README.md
│ │ │ │ │ ├── tealscript:tutorials_Hello World_0001-intro.md
│ │ │ │ │ ├── tealscript:tutorials_Hello World_0002-init.md
│ │ │ │ │ ├── tealscript:tutorials_Hello World_0003-contract.md
│ │ │ │ │ ├── tealscript:tutorials_Hello World_0004-artifacts.md
│ │ │ │ │ ├── tealscript:tutorials_Hello World_0005-hello.md
│ │ │ │ │ └── tealscript:tutorials_Hello World_0006-test.md
│ │ │ │ └── taxonomy-categories
│ │ │ │ ├── algokit-utils.json
│ │ │ │ ├── algokit.json
│ │ │ │ ├── arcs.json
│ │ │ │ ├── clis.json
│ │ │ │ ├── details.json
│ │ │ │ ├── developers.json
│ │ │ │ ├── liquid-auth.json
│ │ │ │ ├── nodes.json
│ │ │ │ ├── puya.json
│ │ │ │ ├── python.json
│ │ │ │ ├── sdks.json
│ │ │ │ └── tealscript.json
│ │ │ └── wallet
│ │ │ └── index.ts
│ │ ├── tools
│ │ │ ├── accountManager.ts
│ │ │ ├── algodManager.ts
│ │ │ ├── apiManager
│ │ │ │ ├── algod
│ │ │ │ │ ├── account.ts
│ │ │ │ │ ├── application.ts
│ │ │ │ │ ├── asset.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── transaction.ts
│ │ │ │ ├── example
│ │ │ │ │ ├── get-balance.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── indexer
│ │ │ │ │ ├── account.ts
│ │ │ │ │ ├── application.ts
│ │ │ │ │ ├── asset.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── transaction.ts
│ │ │ │ ├── nfd
│ │ │ │ │ └── index.ts
│ │ │ │ ├── tinyman
│ │ │ │ │ ├── analytics.ts
│ │ │ │ │ ├── bootstrap.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── liquidity.ts
│ │ │ │ │ ├── opt_in.ts
│ │ │ │ │ ├── pool.ts
│ │ │ │ │ ├── remove_liquidity.ts
│ │ │ │ │ └── swap.ts
│ │ │ │ ├── ultrade
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── market.ts
│ │ │ │ │ ├── system.ts
│ │ │ │ │ └── wallet.ts
│ │ │ │ └── vestige
│ │ │ │ ├── assets.ts
│ │ │ │ ├── balances.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── networks.ts
│ │ │ │ ├── notes.ts
│ │ │ │ ├── pools.ts
│ │ │ │ ├── protocols.ts
│ │ │ │ ├── swaps.ts
│ │ │ │ └── vaults.ts
│ │ │ ├── arc26Manager.ts
│ │ │ ├── index.ts
│ │ │ ├── knowledgeManager.ts
│ │ │ ├── transactionManager
│ │ │ │ ├── accountTransactions.ts
│ │ │ │ ├── appTransactions
│ │ │ │ │ ├── callTxn.ts
│ │ │ │ │ ├── clearTxn.ts
│ │ │ │ │ ├── closeOutTxn.ts
│ │ │ │ │ ├── createTxn.ts
│ │ │ │ │ ├── deleteTxn.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── optInTxn.ts
│ │ │ │ │ ├── test
│ │ │ │ │ │ ├── counter_approval.teal
│ │ │ │ │ │ ├── counter_clear.teal
│ │ │ │ │ │ ├── storage_test_approval_v2.teal
│ │ │ │ │ │ ├── storage_test_approval.teal
│ │ │ │ │ │ └── storage_test_clear.teal
│ │ │ │ │ ├── types.ts
│ │ │ │ │ └── updateTxn.ts
│ │ │ │ ├── assetTransactions.ts
│ │ │ │ ├── generalTransaction.ts
│ │ │ │ └── index.ts
│ │ │ └── utilityManager.ts
│ │ ├── types.ts
│ │ └── utils
│ │ └── responseProcessor.ts
│ ├── tests
│ │ ├── resources
│ │ │ ├── algod
│ │ │ │ ├── account.test.ts
│ │ │ │ ├── application.test.ts
│ │ │ │ ├── asset.test.ts
│ │ │ │ └── transaction.test.ts
│ │ │ └── indexer
│ │ │ ├── account.test.ts
│ │ │ ├── application.test.ts
│ │ │ ├── asset.test.ts
│ │ │ └── transaction.test.ts
│ │ └── tools
│ │ ├── accountManager.test.ts
│ │ ├── algodManager.test.ts
│ │ ├── apiManager
│ │ │ └── example
│ │ │ └── get-balance.test.ts
│ │ ├── transactionManager
│ │ │ ├── accountTransactionManager.test.ts
│ │ │ ├── appTransactionManager.test.ts
│ │ │ ├── assetTransactionManager.test.ts
│ │ │ ├── generalTransactionManager.test.ts
│ │ │ └── transactionManager.test.ts
│ │ └── utilityManager.test.ts
│ └── tsconfig.json
├── README.md
├── rename_files.sh
└── tsconfig.json
```
# Files
--------------------------------------------------------------------------------
/packages/server/src/tools/utilityManager.ts:
--------------------------------------------------------------------------------
```typescript
import algosdk from 'algosdk';
import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js';
import nacl from 'tweetnacl';
// Tool schemas
export const utilityToolSchemas = {
ping: {
type: 'object',
properties: {},
required: []
},
validateAddress: {
type: 'object',
properties: {
address: { type: 'string', description: 'Address in standard Algorand format (58 characters)' }
},
required: ['address']
},
encodeAddress: {
type: 'object',
properties: {
publicKey: { type: 'string', description: 'Public key in hexadecimal format to encode into an address' }
},
required: ['publicKey']
},
decodeAddress: {
type: 'object',
properties: {
address: { type: 'string', description: 'Address in standard Algorand format (58 characters) to decode' }
},
required: ['address']
},
getApplicationAddress: {
type: 'object',
properties: {
appId: { type: 'integer', description: 'Application ID to get the address for' }
},
required: ['appId']
},
bytesToBigint: {
type: 'object',
properties: {
bytes: { type: 'string', description: 'Bytes in hexadecimal format to convert to a BigInt' }
},
required: ['bytes']
},
bigintToBytes: {
type: 'object',
properties: {
value: { type: 'string', description: 'BigInt value as a string to convert to bytes' },
size: { type: 'integer', description: 'Size of the resulting byte array' }
},
required: ['value', 'size']
},
encodeUint64: {
type: 'object',
properties: {
value: { type: 'string', description: 'Uint64 value as a string to encode into bytes' }
},
required: ['value']
},
decodeUint64: {
type: 'object',
properties: {
bytes: { type: 'string', description: 'Bytes in hexadecimal format to decode into a uint64' }
},
required: ['bytes']
},
verifyBytes: {
type: 'object',
properties: {
bytes: { type: 'string', description: 'Bytes in hexadecimal format to verify' },
signature: { type: 'string', description: 'Base64-encoded signature to verify' },
address: { type: 'string', description: 'Algorand account address' }
},
required: ['bytes', 'signature', 'address']
}
};
export class UtilityManager {
static readonly utilityTools = [
{
name: 'ping',
description: 'Basic protocol utility to verify server connectivity',
inputSchema: utilityToolSchemas.ping,
},
{
name: 'validate_address',
description: 'Check if an Algorand address is valid',
inputSchema: utilityToolSchemas.validateAddress,
},
{
name: 'encode_address',
description: 'Encode a public key to an Algorand address',
inputSchema: utilityToolSchemas.encodeAddress,
},
{
name: 'decode_address',
description: 'Decode an Algorand address to a public key',
inputSchema: utilityToolSchemas.decodeAddress,
},
{
name: 'get_application_address',
description: 'Get the address for a given application ID',
inputSchema: utilityToolSchemas.getApplicationAddress,
},
{
name: 'bytes_to_bigint',
description: 'Convert bytes to a BigInt',
inputSchema: utilityToolSchemas.bytesToBigint,
},
{
name: 'bigint_to_bytes',
description: 'Convert a BigInt to bytes',
inputSchema: utilityToolSchemas.bigintToBytes,
},
{
name: 'encode_uint64',
description: 'Encode a uint64 to bytes',
inputSchema: utilityToolSchemas.encodeUint64,
},
{
name: 'decode_uint64',
description: 'Decode bytes to a uint64',
inputSchema: utilityToolSchemas.decodeUint64,
},
{
name: 'verify_bytes',
description: 'Verify a signature against bytes with an Algorand address',
inputSchema: utilityToolSchemas.verifyBytes,
},
{
name: 'sign_bytes',
description: 'Sign bytes with a secret key',
inputSchema: {
type: 'object',
properties: {
bytes: { type: 'string', description: 'Bytes in hexadecimal format to sign' },
sk: { type: 'string', description: 'Secret key in hexadecimal format to sign the bytes with' }
},
required: ['bytes', 'sk']
},
},
{
name: 'encode_obj',
description: 'Encode an object to msgpack format',
inputSchema: {
type: 'object',
properties: {
obj: { type: 'object', description: 'Object to encode' }
},
required: ['obj']
},
},
{
name: 'decode_obj',
description: 'Decode msgpack bytes to an object',
inputSchema: {
type: 'object',
properties: {
bytes: { type: 'string', description: 'Base64-encoded msgpack bytes to decode' }
},
required: ['bytes']
},
}
];
// Tool handlers
static async handleTool(name: string, args: Record<string, unknown>) {
try {
switch (name) {
case 'ping':
return {
content: [{
type: 'text',
text: JSON.stringify({}, null, 2),
}],
};
case 'validate_address':
if (!args.address || typeof args.address !== 'string') {
throw new McpError(ErrorCode.InvalidParams, 'Address is required');
}
const isValid = UtilityManager.isValidAddress(args.address);
return {
content: [{
type: 'text',
text: JSON.stringify({ isValid }, null, 2),
}],
};
case 'encode_address':
if (!args.publicKey || typeof args.publicKey !== 'string') {
throw new McpError(ErrorCode.InvalidParams, 'Public key is required');
}
const encodedAddress = UtilityManager.encodeAddress(Buffer.from(args.publicKey, 'hex'));
return {
content: [{
type: 'text',
text: JSON.stringify({ address: encodedAddress }, null, 2),
}],
};
case 'decode_address':
if (!args.address || typeof args.address !== 'string') {
throw new McpError(ErrorCode.InvalidParams, 'Address is required');
}
const decodedPublicKey = UtilityManager.decodeAddress(args.address);
return {
content: [{
type: 'text',
text: JSON.stringify({ publicKey: Buffer.from(decodedPublicKey).toString('hex') }, null, 2),
}],
};
case 'get_application_address':
if (!args.appId || typeof args.appId !== 'number') {
throw new McpError(ErrorCode.InvalidParams, 'Application ID is required');
}
const appAddress = UtilityManager.getApplicationAddress(args.appId);
return {
content: [{
type: 'text',
text: JSON.stringify({ address: appAddress }, null, 2),
}],
};
case 'bytes_to_bigint':
if (!args.bytes || typeof args.bytes !== 'string') {
throw new McpError(ErrorCode.InvalidParams, 'Bytes are required');
}
const bigInt = UtilityManager.bytesToBigInt(Buffer.from(args.bytes, 'hex'));
return {
content: [{
type: 'text',
text: JSON.stringify({ value: bigInt.toString() }, null, 2),
}],
};
case 'bigint_to_bytes':
if (!args.value || typeof args.value !== 'string' || !args.size || typeof args.size !== 'number') {
throw new McpError(ErrorCode.InvalidParams, 'Value and size are required');
}
const bytes = UtilityManager.bigIntToBytes(BigInt(args.value), args.size);
return {
content: [{
type: 'text',
text: JSON.stringify({ bytes: Buffer.from(bytes).toString('hex') }, null, 2),
}],
};
case 'encode_uint64':
if (!args.value || typeof args.value !== 'string') {
throw new McpError(ErrorCode.InvalidParams, 'Value is required');
}
const encodedUint64 = UtilityManager.encodeUint64(BigInt(args.value));
return {
content: [{
type: 'text',
text: JSON.stringify({ bytes: Buffer.from(encodedUint64).toString('hex') }, null, 2),
}],
};
case 'decode_uint64':
if (!args.bytes || typeof args.bytes !== 'string') {
throw new McpError(ErrorCode.InvalidParams, 'Bytes are required');
}
const decodedUint64 = UtilityManager.decodeUint64(Buffer.from(args.bytes, 'hex'));
return {
content: [{
type: 'text',
text: JSON.stringify({ value: decodedUint64.toString() }, null, 2),
}],
};
case 'sign_bytes': {
if (!args.bytes || typeof args.bytes !== 'string' || !args.sk || typeof args.sk !== 'string') {
throw new McpError(ErrorCode.InvalidParams, 'Invalid sign bytes parameters');
}
try {
const bytes = Buffer.from(args.bytes, 'hex');
const sk = Buffer.from(args.sk, 'hex');
const sig = algosdk.signBytes(bytes, sk);
return {
content: [{
type: 'text',
text: JSON.stringify({
signature: Buffer.from(sig).toString('base64')
}, null, 2)
}]
};
} catch (error) {
throw new McpError(
ErrorCode.InvalidParams,
`Failed to sign bytes: ${error instanceof Error ? error.message : String(error)}`
);
}
}
case 'encode_obj': {
if (!args.obj || typeof args.obj !== 'object') {
throw new McpError(ErrorCode.InvalidParams, 'Invalid encode object parameters');
}
try {
const encoded = algosdk.encodeObj(args.obj);
return {
content: [{
type: 'text',
text: JSON.stringify({
encoded: Buffer.from(encoded).toString('base64')
}, null, 2)
}]
};
} catch (error) {
throw new McpError(
ErrorCode.InvalidParams,
`Failed to encode object: ${error instanceof Error ? error.message : String(error)}`
);
}
}
case 'decode_obj': {
if (!args.bytes || typeof args.bytes !== 'string') {
throw new McpError(ErrorCode.InvalidParams, 'Invalid decode object parameters');
}
try {
const bytes = Buffer.from(args.bytes, 'base64');
const decoded = algosdk.decodeObj(bytes);
return {
content: [{
type: 'text',
text: JSON.stringify(decoded, null, 2)
}]
};
} catch (error) {
throw new McpError(
ErrorCode.InvalidParams,
`Failed to decode object: ${error instanceof Error ? error.message : String(error)}`
);
}
}
case 'verify_bytes':
if (!args.bytes || typeof args.bytes !== 'string' || !args.signature || typeof args.signature !== 'string' || !args.address || typeof args.address !== 'string') {
throw new McpError(ErrorCode.InvalidParams, 'Bytes, signature, and public key are required');
}
const verified = UtilityManager.verifyBytes(new Uint8Array(Buffer.from(args.bytes, 'hex')), new Uint8Array(Buffer.from(args.signature, 'base64')), args.address);
return {
content: [{
type: 'text',
text: JSON.stringify({ verified }, null, 2),
}],
};
default:
console.error(`[MCP Error] Unknown tool requested: ${name}`);
throw new McpError(
ErrorCode.MethodNotFound,
`Unknown tool: ${name}`
);
}
} catch (error) {
if (error instanceof McpError) {
console.error(`[MCP Error] ${error.code}: ${error.message}`);
throw error;
}
console.error('[MCP Error] Unexpected error:', error);
throw new McpError(
ErrorCode.InternalError,
`Operation failed: ${error instanceof Error ? error.message : 'Unknown error'}`
);
}
}
/**
* Checks if an address is valid
* @param address The address to validate
* @returns True if the address is valid, false otherwise
*/
static isValidAddress(address: string): boolean {
try {
return algosdk.isValidAddress(address);
} catch (error) {
console.error('[MCP Error] Failed to validate address:', error);
throw new McpError(
ErrorCode.InvalidParams,
`Invalid address format: ${error instanceof Error ? error.message : 'Unknown error'}`
);
}
}
/**
* Encodes a public key to an Algorand address
* @param publicKey The public key to encode
* @returns The encoded address
*/
static encodeAddress(publicKey: Buffer): string {
try {
return algosdk.encodeAddress(new Uint8Array(publicKey));
} catch (error) {
console.error('[MCP Error] Failed to encode address:', error);
throw new McpError(
ErrorCode.InvalidParams,
`Invalid public key: ${error instanceof Error ? error.message : 'Unknown error'}`
);
}
}
/**
* Decodes an Algorand address to a public key
* @param address The address to decode
* @returns The decoded public key
*/
static decodeAddress(address: string): Uint8Array {
try {
return algosdk.decodeAddress(address).publicKey;
} catch (error) {
console.error('[MCP Error] Failed to decode address:', error);
throw new McpError(
ErrorCode.InvalidParams,
`Invalid address: ${error instanceof Error ? error.message : 'Unknown error'}`
);
}
}
/**
* Gets the application address for a given application ID
* @param appId The application ID
* @returns The application address
*/
static getApplicationAddress(appId: number): string {
try {
return algosdk.getApplicationAddress(appId);
} catch (error) {
console.error('[MCP Error] Failed to get application address:', error);
throw new McpError(
ErrorCode.InvalidParams,
`Invalid application ID: ${error instanceof Error ? error.message : 'Unknown error'}`
);
}
}
/**
* Converts bytes to a BigInt
* @param bytes The bytes to convert
* @returns The BigInt value
*/
static bytesToBigInt(bytes: Uint8Array): bigint {
try {
return BigInt('0x' + Buffer.from(bytes).toString('hex'));
} catch (error) {
console.error('[MCP Error] Failed to convert bytes to BigInt:', error);
throw new McpError(
ErrorCode.InvalidParams,
`Invalid bytes format: ${error instanceof Error ? error.message : 'Unknown error'}`
);
}
}
/**
* Converts a BigInt to bytes
* @param value The BigInt value to convert
* @param size The size of the resulting byte array
* @returns The bytes representation
*/
static bigIntToBytes(value: bigint, size: number): Uint8Array {
try {
const hex = value.toString(16).padStart(size * 2, '0');
return Buffer.from(hex, 'hex');
} catch (error) {
console.error('[MCP Error] Failed to convert BigInt to bytes:', error);
throw new McpError(
ErrorCode.InvalidParams,
`Invalid BigInt value or size: ${error instanceof Error ? error.message : 'Unknown error'}`
);
}
}
/**
* Encodes a uint64 to bytes
* @param value The uint64 value to encode
* @returns The encoded bytes
*/
static encodeUint64(value: bigint): Uint8Array {
try {
return this.bigIntToBytes(value, 8);
} catch (error) {
console.error('[MCP Error] Failed to encode uint64:', error);
throw new McpError(
ErrorCode.InvalidParams,
`Invalid uint64 value: ${error instanceof Error ? error.message : 'Unknown error'}`
);
}
}
/**
* Decodes bytes to a uint64
* @param bytes The bytes to decode
* @returns The decoded uint64 value
*/
static decodeUint64(bytes: Uint8Array): bigint {
try {
return this.bytesToBigInt(bytes);
} catch (error) {
console.error('[MCP Error] Failed to decode uint64:', error);
throw new McpError(
ErrorCode.InvalidParams,
`Invalid uint64 bytes: ${error instanceof Error ? error.message : 'Unknown error'}`
);
}
}
/**
* Verifies a signature against bytes with a public key
* @param bytes The bytes that were signed
* @param signature The signature to verify
* @param address The Algorand address of the signer
* @returns True if the signature is valid
*/
static verifyBytes(bytes: Uint8Array, signature: Uint8Array, address: string): boolean {
console.log('Verifying bytes:', {
bytes: Buffer.from(bytes).toString('hex'),
signature: Buffer.from(signature).toString('base64'),
address,
});
try {
const mxBytes = new TextEncoder().encode("MX");
const fullBytes = new Uint8Array(mxBytes.length + bytes.length);
fullBytes.set(mxBytes);
fullBytes.set(bytes, mxBytes.length);
// Convert back to hex
let pk = algosdk.decodeAddress(address).publicKey;
let verify_nacl = nacl.sign.detached.verify(fullBytes, signature, pk)
//return algosdk.verifyBytes(bytes, signature, address);
return verify_nacl
} catch (error) {
console.error('[MCP Error] Failed to verify bytes:', error);
throw new McpError(
ErrorCode.InvalidParams,
`Failed to verify: ${error instanceof Error ? error.message : 'Unknown error'}`
);
}
}
}
```
--------------------------------------------------------------------------------
/packages/server/src/resources/knowledge/taxonomy/algokit:utils:typescript:code:classes:types_app_deployer.AppDeployer.md:
--------------------------------------------------------------------------------
```markdown
[@algorandfoundation/algokit-utils](../README.md) / [types/app-deployer](../modules/types_app_deployer.md) / AppDeployer
# Class: AppDeployer
[types/app-deployer](../modules/types_app_deployer.md).AppDeployer
Allows management of deployment and deployment metadata of applications.
## Table of contents
### Constructors
- [constructor](types_app_deployer.AppDeployer.md#constructor)
### Properties
- [\_appLookups](types_app_deployer.AppDeployer.md#_applookups)
- [\_appManager](types_app_deployer.AppDeployer.md#_appmanager)
- [\_indexer](types_app_deployer.AppDeployer.md#_indexer)
- [\_transactionSender](types_app_deployer.AppDeployer.md#_transactionsender)
### Methods
- [deploy](types_app_deployer.AppDeployer.md#deploy)
- [getCreatorAppsByName](types_app_deployer.AppDeployer.md#getcreatorappsbyname)
- [updateAppLookup](types_app_deployer.AppDeployer.md#updateapplookup)
## Constructors
### constructor
• **new AppDeployer**(`appManager`, `transactionSender`, `indexer?`): [`AppDeployer`](types_app_deployer.AppDeployer.md)
Creates an `AppManager`
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `appManager` | [`AppManager`](types_app_manager.AppManager.md) | An `AppManager` instance |
| `transactionSender` | [`AlgorandClientTransactionSender`](types_algorand_client_transaction_sender.AlgorandClientTransactionSender.md) | An `AlgorandClientTransactionSender` instance |
| `indexer?` | `IndexerClient` | An optional indexer instance; supply if you want to indexer to look up app metadata |
#### Returns
[`AppDeployer`](types_app_deployer.AppDeployer.md)
#### Defined in
[src/types/app-deployer.ts:123](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/types/app-deployer.ts#L123)
## Properties
### \_appLookups
• `Private` **\_appLookups**: `Map`\<`string`, [`AppLookup`](../interfaces/types_app_deployer.AppLookup.md)\>
#### Defined in
[src/types/app-deployer.ts:115](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/types/app-deployer.ts#L115)
___
### \_appManager
• `Private` **\_appManager**: [`AppManager`](types_app_manager.AppManager.md)
#### Defined in
[src/types/app-deployer.ts:112](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/types/app-deployer.ts#L112)
___
### \_indexer
• `Private` `Optional` **\_indexer**: `IndexerClient`
#### Defined in
[src/types/app-deployer.ts:114](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/types/app-deployer.ts#L114)
___
### \_transactionSender
• `Private` **\_transactionSender**: [`AlgorandClientTransactionSender`](types_algorand_client_transaction_sender.AlgorandClientTransactionSender.md)
#### Defined in
[src/types/app-deployer.ts:113](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/types/app-deployer.ts#L113)
## Methods
### deploy
▸ **deploy**(`deployment`): `Promise`\<[`AppDeployResult`](../modules/types_app_deployer.md#appdeployresult)\>
Idempotently deploy (create if not exists, update if changed) an app against the given name for the given creator account, including deploy-time TEAL template placeholder substitutions (if specified).
To understand the architecture decisions behind this functionality please see https://github.com/algorandfoundation/algokit-cli/blob/main/docs/architecture-decisions/2023-01-12_smart-contract-deployment.md
**Note:** When using the return from this function be sure to check `operationPerformed` to get access to various return properties like `transaction`, `confirmation` and `deleteResult`.
**Note:** if there is a breaking state schema change to an existing app (and `onSchemaBreak` is set to `'replace'`) the existing app will be deleted and re-created.
**Note:** if there is an update (different TEAL code) to an existing app (and `onUpdate` is set to `'replace'`) the existing app will be deleted and re-created.
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `deployment` | `Object` | The arguments to control the app deployment |
| `deployment.createParams` | \{ `accountReferences?`: (`string` \| `Address`)[] ; `appReferences?`: `bigint`[] ; `approvalProgram`: `string` \| `Uint8Array` ; `args?`: `Uint8Array`[] ; `assetReferences?`: `bigint`[] ; `boxReferences?`: ([`BoxIdentifier`](../modules/types_app_manager.md#boxidentifier) \| [`BoxReference`](../interfaces/types_app_manager.BoxReference.md))[] ; `clearStateProgram`: `string` \| `Uint8Array` ; `extraFee?`: [`AlgoAmount`](types_amount.AlgoAmount.md) ; `extraProgramPages?`: `number` ; `firstValidRound?`: `bigint` ; `lastValidRound?`: `bigint` ; `lease?`: `string` \| `Uint8Array` ; `maxFee?`: [`AlgoAmount`](types_amount.AlgoAmount.md) ; `note?`: `string` \| `Uint8Array` ; `onComplete?`: `NoOpOC` \| `OptInOC` \| `CloseOutOC` \| `UpdateApplicationOC` \| `DeleteApplicationOC` ; `rekeyTo?`: `string` \| `Address` ; `schema?`: \{ `globalByteSlices`: `number` ; `globalInts`: `number` ; `localByteSlices`: `number` ; `localInts`: `number` } ; `sender`: `string` \| `Address` ; `signer?`: `TransactionSigner` \| [`TransactionSignerAccount`](../interfaces/types_account.TransactionSignerAccount.md) ; `staticFee?`: [`AlgoAmount`](types_amount.AlgoAmount.md) ; `validityWindow?`: `number` \| `bigint` } \| [`AppCreateMethodCall`](../modules/types_composer.md#appcreatemethodcall) | Create transaction parameters to use if a create needs to be issued as part of deployment |
| `deployment.deleteParams` | \{ `accountReferences?`: (`string` \| `Address`)[] ; `appReferences?`: `bigint`[] ; `args?`: `Uint8Array`[] ; `assetReferences?`: `bigint`[] ; `boxReferences?`: ([`BoxIdentifier`](../modules/types_app_manager.md#boxidentifier) \| [`BoxReference`](../interfaces/types_app_manager.BoxReference.md))[] ; `extraFee?`: [`AlgoAmount`](types_amount.AlgoAmount.md) ; `firstValidRound?`: `bigint` ; `lastValidRound?`: `bigint` ; `lease?`: `string` \| `Uint8Array` ; `maxFee?`: [`AlgoAmount`](types_amount.AlgoAmount.md) ; `note?`: `string` \| `Uint8Array` ; `onComplete?`: `DeleteApplicationOC` ; `rekeyTo?`: `string` \| `Address` ; `sender`: `string` \| `Address` ; `signer?`: `TransactionSigner` \| [`TransactionSignerAccount`](../interfaces/types_account.TransactionSignerAccount.md) ; `staticFee?`: [`AlgoAmount`](types_amount.AlgoAmount.md) ; `validityWindow?`: `number` \| `bigint` } \| \{ `accountReferences?`: (`string` \| `Address`)[] ; `appReferences?`: `bigint`[] ; `args?`: (`undefined` \| `Transaction` \| `ABIValue` \| `TransactionWithSigner` \| `Promise`\<`Transaction`\> \| [`AppMethodCall`](../modules/types_composer.md#appmethodcall)\<\{ `accountReferences?`: (... \| ...)[] ; `appReferences?`: `bigint`[] ; `approvalProgram`: `string` \| `Uint8Array` ; `args?`: `Uint8Array`[] ; `assetReferences?`: `bigint`[] ; `boxReferences?`: BoxIdentifier \| BoxReference[] ; `clearStateProgram`: `string` \| `Uint8Array` ; `extraFee?`: [`AlgoAmount`](types_amount.AlgoAmount.md) ; `extraProgramPages?`: `number` ; `firstValidRound?`: `bigint` ; `lastValidRound?`: `bigint` ; `lease?`: `string` \| `Uint8Array` ; `maxFee?`: [`AlgoAmount`](types_amount.AlgoAmount.md) ; `note?`: `string` \| `Uint8Array` ; `onComplete?`: `NoOpOC` \| `OptInOC` \| `CloseOutOC` \| `UpdateApplicationOC` \| `DeleteApplicationOC` ; `rekeyTo?`: `string` \| `Address` ; `schema?`: \{ `globalByteSlices`: `number` ; `globalInts`: `number` ; `localByteSlices`: `number` ; `localInts`: `number` } ; `sender`: `string` \| `Address` ; `signer?`: `TransactionSigner` \| [`TransactionSignerAccount`](../interfaces/types_account.TransactionSignerAccount.md) ; `staticFee?`: [`AlgoAmount`](types_amount.AlgoAmount.md) ; `validityWindow?`: `number` \| `bigint` }\> \| [`AppMethodCall`](../modules/types_composer.md#appmethodcall)\<\{ `accountReferences?`: (... \| ...)[] ; `appId`: `bigint` ; `appReferences?`: `bigint`[] ; `approvalProgram`: `string` \| `Uint8Array` ; `args?`: `Uint8Array`[] ; `assetReferences?`: `bigint`[] ; `boxReferences?`: BoxIdentifier \| BoxReference[] ; `clearStateProgram`: `string` \| `Uint8Array` ; `extraFee?`: [`AlgoAmount`](types_amount.AlgoAmount.md) ; `firstValidRound?`: `bigint` ; `lastValidRound?`: `bigint` ; `lease?`: `string` \| `Uint8Array` ; `maxFee?`: [`AlgoAmount`](types_amount.AlgoAmount.md) ; `note?`: `string` \| `Uint8Array` ; `onComplete?`: `UpdateApplicationOC` ; `rekeyTo?`: `string` \| `Address` ; `sender`: `string` \| `Address` ; `signer?`: `TransactionSigner` \| [`TransactionSignerAccount`](../interfaces/types_account.TransactionSignerAccount.md) ; `staticFee?`: [`AlgoAmount`](types_amount.AlgoAmount.md) ; `validityWindow?`: `number` \| `bigint` }\> \| [`AppMethodCall`](../modules/types_composer.md#appmethodcall)\<[`AppMethodCallParams`](../modules/types_composer.md#appmethodcallparams)\>)[] ; `assetReferences?`: `bigint`[] ; `boxReferences?`: ([`BoxIdentifier`](../modules/types_app_manager.md#boxidentifier) \| [`BoxReference`](../interfaces/types_app_manager.BoxReference.md))[] ; `extraFee?`: [`AlgoAmount`](types_amount.AlgoAmount.md) ; `firstValidRound?`: `bigint` ; `lastValidRound?`: `bigint` ; `lease?`: `string` \| `Uint8Array` ; `maxFee?`: [`AlgoAmount`](types_amount.AlgoAmount.md) ; `method`: `ABIMethod` ; `note?`: `string` \| `Uint8Array` ; `onComplete?`: `DeleteApplicationOC` ; `rekeyTo?`: `string` \| `Address` ; `sender`: `string` \| `Address` ; `signer?`: `TransactionSigner` \| [`TransactionSignerAccount`](../interfaces/types_account.TransactionSignerAccount.md) ; `staticFee?`: [`AlgoAmount`](types_amount.AlgoAmount.md) ; `validityWindow?`: `number` \| `bigint` } | Delete transaction parameters to use if a delete needs to be issued as part of deployment |
| `deployment.deployTimeParams?` | [`TealTemplateParams`](../interfaces/types_app.TealTemplateParams.md) | Any deploy-time parameters to replace in the TEAL code before compiling it (used if teal code is passed in as a string) |
| `deployment.existingDeployments?` | [`AppLookup`](../interfaces/types_app_deployer.AppLookup.md) | Optional cached value of the existing apps for the given creator; use this to avoid an indexer lookup |
| `deployment.ignoreCache?` | `boolean` | Whether or not to ignore the app metadata cache and force a lookup, default: use the cache * |
| `deployment.maxRoundsToWaitForConfirmation?` | `number` | The number of rounds to wait for confirmation. By default until the latest lastValid has past. |
| `deployment.metadata` | [`AppDeployMetadata`](../interfaces/types_app.AppDeployMetadata.md) | The deployment metadata |
| `deployment.onSchemaBreak?` | [`OnSchemaBreak`](../enums/types_app.OnSchemaBreak.md) \| ``"replace"`` \| ``"fail"`` \| ``"append"`` | What action to perform if a schema break (storage schema or extra pages change) is detected: * `fail` - Fail the deployment (throw an error, **default**) * `replace` - Delete the old app and create a new one * `append` - Deploy a new app and leave the old one as is |
| `deployment.onUpdate?` | ``"replace"`` \| ``"fail"`` \| ``"append"`` \| [`OnUpdate`](../enums/types_app.OnUpdate.md) \| ``"update"`` | What action to perform if a TEAL code update is detected: * `fail` - Fail the deployment (throw an error, **default**) * `update` - Update the app with the new TEAL code * `replace` - Delete the old app and create a new one * `append` - Deploy a new app and leave the old one as is |
| `deployment.populateAppCallResources?` | `boolean` | Whether to use simulate to automatically populate app call resources in the txn objects. Defaults to `Config.populateAppCallResources`. |
| `deployment.suppressLog?` | `boolean` | Whether to suppress log messages from transaction send, default: do not suppress. |
| `deployment.updateParams` | \{ `accountReferences?`: (`string` \| `Address`)[] ; `appReferences?`: `bigint`[] ; `args?`: `Uint8Array`[] ; `assetReferences?`: `bigint`[] ; `boxReferences?`: ([`BoxIdentifier`](../modules/types_app_manager.md#boxidentifier) \| [`BoxReference`](../interfaces/types_app_manager.BoxReference.md))[] ; `extraFee?`: [`AlgoAmount`](types_amount.AlgoAmount.md) ; `firstValidRound?`: `bigint` ; `lastValidRound?`: `bigint` ; `lease?`: `string` \| `Uint8Array` ; `maxFee?`: [`AlgoAmount`](types_amount.AlgoAmount.md) ; `note?`: `string` \| `Uint8Array` ; `onComplete?`: `UpdateApplicationOC` ; `rekeyTo?`: `string` \| `Address` ; `sender`: `string` \| `Address` ; `signer?`: `TransactionSigner` \| [`TransactionSignerAccount`](../interfaces/types_account.TransactionSignerAccount.md) ; `staticFee?`: [`AlgoAmount`](types_amount.AlgoAmount.md) ; `validityWindow?`: `number` \| `bigint` } \| \{ `accountReferences?`: (`string` \| `Address`)[] ; `appReferences?`: `bigint`[] ; `args?`: (`undefined` \| `Transaction` \| `ABIValue` \| `TransactionWithSigner` \| `Promise`\<`Transaction`\> \| [`AppMethodCall`](../modules/types_composer.md#appmethodcall)\<\{ `accountReferences?`: (... \| ...)[] ; `appReferences?`: `bigint`[] ; `approvalProgram`: `string` \| `Uint8Array` ; `args?`: `Uint8Array`[] ; `assetReferences?`: `bigint`[] ; `boxReferences?`: BoxIdentifier \| BoxReference[] ; `clearStateProgram`: `string` \| `Uint8Array` ; `extraFee?`: [`AlgoAmount`](types_amount.AlgoAmount.md) ; `extraProgramPages?`: `number` ; `firstValidRound?`: `bigint` ; `lastValidRound?`: `bigint` ; `lease?`: `string` \| `Uint8Array` ; `maxFee?`: [`AlgoAmount`](types_amount.AlgoAmount.md) ; `note?`: `string` \| `Uint8Array` ; `onComplete?`: `NoOpOC` \| `OptInOC` \| `CloseOutOC` \| `UpdateApplicationOC` \| `DeleteApplicationOC` ; `rekeyTo?`: `string` \| `Address` ; `schema?`: \{ `globalByteSlices`: `number` ; `globalInts`: `number` ; `localByteSlices`: `number` ; `localInts`: `number` } ; `sender`: `string` \| `Address` ; `signer?`: `TransactionSigner` \| [`TransactionSignerAccount`](../interfaces/types_account.TransactionSignerAccount.md) ; `staticFee?`: [`AlgoAmount`](types_amount.AlgoAmount.md) ; `validityWindow?`: `number` \| `bigint` }\> \| [`AppMethodCall`](../modules/types_composer.md#appmethodcall)\<\{ `accountReferences?`: (... \| ...)[] ; `appId`: `bigint` ; `appReferences?`: `bigint`[] ; `approvalProgram`: `string` \| `Uint8Array` ; `args?`: `Uint8Array`[] ; `assetReferences?`: `bigint`[] ; `boxReferences?`: BoxIdentifier \| BoxReference[] ; `clearStateProgram`: `string` \| `Uint8Array` ; `extraFee?`: [`AlgoAmount`](types_amount.AlgoAmount.md) ; `firstValidRound?`: `bigint` ; `lastValidRound?`: `bigint` ; `lease?`: `string` \| `Uint8Array` ; `maxFee?`: [`AlgoAmount`](types_amount.AlgoAmount.md) ; `note?`: `string` \| `Uint8Array` ; `onComplete?`: `UpdateApplicationOC` ; `rekeyTo?`: `string` \| `Address` ; `sender`: `string` \| `Address` ; `signer?`: `TransactionSigner` \| [`TransactionSignerAccount`](../interfaces/types_account.TransactionSignerAccount.md) ; `staticFee?`: [`AlgoAmount`](types_amount.AlgoAmount.md) ; `validityWindow?`: `number` \| `bigint` }\> \| [`AppMethodCall`](../modules/types_composer.md#appmethodcall)\<[`AppMethodCallParams`](../modules/types_composer.md#appmethodcallparams)\>)[] ; `assetReferences?`: `bigint`[] ; `boxReferences?`: ([`BoxIdentifier`](../modules/types_app_manager.md#boxidentifier) \| [`BoxReference`](../interfaces/types_app_manager.BoxReference.md))[] ; `extraFee?`: [`AlgoAmount`](types_amount.AlgoAmount.md) ; `firstValidRound?`: `bigint` ; `lastValidRound?`: `bigint` ; `lease?`: `string` \| `Uint8Array` ; `maxFee?`: [`AlgoAmount`](types_amount.AlgoAmount.md) ; `method`: `ABIMethod` ; `note?`: `string` \| `Uint8Array` ; `onComplete?`: `UpdateApplicationOC` ; `rekeyTo?`: `string` \| `Address` ; `sender`: `string` \| `Address` ; `signer?`: `TransactionSigner` \| [`TransactionSignerAccount`](../interfaces/types_account.TransactionSignerAccount.md) ; `staticFee?`: [`AlgoAmount`](types_amount.AlgoAmount.md) ; `validityWindow?`: `number` \| `bigint` } | Update transaction parameters to use if an update needs to be issued as part of deployment |
#### Returns
`Promise`\<[`AppDeployResult`](../modules/types_app_deployer.md#appdeployresult)\>
The app reference of the new/existing app
#### Defined in
[src/types/app-deployer.ts:142](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/types/app-deployer.ts#L142)
___
### getCreatorAppsByName
▸ **getCreatorAppsByName**(`creatorAddress`, `ignoreCache?`): `Promise`\<[`AppLookup`](../interfaces/types_app_deployer.AppLookup.md)\>
Returns a lookup of name => app metadata (id, address, ...metadata) for all apps created by the given account that have
an [ARC-2](https://github.com/algorandfoundation/ARCs/blob/main/ARCs/arc-0002.md) `AppDeployNote` as the transaction
note of the app creation transaction.
This function caches the result for the given creator account so that subsequent calls will not require an indexer lookup.
If the `AppManager` instance wasn't created with an indexer client, this function will throw an error.
#### Parameters
| Name | Type | Description |
| :------ | :------ | :------ |
| `creatorAddress` | `string` \| `Address` | The address of the account that is the creator of the apps you want to search for |
| `ignoreCache?` | `boolean` | Whether or not to ignore the cache and force a lookup, default: use the cache |
#### Returns
`Promise`\<[`AppLookup`](../interfaces/types_app_deployer.AppLookup.md)\>
A name-based lookup of the app metadata
#### Defined in
[src/types/app-deployer.ts:456](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/types/app-deployer.ts#L456)
___
### updateAppLookup
▸ **updateAppLookup**(`sender`, `appMetadata`): `void`
#### Parameters
| Name | Type |
| :------ | :------ |
| `sender` | `string` \| `Address` |
| `appMetadata` | [`AppMetadata`](../interfaces/types_app_deployer.AppMetadata.md) |
#### Returns
`void`
#### Defined in
[src/types/app-deployer.ts:433](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/types/app-deployer.ts#L433)
```
--------------------------------------------------------------------------------
/packages/server/src/resources/knowledge/taxonomy/algokit:cli:architecture-decisions:2023-06-06_frontend-templates.md:
--------------------------------------------------------------------------------
```markdown
# Frontend Templates
- **Status**: Approved
- **Owner:** Altynbek Orumbayev
- **Deciders**: Rob Moore, Daniel McGregor, Adam Chidlow
- **Date created**: 2023-06-06
- **Date decided:** 2023-06-09
- **Date updated**: 2023-06-08
## Context
AlgoKit v2 aims provide an end-to-end development and deployment experience that includes support for the end-to-end smart contract and dApp development lifecycle. With the release of the typed clients feature - developers are now able to reduce the time it takes to fully integrate the interactions between the contract and the frontend components powering the end-to-end dapp user experience. Hence, as a logical continuation, the following Architecture Decision Record aims to expand on the current capabilities of AlgoKit to support the `frontend` templates, an [AlgoKit Principles](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/algokit.md#guiding-principles) compliant approach towards simplifying integrations of smart contracts with the dApp frontend components.
## Requirements
### Independent Frontend Templates
1. Create official frontend template that complies with AlgoKit's principles of modularity, maintainability, and flexibility while also serving as a reference for template builders.
2. Expand algokit functionality to provide a clear process for developers to link frontend templates with the typed clients generated by backend templates.
3. Design frontend templates such that backend and frontend have no dependencies on each other, ensuring high modularity.
### End-to-End Starter Repositories
1. Establish a starter repository that allows developers to bootstrap end-to-end dApp projects within a single command, while also serving as an example for template builders on how to efficiently couple their backend and frontend templates.
2. Implement a bundling process for backend and frontend templates in the starter repositories that reduce code duplication and maintenance overhead.
3. Develop deployment pipelines for frontend components inside end-to-end starter repository that supports TestNet, and MainNet deployments to hosting providers of choice (Netlify, Vercel and etc to be decided).
4. Ensure that the end-to-end starter repository supports both manual deployment and deployment via a continuous deployment pipeline.
## Principles
- **Modularity**: The dApp templating feature should follow guiding AlgoKit principles and expand on approaches already utilized in existing smart contract templates feature. This implies that giving developers flexibility to mix and match different `smart contract` templates with `frontend` templates should serve as key consideration.
- **Maintainability**: The dApp templating feature should be easy to maintain and extend. This implies that the feature should be implemented in a way that allows for easy addition of new templates and/or modification of existing ones as the complexity and variety of templates scale.
- **Seamless onramp**: The dApp templating feature should provide a seamless onramp for developers to get started with dApp development. This implies that the feature should provide a simple and intuitive way to get started with dApp development and deployment. Providing developers a choice on whether they want more flexibility or rely on default recommended practices.
All of the aforementioned requirements should be met in a way that is consistent with the guiding principles of AlgoKit or attempt to find a balanced trade of between the principles that satisfies the requirements. Refer to [AlgoKit Guiding Principles](../../docs/algokit.md#Guiding-Principles) for detailed reference on the principles.
## Explored options
Enhancing AlgoKit's templating capabilities involves a notable shift from managing individual templates to co-locating multiple templates or projects together. This is a marked increase in complexity that requires careful consideration of the varying trade-offs between different approaches. The subsequent sections explore these options and their associated trade-offs, providing a concise overview of this new challenge and our proposed solutions.
### Option 1: Monolithic template
This option suggests that the frontend and backend templates should be bundled together in a single repository. This approach aims to simplify the maintenance of the templates by reducing the number of repositories that need to be maintained. Both official and community templates should be build on top of this approach where frontend is always tailored for specific needs of the smart contracts that are being used.
Drawbacks:
- **Lack of flexibility**: The monorepo approach does not allow developers to choose their preferred frontend technology stack. This is because the frontend is tightly coupled with the backend and the two cannot be separated. This is a major drawback as it limits the flexibility of the templates and does not allow developers to choose their preferred frontend technology stack.
- **Increased maintenance overhead**: Despite monorepos generally being easier to maintain and collaborate on, this approach has risks of increasing the maintenance overhead as it forces for code duplication when creating new template variations.
### Option 2: Separate individual frontend templates and official full-stack starter templates as an end-to-end reference
This option suggests that the frontend and backend templates should be maintained in separate repositories. This approach aims to provide developers with the flexibility to choose their preferred frontend technology stack. It also allows the templates to be maintained independently, thereby reducing the maintenance overhead.
Drawbacks:
- **Compatibility overhead**: The separate repositories approach increases the maintenance overhead as it requires the templates to be updated independently. This can lead to issues with compatibility between the templates and the typed clients.
- **Lack of guidance**: The separate repositories approach does not provide developers with a clear process for linking the frontend templates with the typed clients generated by the backend templates. This can lead to confusion and issues with the integration of the templates.
The outlined drawbacks can be mitigated by providing a clear process or reference for template builders on how to link various combinations of frontend and backend templates. The compatibility overhead can be mitigated by ensuring that backend and frontend modules are self sufficient and completely decoupled from each other. This will ensure that the templates can be updated independently. The implementation proposal below is a detailed exploration of this approach and ways to mitigate the drawbacks.
### Implementation proposal for Option 2
The proposal consists of 2 main parts. On a high level, the ideas revolve around giving developers a choice on how they want to couple AlgoKit backend and frontend templates if they like to use custom templates. The other is focused on providing an official full-stack template that bundles both backend and frontend templates together, while also serving as an example for template builders on how to efficiently couple any combination of templates.
The addendums to the proposal also explores orthogonal ideas that can further improve the CLI tooling itself by providing a way for any existing non web-3 frontend project be converted into a full-stack dApp with minimal efforts. Lastly, it expands on improving incentives for developers to build and maintain their own templates.
---
### Part 1. Independent frontend templates
> TLDR: Independent frontend templates will be created to provide developers with a highly customizable dApp starter project, built on AlgoKit's principles of modularity, maintainability, and flexibility. The templates will also serve as a reference for template builders.
The following aims to provide a seamless onramp for developers to get started with highly customizable dApp starter projects. The idea is to create a set of separate official frontend template repositories to serve as:
a) A reference for template builders on how to create standalone frontend templates that can be then further coupled with any backend template.
b) Expand on AlgoKit principles of modularity, maintainability and flexibility by giving developers a choice of preferred technological stack.
The official standalone frontend templates can be build by reusing already established best practices and templates from official backend repositories and by continuing reliance on `copier` for template automation. Another important consideration to keep in mind is that with the introduction of frontend templates we need to establish a clear separation of concerns between the backend and frontend templates to ensure modularity.

As demonstrated on the diagram above, the only glue connecting the backend and frontend is the generated typed client. Neither backend or frontend templates should be concerned with the other but instead provide modular interfaces that clearly indicate to developers on how to integrate the two. From a perspective of a backend template, the typed client shall be seen as a static asset that can be reused by any frontend template. Frontend templates on the other hand are mostly standard web projects with an additional layer of utilities that optionally allow them to be integrated with typed clients produced by backend templates.
#### Higher level overview
The main scenario to support for this part is to allow developers to use official starter templates to bootstrap end to end dApp projects.

As demonstrated above the dev experience will consist of executing an `algokit init` command for the preferred backends and frontends.
It gives user a choice and responsibility to then decide how to integrate the two components depending on their project needs. To improve this however, we should **additionally introduce a new utility** that will serve as a tool to automate linking with the typed client that backend templates will be generating. Implementation specific details can be discussed separately is it goes out of scope of this Architecture Decision Record.
---
### Part 2. End-to-end starter repositories
> TLDR: End-to-end starter repositories are designed to offer developers an official starter template for bootstrapping dApp projects. This is achieved by efficiently bundling backend and frontend templates to facilitate easy maintenance and smooth onboarding.
#### Higher level overview
The main scenario to support for this part is to allow developers to use official starter templates to bootstrap end to end dApp projects.

As demonstrated above the user experience will consist of a single execution of `algokit init` command pointed at official full-stack template repository. The full stack templates are responsible for bundling both backend and frontend templates together and providing a seamless onramp for developers to get started with dApp development. The way repositories are bundled should be easy to maintain and should not duplicate individual backend and frontend repositories to avoid redundant maintenance, instead it should expand on metatemplating capabilities of `copier` to allow for efficient reuse of existing standalone backend/frontend templates.
### Addendum 1. Converting _ANY_ frontend projects into dApps.
> TLDR: The approach aims to enhance the algokit-cli codebase's adaptability, enabling easy transformation of existing frontend projects into web3 dApps.
This orthogonal approach proposes to improve capabilities of the algokit-cli codebase by making it adaptable to various frontend stacks to allow anyone to easily convert their existing frontend projects into web3 dApps.
The implementation specific details will consist of deriving a set of bare minimum requirements for such feature to scan and understand the structure of frontend where algokit is being embedded and performing necessary modifications to project's files. A detailed discussion can be held in a scope separate from this Architecture Decision Record.
> This approach can be explored and maintained without overlapping with main proposal on frontend templates.
### Addendum 2. Website for choosing preferred frontend and backend repositories.
> TLDR: The approach proposes a website to enhance the discoverability of official and community-based algokit templates, thereby incentivizing template builders to create and maintain their own templates.
This orthogonal approach proposes to improve discoverability of official and community based algokit templates by providing a simple static website. The website can consist of minimalistic UI components for picking preferred backend, frontend and then a `Generate` button that will output copyable algokit CLI commands to spin up a project with the selected templates.
As a specific example, the website can be hosted on [AwesomeAlgo](https://awesomealgo.com) website, thus ensuring that this is an open-source community maintained entry-point for discovering and using algokit templates. Removing the need and maintenance overhead on our teams to maintain it as official resource.
Lastly, community template builders will get a platform to increase discoverability of their templates and further incentivize them to build and maintain them. While developers using the templates can support creators of templates by donating to their projects (a simple tipping mechanism for Algo and ASAs can be embedded into the website) or by contributing to the templates themselves.
> This approach can be explored and maintained without overlapping with main proposal on frontend templates.
---
## Final decision
After several review rounds team reached a conclusion to expand on [Option 2](#option-2-separate-individual-frontend-templates-and-official-full-stack-starter-templates-as-an-end-to-end-reference) and respective [implementation proposal](#implementation-proposal-for-option-2) given better alignment with AlgoKit design principles such as flexibility and modularity. Hence, the following proposal is further exploration of ideas based on this approach and propose solution to mitigate the potential drawbacks and risks outlined.
## Open questions
- Python typed clients are not going to be too relevant for scenarios where they need to be integrated with frontends given that in majority of cases a developer would prefer a TS typed client. Hence, how do we ensure that user gets a clear information and indication on when to use Python typed clients vs TS typed clients?
- `Answer: This is a fair comment, but to my mind it's a clear dilineation in that it's dependant on what language you are using. While there are Python website libraries, we aren't using them we will use JavaScript (TypeScript).`
- Would we want to introduce a notion of non smart contract based backend templates that can be used to plug in the python typed clients and spin up servers that can be used to build APIs that interact with the smart contracts?
- `Answer: This is definitely out of scope of dApp stuff.`
## Next steps
After the final decision is made, the action items necessary to implement the described proposal can be outlined as follows:
1. **Design and Development of Independent Frontend Template**: This involves selecting appropriate technology stacks and building out the templates. The template should be able to work with the generated typed client from the backend and will be used as a dependency for end-to-end starter repository.
2. **Development of End-to-End Starter Repository**: This involves building comprehensive template that bundles both frontend and backend components. The template should be designed to be easy to maintain and should leverage the metatemplating capabilities of `copier` for efficient reuse of existing standalone templates.
3. **Integration and Testing**: Ensure proper integration between frontend and backend templates. Also, extensive testing should be done to ensure smooth functioning and a seamless onramp experience for the developers.
4. **Documentation**: Write comprehensive documentation covering the use of the new templates, how to integrate them, and the utility for linking them with the typed client. This documentation should also include how-to guides and sample applications to help developers get started.
5. **Addendum 1 - Converting ANY Frontend Projects into dApps**: Start a separate discussion and potentially a project to research the feasibility of this idea. If feasible, design and implement a method that allows developers to convert their existing non-web3 frontend projects into dApps using AlgoKit.
6. **Addendum 2 - Development of Template Selection Website**: Plan and execute the development of a minimalist UI that allows developers to easily discover and select their preferred templates. This should also allow them to easily generate the necessary AlgoKit CLI commands for their project setup.
7. **Community Engagement**: Engage the developer community to drive contributions to the template repositories. This includes encouraging template builders to contribute and supporting developers using the templates with issues and suggestions.
8. **Continuous Review and Maintenance**: Regularly review the templates to ensure they are up to date with changes in technology and AlgoKit principles. Continuous maintenance should also be carried out to ensure the templates remain functional and relevant.
Regarding the open questions, these should be discussed in detail to clarify how to handle Python typed clients and the potential introduction of non-smart contract based backend templates. These discussions may lead to additional actions as required.
```
--------------------------------------------------------------------------------
/packages/server/src/resources/knowledge/taxonomy/algokit:utils:typescript:capabilities:app-deploy.md:
--------------------------------------------------------------------------------
```markdown
# App deployment
AlgoKit contains advanced smart contract deployment capabilities that allow you to have idempotent (safely retryable) deployment of a named app, including deploy-time immutability and permanence control and TEAL template substitution. This allows you to control the smart contract development lifecycle of a single-instance app across multiple environments (e.g. LocalNet, TestNet, MainNet).
It's optional to use this functionality, since you can construct your own deployment logic using create / update / delete calls and your own mechanism to maintaining app metadata (like app IDs etc.), but this capability is an opinionated out-of-the-box solution that takes care of the heavy lifting for you.
App deployment is a higher-order use case capability provided by AlgoKit Utils that builds on top of the core capabilities, particularly [App management](./app.md).
To see some usage examples check out the [automated tests](../../src/app-deploy.spec.ts).
## Smart contract development lifecycle
The design behind the deployment capability is unique. The architecture design behind app deployment is articulated in an [architecture decision record](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/architecture-decisions/2023-01-12_smart-contract-deployment.md). While the implementation will naturally evolve over time and diverge from this record, the principles and design goals behind the design are comprehensively explained.
Namely, it described the concept of a smart contract development lifecycle:
1. Development
1. **Write** smart contracts
2. **Transpile** smart contracts with development-time parameters (code configuration) to TEAL Templates
3. **Verify** the TEAL Templates maintain [output stability](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/articles/output_stability.md) and any other static code quality checks
2. Deployment
1. **Substitute** deploy-time parameters into TEAL Templates to create final TEAL code
2. **Compile** the TEAL to create byte code using algod
3. **Deploy** the byte code to one or more Algorand networks (e.g. LocalNet, TestNet, MainNet) to create Deployed Application(s)
3. Runtime
1. **Validate** the deployed app via automated testing of the smart contracts to provide confidence in their correctness
2. **Call** deployed smart contract with runtime parameters to utilise it

The App deployment capability provided by AlgoKit Utils helps implement **#2 Deployment**.
Furthermore, the implementation contains the following implementation characteristics per the original architecture design:
- Deploy-time parameters can be provided and substituted into a TEAL Template by convention (by replacing `TMPL_{KEY}`)
- Contracts can be built by any smart contract framework that supports [ARC-0032](https://github.com/algorandfoundation/ARCs/pull/150) and [ARC-0004](https://github.com/algorandfoundation/ARCs/blob/main/ARCs/arc-0004.md) ([Beaker](https://beaker.algo.xyz/) or otherwise), which also means the deployment language can be different to the development language e.g. you can deploy a Python smart contract with TypeScript for instance
- There is explicit control of the immutability (updatability / upgradeability) and permanence (deletability) of the smart contract, which can be varied per environment to allow for easier development and testing in non-MainNet environments (by replacing `TMPL_UPDATABLE` and `TMPL_DELETABLE` at deploy-time by convention, if present)
- Contracts are resolvable by a string "name" for a given creator to allow automated determination of whether that contract had been deployed previously or not, but can also be resolved by ID instead
This design allows you to have the same deployment code across environments without having to specify an ID for each environment. This makes it really easy to apply [continuous delivery](https://continuousdelivery.com/) practices to your smart contract deployment and make the deployment process completely automated.
## `AppDeployer`
The [`AppDeployer`](../code/classes/types_app_deployer.AppDeployer.md) is a class that is used to manage app deployments and deployment metadata.
To get an instance of `AppDeployer` you can use either [`AlgorandClient`](./algorand-client.md) via `algorand.appDeployer` or instantiate it directly (passing in an [`AppManager`](./app.md#appmanager), [`AlgorandClientTransactionSender`](./algorand-client.md#sending-a-single-transaction) and optionally an indexer client instance):
```typescript
import { AppDeployer } from '@algorandfoundation/algokit-utils/types/app-deployer'
const appDeployer = new AppDeployer(appManager, transactionSender, indexer)
```
## Deployment metadata
When AlgoKit performs a deployment of an app it creates metadata to describe that deployment and includes this metadata in an [ARC-2](https://github.com/algorandfoundation/ARCs/blob/main/ARCs/arc-0002.md) transaction note on any creation and update transactions.
The deployment metadata is defined in [`AppDeployMetadata`](../code/interfaces/types_app.AppDeployMetadata.md), which is an object with:
- `name: string` - The unique name identifier of the app within the creator account
- `version: string` - The version of app that is / will be deployed; can be an arbitrary string, but we recommend using [semver](https://semver.org/)
- `deletable?: boolean` - Whether or not the app is deletable (`true`) / permanent (`false`) / unspecified (`undefined`)
- `updatable?: boolean` - Whether or not the app is updatable (`true`) / immutable (`false`) / unspecified (`undefined`)
An example of the ARC-2 transaction note that is attached as an app creation / update transaction note to specify this metadata is:
```
ALGOKIT_DEPLOYER:j{name:"MyApp",version:"1.0",updatable:true,deletable:false}
```
## Lookup deployed apps by name
In order to resolve what apps have been previously deployed and their metadata, AlgoKit provides a method that does a series of indexer lookups and returns a map of name to app metadata via `algorand.appDeployer.getCreatorAppsByName(creatorAddress)`.
```typescript
const appLookup = algorand.appDeployer.getCreatorAppsByName('CREATORADDRESS')
const app1Metadata = appLookup['app1']
```
This method caches the result of the lookup, since it's a reasonably heavyweight call (N+1 indexer calls for N deployed apps by the creator). If you want to skip the cache to get a fresh version then you can pass in a second parameter `ignoreCache?: boolean`. This should only be needed if you are performing parallel deployments outside of the current `AppDeployer` instance, since it will keep its cache updated based on its own deployments.
The return type of `getCreatorAppsByName` is [`AppLookup`](../code/interfaces/types_app_deployer.AppLookup.md):
```typescript
export interface AppLookup {
creator: Readonly<string>
apps: {
[name: string]: AppMetadata
}
}
```
The `apps` property contains a lookup by app name that resolves to the current [`AppMetadata`](../code/interfaces/types_app_deployer.AppMetadata.md) value:
```typescript
interface AppMetadata {
/** The id of the app */
appId: bigint
/** The Algorand address of the account associated with the app */
appAddress: string
/** The unique name identifier of the app within the creator account */
name: string
/** The version of app that is / will be deployed */
version: string
/** Whether or not the app is deletable / permanent / unspecified */
deletable?: boolean
/** Whether or not the app is updatable / immutable / unspecified */
updatable?: boolean
/** The round the app was created */
createdRound: bigint
/** The last round that the app was updated */
updatedRound: bigint
/** The metadata when the app was created */
createdMetadata: AppDeployMetadata
/** Whether or not the app is deleted */
deleted: boolean
}
```
An example `AppLookup` might look like this:
```json
{
"creator": "<creator_address>",
"apps": {
"<app_name>": {
/** The id of the app */
"appId": 1,
/** The Algorand address of the account associated with the app */
"appAddress": "<app_account_address>",
/** The unique name identifier of the app within the creator account */
"name": "<app_name>",
/** The version of app that is / will be deployed */
"version": "2.0.0",
/** Whether or not the app is deletable / permanent / unspecified */
"deletable": false,
/** Whether or not the app is updatable / immutable / unspecified */
"updatable": false,
/** The round the app was created */
"createdRound": 1,
/** The last round that the app was updated */
"updatedRound": 2,
/** Whether or not the app is deleted */
"deleted": false,
/** The metadata when the app was created */
"createdMetadata": {
/** The unique name identifier of the app within the creator account */
"name": "<app_name>",
/** The version of app that is / will be deployed */
"version": "1.0.0",
/** Whether or not the app is deletable / permanent / unspecified */
"deletable": true,
/** Whether or not the app is updatable / immutable / unspecified */
"updatable": true
}
}
//...
}
}
```
## Performing a deployment
In order to perform a deployment, AlgoKit provides the `algorand.appDeployer.deploy(deployment)` method.
For example:
```typescript
const deploymentResult = algorand.appDeployer.deploy({
metadata: {
name: 'MyApp',
version: '1.0.0',
deletable: false,
updatable: false,
},
createParams: {
sender: 'CREATORADDRESS',
approvalProgram: approvalTealTemplateOrByteCode,
clearStateProgram: clearStateTealTemplateOrByteCode,
schema: {
globalInts: 1,
globalByteSlices: 2,
localInts: 3,
localByteSlices: 4,
},
// Other parameters if a create call is made...
},
updateParams: {
sender: 'SENDERADDRESS',
// Other parameters if an update call is made...
},
deleteParams: {
sender: 'SENDERADDRESS',
// Other parameters if a delete call is made...
},
deployTimeParams: {
// Key => value of any TEAL template variables to replace before compilation
VALUE: 1,
},
// How to handle a schema break
onSchemaBreak: OnSchemaBreak.Append,
// How to handle a contract code update
onUpdate: OnUpdate.Update,
// Optional execution control parameters
populateAppCallResources: true,
})
```
This method performs an idempotent (safely retryable) deployment. It will detect if the app already exists and if it doesn't it will create it. If the app does already exist then it will:
- Detect if the app has been updated (i.e. the program logic has changed) and either fail, perform an update, deploy a new version or perform a replacement (delete old app and create new app) based on the deployment configuration.
- Detect if the app has a breaking schema change (i.e. more global or local storage is needed than were originally requested) and either fail, deploy a new version or perform a replacement (delete old app and create new app) based on the deployment configuration.
It will automatically [add metadata to the transaction note of the create or update transactions](#deployment-metadata) that indicates the name, version, updatability and deletability of the contract. This metadata works in concert with [`appDeployer.getCreatorAppsByName`](#lookup-deployed-apps-by-name) to allow the app to be reliably retrieved against that creator in it's currently deployed state. It will automatically update it's lookup cache so subsequent calls to `getCreatorAppsByName` or `deploy` will use the latest metadata without needing to call indexer again.
`deploy` also automatically executes [template substitution](#compilation-and-template-substitution) including deploy-time control of permanence and immutability if the requisite template parameters are specified in the provided TEAL template.
### Input parameters
The first parameter `deployment` is an [`AppDeployParams`](../code/interfaces/types_app_deployer.AppDeployParams.md), which is an object with:
- `metadata: AppDeployMetadata` - determines the [deployment metadata](#deployment-metadata) of the deployment
- `createParams: AppCreateParams | AppCreateMethodCall` - the parameters for an [app creation call](./app.md#creation) (raw or ABI method call)
- `updateParams: Omit<AppUpdateParams | AppUpdateMethodCall, 'appId' | 'approvalProgram' | 'clearStateProgram'>` - the parameters for an [app update call](./app.md#updating) (raw or ABI method call) without the `appId`, `approvalProgram` or `clearStateProgram`, since these are calculated by the `deploy` method
- `deleteParams: Omit<AppDeleteParams | AppDeleteMethodCall, 'appId'>` - the parameters for an [app delete call](./app.md#deleting) (raw or ABI method call) without the `appId`, since this is calculated by the `deploy` method
- `deployTimeParams?: TealTemplateParams` - allows automatic substitution of [deploy-time TEAL template variables](#compilation-and-template-substitution)
- [`TealTemplateParams`](../code/interfaces/types_app.TealTemplateParams.md) is a `key => value` object that will result in `TMPL_{key}` being replaced with `value` (where a string or `Uint8Array` will be appropriately encoded as bytes within the TEAL code)
- `onSchemaBreak?: 'replace' | 'fail' | 'append' | OnSchemaBreak` - determines [what should happen](../code/enums/types_app.OnSchemaBreak.md) if a breaking change to the schema is detected (e.g. if you need more global or local state that was previously requested when the contract was originally created)
- `onUpdate?: 'update' | 'replace' | 'fail' | 'append' | OnUpdate` - determines [what should happen](../code/enums/types_app.OnUpdate.md) if an update to the smart contract is detected (e.g. the TEAL code has changed since last deployment)
- `existingDeployments?: AppLookup` - optionally allows the [app lookup retrieval](#lookup-deployed-apps-by-name) to be skipped if it's already been retrieved outside of this `AppDeployer` instance
- `ignoreCache?: boolean` - optionally allows the [lookup cache](#lookup-deployed-apps-by-name) to be ignored and force retrieval of fresh deployment metadata from indexer
- Everything from [`SendParams`](../code/interfaces/types_transaction.SendParams.md) - [transaction execution control parameters](./algorand-client.md#transaction-parameters)
### Idempotency
`deploy` is idempotent which means you can safely call it again multiple times and it will only apply any changes it detects. If you call it again straight after calling it then it will do nothing.
### Compilation and template substitution
When compiling TEAL template code, the capabilities described in the [above design](#design) are present, namely the ability to supply deploy-time parameters and the ability to control immutability and permanence of the smart contract at deploy-time.
In order for a smart contract to opt-in to use this functionality, it must have a TEAL Template that contains the following:
- `TMPL_{key}` - Which can be replaced with a number or a string / byte array which wil be automatically hexadecimal encoded (for any number of `{key}` => `{value}` pairs)
- `TMPL_UPDATABLE` - Which will be replaced with a `1` if an app should be updatable and `0` if it shouldn't (immutable)
- `TMPL_DELETABLE` - Which will be replaced with a `1` if an app should be deletable and `0` if it shouldn't (permanent)
If you are building a smart contract using the production [AlgoKit init templates](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/features/init.md) provide a reference implementation out of the box for the deploy-time immutability and permanence control.
If you passed in a TEAL template for the approvalProgram or clearStateProgram (i.e. a `string` rather than a `Uint8Array`) then `deploy` will return the [compilation result](../code/interfaces/types_app.CompiledTeal.md) of substituting then compiling the TEAL template(s) in the following properties of the return value:
- `compiledApproval?: CompiledTeal`
- `compiledClear?: CompiledTeal`
Template substitution is done by executing `algorand.app.compileTealTemplate(tealTemplateCode, templateParams?, deploymentMetadata?)`, which in turn calls the following in order and returns the compilation result per above (all of which can also be invoked directly):
- `AppManager.stripTealComments(tealCode)` - Strips out any TEAL comments to reduce the payload that is sent to algod and reduce the likelihood of hitting the max payload limit
- `AppManager.replaceTealTemplateParams(tealTemplateCode, templateParams)` - Replaces the `templateParams` by looking for `TMPL_{key}`
- `AppManager.replaceTealTemplateDeployTimeControlParams(tealTemplateCode, deploymentMetadata)` - If `deploymentMetadata` is provided, it allows for deploy-time immutability and permanence control by replacing `TMPL_UPDATABLE` with `deploymentMetadata.updatable` if it's not `undefined` and replacing `TMPL_DELETABLE` with `deploymentMetadata.deletable` if it's not `undefined`
- `algorand.app.compileTeal(tealCode)` - Sends the final TEAL to algod for compilation and returns the result including the source map and caches the compilation result within the `AppManager` instance
### Return value
When `deploy` executes it will return a [comprehensive result](../code/modules/types_app_deployer.md#appdeployresult) object that describes exactly what it did and has comprehensive metadata to describe the end result of the deployed app.
The `deploy` call itself may do one of the following (which you can determine by looking at the `operationPerformed` field on the return value from the function):
- `create` - The smart contract app was created
- `update` - The smart contract app was updated
- `replace` - The smart contract app was deleted and created again (in an atomic transaction)
- `nothing` - Nothing was done since it was detected the existing smart contract app deployment was up to date
As well as the `operationPerformed` parameter and the [optional compilation result](#compilation-and-template-substitution), the return value will have the [`AppMetadata`](../code/interfaces/types_app_deployer.AppMetadata.md) [fields](#deployment-metadata) present.
Based on the value of `operationPerformed` there will be other data available in the return value:
- If `create`, `update` or `replace` then it will have the relevant [`SendAppTransactionResult`](./app.md#calling-an-app) values
- If `replace` then it will also have `{deleteReturn?: ABIReturn, deleteResult: ConfirmedTransactionResult}` to capture the [result](./algorand-client.md#sending-a-single-transaction) of the deletion of the existing app
```
--------------------------------------------------------------------------------
/packages/server/src/resources/knowledge/taxonomy/developer:docs:details:transactions:signatures.md:
--------------------------------------------------------------------------------
```markdown
title: Signatures
In the [Transactions Section](../../transactions), you learned how transactions are composed. In this section you will learn how to authorize them.
Before a transaction is sent to the network, it must first be authorized by the [sender](../../transactions/#transaction-walkthroughs). Authorization occurs through the addition of a **signature** to the transaction object. Specifically, a transaction object, when signed, is wrapped in a [`SignedTxn`](../../transactions/transactions#signed-transaction) object that includes the [transaction](../../transactions/transactions#txn) and a type of [signature](../../transactions/transactions#sig).
There are three types of signatures:
- [Single Signatures](#single-signatures)
- [Multisignatures](#multisignatures)
- [Logic Signatures](#logic-signatures)
# Single Signatures
A single signature corresponds to a signature from the private key of an [Algorand public/private key pair](../../accounts#keys-and-addresses).
This is an example of a transaction signed by an Algorand private key displayed with `goal clerk inspect` command:
```json
{
"sig": "ynA5Hmq+qtMhRVx63pTO2RpDrYiY1wzF/9Rnnlms6NvEQ1ezJI/Ir9nPAT6+u+K8BQ32pplVrj5NTEMZQqy9Dw==",
"txn": {
"amt": 10000000,
"fee": 1000,
"fv": 4694301,
"gen": "testnet-v1.0",
"gh": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
"lv": 4695301,
"rcv": "QC7XT7QU7X6IHNRJZBR67RBMKCAPH67PCSX4LYH4QKVSQ7DQZ32PG5HSVQ",
"snd": "EW64GC6F24M7NDSC5R3ES4YUVE3ZXXNMARJHDCCCLIHZU6TBEOC7XRSBG4",
"type": "pay"
}
}
```
This transaction sends 10 Algo from `"EW64GC..."` to `"QC7XT7..."` on TestNet. The transaction was signed with the private key that corresponds to the `"snd"` address of `"EW64GC..."`. The base64 encoded signature is shown as the value of the [`"sig"`](./transactions.md#sig) field.
# Multisignatures
When the [sender](../../transactions/transactions#sender) of a transaction is the address of a [multisignature account](../../accounts/create#multisignature) then authorization requires a subset of signatures, _equal to or greater than the threshold value_, from the associated private keys of the addresses that multisignature account is composed of. See [Multisignature Accounts](../../accounts/create#multisignature) for details on how to configure a multisignature account.
!!! important
Upon signing, either the signing agent or the transaction needs to know the composition of the multisignature account, i.e. the ordered addresses, threshold, and version.
Here is what the same transaction above would look like if sent from a 2/3 multisig account.
```json
{
"msig": {
"subsig": [
{
"pk": "SYGHTA2DR5DYFWJE6D4T34P4AWGCG7JTNMY4VI6EDUVRMX7NG4KTA2WMDA"
},
{
"pk": "VBDMPQACQCH5M6SBXKQXRWQIL7QSR4FH2UI6EYI4RCJSB2T2ZYF2JDHZ2Q"
},
{
"pk": "W3KONPXCGFNUGXGDCOCQYVD64KZOLUMHZ7BNM2ZBK5FSSARRDEXINLYHPI"
}
],
"thr": 2,
"v": 1
},
"txn": {
"amt": 10000000,
"fee": 1000,
"fv": 4694301,
"gen": "testnet-v1.0",
"gh": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
"lv": 4695301,
"rcv": "QC7XT7QU7X6IHNRJZBR67RBMKCAPH67PCSX4LYH4QKVSQ7DQZ32PG5HSVQ",
"snd": "GQ3QPLJL4VKVGQCHPXT5UZTNZIJAGVJPXUHCJLRWQMFRVL4REVW7LJ3FGY",
"type": "pay"
}
}
```
The difference between this transaction and the one above is the form of its signature component. For multisignature accounts, an [`"msig"`](../../transactions/transactions#msig) struct is added which contains the 3 public addresses (`"pk"`), the threshold value (`"thr"`) and the multisig version `"v"`. This transaction is still unsigned but the addition of the correct `"msig"` struct is confirmation that the transaction is "aware" of the fact that the sender is multisig and will have no trouble accepting sub-signatures from single keys even if the signing agent does not contain information about its multisignature properties.
!!! tip
Adding the `"msig"` template to make the transaction "aware" of its multisig sender is highly recommended, particularly in cases where the transaction is signed by multiple parties or offline. Without it, the signing agent would need to have its own knowledge of the multisignature account. For example, `goal` can sign a multisig transaction that does not contain an `"msig"` template _if_ the multisig address was created within its wallet. On signing, it will add the `"msig"` template.
Sub-signatures can be added to the transaction one at a time, cumulatively, or merged together from multiple transactions. Here is the same transaction above, fully authorized:
```json hl_lines="6 13"
{
"msig": {
"subsig": [
{
"pk": "SYGHTA2DR5DYFWJE6D4T34P4AWGCG7JTNMY4VI6EDUVRMX7NG4KTA2WMDA",
"s": "xoQkPyyqCPEhodngmOTP2930Y2GgdmhU/YRQaxQXOwh775gyVSlb1NWn70KFRZvZU96cMtq6TXW+r4sK/lXBCQ=="
},
{
"pk": "VBDMPQACQCH5M6SBXKQXRWQIL7QSR4FH2UI6EYI4RCJSB2T2ZYF2JDHZ2Q"
},
{
"pk": "W3KONPXCGFNUGXGDCOCQYVD64KZOLUMHZ7BNM2ZBK5FSSARRDEXINLYHPI",
"s": "p1ynP9+LZSOZCBcrFwt5JZB2F+zqw3qpLMY5vJBN83A+55cXDYp5uz/0b+vC0VKEKw+j+bL2TzKSL6aTESlDDw=="
}
],
"thr": 2,
"v": 1
},
"txn": {
"amt": 10000000,
"fee": 1000,
"fv": 4694301,
"gen": "testnet-v1.0",
"gh": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
"lv": 4695301,
"rcv": "QC7XT7QU7X6IHNRJZBR67RBMKCAPH67PCSX4LYH4QKVSQ7DQZ32PG5HSVQ",
"snd": "GQ3QPLJL4VKVGQCHPXT5UZTNZIJAGVJPXUHCJLRWQMFRVL4REVW7LJ3FGY",
"type": "pay"
}
}
```
The two signatures are added underneath their respective addresses. Since 2 meets the threshold, this transaction is now fully authorized and can be sent to the network.
!!! info
Adding more sub-signatures than the threshold requires is unnecessary but perfectly valid.
**How-To**
Extend the example from the [Multisignature Account](../../accounts/create#multisignature) section by creating, signing, and sending a transaction from a multisig account on TestNet.
=== "JavaScript"
<!-- ===JSSDK_MULTISIG_CREATE=== -->
```javascript
const signerAccounts: algosdk.Account[] = [];
signerAccounts.push(algosdk.generateAccount());
signerAccounts.push(algosdk.generateAccount());
signerAccounts.push(algosdk.generateAccount());
// multiSigParams is used when creating the address and when signing transactions
const multiSigParams = {
version: 1,
threshold: 2,
addrs: signerAccounts.map((a) => a.addr),
};
const multisigAddr = algosdk.multisigAddress(multiSigParams);
console.log('Created MultiSig Address: ', multisigAddr);
```
[Snippet Source](https://github.com/algorand/js-algorand-sdk/blob/examples/examples/accounts.ts#L27-L41)
<!-- ===JSSDK_MULTISIG_CREATE=== -->
<!-- ===JSSDK_MULTISIG_SIGN=== -->
```javascript
const msigTxn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({
from: multisigAddr,
to: funder.addr,
amount: 100,
suggestedParams,
});
// First signature uses signMultisigTransaction
const msigWithFirstSig = algosdk.signMultisigTransaction(
msigTxn,
multiSigParams,
signerAccounts[0].sk
).blob;
// Subsequent signatures use appendSignMultisigTransaction
const msigWithSecondSig = algosdk.appendSignMultisigTransaction(
msigWithFirstSig,
multiSigParams,
signerAccounts[1].sk
).blob;
await client.sendRawTransaction(msigWithSecondSig).do();
await algosdk.waitForConfirmation(client, msigTxn.txID().toString(), 3);
```
[Snippet Source](https://github.com/algorand/js-algorand-sdk/blob/examples/examples/accounts.ts#L54-L77)
<!-- ===JSSDK_MULTISIG_SIGN=== -->
=== "Python"
<!-- ===PYSDK_MULTISIG_CREATE=== -->
```python
version = 1 # multisig version
threshold = 2 # how many signatures are necessary
# create a Multisig given the set of participants and threshold
msig = transaction.Multisig(
version,
threshold,
[account_1.address, account_2.address, account_3.address],
)
print("Multisig Address: ", msig.address())
```
[Snippet Source](https://github.com/algorand/py-algorand-sdk/blob/examples/examples/account.py#L25-L34)
<!-- ===PYSDK_MULTISIG_CREATE=== -->
<!-- ===PYSDK_MULTISIG_SIGN=== -->
```python
msig_pay = transaction.PaymentTxn(
msig.address(),
sp,
account_1.address,
0,
close_remainder_to=account_1.address,
)
msig_txn = transaction.MultisigTransaction(msig_pay, msig)
msig_txn.sign(account_2.private_key)
msig_txn.sign(account_3.private_key)
txid = algod_client.send_transaction(msig_txn)
result = transaction.wait_for_confirmation(algod_client, txid, 4)
print(
f"Payment made from msig account confirmed in round {result['confirmed-round']}"
)
```
[Snippet Source](https://github.com/algorand/py-algorand-sdk/blob/examples/examples/account.py#L46-L61)
<!-- ===PYSDK_MULTISIG_SIGN=== -->
=== "Java"
<!-- ===JAVASDK_MULTISIG_CREATE=== -->
```java
int version = 1; // no other versions at the time of writing
int threshold = 2; // we're making a 2/3 msig
// Populate a list of Ed25519 pubkeys
List<Ed25519PublicKey> accts = new ArrayList<>();
accts.add(addr1.getEd25519PublicKey());
accts.add(addr2.getEd25519PublicKey());
accts.add(addr3.getEd25519PublicKey());
// create the MultisigAddress object
MultisigAddress msig = new MultisigAddress(version, threshold, accts);
System.out.printf("msig address: %s\n", msig.toAddress().toString());
```
[Snippet Source](https://github.com/algorand/java-algorand-sdk/blob/examples/examples/src/main/java/com/algorand/examples/AccountExamples.java#L77-L88)
<!-- ===JAVASDK_MULTISIG_CREATE=== -->
<!-- ===JAVASDK_MULTISIG_SIGN=== -->
```java
// Construct transaction with sender as address of msig
Transaction msigPayTxn = Transaction.PaymentTransactionBuilder()
.sender(msig.toAddress())
.amount(1000)
.receiver(acct1.getAddress())
.suggestedParams(sp)
.build();
// For each subsig, sign or append to the existing partially signed transaction
SignedTransaction signedMsigPayTxn = acct1.signMultisigTransaction(msig, msigPayTxn);
signedMsigPayTxn = acct2.appendMultisigTransaction(msig, signedMsigPayTxn);
Response<PostTransactionsResponse> msigSubResponse = algodClient.RawTransaction()
.rawtxn(Encoder.encodeToMsgPack(signedMsigPayTxn)).execute();
```
[Snippet Source](https://github.com/algorand/java-algorand-sdk/blob/examples/examples/src/main/java/com/algorand/examples/AccountExamples.java#L42-L55)
<!-- ===JAVASDK_MULTISIG_SIGN=== -->
=== "Go"
<!-- ===GOSDK_MULTISIG_CREATE=== -->
```go
// Get pre-defined set of keys for example
_, pks := loadAccounts()
addr1, _ := types.DecodeAddress(pks[1])
addr2, _ := types.DecodeAddress(pks[2])
addr3, _ := types.DecodeAddress(pks[3])
ma, err := crypto.MultisigAccountWithParams(1, 2, []types.Address{
addr1,
addr2,
addr3,
})
if err != nil {
panic("invalid multisig parameters")
}
fromAddr, _ := ma.Address()
// Print multisig account
fmt.Printf("Multisig address : %s \n", fromAddr)
```
[Snippet Source](https://github.com/algorand/go-algorand-sdk/blob/examples/examples/kmd/main.go#L178-L196)
<!-- ===GOSDK_MULTISIG_CREATE=== -->
<!-- ===GOSDK_MULTISIG_SIGN=== -->
```go
package main
import (
"context"
"crypto/ed25519"
"fmt"
json "encoding/json"
"github.com/algorand/go-algorand-sdk/client/v2/algod"
"github.com/algorand/go-algorand-sdk/crypto"
"github.com/algorand/go-algorand-sdk/mnemonic"
"github.com/algorand/go-algorand-sdk/transaction"
"github.com/algorand/go-algorand-sdk/types"
)
// UPDATE THESE VALUES
// const algodAddress = "Your ADDRESS"
// const algodToken = "Your TOKEN"
// sandbox
const algodAddress = "http://localhost:4001"
const algodToken = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
// Accounts to be used through examples
func loadAccounts() (map[int][]byte, map[int]string) {
// Shown for demonstration purposes. NEVER reveal secret mnemonics in practice.
// Change these values to use the accounts created previously.
// Paste in mnemonic phrases for all three accounts
mnemonic1 := "PASTE phrase for account 1"
mnemonic2 := "PASTE phrase for account 2"
mnemonic3 := "PASTE phrase for account 3"
// never use mnemonics in production code, replace for demo purposes only
mnemonics := []string{mnemonic1, mnemonic2, mnemonic3}
pks := map[int]string{1: "", 2: "", 3: ""}
var sks = make(map[int][]byte)
for i, m := range mnemonics {
var err error
sk, err := mnemonic.ToPrivateKey(m)
sks[i+1] = sk
if err != nil {
fmt.Printf("Issue with account %d private key conversion.", i+1)
}
// derive public address from Secret Key.
pk := sk.Public()
var a types.Address
cpk := pk.(ed25519.PublicKey)
copy(a[:], cpk[:])
pks[i+1] = a.String()
fmt.Printf("Loaded Key %d: %s\n", i+1, pks[i+1])
}
return sks, pks
}
// PrettyPrint prints Go structs
func PrettyPrint(data interface{}) {
var p []byte
// var err := error
p, err := json.MarshalIndent(data, "", "\t")
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%s \n", p)
}
func main() {
// Initialize an algodClient
algodClient, err := algod.MakeClient(algodAddress, algodToken)
if err != nil {
return
}
// Get network-related transaction parameters and assign
txParams, err := algodClient.SuggestedParams().Do(context.Background())
if err != nil {
fmt.Printf("error getting suggested tx params: %s\n", err)
return
}
// comment out the next two (2) lines to use suggested fees
// txParams.FlatFee = true
// txParams.Fee = 1000
// Get pre-defined set of keys for example
sks, pks := loadAccounts()
addr1, _ := types.DecodeAddress(pks[1])
addr2, _ := types.DecodeAddress(pks[2])
addr3, _ := types.DecodeAddress(pks[3])
ma, err := crypto.MultisigAccountWithParams(1, 2, []types.Address{
addr1,
addr2,
addr3,
})
if err != nil {
panic("invalid multisig parameters")
}
fromAddr, _ := ma.Address()
// Fund account
fmt.Println("Fund multisig account using testnet faucet:\n--> https://dispenser.testnet.aws.algodev.network?account=" + fromAddr.String())
fmt.Println("--> Once funded, press ENTER key to continue...")
// fmt.Scanln() // wait for Enter Key
toAddr := addr3.String()
var amount uint64 = 10000
note := []byte("Hello World")
genID := txParams.GenesisID
genHash := txParams.GenesisHash
firstValidRound := uint64(txParams.FirstRoundValid)
lastValidRound := uint64(txParams.LastRoundValid)
var minFee uint64 = 1000
txn, err := transaction.MakePaymentTxn(
fromAddr.String(),
toAddr,
minFee, // fee per byte
amount, // amount
firstValidRound, // first valid round
lastValidRound, // last valid round
note, // note
"", // closeRemainderTo
genID, // genesisHash
genHash, // genesisHash
)
txid, txBytes, err := crypto.SignMultisigTransaction(sks[1], ma, txn)
if err != nil {
println(err.Error)
panic("could not sign multisig transaction")
}
fmt.Printf("Made partially-signed multisig transaction with TxID %s: %x\n", txid, txBytes)
txid, twoOfThreeTxBytes, err := crypto.AppendMultisigTransaction(sks[2], ma, txBytes)
if err != nil {
panic("could not append signature to multisig transaction")
}
fmt.Printf("Appended bytes %x\n", twoOfThreeTxBytes)
fmt.Printf("Made 2-out-of-3 multisig transaction with TxID %s: %x\n", txid, twoOfThreeTxBytes)
// We can also merge raw, partially-signed multisig transactions:
// otherTxBytes := ... // generate another raw multisig transaction
// txid, mergedTxBytes, err := crypto.MergeMultisigTransactions(twoOfThreeTxBytes, otherTxBytes)
// Broadcast the transaction to the network
txid, err = algodClient.SendRawTransaction(twoOfThreeTxBytes).Do(context.Background())
// Wait for confirmation
confirmedTxn, err := transaction.WaitForConfirmation(algodClient,txid, 4, context.Background())
if err != nil {
fmt.Printf("Error waiting for confirmation on txID: %s\n", txid)
return
}
fmt.Printf("Confirmed Transaction: %s in Round %d\n", txid ,confirmedTxn.ConfirmedRound)
txnJSON, err := json.MarshalIndent(confirmedTxn.Transaction.Txn, "", "\t")
if err != nil {
fmt.Printf("Can not marshall txn data: %s\n", err)
}
fmt.Printf("Transaction information: %s\n", txnJSON)
fmt.Printf("Decoded note: %s\n", string(confirmedTxn.Transaction.Txn.Note))
}
```
<!-- ===GOSDK_MULTISIG_SIGN=== -->
=== "goal"
```zsh
# Sign cumulatively
$ goal clerk multisig sign -t multisig.txn -a $ADDRESS1
$ goal clerk multisig sign -t multisig.txn -a $ADDRESS2
# Or sign two separate files and merge
$ goal clerk multisig sign -t multisig1.txn -a $ADDRESS1
$ goal clerk multisig sign -t multisig2.txn -a $ADDRESS2
$ goal clerk multisig merge multisig1.txn multisig2.txn --out=merged.stxn
```
=== "algokey"
```zsh
# algokey takes account-level mnemonics at the time of signing
# requires the transaction to include the msig struct before signing
$ algokey multisig --txfile=multisig1.txn --outfile=multisig1.stxn -m <25-word-mnemonic>
$ algokey multisig --txfile=multisig2.txn --outfile=multisig2.stxn -m <25-word-mnemonic>
# Use goal to merge the the *.stxn files.
```
# Logic Signatures
Logic signatures authorize transactions associated with an Algorand Smart Signature. Logic signatures are added to transactions to authorize spends from a [Contract Account](../../dapps/smart-contracts/smartsigs/modes#contract-account) or from a [Delegated Account](../../dapps/smart-contracts/smartsigs/modes#delegated-approval).
A full explanation of Logic Signatures can be found in the [Algorand Smart Contract Usage Modes Guide](../../dapps/smart-contracts/smartsigs/modes).
**Related How-To**
- [Use LogicSigs with the SDKs](../../dapps/smart-contracts/frontend/smartsigs)
- [Attach a LogicSig with `goal`](../../dapps/smart-contracts/smartsigs/walkthrough)
```
--------------------------------------------------------------------------------
/packages/server/src/resources/knowledge/taxonomy/developer:docs:details:indexer.md:
--------------------------------------------------------------------------------
```markdown
title: Indexer
This guide explains how to search the Algorand Blockchain using the Indexer. This Indexer is not part of the Algorand node and requires a separate binary download. See the [Indexer Install Guide](../run-a-node/setup/indexer.md) for instructions on installing and configuring the new Indexer.

<center>*Algorand V2 Indexer*</center>
The primary purpose of this Indexer is to provide a REST API interface of API calls to support searching the Algorand Blockchain. The Indexer REST APIs retrieve the blockchain data from a [PostgreSQL](https://www.postgresql.org/) compatible database that must be populated. This database is populated using the same indexer instance or a separate instance of the indexer which must connect to the algod process of a running Algorand node to read block data. This node must also be an Archival node to make searching the entire blockchain possible.
The Indexer provides a set of REST API calls for searching blockchain Transactions, Accounts, Assets and Blocks. Each of these calls also provides several filter parameters to support refining searches. The latest Algorand native SDKs (Python, JavaScript, Go, and Java) provide similar functionality. These REST calls are based on the Open API specification and are described in the REST SDK reference documentation.
See the full description of endpoints available in the [indexer docs](../rest-apis/indexer.md).
# SDK client instantiations
=== "JavaScript"
<!-- ===JSSDK_INDEXER_CREATE_CLIENT=== -->
```javascript
const indexerToken = 'a'.repeat(64);
const indexerServer = 'http://localhost';
const indexerPort = 8980;
const indexerClient = new algosdk.Indexer(
indexerToken,
indexerServer,
indexerPort
);
```
[Snippet Source](https://github.com/algorand/js-algorand-sdk/blob/examples/examples/indexer.ts#L15-L24)
<!-- ===JSSDK_INDEXER_CREATE_CLIENT=== -->
=== "Python"
<!-- ===PYSDK_INDEXER_CREATE_CLIENT=== -->
```python
# instantiate indexer client
indexer_host = "http://localhost:8980"
indexer_token = "a" * 64
indexer_client = indexer.IndexerClient(
indexer_token=indexer_token, indexer_address=indexer_host
)
```
[Snippet Source](https://github.com/algorand/py-algorand-sdk/blob/examples/examples/indexer.py#L7-L13)
<!-- ===PYSDK_INDEXER_CREATE_CLIENT=== -->
=== "Java"
<!-- ===JAVASDK_INDEXER_CREATE_CLIENT=== -->
```java
String indexerHost = "http://localhost";
int indexerPort = 8980;
String indexerToken = "a".repeat(64);
IndexerClient indexerClient = new IndexerClient(indexerHost, indexerPort, indexerToken);
```
[Snippet Source](https://github.com/algorand/java-algorand-sdk/blob/examples/examples/src/main/java/com/algorand/examples/IndexerExamples.java#L12-L16)
<!-- ===JAVASDK_INDEXER_CREATE_CLIENT=== -->
=== "Go"
<!-- ===GOSDK_INDEXER_CREATE_CLIENT=== -->
```go
// Create a new indexer client, configured to connect to out local sandbox
var indexerAddress = "http://localhost:8980"
var indexerToken = strings.Repeat("a", 64)
indexerClient, _ := indexer.MakeClient(
indexerAddress,
indexerToken,
)
// Or, if necessary, pass alternate headers
var indexerHeader common.Header
indexerHeader.Key = "X-API-Key"
indexerHeader.Value = indexerToken
indexerClientWithHeaders, err := indexer.MakeClientWithHeaders(
indexerAddress,
indexerToken,
[]*common.Header{&indexerHeader},
)
```
[Snippet Source](https://github.com/algorand/go-algorand-sdk/blob/examples/examples/indexer/main.go#L15-L33)
<!-- ===GOSDK_INDEXER_CREATE_CLIENT=== -->
!!! info
When using cURL be aware that the parameters may need to be URL encoded. The SDKs handle the encoding of parameter data.
The indexer provides two primary ways to access information:
1) Lookup a single item (a single account, a single transaction, a single block)
2) Search for items that match a query (transactions for > 100A and between round N and M)
Each SDK provides methods for looking up or searching for transactions, assets, applications(smart contracts), and blocks. For a full list of method calls see the SDK docs:
- [Python](https://py-algorand-sdk.readthedocs.io/en/latest/algosdk/v2client/indexer.html)
- [JavaScript](https://algorand.github.io/js-algorand-sdk/classes/Indexer.html)
- [Java](https://algorand.github.io/java-algorand-sdk/com/algorand/algosdk/v2/client/indexer/package-summary.html)
- [Go](https://pkg.go.dev/github.com/algorand/go-algorand-sdk/[email protected]/client/v2/indexer)
# Lookup
As an example, to get the details of a specific asset the indexer provides the `/assets/{asset-id}` REST call. This call takes no parameters as the asset id is passed in the URL. This call returns the details of the asset and the round the results were calculated in.
=== "JavaScript"
<!-- ===JSSDK_INDEXER_LOOKUP_ASSET=== -->
```javascript
const indexer = getLocalIndexerClient();
const indexerAssetInfo = await indexer.lookupAssetByID(assetIndex).do();
console.log('Indexer Asset Info:', indexerAssetInfo);
```
[Snippet Source](https://github.com/algorand/js-algorand-sdk/blob/examples/examples/asa.ts#L54-L57)
<!-- ===JSSDK_INDEXER_LOOKUP_ASSET=== -->
=== "Python"
<!-- ===PYSDK_INDEXER_LOOKUP_ASSET=== -->
```python
# lookup a single asset
# by passing include_all, we specify that we want to see deleted assets as well
response = indexer_client.asset_info(asset_id, include_all=True)
print(f"Asset Info: {json.dumps(response, indent=2,)}")
```
[Snippet Source](https://github.com/algorand/py-algorand-sdk/blob/examples/examples/indexer.py#L50-L54)
<!-- ===PYSDK_INDEXER_LOOKUP_ASSET=== -->
=== "Java"
<!-- ===JAVASDK_INDEXER_LOOKUP_ASSET=== -->
```java
Long asaId = 25l;
Response<AssetResponse> assetResponse = indexerClient.lookupAssetByID(asaId).execute();
Asset assetInfo = assetResponse.body().asset;
System.out.printf("Name for %d: %s\n", asaId, assetInfo.params.name);
```
[Snippet Source](https://github.com/algorand/java-algorand-sdk/blob/examples/examples/src/main/java/com/algorand/examples/IndexerExamples.java#L19-L23)
<!-- ===JAVASDK_INDEXER_LOOKUP_ASSET=== -->
=== "Go"
<!-- ===GOSDK_INDEXER_LOOKUP_ASSET=== -->
```go
// query parameters
var assetId uint64 = 2044572
var minBalance uint64 = 50
// Lookup accounts with minimum balance of asset
assetResult, _ := indexerClient.
LookupAssetBalances(assetId).
CurrencyGreaterThan(minBalance).
Do(context.Background())
// Print the results
assetJson, _ := json.MarshalIndent(assetResult, "", "\t")
fmt.Printf(string(assetJson) + "\n")
```
[Snippet Source](https://github.com/algorand/go-algorand-sdk/blob/examples/examples/indexer/main.go#L55-L68)
<!-- ===GOSDK_INDEXER_LOOKUP_ASSET=== -->
=== "cURL"
<!-- ===CURL_INDEXER_LOOKUP_ASSET=== -->
``` bash
$ curl "localhost:8980/v2/assets/2044572"
```
<!-- ===CURL_INDEXER_LOOKUP_ASSET=== -->
# Search
Searching is similar to lookup with the ability to return multiple or filtered results. This example searches for transactions based on a few filters.
=== "JavaScript"
<!-- ===JSSDK_INDEXER_SEARCH_MIN_AMOUNT=== -->
```javascript
const transactionInfo = await indexerClient
.searchForTransactions()
.currencyGreaterThan(100)
.do();
console.log(transactionInfo.transactions.map((t) => t.id));
```
[Snippet Source](https://github.com/algorand/js-algorand-sdk/blob/examples/examples/indexer.ts#L33-L38)
<!-- ===JSSDK_INDEXER_SEARCH_MIN_AMOUNT=== -->
=== "Python"
<!-- ===PYSDK_INDEXER_SEARCH_MIN_AMOUNT=== -->
```python
response = indexer_client.search_transactions(
min_amount=10, min_round=1000, max_round=1500
)
print(f"Transaction results: {json.dumps(response, indent=2)}")
```
[Snippet Source](https://github.com/algorand/py-algorand-sdk/blob/examples/examples/indexer.py#L57-L61)
<!-- ===PYSDK_INDEXER_SEARCH_MIN_AMOUNT=== -->
=== "Java"
<!-- ===JAVASDK_INDEXER_SEARCH_MIN_AMOUNT=== -->
```java
Response<TransactionsResponse> transactionSearchResult = indexerClient.searchForTransactions()
.minRound(10l).maxRound(500l).currencyGreaterThan(10l).execute();
TransactionsResponse txResp = transactionSearchResult.body();
System.out.printf("Found %d transactions that match criteria\n", txResp.transactions.size());
```
[Snippet Source](https://github.com/algorand/java-algorand-sdk/blob/examples/examples/src/main/java/com/algorand/examples/IndexerExamples.java#L26-L30)
<!-- ===JAVASDK_INDEXER_SEARCH_MIN_AMOUNT=== -->
=== "Go"
<!-- ===GOSDK_INDEXER_SEARCH_MIN_AMOUNT=== -->
```go
// query parameters
var transactionMinAmount uint64 = 10
// Query
transactionResult, _ := indexerClient.
SearchForTransactions().
CurrencyGreaterThan(transactionMinAmount).
Do(context.Background())
// Print results
transactionJson, _ := json.MarshalIndent(transactionResult, "", "\t")
fmt.Printf(string(transactionJson) + "\n")
```
[Snippet Source](https://github.com/algorand/go-algorand-sdk/blob/examples/examples/indexer/main.go#L73-L85)
<!-- ===GOSDK_INDEXER_SEARCH_MIN_AMOUNT=== -->
=== "cURL"
<!-- ===CURL_INDEXER_SEARCH_MIN_AMOUNT=== -->
```bash
$ curl "localhost:8980/v2/transactions?currency-greater-than=10"
```
<!-- ===CURL_INDEXER_SEARCH_MIN_AMOUNT=== -->
# Pagination
When searching large amounts of blockchain data often the results may be too large to process in one given operation. In fact, the indexer imposes hard limits on the number of results returned for specific searches. The default limits for these searches are summarized in the table below.
| Search Type | Maximum number of results per search |
| ------------- | ------------- |
| API Resources Per Account | 1,000 |
| Transactions Search | 1,000 |
| Accounts Search | 100 |
| Assets Search | 100 |
| Balances Search | 1,000 |
| Applications Search | 100 |
When trying to find specific transactions, the Indexer supplies a pagination method that allows separating the results into several REST calls to return larger result sets. When used with the limit parameter the results for large data sets can be returned in expected result counts.
For example, adding a limit parameter of 5 to the previous call will cause only 5 results to be returned in each page. To get the next 5 transactions simply add the next-token as a parameter to the next REST call. The parameter is named `next` and this token is only good for the next 5 results.
=== "JavaScript"
<!-- ===JSSDK_INDEXER_PAGINATE_RESULTS=== -->
```javascript
let nextToken = '';
// nextToken will be undefined if we reached the last page
while (nextToken !== undefined) {
// eslint-disable-next-line no-await-in-loop
const response = await indexerClient
.searchForTransactions()
.limit(5)
.currencyGreaterThan(10)
.nextToken(nextToken)
.do();
nextToken = response['next-token'];
const txns = response.transactions;
if (txns.length > 0)
console.log(`Transaction IDs: ${response.transactions.map((t) => t.id)}`);
}
```
[Snippet Source](https://github.com/algorand/js-algorand-sdk/blob/examples/examples/indexer.ts#L41-L58)
<!-- ===JSSDK_INDEXER_PAGINATE_RESULTS=== -->
=== "Python"
<!-- ===PYSDK_INDEXER_PAGINATE_RESULTS=== -->
```python
nexttoken = ""
has_results = True
page = 0
# loop using next_page to paginate until there are
# no more transactions in the response
while has_results:
response = indexer_client.search_transactions(
min_amount=10, min_round=1000, max_round=1500, next_page=nexttoken
)
has_results = len(response["transactions"]) > 0
if has_results:
nexttoken = response["next-token"]
print(f"Tranastion on page {page}: " + json.dumps(response, indent=2))
page += 1
```
[Snippet Source](https://github.com/algorand/py-algorand-sdk/blob/examples/examples/indexer.py#L64-L83)
<!-- ===PYSDK_INDEXER_PAGINATE_RESULTS=== -->
=== "Java"
<!-- ===JAVASDK_INDEXER_PAGINATE_RESULTS=== -->
```java
String nextToken = "";
boolean hasResults = true;
// Start with empty nextToken and while there are
// results in the transaction results, query again with the next page
while (hasResults) {
Response<TransactionsResponse> searchResults = indexerClient.searchForTransactions().minRound(1000l)
.maxRound(1500l).currencyGreaterThan(10l).next(nextToken).execute();
TransactionsResponse txnRes = searchResults.body();
//
// ... do something with transaction results
//
hasResults = txnRes.transactions.size() > 0;
nextToken = txnRes.nextToken;
}
```
[Snippet Source](https://github.com/algorand/java-algorand-sdk/blob/examples/examples/src/main/java/com/algorand/examples/IndexerExamples.java#L33-L47)
<!-- ===JAVASDK_INDEXER_PAGINATE_RESULTS=== -->
=== "Go"
<!-- ===GOSDK_INDEXER_PAGINATE_RESULTS=== -->
```go
var nextToken = ""
var numTx = 1
var numPages = 1
var pagedMinAmount uint64 = 10
var limit uint64 = 1
for numTx > 0 {
// Query
pagedResults, err := indexerClient.
SearchForTransactions().
CurrencyGreaterThan(pagedMinAmount).
Limit(limit).
NextToken(nextToken).
Do(context.Background())
if err != nil {
return
}
pagedTransactions := pagedResults.Transactions
numTx = len(pagedTransactions)
nextToken = pagedResults.NextToken
if numTx > 0 {
// Print results
pagedJson, err := json.MarshalIndent(pagedTransactions, "", "\t")
if err != nil {
return
}
fmt.Printf(string(pagedJson) + "\n")
fmt.Println("End of page : ", numPages)
fmt.Println("Transaction printed : ", len(pagedTransactions))
fmt.Println("Next Token : ", nextToken)
numPages++
}
}
```
[Snippet Source](https://github.com/algorand/go-algorand-sdk/blob/examples/examples/indexer/main.go#L88-L122)
<!-- ===GOSDK_INDEXER_PAGINATE_RESULTS=== -->
=== "cURL"
<!-- ===CURL_INDEXER_PAGINATE_RESULTS=== -->
```bash
$ curl "localhost:8980/v2/transactions?currency-greater-than=10&limit=5"
# note the "next-token" field in the most recent results and supply the value to the "next" parameter
$ curl "localhost:8979/v2/transactions?currency-greater-than=10&limit=5&next=cAoBAAAAAAAAAAAA"
```
<!-- ===CURL_INDEXER_PAGINATE_RESULTS=== -->
Results showing "next-token"
```json
{
"next-token" : "cAoBAAAAAAAAAAAA",
"current-round" : 7050272,
"transactions" : []
}
```
A new next token will be returned to get the next five. This token acts as a marker in the current result set and allows the next call to pick up where the last search ended. We note that the 'limit' parameter can also be used to specify a larger (rather than smaller) results set than the defaults above. These limits are shown in the following table and are per call, not the total result set.
| Search Type | Search Limit with a limit parameter |
| ------------- | ------------- |
| Transaction Search | 10000 |
| Account Search | 1000 |
| Asset Search | 1000 |
| Asset Balance Search | 10000 |
The following REST calls support paginated results.
* `/accounts` - Search for specific accounts.
* `/accounts/{account-id}/transactions` - Search for transactions for a specific account.
* `/accounts/{account-id}/created-apps` - Search for created applications for a specific account.
* `/accounts/{account-id}/created-assets` - Search for created assets for a specific account.
* `/accounts/{account-id}/assets` - Search for assets on a specific account.
* `/accounts/{account-id}/apps-local-state` - Search for application local state for a specific account.
* `/assets` - Search Assets.
* `/assets/{asset-id}/balances` - Search Asset balances.
* `/assets/{asset-id}/transactions` - Search for Transactions with a specific Asset.
* `/transactions` - Search all transactions
# Note field searching
Every transaction has the ability to add up to a 1kb note in the note field. Several of the REST APIs provide the ability to search for a prefix that is present in the note field, meaning that the note starts with a specific string. This can be a very powerful way to quickly locate transactions that are specific to an application. The REST calls that support prefix searching are the following.
* `/accounts/{account-id}/transactions` - Search for a prefix for a specific accounts transactions.
* `/assets/{asset-id}/transactions` - Search for a prefix for a specific Asset Id.
* `/transactions` - Search all Transactions for a specific transaction note field prefix.
To search for a specific prefix use the `note-prefix` parameter. For the Javascript and direct REST API, the value needs to be base64 encoded to return results. (The other SDKs perform the base64 encoding for you.) For example, if the contents of the note field started with the string “showing prefix searches”, encoding the beginning of that sentence using python like the following:
``` bash
$ python3 -c "import base64;print(base64.b64encode('showing prefix'.encode()))"
```
This will return an encoded value of `c2hvd2luZyBwcmVmaXg=`. This value can then be passed to the search. To search all transactions use the following command.
=== "JavaScript"
<!-- ===JSSDK_INDEXER_PREFIX_SEARCH=== -->
```javascript
const txnsWithNotePrefix = await indexerClient
.searchForTransactions()
.notePrefix(Buffer.from('Hello'))
.do();
console.log(
`Transactions with note prefix "Hello" ${JSON.stringify(
txnsWithNotePrefix,
undefined,
2
)}`
);
```
[Snippet Source](https://github.com/algorand/js-algorand-sdk/blob/examples/examples/indexer.ts#L80-L91)
<!-- ===JSSDK_INDEXER_PREFIX_SEARCH=== -->
=== "Python"
<!-- ===PYSDK_INDEXER_PREFIX_SEARCH=== -->
```python
note_prefix = "showing prefix".encode()
response = indexer_client.search_transactions(note_prefix=note_prefix)
print(f"result: {json.dumps(response, indent=2)}")
```
[Snippet Source](https://github.com/algorand/py-algorand-sdk/blob/examples/examples/indexer.py#L86-L89)
<!-- ===PYSDK_INDEXER_PREFIX_SEARCH=== -->
=== "Java"
<!-- ===JAVASDK_INDEXER_PREFIX_SEARCH=== -->
```java
byte[] prefix = new String("showing prefix").getBytes();
Response<TransactionsResponse> prefixResults = indexerClient.searchForTransactions().notePrefix(prefix)
.execute();
// ...
```
[Snippet Source](https://github.com/algorand/java-algorand-sdk/blob/examples/examples/src/main/java/com/algorand/examples/IndexerExamples.java#L50-L54)
<!-- ===JAVASDK_INDEXER_PREFIX_SEARCH=== -->
=== "Go"
<!-- ===GOSDK_INDEXER_PREFIX_SEARCH=== -->
```go
// Parameters
var notePrefix = "showing prefix"
// Query
prefixResult, _ := indexerClient.
SearchForTransactions().
NotePrefix([]byte(notePrefix)).
Do(context.Background())
// Print results
prefixJson, _ := json.MarshalIndent(prefixResult, "", "\t")
fmt.Printf(string(prefixJson) + "\n")
```
[Snippet Source](https://github.com/algorand/go-algorand-sdk/blob/examples/examples/indexer/main.go#L125-L137)
<!-- ===GOSDK_INDEXER_PREFIX_SEARCH=== -->
=== "cURL"
<!-- ===CURL_INDEXER_PREFIX_SEARCH=== -->
```bash
python3 -c "import base64;print(base64.b64encode('showing prefix'.encode()))"
$ curl "localhost:8980/v2/transactions?note-prefix=c2hvd2luZyBwcmVmaXg=" | json_pp
```
<!-- ===CURL_INDEXER_PREFIX_SEARCH=== -->
```