Skip to content

Commit 3c2586e

Browse files
committed
Add integrator FAQ documentation
1 parent 27f41c6 commit 3c2586e

File tree

1 file changed

+269
-0
lines changed

1 file changed

+269
-0
lines changed

docs/INTEGRATOR_FAQ.md

Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
# Integrator FAQ
2+
3+
## Overview
4+
5+
This document addresses common integration questions for the Forecast Protocol Leverage SDK. Answers are based on SDK version 2.0 and reference only public interfaces.
6+
7+
## Questions
8+
9+
### 1. Signer Compatibility: Can we use Privy embedded wallets instead of private keys?
10+
11+
The SDK accepts either private key strings or ethers.Signer objects in the constructor. For Privy integration:
12+
13+
```typescript
14+
const privyProvider = await wallet.getEthereumProvider();
15+
const ethersProvider = new ethers.BrowserProvider(privyProvider);
16+
const signer = await ethersProvider.getSigner();
17+
18+
const sdk = new ForecastLeverageSDK(
19+
rpcUrl,
20+
signer, // Pass signer directly
21+
protocolAddress,
22+
usdcAddress,
23+
ctfAddress,
24+
polymarketFunderAddress
25+
);
26+
```
27+
28+
The SDK internally converts v6 signers to v5 format for Polymarket CLOB client compatibility. This conversion extracts the private key using standard ethers interfaces (privateKey, signingKey properties).
29+
30+
If your Privy configuration restricts private key access, you will receive an error message with instructions to adjust permissions or export the key manually.
31+
32+
### 2. Order Types: Do you support FOK or IOC orders? Is there auto-retry?
33+
34+
The SDK supports three order execution modes:
35+
36+
**FOK (Fill or Kill)**: Attempts immediate execution with slippage protection. If unfilled within 10 seconds, the order is cancelled and retried up to 3 times (configurable) with exponential backoff.
37+
38+
**GTC (Good Till Cancelled)**: Places a limit order with a 30 second fill window. Allows for better price execution at the cost of slower fills.
39+
40+
**GTD (Good Till Date)**: Similar to GTC with time-based expiration.
41+
42+
Configuration example:
43+
44+
```typescript
45+
const position = await sdk.openTargetPosition({
46+
marketConditionId: '0x...',
47+
longYes: true,
48+
currentPrice: 0.40,
49+
targetPrice: 0.44,
50+
timeframeSeconds: 3600,
51+
capitalUSDC: 1000,
52+
maxSlippageBps: 100,
53+
orderType: 'FOK', // Optional, defaults to FOK
54+
maxRetries: 3, // Optional, defaults to 3
55+
retryDelayMs: 2000 // Optional, defaults to 2000ms
56+
});
57+
```
58+
59+
Auto-retry behavior:
60+
1. Order placed on Polymarket
61+
2. SDK polls for fill status every 1 second
62+
3. If timeout reached, order is cancelled
63+
4. Retry with updated orderbook price and exponential backoff (1.5x multiplier per attempt)
64+
5. Non-retryable errors (no liquidity, invalid price) throw immediately
65+
66+
### 3. Leverage Control: Can we specify fixed leverage or cap the loops?
67+
68+
The SDK does not enforce hard leverage caps. Leverage is determined by:
69+
1. Protocol capital efficiency factor (F) based on current utilization
70+
2. Available liquidity in senior and junior pools
71+
3. Number of loop iterations calculated from F
72+
73+
The loop count formula is `ceil(-ln(0.01) / ln(F))`, which calculates iterations needed to reach 99% of theoretical maximum leverage `1/(1-F)`.
74+
75+
To implement custom leverage limits:
76+
77+
**Frontend approach** (recommended):
78+
```typescript
79+
const simulation = await sdk.simulatePosition(params);
80+
if (simulation.effectiveLeverage > MAX_LEVERAGE) {
81+
// Reject or adjust parameters
82+
throw new Error(`Leverage ${simulation.effectiveLeverage}x exceeds limit`);
83+
}
84+
```
85+
86+
**SDK wrapper approach**:
87+
```typescript
88+
class LeverageCapSDK extends ForecastLeverageSDK {
89+
async openTargetPosition(params: TargetPositionParams, maxLeverage: number): Promise<LeveragePosition> {
90+
const sim = await this.simulatePosition(params);
91+
if (sim.effectiveLeverage > maxLeverage) {
92+
// Reduce capital or adjust timeframe
93+
params.capitalUSDC = params.capitalUSDC * (maxLeverage / sim.effectiveLeverage);
94+
}
95+
return super.openTargetPosition(params);
96+
}
97+
}
98+
```
99+
100+
Protocol-level limits are based on available liquidity only. No fixed caps are encoded in the SDK or contracts.
101+
102+
### 4. Settlement: What is the payout waterfall on close, expiry, and liquidation?
103+
104+
Position closing follows this sequence:
105+
106+
**Manual close (before expiry)**:
107+
User calls `closePosition(legIds)` which triggers `protocol.close()` for each leg. The protocol:
108+
1. Transfers CTF tokens from borrower back to protocol
109+
2. Returns long position tokens to borrower
110+
3. Refunds borrowed USDC plus interest to pools
111+
112+
**Auto-close (at or after expiry)**:
113+
When term expires or market resolves, anyone can trigger close. The protocol:
114+
1. Redeems CTF token pairs (YES + NO) for USDC at Polymarket CTF contract
115+
2. Distributes USDC to lenders based on pre-calculated interest rates
116+
3. Returns any surplus to borrower
117+
4. Emits LegClosed event with boolean flag indicating auto-close path
118+
119+
**Payout priority**:
120+
Senior pool receives principal plus interest first. Junior pool receives remaining amount. This structure is enforced at the protocol level via the quote() function which calculates rates ensuring senior coverage.
121+
122+
**Event emission**:
123+
```solidity
124+
event LegClosed(uint256 indexed legId, bool autoClose);
125+
```
126+
127+
Principal and interest amounts are NOT emitted in events. Calculate them off-chain using:
128+
```typescript
129+
const leg = await protocol.legs(legId);
130+
const seniorInterest = (leg.sets * leg.F_e18 * leg.rS_e18 * leg.term) / (365 * 24 * 3600 * 1e36);
131+
const juniorInterest = (leg.sets * leg.F_e18 * leg.rJ_e18 * leg.term) / (365 * 24 * 3600 * 1e36);
132+
```
133+
134+
### 5. Lender Pools: Are they protocol-managed or can users deposit?
135+
136+
Both senior and junior pools are open for user deposits.
137+
138+
**Senior pool** (USDC):
139+
Implemented as ERC4626 vault. Users deposit USDC and receive fUSDC shares representing proportional pool ownership. Standard vault interface:
140+
```typescript
141+
protocol.deposit(usdcAmount, receiverAddress);
142+
protocol.withdraw(usdcAmount, receiverAddress, ownerAddress);
143+
protocol.redeem(shareAmount, receiverAddress, ownerAddress);
144+
```
145+
146+
**Junior pools** (CTF tokens):
147+
Per-market staking pools. Users deposit YES or NO tokens from specific Polymarket markets:
148+
```typescript
149+
protocol.verifyMarket(conditionId); // One-time setup per market
150+
protocol.depositJunior(positionId, amount);
151+
protocol.withdrawJunior(positionId, amount);
152+
protocol.claimJuniorRewards(positionId);
153+
```
154+
155+
Junior lenders earn yield when borrowers repay loans. Rewards are distributed as fUSDC vault shares.
156+
157+
For integration, use these contract methods directly. The SDK focuses on the borrower experience and does not wrap lender functionality.
158+
159+
### 6. Market Eligibility: What criteria determine which markets are eligible?
160+
161+
The `verifyMarket(conditionId)` function validates:
162+
163+
1. Market must be binary (exactly 2 outcomes)
164+
2. Market must not be previously verified
165+
3. Market must be unresolved (payout numerators both zero)
166+
4. Market must exist in Polymarket CTF contract
167+
168+
No liquidity, volatility, or volume checks are performed. The verification is structural only.
169+
170+
SDK-level validation (in `openTargetPosition`):
171+
```typescript
172+
if (!params.marketConditionId.startsWith('0x')) {
173+
throw new ValidationError('Invalid conditionId format');
174+
}
175+
```
176+
177+
Integrators should perform additional checks:
178+
1. Query Polymarket orderbook for liquidity depth
179+
2. Check market metadata (resolution source, end date)
180+
3. Validate collateral is USDC
181+
4. Verify market has trading activity
182+
183+
The protocol does not filter markets beyond binary/unresolved requirements. Due diligence is the integrator's responsibility.
184+
185+
### 7. Execution Types: Do you support limit orders or only market orders?
186+
187+
The SDK supports both market-style and limit order execution via order type configuration.
188+
189+
**Market-style execution** (FOK):
190+
```typescript
191+
orderType: 'FOK' // Fill or Kill
192+
```
193+
Uses wider limit price: `bestAsk * (1 + maxSlippageBps / 10000)`
194+
10 second timeout for aggressive fills.
195+
196+
**Limit order execution** (GTC/GTD):
197+
```typescript
198+
orderType: 'GTC' // Good Till Cancelled
199+
```
200+
Uses tighter limit price: `bestAsk * (1 + maxSlippageBps / 20000)`
201+
30 second timeout allows passive price improvement.
202+
203+
Polymarket order structure:
204+
```typescript
205+
{
206+
tokenID: string,
207+
price: number, // Limit price calculated from orderbook
208+
side: 'BUY',
209+
size: number, // Calculated from capital / price
210+
feeRateBps: 0
211+
}
212+
```
213+
214+
Both order types use limit prices for slippage protection. The distinction is timeout duration and price aggressiveness. True market orders (no limit price) are not supported for safety.
215+
216+
### 8. Ethers.js Version: Can we use ethers v6 or do we need v5?
217+
218+
The SDK supports both ethers v5 and v6 via peer dependency configuration:
219+
220+
```json
221+
"dependencies": {
222+
"ethers": "5.7.2"
223+
},
224+
"peerDependencies": {
225+
"ethers": "5.7.2 || ^6.0.0"
226+
}
227+
```
228+
229+
Your application can use ethers v6. Pass v6 Provider and Signer objects directly:
230+
231+
```typescript
232+
// Your app using ethers v6
233+
import { ethers } from 'ethers'; // v6
234+
235+
const provider = new ethers.BrowserProvider(window.ethereum);
236+
const signer = await provider.getSigner();
237+
238+
// SDK accepts v6 signer, converts internally to v5
239+
const sdk = new ForecastLeverageSDK(
240+
await provider._getConnection().url, // RPC URL
241+
signer, // v6 signer
242+
protocolAddress,
243+
usdcAddress,
244+
ctfAddress,
245+
polymarketFunderAddress
246+
);
247+
```
248+
249+
Internal conversion logic:
250+
1. SDK detects signer type
251+
2. Extracts private key via v6 signing key interface
252+
3. Creates v5 Wallet instance for Polymarket CLOB client
253+
4. All contract interactions use v5 internally
254+
255+
No need to install or import ethers v5 in your application. The SDK handles version bridging transparently.
256+
257+
## Contract Addresses
258+
259+
Polygon Mainnet:
260+
```
261+
USDC: 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174
262+
CTF: 0x4D97DCd97eC945f40cF65F87097ACe5EA0476045
263+
```
264+
265+
Protocol address: Contact team for deployment address.
266+
267+
## Support
268+
269+
For technical questions or integration assistance, open an issue at the GitHub repository.

0 commit comments

Comments
 (0)