import { describe, it, expect, vi, beforeEach } from 'vitest'; import { PasskeyProvider } from './passkey-provider'; import * as WebAuthnAuth from '../core/web-authn'; import { querySharedWallets } from '../graph/wallets'; import { encodeSignatureBytes } from '@prex0/prex-structs'; import { PrexApiService } from '../api'; import { zeroHash } from 'viem'; const MOCK_ADDRESS = '0x1234000000000000000000000000000000000000'; const MOCK_SHARED_ADDRESS = '0x1234000000000000000000000000000000000001'; vi.mock('../graph/wallets', () => { return { querySharedWallets: vi.fn(), }; }); describe('PasskeyProvider', () => { let provider: PasskeyProvider; beforeEach(() => { provider = new PasskeyProvider( { chainId: 1 } as PrexApiService, MOCK_ADDRESS, 0, ['1', '2', '3'] ); }); describe('request', () => { it('should throw an error for unknown method', async () => { await expect( provider.request({ method: 'unknown', params: [], }) ).rejects.toThrow('unknown method'); }); it('should handle eth_accounts method', async () => { const result = await provider.request({ method: 'eth_accounts', params: [], }); expect(result).toEqual([MOCK_ADDRESS]); }); it('should handle eth_chainId method', async () => { const result = await provider.request({ method: 'eth_chainId', params: [], }); expect(result).toBe('0x1'); }); it('should handle eth_sign method', async () => { const mockSignature = '0xmocksignature'; vi.spyOn(WebAuthnAuth, 'signByPasskey').mockResolvedValue({ userHandle: '0x123', name: 'mockName', signature: mockSignature, }); const result = await provider.request({ method: 'eth_sign', params: [MOCK_ADDRESS, '0xmockhash'], }); expect(WebAuthnAuth.signByPasskey).toHaveBeenCalled(); expect(result).toBe( '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000007mocksignature000000000000000000000000000000000000000000000000000' ); }); it('should handle eth_sign method for shared wallet', async () => { const mockSignature = '0x11223344556677889900'; vi.spyOn(WebAuthnAuth, 'signByPasskey').mockResolvedValue({ userHandle: '0x123', name: 'mockName', signature: mockSignature, }); // Mock the querySharedWallets function vi.mocked(querySharedWallets).mockResolvedValue({ sharedWallets: [ { address: MOCK_SHARED_ADDRESS, index: 1, isRemoved: false, owners: [ { address: MOCK_ADDRESS, index: 1, isRemoved: false, }, ], }, ], }); const result = await provider.request({ method: 'eth_sign', params: [MOCK_SHARED_ADDRESS, zeroHash], }); expect(WebAuthnAuth.signByPasskey).toHaveBeenCalled(); expect(result).toBe( encodeSignatureBytes(1n, encodeSignatureBytes(0n, mockSignature)) ); }); it('should handle eth_signTypedData_v4 method', async () => { const mockSignature = '0xmocksignature'; vi.spyOn(WebAuthnAuth, 'signByPasskey').mockResolvedValue({ userHandle: '0x123', name: 'mockName', signature: mockSignature, }); const result = await provider.request({ method: 'eth_signTypedData_v4', params: [ MOCK_ADDRESS, { types: { MockType: [ { name: 'MockType', type: 'string', }, ], }, primaryType: 'MockType', message: { MockType: 'mockValue', }, domain: { name: 'mockName', version: '1.0.0', chainId: 1, verifyingContract: MOCK_ADDRESS, }, }, ], }); expect(WebAuthnAuth.signByPasskey).toHaveBeenCalled(); expect(result).toBe( '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000007mocksignature000000000000000000000000000000000000000000000000000' ); }); }); });