multi-platform-signing.integration.test.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. /**
  2. * Integration Test for Multi-Platform Signing
  3. *
  4. * Tests end-to-end signing functionality across all supported platforms.
  5. * Validates the complete integration between credential manager, signers, and account pools.
  6. */
  7. import { CredentialManager } from '@/core/credential-manager/CredentialManager'
  8. import { Platform } from '@/types/credential'
  9. import { TradingOperation } from '@/core/credential-manager/TradingIntegration'
  10. describe('Multi-Platform Signing Integration Test', () => {
  11. let credentialManager: CredentialManager
  12. beforeEach(async () => {
  13. const config = {
  14. accounts: [
  15. {
  16. id: 'pacifica-main',
  17. name: 'Pacifica Main Account',
  18. platform: Platform.PACIFICA,
  19. enabled: true,
  20. credentials: {
  21. type: 'ed25519' as const,
  22. privateKey: 'f26670e2ca334117f8859f9f32e50251641953a30b54f6ffcf82db836cfdfea5'
  23. }
  24. },
  25. {
  26. id: 'aster-main',
  27. name: 'Aster Main Account',
  28. platform: Platform.ASTER,
  29. enabled: true,
  30. credentials: {
  31. type: 'secp256k1' as const,
  32. privateKey: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'
  33. }
  34. },
  35. {
  36. id: 'binance-main',
  37. name: 'Binance Main Account',
  38. platform: Platform.BINANCE,
  39. enabled: true,
  40. credentials: {
  41. type: 'hmac' as const,
  42. apiKey: 'test-api-key',
  43. secretKey: 'test-secret-key'
  44. }
  45. }
  46. ],
  47. hedging: {
  48. platforms: {
  49. [Platform.PACIFICA]: {
  50. enabled: true,
  51. primaryAccounts: ['pacifica-main'],
  52. backupAccounts: [],
  53. loadBalanceStrategy: 'round-robin',
  54. healthCheckInterval: 30000,
  55. failoverThreshold: 3
  56. },
  57. [Platform.ASTER]: {
  58. enabled: true,
  59. primaryAccounts: ['aster-main'],
  60. backupAccounts: [],
  61. loadBalanceStrategy: 'round-robin',
  62. healthCheckInterval: 30000,
  63. failoverThreshold: 3
  64. },
  65. [Platform.BINANCE]: {
  66. enabled: true,
  67. primaryAccounts: ['binance-main'],
  68. backupAccounts: [],
  69. loadBalanceStrategy: 'round-robin',
  70. healthCheckInterval: 30000,
  71. failoverThreshold: 3
  72. }
  73. },
  74. hedging: {
  75. enableCrossplatformBalancing: true,
  76. maxAccountsPerPlatform: 5,
  77. reservationTimeoutMs: 60000
  78. }
  79. }
  80. }
  81. credentialManager = new CredentialManager()
  82. await credentialManager.loadConfiguration(config)
  83. })
  84. afterEach(async () => {
  85. await credentialManager.shutdown()
  86. })
  87. describe('Basic Signing Operations', () => {
  88. test('should sign messages for Pacifica platform', async () => {
  89. const message = new TextEncoder().encode('test message for pacifica')
  90. const result = await credentialManager.sign('pacifica-main', message)
  91. expect(result.success).toBe(true)
  92. expect(result.signature).toBeDefined()
  93. expect(result.algorithm).toBe('ed25519')
  94. expect(result.metadata?.platform).toBe(Platform.PACIFICA)
  95. })
  96. test('should sign messages for Aster platform', async () => {
  97. const message = new TextEncoder().encode('test message for aster')
  98. const result = await credentialManager.sign('aster-main', message)
  99. expect(result.success).toBe(true)
  100. expect(result.signature).toBeDefined()
  101. expect(result.algorithm).toBe('eip191')
  102. expect(result.metadata?.platform).toBe(Platform.ASTER)
  103. })
  104. test('should sign messages for Binance platform', async () => {
  105. const message = new TextEncoder().encode('test message for binance')
  106. const result = await credentialManager.sign('binance-main', message)
  107. expect(result.success).toBe(true)
  108. expect(result.signature).toBeDefined()
  109. expect(result.algorithm).toBe('hmac-sha256')
  110. expect(result.metadata?.platform).toBe(Platform.BINANCE)
  111. })
  112. test('should handle signing failures gracefully', async () => {
  113. const message = new TextEncoder().encode('test message')
  114. const result = await credentialManager.sign('non-existent-account', message)
  115. expect(result.success).toBe(false)
  116. expect(result.error).toBeDefined()
  117. expect(result.error).toContain('Account not found')
  118. })
  119. })
  120. describe('Performance Requirements', () => {
  121. test('should complete signing within 50ms for all platforms', async () => {
  122. const message = new TextEncoder().encode('performance test message')
  123. const platforms = [
  124. { accountId: 'pacifica-main', platform: Platform.PACIFICA },
  125. { accountId: 'aster-main', platform: Platform.ASTER },
  126. { accountId: 'binance-main', platform: Platform.BINANCE }
  127. ]
  128. for (const { accountId, platform } of platforms) {
  129. const startTime = Date.now()
  130. const result = await credentialManager.sign(accountId, message)
  131. const duration = Date.now() - startTime
  132. expect(result.success).toBe(true)
  133. expect(duration).toBeLessThan(50) // Performance requirement
  134. expect(result.metadata?.duration).toBeLessThan(50)
  135. }
  136. })
  137. test('should handle concurrent signing operations', async () => {
  138. const message = new TextEncoder().encode('concurrent test message')
  139. const startTime = Date.now()
  140. const promises = [
  141. credentialManager.sign('pacifica-main', message),
  142. credentialManager.sign('aster-main', message),
  143. credentialManager.sign('binance-main', message),
  144. credentialManager.sign('pacifica-main', message),
  145. credentialManager.sign('aster-main', message)
  146. ]
  147. const results = await Promise.all(promises)
  148. const duration = Date.now() - startTime
  149. expect(results).toHaveLength(5)
  150. expect(results.every(r => r.success)).toBe(true)
  151. expect(duration).toBeLessThan(100) // All 5 operations within 100ms
  152. })
  153. })
  154. describe('Trading Integration', () => {
  155. test('should sign trading requests for different platforms', async () => {
  156. const tradingRequests = [
  157. {
  158. operation: TradingOperation.PLACE_ORDER,
  159. platform: Platform.PACIFICA,
  160. parameters: {
  161. symbol: 'SOL/USDC',
  162. side: 'buy' as const,
  163. type: 'limit' as const,
  164. quantity: 1.0,
  165. price: 100.0
  166. }
  167. },
  168. {
  169. operation: TradingOperation.GET_BALANCE,
  170. platform: Platform.ASTER,
  171. parameters: {}
  172. },
  173. {
  174. operation: TradingOperation.CANCEL_ORDER,
  175. platform: Platform.BINANCE,
  176. parameters: {
  177. symbol: 'BTCUSDT',
  178. orderId: '12345'
  179. }
  180. }
  181. ]
  182. for (const request of tradingRequests) {
  183. const result = await credentialManager.signTradingRequest(request)
  184. expect(result.success).toBe(true)
  185. expect(result.selectedAccount).toBeDefined()
  186. expect(result.selectedAccount.platform).toBe(request.platform)
  187. expect(result.operation).toBe(request.operation)
  188. expect(result.platformSignature).toBeDefined()
  189. }
  190. })
  191. test('should handle batch trading requests', async () => {
  192. const batchRequests = [
  193. {
  194. operation: TradingOperation.PLACE_ORDER,
  195. platform: Platform.PACIFICA,
  196. parameters: { symbol: 'SOL/USDC', side: 'buy' as const, quantity: 1.0 }
  197. },
  198. {
  199. operation: TradingOperation.PLACE_ORDER,
  200. platform: Platform.ASTER,
  201. parameters: { symbol: 'ETH/USDC', side: 'sell' as const, quantity: 0.5 }
  202. },
  203. {
  204. operation: TradingOperation.GET_BALANCE,
  205. platform: Platform.BINANCE,
  206. parameters: {}
  207. }
  208. ]
  209. const results = await credentialManager.signBatchTradingRequests(batchRequests)
  210. expect(results).toHaveLength(3)
  211. expect(results.every(r => r.success)).toBe(true)
  212. const platforms = results.map(r => r.selectedAccount.platform)
  213. expect(platforms).toContain(Platform.PACIFICA)
  214. expect(platforms).toContain(Platform.ASTER)
  215. expect(platforms).toContain(Platform.BINANCE)
  216. })
  217. })
  218. describe('Account Pool Integration', () => {
  219. test('should select accounts from hedging pool for trading', async () => {
  220. const accounts = await credentialManager.getAvailableAccountsForTrading({
  221. minBalance: 1000,
  222. riskTolerance: 'medium'
  223. })
  224. expect(accounts.length).toBeGreaterThan(0)
  225. const platforms = new Set(accounts.map(a => a.platform))
  226. expect(platforms.size).toBeGreaterThan(1) // Multiple platforms available
  227. })
  228. test('should handle account health monitoring', async () => {
  229. const accountIds = ['pacifica-main', 'aster-main', 'binance-main']
  230. const healthStatuses = await credentialManager.checkAccountHealth(accountIds)
  231. expect(healthStatuses.size).toBe(3)
  232. for (const [accountId, status] of healthStatuses) {
  233. expect(accountIds).toContain(accountId)
  234. expect(status.accountId).toBe(accountId)
  235. expect(status.isHealthy).toBe(true) // Fresh accounts should be healthy
  236. expect(status.healthScore).toBeGreaterThan(0)
  237. }
  238. })
  239. test('should handle account reservation for trading', async () => {
  240. const accountIds = ['pacifica-main', 'aster-main']
  241. const reservation = await credentialManager.reserveAccountsForTrading(accountIds, 30000)
  242. expect(reservation.success).toBe(true)
  243. expect(reservation.reservedAccounts).toEqual(expect.arrayContaining(accountIds))
  244. // Reserved accounts should not be selected for other operations
  245. const availableAccounts = await credentialManager.getAvailableAccountsForTrading({})
  246. const availableIds = availableAccounts.map(a => a.accountId)
  247. // Should have fewer available accounts (reserved ones excluded)
  248. expect(availableIds).not.toContain('pacifica-main')
  249. expect(availableIds).not.toContain('aster-main')
  250. // Release reservations
  251. const release = await credentialManager.releaseReservedAccounts(accountIds)
  252. expect(release.success).toBe(true)
  253. })
  254. })
  255. describe('Cross-Platform Hedging', () => {
  256. test('should distribute hedging across multiple platforms', async () => {
  257. const platforms = [Platform.PACIFICA, Platform.ASTER, Platform.BINANCE]
  258. const totalVolume = 30000
  259. const distribution = await credentialManager.getHedgingAccountDistribution(
  260. totalVolume,
  261. platforms
  262. )
  263. expect(distribution.size).toBe(3) // All platforms should have accounts
  264. for (const [platform, accounts] of distribution) {
  265. expect(platforms).toContain(platform)
  266. expect(accounts.length).toBeGreaterThan(0)
  267. expect(accounts.every(a => a.platform === platform)).toBe(true)
  268. }
  269. })
  270. test('should handle cross-platform account selection', async () => {
  271. const platforms = [Platform.PACIFICA, Platform.ASTER]
  272. const accountCount = 2
  273. const accounts = await credentialManager.selectAccountsAcrossPlatforms(
  274. platforms,
  275. accountCount
  276. )
  277. expect(accounts.length).toBeLessThanOrEqual(accountCount)
  278. const selectedPlatforms = new Set(accounts.map(a => a.platform))
  279. expect(selectedPlatforms.size).toBeGreaterThan(1) // Multiple platforms selected
  280. })
  281. })
  282. describe('Error Recovery and Failover', () => {
  283. test('should handle account failures and recover', async () => {
  284. const message = new TextEncoder().encode('test message')
  285. // Simulate account failure
  286. credentialManager.updateAccountAfterTrade('pacifica-main', {
  287. success: false,
  288. error: 'Simulated failure',
  289. timestamp: new Date()
  290. })
  291. // Account should still be usable (not immediately disabled)
  292. const result = await credentialManager.sign('pacifica-main', message)
  293. expect(result.success).toBe(true)
  294. // Record success to recover
  295. credentialManager.updateAccountAfterTrade('pacifica-main', {
  296. success: true,
  297. tradeId: 'recovery-test',
  298. timestamp: new Date()
  299. })
  300. const healthCheck = await credentialManager.checkAccountHealth(['pacifica-main'])
  301. const health = healthCheck.get('pacifica-main')
  302. expect(health?.isHealthy).toBe(true)
  303. })
  304. test('should disable accounts after repeated failures', async () => {
  305. // Simulate multiple failures
  306. for (let i = 0; i < 5; i++) {
  307. credentialManager.updateAccountAfterTrade('pacifica-main', {
  308. success: false,
  309. error: `Failure ${i + 1}`,
  310. timestamp: new Date()
  311. })
  312. }
  313. const healthCheck = await credentialManager.checkAccountHealth(['pacifica-main'])
  314. const health = healthCheck.get('pacifica-main')
  315. expect(health?.consecutiveFailures).toBe(5)
  316. expect(health?.isHealthy).toBe(false)
  317. })
  318. })
  319. describe('Platform-Specific Signature Formats', () => {
  320. test('should generate correct signature format for Pacifica', async () => {
  321. const request = {
  322. operation: TradingOperation.PLACE_ORDER,
  323. platform: Platform.PACIFICA,
  324. parameters: {
  325. symbol: 'SOL/USDC',
  326. side: 'buy' as const,
  327. quantity: 1.0
  328. }
  329. }
  330. const result = await credentialManager.signTradingRequest(request)
  331. expect(result.platformSignature.format).toBe('base64')
  332. expect(result.platformSignature.headers?.['X-Algorithm']).toBe('ed25519')
  333. })
  334. test('should generate correct signature format for Aster', async () => {
  335. const request = {
  336. operation: TradingOperation.GET_BALANCE,
  337. platform: Platform.ASTER,
  338. parameters: {}
  339. }
  340. const result = await credentialManager.signTradingRequest(request)
  341. expect(result.platformSignature.format).toBe('hex')
  342. expect(result.platformSignature.headers?.['X-Algorithm']).toBe('eip191')
  343. })
  344. test('should generate correct signature format for Binance', async () => {
  345. const request = {
  346. operation: TradingOperation.GET_POSITIONS,
  347. platform: Platform.BINANCE,
  348. parameters: {
  349. apiKey: 'test-api-key'
  350. }
  351. }
  352. const result = await credentialManager.signTradingRequest(request)
  353. expect(result.platformSignature.format).toBe('hex')
  354. expect(result.platformSignature.headers?.['X-MBX-APIKEY']).toBeDefined()
  355. expect(result.platformSignature.headers?.['X-MBX-SIGNATURE']).toBeDefined()
  356. })
  357. })
  358. })