diff --git a/packages/snap/src/core/handlers/onKeyringRequest/Keyring.test.ts b/packages/snap/src/core/handlers/onKeyringRequest/Keyring.test.ts index 234cc270..ec4770c5 100644 --- a/packages/snap/src/core/handlers/onKeyringRequest/Keyring.test.ts +++ b/packages/snap/src/core/handlers/onKeyringRequest/Keyring.test.ts @@ -569,6 +569,23 @@ describe('SolanaKeyring', () => { 'Error creating account: Error listing accounts', ); }); + + describe('state consistency', () => { + it('rolls back the account creation operation if the client fails to be informed', async () => { + const emitEventSpy = jest.spyOn(keyring, 'emitEvent'); + const mockErrorMessage = + 'Could not digest event KeyringEvent.AccountCreated'; + emitEventSpy.mockRejectedValueOnce(new Error(mockErrorMessage)); + const stateDeleteKeySpy = jest.spyOn(mockState, 'deleteKey'); + + await expect(keyring.createAccount()).rejects.toThrow( + `Error creating account: ${mockErrorMessage}`, + ); + + // We should remove the account from the snap's state to ensure state consistency between the snap and the client + expect(stateDeleteKeySpy).toHaveBeenCalledTimes(3); + }); + }); }); describe('deleteAccount', () => { diff --git a/packages/snap/src/core/handlers/onKeyringRequest/Keyring.ts b/packages/snap/src/core/handlers/onKeyringRequest/Keyring.ts index 3cb36a1a..b64fa1e1 100644 --- a/packages/snap/src/core/handlers/onKeyringRequest/Keyring.ts +++ b/packages/snap/src/core/handlers/onKeyringRequest/Keyring.ts @@ -286,14 +286,16 @@ export class SolanaKeyring implements Keyring { ], }; + const keyringAccount: KeyringAccount = + asStrictKeyringAccount(solanaKeyringAccount); + + // Save the account in the snap state await this.#state.setKey( `keyringAccounts.${solanaKeyringAccount.id}`, solanaKeyringAccount, ); - const keyringAccount: KeyringAccount = - asStrictKeyringAccount(solanaKeyringAccount); - + // Inform the client about the new account await this.emitEvent(KeyringEvent.AccountCreated, { /** * We can't pass the `keyringAccount` object because it contains the index @@ -317,6 +319,14 @@ export class SolanaKeyring implements Keyring { metamask: metamaskOptions, } : {}), + }).catch(async (error: any) => { + // Rollback the saving of the account in the snap state to ensure data consistency between the snap and the client + this.#logger.warn( + 'Could not inform the client about the account creation. Rolling back the account creation operation.', + { error }, + ); + await this.#deleteAccountFromState(id); + throw error; }); await endTrace(this.#traceName); @@ -324,8 +334,6 @@ export class SolanaKeyring implements Keyring { return keyringAccount; } catch (error: any) { this.#logger.error({ error }, 'Error creating account'); - await this.#deleteAccountFromState(id); - throw new Error(`Error creating account: ${error.message}`); } }