@catalyst-team/poly-sdk 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. package/LICENSE +21 -0
  2. package/README.en.md +538 -0
  3. package/README.md +357 -78
  4. package/docs/00-design.md +1 -1
  5. package/docs/02-API.md +21 -21
  6. package/docs/arb/test-plan.md +387 -0
  7. package/docs/arb/test-results.md +336 -0
  8. package/docs/arbitrage.md +754 -0
  9. package/docs/reports/smart-money-analysis-2025-12-23-cn.md +840 -0
  10. package/examples/13-arbitrage-service.ts +211 -0
  11. package/examples/README.md +1 -1
  12. package/package.json +19 -19
  13. package/scripts/arb/faze-bo3-arb.ts +385 -0
  14. package/scripts/arb/settle-position.ts +190 -0
  15. package/scripts/arb/token-rebalancer.ts +420 -0
  16. package/scripts/arb-tests/01-unit-tests.ts +495 -0
  17. package/scripts/arb-tests/02-integration-tests.ts +412 -0
  18. package/scripts/arb-tests/03-e2e-tests.ts +503 -0
  19. package/scripts/arb-tests/README.md +109 -0
  20. package/scripts/verify/verify-all-apis.ts +1 -1
  21. package/src/clients/clob-api.ts +1 -1
  22. package/src/clients/gamma-api.ts +1 -1
  23. package/src/core/cache-adapter-bridge.ts +1 -1
  24. package/src/core/types.ts +3 -3
  25. package/src/core/unified-cache.ts +1 -1
  26. package/src/index.ts +25 -19
  27. package/src/services/arbitrage-service.ts +1807 -0
  28. package/.env +0 -0
  29. package/dist/__tests__/clob-api.test.d.ts +0 -5
  30. package/dist/__tests__/clob-api.test.d.ts.map +0 -1
  31. package/dist/__tests__/clob-api.test.js +0 -240
  32. package/dist/__tests__/clob-api.test.js.map +0 -1
  33. package/dist/__tests__/integration/bridge-client.integration.test.d.ts +0 -11
  34. package/dist/__tests__/integration/bridge-client.integration.test.d.ts.map +0 -1
  35. package/dist/__tests__/integration/bridge-client.integration.test.js +0 -260
  36. package/dist/__tests__/integration/bridge-client.integration.test.js.map +0 -1
  37. package/dist/__tests__/integration/clob-api.integration.test.d.ts +0 -13
  38. package/dist/__tests__/integration/clob-api.integration.test.d.ts.map +0 -1
  39. package/dist/__tests__/integration/clob-api.integration.test.js +0 -170
  40. package/dist/__tests__/integration/clob-api.integration.test.js.map +0 -1
  41. package/dist/__tests__/integration/ctf-client.integration.test.d.ts +0 -17
  42. package/dist/__tests__/integration/ctf-client.integration.test.d.ts.map +0 -1
  43. package/dist/__tests__/integration/ctf-client.integration.test.js +0 -234
  44. package/dist/__tests__/integration/ctf-client.integration.test.js.map +0 -1
  45. package/dist/__tests__/integration/data-api.integration.test.d.ts +0 -9
  46. package/dist/__tests__/integration/data-api.integration.test.d.ts.map +0 -1
  47. package/dist/__tests__/integration/data-api.integration.test.js +0 -161
  48. package/dist/__tests__/integration/data-api.integration.test.js.map +0 -1
  49. package/dist/__tests__/integration/gamma-api.integration.test.d.ts +0 -9
  50. package/dist/__tests__/integration/gamma-api.integration.test.d.ts.map +0 -1
  51. package/dist/__tests__/integration/gamma-api.integration.test.js +0 -170
  52. package/dist/__tests__/integration/gamma-api.integration.test.js.map +0 -1
  53. package/dist/__tests__/test-utils.d.ts +0 -92
  54. package/dist/__tests__/test-utils.d.ts.map +0 -1
  55. package/dist/__tests__/test-utils.js +0 -143
  56. package/dist/__tests__/test-utils.js.map +0 -1
  57. package/dist/clients/bridge-client.d.ts +0 -388
  58. package/dist/clients/bridge-client.d.ts.map +0 -1
  59. package/dist/clients/bridge-client.js +0 -587
  60. package/dist/clients/bridge-client.js.map +0 -1
  61. package/dist/clients/clob-api.d.ts +0 -318
  62. package/dist/clients/clob-api.d.ts.map +0 -1
  63. package/dist/clients/clob-api.js +0 -388
  64. package/dist/clients/clob-api.js.map +0 -1
  65. package/dist/clients/ctf-client.d.ts +0 -473
  66. package/dist/clients/ctf-client.d.ts.map +0 -1
  67. package/dist/clients/ctf-client.js +0 -915
  68. package/dist/clients/ctf-client.js.map +0 -1
  69. package/dist/clients/data-api.d.ts +0 -134
  70. package/dist/clients/data-api.d.ts.map +0 -1
  71. package/dist/clients/data-api.js +0 -265
  72. package/dist/clients/data-api.js.map +0 -1
  73. package/dist/clients/gamma-api.d.ts +0 -401
  74. package/dist/clients/gamma-api.d.ts.map +0 -1
  75. package/dist/clients/gamma-api.js +0 -352
  76. package/dist/clients/gamma-api.js.map +0 -1
  77. package/dist/clients/trading-client.d.ts +0 -252
  78. package/dist/clients/trading-client.d.ts.map +0 -1
  79. package/dist/clients/trading-client.js +0 -543
  80. package/dist/clients/trading-client.js.map +0 -1
  81. package/dist/clients/websocket-manager.d.ts +0 -100
  82. package/dist/clients/websocket-manager.d.ts.map +0 -1
  83. package/dist/clients/websocket-manager.js +0 -193
  84. package/dist/clients/websocket-manager.js.map +0 -1
  85. package/dist/core/cache-adapter-bridge.d.ts +0 -36
  86. package/dist/core/cache-adapter-bridge.d.ts.map +0 -1
  87. package/dist/core/cache-adapter-bridge.js +0 -81
  88. package/dist/core/cache-adapter-bridge.js.map +0 -1
  89. package/dist/core/cache.d.ts +0 -40
  90. package/dist/core/cache.d.ts.map +0 -1
  91. package/dist/core/cache.js +0 -71
  92. package/dist/core/cache.js.map +0 -1
  93. package/dist/core/errors.d.ts +0 -38
  94. package/dist/core/errors.d.ts.map +0 -1
  95. package/dist/core/errors.js +0 -84
  96. package/dist/core/errors.js.map +0 -1
  97. package/dist/core/rate-limiter.d.ts +0 -31
  98. package/dist/core/rate-limiter.d.ts.map +0 -1
  99. package/dist/core/rate-limiter.js +0 -70
  100. package/dist/core/rate-limiter.js.map +0 -1
  101. package/dist/core/types.d.ts +0 -314
  102. package/dist/core/types.d.ts.map +0 -1
  103. package/dist/core/types.js +0 -19
  104. package/dist/core/types.js.map +0 -1
  105. package/dist/core/unified-cache.d.ts +0 -63
  106. package/dist/core/unified-cache.d.ts.map +0 -1
  107. package/dist/core/unified-cache.js +0 -114
  108. package/dist/core/unified-cache.js.map +0 -1
  109. package/dist/index.d.ts +0 -94
  110. package/dist/index.d.ts.map +0 -1
  111. package/dist/index.js +0 -258
  112. package/dist/index.js.map +0 -1
  113. package/dist/mcp/errors.d.ts +0 -33
  114. package/dist/mcp/errors.d.ts.map +0 -1
  115. package/dist/mcp/errors.js +0 -86
  116. package/dist/mcp/errors.js.map +0 -1
  117. package/dist/mcp/index.d.ts +0 -62
  118. package/dist/mcp/index.d.ts.map +0 -1
  119. package/dist/mcp/index.js +0 -173
  120. package/dist/mcp/index.js.map +0 -1
  121. package/dist/mcp/server.d.ts +0 -17
  122. package/dist/mcp/server.d.ts.map +0 -1
  123. package/dist/mcp/server.js +0 -155
  124. package/dist/mcp/server.js.map +0 -1
  125. package/dist/mcp/tools/guide.d.ts +0 -12
  126. package/dist/mcp/tools/guide.d.ts.map +0 -1
  127. package/dist/mcp/tools/guide.js +0 -801
  128. package/dist/mcp/tools/guide.js.map +0 -1
  129. package/dist/mcp/tools/index.d.ts +0 -11
  130. package/dist/mcp/tools/index.d.ts.map +0 -1
  131. package/dist/mcp/tools/index.js +0 -27
  132. package/dist/mcp/tools/index.js.map +0 -1
  133. package/dist/mcp/tools/market.d.ts +0 -11
  134. package/dist/mcp/tools/market.d.ts.map +0 -1
  135. package/dist/mcp/tools/market.js +0 -314
  136. package/dist/mcp/tools/market.js.map +0 -1
  137. package/dist/mcp/tools/order.d.ts +0 -10
  138. package/dist/mcp/tools/order.d.ts.map +0 -1
  139. package/dist/mcp/tools/order.js +0 -258
  140. package/dist/mcp/tools/order.js.map +0 -1
  141. package/dist/mcp/tools/trade.d.ts +0 -38
  142. package/dist/mcp/tools/trade.d.ts.map +0 -1
  143. package/dist/mcp/tools/trade.js +0 -314
  144. package/dist/mcp/tools/trade.js.map +0 -1
  145. package/dist/mcp/tools/trader.d.ts +0 -11
  146. package/dist/mcp/tools/trader.d.ts.map +0 -1
  147. package/dist/mcp/tools/trader.js +0 -277
  148. package/dist/mcp/tools/trader.js.map +0 -1
  149. package/dist/mcp/tools/wallet.d.ts +0 -274
  150. package/dist/mcp/tools/wallet.d.ts.map +0 -1
  151. package/dist/mcp/tools/wallet.js +0 -579
  152. package/dist/mcp/tools/wallet.js.map +0 -1
  153. package/dist/mcp/types.d.ts +0 -413
  154. package/dist/mcp/types.d.ts.map +0 -1
  155. package/dist/mcp/types.js +0 -5
  156. package/dist/mcp/types.js.map +0 -1
  157. package/dist/services/authorization-service.d.ts +0 -97
  158. package/dist/services/authorization-service.d.ts.map +0 -1
  159. package/dist/services/authorization-service.js +0 -279
  160. package/dist/services/authorization-service.js.map +0 -1
  161. package/dist/services/market-service.d.ts +0 -108
  162. package/dist/services/market-service.d.ts.map +0 -1
  163. package/dist/services/market-service.js +0 -458
  164. package/dist/services/market-service.js.map +0 -1
  165. package/dist/services/realtime-service.d.ts +0 -82
  166. package/dist/services/realtime-service.d.ts.map +0 -1
  167. package/dist/services/realtime-service.js +0 -150
  168. package/dist/services/realtime-service.js.map +0 -1
  169. package/dist/services/swap-service.d.ts +0 -217
  170. package/dist/services/swap-service.d.ts.map +0 -1
  171. package/dist/services/swap-service.js +0 -695
  172. package/dist/services/swap-service.js.map +0 -1
  173. package/dist/services/wallet-service.d.ts +0 -94
  174. package/dist/services/wallet-service.d.ts.map +0 -1
  175. package/dist/services/wallet-service.js +0 -173
  176. package/dist/services/wallet-service.js.map +0 -1
  177. package/dist/utils/price-utils.d.ts +0 -153
  178. package/dist/utils/price-utils.d.ts.map +0 -1
  179. package/dist/utils/price-utils.js +0 -236
  180. package/dist/utils/price-utils.js.map +0 -1
  181. package/docs/01-mcp.md +0 -2041
  182. package/docs/e2e/01-trader-tools.md +0 -159
  183. package/docs/e2e/02-market-tools.md +0 -180
  184. package/docs/e2e/03-order-tools.md +0 -166
  185. package/docs/e2e/04-wallet-tools.md +0 -224
  186. package/docs/e2e/05-trading-tools.md +0 -327
  187. package/docs/e2e/06-integration-scenarios.md +0 -481
  188. package/docs/e2e/coordinator.md +0 -376
  189. package/scripts/truth.md +0 -440
  190. package/src/mcp/README.md +0 -380
  191. package/src/mcp/errors.ts +0 -124
  192. package/src/mcp/index.ts +0 -309
  193. package/src/mcp/server.ts +0 -183
  194. package/src/mcp/tools/guide.ts +0 -821
  195. package/src/mcp/tools/index.ts +0 -73
  196. package/src/mcp/tools/market.ts +0 -363
  197. package/src/mcp/tools/order.ts +0 -326
  198. package/src/mcp/tools/trade.ts +0 -417
  199. package/src/mcp/tools/trader.ts +0 -322
  200. package/src/mcp/tools/wallet.ts +0 -683
  201. package/src/mcp/types.ts +0 -472
