Skip to content

Commit

Permalink
chore: add docs
Browse files Browse the repository at this point in the history
  • Loading branch information
neilcampbell committed Oct 18, 2024
1 parent f63c367 commit e529e8a
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 2 deletions.
48 changes: 48 additions & 0 deletions docs/capabilities/app-client.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)`.
Expand Down
2 changes: 0 additions & 2 deletions src/types/algorand-client.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'),
Expand Down
1 change: 1 addition & 0 deletions src/types/app-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)[]
}
Expand Down
3 changes: 3 additions & 0 deletions src/types/composer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@ export type AppMethodCall<T> = Expand<Omit<T, 'args'>> & {
* * 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
Expand Down Expand Up @@ -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.
Expand Down

0 comments on commit e529e8a

Please sign in to comment.