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

Feat: Improve failed extension transaction handling #3349

Merged

Conversation

iamsamgibbs
Copy link
Contributor

@iamsamgibbs iamsamgibbs commented Oct 16, 2024

Description

This PR aims to improve failed transactions when installing / enabling / assigning permissions for extensions.

Currently, when installing an extension it will call the extensionInstallAndEnable saga which includes transactions for install, initialise and setUserRoles (and will conditionally call them depending on the extension configuration).

However, if either the initalise or setUserRoles transaction fails or is rejected, the UI will not handle this error state correctly and will appear as though the extension has not been installed (even though the install transaction succeeded).

This PR aims to resolve this by adding error steps to the extensionInstallAndEnable saga and pick these up in the error handler to update the UI as appropriate.

Whilst working on this, I discovered the same issue affects the extensionEnable saga and related handlers. This PR applies the same changes to the extensionEnable saga and the places from which that is called.

I also discovered an issue when re-enabling an extension which I have created a new issue for (#3430) and left a TODO in this PR which suggests a starting point for a potential fix.

Testing

This one is going to be a pain to test I am afraid! Before anything else, switch to the metamask wallet as we need to be able to reject specific transactions.

There a three extensions we will be testing with as the install / enable steps work slightly differently for each.

Reputation Weighted Extension

This extension has an install step which calls only the install transaction. It then has an entirely separate enable step which calls the initialise and setUserRoles transactions. This is the only extension which explicitly has this extra enable step.

Let us first test with the intended use.

  • Step 1 - Navigate to: http://localhost:9091/planex/extensions/VotingReputation
  • Step 2 - Click the "Install" button and accept the install transaction. The transaction should succeed, the success toast should appear and the tab should automatically switch to the "Extension settings" tab.
  • Step 3 - Select a governance style and click the "Enable" button. Accept both the initialise and setUserRoles transactions. The transactions should succeed, the install success toast should appear and the tab should automatically switch to the "Overview" tab.

Now let us test rejecting some of the transactions. First we must remove the extension.

  • Step 4 - Deprecate the extension.
  • Step 5 - Uninstall the extension.

Okay, we will reject each transaction.

  • Step 6 - Click the "Install" button and reject the install transaction. The transaction should fail, the install error toast should appear.

  • Step 7 - Click the "Install" button and accept the install transaction. Select a governance style and click the "Enable" button. This time, reject the initialise transaction. The setUserRoles transaction should not appear at all, the initialise transaction should fail, an enable error toast should appear.

  • Step 8 - Click the "Enable" button again. Accept the initialise transaction and reject the setUserRoles transaction. The initialise transaction should succeed, the setUserRole transaction should fail, the "Failed to assign extension permissions" toast should appear. Also note that the extension is intialised, the "Missing permissions banner" should appear.

  • Step 9 - Click "Enable permissions" in the "Missing permissions banner". Reject the setUserRoles transaction. The banner should remain visible.

  • Step 10 - Click "Enable permissions" in the "Missing permissions banner". Accept the transaction. The banner should switch to the green success banner.

Multi-sig Extension

This extension has only the install step, but calls both the install and setUserRoles transactions. It has no initialise transaction.

Feel free to test with the intended use to make sure it still functions properly, but I will only detail the testing steps which cover the new functionality.

  • Step 1 - Navigate to: http://localhost:9091/planex/extensions/MultisigPermissions

  • Step 2 - Click the "Install" button and reject the install transaction. The transaction should fail, the install error toast should appear.

  • Step 3 - Click the "Install" button. Accept the install transaction and reject the setUserRoles transaction. The install transaction should succeed, the setUserRoles transaction should fail, the install success toast should show (as technically the install did succeed), but also the assign extension permissions error toast should show. The tab should automatically switch to the "Extension settings" tab and the "Missing permissions banner" should show.

  • Step 4 - Change the threshold type to a fixed threshold with 2 approvals, and click the "Save changes" button. Accept the multicall transaction. The "Missing permissions banner" should remain visible and the tab should not change.

Feel free to retest the Manage permissions banner functionality here too if you wish.

Staking Advanced Payments

This extension has only the install step and calls all 3 of the install, initialise and setUserRoles transactions.

  • Step 1 - Navigate to: http://localhost:9091/planex/extensions/StakedExpenditure

  • Step 2 - This extension is installed by default, so deprecate and uninstall the extension.

  • Step 3 - Rejecting the install transaction should work exactly the same as the last two extensions, so let us skip that step. Click the "Install" button. Accept the install transaction and reject the initialise transaction. The install transaction should succeed, the initialise transaction should fail and the setUserRoles transaction should not get called at all. The install success toast should show, but also the enable extension error toast should show. The tab should automatically switch to the "Extension settings" tab. The "Missing permissions banner" should not yet show at this point as the extension is not yet enabled. This is different than the multi-sig extension as the multi-sig extension does not have the initialise step.

  • Step 4 - Click the "Enable" button. Reject the initialise transaction. The setUserRoles transaction should not appear at all, the initialise transaction should fail, an enable error toast should appear.

  • Step 5 - Click the "Enable" button again. Accept the initialise transaction and reject the setUserRoles transaction. The initialise transaction should succeed, the setUserRole transaction should fail, the "Failed to assign extension permissions" error toast should appear. Also note that the extension is intialised, the "Missing permissions banner" should appear.

From here, test the missing permissions banner functionality if you wish.

Final bit of testing, if you have made it this far, have a drink to sustain you for the last bit! ☕ We will test accepting the install and initialise transactions, but rejecting the setUserRoles transaction.

  • Step 6 - Remove the extension (deprecate and uninstall)
  • Step 7 - Click the "Install" button. Accept the install transaction. Accept the initialise transaction. Reject the setUserRoles transaction. The install success toast should show, but also the extension permissions error toast should show. The tab should automatically switch to the "Extension settings" tab. This time the "missing permissions banner" should show as the extension has been enabled this time around.

Further testing: Feel free to try and break this in anyway you can but the testing steps are hopefully thorough enough that this is not possible. There is an unrelated issue on master related to deprecating and re-enabling where the missing permissions banner will incorrectly show (#3430).

Diffs

New stuff

  • Added error flags to extensionInstallAndEnable and extensionEnable sagas
  • Added new handleWaitingForDbAfterFormCompletion util

Changes 🏗

  • waitForDbAfterExtensionAction handles new error flags
  • useInstall hook now uses handleWaitingForDbAfterFormCompletion util in onSuccess and onError handlers
  • ExtensionsSettingsForm uses handleWaitingForDbAfterFormCompletion util in onSuccess and onError handlers

TODO

Resolves #2754
Contributes to #3337

@iamsamgibbs iamsamgibbs self-assigned this Oct 16, 2024
Comment on lines 121 to 136
await waitForDbAfterExtensionAction({
method: ExtensionMethods.INSTALL,
refetchExtensionData,
initialiseTransactionFailed,
setUserRolesTransactionFailed,
});

toast.success(
<Toast
type="success"
title={{ id: 'extensionInstall.toast.title.success' }}
description={{
id: 'extensionInstall.toast.description.success',
}}
/>,
);
Copy link
Contributor

Choose a reason for hiding this comment

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

@iamsamgibbs if there could be some errors while either initialising the transaction or setting the user roles, does it make sense to refetch the extension action and show the success toast?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In the case where the initialise transaction fails, I think you might be right that we don't need to refetch the extension data.

In the case where the setUserRole transaction fails, we still want to refetch the extension data to check that the extension has been enabled still.

As for the success toast, it's a bit of a confusing ones as technically the install was successful, but the initalise / setUserRoles transactions failed, so I've opted to still show the install success but also show a failure toast for initalise / setUserRoles.

Copy link
Contributor

Choose a reason for hiding this comment

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

@iamsamgibbs I really like your approach with the error steps 🙌 though I'm wondering if it is not more clear to set the initialiseTransactionFailed and setUserRolesTransactionFailed flags directly?

yield waitForTxResult(installExtension.channel);
} catch (error) {
// Declare an error step for the error handler
error.step = ExtensionInstallAndEnableErrorStep.InstallExtension;
Copy link
Contributor

Choose a reason for hiding this comment

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

we could throw specific errors and then have typeguards too
Like for example a ExtensionInstallError which has a step property like this component I just randomly pulled up
image

and then we can check the error like this:
if (error instanceof ExtensionInstallError)

and the step property will be defined

Maybe it's overkill, just wanted to drop this here :D

@iamsamgibbs iamsamgibbs force-pushed the feat/2754-improve-failed-extension-transaction-handling branch from 5f905ce to 4380ba0 Compare October 21, 2024 12:35
Comment on lines +49 to +86
export const getExtensionSettingsDefaultValues = (
extensionData: AnyExtensionData,
): object => {
const { initializationParams = [] } = extensionData;
const defaultValues = getInitializationDefaultValues(initializationParams);

if (!isInstalledExtensionData(extensionData)) {
return defaultValues;
}

switch (extensionData.extensionId) {
case Extension.StakedExpenditure: {
return {
stakeFraction: extensionData?.params?.stakedExpenditure?.stakeFraction
? convertFractionToEth(
extensionData.params.stakedExpenditure.stakeFraction,
)
: String(defaultValues.stakeFraction),
};
}
case Extension.MultisigPermissions: {
const { colonyThreshold: globalThreshold } =
extensionData.params?.multiSig ?? {};

return {
thresholdType:
globalThreshold !== undefined
? getGlobalThresholdType(globalThreshold)
: MultiSigThresholdType.MAJORITY_APPROVAL,
globalThreshold: globalThreshold ?? 0,
domainThresholds: [],
} satisfies MultiSigSettingsFormValues;
}
default: {
return defaultValues;
}
}
};
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is just moving an existing function up to please the liner. Below here are the actual changes.

Copy link
Member

@rdig rdig left a comment

Choose a reason for hiding this comment

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

You weren't kidding that this was finniky to test, but managed to do so in the end :)

Everything seems to be working as expected, so nice work as always 💯

Voting Reputation

Screenshot from 2024-10-23 15-35-25
Screenshot from 2024-10-23 15-35-38
Screenshot from 2024-10-23 15-36-40
Screenshot from 2024-10-23 15-36-44
Screenshot from 2024-10-23 15-37-19
Screenshot from 2024-10-23 15-37-28
Screenshot from 2024-10-23 15-37-43
Screenshot from 2024-10-23 15-39-31
Screenshot from 2024-10-23 15-40-33
Screenshot from 2024-10-23 15-41-52
Screenshot from 2024-10-23 15-42-05
Screenshot from 2024-10-23 15-42-14
Screenshot from 2024-10-23 15-42-28

Multisig

Screenshot from 2024-10-23 15-49-32
Screenshot from 2024-10-23 15-49-49
Screenshot from 2024-10-23 15-49-53
Screenshot from 2024-10-23 15-50-31

*Staking

Screenshot from 2024-10-23 15-54-40
Screenshot from 2024-10-23 15-54-54
Screenshot from 2024-10-23 15-55-04
Screenshot from 2024-10-23 15-59-20
Screenshot from 2024-10-23 16-00-29
Screenshot from 2024-10-23 16-00-56

Copy link
Contributor

@bassgeta bassgeta left a comment

Choose a reason for hiding this comment

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

This was a lot to untangle damn, really nice job!
It covers so many edge cases and the comments are quite welcome since all of our extension enabling has so much proprietary logic :')
Thanks for the testing steps 💯

Voting reputation

Installing the voting reputation extension works ✔️
image
Rejecting installation ✔️
image
Failed initialisation ✔️
image
Rejected set user roles ✔️
image
Rejection from the banner ✔️
image
Everything goes through when signing the tx ✔️
image

Multisig

Rejected the install tx ✔️
image
Signed the enable step but rejected set user roles ✔️
image
The banner is shown ✔️
image
Settings still work ✔️
image

Staking advanced payments

Rejected initialise ✔️
image
Rejected set user roles ✔️
image
Accept install, initialise and reject set user roles ✔️
image

🚢

Copy link
Contributor

@mmioana mmioana left a comment

Choose a reason for hiding this comment

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

Such a nice solution to look at code-wise and also to test 💯 Really nice job here @iamsamgibbs 🙌 🥇

Went through the testing steps for the Reputation Weighted Extension extension

Screenshot 2024-10-30 at 13 12 28
Screenshot 2024-10-30 at 13 12 33
Screenshot 2024-10-30 at 13 12 58
Screenshot 2024-10-30 at 13 13 59
Screenshot 2024-10-30 at 13 14 18
Screenshot 2024-10-30 at 13 14 40
Screenshot 2024-10-30 at 13 15 01
Screenshot 2024-10-30 at 13 15 16
Screenshot 2024-10-30 at 13 15 22
Screenshot 2024-10-30 at 13 15 33
Screenshot 2024-10-30 at 13 15 51
Screenshot 2024-10-30 at 13 16 01

Then went through the testing steps for Multi-sig
Screenshot 2024-10-30 at 13 16 51
Screenshot 2024-10-30 at 13 17 20
Screenshot 2024-10-30 at 13 17 58
Screenshot 2024-10-30 at 13 18 07
Screenshot 2024-10-30 at 13 18 52
Screenshot 2024-10-30 at 13 19 05

And finally got to the Staking Advanced Payments extension - here I also tested rejecting the deprecate and uninstall transactions and everything was working as expected
Screenshot 2024-10-30 at 13 19 50
Screenshot 2024-10-30 at 13 20 05
Screenshot 2024-10-30 at 13 20 18
Screenshot 2024-10-30 at 13 20 34
Screenshot 2024-10-30 at 13 20 51
Screenshot 2024-10-30 at 13 21 43
Screenshot 2024-10-30 at 13 21 54
Screenshot 2024-10-30 at 13 22 16
Screenshot 2024-10-30 at 13 22 42
Screenshot 2024-10-30 at 13 23 17
Screenshot 2024-10-30 at 13 23 47
Screenshot 2024-10-30 at 13 23 56

All nice and clean, let's get it merged 🎉

@iamsamgibbs iamsamgibbs merged commit 41132c8 into master Oct 30, 2024
4 of 6 checks passed
@iamsamgibbs iamsamgibbs deleted the feat/2754-improve-failed-extension-transaction-handling branch October 30, 2024 13:13
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.

[Multi-sig] Extension is not enabled if "Enable permission" transaction using Metamask is rejected
4 participants