Skip to content

Conversation

@0xGh-st
Copy link
Collaborator

@0xGh-st 0xGh-st commented Jan 10, 2026

close #43

- Add Predict.fun exchange configuration to .env.example
- Update pyproject.toml and uv.lock to include predict-sdk dependency
- Enhance ExchangeClient and ExchangeConfig to support Predict.fun
- Introduce PredictFun class for handling API interactions with Predict.fun
- Update strategy to manage insufficient funds and improve order handling

This integration allows users to trade on the Predict.fun platform, enhancing the overall functionality of the trading system.
- Moved the import of InsufficientFunds to the correct location in strategy.py for better organization.
- Renamed constants in predictfun.py for consistency and clarity (PRECISION to precision, MAX_SALT to max_salt).
- Updated test for list_exchanges to include the new "predictfun" exchange, increasing the expected count from 3 to 4.

These changes improve code readability and maintainability while ensuring the integration of the Predict.fun exchange is properly reflected in the tests.
- Adjusted formatting in exchange_factory.py, strategy.py, and predictfun.py for better code clarity.
- Enhanced the readability of environment variable loading and logging messages.
- Ensured consistent line breaks and indentation across multiple files.

These changes contribute to a cleaner codebase, making it easier to maintain and understand.
@claude

This comment was marked as outdated.

- Replaced the random module with secrets for generating secure random values.
- Enhanced error handling in the order book fetching method to include verbose logging of exceptions.
- Added validation to ensure order size is greater than zero, improving input validation.

These changes enhance the security and robustness of the PredictFun class, ensuring better error reporting and input validation.
@claude
Copy link

claude bot commented Jan 10, 2026

Pull Request Review: Predict.fun Exchange Integration

Summary

This PR adds support for the Predict.fun exchange on BNB Chain, introducing 1,495 lines of new code in predictfun.py plus integration changes across the codebase. The implementation closes issue #43.


Code Quality & Best Practices

Strengths

  • Well-structured implementation following existing exchange patterns
  • Comprehensive documentation with good docstrings
  • Dual-mode support for EOA and Smart Wallet authentication
  • Proper error handling with custom exception types
  • Correct EIP-712 typed data signing implementation

Critical Issues

1. VIOLATION: CLAUDE.md Rule #4 - Too Many .env Variables

Location: .env.example:16-29

The PR adds 7 new environment variables for configuration. CLAUDE.md Rule #4 states: "Single Source of Truth: DO NOT place many variables in .env file. Place them in the code instead."

Recommendation: Move non-sensitive configuration (PREDICTFUN_USE_SMART_WALLET, PREDICTFUN_TESTNET) to code constants. Only API keys and private keys should be in .env.

2. Hardcoded Magic Numbers

Location: predictfun.py:1220

Magic number 4102444800 for order expiration should be a named constant NO_EXPIRY_TIMESTAMP. Precision values like 1e13, 1e18, 1e24 scattered throughout should also be named constants.

3. Insufficient Funds State Management Bug

Location: dr_manhattan/base/strategy.py:88, 476-549

The _insufficient_funds flag permanently stops trading with no recovery mechanism. If users deposit more funds, trading won't resume automatically.

Recommendation: Add a reset method or check balance before each order cycle to auto-recover.


Potential Bugs

1. Re-authentication Smart Wallet Check

Location: predictfun.py:367

Checks self._account but should check self._owner_account for smart wallet mode.

Fix: if self.api_key and (self._account or self._owner_account):

2. Division by Zero Edge Case

Location: predictfun.py:537-540

If both amount conditions fail, price remains 0.0 which may not be intended.

3. Hardcoded Gas Limit

Location: predictfun.py:1089

Gas limit of 100,000 may be insufficient during BNB Chain congestion.

Recommendation: Use estimateGas with 20% buffer.


Security Concerns

1. CRITICAL: Private Key Exposure Risk

Location: .env.example:25-27

Issues:

  • Private keys in plaintext environment variables
  • No validation or security warnings
  • Risk of exposure in logs/CI/CD pipelines

Recommendations:

  • Add security warnings in documentation
  • Validate keys don't match example patterns
  • Never include key values in error messages

2. Unlimited Token Approval

Location: predictfun.py:1061, 1084

Grants unlimited USDT spending to exchange contracts. If compromised, all USDT can be drained.

Recommendation: Use limited approvals (2-5x trade size) with refresh as needed. Document this trade-off clearly.


Performance Issues

1. Synchronous Approval Checks

Location: predictfun.py:1071-1107

Sequential on-chain calls for 4 contracts could take 10-20 seconds.

Recommendation: Parallelize allowance checks or only approve contracts needed for current market.


Test Coverage - INSUFFICIENT

Issues:

  • Only updated test count from 3 to 4 exchanges
  • NO tests for PredictFun implementation
  • NO tests for smart wallet signing
  • NO tests for EIP-712 signatures
  • NO tests for approval flow
  • NO tests for insufficient funds handling
  • NO edge case testing

Recommendation: Add comprehensive unit tests, integration tests with testnet, and mock tests for Web3 interactions.


CLAUDE.md Compliance

  • Rule 1 (focused, clean code): PASS
  • Rule 2 (no unnecessary files): ACCEPTABLE
  • Rule 3 (use UV): PASS
  • Rule 4 (minimize .env variables): FAIL
  • Rule 5 (run and debug proactively): NEEDS VERIFICATION

Summary & Verdict

SOLID IMPLEMENTATION with good architecture and Web3 understanding, BUT has critical issues.

Must Fix (Blocking):

  1. Reduce .env variables per CLAUDE.md Rule fix: polymarket impl #4
  2. Add security warnings for private key handling
  3. Fix smart wallet check in re-authentication (line 367)
  4. Add recovery mechanism for insufficient funds state
  5. Add comprehensive test coverage

Should Fix:

  1. Replace magic numbers with named constants
  2. Use limited token approvals instead of unlimited
  3. Improve gas estimation for transactions
  4. Verify OutcomeToken backward compatibility

Nice to Have:

  1. Split 1,495-line file into modules
  2. Add proper logging framework
  3. Add documentation in docs/exchanges/
  4. Parallelize approval checks

Recommendation: REQUEST CHANGES before merging

The core implementation demonstrates solid understanding of EIP-712 and Web3, but security concerns, lack of tests, and CLAUDE.md violations must be addressed first.

…edictFun class

- Introduced NO_EXPIRY_TIMESTAMP constant for clarity and maintainability.
- Updated order expiration logic to use the new constant instead of a hardcoded value.
- Enhanced account authentication check to include owner account, improving flexibility.

These changes improve code readability and maintainability while ensuring consistent handling of no-expiry orders.
@claude
Copy link

claude bot commented Jan 10, 2026

PR Review: Predict.fun Exchange Integration

Summary

This PR adds Predict.fun exchange integration to dr-manhattan, introducing support for BNB Chain-based prediction markets with both EOA and Smart Wallet trading modes. The implementation is comprehensive and well-structured.

Code Quality ✅

Strengths:

  • Clean, well-documented code with extensive docstrings
  • Follows existing exchange implementation patterns (Polymarket, Opinion, Limitless)
  • Good separation of concerns between authentication, order signing, and API interaction
  • Comprehensive error handling with custom exception types
  • Proper support for both testnet and mainnet environments

Observations:

  • The new predictfun.py file is 1496 lines - significantly larger than other exchange implementations:
    • polymarket.py: 1920 lines
    • limitless.py: 1704 lines
    • predictfun.py: 1496 lines (new)
  • According to CLAUDE.md rule add logo #2: "DO NOT create a new document. Purge unnecessary code and files"
    • However, this is a legitimate new exchange integration, not unnecessary documentation

Security Concerns ⚠️

1. Private Key Handling (CRITICAL)

