@@ -175,51 +175,17 @@ Present the user with these trading algorithm options for prediction markets:
175175- Best for: Markets with overconfident pricing
176176- Risk: Medium - based on market efficiency assumptions
177177
178- ## Step 4.5: Approval Mode Selection
179-
180- After selecting an algorithm, ask the user which USDC approval mode they prefer:
181-
182- ** Option A: Permit-Based (Recommended for beginners)**
183- - ** No native gas token required** - Orders are fully gasless
184- - Uses EIP-2612 permit signatures attached to each order
185- - ** Trade-off** : Requires time between orders (~ 5-10s) for permit nonce to increment after settlement
186- - Best for: Casual trading, low-frequency strategies, users without native gas
187- - Reference: ` examples/price_action_bot.py `
188-
189- ** Option B: Pre-Approval (Recommended for high-frequency)**
190- - ** Requires native gas token** (ETH on Base, MATIC on Polygon) for one-time USDC approval transaction
191- - Orders submitted without permit signatures (faster)
192- - ** Trade-off** : Must send an on-chain approval transaction at startup
193- - Best for: High-frequency trading, stress testing, rapid order placement
194- - Reference: ` examples/price_action_bot_preapproved.py `
195-
196- ** Key differences:**
197-
198- | Feature | Permit-Based | Pre-Approval |
199- | ---------| --------------| --------------|
200- | Native gas needed | No | Yes (for approval TX) |
201- | Order frequency | ~ 5-10s between orders | No permit delays (API rate limits apply) |
202- | Complexity | Per-order permit signing | One-time approval |
203- | Nonce management | Must track permit nonces | None |
204- | Best for | Beginners, gasless | High-frequency, bots |
205-
206178## Reference Implementation
207179
208- Two complete, production-ready implementations exist for the ** Price Action Trader** :
209-
210- ** Permit-Based: ` examples/price_action_bot.py ` **
211- - Uses EIP-2612 permits for gasless trading
212- - Includes permit nonce tracking and management
213- - Best for users who don't want to hold native gas tokens
180+ A complete, production-ready implementation exists for the ** Price Action Trader** :
214181
215- ** Pre-Approval: ` examples/price_action_bot_preapproved .py ` **
216- - Uses pre-approved USDC allowance
217- - Auto-approves USDC at startup when entering new markets
182+ ** ` examples/price_action_bot .py ` **
183+ - Signs a single gasless max USDC permit per settlement contract on first trade
184+ - All subsequent orders use the existing allowance (no per-order permit overhead)
218185- Order sizing in USDC terms with position tracking
219- - Best for high-frequency trading scenarios
220186
221187When generating a bot:
222- 1 . ** Read the appropriate reference file ** based on approval mode chosen
188+ 1 . ** Read ` examples/price_action_bot.py ` ** as the primary reference
2231892 . Copy the structure exactly, customizing only configuration parameters as needed
2241903 . ** DO NOT** use the simplified code snippets in this skill - they are incomplete
225191
@@ -236,16 +202,13 @@ The reference implementations include critical patterns that **MUST** be preserv
236202- Unclaimed winnings discovery from previous sessions
237203- Rate-limited claiming (15s delay between claims)
238204- Async HTTP client for non-blocking external API calls
239-
240- ** Additional patterns for Pre-Approval mode:**
241- - Auto-approval when entering new markets (` ensure_settlement_approved() ` )
205+ - Gasless max permit approval when entering new markets (` ensure_settlement_approved() ` )
242206- USDC-based order sizing (` calculate_shares_from_usdc() ` )
243207- Position tracking in USDC terms (` position_usdc ` dict)
244- - Allowance checking via ` client.get_usdc_allowance() `
245208
246209## Step 5: Generate the Bot Code
247210
248- Based on the user's algorithm and approval mode choices , generate a complete bot file. The bot should:
211+ Based on the user's algorithm choice , generate a complete bot file. The bot should:
249212
2502131 . Load credentials from environment variables
2512142 . Auto-register API keys if needed
@@ -255,13 +218,10 @@ Based on the user's algorithm and approval mode choices, generate a complete bot
2552186 . Cancel orders on shutdown
2562197 . ** Automatically detect new BTC markets and switch liquidity/trades to them**
2572208 . Handle market expiration gracefully with seamless transitions
258- 9 . ** Handle USDC authorization based on chosen mode:**
259- - ** Permit mode** : Sign USDC permits for each order (gasless)
260- - ** Pre-approval mode** : Auto-approve USDC at startup/market switch (high-frequency)
221+ 9 . ** Handle gasless USDC approval** via one-time max permit per settlement contract
26122210 . ** Track traded markets and automatically claim winnings when they resolve**
262223
263- ** For Permit mode** : Use ` examples/price_action_bot.py ` as reference
264- ** For Pre-approval mode** : Use ` examples/price_action_bot_preapproved.py ` as reference
224+ Use ` examples/price_action_bot.py ` as the primary reference
265225
266226Use this template structure for all bots:
267227
@@ -356,7 +316,7 @@ class MarketMakerBot:
356316 def __init__ (self , client : TurbineClient):
357317 self .client = client
358318 self .market_id: str | None = None
359- self .settlement_address: str | None = None # For USDC permits
319+ self .settlement_address: str | None = None # For USDC approval
360320 self .contract_address: str | None = None # For claiming winnings
361321 self .strike_price: int = 0 # BTC price when market created (6 decimals) - used by Price Action Trader
362322 self .current_position = 0
@@ -491,7 +451,7 @@ async def main():
491451 print (f " Market expires at: { quick_market.end_time} " )
492452
493453 # Note gasless features
494- print (" Orders will include USDC permit signatures for gasless trading " )
454+ print (" USDC approval: gasless one-time max permit per settlement " )
495455 print (" Automatic winnings claim enabled for resolved markets" )
496456 print ()
497457
@@ -542,43 +502,21 @@ Note: `httpx` is used by the Price Action Trader to fetch real-time BTC prices f
542502
543503## Step 7: Explain How to Run and Deploy
544504
545- Tell the user based on their chosen approval mode :
505+ Tell the user:
546506
547- ** For Permit-Based bots:**
548507```
549- Your bot is ready! To run it locally :
508+ Your bot is ready! To run it:
550509
551510 python {bot_filename}.py
552511
553512The bot will:
554513- Automatically register API credentials on first run (saved to .env)
555514- Connect to the current BTC 15-minute market
515+ - Gaslessly approve USDC on first trade per settlement (one-time max permit, no gas needed)
556516- Start trading based on your chosen algorithm
557- - Sign USDC permits for gasless order execution (no approval TX needed)
558517- Automatically switch to new markets when they start
559518- Track traded markets and claim winnings when they resolve
560519
561- Note: Orders require ~5-10 seconds between submissions for permit nonce propagation.
562-
563- To stop the bot, press Ctrl+C.
564- ```
565-
566- ** For Pre-Approval bots:**
567- ```
568- Your bot is ready! To run it:
569-
570- python {bot_filename}.py
571-
572- The bot will:
573- - Automatically register API credentials on first run (saved to .env)
574- - Connect to the current BTC 15-minute market
575- - Auto-approve USDC spending (requires native gas token: ETH on Base, MATIC on Polygon)
576- - Start trading based on your chosen algorithm (no permit nonce delays)
577- - Automatically switch to new markets when they start (re-approves for new settlements)
578- - Track traded markets and claim winnings when they resolve
579-
580- Note: Ensure your wallet has native gas tokens for the initial USDC approval transaction.
581-
582520To stop the bot, press Ctrl+C.
583521
584522
@@ -616,7 +554,7 @@ async def run(self, host: str) -> None:
616554 await stream.subscribe(current_market)
617555 print (f " Subscribed to market { current_market[:8 ]} ... " )
618556
619- # Place initial quotes (with USDC permits)
557+ # Place initial quotes
620558 await self .place_quotes()
621559
622560 async for message in stream:
@@ -788,172 +726,35 @@ def find_edge(self, best_bid, best_ask):
788726- When less than 60 seconds remain, the bot logs a warning
789727- Orders are cancelled proactively to avoid stuck orders on expired markets
790728
791- ## USDC Approval Modes
792-
793- There are two ways to authorize USDC spending for order execution:
794-
795- ### Mode A: Permit Signatures (Gasless)
729+ ## USDC Approval
796730
797- ** Every order includes a USDC permit signature** for gasless execution. No on-chain approval needed.
798-
799- The ` TurbineClient ` provides ` sign_usdc_permit() ` to create EIP-2612 permit signatures:
800-
801- ** Pros:** No native gas token needed
802- ** Cons:** Must wait ~ 5-10s between orders for permit nonce to propagate after settlement
803-
804- ### Mode B: Pre-Approval (High-Frequency)
805-
806- ** Approve USDC once at startup** , then submit orders without permit signatures.
731+ Bots use a ** one-time gasless max permit** for USDC approval. On first trade per settlement contract, the bot signs an EIP-2612 max permit (max value, max deadline) and submits it via the relayer. No native gas is required.
807732
808733``` python
809- # At startup or when entering a new market:
810- APPROVAL_AMOUNT = 1_000_000_000_000 # 1 million USDC (adjust as needed)
811-
812734def ensure_settlement_approved (self , settlement_address : str ) -> None :
813- """ Ensure USDC is approved for this settlement contract."""
735+ """ Ensure USDC is approved for this settlement contract via gasless max permit ."""
814736 if settlement_address in self .approved_settlements:
815737 return
816738
817- # Check current allowance
739+ # Check on-chain allowance
818740 current = self .client.get_usdc_allowance(spender = settlement_address)
819- if current >= APPROVAL_AMOUNT // 2 :
820- print (f " Existing allowance sufficient: $ { current / 1e6 :,.2f } " )
741+ if current >= MAX_APPROVAL_THRESHOLD : # half of max uint256
821742 self .approved_settlements[settlement_address] = current
822743 return
823744
824- # Send approval transaction (requires native gas)
825- print (f " Approving USDC for settlement { settlement_address[:16 ]} ... " )
826- tx_hash = self .client.approve_usdc(APPROVAL_AMOUNT , spender = settlement_address)
827- print (f " Approval TX: { tx_hash} " )
828-
829- # Wait for confirmation
830- time.sleep(5 )
831- self .approved_settlements[settlement_address] = APPROVAL_AMOUNT
832- ```
833-
834- ** Pros:** No permit nonce delays (API rate limits still apply), no permit nonce tracking
835- ** Cons:** Requires native gas token for approval transaction
836-
837- ### Permit-Based Order Placement (Mode A)
838-
839- ``` python
840- async def place_quotes (self ) -> None :
841- """ Place bid and ask orders with USDC permit signatures."""
842- bid_price, ask_price = self .calculate_quotes()
843-
844- # Place bid (buy YES)
845- bid_order = self .client.create_limit_buy(
846- market_id = self .market_id,
847- outcome = Outcome.YES ,
848- price = bid_price,
849- size = ORDER_SIZE ,
850- expiration = int (time.time()) + QUOTE_REFRESH_SECONDS + 60 ,
851- settlement_address = self .settlement_address,
852- )
853-
854- # Calculate permit amount for BUY orders:
855- # (size * price / 1e6) + 1% fee + 10% safety margin
856- buyer_cost = (ORDER_SIZE * bid_price) // 1_000_000
857- total_fee = ORDER_SIZE // 100 # 1% fee
858- permit_amount = ((buyer_cost + total_fee) * 110 ) // 100
859-
860- # Sign and attach USDC permit
861- permit = self .client.sign_usdc_permit(
862- value = permit_amount,
863- settlement_address = self .settlement_address,
864- )
865- bid_order.permit_signature = permit
866-
867- result = self .client.post_order(bid_order)
868-
869- # Place ask (sell YES)
870- ask_order = self .client.create_limit_sell(
871- market_id = self .market_id,
872- outcome = Outcome.YES ,
873- price = ask_price,
874- size = ORDER_SIZE ,
875- expiration = int (time.time()) + QUOTE_REFRESH_SECONDS + 60 ,
876- settlement_address = self .settlement_address,
877- )
878-
879- # Calculate permit amount for SELL orders: size + 10% margin
880- permit_amount = (ORDER_SIZE * 110 ) // 100
881-
882- permit = self .client.sign_usdc_permit(
883- value = permit_amount,
884- settlement_address = self .settlement_address,
885- )
886- ask_order.permit_signature = permit
887-
888- result = self .client.post_order(ask_order)
745+ # Sign and submit gasless max permit via relayer
746+ result = self .client.approve_usdc_for_settlement(settlement_address)
747+ # Wait for TX confirmation...
748+ self .approved_settlements[settlement_address] = 2 ** 256 - 1
889749```
890750
891751** Key points:**
892- - BUY orders need permit for: ` (size * price / 1e6) + fee `
893- - SELL orders need permit for: ` size ` (for JIT token splitting)
894- - Always add a 10% safety margin to permit amounts
895- - Permits are signed per-order with the settlement address as spender
896-
897- ### Pre-Approval Order Placement (Mode B)
898752
899- When using pre-approval mode, orders are submitted ** without** permit signatures:
900-
901- ``` python
902- # Bot initialization includes approval tracking
903- class PreapprovedBot :
904- def __init__ (self , client : TurbineClient):
905- self .client = client
906- self .approved_settlements: dict[str , int ] = {} # settlement -> approved amount
907- self .order_size_usdc = 1.0 # Order size in USDC terms
908- self .position_usdc: dict[str , float ] = {} # market_id -> USDC position
909- # ... other fields
910-
911- def calculate_shares_from_usdc (self , usdc_amount : float , price : int ) -> int :
912- """ Convert USDC amount to shares based on price.
913-
914- Args:
915- usdc_amount: Amount in USDC (e.g., 1.0 = $1)
916- price: Price in 6 decimals (e.g., 500000 = 50%)
917-
918- Returns:
919- Number of shares in 6 decimals
920- """
921- # shares = (usdc * 1e6 * 1e6) / price
922- return int ((usdc_amount * 1_000_000 * 1_000_000 ) / price)
923-
924- async def place_order (self , outcome : Outcome, price : int ) -> None :
925- """ Place order without permit signature (pre-approved)."""
926- # Ensure approved for this market's settlement
927- self .ensure_settlement_approved(self .settlement_address)
928-
929- # Calculate shares from USDC amount
930- shares = self .calculate_shares_from_usdc(self .order_size_usdc, price)
931-
932- order = self .client.create_limit_buy(
933- market_id = self .market_id,
934- outcome = outcome,
935- price = price,
936- size = shares,
937- expiration = int (time.time()) + 300 ,
938- settlement_address = self .settlement_address,
939- )
940-
941- # NO permit_signature attached - uses pre-approved allowance
942- result = self .client.post_order(order)
943- print (f " Order submitted: { result.order_hash[:16 ]} ... " )
944- ```
945-
946- ** Key points:**
947753- Call ` ensure_settlement_approved() ` when entering each new market
948- - Orders submitted without ` permit_signature ` field
949- - Settlement contract uses existing USDC allowance
754+ - Orders submitted without ` permit_signature ` field — Settlement uses existing allowance
755+ - No native gas token required (relayer pays gas)
756+ - One-time per settlement contract — all future orders reuse the allowance
950757- Order size specified in USDC terms, converted to shares based on price
951- - Track position in USDC terms per market for risk management
952-
953- ** When to auto-approve:**
954- - At bot startup
955- - When switching to a new market (new settlement address)
956- - When allowance drops below threshold
957758
958759## Automatic Winnings Claiming
959760
@@ -1142,9 +943,7 @@ After posting an order:
1142943- ** Market Expiration** : BTC 15-minute markets expire quickly. Bots handle this automatically!
1143944- ** Gas/Fees** : Trading on Polygon has minimal gas costs but watch for fees.
1144945- ** Continuous Operation** : Bots are designed to run 24/7, switching between markets automatically.
1145- - ** Approval Mode Choice** :
1146- - ** Permit mode** : Fully gasless, but ~ 5-10s delay between orders for nonce propagation
1147- - ** Pre-approval mode** : Needs native gas for approval TX, but no permit nonce delays
946+ - ** USDC Approval** : Bots use a one-time gasless max permit per settlement contract. No native gas required.
1148947
1149948## Quick Reference
1150949
0 commit comments