{"id":8130,"library":"driftpy","title":"Python client for the Drift DEX","description":"DriftPy is the official Python client for the Drift Protocol, a decentralized exchange on the Solana blockchain. It enables users to programmatically trade, fetch data, and interact with the Drift DEX. The library is actively maintained with frequent updates, currently at version 0.8.89.","status":"active","version":"0.8.89","language":"en","source_language":"en","source_url":"https://github.com/drift-labs/driftpy","tags":["solana","defi","dex","trading","crypto","blockchain"],"install":[{"cmd":"pip install driftpy","lang":"bash","label":"Install latest version"}],"dependencies":[{"reason":"Requires Python 3.10 or newer, but less than 4.0.","package":"python","optional":false},{"reason":"Fundamental for Solana RPC communication and keypair management.","package":"solana","optional":false},{"reason":"Used for Solana wallet integration, commonly alongside driftpy.","package":"anchorpy","optional":false},{"reason":"Often used in examples for managing environment variables (e.g., RPC URL, private key).","package":"python-dotenv","optional":true}],"imports":[{"symbol":"DriftClient","correct":"from driftpy.drift_client import DriftClient"},{"symbol":"DriftUser","correct":"from driftpy.drift_user import DriftUser"},{"symbol":"BASE_PRECISION, AMM_RESERVE_PRECISION","correct":"from driftpy.constants.numeric_constants import BASE_PRECISION, AMM_RESERVE_PRECISION"},{"symbol":"AccountSubscriptionConfig","correct":"from driftpy.account_subscription_config import AccountSubscriptionConfig"},{"symbol":"load_keypair","correct":"from driftpy.keypair import load_keypair"},{"symbol":"AsyncClient","correct":"from solana.rpc.async_api import AsyncClient"},{"note":"While `solana.keypair.Keypair` might work in older versions, `solders.keypair.Keypair` is the recommended and re-exported symbol from the `solana` library.","wrong":"from solana.keypair import Keypair","symbol":"Keypair","correct":"from solders.keypair import Keypair"},{"symbol":"Wallet","correct":"from anchorpy import Wallet"}],"quickstart":{"code":"import os\nimport asyncio\nfrom dotenv import load_dotenv\nfrom solders.keypair import Keypair\nfrom solana.rpc.async_api import AsyncClient\nfrom anchorpy import Wallet\nfrom driftpy.drift_client import DriftClient\nfrom driftpy.keypair import load_keypair\n\nasync def main():\n    load_dotenv() # Load .env file for environment variables\n\n    # It's safer to use os.environ.get with a default empty string for sensitive info\n    # and then handle the case where it's missing.\n    secret_key_str = os.environ.get(\"PRIVATE_KEY\", \"\") \n    rpc_url = os.environ.get(\"RPC_URL\", \"https://api.devnet.solana.com\")\n\n    if not secret_key_str:\n        print(\"Error: PRIVATE_KEY environment variable not set.\")\n        return\n    if not rpc_url:\n        print(\"Error: RPC_URL environment variable not set.\")\n        return\n\n    # Ensure the secret key is in the correct format (list of integers)\n    try:\n        secret_key_bytes = bytes(list(map(int, secret_key_str.strip('[]').split(','))))\n        keypair = Keypair.from_secret_key(secret_key_bytes)\n    except Exception as e:\n        print(f\"Error loading keypair: {e}. Ensure PRIVATE_KEY is a comma-separated list of integers in your .env file.\")\n        return\n\n    wallet = Wallet(keypair)\n    connection = AsyncClient(rpc_url)\n    \n    # Initialize DriftClient for 'devnet'\n    # For mainnet, use 'mainnet'\n    drift_client = DriftClient(\n        connection,\n        wallet,\n        \"devnet\", \n    )\n\n    print(\"Subscribing to Drift Client...\")\n    await drift_client.subscribe() # Crucial: Must subscribe before fetching data\n    print(\"Drift Client subscribed.\")\n\n    # Optional: Register a default sub-account if not already done\n    # await drift_client.add_user(0)\n\n    # Example: Fetch user stats (after subscription)\n    user_stats = await drift_client.get_user_stats_account()\n    print(f\"User Stats: {user_stats}\")\n\n    await drift_client.unsubscribe()\n    await connection.close()\n\nif __name__ == \"__main__\":\n    asyncio.run(main())\n","lang":"python","description":"This quickstart demonstrates how to initialize the Drift client, connect to a Solana RPC, and subscribe to market data. It assumes `PRIVATE_KEY` (as a comma-separated list of integers) and `RPC_URL` are set in a `.env` file. Proper subscription is critical before making data requests."},"warnings":[{"fix":"Always ensure `await drift_client.subscribe()` is called and awaited after instantiating `DriftClient` before attempting to interact with the protocol.","message":"Failing to call `await drift_client.subscribe()` after `DriftClient` initialization will cause `IndexError: list index out of range` or similar data access errors when attempting to fetch market or user data.","severity":"breaking","affected_versions":"All versions"},{"fix":"Initialize `DriftClient` with `account_subscription=AccountSubscriptionConfig('demo')` and ensure `perp_market_indexes` and `spot_market_indexes` parameters each contain at most one index. Call `get_markets_and_oracles()` to retrieve necessary market info for 'demo' config.","message":"Users of QuickNode's free RPC plan must use `AccountSubscriptionConfig('demo')` and are limited to subscribing to only one perp market and one spot market at a time. Exceeding this limit or using other configurations will result in connection issues (e.g., 'quiknode 400 error').","severity":"gotcha","affected_versions":"All versions"},{"fix":"Upgrade `driftpy` to version `0.8.86` or higher, which includes a bump to `cffi>=1.17.1` (though `cffi>=2.0.0` is recommended for Python 3.14+). If issues persist, manually ensure `pip install cffi>=2.0.0` is used.","message":"When running on Python 3.13, older versions of `cffi` (specifically below 2.0.0) might not be fully compatible, potentially leading to build or runtime issues, especially with free-threaded Python builds.","severity":"gotcha","affected_versions":"<0.8.86"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"Add `await drift_client.subscribe()` immediately after `DriftClient` instantiation to properly initialize data caches. Ensure this is awaited in an `async` context.","cause":"Attempting to access market or user data from `DriftClient` before `await drift_client.subscribe()` has been successfully called and completed.","error":"IndexError: list index out of range"},{"fix":"Verify that the `Keypair` used to initialize the `Wallet` and `DriftClient` corresponds to the actual authority or a correctly configured delegate with appropriate permissions. Double-check your `PRIVATE_KEY` and ensure it matches the expected account.","cause":"This error typically occurs when trying to perform transactions (e.g., cancelling an order) on a delegated account where the signing keypair is not correctly configured or does not have the necessary permissions for the action.","error":"AttributeError: transaction has not been signed correctly"},{"fix":"Switch to `AccountSubscriptionConfig('demo')` for free QuickNode plans. Limit `perp_market_indexes` and `spot_market_indexes` in `DriftClient` initialization to at most one index each. Consider using a paid RPC for higher limits and more flexibility.","cause":"Using a QuickNode free plan RPC endpoint with an `AccountSubscriptionConfig` other than 'demo', or subscribing to more than one perp/spot market.","error":"quiknode 400 error"}]}