From e529e8a23ae67ce3361089730d8a0db5dd7aab55 Mon Sep 17 00:00:00 2001 From: Neil Campbell Date: Sat, 19 Oct 2024 01:27:14 +0800 Subject: [PATCH] chore: add docs --- docs/capabilities/app-client.md | 48 +++++++++++++++++++++++++++++++ src/types/algorand-client.spec.ts | 2 -- src/types/app-client.ts | 1 + src/types/composer.ts | 3 ++ 4 files changed, 52 insertions(+), 2 deletions(-) diff --git a/docs/capabilities/app-client.md b/docs/capabilities/app-client.md index cc5e8731..615dc94a 100644 --- a/docs/capabilities/app-client.md +++ b/docs/capabilities/app-client.md @@ -248,6 +248,54 @@ const transaction = await appClient.createTransaction.bare.closeOut({ const params = appClient.params.optIn({ method: 'optin' }) ``` +### Nested ABI Method Call Transactions + +The ARC4 ABI specification supports ABI method calls as arguments to other ABI method calls, enabling some interesting use cases. While this conceptually resembles a function call hierarchy, in practice, the transactions are organized as a flat, ordered transaction group. Unfortunately, this logically hierarchical structure cannot always be correctly represented as a flat transaction group, making some scenarios impossible. + +To illustrate this, let's consider an example of two ABI methods with the following signatures: + +- `myMethod(pay, appl): void` +- `myOtherMethod(pay): void` + +These signatures are compatible, so `myOtherMethod` can be passed as an ABI method call argument to `myMethod`, which would look like: + +Hierarchical method call + +``` +myMethod(pay, myOtherMethod(pay)) +``` + +Flat transaction group + +``` +pay (pay) +appl (myOtherMethod) +appl (myMethod) +``` + +An important limitation to note is that the flat transaction group representation does not allow having two different pay transactions. This invariant is represented in the hierarchical call interface of the app client by passing an `undefined` value. This acts as a placeholder and tells the app client that another ABI method call argument will supply the value for this argument. For example: + +```typescript +const payment = algorand.createTransaction.payment({ + sender: alice.addr, + receiver: alice.addr, + amount: microAlgo(1), +}) + +const myOtherMethodCall = await appClient.params.call({ + method: 'myOtherMethod', + args: [payment], +}) + +const myMethodCall = await appClient.send.call({ + method: 'myMethod', + args: [undefined, myOtherMethodCall], +}) +``` + +`myOtherMethodCall` supplies the pay transaction to the transaction group and, by association, `myOtherMethodCall` has access to it as defined in its signature. +To ensure the app client builds the correct transaction group, you must supply a value for every argument in a method call signature. + ## Funding the app account Often there is a need to fund an app account to cover minimum balance requirements for boxes and other scenarios. There is an app client method that will do this for you `fundAppAccount(params)`. diff --git a/src/types/algorand-client.spec.ts b/src/types/algorand-client.spec.ts index fc3ac2dd..f8317b24 100644 --- a/src/types/algorand-client.spec.ts +++ b/src/types/algorand-client.spec.ts @@ -271,8 +271,6 @@ describe('AlgorandClient', () => { test('methodCall create', async () => { const contract = new algosdk.ABIContract(APP_SPEC.contract) - console.debug(JSON.stringify(APP_SPEC)) - await algorand.send.appCreateMethodCall({ sender: alice.addr, method: contract.getMethodByName('createApplication'), diff --git a/src/types/app-client.ts b/src/types/app-client.ts index 3e2228e3..d40e0f98 100644 --- a/src/types/app-client.ts +++ b/src/types/app-client.ts @@ -374,6 +374,7 @@ export type AppClientMethodCallParams = Expand< * * A transaction (where the signer will be automatically assigned) * * An unawaited transaction (e.g. from algorand.createTransaction.transactionType()) * * Another method call (via method call params object) + * * undefined (this represents a placeholder for either a default argument or a transaction argument that is fulfilled by another method call argument) */ args?: (ABIValue | ABIStruct | AppMethodCallTransactionArgument | undefined)[] } diff --git a/src/types/composer.ts b/src/types/composer.ts index 850a6771..7028faca 100644 --- a/src/types/composer.ts +++ b/src/types/composer.ts @@ -430,6 +430,7 @@ export type AppMethodCall = Expand> & { * * A transaction (where the signer will be automatically assigned) * * An unawaited transaction (e.g. from algorand.createTransaction.{transactionType}()) * * Another method call (via method call params object) + * * undefined (this represents a placeholder transaction argument that is fulfilled by another method call argument) */ args?: ( | algosdk.ABIValue @@ -1235,6 +1236,8 @@ export default class AlgoKitComposer { return { atc: this.atc, transactions: this.atc.buildGroup(), methodCalls: this.atc['methodCalls'] } } + // TODO: NC - Docs about the behaviour + /** * Rebuild the group, discarding any previously built transactions. * This will potentially cause new signers and suggested params to be used if the callbacks return a new value compared to the first build.