Python client for the Forkast Orderbooks
Project description
Forkast Python SDK
A Python SDK for interacting with the Forkast trading platform
✨ Features
- 🔐 Gnosis Safe (Proxy Wallet) approval via MultiSend
- 📝 Place / cancel orders (EIP-712 signed)
- 📊 Fetch balances, markets, orders
- 🌐 Network-aware (Testnet / Mainnet)
- 🧪 Integration tests
🚧 Requirements
- Python >= 3.12
- pip
- An async-compatible environment (asyncio)
📦 Installation
pip install forkast-py-client
🌀 Running
⚠️ Examples require Python ≥ 3.12 and a virtual environment. You can see the full quickstart example below at examples/example.py. Run examples with:
python3 examples/example.py
⚠️ Async Usage
This SDK is fully asynchronous and built on top of aiohttp.
- All network calls must be awaited
- The SDK must be used inside an async event loop
- Always use
async with ForkastSDK(...)or callawait sdk.open()
Example:
async with ForkastSDK(...) as sdk:
...
🚀 Quick Start
Minimal Example
import asyncio
from forkast_py_client import ForkastSDK, Network
async def main():
async with ForkastSDK(Network.TESTNET) as sdk:
market_service = sdk.get_market_service()
event_id = 35 # Replace with a valid event id
event_data = await market_service.get_event_data(event_id)
print("Event data: ", event_data)
asyncio.run(main())
1️⃣ Initialize SDK
import asyncio
from eth_account import Account
from forkast_py_client import ForkastSDK, MarketOutcome, Network, load_abi, create_provider_without_signer
async def main():
# Initialize SDK
async with ForkastSDK(
network=Network.TESTNET, # or Network.MAINNET
api_key="YOUR_API_KEY"
) as sdk:
2️⃣ Login using private key
account_service = sdk.get_account_service()
# Login using private key
private_key = "YOUR_PRIVATE_KEY"
login = await account_service.login_with_private_key(private_key)
access_token = login.access_token
print("access token: ", access_token)
3️⃣ Fetch user profile
user = await account_service.get_user(access_token)
print("User: ", user)
4️⃣ Fetch balances
balances_service = sdk.get_balances_service()
balances = await balances_service.get_balances(access_token)
print("Balances: ", balances)
5️⃣ Fetch event data
market_service = sdk.get_market_service()
event_id = 35 # Replace with a valid event id
event_data = await market_service.get_event_data(event_id)
print("Event data: ", event_data)
6️⃣ Choose a market and get its details
market_id = event_data.markets[0].id
outcome_id = event_data.markets[0].outcomes[0].id
outcome_token_id = event_data.markets[0].outcomes[0].token_id
outcome_type = event_data.markets[0].outcomes[0].outcome_type
order_book = await market_service.get_order_book(market_id, outcome_id, outcome_type)
print("Market ID: ", market_id)
print("Outcome ID: ", outcome_id)
print("Outcome Token ID: ", outcome_token_id)
print("Outcome Type: ", outcome_type)
print("Orderbook: ", order_book)
7️⃣ Get token prices
token_prices = await market_service.get_token_prices(market_id, 0) # 0 = BUY, 1 = SELL
print("Token prices: ", token_prices)
8️⃣ Approve if needed
Required once before placing orders.
signer = Account.from_key(private_key)
provider = await create_provider_without_signer(Network.TESTNET)
proxy_wallet = "YOUR_PROXY_WALLET_ADDRESS"
gnosis_safe_abi = load_abi("GnosisSafe.abi.json")
multi_send = "MULTI_SEND_CONTRACT_ADDRESS"
chain_id = 421614 # Arbitrum Sepolia (TESTNET), replace with correct chain id
result = await account_service.approve_max_platform_credits_for_proxy_wallet(
signer=signer,
wallet_proxy_address=proxy_wallet,
buy_amount=10000000,
)
print("approve_max_platform_credits_for_proxy_wallet_success response: ", result)
Send transaction if approval is required
if result is not None:
gnosis_safe = provider.eth.contract(
address=proxy_wallet,
abi=gnosis_safe_abi,
)
tx = await gnosis_safe.functions.execTransaction(
provider.to_checksum_address(multi_send),
0, # value
bytes.fromhex(result.data_sign["data"][2:]),
1, # DELEGATE_CALL
0,
0,
0,
"0x0000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000",
bytes.fromhex(result.signature[2:]),
).build_transaction(
{
"from": signer.address,
"nonce": await provider.eth.get_transaction_count(signer.address),
"gas": 500_000,
"chainId": chain_id,
}
)
print("Built tx: ", tx)
signed_tx = signer.sign_transaction(tx) # The signer address will be the one sending tx, so we need to ensure signer has enough gas
tx_hash = await provider.eth.send_raw_transaction(signed_tx.raw_transaction)
await provider.eth.wait_for_transaction_receipt(tx_hash)
print("Tx Hash: ", tx_hash.hex())
⚠️ The signer address must have enough native gas.
9️⃣ Place an order
order_service = sdk.get_order_service()
market_outcome = MarketOutcome(
id=outcome_id, # outcome id
token_id=outcome_token_id, # outcome token id
outcome_type=outcome_type, # 0 = No, 1 = Yes
)
resp = await order_service.place_single_order(
event_id=event_id,
market_id=market_id,
token=market_outcome,
account={
"wallet": signer.address,
"private_key": private_key,
"proxy_wallet": proxy_wallet,
},
price=0.7, # the price you want to place your order
amount=96, # the amount you want to buy/sell
side=0, # the side of your order: 0 = BUY, 1 = SELL
access_token=access_token,
)
print("place_single_order response:", resp)
order_id_placed = None
if resp.success:
order_id_placed = resp.order_result["data"]["id"]
print("Order ID placed: ", order_id_placed)
🔟 Get all orders
resp = await order_service.get_all_orders(
address=proxy_wallet,
outcome_id=outcome_id,
access_token=access_token,
limit=10,
page=1,
)
print("get_all_orders response:", resp)
🟡 Cancel order
if order_id_placed:
resp = await order_service.cancel_order(
order_id=order_id_placed,
access_token=access_token,
)
print("cancel_order response:", resp)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file forkast_py_client-0.3.0.tar.gz.
File metadata
- Download URL: forkast_py_client-0.3.0.tar.gz
- Upload date:
- Size: 36.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.4.1 CPython/3.12.6 Windows/11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3349ab1d7116d0796399bf88d9592c75feb1cbbe21bbea9587f89fc3feda4ca3
|
|
| MD5 |
2f831f0f3eae4a5da23d40502029c1e7
|
|
| BLAKE2b-256 |
08706d7a54ba592852c0890d0c199a383d1f934d81ad701d6f65e4d84f7fa294
|
File details
Details for the file forkast_py_client-0.3.0-py3-none-any.whl.
File metadata
- Download URL: forkast_py_client-0.3.0-py3-none-any.whl
- Upload date:
- Size: 44.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.4.1 CPython/3.12.6 Windows/11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
58549e006ee2c25c700803141ee219e013da8bbd0266659d76dee6e2f603a6b9
|
|
| MD5 |
e914c04afb0c92544d1bd1bbafc62ca5
|
|
| BLAKE2b-256 |
3eff2aa9d135b1dd65e06d247ebff29221f5ba3749715d78cb095a590b483d9c
|