-
Notifications
You must be signed in to change notification settings - Fork 11
Composer integration #457
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: decoupling
Are you sure you want to change the base?
Composer integration #457
Conversation
| return result | ||
| })() | ||
| : undefined, | ||
| rejectVersion: bigIntCodec.decodeOptional(transactionDto.aprv), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| rejectVersion?: bigint | |
| rejectVersion?: number |
| apep?: number | ||
|
|
||
| /** Reject version */ | ||
| aprv?: bigint | number |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| aprv?: bigint | number | |
| aprv?: number |
src/transaction/legacy-bridge.ts
Outdated
| // 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)) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
src/types/composer.ts
Outdated
| * 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. |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
src/types/composer.ts
Outdated
|
|
||
| const builtTransactions = await this.buildTransactions() | ||
| const transactions = |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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:
buildTransactionsexisted in the composer. It does similar functionality.buildexisted in the composer, but private. Inmain, resource population + fee coverage happen insend, for this version, I lifted them tobuild
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 }) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
src/types/composer.ts
Outdated
| return ( | ||
| ctxn.type === 'appCall' || | ||
| ctxn.type === 'methodCall' || | ||
| (ctxn.type === 'txnWithSigner' && ctxn.data.txn.type === TransactionType.AppCall) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about asyncTxn?
There was a problem hiding this comment.
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.
db98a4b to
09000c2
Compare
src/types/composer.ts
Outdated
| @@ -547,19 +234,19 @@ export interface BuiltTransactions { | |||
| signers: Map<number, algosdk.TransactionSigner> | |||
| } | |||
|
|
|||
| class BuildComposerTransactionsError extends Error { | |||
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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).
src/types/app-client.spec.ts
Outdated
| 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( |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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?
src/transaction/transaction.spec.ts
Outdated
| sender: testAccount, | ||
| receiver: externalClient.appAddress, | ||
| amount: (1).algo(), | ||
| signer: testAccount, |
There was a problem hiding this comment.
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?
src/transaction/transaction.ts
Outdated
| // if skipWaiting to true, do not wait | ||
| // if skipWaiting to set, wait for maxRoundsToWaitForConfirmation or 5 rounds |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| // 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() |
There was a problem hiding this comment.
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?
src/transaction/transaction.ts
Outdated
| * 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| * @param atc The transaction composer | |
| * @param composer The transaction composer |
src/types/composer.ts
Outdated
| * 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. |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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 }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| this.txns[index].data.maxFee = new AlgoAmount({ microAlgos: maxFee.microAlgos }) | |
| this.txns[index].data.maxFee = maxFee |
src/types/composer.ts
Outdated
| @@ -547,19 +234,19 @@ export interface BuiltTransactions { | |||
| signers: Map<number, algosdk.TransactionSigner> | |||
| } | |||
|
|
|||
| class BuildComposerTransactionsError extends Error { | |||
There was a problem hiding this comment.
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() |
There was a problem hiding this comment.
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?
Proposed Changes