Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.delphimarkets.com/llms.txt

Use this file to discover all available pages before exploring further.

Opinion Labs (opinion.trade) runs on BNB Chain and uses a Gnosis Safe to hold positions, similar in structure to Polymarket. Orders are EIP-712 signed by your EOA on behalf of the Safe.

At a glance

ChainBNB Chain (chainId 56)
Wallet modelGnosis Safe, signed by EOA
Quote tokenUSDT (18 decimals on BSC)
SigningClient-side (EIP-712)
AuthOpinion Labs API key + EOA private key

Prerequisites

  • An Opinion Labs account (opinion.trade)
  • USDT on BNB Chain in your Opinion Labs Safe wallet
  • The EOA private key that controls the Safe
  • A Delphi API key

One-time setup

Opinion Labs has two pre-trading steps: looking up your Safe address and approving the exchange contracts.

1. Get your Safe address

import { getSafeAddress } from '@delphimarkets/sdk';

const safeAddress = await getSafeAddress(process.env.OPINIONLABS_API_KEY!);
console.log(safeAddress); // 0x...
This calls the Opinion Labs API directly (no server-side state).

2. Approve the exchange contracts

The Safe needs to approve the CTF Exchange contract to spend your USDT and Conditional Tokens. This is a one-time transaction per Safe.
import {
  getSafeApprovalStatus,
  enableTrading,
} from '@delphimarkets/sdk';
import { createWalletClient, createPublicClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { bsc } from 'viem/chains';

const account = privateKeyToAccount(`0x${process.env.OPINIONLABS_PRIVATE_KEY!}`);
const walletClient = createWalletClient({ account, chain: bsc, transport: http() });
const publicClient = createPublicClient({ chain: bsc, transport: http() });

const status = await getSafeApprovalStatus(publicClient, safeAddress);
if (!status.allApproved) {
  const txHash = await enableTrading(safeAddress, walletClient, publicClient);
  await publicClient.waitForTransactionReceipt({ hash: txHash });
  console.log(`Approvals confirmed: ${txHash}`);
}
enableTrading submits a Safe transaction that sets approvals for both USDT (ERC-20) and Conditional Tokens (ERC-1155). After it confirms, you can place orders.

3. Register credentials with Delphi

const client = new DelphiClient({
  apiKey: process.env.DELPHI_API_KEY!,
  baseUrl: 'https://api.delphiterminal.co',
});

await client.registerCredentials('opinionlabs', {
  api_key: process.env.OPINIONLABS_API_KEY!,
  api_secret: '',                  // unused
  api_passphrase: '',              // unused
  signer_address: account.address, // your EOA address
});

Build and place an order

import { DelphiClient, buildOpinionLabsOrder } from '@delphimarkets/sdk';
import { createWalletClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { bsc } from 'viem/chains';

const account = privateKeyToAccount(`0x${process.env.OPINIONLABS_PRIVATE_KEY!}`);
const walletClient = createWalletClient({ account, chain: bsc, transport: http() });

const signedOrder = await buildOpinionLabsOrder(
  {
    marketId: 8453,                  // numeric market ID
    tokenId: '1087612329966...',     // outcome token (uint256 decimal string)
    side: 'BUY',
    price: 0.50,                     // 0.01 to 0.99
    amount: 3,                        // USDT amount, human-readable
    safeAddress,                      // from step 1 above
  },
  walletClient,
);

const order = await client.placeOrder({
  exchange: 'opinionlabs',
  market_id: '8453',
  order_type: 'GTC',
  signed_order: signedOrder,
});

console.log(`Placed: ${order.order_id} (${order.status})`);

Build parameters

FieldTypeDescription
marketIdnumberOpinion Labs numeric market ID.
tokenIdstringOutcome token ID (uint256 decimal string).
side'BUY' | 'SELL'
pricenumberPrice per share in [0.01, 0.99].
amountnumberUSDT amount, human-readable (e.g. 3 for 3 USDT).
safeAddressstringYour Opinion Labs Safe address. Required.
feeRateBpsstring?Default '0'.
expirationnumber?Unix seconds. Default = now + 24h.
The signed payload includes both the EIP-712 fields and Opinion-Labs-specific metadata (topicId, currencyAddress, tradingMethod, etc.) that the Opinion Labs API requires alongside the signature.

Query and cancel

const status = await client.getOrder(order.order_id, 'opinionlabs');
const all = await client.listOrders('opinionlabs');
await client.cancelOrder(order.order_id, 'opinionlabs');

Common pitfalls

Run enableTrading() once and wait for the receipt. The Safe transaction sets approvals atomically. Re-check getSafeApprovalStatus() after the receipt confirms — it should return allApproved: true.
USDT on BNB Chain uses 18 decimals, not 6 like USDT on Ethereum or Polygon. The SDK handles this for you — pass human-readable values to amount (e.g. 3 for 3 USDT) and the SDK converts internally.
Opinion Labs requires signatureType: '2' (POLY_GNOSIS_SAFE) — the Safe signs as the asset owner with the EOA producing the signature. The SDK sets this automatically. If you’re hand-rolling a signed payload, don’t use 0 (EOA) or 1 (PROXY).
Opinion Labs’s API requires both signature and sign fields, set to the same value. The SDK populates both. This is a quirk of their API surface, not a bug.

API reference