Sports Markets Integration

Overtime API

In order to ensure easy integration with third party applications, Overtime API is created. API returns all main data available on Overtime. Using Overtime API endpoints someone can get data about:

  • Overtime sports

  • Overtime collaterals

  • Overtime markets

  • Overtime market

  • User Overtime positions

  • User Overtime transactions

  • Single quote

  • Parlay quote

More details about each API endpoint with request/response examples can be found under Postman documentation.

Contract integration

Once all data are fetched from API, the next step is integration with Overtime contracts. Depending on whether someone wants to buy a single or a parlay, integration should be done with Sports AMM Smart Contract or Parlay AMM Smart Contract.

The next sections describe integration with Overtime API and Overtime contracts together with JS code examples.

Buy a single

Let's say someone wants to buy positional tokens on Chelsea for the game Chelsea - Liverpool with a buy-in amount of 100 sUSD.

Integration with Overtime API and Sports AMM contract should include the following steps:

  1. Get a quote for a single market from Overtime API

  2. Get a Sports AMM contract address for a specific network from Thales contracts

  3. Get a Sports AMM contract ABI from Overtime contract repository contract repository

  4. Create Sports AMM contract instance

  5. Call buyFromAmm method on Sports AMM contract with input parameters fetched from Overtime API in step #1

The JS code snippet below implements these steps:

import { ethers } from "ethers";
import w3utils from "web3-utils";
import axios from "axios";
import dotenv from "dotenv";
import sportsAMMContractAbi from "./SportsAMMContractAbi.js"; // SportsAMM contract ABI

dotenv.config();

const API_URL = "https://overtimemarketsv2.xyz"; // base API URL
const NETWORK_ID = 10; // optimism network ID
const NETWORK = "optimism"; // optimism network
const SPORTS_AMM_CONTRACT_ADDRESS =
  "0x170a5714112daEfF20E798B6e92e25B86Ea603C1"; // SportsAMM contract address on optimism
const MARKET_ADDRESS = "0xb157e64720d3ff251023119a5f6557067763b08a"; // address od market Chelsea - Liverpool
const POSITION = 0; // select Chelsea position
const BUY_IN = 100; // 100 sUSD
const SLIPPAGE = 0.02; // slippage 2%

// create instance of Infura provider for optimism network
const provider = new ethers.providers.InfuraProvider(
  { chainId: Number(NETWORK_ID), name: NETWORK },
  process.env.INFURA
);

// create wallet instance for provided private key and provider
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);

// create instance of Sports AMM contract
const sportsAMM = new ethers.Contract(
  SPORTS_AMM_CONTRACT_ADDRESS,
  sportsAMMContractAbi,
  wallet
);

const buyFromAmm = async () => {
  try {
    // get a quote from Overtime API for provided market, position and buy-in amount on optimism network
    const quoteResponse = await axios.get(
      `${API_URL}/overtime/networks/${NETWORK_ID}/markets/${MARKET_ADDRESS}/quote?position=${POSITION}&buyIn=${BUY_IN}`
    );
    const quoteData = quoteResponse.data;
    console.log("Quote data", quoteData);

    // convert payout got from API to BigNumber
    const parsedPayout = ethers.utils.parseEther(quoteData.payout.toString());
    // convert actual buy-in amount got from API to BigNumber
    // actualBuyInCollateralAmount is different from BUY_IN due to the contract architecture having positions amount as input and not buy-in amount
    const parsedActualBuyInCollateralAmount = ethers.utils.parseEther(
      quoteData.actualBuyInCollateralAmount.toString()
    );
    // convert slippage tolerance to BigNumber
    const parsedSlippage = ethers.utils.parseEther(SLIPPAGE.toString());

    // call buyFromAMM method on Sports AMM contract
    const tx = await sportsAMM.buyFromAMM(
      MARKET_ADDRESS,
      POSITION,
      parsedPayout,
      parsedActualBuyInCollateralAmount,
      parsedSlippage,
      {
        type: 2,
        maxPriorityFeePerGas: w3utils.toWei("0.00000000000000001"),
      }
    );
    // wait for the result
    const txResult = await tx.wait();
    console.log(
      `Successfully bought from AMM. Transaction hash: ${txResult.transactionHash}`
    );
  } catch (e) {
    console.log("Failed to buy from AMM", e);
  }
};

