Skip to main content
One script takes you through a full trade on Mainnet (https://upsidemax.xyz). It registers your wallet (with an invitation code), checks that the account has usable margin, then places and cancels a limit order. Every POST /exchange call is signed with EIP-712; read queries to POST /info need no signature. The script resolves its contract from configs rather than assuming one. Filter to status: "Active" first — the response also returns delisted contracts, with a full parameter set and nothing else to mark them — then either match on name or take the first Active contract. contractId 1/2/3 do not map to any fixed pair.

Prerequisites

Get an invitation code first. Registration requires a valid single-use inviteCode — request one from the UpsideMAX team and set it as INVITE_CODE below. A new account starts with no balance: deposit funds before the script reaches the order step, or the script stops and tells you so. Mainnet trades real funds — the order below rests 20% away from the mark price and is cancelled straight away.

The script

Two ways in

Python SDK — recommended

pip install upside-python-sdk. The client builds and signs the EIP-712 payloads for you, so the same flow is a handful of calls.

REST directly

The script below, with the signer written out. Worth reading once even if you use the SDK — it is the clearest description of the signing protocol.
The SDK covers the same flow in a few lines:
Some endpoints have no SDK method yet — see SDKs for the current gaps.

The script

Set INVITE_CODE, then run. Only registerAccount and lockCollateral use the EIP-712 typed path here — the full typed set is in Authentication.

Expected output

Configuration

The script hardcodes only these settings, and none is an ID: The order size is the smallest whole multiple of stepSize whose notional (price × size × notionalScaleMultiplier, all raw) reaches the top-level minNotionalValue in configs. Every order that is not reduce-only must meet that minimum. Everything else — the contract ID, the quote coin ID, priceScale, qtyScale, tickSize, stepSize — is read from configs at runtime, and the limit price is derived from the live mark price. Do not replace any of that with a literal. Contract IDs are server-assigned, scales differ per contract and are frequently 0, and a price that is not derived from the current mark will be rejected by the contract’s price band. Prices and sizes (p, s) are raw integer strings, scaled by that contract’s priceScale / qtyScale.
  • inviteCode required — INVITE_CODE is missing or invalid. Set a valid single-use code from the UpsideMAX team.
  • has no usable margin — the account holds no funds in the market deployer. Deposit funds, then re-run: the script reuses the saved wallet and account, so no second invitation code is spent.
  • Order rejected for margin — the account’s marginAvailableForOrder is below what the order needs. Add funds or lower the size.
  • SIGNATURE_INVALID — CHAIN_ID does not match BASE_URL: Mainnet signs over 9788, Devnet over 9767.
  • No oid in the order response — submission is asynchronous. A 202 with "status": "accepted" means the batch was taken for processing, not that the order rested. The script confirms by polling userOrders for its own clientOrderId.
  • the order never rested — the order was rejected after acceptance. The rejection is only delivered on the orderUpdates channel, never in the HTTP response. Subscribe to it and read reason. The most common cause is price exceeds priceBandBps: a limit price further from the mark price than the contract’s priceBandBps allows.