package/docs/02-API.md CHANGED
@@ -1,4 +1,4 @@
1
- # @prediction-router/poly-sdk API Reference
1
+ # @catalyst-team/poly-sdk API Reference
2
2
 
3
3
  Complete API documentation for the Polymarket SDK.
4
4
 
@@ -29,13 +29,13 @@ Complete API documentation for the Polymarket SDK.
29
29
  ## Installation
30
30
 
31
31
  ```bash
32
- pnpm add @prediction-router/poly-sdk
32
+ pnpm add @catalyst-team/poly-sdk
33
33
  ```
34
34
 
35
35
  ## Quick Start
36
36
 
37
37
  ```typescript
38
- import { PolymarketSDK } from '@prediction-router/poly-sdk';
38
+ import { PolymarketSDK } from '@catalyst-team/poly-sdk';
39
39
 
40
40
  const sdk = new PolymarketSDK();
41
41
 
@@ -57,7 +57,7 @@ console.log('Long arb profit:', orderbook.summary.longArbProfit);
57
57
  The main SDK class that provides access to all API clients.
58
58
 
59
59
  ```typescript
60
- import { PolymarketSDK } from '@prediction-router/poly-sdk';
60
+ import { PolymarketSDK } from '@catalyst-team/poly-sdk';
61
61
 
