@@ -4,19 +4,30 @@ import { ethers, Wallet } from "ethers";
44/**
55 * TURNKEY LEVERAGE SDK FOR POLYMARKET INTEGRATION
66 *
7- * Enables integrators to add leverage to Polymarket trading with a simple API:
8- * - User picks: "YES 40¢ → 44¢ in 1 hour with $1000"
9- * - SDK executes full leverage loop
10- * - Returns complete position with all fees calculated
7+ * Target-based UX: User picks "YES 40¢ → 44¢ in 1 hour with $1000"
8+ * SDK handles everything else.
119 *
12- * Architecture:
13- * 1. Calculate leverage parameters (F, loops, term)
14- * 2. For each loop iteration:
15- * - Buy tokens on Polymarket (FOK order)
16- * - Wait for confirmation
17- * - Open protocol leg
18- * - Use borrowed USDC for next iteration
19- * 3. Return position tracking all legs
10+ * PROTOCOL MECHANICS (Critical):
11+ *
12+ * 1. COLLATERAL = 1 YES + 1 NO = always $1 (CTF guarantee)
13+ * - Each "set" of collateral has guaranteed $1 value
14+ * - User deposits LONG tokens, protocol borrows SHORT from junior pool
15+ *
16+ * 2. BORROWING:
17+ * - Against $1 collateral, protocol lends F * $1 USDC
18+ * - F = capital efficiency (typically 0.85-0.95)
19+ * - Example: 1000 tokens → borrow 900 USDC (F=0.9)
20+ *
21+ * 3. LOOP LEVERAGE:
22+ * - Buy tokens with capital C
23+ * - Loop: Deposit → borrow C*F → buy more → deposit → borrow C*F² → ...
24+ * - Max leverage = 1 / (1 - F) [geometric series]
25+ *
26+ * 4. RUNWAY:
27+ * - Debt per set: F * (1 + R * time/year)
28+ * - RUNWAY = time until debt hits $1
29+ * - Formula: runway = (1 - F) / (F * R) * year
30+ * - Term MUST be < runway
2031 */
2132
2233// Protocol ABIs
@@ -170,12 +181,13 @@ export class ForecastLeverageSDK {
170181 let remainingUSDC = params . capitalUSDC ;
171182
172183 for ( let i = 0 ; i < leverageParams . loops ; i ++ ) {
173- // Estimate tokens from current capital
184+ // Buy tokens at current price
174185 const tokensThisLoop = remainingUSDC / params . currentPrice ;
175186 totalTokens += tokensThisLoop ;
176187
177- // Estimate borrowed USDC for next loop
178- remainingUSDC = tokensThisLoop * leverageParams . F * params . currentPrice ;
188+ // Protocol lends F per $1 of collateral (1 YES + 1 NO = $1)
189+ // CRITICAL: Each token pair is worth $1, NOT token price
190+ remainingUSDC = tokensThisLoop * leverageParams . F ;
179191
180192 if ( remainingUSDC < 1 ) break ;
181193 }
@@ -376,6 +388,31 @@ export class ForecastLeverageSDK {
376388 }
377389 }
378390
391+ /**
392+ * Validate term doesn't exceed runway
393+ * Runway = time until debt reaches $1 per set
394+ * Debt formula: F * (1 + R * time/year)
395+ * Runway when debt = 1: (1 - F) / (F * R) * year
396+ */
397+ private validateRunway ( F : number , R : number , termSeconds : number ) : void {
398+ if ( R === 0 ) return ; // Zero rates = infinite runway
399+
400+ const YEAR_SECONDS = 365 * 24 * 3600 ;
401+ const runway = ( ( 1 - F ) / ( F * R ) ) * YEAR_SECONDS ;
402+ const safeRunway = runway * 0.95 ; // 95% safety margin
403+
404+ if ( termSeconds >= safeRunway ) {
405+ const termHours = termSeconds / 3600 ;
406+ const runwayHours = safeRunway / 3600 ;
407+
408+ throw new ValidationError (
409+ `Term ${ termHours . toFixed ( 1 ) } h exceeds safe runway ${ runwayHours . toFixed ( 1 ) } h. ` +
410+ `Debt would exceed collateral value. ` +
411+ `Try shorter timeframe or wait for lower rates.`
412+ ) ;
413+ }
414+ }
415+
379416 /**
380417 * Calculate leverage parameters from target
381418 */
@@ -391,10 +428,17 @@ export class ForecastLeverageSDK {
391428 const F = Number ( quote . F ) / 1e18 ;
392429 const R = ( Number ( quote . rS ) + Number ( quote . rJ ) ) / 1e18 ;
393430
394- // Calculate loops needed based on capital and F
395- // Geometric series: total_exposure = capital × 1/(1-F)
431+ // Validate term doesn't exceed runway
432+ this . validateRunway ( F , R , params . timeframeSeconds ) ;
433+
434+ // Calculate loops to reach ~90% of max leverage
435+ // Geometric series: (1 - F^N) / (1 - F) approaches 1 / (1 - F)
436+ // To reach 90%: F^N = 0.1, so N = log(0.1) / log(F)
396437 const maxLeverage = 1 / ( 1 - F ) ;
397- const loops = Math . floor ( Math . log ( 1 - maxLeverage * ( 1 - F ) ) / Math . log ( F ) ) + 1 ;
438+ const loops = Math . min (
439+ Math . ceil ( Math . log ( 0.1 ) / Math . log ( F ) ) ,
440+ 10 // Safety cap
441+ ) ;
398442
399443 // Get token ID from condition
400444 const tokenId = params . longYes
@@ -404,7 +448,7 @@ export class ForecastLeverageSDK {
404448 return {
405449 F,
406450 R,
407- loops : Math . min ( loops , 10 ) , // Cap at 10 loops for safety
451+ loops, // Already capped above
408452 maxLeverage,
409453 tokenId,
410454 } ;
0 commit comments