buyFromAmm();

Buy a parlay

Let's say someone wants to buy a 4-game parlay with a buy-in amount of 100 sUSD.

  1. Get a quote for a parlay from Overtime API

  2. Get a Parlay AMM contract address for a specific network from Thales contracts

  3. Get a Parlay AMM contract ABI from Overtime contract repository contract repository

  4. Create Parlay AMM contract instance

  5. Call buyFromParlay method on Parlay AMM contract with input parameters fetched from Overtime API in step #1

The JS code snippet below implements these steps:

import { ethers } from "ethers";
import w3utils from "web3-utils";
import axios from "axios";
import dotenv from "dotenv";
import parlayAMMContractAbi from "./parlayAMMContractAbi.js"; // ParlayAMM contract ABI

dotenv.config();

const API_URL = "https://overtimemarketsv2.xyz"; // base API URL
const NETWORK_ID = 10; // optimism network ID
const NETWORK = "optimism"; // optimism network
const PARLAY_AMM_CONTRACT_ADDRESS =
  "0x82B3634C0518507D5d817bE6dAb6233ebE4D68D9"; // ParlayAMM contract address on optimism
const MARKETS = [
  "0xb157e64720d3ff251023119a5f6557067763b08a",
  "0xbf1e460b82308cb76d5918377eb03ac7a3c33a43",
  "0xa73553b23799ae0e8743771a79d26cb196eca892",
  "0x91300647b7bc3b698fd2e841d26cdfc61a4145ed",
]; // market addresses
const POSITIONS = [0, 1, 0, 0]; // market positions
const BUY_IN = 100; // 100 sUSD
const SLIPPAGE = 0.02; // slippage 2%
const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"; // pass as a differentRecipient parameter for the buyFromParlay method

// create instance of Infura provider for optimism network
const provider = new ethers.providers.InfuraProvider(
  { chainId: Number(NETWORK_ID), name: NETWORK },
  process.env.INFURA
);

// create wallet instance for provided private key and provider
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);

// create instance of Parlay AMM contract
const parlayAMM = new ethers.Contract(
  PARLAY_AMM_CONTRACT_ADDRESS,
  parlayAMMContractAbi,
  wallet
);

const buyFromParlay = async () => {
  try {
    // get a quote from Overtime API for provided market addresses, market positions and buy-in amount on optimism network
    const quoteResponse = await axios.get(
      `${API_URL}/overtime/networks/${NETWORK_ID}/parlay/quote?markets=${MARKETS.join(
        ","
      )}&positions=${POSITIONS.join(",")}&buyIn=${BUY_IN}`
    );
    const quoteData = quoteResponse.data;
    console.log("Quote data", quoteData);

    // convert payout got from API to BigNumber
    const parsedPayout = ethers.utils.parseEther(quoteData.payout.toString());
    // convert buy-in amount to BigNumber
    const parsedBuyInAmount = ethers.utils.parseEther(BUY_IN.toString());
    // convert slippage tolerance to BigNumber
    const parsedSlippage = ethers.utils.parseEther(SLIPPAGE.toString());

    // call buyFromParlay method on Parlay AMM contract
    const tx = await parlayAMM.buyFromParlay(
      MARKETS,
      POSITIONS,
      parsedBuyInAmount,
      parsedSlippage,
      parsedPayout,
      ZERO_ADDRESS,
      {
        type: 2,
        maxPriorityFeePerGas: w3utils.toWei("0.00000000000000001"),
      }
    );
    // wait for the result
    const txResult = await tx.wait();
    console.log(
      `Successfully bought from Parlay AMM. Transaction hash: ${txResult.transactionHash}`
    );
  } catch (e) {
    console.log("Failed to buy from Parlay AMM", e);
  }
};

buyFromParlay();

Last updated