From 73de8dc2dc1d9521d5ee823e907d8c6bfc57009a Mon Sep 17 00:00:00 2001 From: Michele Esposito Date: Wed, 24 Jan 2024 15:43:46 +0100 Subject: [PATCH] test: refactor user operations tests --- .../src/KeyringController.test.ts | 338 +++++++++++------- 1 file changed, 204 insertions(+), 134 deletions(-) diff --git a/packages/keyring-controller/src/KeyringController.test.ts b/packages/keyring-controller/src/KeyringController.test.ts index e870f4914b..9b9be3fa31 100644 --- a/packages/keyring-controller/src/KeyringController.test.ts +++ b/packages/keyring-controller/src/KeyringController.test.ts @@ -1576,156 +1576,226 @@ describe('KeyringController', () => { }); }); - describe('UserOperation methods', () => { - const addresses: Hex[] = ['0x660265edc169bab511a40c0e049cc1e33774443d']; - - it('should prepare base user operation', async () => { - await withController( - { keyringBuilders: [keyringBuilderFactory(MockErc4337Keyring)] }, - async ({ controller }) => { - const mockKeyring = (await controller.addNewKeyring( - MockErc4337Keyring.type, - )) as EthKeyring; - - jest - .spyOn(mockKeyring, 'getAccounts') - .mockResolvedValueOnce(addresses); - - const baseUserOp = { - callData: '0x7064', - initCode: '0x22ff', - nonce: '0x1', - gasLimits: { - callGasLimit: '0x58a83', - verificationGasLimit: '0xe8c4', - preVerificationGas: '0xc57c', - }, - dummySignature: '0x', - dummyPaymasterAndData: '0x', - bundlerUrl: 'https://bundler.example.com/rpc', - }; + describe('prepareUserOperation', () => { + describe('when the keyring for the given address supports prepareUserOperation', () => { + it('should prepare base user operation', async () => { + const address = '0x660265edc169bab511a40c0e049cc1e33774443d'; + stubKeyringClassWithAccount(MockErc4337Keyring, address); + await withController( + { keyringBuilders: [keyringBuilderFactory(MockErc4337Keyring)] }, + async ({ controller }) => { + const mockKeyring = (await controller.addNewKeyring( + MockErc4337Keyring.type, + )) as EthKeyring; + const baseUserOp = { + callData: '0x7064', + initCode: '0x22ff', + nonce: '0x1', + gasLimits: { + callGasLimit: '0x58a83', + verificationGasLimit: '0xe8c4', + preVerificationGas: '0xc57c', + }, + dummySignature: '0x', + dummyPaymasterAndData: '0x', + bundlerUrl: 'https://bundler.example.com/rpc', + }; + const baseTxs = [ + { + to: '', + value: '0x0', + data: '0x7064', + }, + ]; + jest + .spyOn(mockKeyring, 'prepareUserOperation') + .mockResolvedValueOnce(baseUserOp); - const baseTxs = [ - { - to: '', - value: '0x0', - data: '0x7064', - }, - ]; + const result = await controller.prepareUserOperation( + address, + baseTxs, + ); - jest - .spyOn(mockKeyring, 'prepareUserOperation') - .mockResolvedValueOnce(baseUserOp); + expect(result).toStrictEqual(baseUserOp); + expect(mockKeyring.prepareUserOperation).toHaveBeenCalledTimes(1); + expect(mockKeyring.prepareUserOperation).toHaveBeenCalledWith( + address, + baseTxs, + ); + }, + ); + }); + }); - const result = await controller.prepareUserOperation( - addresses[0], - baseTxs, - ); + describe('when the keyring for the given address does not support prepareUserOperation', () => { + it('should throw error', async () => { + const address = '0x660265edc169bab511a40c0e049cc1e33774443d'; + stubKeyringClassWithAccount(MockKeyring, address); + await withController( + { keyringBuilders: [keyringBuilderFactory(MockKeyring)] }, + async ({ controller }) => { + await controller.addNewKeyring(MockKeyring.type); - expect(result).toStrictEqual(baseUserOp); - expect(mockKeyring.prepareUserOperation).toHaveBeenCalledTimes(1); - expect(mockKeyring.prepareUserOperation).toHaveBeenCalledWith( - addresses[0], - baseTxs, - ); - }, - ); + await expect( + controller.prepareUserOperation(address, []), + ).rejects.toThrow( + KeyringControllerError.UnsupportedPrepareUserOperation, + ); + }, + ); + }); }); + }); - it('should patch an user operation', async () => { - await withController( - { keyringBuilders: [keyringBuilderFactory(MockErc4337Keyring)] }, - async ({ controller }) => { - const mockKeyring = (await controller.addNewKeyring( - MockErc4337Keyring.type, - )) as EthKeyring; - - jest - .spyOn(mockKeyring, 'getAccounts') - .mockResolvedValueOnce(addresses); - - const userOp = { - sender: '0x4584d2B4905087A100420AFfCe1b2d73fC69B8E4', - nonce: '0x1', - initCode: '0x', - callData: '0x7064', - callGasLimit: '0x58a83', - verificationGasLimit: '0xe8c4', - preVerificationGas: '0xc57c', - maxFeePerGas: '0x87f0878c0', - maxPriorityFeePerGas: '0x1dcd6500', - paymasterAndData: '0x', - signature: '0x', - }; + describe('patchUserOperation', () => { + describe('when the keyring for the given address supports patchUserOperation', () => { + it('should patch an user operation', async () => { + const address = '0x660265edc169bab511a40c0e049cc1e33774443d'; + stubKeyringClassWithAccount(MockErc4337Keyring, address); + await withController( + { keyringBuilders: [keyringBuilderFactory(MockErc4337Keyring)] }, + async ({ controller }) => { + const mockKeyring = (await controller.addNewKeyring( + MockErc4337Keyring.type, + )) as EthKeyring; + const userOp = { + sender: '0x4584d2B4905087A100420AFfCe1b2d73fC69B8E4', + nonce: '0x1', + initCode: '0x', + callData: '0x7064', + callGasLimit: '0x58a83', + verificationGasLimit: '0xe8c4', + preVerificationGas: '0xc57c', + maxFeePerGas: '0x87f0878c0', + maxPriorityFeePerGas: '0x1dcd6500', + paymasterAndData: '0x', + signature: '0x', + }; + const patch = { + paymasterAndData: '0x1234', + }; + jest + .spyOn(mockKeyring, 'patchUserOperation') + .mockResolvedValueOnce(patch); - const patch = { - paymasterAndData: '0x1234', - }; + const result = await controller.patchUserOperation(address, userOp); - jest - .spyOn(mockKeyring, 'patchUserOperation') - .mockResolvedValueOnce(patch); + expect(result).toStrictEqual(patch); + expect(mockKeyring.patchUserOperation).toHaveBeenCalledTimes(1); + expect(mockKeyring.patchUserOperation).toHaveBeenCalledWith( + address, + userOp, + ); + }, + ); + }); + }); - const result = await controller.patchUserOperation( - addresses[0], - userOp, - ); + describe('when the keyring for the given address does not support patchUserOperation', () => { + it('should throw error', async () => { + const address = '0x660265edc169bab511a40c0e049cc1e33774443d'; + stubKeyringClassWithAccount(MockKeyring, address); + await withController( + { keyringBuilders: [keyringBuilderFactory(MockKeyring)] }, + async ({ controller }) => { + await controller.addNewKeyring(MockKeyring.type); + const userOp = { + sender: '0x4584d2B4905087A100420AFfCe1b2d73fC69B8E4', + nonce: '0x1', + initCode: '0x', + callData: '0x7064', + callGasLimit: '0x58a83', + verificationGasLimit: '0xe8c4', + preVerificationGas: '0xc57c', + maxFeePerGas: '0x87f0878c0', + maxPriorityFeePerGas: '0x1dcd6500', + paymasterAndData: '0x', + signature: '0x', + }; - expect(result).toStrictEqual(patch); - expect(mockKeyring.patchUserOperation).toHaveBeenCalledTimes(1); - expect(mockKeyring.patchUserOperation).toHaveBeenCalledWith( - addresses[0], - userOp, - ); - }, - ); + await expect( + controller.patchUserOperation(address, userOp), + ).rejects.toThrow( + KeyringControllerError.UnsupportedPatchUserOperation, + ); + }, + ); + }); }); + }); - it('should sign an user operation', async () => { - await withController( - { keyringBuilders: [keyringBuilderFactory(MockErc4337Keyring)] }, - async ({ controller }) => { - const mockKeyring = (await controller.addNewKeyring( - MockErc4337Keyring.type, - )) as EthKeyring; - - jest - .spyOn(mockKeyring, 'getAccounts') - .mockResolvedValueOnce(addresses); - - const userOp = { - sender: '0x4584d2B4905087A100420AFfCe1b2d73fC69B8E4', - nonce: '0x1', - initCode: '0x', - callData: '0x7064', - callGasLimit: '0x58a83', - verificationGasLimit: '0xe8c4', - preVerificationGas: '0xc57c', - maxFeePerGas: '0x87f0878c0', - maxPriorityFeePerGas: '0x1dcd6500', - paymasterAndData: '0x', - signature: '0x', - }; + describe('signUserOperation', () => { + describe('when the keyring for the given address supports signUserOperation', () => { + it('should sign an user operation', async () => { + const address = '0x660265edc169bab511a40c0e049cc1e33774443d'; + stubKeyringClassWithAccount(MockErc4337Keyring, address); + await withController( + { keyringBuilders: [keyringBuilderFactory(MockErc4337Keyring)] }, + async ({ controller }) => { + const mockKeyring = (await controller.addNewKeyring( + MockErc4337Keyring.type, + )) as EthKeyring; + const userOp = { + sender: '0x4584d2B4905087A100420AFfCe1b2d73fC69B8E4', + nonce: '0x1', + initCode: '0x', + callData: '0x7064', + callGasLimit: '0x58a83', + verificationGasLimit: '0xe8c4', + preVerificationGas: '0xc57c', + maxFeePerGas: '0x87f0878c0', + maxPriorityFeePerGas: '0x1dcd6500', + paymasterAndData: '0x', + signature: '0x', + }; + const signature = '0x1234'; + jest + .spyOn(mockKeyring, 'signUserOperation') + .mockResolvedValueOnce(signature); - const signature = '0x1234'; + const result = await controller.signUserOperation(address, userOp); - jest - .spyOn(mockKeyring, 'signUserOperation') - .mockResolvedValueOnce(signature); + expect(result).toStrictEqual(signature); + expect(mockKeyring.signUserOperation).toHaveBeenCalledTimes(1); + expect(mockKeyring.signUserOperation).toHaveBeenCalledWith( + address, + userOp, + ); + }, + ); + }); + }); - const result = await controller.signUserOperation( - addresses[0], - userOp, - ); + describe('when the keyring for the given address does not support signUserOperation', () => { + it('should throw error', async () => { + const address = '0x660265edc169bab511a40c0e049cc1e33774443d'; + stubKeyringClassWithAccount(MockKeyring, address); + await withController( + { keyringBuilders: [keyringBuilderFactory(MockKeyring)] }, + async ({ controller }) => { + await controller.addNewKeyring(MockKeyring.type); + const userOp = { + sender: '0x4584d2B4905087A100420AFfCe1b2d73fC69B8E4', + nonce: '0x1', + initCode: '0x', + callData: '0x7064', + callGasLimit: '0x58a83', + verificationGasLimit: '0xe8c4', + preVerificationGas: '0xc57c', + maxFeePerGas: '0x87f0878c0', + maxPriorityFeePerGas: '0x1dcd6500', + paymasterAndData: '0x', + signature: '0x', + }; - expect(result).toStrictEqual(signature); - expect(mockKeyring.signUserOperation).toHaveBeenCalledTimes(1); - expect(mockKeyring.signUserOperation).toHaveBeenCalledWith( - addresses[0], - userOp, - ); - }, - ); + await expect( + controller.signUserOperation(address, userOp), + ).rejects.toThrow( + KeyringControllerError.UnsupportedSignUserOperation, + ); + }, + ); + }); }); });