Skip to content

Conversation

@PatrickDinh
Copy link
Contributor

Proposed Changes

return result
})()
: undefined,
rejectVersion: bigIntCodec.decodeOptional(transactionDto.aprv),
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
rejectVersion: bigIntCodec.decodeOptional(transactionDto.aprv),
rejectVersion: numberCodec.decodeOptional(transactionDto.aprv),

/**
* The lowest application version for which this transaction should immediately fail. 0 indicates that no version check should be performed.
*/
rejectVersion?: bigint
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
rejectVersion?: bigint
rejectVersion?: number

apep?: number

/** Reject version */
aprv?: bigint | number
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
aprv?: bigint | number
aprv?: number

// Populate the composer with method calls
if ('transactions' in transaction) {
transaction.methodCalls.forEach((m, i) => sendParams.atc!['methodCalls'].set(i + baseIndex, m))
transaction.methodCalls.forEach((m, i) => sendParams.transactionComposer!['methodCalls'].set(i + baseIndex, m))
Copy link
Contributor

Choose a reason for hiding this comment

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

This feels hacky. Maybe it's ok because it's in the legacy code.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeh it's pretty hacky. The problem comes from here

const transaction = await txn(transactionCreator)(params)

this causes the trasaction to be a txnWithSigner => when it's added to the composer, the methodCalls map isn't updated.

* Builds an ABI method call transaction and any other associated transactions represented in the ABI args.
* @param includeSigner Whether to include the actual signer for the transactions.
* If you are just building transactions without signers yet then set this to `false`.
* Compose all of the transactions without signers and return the transaction objects directly along with any ABI method calls.
Copy link
Contributor

Choose a reason for hiding this comment

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

This does return signers as well

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The jsdocs confused me as first too because this method returns the signer Map. I think it means that the transactions returned doesn't have signers attached. Should I change the docs?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes I think the docs should be updated to be clearer.


const builtTransactions = await this.buildTransactions()
const transactions =
Copy link
Contributor

Choose a reason for hiding this comment

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

Doesn't buildTransactions take care of grouping?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, buildTransactions doesn't do grouping. Grouping is applied in build, after resource population and fee coverage.

You mentioned this makes me think that the names buildTransactions and build are confusing. I kept them because:

  • buildTransactions existed in the composer. It does similar functionality.
  • build existed in the composer, but private. In main, resource population + fee coverage happen in send, for this version, I lifted them to build
    I'm happy to find better names for them but that means breaking changes.

const error = new Error(errorMessage)

if (Config.debug) {
await Config.events.emitAsync(EventType.TxnGroupSimulated, { simulateResponse })
await Config.events.emitAsync(EventType.TxnGroupSimulated, { simulateTransaction: simulateResponse })
Copy link
Contributor

Choose a reason for hiding this comment

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

The utils-ts-debug repo provides a handler for this event, so we need to think about migration and breaking changes here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll add a note to the migration doc

return (
ctxn.type === 'appCall' ||
ctxn.type === 'methodCall' ||
(ctxn.type === 'txnWithSigner' && ctxn.data.txn.type === TransactionType.AppCall)
Copy link
Contributor

Choose a reason for hiding this comment

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

What about asyncTxn?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll remove this function, it isn't needed anymore. In build (where it was used) I have access to the built transaction, I can check for the transaction type directly.

@@ -547,19 +234,19 @@ export interface BuiltTransactions {
signers: Map<number, algosdk.TransactionSigner>
}

class BuildComposerTransactionsError extends Error {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@neilcampbell I created this error type for errors during build transactions. I think this is helpful because before this, in debug mode, if something goes wrong during resource population, we will need to run simulate again in the error handler. Using this error type, we can surface to simulation result to the error handler => eliminate the need to simulate again.

Copy link
Contributor

Choose a reason for hiding this comment

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

I like the idea, however this also become part of the public interface of the composer and an exception that a user may receive. I'd be inclined to keep as before and run another simulate. It only occurs in debug mode, which should only be enabled in testing scenarios (non prod).

expect(clonedAppClient.appId).toBe(appClient.appId)
expect(clonedAppClient.appName).toBe(appClient.appName)
expect((await clonedAppClient.createTransaction.bare.call()).sender).toBe(testAccount2.addr.toString())
expect((await clonedAppClient.createTransaction.call({ method: 'default_value', args: ['test value'] })).transactions[0].sender).toBe(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I had to update this test to use valid transaction params because the transaction creator now calls composer.build(), resulted in a simulate call.

Copy link
Contributor

Choose a reason for hiding this comment

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

Interesting. This is also a behavioural change. I'm actually wondering if it's better to not run resource population when using the TransactionCreator? Another thing that jumped to mind, is how would a user disable this behaviour?

Another approach is we could default to not populating resource in the transaction creator, however perform population if the user explicitly sets populateAppCallResource: true, when creating the AlgorandClient/AppClient?

stackChange: true,
stateChange: true,
},
throwOnFailure: false,
Copy link
Contributor

Choose a reason for hiding this comment

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

Would this technically be a breaking change? I'm assuming we'd previously throw on failure?

sender: testAccount,
receiver: externalClient.appAddress,
amount: (1).algo(),
signer: testAccount,
Copy link
Contributor

Choose a reason for hiding this comment

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

This shouldn't be needed, as fixture.newScope() should have added the signer account.
Does this indicate some kind of behavioural change?

Comment on lines 246 to 247
// if skipWaiting to true, do not wait
// if skipWaiting to set, wait for maxRoundsToWaitForConfirmation or 5 rounds
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// if skipWaiting to true, do not wait
// if skipWaiting to set, wait for maxRoundsToWaitForConfirmation or 5 rounds
// if skipWaiting is true, do not wait
// if skipWaiting is false, wait for maxRoundsToWaitForConfirmation or 5 rounds

t.txn.group = undefined
newAtc.addTransaction(t)
})
await newComposer.build()
Copy link
Contributor

Choose a reason for hiding this comment

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

This will technically group the transactions which the previous code does not (Is that correct?).
If we wanted to keep the same behaviour, we could build, then return a clone?

* Returns the array of transactions currently present in the given `AtomicTransactionComposer`
* @param atc The atomic transaction composer
* Returns the array of transactions currently present in the given `TransactionComposer`
* @param atc The transaction composer
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
* @param atc The transaction composer
* @param composer The transaction composer

* Builds an ABI method call transaction and any other associated transactions represented in the ABI args.
* @param includeSigner Whether to include the actual signer for the transactions.
* If you are just building transactions without signers yet then set this to `false`.
* Compose all of the transactions without signers and return the transaction objects directly along with any ABI method calls.
Copy link
Contributor

Choose a reason for hiding this comment

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

Yes I think the docs should be updated to be clearer.

* @example
* ```typescript
* const { atc, transactions, methodCalls } = await composer.rebuild()
* ```
*/
async rebuild() {
this.atc = new algosdk.AtomicTransactionComposer()
this.transactionsWithSigners = undefined
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need to also do this.signedTransactions?

If so, i think it make sense to extract this logic into a private reset() method, which can be called by send() (in the scenario where resource population/fee coverage settings are different) as well.

})

maxFees.forEach((maxFee, index) => {
this.txns[index].data.maxFee = new AlgoAmount({ microAlgos: maxFee.microAlgos })
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
this.txns[index].data.maxFee = new AlgoAmount({ microAlgos: maxFee.microAlgos })
this.txns[index].data.maxFee = maxFee

@@ -547,19 +234,19 @@ export interface BuiltTransactions {
signers: Map<number, algosdk.TransactionSigner>
}

class BuildComposerTransactionsError extends Error {
Copy link
Contributor

Choose a reason for hiding this comment

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

I like the idea, however this also become part of the public interface of the composer and an exception that a user may receive. I'd be inclined to keep as before and run another simulate. It only occurs in debug mode, which should only be enabled in testing scenarios (non prod).

// Note: This doesn't need to be a private field of this class
// It has been done this way so that another process can manipulate this values, i.e. `legacySendTransactionBridge`
// Once the legacy bridges are removed, this can be calculated on the fly
private methodCalls: Map<number, algosdk.ABIMethod> = new Map()
Copy link
Contributor

Choose a reason for hiding this comment

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

Having to keep this in sync isn't great. I'm wondering if we could instead calculate on the fly (as you mentioned above), however add a private method which the legacy bridge can call?

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants