import { Test, TestingModule } from '@nestjs/testing'; import { ConfigService } from '@nestjs/config'; import { WalletGeneratorService } from './wallet-generator.service'; import { ChainType, Mnemonic } from '@/domain/value-objects'; describe('WalletGeneratorService', () => { let service: WalletGeneratorService; let configService: ConfigService; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ providers: [ WalletGeneratorService, { provide: ConfigService, useValue: { get: jest.fn().mockReturnValue('test-salt'), }, }, ], }).compile(); service = module.get(WalletGeneratorService); configService = module.get(ConfigService); }); it('should be defined', () => { expect(service).toBeDefined(); }); describe('generateWalletSystem', () => { it('应该生成完整的钱包系统', () => { const result = service.generateWalletSystem({ userId: '12345', deviceId: 'test-device-id', }); expect(result).toBeDefined(); expect(result.mnemonic).toBeDefined(); expect(result.mnemonic).toBeInstanceOf(Mnemonic); expect(result.wallets).toBeDefined(); expect(result.wallets.size).toBe(3); }); it('应该为所有链生成钱包地址', () => { const result = service.generateWalletSystem({ userId: '12345', deviceId: 'test-device-id', }); expect(result.wallets.has(ChainType.KAVA)).toBe(true); expect(result.wallets.has(ChainType.DST)).toBe(true); expect(result.wallets.has(ChainType.BSC)).toBe(true); }); it('生成的 KAVA 地址应该有正确的格式', () => { const result = service.generateWalletSystem({ userId: '12345', deviceId: 'test-device-id', }); const kavaWallet = result.wallets.get(ChainType.KAVA); expect(kavaWallet).toBeDefined(); expect(kavaWallet!.address).toMatch(/^kava1[a-z0-9]{38}$/); }); it('生成的 DST 地址应该有正确的格式', () => { const result = service.generateWalletSystem({ userId: '12345', deviceId: 'test-device-id', }); const dstWallet = result.wallets.get(ChainType.DST); expect(dstWallet).toBeDefined(); expect(dstWallet!.address).toMatch(/^dst1[a-z0-9]{38}$/); }); it('生成的 BSC 地址应该有正确的格式', () => { const result = service.generateWalletSystem({ userId: '12345', deviceId: 'test-device-id', }); const bscWallet = result.wallets.get(ChainType.BSC); expect(bscWallet).toBeDefined(); expect(bscWallet!.address).toMatch(/^0x[a-fA-F0-9]{40}$/); }); it('每次生成的钱包应该不同', () => { const result1 = service.generateWalletSystem({ userId: '11111', deviceId: 'test-device-id-1', }); const result2 = service.generateWalletSystem({ userId: '22222', deviceId: 'test-device-id-2', }); expect(result1.mnemonic.value).not.toBe(result2.mnemonic.value); expect(result1.wallets.get(ChainType.KAVA)!.address).not.toBe( result2.wallets.get(ChainType.KAVA)!.address ); }); }); describe('recoverWalletSystem', () => { it('应该使用助记词恢复钱包系统', () => { // 先生成一个钱包系统 const original = service.generateWalletSystem({ userId: '12345', deviceId: 'test-device-id', }); // 使用助记词恢复 const recovered = service.recoverWalletSystem({ userId: '12345', mnemonic: original.mnemonic, deviceId: 'new-device-id', }); expect(recovered.size).toBe(3); // 验证恢复的地址与原地址相同 expect(recovered.get(ChainType.KAVA)!.address).toBe( original.wallets.get(ChainType.KAVA)!.address ); expect(recovered.get(ChainType.DST)!.address).toBe( original.wallets.get(ChainType.DST)!.address ); expect(recovered.get(ChainType.BSC)!.address).toBe( original.wallets.get(ChainType.BSC)!.address ); }); it('不同设备应该生成相同的地址(相同助记词)', () => { const original = service.generateWalletSystem({ userId: '12345', deviceId: 'device-1', }); const recovered1 = service.recoverWalletSystem({ userId: '12345', mnemonic: original.mnemonic, deviceId: 'device-2', }); const recovered2 = service.recoverWalletSystem({ userId: '12345', mnemonic: original.mnemonic, deviceId: 'device-3', }); expect(recovered1.get(ChainType.KAVA)!.address).toBe( recovered2.get(ChainType.KAVA)!.address ); }); }); describe('deriveAddress', () => { it('相同的助记词应该派生相同的地址', () => { const mnemonic = Mnemonic.generate(); const address1 = service.deriveAddress(ChainType.KAVA, mnemonic); const address2 = service.deriveAddress(ChainType.KAVA, mnemonic); expect(address1).toBe(address2); }); it('不同的助记词应该派生不同的地址', () => { const mnemonic1 = Mnemonic.generate(); const mnemonic2 = Mnemonic.generate(); const address1 = service.deriveAddress(ChainType.KAVA, mnemonic1); const address2 = service.deriveAddress(ChainType.KAVA, mnemonic2); expect(address1).not.toBe(address2); }); it('应该为不同的链派生不同的地址', () => { const mnemonic = Mnemonic.generate(); const kavaAddress = service.deriveAddress(ChainType.KAVA, mnemonic); const dstAddress = service.deriveAddress(ChainType.DST, mnemonic); const bscAddress = service.deriveAddress(ChainType.BSC, mnemonic); expect(kavaAddress).not.toBe(dstAddress); expect(kavaAddress).not.toBe(bscAddress); expect(dstAddress).not.toBe(bscAddress); }); }); describe('verifyMnemonic', () => { it('应该验证正确的助记词', () => { const result = service.generateWalletSystem({ userId: '12345', deviceId: 'test-device-id', }); const kavaWallet = result.wallets.get(ChainType.KAVA)!; const isValid = service.verifyMnemonic( result.mnemonic, ChainType.KAVA, kavaWallet.address ); expect(isValid).toBe(true); }); it('应该拒绝错误的助记词', () => { const result1 = service.generateWalletSystem({ userId: '11111', deviceId: 'test-device-id-1', }); const result2 = service.generateWalletSystem({ userId: '22222', deviceId: 'test-device-id-2', }); const kavaWallet1 = result1.wallets.get(ChainType.KAVA)!; const isValid = service.verifyMnemonic( result2.mnemonic, ChainType.KAVA, kavaWallet1.address ); expect(isValid).toBe(false); }); }); describe('加密和解密', () => { it('应该正确加密和解密助记词', () => { const mnemonic = 'test mnemonic phrase for encryption'; const key = 'encryption-key'; const encrypted = service.encryptMnemonic(mnemonic, key); expect(encrypted).toBeDefined(); expect(encrypted.encrypted).toBeDefined(); expect(encrypted.iv).toBeDefined(); expect(encrypted.authTag).toBeDefined(); const decrypted = service.decryptMnemonic(encrypted, key); expect(decrypted).toBe(mnemonic); }); it('使用错误的密钥应该解密失败', () => { const mnemonic = 'test mnemonic phrase'; const key = 'correct-key'; const wrongKey = 'wrong-key'; const encrypted = service.encryptMnemonic(mnemonic, key); expect(() => { service.decryptMnemonic(encrypted, wrongKey); }).toThrow(); }); it('相同的助记词和密钥应该生成不同的密文(因为随机 IV)', () => { const mnemonic = 'test mnemonic phrase'; const key = 'encryption-key'; const encrypted1 = service.encryptMnemonic(mnemonic, key); const encrypted2 = service.encryptMnemonic(mnemonic, key); // 密文应该不同(因为 IV 不同) expect(encrypted1.encrypted).not.toBe(encrypted2.encrypted); expect(encrypted1.iv).not.toBe(encrypted2.iv); // 但解密后应该相同 const decrypted1 = service.decryptMnemonic(encrypted1, key); const decrypted2 = service.decryptMnemonic(encrypted2, key); expect(decrypted1).toBe(mnemonic); expect(decrypted2).toBe(mnemonic); }); }); describe('deriveEncryptionKey', () => { it('相同的输入应该生成相同的密钥', () => { const key1 = service.deriveEncryptionKey('device-1', 'user-1'); const key2 = service.deriveEncryptionKey('device-1', 'user-1'); expect(key1).toBe(key2); }); it('不同的输入应该生成不同的密钥', () => { const key1 = service.deriveEncryptionKey('device-1', 'user-1'); const key2 = service.deriveEncryptionKey('device-2', 'user-1'); const key3 = service.deriveEncryptionKey('device-1', 'user-2'); expect(key1).not.toBe(key2); expect(key1).not.toBe(key3); expect(key2).not.toBe(key3); }); }); });