@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.
- package/LICENSE +21 -0
- package/README.en.md +538 -0
- package/README.md +357 -78
- package/docs/00-design.md +1 -1
- package/docs/02-API.md +21 -21
- package/docs/arb/test-plan.md +387 -0
- package/docs/arb/test-results.md +336 -0
- package/docs/arbitrage.md +754 -0
- package/docs/reports/smart-money-analysis-2025-12-23-cn.md +840 -0
- package/examples/13-arbitrage-service.ts +211 -0
- package/examples/README.md +1 -1
- package/package.json +19 -19
- package/scripts/arb/faze-bo3-arb.ts +385 -0
- package/scripts/arb/settle-position.ts +190 -0
- package/scripts/arb/token-rebalancer.ts +420 -0
- package/scripts/arb-tests/01-unit-tests.ts +495 -0
- package/scripts/arb-tests/02-integration-tests.ts +412 -0
- package/scripts/arb-tests/03-e2e-tests.ts +503 -0
- package/scripts/arb-tests/README.md +109 -0
- package/scripts/verify/verify-all-apis.ts +1 -1
- package/src/clients/clob-api.ts +1 -1
- package/src/clients/gamma-api.ts +1 -1
- package/src/core/cache-adapter-bridge.ts +1 -1
- package/src/core/types.ts +3 -3
- package/src/core/unified-cache.ts +1 -1
- package/src/index.ts +25 -19
- package/src/services/arbitrage-service.ts +1807 -0
- package/.env +0 -0
- package/dist/__tests__/clob-api.test.d.ts +0 -5
- package/dist/__tests__/clob-api.test.d.ts.map +0 -1
- package/dist/__tests__/clob-api.test.js +0 -240
- package/dist/__tests__/clob-api.test.js.map +0 -1
- package/dist/__tests__/integration/bridge-client.integration.test.d.ts +0 -11
- package/dist/__tests__/integration/bridge-client.integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration/bridge-client.integration.test.js +0 -260
- package/dist/__tests__/integration/bridge-client.integration.test.js.map +0 -1
- package/dist/__tests__/integration/clob-api.integration.test.d.ts +0 -13
- package/dist/__tests__/integration/clob-api.integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration/clob-api.integration.test.js +0 -170
- package/dist/__tests__/integration/clob-api.integration.test.js.map +0 -1
- package/dist/__tests__/integration/ctf-client.integration.test.d.ts +0 -17
- package/dist/__tests__/integration/ctf-client.integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration/ctf-client.integration.test.js +0 -234
- package/dist/__tests__/integration/ctf-client.integration.test.js.map +0 -1
- package/dist/__tests__/integration/data-api.integration.test.d.ts +0 -9
- package/dist/__tests__/integration/data-api.integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration/data-api.integration.test.js +0 -161
- package/dist/__tests__/integration/data-api.integration.test.js.map +0 -1
- package/dist/__tests__/integration/gamma-api.integration.test.d.ts +0 -9
- package/dist/__tests__/integration/gamma-api.integration.test.d.ts.map +0 -1
- package/dist/__tests__/integration/gamma-api.integration.test.js +0 -170
- package/dist/__tests__/integration/gamma-api.integration.test.js.map +0 -1
- package/dist/__tests__/test-utils.d.ts +0 -92
- package/dist/__tests__/test-utils.d.ts.map +0 -1
- package/dist/__tests__/test-utils.js +0 -143
- package/dist/__tests__/test-utils.js.map +0 -1
- package/dist/clients/bridge-client.d.ts +0 -388
- package/dist/clients/bridge-client.d.ts.map +0 -1
- package/dist/clients/bridge-client.js +0 -587
- package/dist/clients/bridge-client.js.map +0 -1
- package/dist/clients/clob-api.d.ts +0 -318
- package/dist/clients/clob-api.d.ts.map +0 -1
- package/dist/clients/clob-api.js +0 -388
- package/dist/clients/clob-api.js.map +0 -1
- package/dist/clients/ctf-client.d.ts +0 -473
- package/dist/clients/ctf-client.d.ts.map +0 -1
- package/dist/clients/ctf-client.js +0 -915
- package/dist/clients/ctf-client.js.map +0 -1
- package/dist/clients/data-api.d.ts +0 -134
- package/dist/clients/data-api.d.ts.map +0 -1
- package/dist/clients/data-api.js +0 -265
- package/dist/clients/data-api.js.map +0 -1
- package/dist/clients/gamma-api.d.ts +0 -401
- package/dist/clients/gamma-api.d.ts.map +0 -1
- package/dist/clients/gamma-api.js +0 -352
- package/dist/clients/gamma-api.js.map +0 -1
- package/dist/clients/trading-client.d.ts +0 -252
- package/dist/clients/trading-client.d.ts.map +0 -1
- package/dist/clients/trading-client.js +0 -543
- package/dist/clients/trading-client.js.map +0 -1
- package/dist/clients/websocket-manager.d.ts +0 -100
- package/dist/clients/websocket-manager.d.ts.map +0 -1
- package/dist/clients/websocket-manager.js +0 -193
- package/dist/clients/websocket-manager.js.map +0 -1
- package/dist/core/cache-adapter-bridge.d.ts +0 -36
- package/dist/core/cache-adapter-bridge.d.ts.map +0 -1
- package/dist/core/cache-adapter-bridge.js +0 -81
- package/dist/core/cache-adapter-bridge.js.map +0 -1
- package/dist/core/cache.d.ts +0 -40
- package/dist/core/cache.d.ts.map +0 -1
- package/dist/core/cache.js +0 -71
- package/dist/core/cache.js.map +0 -1
- package/dist/core/errors.d.ts +0 -38
- package/dist/core/errors.d.ts.map +0 -1
- package/dist/core/errors.js +0 -84
- package/dist/core/errors.js.map +0 -1
- package/dist/core/rate-limiter.d.ts +0 -31
- package/dist/core/rate-limiter.d.ts.map +0 -1
- package/dist/core/rate-limiter.js +0 -70
- package/dist/core/rate-limiter.js.map +0 -1
- package/dist/core/types.d.ts +0 -314
- package/dist/core/types.d.ts.map +0 -1
- package/dist/core/types.js +0 -19
- package/dist/core/types.js.map +0 -1
- package/dist/core/unified-cache.d.ts +0 -63
- package/dist/core/unified-cache.d.ts.map +0 -1
- package/dist/core/unified-cache.js +0 -114
- package/dist/core/unified-cache.js.map +0 -1
- package/dist/index.d.ts +0 -94
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -258
- package/dist/index.js.map +0 -1
- package/dist/mcp/errors.d.ts +0 -33
- package/dist/mcp/errors.d.ts.map +0 -1
- package/dist/mcp/errors.js +0 -86
- package/dist/mcp/errors.js.map +0 -1
- package/dist/mcp/index.d.ts +0 -62
- package/dist/mcp/index.d.ts.map +0 -1
- package/dist/mcp/index.js +0 -173
- package/dist/mcp/index.js.map +0 -1
- package/dist/mcp/server.d.ts +0 -17
- package/dist/mcp/server.d.ts.map +0 -1
- package/dist/mcp/server.js +0 -155
- package/dist/mcp/server.js.map +0 -1
- package/dist/mcp/tools/guide.d.ts +0 -12
- package/dist/mcp/tools/guide.d.ts.map +0 -1
- package/dist/mcp/tools/guide.js +0 -801
- package/dist/mcp/tools/guide.js.map +0 -1
- package/dist/mcp/tools/index.d.ts +0 -11
- package/dist/mcp/tools/index.d.ts.map +0 -1
- package/dist/mcp/tools/index.js +0 -27
- package/dist/mcp/tools/index.js.map +0 -1
- package/dist/mcp/tools/market.d.ts +0 -11
- package/dist/mcp/tools/market.d.ts.map +0 -1
- package/dist/mcp/tools/market.js +0 -314
- package/dist/mcp/tools/market.js.map +0 -1
- package/dist/mcp/tools/order.d.ts +0 -10
- package/dist/mcp/tools/order.d.ts.map +0 -1
- package/dist/mcp/tools/order.js +0 -258
- package/dist/mcp/tools/order.js.map +0 -1
- package/dist/mcp/tools/trade.d.ts +0 -38
- package/dist/mcp/tools/trade.d.ts.map +0 -1
- package/dist/mcp/tools/trade.js +0 -314
- package/dist/mcp/tools/trade.js.map +0 -1
- package/dist/mcp/tools/trader.d.ts +0 -11
- package/dist/mcp/tools/trader.d.ts.map +0 -1
- package/dist/mcp/tools/trader.js +0 -277
- package/dist/mcp/tools/trader.js.map +0 -1
- package/dist/mcp/tools/wallet.d.ts +0 -274
- package/dist/mcp/tools/wallet.d.ts.map +0 -1
- package/dist/mcp/tools/wallet.js +0 -579
- package/dist/mcp/tools/wallet.js.map +0 -1
- package/dist/mcp/types.d.ts +0 -413
- package/dist/mcp/types.d.ts.map +0 -1
- package/dist/mcp/types.js +0 -5
- package/dist/mcp/types.js.map +0 -1
- package/dist/services/authorization-service.d.ts +0 -97
- package/dist/services/authorization-service.d.ts.map +0 -1
- package/dist/services/authorization-service.js +0 -279
- package/dist/services/authorization-service.js.map +0 -1
- package/dist/services/market-service.d.ts +0 -108
- package/dist/services/market-service.d.ts.map +0 -1
- package/dist/services/market-service.js +0 -458
- package/dist/services/market-service.js.map +0 -1
- package/dist/services/realtime-service.d.ts +0 -82
- package/dist/services/realtime-service.d.ts.map +0 -1
- package/dist/services/realtime-service.js +0 -150
- package/dist/services/realtime-service.js.map +0 -1
- package/dist/services/swap-service.d.ts +0 -217
- package/dist/services/swap-service.d.ts.map +0 -1
- package/dist/services/swap-service.js +0 -695
- package/dist/services/swap-service.js.map +0 -1
- package/dist/services/wallet-service.d.ts +0 -94
- package/dist/services/wallet-service.d.ts.map +0 -1
- package/dist/services/wallet-service.js +0 -173
- package/dist/services/wallet-service.js.map +0 -1
- package/dist/utils/price-utils.d.ts +0 -153
- package/dist/utils/price-utils.d.ts.map +0 -1
- package/dist/utils/price-utils.js +0 -236
- package/dist/utils/price-utils.js.map +0 -1
- package/docs/01-mcp.md +0 -2041
- package/docs/e2e/01-trader-tools.md +0 -159
- package/docs/e2e/02-market-tools.md +0 -180
- package/docs/e2e/03-order-tools.md +0 -166
- package/docs/e2e/04-wallet-tools.md +0 -224
- package/docs/e2e/05-trading-tools.md +0 -327
- package/docs/e2e/06-integration-scenarios.md +0 -481
- package/docs/e2e/coordinator.md +0 -376
- package/scripts/truth.md +0 -440
- package/src/mcp/README.md +0 -380
- package/src/mcp/errors.ts +0 -124
- package/src/mcp/index.ts +0 -309
- package/src/mcp/server.ts +0 -183
- package/src/mcp/tools/guide.ts +0 -821
- package/src/mcp/tools/index.ts +0 -73
- package/src/mcp/tools/market.ts +0 -363
- package/src/mcp/tools/order.ts +0 -326
- package/src/mcp/tools/trade.ts +0 -417
- package/src/mcp/tools/trader.ts +0 -322
- package/src/mcp/tools/wallet.ts +0 -683
- package/src/mcp/types.ts +0 -472
package/docs/02-API.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# @
|
|
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 @
|
|
32
|
+
pnpm add @catalyst-team/poly-sdk
|
|
33
33
|
```
|
|
34
34
|
|
|
35
35
|
## Quick Start
|
|
36
36
|
|
|
37
37
|
```typescript
|
|
38
|
-
import { PolymarketSDK } from '@
|
|
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 '@
|
|
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 '@
|
|
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 '@
|
|
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 '@
|
|
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 '@
|
|
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 '@
|
|
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 '@
|
|
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 '@
|
|
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 '@
|
|
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 '@
|
|
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 '@
|
|
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 '@
|
|
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 '@
|
|
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 '@
|
|
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 '@
|
|
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 '@
|
|
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 '@
|
|
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 '@
|
|
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
|