62
62
  const sdk = new PolymarketSDK(config?: PolymarketSDKConfig);
63
63
  ```
@@ -85,7 +85,7 @@ const sdk = new PolymarketSDK(config?: PolymarketSDKConfig);
85
85
  Central Limit Order Book (CLOB) API client for orderbook and market data.
86
86
 
87
87
  ```typescript
88
- import { ClobApiClient, RateLimiter, Cache } from '@prediction-router/poly-sdk';
88
+ import { ClobApiClient, RateLimiter, Cache } from '@catalyst-team/poly-sdk';
89
89
 
90
90
  const client = new ClobApiClient(
91
91
  rateLimiter: RateLimiter,
@@ -175,7 +175,7 @@ Correct arbitrage calculation uses "effective prices":
175
175
  Market discovery and metadata API client.
176
176
 
177
177
  ```typescript
178
- import { GammaApiClient, RateLimiter, Cache } from '@prediction-router/poly-sdk';
178
+ import { GammaApiClient, RateLimiter, Cache } from '@catalyst-team/poly-sdk';
179
179
 
180
180
  const client = new GammaApiClient(rateLimiter: RateLimiter, cache: Cache);
181
181
  ```
@@ -249,7 +249,7 @@ const events = await client.getEvents({ active: true, limit: 20 });
249
249
  User data, positions, and leaderboard API client.
250
250
 
251
251
  ```typescript
252
- import { DataApiClient, RateLimiter, Cache } from '@prediction-router/poly-sdk';
252
+ import { DataApiClient, RateLimiter, Cache } from '@catalyst-team/poly-sdk';
253
253
 
254
254
  const client = new DataApiClient(rateLimiter: RateLimiter, cache: Cache);
255
255
  ```
@@ -308,7 +308,7 @@ for (const entry of leaderboard.entries) {
308
308
  Trading operations client (requires authentication).
309
309
 
310
310
  ```typescript
311
- import { TradingClient, RateLimiter } from '@prediction-router/poly-sdk';
311
+ import { TradingClient, RateLimiter } from '@catalyst-team/poly-sdk';
312
312
 
313
313
  const client = new TradingClient(rateLimiter: RateLimiter, {
314
314
  privateKey: '0x...',
@@ -403,7 +403,7 @@ console.log(`USDC Balance: ${balance}`);
403
403
  Cross-chain deposit client for funding your Polymarket account.
404
404
 
405
405
  ```typescript
406
- import { BridgeClient } from '@prediction-router/poly-sdk';
406
+ import { BridgeClient } from '@catalyst-team/poly-sdk';
407
407
 
408
408
  const bridge = new BridgeClient();
409
409
  ```
@@ -558,7 +558,7 @@ if (min) {
558
558
 
559
559
  ```typescript
560
560
  import { providers, Wallet, Contract, utils } from 'ethers';
561
- import { BridgeClient, BRIDGE_TOKENS } from '@prediction-router/poly-sdk';
561
+ import { BridgeClient, BRIDGE_TOKENS } from '@catalyst-team/poly-sdk';
562
562
 
563
563
  // 1. Setup
564
564
  const provider = new providers.JsonRpcProvider('https://polygon-rpc.com');
@@ -591,7 +591,7 @@ console.log('Bridge fee: ~0.16%');
591
591
  CTF (Conditional Token Framework) client for on-chain token operations.
592
592
 
593
593
  ```typescript
594
- import { CTFClient } from '@prediction-router/poly-sdk';
594
+ import { CTFClient } from '@catalyst-team/poly-sdk';
595
595
 
596
596
  const ctf = new CTFClient({
597
597
  privateKey: '0x...',
@@ -617,7 +617,7 @@ import {
617
617
  NEG_RISK_CTF_EXCHANGE, // 0xC5d563A36AE78145C45a50134d48A1215220f80a
618
618
  NEG_RISK_ADAPTER, // 0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296
619
619
  USDC_DECIMALS, // 6
620
- } from '@prediction-router/poly-sdk';
620
+ } from '@catalyst-team/poly-sdk';
621
621
  ```
622
622
 
623
623
  #### Methods
@@ -655,7 +655,7 @@ console.log(`USDC received: ${result.usdcReceived}`);
655
655
  Get token balances using CLOB token IDs. **Recommended method.**
656
656
 
657
657
  ```typescript
658
- import type { TokenIds } from '@prediction-router/poly-sdk';
658
+ import type { TokenIds } from '@catalyst-team/poly-sdk';
659
659
 
660
660
  // Get token IDs from CLOB API
661
661
  const market = await clobApi.getMarket('0xabc123...');
@@ -818,7 +818,7 @@ interface MarketResolution {
818
818
  #### CTF Arbitrage Example
819
819
 
820
820
  ```typescript
821
- import { CTFClient, ClobApiClient, TokenIds } from '@prediction-router/poly-sdk';
821
+ import { CTFClient, ClobApiClient, TokenIds } from '@catalyst-team/poly-sdk';
822
822
 
823
823
  const ctf = new CTFClient({ privateKey, rpcUrl, chainId: 137 });
824
824
  const clobApi = new ClobApiClient(rateLimiter, cache);
@@ -864,7 +864,7 @@ if (ob.summary.shortArbProfit > 0.005) {
864
864
  Real-time market data via WebSocket.
865
865
 
866
866
  ```typescript
867
- import { WebSocketManager } from '@prediction-router/poly-sdk';
867
+ import { WebSocketManager } from '@catalyst-team/poly-sdk';
868
868
 
869
869
  const ws = new WebSocketManager({ enableLogging: true });
870
870
  ```
@@ -909,7 +909,7 @@ Unsubscribe from all assets and cleanup.
909
909
  High-level market analysis service.
910
910
 
911
911
  ```typescript
912
- import { MarketService } from '@prediction-router/poly-sdk';
912
+ import { MarketService } from '@catalyst-team/poly-sdk';
913
913
 
914
914
  const service = new MarketService(clobApi, gammaApi);
915
915
 
@@ -924,7 +924,7 @@ const analysis = await service.getMarketWithAnalysis('0x82ace55...');
924
924
  Arbitrage opportunity detection.
925
925
 
926
926
  ```typescript
927
- import { ArbitrageService } from '@prediction-router/poly-sdk';
927
+ import { ArbitrageService } from '@catalyst-team/poly-sdk';
928
928
 
929
929
  const service = new ArbitrageService(clobApi, gammaApi);
930
930
 
@@ -946,7 +946,7 @@ for (const opp of opportunities) {
946
946
  High-level WebSocket subscription management.
947
947
 
948
948
  ```typescript
949
- import { RealtimeService, WebSocketManager } from '@prediction-router/poly-sdk';
949
+ import { RealtimeService, WebSocketManager } from '@catalyst-team/poly-sdk';
950
950
 
951
951
  const ws = new WebSocketManager();
952
952
  const realtime = new RealtimeService(ws);
@@ -972,7 +972,7 @@ await sub.unsubscribe();
972
972
  Calculate effective prices accounting for orderbook mirroring.
973
973
 
974
974
  ```typescript
975
- import { getEffectivePrices } from '@prediction-router/poly-sdk';
975
+ import { getEffectivePrices } from '@catalyst-team/poly-sdk';
976
976
 
977
977
  const effective = getEffectivePrices(0.57, 0.55, 0.45, 0.43);
978
978
  console.log('Effective buy YES:', effective.effectiveBuyYes);
@@ -986,7 +986,7 @@ console.log('Effective buy NO:', effective.effectiveBuyNo);
986
986
  Check for arbitrage opportunities.
987
987
 
988
988
  ```typescript
989
- import { checkArbitrage } from '@prediction-router/poly-sdk';
989
+ import { checkArbitrage } from '@catalyst-team/poly-sdk';
990
990
 
991
991
  const arb = checkArbitrage(0.57, 0.55, 0.45, 0.43);
992
992
  if (arb.hasOpportunity) {
@@ -1107,7 +1107,7 @@ interface Position {
1107
1107
  The SDK uses `PolymarketError` for all errors.
1108
1108
 
1109
1109
  ```typescript
1110
- import { PolymarketError, ErrorCode } from '@prediction-router/poly-sdk';
1110
+ import { PolymarketError, ErrorCode } from '@catalyst-team/poly-sdk';
1111
1111
 
1112
1112
  try {
1113
1113
  await client.getMarket('invalid-id');
@@ -0,0 +1,387 @@
1
+ # ArbitrageService E2E Test Plan
2
+
3
+ > **Status**: In Progress
4
+ > **Date**: 2024-12-24
5
+ > **Author**: Claude Code
6
+
7
+ ## Overview
8
+
9
+ This document outlines the comprehensive test plan for the ArbitrageService based on first principles understanding of the Polymarket arbitrage mechanism.
10
+
11
+ ## First Principles: Understanding the Arbitrage Mechanism
12
+
13
+ ### Core Concept: Mirror Orderbook
14
+
15
+ Polymarket orderbooks have a critical property that's often misunderstood:
16
+
17
+ ```
18
+ Buy YES @ P = Sell NO @ (1-P)
19
+ ```
20
+
21
+ This means **the same order appears in both orderbooks**. Naive addition of prices leads to incorrect calculations.
22
+
23
+ ### Effective Prices
24
+
25
+ To correctly calculate arbitrage opportunities, we must use **effective prices**:
26
+
27
+ ```typescript
28
+ // Long Arb (Buy both + Merge)
29
+ effectiveBuyYes = min(YES.ask, 1 - NO.bid)
30
+ effectiveBuyNo = min(NO.ask, 1 - YES.bid)
31
+ longCost = effectiveBuyYes + effectiveBuyNo
32
+ longProfit = 1 - longCost // > 0 means arbitrage exists
33
+
34
+ // Short Arb (Split + Sell both)
35
+ effectiveSellYes = max(YES.bid, 1 - NO.ask)
36
+ effectiveSellNo = max(NO.bid, 1 - YES.ask)
37
+ shortRevenue = effectiveSellYes + effectiveSellNo
38
+ shortProfit = shortRevenue - 1 // > 0 means arbitrage exists
39
+ ```
40
+
41
+ ### Why We Need the Rebalancer
42
+
43
+ Arbitrage execution requires:
44
+ - **Long Arb**: USDC to buy tokens
45
+ - **Short Arb**: YES + NO tokens to sell
46
+
47
+ The Rebalancer maintains the optimal ratio:
48
+ - USDC < 20% → Merge tokens to recover USDC
49
+ - USDC > 80% → Split USDC to create tokens
50
+
51
+ ### Partial Fill Protection
52
+
53
+ When buying both YES and NO in parallel, one order might succeed while the other fails:
54
+ - `sizeSafetyFactor = 0.8` → Use only 80% of orderbook depth
55
+ - `autoFixImbalance = true` → Auto-sell excess if imbalance occurs
56
+ - `imbalanceThreshold = 5` → Trigger fix when YES-NO diff > $5
57
+
58
+ ---
59
+
60
+ ## Test Hierarchy
61
+
62
+ ```
63
+ ┌─────────────────────────────────────────────────────────────────────────────┐
64
+ │ Level 1: Unit Tests (No Network) │
65
+ ├─────────────────────────────────────────────────────────────────────────────┤
66
+ │ • getEffectivePrices() - Correct calculation of effective prices │
67
+ │ • checkArbitrage() - Correct arbitrage detection │
68
+ │ • calculateRebalanceAction() - Rebalance strategy logic │
69
+ ├─────────────────────────────────────────────────────────────────────────────┤
70
+ │ Level 2: Integration Tests (Network, No Private Key) │
71
+ ├─────────────────────────────────────────────────────────────────────────────┤
72
+ │ • scanMarkets() - Market scanning and filtering │
73
+ │ • WebSocket subscription - Real-time orderbook updates │
74
+ │ • checkOpportunity() - Opportunity detection with real data │
75
+ ├─────────────────────────────────────────────────────────────────────────────┤
76
+ │ Level 3: E2E Tests (Real Market, With Private Key) │
77
+ ├─────────────────────────────────────────────────────────────────────────────┤
78
+ │ • Wallet connection and balance query │
79
+ │ • CTF Split/Merge operations │
80
+ │ • Order execution (small amounts) │
81
+ │ • Rebalancer functionality │
82
+ │ • clearPositions() smart clearing │
83
+ └─────────────────────────────────────────────────────────────────────────────┘
84
+ ```
85
+
86
+ ---
87
+
88
+ ## Test Cases
89
+
90
+ ### Level 1: Unit Tests
91
+
92
+ #### Test 1.1: Effective Price Calculation
93
+ ```typescript
94
+ // Input
95
+ yesAsk = 0.52, yesBid = 0.48
96
+ noAsk = 0.50, noBid = 0.46
97
+
98
+ // Expected
99
+ effectiveBuyYes = min(0.52, 1 - 0.46) = min(0.52, 0.54) = 0.52
100
+ effectiveBuyNo = min(0.50, 1 - 0.48) = min(0.50, 0.52) = 0.50
101
+ effectiveSellYes = max(0.48, 1 - 0.50) = max(0.48, 0.50) = 0.50
102
+ effectiveSellNo = max(0.46, 1 - 0.52) = max(0.46, 0.48) = 0.48
103
+ ```
104
+
105
+ #### Test 1.2: Long Arbitrage Detection
106
+ ```typescript
107
+ // Scenario: Long arb exists
108
+ yesAsk = 0.48, noAsk = 0.50, yesBid = 0.46, noBid = 0.48
109
+ longCost = 0.48 + 0.50 = 0.98 < 1.00
110
+ // Expected: longProfit = 0.02 (2%)
111
+ ```
112
+
113
+ #### Test 1.3: Short Arbitrage Detection
114
+ ```typescript
115
+ // Scenario: Short arb exists
116
+ yesBid = 0.52, noBid = 0.50, yesAsk = 0.54, noAsk = 0.52
117
+ shortRevenue = 0.52 + 0.50 = 1.02 > 1.00
118
+ // Expected: shortProfit = 0.02 (2%)
119
+ ```
120
+
121
+ #### Test 1.4: No Arbitrage (Normal Market)
122
+ ```typescript
123
+ // Normal efficient market
124
+ yesAsk = 0.52, yesBid = 0.48, noAsk = 0.52, noBid = 0.48
125
+ longCost ≈ 1.02-1.04
126
+ shortRevenue ≈ 0.96-0.98
127
+ // Expected: No arbitrage opportunity
128
+ ```
129
+
130
+ #### Test 1.5: Rebalance Action Calculation
131
+ ```typescript
132
+ // Scenario: USDC too low
133
+ usdc = 10, yesTokens = 80, noTokens = 80
134
+ usdcRatio = 10 / (10 + 80) = 0.11 < 0.20
135
+ // Expected: action = 'merge', reason = 'USDC 11% < 20% min'
136
+
137
+ // Scenario: USDC too high
138
+ usdc = 90, yesTokens = 10, noTokens = 10
139
+ usdcRatio = 90 / (90 + 10) = 0.90 > 0.80
140
+ // Expected: action = 'split', reason = 'USDC 90% > 80% max'
141
+
142
+ // Scenario: Token imbalance
143
+ yesTokens = 60, noTokens = 45
144
+ imbalance = 15 > threshold(5)
145
+ // Expected: action = 'sell_yes', priority = 100 (highest)
146
+ ```
147
+
148
+ ---
149
+
150
+ ### Level 2: Integration Tests
151
+
152
+ #### Test 2.1: Market Scanning
153
+ ```typescript
154
+ const service = new ArbitrageService({ enableLogging: true });
155
+
156
+ const results = await service.scanMarkets({
157
+ minVolume24h: 5000,
158
+ limit: 20
159
+ }, 0.005);
160
+
161
+ // Verify:
162
+ // - Returns array of ScanResult
163
+ // - Each result has valid market config
164
+ // - Effective prices are calculated correctly
165
+ // - Score is computed based on profit * volume
166
+ ```
167
+
168
+ #### Test 2.2: WebSocket Monitoring
169
+ ```typescript
170
+ const service = new ArbitrageService({ enableLogging: true });
171
+
172
+ // Find a market to monitor
173
+ const results = await service.quickScan(0, 1);
174
+ const market = results[0].market;
175
+
176
+ // Start monitoring (no private key = no execution)
177
+ await service.start(market);
178
+
179
+ // Wait for orderbook updates
180
+ await new Promise(resolve => setTimeout(resolve, 10000));
181
+
182
+ // Verify:
183
+ // - Orderbook state is populated
184
+ // - Events are emitted
185
+ const orderbook = service.getOrderbook();
186
+ // Should have bids/asks for both YES and NO
187
+ ```
188
+
189
+ #### Test 2.3: Opportunity Detection
190
+ ```typescript
191
+ // After monitoring for some time:
192
+ const opportunity = service.checkOpportunity();
193
+
194
+ // If opportunity exists:
195
+ // - type is 'long' or 'short'
196
+ // - profitRate > 0
197
+ // - recommendedSize respects config limits
198
+ // - description is accurate
199
+ ```
200
+
201
+ ---
202
+
203
+ ### Level 3: E2E Tests
204
+
205
+ #### Test 3.1: Wallet Connection
206
+ ```typescript
207
+ const service = new ArbitrageService({
208
+ privateKey: process.env.PRIVATE_KEY,
209
+ enableLogging: true,
210
+ });
211
+
212
+ // Find a market
213
+ const results = await service.quickScan(0, 1);
214
+ await service.start(results[0].market);
215
+
216
+ // Verify:
217
+ const balance = service.getBalance();
218
+ console.log(`USDC: ${balance.usdc}`);
219
+ console.log(`YES: ${balance.yesTokens}`);
220
+ console.log(`NO: ${balance.noTokens}`);
221
+
222
+ // Expected: All balance fields are populated
223
+ ```
224
+
225
+ #### Test 3.2: CTF Split Operation
226
+ ```typescript
227
+ import { CTFClient } from '@catalyst-team/poly-sdk';
228
+
229
+ const ctf = new CTFClient({
230
+ privateKey: process.env.PRIVATE_KEY,
231
+ });
232
+
233
+ // Split a small amount
234
+ const splitResult = await ctf.split(conditionId, '5'); // $5 USDC
235
+
236
+ // Verify:
237
+ // - txHash is returned
238
+ // - Balance now has 5 YES + 5 NO tokens
239
+ // - USDC decreased by $5
240
+ ```
241
+
242
+ #### Test 3.3: CTF Merge Operation
243
+ ```typescript
244
+ // After split, merge back
245
+ const tokenIds = {
246
+ yesTokenId: market.yesTokenId,
247
+ noTokenId: market.noTokenId,
248
+ };
249
+
250
+ const mergeResult = await ctf.mergeByTokenIds(conditionId, tokenIds, '5');
251
+
252
+ // Verify:
253
+ // - txHash is returned
254
+ // - YES and NO tokens decreased by 5
255
+ // - USDC increased by $5
256
+ ```
257
+
258
+ #### Test 3.4: Order Execution
259
+ ```typescript
260
+ // Buy a small amount of YES tokens
261
+ const buyResult = await tradingClient.createMarketOrder({
262
+ tokenId: market.yesTokenId,
263
+ side: 'BUY',
264
+ amount: 5, // $5 USDC
265
+ orderType: 'FOK',
266
+ });
267
+
268
+ // Verify:
269
+ // - success is true
270
+ // - orderId is returned
271
+ // - Balance reflects the purchase
272
+ ```
273
+
274
+ #### Test 3.5: Rebalancer
275
+ ```typescript
276
+ const service = new ArbitrageService({
277
+ privateKey: process.env.PRIVATE_KEY,
278
+ enableRebalancer: true,
279
+ minUsdcRatio: 0.2,
280
+ maxUsdcRatio: 0.8,
281
+ targetUsdcRatio: 0.5,
282
+ });
283
+
284
+ // Create imbalanced state (e.g., split all USDC)
285
+ // Then let rebalancer run
286
+
287
+ // Verify:
288
+ // - Rebalance event is emitted
289
+ // - Balance moves toward target ratio
290
+ ```
291
+
292
+ #### Test 3.6: Clear Positions
293
+ ```typescript
294
+ // After some operations, clear all positions
295
+ const clearResult = await service.clearPositions(market, false);
296
+
297
+ console.log('Plan:', clearResult.actions);
298
+ console.log('Expected recovery:', clearResult.totalUsdcRecovered);
299
+
300
+ // If executing:
301
+ const executeResult = await service.clearPositions(market, true);
302
+ // - Merged tokens are recovered as USDC
303
+ // - Unpaired tokens are sold
304
+ ```
305
+
306
+ ---
307
+
308
+ ## Test Environment
309
+
310
+ ### Configuration
311
+ ```typescript
312
+ // .env file
313
+ PRIVATE_KEY=0x... // Test wallet private key
314
+
315
+ // Test parameters
316
+ MIN_TRADE_SIZE = 5 // Minimum $5 for safety
317
+ MAX_TRADE_SIZE = 20 // Maximum $20 for safety
318
+ PROFIT_THRESHOLD = 0 // Monitor all opportunities
319
+ ```
320
+
321
+ ### Safety Measures
322
+
323
+ 1. **Small amounts only**: All tests use $5-20 amounts
324
+ 2. **Monitor mode first**: Verify detection before execution
325
+ 3. **High profit threshold**: Production should use 0.5%+
326
+ 4. **Dry run first**: Use `execute = false` before real execution
327
+
328
+ ---
329
+
330
+ ## Execution Plan
331
+
332
+ ### Phase 1: Unit Tests (No Network)
333
+ 1. Create test file: `scripts/arb-tests/01-unit-tests.ts`
334
+ 2. Test price utilities
335
+ 3. Test rebalance logic
336
+ 4. Verify all calculations match expected values
337
+
338
+ ### Phase 2: Integration Tests (Network, No Execution)
339
+ 1. Create test file: `scripts/arb-tests/02-integration-tests.ts`
340
+ 2. Test market scanning
341
+ 3. Test WebSocket monitoring
342
+ 4. Verify opportunity detection on real data
343
+
344
+ ### Phase 3: E2E Tests (Real Execution)
345
+ 1. Create test file: `scripts/arb-tests/03-e2e-tests.ts`
346
+ 2. Test wallet connection
347
+ 3. Test CTF operations with small amounts
348
+ 4. Test order execution with small amounts
349
+ 5. Test clearPositions
350
+
351
+ ### Phase 4: Full Flow Test
352
+ 1. Create test file: `scripts/arb-tests/04-full-flow.ts`
353
+ 2. Scan → Select → Monitor → Execute → Clear
354
+ 3. Generate report
355
+
356
+ ---
357
+
358
+ ## Success Criteria
359
+
360
+ | Test Level | Criteria |
361
+ |------------|----------|
362
+ | Unit | All calculations match expected values |
363
+ | Integration | Market scanning returns valid results |
364
+ | Integration | WebSocket receives orderbook updates |
365
+ | E2E | Wallet balance is correctly queried |
366
+ | E2E | Split/Merge operations succeed |
367
+ | E2E | Order execution works |
368
+ | E2E | clearPositions recovers funds |
369
+
370
+ ---
371
+
372
+ ## Risk Mitigation
373
+
374
+ 1. **Financial Risk**: Test with small amounts ($5-20 max)
375
+ 2. **Execution Risk**: Always dry-run first
376
+ 3. **Network Risk**: Handle errors gracefully
377
+ 4. **Timing Risk**: Use FOK orders to avoid partial fills
378
+
379
+ ---
380
+
381
+ ## Next Steps
382
+
383
+ 1. [x] Create test plan document
384
+ 2. [ ] Implement unit tests
385
+ 3. [ ] Implement integration tests
386
+ 4. [ ] Implement E2E tests
387
+ 5. [ ] Generate test report