Skip to content
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

fix: transaction-controller – approveTransaction should not throw away raw signed transaction #4255

Merged
merged 5 commits into from
May 16, 2024

Conversation

dbrans
Copy link
Contributor

@dbrans dbrans commented May 5, 2024

Explanation

Changed approveTransaction to use #updateTransactionInternal.
Addresses MetaMask/metamask-extension#24183 – Manually verified in extension.

@matthewwalsh0 observed:
The implementation of approveTransaction is throwing away the raw signed transaction that signTransaction was adding to the metadata state by holding onto a stale version of the tx metadata.

function approveTransaction(id) {
  const updatedMetadata = ...
  
  // signTransaction calls updateTransaction
  // So any existing references to the txMetadata will be stale.
  this.signTransaction(updatedMetadata)
  updateTransaction(updatedMetadata) // BUG: updatedMetadata is now stale.
  //...

Long-term @matthewwalsh0 recommends replaying updateTransaction with the more modern updateTransactionInternal everywhere to avoid bugs like this.

References

Changelog

@metamask/transaction-controller

  • FIXED: approveTransaction was throwing away the raw signed transaction that signTransaction was adding to the metadata state by holding onto a stale version of the tx metadata.

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've highlighted breaking changes using the "BREAKING" category above as appropriate

@dbrans
Copy link
Contributor Author

dbrans commented May 5, 2024

@metamaskbot publish-preview

Copy link
Contributor

github-actions bot commented May 5, 2024

Preview builds have been published. See these instructions for more information about preview builds.

Expand for full list of packages and versions.
{
  "@metamask-previews/accounts-controller": "14.0.0-preview-3301ad9",
  "@metamask-previews/address-book-controller": "4.0.1-preview-3301ad9",
  "@metamask-previews/announcement-controller": "6.1.0-preview-3301ad9",
  "@metamask-previews/approval-controller": "6.0.2-preview-3301ad9",
  "@metamask-previews/assets-controllers": "29.0.0-preview-3301ad9",
  "@metamask-previews/base-controller": "5.0.2-preview-3301ad9",
  "@metamask-previews/build-utils": "2.0.1-preview-3301ad9",
  "@metamask-previews/composable-controller": "6.0.1-preview-3301ad9",
  "@metamask-previews/controller-utils": "9.1.0-preview-3301ad9",
  "@metamask-previews/ens-controller": "10.0.1-preview-3301ad9",
  "@metamask-previews/eth-json-rpc-provider": "3.0.2-preview-3301ad9",
  "@metamask-previews/gas-fee-controller": "15.1.1-preview-3301ad9",
  "@metamask-previews/json-rpc-engine": "8.0.2-preview-3301ad9",
  "@metamask-previews/json-rpc-middleware-stream": "7.0.1-preview-3301ad9",
  "@metamask-previews/keyring-controller": "16.0.0-preview-3301ad9",
  "@metamask-previews/logging-controller": "3.0.1-preview-3301ad9",
  "@metamask-previews/message-manager": "8.0.2-preview-3301ad9",
  "@metamask-previews/name-controller": "6.0.1-preview-3301ad9",
  "@metamask-previews/network-controller": "18.1.0-preview-3301ad9",
  "@metamask-previews/notification-controller": "5.0.1-preview-3301ad9",
  "@metamask-previews/permission-controller": "9.0.2-preview-3301ad9",
  "@metamask-previews/permission-log-controller": "2.0.1-preview-3301ad9",
  "@metamask-previews/phishing-controller": "9.0.2-preview-3301ad9",
  "@metamask-previews/polling-controller": "6.0.2-preview-3301ad9",
  "@metamask-previews/preferences-controller": "11.0.0-preview-3301ad9",
  "@metamask-previews/queued-request-controller": "0.9.0-preview-3301ad9",
  "@metamask-previews/rate-limit-controller": "5.0.1-preview-3301ad9",
  "@metamask-previews/selected-network-controller": "12.0.1-preview-3301ad9",
  "@metamask-previews/signature-controller": "16.0.0-preview-3301ad9",
  "@metamask-previews/transaction-controller": "28.1.1-preview-3301ad9",
  "@metamask-previews/user-operation-controller": "9.0.0-preview-3301ad9"
}

@dbrans dbrans marked this pull request as ready for review May 5, 2024 16:59
@dbrans dbrans requested a review from a team as a code owner May 5, 2024 16:59

if (status === TransactionStatus.submitted) {
if (updatedTransactionMeta.status === TransactionStatus.submitted) {
Copy link
Member

Choose a reason for hiding this comment

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

Do we need to change these?

The logic here is based on the original input so the merged metadata shouldn't be relevant.

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 added this for typescript type checking: A TransactionMeta only has a submittedType when its status is submitted. It only has an error when status is failed.

let releaseNonceLock: (() => void) | undefined;

let txMeta = this.getTransactionOrThrow(transactionId);
Copy link
Member

Choose a reason for hiding this comment

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

Can we keep this called transactionMeta for readability and to minimise the diff?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

nonce,
chainId,
gasLimit: txParams.gas,
...(isEIP1559 && {
Copy link
Member

Choose a reason for hiding this comment

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

It seems that previously we first did an update with the nonce, chainId, gasLimit, and status.

Then the estimatedBaseFee and type were updated by the signTransaction method which also does additional updates.

Then later, we update the hash, status and submittedTime.

For the sake of risk and matching state history, should we match that now and ensure the same updates happen in the same order?

It also ensures we at least get the approved status even if the preTxBalance query failed for example.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Matt, based on your comment, I took a closer look at what is being updated and when. It's not straightforward.

Before this PR:

Update 1:

  • status, nonce, chainid are updated
  • gasLimit: looks like it's being set but it is not. It's actually set on baseTxParams which is not attached to updatedTransactionMeta and so is not stored.

Update 2 (in signTransaction):

  • status, r, s, v are updated
  • gasLimit, estimatedBaseFee, type: look like they're being updated. They're actually set on txParams. txParams is signed, but never attached to updatedTransactionMeta. Wait... estimatedBaseFee is already there from the original txParams. So just "type" and “gasLimit” are in limbo: they are on the signed txParams (rawTx) but not on the updatedTransactionMeta in storage.

Update 3 (in signTransaction):

  • rawTx is added

[At this point, before publishing, preTxBalance is fetched]

Update 4:

  • status, hash, submittedTime, preTxBalance are updated
  • rawTx, r, s, v are all lost in this update because updatedTransactionMeta is now stale. This was the original reason for this PR.

Based on your suggestion, I made some changes to closer match the order of operations, while addressing inconsistencies between the signed txParams and what is in storage. I also endeavoured to make updates more obvious.

After this PR:

Update 1:

  • status, nonce, chainid, gasLimit, type are updated. estimatedBaseFee is already there from the original txParams.
  • This is the biggest change in what gets saved: the txParams that what will be signed is the one that is saved.

Update 2 (in signTransaction):

  • status, r, s, v are updated

Update 3 (in signTransaction):

  • rawTx is added

[At this point, before publishing, preTxBalance is fetched]

Update 4:

  • status, hash, submittedTime, preTxBalance are updated

@@ -3611,8 +3610,8 @@ export class TransactionController extends BaseController<
note,
skipHistory,
}: { transactionId: string; note?: string; skipHistory?: boolean },
callback: (transactionMeta: TransactionMeta) => TransactionMeta | void,
) {
mutationFn: (transactionMeta: TransactionMeta) => TransactionMeta | void,
Copy link
Member

Choose a reason for hiding this comment

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

This was for consistency with the update method which refers to the argument as callback.

Plus it's not necessarily always a mutation as you can return a fresh metadata if that is easier.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

Copy link
Contributor

@vinistevam vinistevam left a comment

Choose a reason for hiding this comment

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

Great PR @dbrans !

@dbrans
Copy link
Contributor Author

dbrans commented May 16, 2024

@metamaskbot publish-preview

Copy link
Contributor

Preview builds have been published. See these instructions for more information about preview builds.

Expand for full list of packages and versions.
{
  "@metamask-previews/accounts-controller": "14.0.0-preview-a6633f22",
  "@metamask-previews/address-book-controller": "4.0.1-preview-a6633f22",
  "@metamask-previews/announcement-controller": "6.1.0-preview-a6633f22",
  "@metamask-previews/approval-controller": "6.0.2-preview-a6633f22",
  "@metamask-previews/assets-controllers": "29.0.0-preview-a6633f22",
  "@metamask-previews/base-controller": "5.0.2-preview-a6633f22",
  "@metamask-previews/build-utils": "2.0.1-preview-a6633f22",
  "@metamask-previews/composable-controller": "6.0.1-preview-a6633f22",
  "@metamask-previews/controller-utils": "9.1.0-preview-a6633f22",
  "@metamask-previews/ens-controller": "10.0.1-preview-a6633f22",
  "@metamask-previews/eth-json-rpc-provider": "3.0.2-preview-a6633f22",
  "@metamask-previews/gas-fee-controller": "15.1.2-preview-a6633f22",
  "@metamask-previews/json-rpc-engine": "8.0.2-preview-a6633f22",
  "@metamask-previews/json-rpc-middleware-stream": "7.0.1-preview-a6633f22",
  "@metamask-previews/keyring-controller": "16.0.0-preview-a6633f22",
  "@metamask-previews/logging-controller": "3.0.1-preview-a6633f22",
  "@metamask-previews/message-manager": "8.0.2-preview-a6633f22",
  "@metamask-previews/name-controller": "6.0.1-preview-a6633f22",
  "@metamask-previews/network-controller": "18.1.0-preview-a6633f22",
  "@metamask-previews/notification-controller": "5.0.1-preview-a6633f22",
  "@metamask-previews/permission-controller": "9.0.2-preview-a6633f22",
  "@metamask-previews/permission-log-controller": "2.0.1-preview-a6633f22",
  "@metamask-previews/phishing-controller": "9.0.2-preview-a6633f22",
  "@metamask-previews/polling-controller": "6.0.2-preview-a6633f22",
  "@metamask-previews/preferences-controller": "11.0.0-preview-a6633f22",
  "@metamask-previews/profile-sync-controller": "0.0.0-preview-a6633f22",
  "@metamask-previews/queued-request-controller": "0.10.0-preview-a6633f22",
  "@metamask-previews/rate-limit-controller": "5.0.1-preview-a6633f22",
  "@metamask-previews/selected-network-controller": "13.0.0-preview-a6633f22",
  "@metamask-previews/signature-controller": "16.0.0-preview-a6633f22",
  "@metamask-previews/transaction-controller": "29.0.0-preview-a6633f22",
  "@metamask-previews/user-operation-controller": "10.0.0-preview-a6633f22"
}

@dbrans dbrans merged commit 0119015 into main May 16, 2024
143 checks passed
@dbrans dbrans deleted the dbrans/fix-approve-tx branch May 16, 2024 13:15
@dbrans dbrans mentioned this pull request May 16, 2024
dbrans added a commit that referenced this pull request May 17, 2024
## Explanation

Patch release of TransactionController to fix rawTx being dropped from
Tx Metadata #4255.

## References

* Related MetaMask/metamask-extension#24183

---------

Co-authored-by: Mark Stacey <markjstacey@gmail.com>
@keithchew
Copy link

I caught this regression and posted in metamask-extension a while back, just wanted to link it from here, so that one can also be closed:

MetaMask/metamask-extension#24359

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

None yet

4 participants