Skip to content

Getting Started

Four steps stand between you and your first quote: depositing USDC.e onto Polygon, deploying a wallet, granting token approvals to the exchange contracts, and generating API credentials.


Openfish markets settle in USDC.e (bridged USDC) on Polygon. Load your trading wallet using whichever method fits your workflow.

MethodBest For
Bridge APIAutomated deposits from Ethereum or other chains
Direct Polygon transferYou already hold USDC.e on Polygon
Cross-chain bridgeLarge deposits from Ethereum mainnet

A standard Ethereum externally owned account. You pay gas for all on-chain operations (approvals, splits, merges, settlement).

A Gnosis Safe deployed via the Openfish relayer. Benefits include gasless transactions for on-chain operations and support for batched calls.

Deploy a Safe wallet with the Rust SDK:

use openfish_client_sdk::wallet::deploy_safe;
let safe_address = deploy_safe(&relayer_client, &signer).await?;
println!("Safe deployed at: {safe_address:#x}");

The exchange contracts need permission to move your tokens before you can trade.

TokenSpenderPurpose
USDC.eCTF ContractSplit USDC.e into outcome tokens
CTF (outcome tokens)CTF ExchangeTrade on standard markets
CTF (outcome tokens)Neg Risk CTF ExchangeTrade on negative risk markets
// All contracts live on Polygon mainnet (chain ID 137).
const USDC_E: &str = "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174";
const CTF: &str = "0x4D97DCd97eC945f40cF65F87097ACe5EA0476045";
const CTF_EXCHANGE: &str = "0xA642f9165D192Ff13b1D43a0Ef56B3BD074614bB";
const NEG_RISK_EXCHANGE: &str = "0x700eaF3f3FEb1D3f2aE67000e1A4FA41a6E35DF1";
const NEG_RISK_ADAPTER: &str = "0x0d8FA66CFe5D5EF96D6be9C4e808BD4279527d6e";
use openfish_client_sdk::{POLYGON, contract_config};
use openfish_client_sdk::ctf::Client as CtfClient;
let config = contract_config(POLYGON, false).expect("polygon config");
// Approve USDC.e for the CTF contract (splitting)
ctf_client.approve_erc20(config.collateral, config.conditional_tokens, u256::MAX).await?;
// Approve outcome tokens for the CTF Exchange (trading)
ctf_client.approve_for_all(config.conditional_tokens, config.exchange).await?;
// For negative risk markets, also approve the Neg Risk Exchange
let neg = contract_config(POLYGON, true).expect("neg risk config");
ctf_client.approve_for_all(neg.conditional_tokens, neg.exchange).await?;

Authenticated CLOB endpoints rely on L2 API credentials derived from a wallet signature.

use openfish_client_sdk::clob::{Client, Config};
use openfish_client_sdk::auth::{LocalSigner, Signer};
use std::str::FromStr;
let private_key = std::env::var("OPENFISH_PRIVATE_KEY")?;
let signer = LocalSigner::from_str(&private_key)?
.with_chain_id(Some(openfish_client_sdk::POLYGON));
let client = Client::new("https://api.openfish.fun", Config::default())?
.authentication_builder(&signer)
.authenticate()
.await?;
// The client now holds your API key, secret, and passphrase internally.

Persist credentials in environment variables — never check them into version control.

Terminal window
export OPENFISH_PRIVATE_KEY="0x..."
export OPENFISH_API_KEY="..."
export OPENFISH_SECRET="..."
export OPENFISH_PASSPHRASE="..."

  • Trading — Post limit orders and manage quotes.
  • Market Data — Connect to real-time orderbook feeds.
  • Inventory — Split USDC.e into outcome tokens for quoting.