Skip to main content
POST
/
orders
/
fill
/
v2
Sign & Fill Order
import { Wallet, ZeroAddress, ZeroHash, randomBytes, hexlify } from "ethers";

async function fillOrder() {
  // get the following from https://api.sx.bet/metadata
  const EIP712FillHasherAddress = process.env.EIP712_FILL_HASHER_ADDRESS;
  const chainId = Number(process.env.CHAIN_ID); // Mainnet — use 79479957 for testnet
  const domainVersion = process.env.DOMAIN_VERSION;

  const wallet = new Wallet(process.env.SX_PRIVATE_KEY);
  const takerAddress = wallet.address;
  const stakeWei = "50000000"; // 50 USDC
  const marketHash = "0x0246b760b06009ece42d08e706563de1967e7f1b4799d0f559244e3f80bbc496"; // Liverpool vs Arsenal
  const baseToken = "0x6629Ce1Cf35Cc1329ebB4F63202F3f197b3F050B"; // Mainnet — see References for testnet address
  const desiredOdds = "83000000000000000000"; // ~1.20 decimal odds
  const oddsSlippage = 5; // 5% slippage, so worst decimal odds ~1.14
  const isTakerBettingOutcomeOne = true; // taker is betting that team 1 wins
  const fillSalt = BigInt(hexlify(randomBytes(32))).toString();

  const domain = {
    name: "SX Bet",
    version: domainVersion,
    chainId,
    verifyingContract: EIP712FillHasherAddress,
  };

  const types = {
    Details: [
      { name: "action", type: "string" },
      { name: "market", type: "string" },
      { name: "betting", type: "string" },
      { name: "stake", type: "string" },
      { name: "worstOdds", type: "string" },
      { name: "worstReturning", type: "string" },
      { name: "fills", type: "FillObject" },
    ],
    FillObject: [
      { name: "stakeWei", type: "string" },
      { name: "marketHash", type: "string" },
      { name: "baseToken", type: "string" },
      { name: "desiredOdds", type: "string" },
      { name: "oddsSlippage", type: "uint256" },
      { name: "isTakerBettingOutcomeOne", type: "bool" },
      { name: "fillSalt", type: "uint256" },
      { name: "beneficiary", type: "address" },
      { name: "beneficiaryType", type: "uint8" },
      { name: "cashOutTarget", type: "bytes32" },
    ],
  };

  const message = {
    action: "N/A",
    betting: "N/A",
    stake: "N/A",
    worstOdds: "N/A",
    worstReturning: "N/A",
    market: marketHash,
    fills: {
      stakeWei,
      marketHash,
      baseToken,
      desiredOdds,
      oddsSlippage,
      isTakerBettingOutcomeOne,
      fillSalt,
      beneficiary: ZeroAddress,
      beneficiaryType: 0,
      cashOutTarget: ZeroHash,
    },
  };

  const signature = await wallet.signTypedData(domain, types, message);

  const apiPayload = {
    market: marketHash,
    baseToken,
    isTakerBettingOutcomeOne,
    stakeWei,
    desiredOdds,
    oddsSlippage,
    taker: takerAddress,
    takerSig: signature,
    fillSalt,
  };

  const response = await fetch(`https://api.sx.bet/orders/fill/v2`, { // Mainnet — use https://api.toronto.sx.bet for testnet
    method: "POST",
    body: JSON.stringify(apiPayload),
    headers: { "Content-Type": "application/json" },
  });
}
{
  "status": "success",
  "data": {
    "fillHash": "0x840763ae29b7a6adfa0e315afa47be30cdebd5b793d179dc07dc8fc4f0034965",
    "isPartialFill": false,
    "totalFilled": "50000000",
    "averageOdds": "73000000000000000000"
  }
}
Rate limit: All POST /orders/* endpoints share a combined limit of 5,500 requests/min. See Rate Limits.
This endpoint fills orders on the exchange based on the specified desiredOdds and oddsSlippage. Order matching is done internally after the built-in betting delay, optimizing the taker experience particularly during in-play betting. Furthermore, if any new orders with better odds are added during the betting delay window, those orders will be filled. Lastly, if there isn’t sufficient size to support the full stake amount, the response will include a isPartialFill: true flag to indicate that the fill was only partially filled. Takers can then attempt to fill again if they choose to do so. To fill orders on sx.bet via the API, make sure you first enable betting by following the steps here.
Your assets must be on SX Mainnet to place bets.

Body

application/json
market
string
required

User facing string for what market the user is betting on. Can simply set to "N/A" when using the API

baseToken
string
required

The address of the ERC-20 token representing the currency of the fill. Token addresses vary by network — see the addresses field in GET /metadata or the References page for the correct address.

isTakerBettingOutcomeOne
boolean
required

Whether or not taker is betting outcome 1 (team 1 wins), if false then taker is betting outcome 2 (team 2 wins)

stakeWei
string
required

The stake amount for this bet in wei units - see Unit Conversion. Minimum 1 USDC.

desiredOdds
string
required

The worst taker odds acceptable for filling, used as an anchor when applying oddsSlippage - note that any order found with taker odds better than the desiredOdds can still fill if found at the time of order matching

oddsSlippage
integer
required

An integer between 0-100 representing the percentage of tolerance that is acceptable based on desiredOdds

fillSalt
string
required

Random 32 byte string to identify this fill. Must match the fillSalt used when computing the signing payload

taker
string
required

Address of the taker taking the bet

takerSig
string
required

Your wallet signature over the fill payload.

Response

status
string

success or failure if the request succeeded or not

data
object