The .env.example file now contains 3 different private key fields:

PREDICTFUN_PRIVATE_KEY=0x...your-privy-wallet-private-key
PREDICTFUN_SMART_WALLET_OWNER_PRIVATE_KEY=0x...your-smart-wallet-owner-private-key

Concerns:

  • Multiple private keys increase attack surface
  • Per CLAUDE.md rule fix: polymarket impl #4: "Single Source of Truth: DO NOT place many variables in .env file"
  • 15+ new environment variables added (violates the spirit of keeping .env minimal)

Recommendation:

  • Consider adding security warnings in documentation about private key management
  • Ensure users understand the distinction between EOA and Smart Wallet modes
  • Consider if all these env vars are truly necessary or if some can have sensible defaults in code

2. Smart Wallet Complexity

The dual-mode (EOA vs Smart Wallet) authentication adds complexity:

  • _authenticate() - branching logic based on wallet type
  • _sign_order_eip712() - different signing methods
  • _sign_predict_account_message() - Kernel domain wrapping

Risk: This complexity could lead to signature validation issues or authentication failures.

Mitigation: Good error messages are in place (lines 297-306), which is excellent.

3. On-chain Approvals

The check_and_set_approvals() method (lines 1037-1118) automatically approves unlimited USDT spending:

max_approval = 2**256 - 1  # Unlimited approval

Concern: Unlimited approvals are a security risk if exchange contracts are compromised.

Recommendation: Consider using more conservative approval amounts or warning users about this behavior.

4. Hardcoded Contract Addresses

Multiple contract addresses are hardcoded (lines 42-63). Ensure these are correct and immutable.

Best Practices 👍

Well Done:

  1. Type hints throughout the code
  2. Retry logic with @_retry_on_failure decorator
  3. Proper datetime handling with timezone awareness
  4. Constants defined at module level (follows Python conventions)
  5. EIP-712 signing implemented correctly
  6. Insufficient funds detection properly propagates up to strategy layer
  7. Secrets module for cryptographic randomness (line 10, 1193) - excellent!

Minor Issues:

  1. Line 70: Magic Number
NO_EXPIRY_TIMESTAMP = 4102444800  # year 2100

Consider adding a comment explaining this is 2100-01-01 in Unix time, or use datetime to calculate it.

  1. Inconsistent USDT/USDC Handling
  • Line 196 in exchange_client.py: Now includes USDT in NAV calculation
  • This is good, but ensure consistency across all exchanges
  1. Strategy.py Changes
    The changes to strategy.py properly handle insufficient funds with a circuit breaker pattern:
self._insufficient_funds = False  # Stop trading on insufficient funds

This is excellent defensive programming! ✅

Performance Considerations 🚀

  1. Web3 RPC Calls

    • fetch_balance() makes on-chain calls every time (lines 1429-1461)
    • Consider caching with TTL for better performance
  2. Approval Checks

    • Currently done once per session (_approvals_checked flag)
    • Good approach! ✅
  3. Orderbook Parsing

    • Line 856-868: Inverts prices for second outcome
    • O(n) complexity is acceptable for orderbooks

Potential Bugs 🐛

1. Token to Market Mapping

Lines 488-492 populate _token_to_market but this is instance state, not persistent:

self._token_to_market[token_id] = market_id
self._token_to_index[token_id] = idx

Issue: If you call get_orderbook(token_id) before ever calling fetch_market(), the mapping won't exist.

Recommendation: Add a fallback in get_orderbook() to fetch market data if token_id not in cache.

2. Order Size Validation

Line 966-967:

if size <= 0:
    raise InvalidOrder(f"Size must be greater than 0, got: {size}")

Good validation! ✅ But ensure upstream callers handle this properly.

3. Price Precision

Lines 996-997, 1204:

precision = int(1e13)
price_per_share_wei = (int(price * 1e18) // precision) * precision

This rounds down to nearest 1e13. Ensure this doesn't cause issues with very small orders.

Test Coverage 📊

Modified Test:

assert len(exchanges) == 4  # Updated from 3
assert "predictfun" in exchanges

Concern: Only 1 test file modified, no new tests for:

  • Predict.fun-specific functionality
  • Smart wallet authentication
  • Order signing
  • Balance fetching
  • Approval checking

Recommendation: Add comprehensive test coverage for the new exchange.

CLAUDE.md Compliance

Rule Status Notes
1. Focused, clean code Code is well-structured
2. No unnecessary docs ⚠️ 15+ new env vars in .env.example
3. Use UV for deps pyproject.toml updated correctly
4. Single Source of Truth Too many env variables (violates spirit)
5. Run and Debug Need to verify integration works

Recommendations

High Priority

  1. Test the integration - CLAUDE.md rule Create debugging frontend for trading strategies #5 says "Run and Debug yourself PROACTIVELY"
  2. Add test coverage for Predict.fun exchange
  3. Document security implications of unlimited approvals
  4. Consider reducing env vars - can some have code defaults?

Medium Priority

  1. Add caching for fetch_balance() to reduce RPC calls
  2. Add fallback in get_orderbook() for unmapped token_ids
  3. Document the difference between EOA and Smart Wallet modes more clearly
  4. Add integration examples to help users get started

Low Priority

  1. Consider extracting EIP-712 signing to a shared utility
  2. Add more detailed logging for debugging auth issues

Conclusion

This is a solid implementation of a complex integration. The code quality is high, error handling is comprehensive, and it follows existing patterns well. However:

  • ⚠️ Security: Review unlimited approval approach
  • ⚠️ Testing: Needs comprehensive test coverage
  • ⚠️ Configuration: Too many environment variables (violates CLAUDE.md fix: polymarket impl #4)
  • Code Quality: Well-structured and documented
  • Error Handling: Excellent use of custom exceptions

Recommendation: Approve with minor changes

The integration is production-ready from a code perspective, but should address the configuration bloat and add tests before merging.


Review generated by Claude Code

- Added Predict.fun logo to README for better visibility.
- Updated architecture section to include the new predictfun.py file.
- Introduced PredictFun class in the codebase for handling API interactions with Predict.fun.
- Updated list_exchanges function to reflect the addition of the Predict.fun exchange.
- Included example command for listing markets on Predict.fun in the usage section.

These changes improve documentation and enhance the functionality of the trading system by integrating the Predict.fun exchange.
Repository owner deleted a comment from claude bot Jan 10, 2026
@claude
Copy link

claude bot commented Jan 10, 2026

PR Review: Predict.fun Exchange Integration

Thank you for this comprehensive implementation! This PR adds a significant new exchange integration. Below is my detailed review:

✅ Strengths

  1. Comprehensive Implementation: The PR includes a complete exchange implementation with all core functionality (markets, orders, positions, balance)
  2. Good Documentation: Code includes helpful docstrings and inline comments explaining complex logic
  3. Smart Wallet Support: Nice implementation of both EOA and Smart Wallet modes with proper signing
  4. Error Handling: Good use of custom exception types (InsufficientFunds, InvalidOrder, etc.)
  5. Test Coverage: Updated test file to include predictfun in the exchange list
  6. Consistent Architecture: Follows the existing pattern established by other exchanges

🔍 Code Quality & Best Practices

Critical Issues

  1. CLAUDE.md Violation - Environment Variables (Line 4 violation)

    • .env.example adds 6 new environment variables for Predict.fun configuration
    • CLAUDE.md explicitly states: "DO NOT place many variables in .env file. Place them in the code instead."
    • Recommendation: Consider reducing the number of env vars. The testnet flag and API key are reasonable, but the complex dual-mode configuration (EOA vs Smart Wallet) could potentially be simplified or consolidated.
  2. Private Key Storage in Code

    • Lines 186-192 in predictfun.py: Private keys are stored as instance attributes
    • While this follows the pattern from other exchanges, storing private keys in memory for extended periods increases risk
    • Recommendation: Consider implementing a more secure pattern (e.g., using environment-based credential providers or HSM integration for production use)
  3. Hardcoded Contract Addresses

    • Lines 42-52: Multiple contract addresses hardcoded as constants
    • While documented, these could change and would require code updates
    • Recommendation: Consider fetching these from a configuration service or at minimum, add comments about how to verify these addresses are current

Security Concerns

  1. Approval Transactions Without Gas Estimation (lines 1037-1120)

    • check_and_set_approvals() sends approval transactions without explicit gas estimation
    • Could fail silently or waste gas
    • Recommendation: Add gas estimation before sending approval transactions
  2. Unlimited Approval Amount (line 1097)

    • Approves 2**256 - 1 (max uint256) for all exchange contracts
    • While common in DeFi, this is a security risk if contracts are compromised
    • Recommendation: Consider implementing time-limited or amount-limited approvals, or at minimum add a warning in documentation
  3. RPC Endpoint Hardcoding

    • Lines 73-74: Public RPC endpoints hardcoded
    • Public RPCs can be unreliable and may rate limit
    • Recommendation: Make RPC URLs configurable via environment variable
  4. Missing Input Validation

    • _authenticate() method (line 210): Doesn't validate API response structure before accessing nested fields
    • Could cause unclear error messages
    • Recommendation: Add validation for required fields in API responses
  5. Signature Exposure

    • Signatures are logged in verbose mode potentially
    • Recommendation: Ensure signatures are never logged even in verbose mode

Performance Considerations

  1. Session Reuse

    • Good: Uses requests.Session() for connection pooling (line 163)
  2. Caching Strategy

    • Lines 488-492: Caches token-to-market mappings
    • Good optimization, but cache is never cleared
    • Recommendation: Add cache invalidation or TTL to prevent stale data
  3. Synchronous Web3 Calls

    • Line 1450-1452: Synchronous on-chain balance queries could be slow
    • Recommendation: Consider async/await pattern or caching balance queries
  4. No Rate Limiting

    • While retry logic exists (via _retry_on_failure), no built-in rate limiting
    • Recommendation: Add rate limiting to prevent hitting API limits

Potential Bugs

  1. Price Precision Loss (lines 995-996)

    • Price rounded to 1e13 precision: (int(price * 1e18) // precision) * precision
    • This could cause unexpected price changes
    • Recommendation: Add validation that the rounded price matches user intent within acceptable tolerance
  2. Empty Outcome Handling (lines 458-459)

    • Falls back to ["Yes", "No"] if outcomes are empty
    • This assumption may not hold for all market types
    • Recommendation: Raise an error instead of assuming binary outcomes
  3. Token ID Lookup (lines 839-842, 953-961)

    • Relies on cached _token_to_market mapping
    • If market hasn't been fetched yet, lookup will fail
    • Recommendation: Auto-fetch market data if token mapping is missing
  4. Insufficient Funds State Management (line 88, strategy.py line 543)

    • _insufficient_funds flag is set but never reset
    • Once set, no new orders can be placed even if funds are added
    • Recommendation: Add a method to reset this flag or check balance before skipping orders

Code Organization

  1. File Size: The predictfun.py file is 1,496 lines - quite large

    • Recommendation: Consider splitting into multiple files (e.g., predictfun/client.py, predictfun/signing.py, predictfun/models.py)
  2. Magic Numbers: Several magic numbers without constants

    • Line 70: 4102444800 (year 2100 timestamp)
    • Line 995: 1e13 precision
    • Recommendation: Extract to named constants with explanatory comments
  3. Duplicated Logic: Order parsing logic is complex and could be refactored

    • Lines 507-579: _parse_order method is quite long
    • Recommendation: Break into smaller helper methods

🧪 Testing

Concerns:

  1. Only updated one test file to increment exchange count
  2. No unit tests for the new exchange implementation
  3. No integration tests for order creation/cancellation
  4. No tests for Smart Wallet vs EOA mode differences
  5. No tests for error handling

Recommendation: Add comprehensive test coverage including:

  • Unit tests for signing methods
  • Tests for both EOA and Smart Wallet modes
  • Order creation/parsing tests with mocked API responses
  • Error handling tests (insufficient funds, auth failures, etc.)

📝 Documentation

Good:

  • README.md updated with examples
  • .env.example includes helpful comments about the two modes
  • Docstrings present for public methods

Recommendations:

  1. Add a dedicated doc file explaining Predict.fun integration specifics
  2. Document the differences between EOA and Smart Wallet modes more clearly
  3. Add troubleshooting guide for common issues
  4. Document gas costs and approval requirements

🎯 Summary

Overall Assessment: This is a solid implementation that follows the existing architectural patterns. The code is well-structured and functional, but has several areas for improvement particularly around:

  • Security (unlimited approvals, private key handling)
  • Testing (minimal test coverage)
  • Configuration (violates CLAUDE.md guidance on env vars)
  • Error handling (insufficient funds flag never resets)

Recommendation: Request changes focusing on:

  1. Addressing the CLAUDE.md violation regarding environment variables
  2. Fixing the _insufficient_funds flag bug in strategy.py
  3. Adding proper test coverage
  4. Implementing gas estimation for approval transactions
  5. Adding cache invalidation

The implementation is feature-complete and demonstrates good understanding of the codebase, but needs refinement before merging to production.


Review generated by Claude Code

guzus and others added 2 commits January 10, 2026 15:25
- Removed the _insufficient_funds attribute and related checks from the Strategy class.
- Cleaned up order placement methods by eliminating unnecessary conditions for insufficient funds.
- Enhanced logging by removing warnings related to insufficient funds during order processing.

These changes streamline the order handling process and improve code clarity by focusing on essential trading logic.
@claude
Copy link

claude bot commented Jan 10, 2026

Pull Request Review: Predict.fun Exchange Integration

Thank you for this comprehensive integration of Predict.fun! This is a significant addition that brings BNB Chain prediction markets to dr-manhattan. Here's my detailed review:


✅ Strengths

1. Excellent Code Organization

  • Clean separation of concerns with well-documented methods
  • Comprehensive EIP-712 signing implementation for both EOA and Smart Wallet modes
  • Good error handling with specific exception types (InsufficientFunds, AuthenticationError, etc.)

2. Strong Security Practices

  • Proper EIP-712 typed data signing for order creation
  • JWT authentication with re-authentication on 401 errors
  • Approval checking before transactions (EOA mode)
  • Safe handling of private keys (never logged or exposed)

3. Feature Completeness

  • Full CRUD operations for orders, markets, positions
  • Smart Wallet support (Kernel v0.3.1 domain wrapping)
  • Testnet support with environment-based configuration
  • On-chain balance queries via Web3
  • Orderbook inversion for binary markets (Yes/No outcomes)

4. Integration Quality

  • Follows existing dr-manhattan patterns (Exchange base class)
  • Properly integrated into factory pattern (create_exchange, list_exchanges)
  • Good documentation in README with usage examples
  • Consistent with CLAUDE.md guidelines (clean, focused code)

🔍 Issues & Recommendations

HIGH PRIORITY

1. ❌ CLAUDE.md Violation: Excessive .env Variables

Location: .env.example lines 16-32

The project's CLAUDE.md explicitly states:

"Single Source of Truth: DO NOT place many variables in .env file. Place them in the code instead."

However, this PR adds 8 new environment variables for Predict.fun configuration. This violates the project's core principle.

Recommendation: Move non-sensitive configuration to code constants:

# In predictfun.py - add these as class constants with sensible defaults
DEFAULT_USE_SMART_WALLET = False
DEFAULT_TESTNET = False

Only keep sensitive credentials in .env:

  • PREDICTFUN_API_KEY
  • PREDICTFUN_PRIVATE_KEY
  • PREDICTFUN_SMART_WALLET_OWNER_PRIVATE_KEY
  • PREDICTFUN_SMART_WALLET_ADDRESS

Remove boolean flags and non-sensitive config from .env.

2. ⚠️ Missing Test Coverage

Location: No test files for predictfun

Per CLAUDE.md guideline #5: "Run and Debug yourself PROACTIVELY"

Recommendation: Add basic tests:

# tests/test_predictfun.py
def test_predictfun_init():
    """Test exchange initialization"""
    
def test_fetch_markets():
    """Test public API market fetching"""
    
def test_parse_market():
    """Test market data parsing"""

At minimum, add tests for:

  • Exchange initialization (both modes)
  • Public API methods (fetch_markets, get_orderbook)
  • Data parsing (_parse_market, _parse_order)
  • Error handling

3. 🐛 Potential Bug: Insufficient Funds Handling

Location: dr_manhattan/base/strategy.py:529-537

The insufficient funds flag is set but never reset. Once triggered, the strategy stops placing orders permanently, even if the user adds funds.

except InsufficientFunds as e:
    self._insufficient_funds = True  # Never reset!
    return

Recommendation: Add a reset mechanism:

# In strategy.py update_state():
if self._insufficient_funds:
    # Check if balance recovered
    balance = self.client.fetch_balance()
    if balance.get('USDC', 0) > self.order_size or balance.get('USDT', 0) > self.order_size:
        self._insufficient_funds = False
        logger.info('Balance recovered - resuming trading')

MEDIUM PRIORITY

4. 📊 USDT Support Side Effects

Location: dr_manhattan/base/exchange_client.py:787

The USDT addition to NAV calculation affects all exchanges, not just Predict.fun.

cash = balance.get("USDC", 0.0) + balance.get("USD", 0.0) + balance.get("USDT", 0.0)

Recommendation: This is actually good (more flexible), but should be documented in the PR description as a cross-cutting change.

5. 🔄 OutcomeToken Constructor Change

Location: dr_manhattan/base/strategy.py:125

Changed from:

OutcomeToken(outcome=outcome, token_id=token_id)

To:

OutcomeToken(market_id=self.market_id, outcome=outcome, token_id=token_id)

Recommendation:

  • Verify this doesn't break existing strategies for Polymarket/Limitless/Opinion
  • Add migration notes if this is a breaking change
  • Consider making market_id optional with default value for backward compatibility

6. 🔐 Security: Hardcoded Gas Limit

Location: predictfun.py:1092

"gas": 100000,  # Hardcoded gas limit

Recommendation: Use gas estimation:

estimated_gas = self._usdt_contract.functions.approve(
    exchange_checksum, max_approval
).estimate_gas({'from': owner_checksum})

tx = self._usdt_contract.functions.approve(
    exchange_checksum, max_approval
).build_transaction({
    "gas": int(estimated_gas * 1.2),  # 20% buffer
    # ...
})

7. ⚡ Performance: Approval Checking

Location: predictfun.py:1037-1118

The approval check happens on every create_order call, even though it's only executed once per session. The check itself makes 4 RPC calls.

Recommendation: Move the check earlier:

def _ensure_authenticated(self):
    # Existing auth logic...
    
    # Check approvals immediately after first auth (not on every order)
    if not self._is_using_smart_wallet() and not self._approvals_checked:
        self.check_and_set_approvals()

LOW PRIORITY

8. 📝 Documentation: Smart Wallet Mode

The README example for Predict.fun configuration is good, but could be clearer about when to use each mode.

Recommendation: Add a decision matrix:

### When to use each mode:

**EOA Mode** (`use_smart_wallet=False`):
- Simpler setup
- Good for bots/automated trading
- Requires USDT approval transactions
- Cannot manage positions in web browser

**Smart Wallet Mode** (`use_smart_wallet=True`):  
- Positions visible in Predict.fun web UI
- No approval transactions needed
- Requires both owner key and wallet address
- Better for hybrid manual/automated trading

9. 🎨 Code Style: Magic Numbers

Location: Multiple locations

NO_EXPIRY_TIMESTAMP = 4102444800  # Year 2100
approval_threshold = int(1e24)  # 1M USDT

Recommendation: Add inline comments explaining these values (already done for some, but not all).

10. 🧹 Unused Import

Location: predictfun.py:9

import secrets  # Used for salt generation - OK

This is actually used (line 993: salt = secrets.randbits(256)), so this is fine.


🧪 Testing Recommendations

Per CLAUDE.md guideline #5, please test:

  1. Both modes work:

    # EOA mode
    PREDICTFUN_USE_SMART_WALLET=false uv run python examples/list_all_markets.py predictfun
    
    # Smart Wallet mode  
    PREDICTFUN_USE_SMART_WALLET=true uv run python examples/list_all_markets.py predictfun
  2. Order creation:

    uv run python examples/spread_strategy.py --exchange predictfun --slug <test-market>
  3. Error handling:

    • Test with invalid API key
    • Test with insufficient balance
    • Test with invalid market ID

📊 Summary

Category Count
High Priority Issues 3
Medium Priority Issues 5
Low Priority Issues 3

Overall Assessment: This is high-quality work with comprehensive functionality. The main concerns are:

  1. .env variable overuse (CLAUDE.md violation)
  2. Missing tests (CLAUDE.md violation)
  3. Insufficient funds flag never resets (bug)

Recommendation: Request changes for HIGH priority items. The integration is solid but needs to align with project conventions and include basic tests.


✨ Positive Highlights

  • Excellent handling of EIP-712 signing complexity
  • Smart Wallet support is impressive and well-implemented
  • Error handling is thorough and uses proper exception types
  • Code is well-commented and self-documenting
  • Integration follows existing patterns perfectly

Great work overall! 🚀

@claude
Copy link

claude bot commented Jan 10, 2026

PR Review: Predict.fun Exchange Integration

Summary

This PR adds Predict.fun exchange support to dr-manhattan, a ~1500 line implementation that integrates a BNB Chain-based prediction market with CLOB-style orderbook. The implementation follows the existing patterns and adds USDT support alongside USDC.

Code Quality & Best Practices

Strengths ✅

  1. Consistent Architecture: Follows the existing CCXT-style unified API pattern used by Polymarket, Opinion, and Limitless
  2. Comprehensive Documentation: Excellent inline documentation explaining EIP-712 signing, smart wallet vs EOA modes, and API quirks
  3. Proper Error Handling: Good use of custom exceptions (AuthenticationError, InsufficientFunds, InvalidOrder, etc.)
  4. Configuration Management: Clean integration with existing config system and factory pattern
  5. Smart Wallet Support: Sophisticated implementation supporting both EOA and Kernel smart wallet signing modes

Areas for Improvement ⚠️

1. Security: Private Key Exposure Risk 🔴 CRITICAL

Location: dr_manhattan/exchanges/predictfun.py:186-192

if self.private_key:
    self._account = Account.from_key(self.private_key)
    self._address = self._account.address

if self.smart_wallet_owner_private_key:
    self._owner_account = Account.from_key(self.smart_wallet_owner_private_key)

Issue: No input validation or error handling for invalid private keys. A malformed private key could cause crashes or expose sensitive error messages.

Recommendation: Add try-except with sanitized error messages:

try:
    if self.private_key:
        self._account = Account.from_key(self.private_key)
        self._address = self._account.address
except Exception:
    raise AuthenticationError("Invalid private key format")

2. Security: Unlimited Token Approval 🟡 HIGH

Location: dr_manhattan/exchanges/predictfun.py:1064

max_approval = 2**256 - 1

Issue: Grants unlimited USDT approval to exchange contracts. While common practice, it's a security risk if contracts are compromised.

Recommendation:

  • Consider approving only what's needed per transaction, OR
  • Document this security tradeoff clearly in user-facing docs, OR
  • Make this configurable via environment variable

3. Violation of CLAUDE.md Rule #3 🟡 MEDIUM

Location: .env.example:16-33

The PR adds 18 new environment variables, violating the project's "Single Source of Truth" principle:

"DO NOT place many variables in .env file. Place them in the code instead."

Current:

PREDICTFUN_TESTNET=false
PREDICTFUN_API_KEY=your-api-key-here
PREDICTFUN_USE_SMART_WALLET=true
PREDICTFUN_PRIVATE_KEY=0x...
PREDICTFUN_SMART_WALLET_OWNER_PRIVATE_KEY=0x...
PREDICTFUN_SMART_WALLET_ADDRESS=0x...

Recommendation: Consider hardcoding non-sensitive values (testnet flag, RPC URLs, contract addresses) and only keeping secrets in .env:

# Only secrets in .env
PREDICTFUN_API_KEY=your-api-key-here
PREDICTFUN_PRIVATE_KEY=0x...

4. Hard-coded RPC Endpoints 🟡 MEDIUM

Location: dr_manhattan/exchanges/predictfun.py:73-74

BNB_RPC_MAINNET = "https://bsc-dataseed.binance.org/"
BNB_RPC_TESTNET = "https://data-seed-prebsc-1-s1.binance.org:8545/"

Issue:

  • Single point of failure (no fallback RPCs)
  • Public RPCs can be slow or rate-limited
  • No option for users to specify custom/private RPC

Recommendation: Either add RPC URL as config option or use multiple fallback RPCs

5. Incomplete Error Handling in Balance Fetching 🟡 MEDIUM

Location: dr_manhattan/exchanges/predictfun.py:1458-1461

except Exception as e:
    if self.verbose:
        print(f"Failed to fetch on-chain balance: {e}")
    return {"USDT": 0.0}

Issue: Catches all exceptions and silently returns 0 balance. Could hide critical issues (network problems, wrong address, etc.)

Recommendation: Log at WARNING level (not just print), and distinguish between expected vs unexpected errors

6. Missing Input Validation 🟢 LOW

Location: dr_manhattan/exchanges/predictfun.py:912-967

In create_order(), some validations exist but could be more comprehensive:

  • No validation for size being NaN or Infinity
  • No check for unreasonably large orders
  • Price validation is good (0 < price <= 1) but size validation is minimal

Recommendation: Add size sanity checks and validate numeric types

7. Potential Division by Zero 🟢 LOW

Location: Multiple locations (lines 540, 542, etc.)

if side == OrderSide.BUY and taker_amount > 0:
    price = maker_amount / taker_amount

Issue: Good zero-check exists, but elif for SELL doesn't have equivalent protection

Recommendation: Add explicit zero-check for both branches

Performance Considerations

Good ✅

  1. Session reuse: Uses requests.Session() for connection pooling (line 163)
  2. Caching: Token-to-market mapping cached to avoid repeated lookups (lines 170-173, 489-492)
  3. Pagination support: Handles paginated API responses for large market lists (lines 665-679)
  4. Lazy authentication: Only authenticates when needed via _ensure_authenticated()

Concerns ⚠️

  1. No request rate limiting: Could hit API rate limits during high-frequency trading
  2. Synchronous blockchain calls: check_and_set_approvals() waits for transaction confirmations (line 1102) - could timeout
  3. No caching for market data: Every fetch_market() call hits the API, even for immutable data

Recommendation:

  • Add local rate limiting
  • Consider async blockchain operations
  • Cache market metadata with TTL

Security Concerns

Critical Issues 🔴

  1. Private key handling (mentioned above)
  2. No key rotation mechanism: Once compromised, keys must be manually changed
  3. Unlimited token approvals (mentioned above)

Additional Concerns 🟡

  1. Hardcoded validator address (line 63): No verification that this address is correct/trusted
  2. No signature verification: Order signatures are generated but not verified locally before submission
  3. JWT token storage: _jwt_token stored in memory could leak via error messages or logging

Recommendations:

  1. Add optional signature verification before API submission
  2. Never log or print JWT tokens (scan code for this)
  3. Add documentation about key security best practices

Test Coverage

Current State ❌

  • No unit tests for PredictFun class
  • Only basic integration test confirming the exchange is registered
  • No test coverage for:
    • Order signing (EIP-712)
    • Smart wallet vs EOA modes
    • Error handling paths
    • Approval flow
    • Price inversion for second outcome

Recommendation 🎯

HIGH PRIORITY: Add tests before merging:

# Minimum test coverage needed:
tests/exchanges/test_predictfun.py:
  - test_parse_market
  - test_parse_order
  - test_orderbook_price_inversion  # For second outcome
  - test_eip712_signing
  - test_smart_wallet_signing
  - test_approval_flow
  - test_authentication_eoa_mode
  - test_authentication_smart_wallet_mode
  - test_error_handling (invalid API key, insufficient funds, etc.)
  - test_fetch_balance

Per CLAUDE.md Rule #5: "Run and Debug yourself PROACTIVELY"

Potential Bugs

1. OutcomeToken Constructor Mismatch 🔴 CRITICAL

Location: dr_manhattan/base/strategy.py:123

OutcomeToken(market_id=self.market_id, outcome=outcome, token_id=token_id)

Issue: The PR changes the OutcomeToken constructor to require market_id, but I don't see the corresponding change to the OutcomeToken class definition. This will cause runtime errors for all strategies.

Recommendation: Verify OutcomeToken class signature matches this usage. If not, this is a breaking change.

2. Inconsistent Currency Fallback 🟡 MEDIUM

Location: dr_manhattan/base/strategy.py:148

amount = balance.get("USDC", 0.0) or balance.get("USDT", 0.0)
symbol = "USDC" if balance.get("USDC") else "USDT"

Issue: If balance = {"USDC": 0.0, "USDT": 100.0}, this will:

  • Set amount = 100.0 (correct, due to or)
  • Set symbol = "USDT" (correct)

But if balance = {"USDC": None, "USDT": 100.0}:

  • Set amount = 100.0 (correct)
  • Set symbol = "USDC" (wrong! Should be USDT)

Recommendation:

amount = balance.get("USDC") or balance.get("USDT") or 0.0
symbol = "USDC" if balance.get("USDC") else "USDT"

3. Token Index Assumption 🟡 MEDIUM

Location: dr_manhattan/exchanges/predictfun.py:894

def _is_second_outcome_token(self, token_id: str, market_id: str) -> bool:
    return self._token_to_index.get(token_id, 0) == 1

Issue: Assumes binary markets (0=Yes, 1=No). Will break for multi-outcome markets.

Recommendation: Add validation or document this limitation clearly

4. Order ID Fallback Chain 🟢 LOW

Location: dr_manhattan/exchanges/predictfun.py:514-519

order_id = str(
    data.get("id", "")
    or nested_order.get("hash", "")
    or data.get("hash", "")
    or data.get("orderHash", "")
)

Issue: Complex fallback logic suggests API inconsistency. Could return empty string if none exist, causing silent failures.

Recommendation: Raise exception if no valid ID found

Architecture & Design

Excellent Patterns ✅

  1. Dual-mode authentication: Smart wallet + EOA modes well-abstracted
  2. EIP-712 implementation: Follows standards correctly
  3. Extensible config system: PredictFunConfig integrates cleanly
  4. Retry decorator usage: Proper use of @self._retry_on_failure

Concerns ⚠️

  1. Large monolithic file: 1496 lines in a single file
    • Consider splitting: predictfun_auth.py, predictfun_signing.py, predictfun_core.py
  2. Mixed concerns: Balance fetching uses Web3 (on-chain) while everything else uses REST API
    • This is necessary but increases complexity
  3. Magic numbers: Several unexplained constants (e.g., 1e13 precision, 4102444800 expiration)
    • Add explaining comments or constants with descriptive names

Additional Notes

Documentation

  • README.md updates are clear and helpful ✅
  • Code comments are excellent ✅
  • Consider adding a separate docs/exchanges/predictfun.md with:
    • Smart wallet setup guide
    • EOA vs Smart Wallet mode comparison table
    • Approval flow explanation
    • Troubleshooting common issues

Deployment Considerations

  1. Gas costs: Approval transactions cost BNB - document this requirement
  2. BNB balance: EOA mode requires BNB for gas - add balance check and clear error message
  3. Testnet testing: Ensure testnet mode is thoroughly tested before mainnet deployment

Verdict

Approve with Conditions ✅⚠️

This is a solid implementation that follows good practices and integrates well with the existing codebase. However, there are some important issues that should be addressed:

Must Fix Before Merge 🔴:

  1. Add test coverage (at minimum: basic integration test, signing test, error handling)
  2. Fix OutcomeToken constructor mismatch (verify this doesn't break other exchanges)
  3. Add private key validation with safe error handling

Should Fix Before Merge 🟡:

  1. Address CLAUDE.md violation (reduce .env variables)
  2. Add RPC endpoint configuration/fallbacks
  3. Document unlimited approval security tradeoff
  4. Improve balance fetching error handling

Nice to Have 🟢:

  1. Split large file into modules
  2. Add rate limiting
  3. Add more input validation
  4. Add comprehensive docs

Great work overall! The smart wallet integration is particularly impressive. Once the critical issues are addressed, this will be a strong addition to the project.


Code Review completed by Claude Code

@claude
Copy link

claude bot commented Jan 10, 2026

Pull Request Review: Predict.fun Exchange Integration

Overview

This PR adds comprehensive support for the Predict.fun prediction market exchange on BNB Chain. The integration is well-structured and follows the existing codebase patterns established for Polymarket, Opinion, and Limitless.

Code Quality ✅

Strengths:

  • Excellent documentation: The predictfun.py file has clear docstrings explaining the dual wallet modes (EOA vs Smart Wallet), EIP-712 signing, and complex authentication flows
  • Consistent architecture: Follows the existing exchange pattern with proper inheritance from the Exchange base class
  • Comprehensive error handling: Properly catches and handles various API errors including 401, 403, 404, 429, and 400 (insufficient funds)
  • Type hints: Good use of type annotations throughout the code
  • Constants organization: Well-organized constants at the module level for addresses, URLs, and configuration

Areas for improvement:

  1. Line 1029: The _is_using_smart_wallet() method checks self._address but this seems incorrect - it should check if smart wallet owner account exists, not EOA address

    # Current (potentially buggy)
    return bool(self.use_smart_wallet and self.smart_wallet_address and self._address)
    
    # Should likely be:
    return bool(self.use_smart_wallet and self.smart_wallet_address and self._owner_account)
  2. Hardcoded precision values: Lines 1197, 1204 use magic number int(1e13) - consider making this a named constant like AMOUNT_PRECISION = int(1e13) for clarity

  3. .env.example complexity: The configuration has many modes and options which may confuse users. Consider adding validation that errors early with helpful messages when incompatible options are set.

Best Practices ✅

Excellent:

  • Uses secrets.randbelow() instead of random for salt generation (line 1193) - cryptographically secure
  • Proper retry logic with the @self._retry_on_failure decorator
  • Session reuse with requests.Session() for better performance
  • Proper cleanup of resources in error cases
  • Web3 integration for on-chain balance queries and approvals

Minor issues:

  • Line 440: Empty string in error detail could be more descriptive: error_detail = response.text[:500] if response.text else "(no response body)"

Potential Bugs 🐛

  1. Critical - Smart wallet mode detection (line 1029):

    def _is_using_smart_wallet(self) -> bool:
        return bool(self.use_smart_wallet and self.smart_wallet_address and self._address)

    In smart wallet mode, self._address is None (not initialized, see lines 185-188), so this will always return False even when smart wallet is configured. This breaks smart wallet functionality.

  2. Minor - Order size validation (line 967):
    The validation if size <= 0 is good, but should also check for unreasonably small sizes that might cause precision issues given the 1e13 rounding.

  3. Token mapping caching (lines 489-492):
    The _token_to_market and _token_to_index mappings are only populated during _parse_market(). If a market is fetched by ID multiple times, this could lead to duplicate entries or stale data.

Performance Considerations ⚡

Good:

  • Approval checks cached per session (self._approvals_checked, line 183)
  • WebSocket orderbook support integrated via ExchangeClient
  • Efficient orderbook price inversion for binary markets (lines 856-881)

Potential improvements:

  • Lines 1069-1111: The approval checking loops through 4 exchange contracts sequentially with on-chain calls. Consider parallelizing these checks for faster initialization
  • The get_orderbook method (line 822) doesn't implement any caching. For high-frequency strategies, this could be optimized

Security Concerns 🔒

Critical:

  1. Private key handling: ✅ Good - private keys are only stored in memory and used for signing, never logged
  2. EIP-712 signing: ✅ Properly implemented with correct domain separation for both EOA and Smart Wallet modes
  3. Kernel domain wrapping: ✅ Correctly implements the Predict.fun smart wallet signing scheme

Recommendations:

  1. The .env.example file stores private keys in plaintext. Consider adding a warning comment about never committing actual private keys
  2. Line 1064: Using max uint256 for unlimited approval is standard but risky. Consider documenting this in the approval check method

Test Coverage 📊

Current coverage:

  • ✅ Updated test_exchange_tools.py to include "predictfun" in the exchange list (line 13-14)
  • ✅ Exchange factory properly handles PredictFun configuration and validation

Missing tests:

  • ❌ No unit tests for the PredictFun class itself
  • ❌ No tests for EIP-712 signing logic
  • ❌ No tests for smart wallet vs EOA mode switching
  • ❌ No tests for error handling (insufficient funds, auth errors, etc.)
  • ❌ No integration tests

Recommendation: Add at least basic unit tests for:

  • Market fetching and parsing
  • Order creation with different wallet modes
  • Error handling paths
  • Orderbook price inversion for binary markets

Additional Observations

Configuration (.env.example)

  • Good: Comprehensive documentation of both wallet modes
  • Issue: Lines 29-30 show both modes' keys uncommented, which could lead to confusion about which to use

Strategy Integration (strategy.py)

  • Lines 147-150: Good addition of USDT support alongside USDC
  • Lines 164-173: Excellent fallback logic to get prices from orderbook if not in market.prices
  • Line 123: Added market_id to OutcomeToken - verify this doesn't break existing code

Exchange Factory (exchange_factory.py)

  • Lines 205-210: Smart conditional validation based on wallet mode is well-implemented
  • Lines 219-226: Proper private key validation for the correct mode

Documentation (README.md)

  • ✅ Logo added, architecture updated, examples provided
  • ✅ Clear usage examples for both wallet modes

Summary

Overall Assessment: Good Quality ⭐⭐⭐⭐☆

This is a solid implementation that follows the codebase patterns well. The main concern is the potential bug in _is_using_smart_wallet() (line 1029) which could break smart wallet functionality entirely.

Must Fix Before Merge:

  1. 🔴 Fix _is_using_smart_wallet() method to check self._owner_account instead of self._address

Strongly Recommended:

  1. 🟡 Add unit tests for core functionality
  2. 🟡 Extract magic numbers to named constants (precision values)
  3. 🟡 Improve error messages for empty response bodies

Nice to Have:

  1. 🟢 Add integration tests
  2. 🟢 Parallelize approval checks for better performance
  3. 🟢 Add orderbook caching
  4. 🟢 Clarify .env.example by commenting out one of the wallet modes

Great work on this integration! The code is well-structured and thoughtfully implemented. Once the critical bug is fixed and tests are added, this will be a solid addition to dr-manhattan.

Reviewed with ❤️ by Claude Code

- Introduced a new method to enrich markets with orderbook prices, improving market data accuracy.
- Refactored market fetching logic to streamline the process and handle fallback scenarios more effectively.
- Added detailed error handling for orderbook fetching, ensuring robustness in price retrieval.

These changes enhance the functionality and reliability of the PredictFun class, providing users with more accurate market information.
@claude
Copy link

claude bot commented Jan 10, 2026

PR Review: Predict.fun Exchange Integration

Thank you for this comprehensive implementation! This is a substantial addition (1,539 lines) that adds Predict.fun exchange support to dr-manhattan. Here's my detailed review:


✅ Strengths

1. Comprehensive Implementation

  • Complete CCXT-style API implementation with all core methods
  • Supports both EOA and Smart Wallet modes (very flexible)
  • Proper EIP-712 and EIP-191 message signing
  • Good error handling with specific exception types

2. Code Quality

  • Well-documented with clear docstrings
  • Clean separation of concerns
  • Follows existing codebase patterns (matches other exchange implementations)
  • Type hints used throughout

3. Smart Wallet Support

  • Kernel domain wrapping for smart wallet signing is properly implemented
  • Clear configuration options in .env.example with helpful comments
  • Good error messages explaining what's needed for each mode

4. Configuration Management

  • Properly integrated into factory pattern (exchange_factory.py)
  • Config validation checks required fields based on wallet mode
  • Supports both testnet and mainnet

🔴 Critical Issues

1. SECURITY: Violation of CLAUDE.md Rule #4 - Environment Variables

Issue: The implementation heavily uses .env file for configuration (18 new env vars in .env.example), which directly violates project guideline #4:

"Single Source of Truth: DO NOT place many variables in .env file. Place them in the code instead."

Files affected:

  • .env.example (lines 16-33): 18 new environment variables
  • dr_manhattan/base/exchange_factory.py:141-155: Loads 6 env vars for predictfun

Recommendation:

  • Move constants like chain IDs, contract addresses, RPC URLs to code (already done in predictfun.py:39-74)
  • Only keep truly secret values (API keys, private keys) in environment
  • Consider hardcoding use_smart_wallet and testnet flags or using config file

2. SECURITY: Hardcoded Private Keys Risk

File: dr_manhattan/exchanges/predictfun.py:186-192

# Initialize account if private key provided (skip in smart wallet mode)
if self.private_key and not self.use_smart_wallet:
    self._account = Account.from_key(self.private_key)
    self._address = self._account.address

# Initialize owner account for smart wallet mode
if self.smart_wallet_owner_private_key:
    self._owner_account = Account.from_key(self.smart_wallet_owner_private_key)

Recommendation: Add validation to ensure private keys are never logged or exposed in error messages. Consider adding warning in docstring about secure key management.


⚠️ Important Issues

3. Missing Test Coverage

The only test update is incrementing the exchange count in tests/mcp/test_exchange_tools.py:13.

Missing tests:

  • No unit tests for PredictFun class
  • No tests for EIP-712 signing logic
  • No tests for smart wallet vs EOA mode switching
  • No tests for order creation/cancellation
  • No integration tests

Recommendation: Add comprehensive test suite:

tests/exchanges/test_predictfun.py
tests/exchanges/test_predictfun_signing.py

4. Error Handling: Bare Exception Catches

File: dr_manhattan/exchanges/predictfun.py

Lines with bare except Exception::

  • Line 413: Catches all exceptions when parsing error body
  • Line 439: Catches all exceptions when extracting error detail
  • Line 797: Catches all exceptions during price enrichment (silently fails)

Recommendation: Use specific exception types or at least log the errors for debugging.

5. Incomplete USDT Support in NAV Calculation

File: dr_manhattan/base/exchange_client.py:787

cash = balance.get("USDC", 0.0) + balance.get("USD", 0.0) + balance.get("USDT", 0.0)

Good addition for Predict.fun (which uses USDT), but the fallback logic in strategy.py:147-149 uses or instead of +:

amount = balance.get("USDC", 0.0) or balance.get("USDT", 0.0)
symbol = "USDC" if balance.get("USDC") else "USDT"

This won't handle multi-currency scenarios correctly. Should be consistent with NAV calculation.


🟡 Minor Issues & Improvements

6. Code Duplication in Contract Address Selection

File: dr_manhattan/exchanges/predictfun.py:1147-1162

The _get_exchange_address method has repetitive if-else logic. Consider using a lookup dictionary:

def _get_exchange_address(self, is_neg_risk: bool, is_yield_bearing: bool) -> str:
    exchanges = {
        (True, True): self._yield_bearing_neg_risk_ctf_exchange,
        (True, False): self._neg_risk_ctf_exchange,
        (False, True): self._yield_bearing_ctf_exchange,
        (False, False): self._ctf_exchange,
    }
    return exchanges[(is_neg_risk, is_yield_bearing)]

7. Magic Numbers

  • Line 70: NO_EXPIRY_TIMESTAMP = 4102444800 (year 2100) - good comment
  • Line 1236: max_salt = 2147483648 - should be 2**31 for clarity
  • Line 1240: precision = int(1e13) - good variable name

8. Inconsistent Price Handling

File: dr_manhattan/base/strategy.py:163-172

The fallback logic for getting prices from orderbook is complex. This could be extracted to a helper method for clarity.

9. Documentation: Missing Architecture Diagram

The assets/predict_fun.jpg file is added but referenced in README without explanation of integration architecture.


📊 Performance Considerations

10. Sequential API Calls in Price Enrichment

File: dr_manhattan/exchanges/predictfun.py:765-798

The _enrich_markets_with_prices method makes sequential orderbook API calls for each market. For large market lists, this could be slow.

Recommendation: Consider batch API calls or concurrent requests if API supports it.

11. Web3 Connection on Every Init

File: dr_manhattan/exchanges/predictfun.py:176

self._web3 = Web3(Web3.HTTPProvider(self._rpc_url))

Creates a new Web3 connection for every instance. Consider connection pooling or reuse.


🔒 Security Review

12. Approval Checking Logic

File: dr_manhattan/exchanges/predictfun.py:1099-1145

The ensure_approvals method is well-implemented with proper checks and transaction handling. Good security practice.

13. Salt Generation

File: dr_manhattan/exchanges/predictfun.py:1236

salt = secrets.randbelow(max_salt)

Correctly uses secrets module for cryptographically secure randomness. ✅

14. Message Signing

The EIP-712 and Kernel domain wrapping implementation appears correct and follows security best practices.


📝 Suggestions

15. Add Usage Examples

The README shows basic initialization but could include:

  • Example of switching between EOA and Smart Wallet modes
  • Example of handling approvals
  • Example trading workflow

16. Error Messages Could Be More Helpful

Example from line 298-300:

raise AuthenticationError(
    "Smart Wallet mode requires PREDICTFUN_SMART_WALLET_OWNER_PRIVATE_KEY.\n"
    "This is the private key of the EOA that owns the Smart Wallet."
)

Good! But could also explain HOW to get this (e.g., link to predict.fun docs).

17. Consider Adding Logging

The codebase uses print() statements (e.g., line 276, 768). Consider using Python's logging module for better control and production usage.


🎯 Summary

Overall Assessment: This is a solid implementation that adds significant value to the project. The code quality is good and follows most best practices.

Before Merging:

  1. MUST FIX: Address CLAUDE.md Rule fix: polymarket impl #4 violation (reduce .env variables)
  2. MUST ADD: Comprehensive test coverage
  3. SHOULD FIX: Bare exception catches
  4. SHOULD FIX: Consistent USDT handling in strategy.py

Recommendation: Request changes for items 1-2, consider items 3-4 as high priority for follow-up.


Test Plan Suggestion

Since CLAUDE.md Rule #5 says "Run and Debug yourself PROACTIVELY", here's what should be tested:

# 1. Test basic imports
uv run python -c "from dr_manhattan import PredictFun; print('Import OK')"

# 2. Test factory
uv run python -c "from dr_manhattan import create_exchange; e = create_exchange('predictfun'); print(e.name)"

# 3. Test market fetching (no auth required)
uv run python examples/list_all_markets.py predictfun

# 4. Test with actual credentials (if available)
# - Test EOA mode
# - Test Smart Wallet mode
# - Test order creation
# - Test approvals

Great work overall! Looking forward to seeing this merged after addressing the critical issues. 🚀

…andling

- Added logic to set the _address attribute for smart wallet mode, ensuring proper initialization.
- Updated authentication checks to differentiate between standard and smart wallet modes, improving error handling for wallet initialization.

These changes enhance the robustness of the PredictFun class, ensuring accurate wallet management in different modes.
@claude
Copy link

claude bot commented Jan 10, 2026

PR Review: Predict.fun Exchange Integration

This PR adds support for Predict.fun, a prediction market on BNB Chain. Here's my comprehensive review:


✅ Code Quality & Best Practices

Strengths:

  1. Well-structured implementation - Follows the existing exchange pattern consistently (similar to Polymarket/Opinion/Limitless)
  2. Comprehensive documentation - Good docstrings explaining API endpoints, parameters, and return types
  3. Proper error handling - Uses appropriate exception types (AuthenticationError, InsufficientFunds, InvalidOrder, etc.)
  4. Type hints - Proper typing throughout the implementation
  5. Retry logic - Uses @self._retry_on_failure decorator for resilient API calls
  6. Smart wallet support - Implements both EOA and Smart Wallet modes with Kernel v0.3.1 signing

Areas for Improvement:

  1. CLAUDE.md Guideline fix: polymarket impl #4 Violation - The .env.example file adds 9 environment variables, contradicting the "Single Source of Truth" principle stated in CLAUDE.md. Consider moving some constants (like PREDICTFUN_TESTNET, PREDICTFUN_USE_SMART_WALLET) to code defaults instead of requiring them in .env.

  2. Magic numbers - Several hardcoded values should be constants:

    • Line 1046: precision = int(1e13) - should be a module constant with explanation
    • Line 1143: gas: 100000 - should be a named constant
    • Line 1115: max_approval = 2**256 - 1 and approval_threshold = int(1e24) - should be module constants
  3. Code duplication in _request method (lines 364-392) - The retry logic for re-authentication repeats the same HTTP method dispatch. Consider extracting to a helper function.


🐛 Potential Bugs & Issues

  1. ⚠️ Critical: Race condition in approval checking (line 988-990):

    • _approvals_checked is a session flag but check_and_set_approvals() may fail silently
    • If approval fails mid-session, subsequent orders will fail without checking approvals again
    • Fix: Either remove the session flag or handle approval failures more robustly
  2. ⚠️ Silent failure in price enrichment (line 801-802):

    • Catches all exceptions without logging when fetching orderbook prices
    • Users won't know why prices are missing
    • Fix: Add logging when verbose mode is enabled
  3. Potential issue with token mapping (lines 492-496):

    • Token-to-market mapping is stored in memory and never cleared
    • Could cause issues with market re-indexing or closed markets
    • Fix: Add a cache invalidation mechanism or TTL
  4. Hardcoded pagination limit (line 667):

    • max_pages = 10 limits total results to ~1000 markets when all=True
    • No warning to users that results are capped
    • Fix: Either make this configurable or document the limitation

🔒 Security Concerns

  1. ⚠️ Private key handling (lines 186-192):

    • Private keys stored in plaintext memory
    • Consider using secure string types or warning users about memory dumps
    • Recommendation: Add documentation about secure key management
  2. Gas price oracle (line 1135):

    • Uses self._web3.eth.gas_price without bounds checking
    • Could lead to excessive gas costs during network congestion
    • Fix: Add max gas price limit or make it configurable
  3. Unlimited token approval (line 1115):

    • Approves 2**256 - 1 tokens to exchange contracts
    • Standard practice but increases risk if contracts are compromised
    • Recommendation: Document this risk and consider adding option for limited approvals
  4. RPC endpoint hardcoded (lines 73-74):

    • Public RPC endpoints may rate limit or go down
    • Fix: Make RPC URL configurable or support multiple fallback endpoints

⚡ Performance Considerations

  1. Unnecessary API calls in orderbook (lines 882-936):

    • Always fetches full orderbook even for simple price checks
    • Consider adding a separate endpoint for best bid/ask if available
  2. Blocking transaction waits (line 1153):

    • wait_for_transaction_receipt blocks for up to 60 seconds
    • Could timeout on slow networks
    • Fix: Make timeout configurable and add better error handling
  3. Inefficient market search (lines 851-867):

    • Fetches ALL markets then filters in memory
    • Could be slow with many markets
    • Fix: Use API search if available, or add early termination
  4. No connection pooling (line 163):

    • Creates new requests.Session but doesn't configure pool size
    • Fix: Consider configuring connection pool for better performance

🧪 Test Coverage

Missing Tests:

  • No unit tests for the PredictFun exchange implementation
  • No integration tests for order creation/cancellation
  • No tests for smart wallet signing logic
  • No tests for approval flow

Recommendations:

  1. Add unit tests for order signing (EIP-712)
  2. Add tests for price inversion logic (second outcome)
  3. Add tests for both EOA and Smart Wallet modes
  4. Mock the Web3 calls for testing approval flow

📚 Documentation & Code Comments

Good:

  • Clear docstrings on public methods
  • Helpful comments explaining dual wallet modes
  • Good README updates with examples

Needs Improvement:

  1. Complex cryptographic operations lack explanation (lines 1171-1227):

    • Kernel domain wrapping logic needs more detailed comments
    • EIP-712 signature flow could use step-by-step explanation
  2. Missing ADR/design doc for why certain design choices were made:

    • Why both yield-bearing and non-yield-bearing contracts?
    • When to use which exchange contract?

🎯 Recommendations Summary

High Priority:

  1. Fix the approval checking race condition
  2. Add tests for core functionality
  3. Address CLAUDE.md guideline fix: polymarket impl #4 violation (reduce .env variables)
  4. Add logging for silent failures

Medium Priority:

  1. Extract magic numbers to constants
  2. Make gas price and RPC endpoints configurable
  3. Improve error messages for better debugging
  4. Add documentation for cryptographic operations

Low Priority:

  1. Optimize market search
  2. Add cache invalidation for token mappings
  3. Configure connection pool settings

✨ Overall Assessment

This is a solid implementation that follows the existing codebase patterns well. The dual wallet mode support (EOA + Smart Wallet) is particularly well-executed with proper Kernel v0.3.1 EIP-712 signing.

Main concerns:

  • Lack of tests
  • Some deviation from CLAUDE.md guidelines
  • A few potential bugs around approval flow and error handling

Recommendation: Approve with minor changes requested. The implementation is functional but would benefit from addressing the high-priority items before merging.


Reviewed with: Claude Sonnet 4.5 via Claude Code
Files reviewed: 12 changed files, 1668 additions, 12 deletions

@guzus guzus self-requested a review January 10, 2026 07:05
@guzus guzus merged commit d110eb8 into main Jan 10, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Exchange: Predict.fun

3 participants