In order to ensure easy integration with external partners 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 and Market Contracts.
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:
Get a quote for a single market from Overtime API
Get a Sports AMM contract address for a specific network from Thales contracts
Get a Sports AMM contract ABI from Overtime contract repository contract repository
Create Sports AMM contract instance
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 ABIdotenv.config();constAPI_URL="https://overtimemarketsv2.xyz"; // base API URLconstNETWORK_ID=10; // optimism network IDconstNETWORK="optimism"; // optimism networkconstSPORTS_AMM_CONTRACT_ADDRESS="0x170a5714112daEfF20E798B6e92e25B86Ea603C1"; // SportsAMM contract address on optimismconstMARKET_ADDRESS="0xb157e64720d3ff251023119a5f6557067763b08a"; // address od market Chelsea - LiverpoolconstPOSITION=0; // select Chelsea positionconstBUY_IN=100; // 100 sUSDconstSLIPPAGE=0.02; // slippage 2%// create instance of Infura provider for optimism networkconstprovider=newethers.providers.InfuraProvider( { chainId:Number(NETWORK_ID), name:NETWORK },process.env.INFURA);// create wallet instance for provided private key and providerconstwallet=newethers.Wallet(process.env.PRIVATE_KEY, provider);// create instance of Sports AMM contractconstsportsAMM=newethers.Contract(SPORTS_AMM_CONTRACT_ADDRESS, sportsAMMContractAbi, wallet);constbuyFromAmm=async () => {try {// get a quote from Overtime API for provided market, position and buy-in amount on optimism networkconstquoteResponse=awaitaxios.get(`${API_URL}/overtime/networks/${NETWORK_ID}/markets/${MARKET_ADDRESS}/quote?position=${POSITION}&buyIn=${BUY_IN}` );constquoteData=quoteResponse.data;console.log("Quote data", quoteData);// convert payout got from API to BigNumberconstparsedPayout=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 amountconstparsedActualBuyInCollateralAmount=ethers.utils.parseEther(quoteData.actualBuyInCollateralAmount.toString() );// convert slippage tolerance to BigNumberconstparsedSlippage=ethers.utils.parseEther(SLIPPAGE.toString());// call buyFromAMM method on Sports AMM contractconsttx=awaitsportsAMM.buyFromAMM(MARKET_ADDRESS,POSITION, parsedPayout, parsedActualBuyInCollateralAmount, parsedSlippage, { type:2, maxPriorityFeePerGas:w3utils.toWei("0.00000000000000001"), } );// wait for the resultconsttxResult=awaittx.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:
Integration with Overtime API and Parlay AMM contract should include the following steps:
Get a quote for a parlay from Overtime API
Get a Parlay AMM contract address for a specific network from Thales contracts
Get a Parlay AMM contract ABI from Overtime contract repository contract repository
Create Parlay AMM contract instance
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 ABIdotenv.config();constAPI_URL="https://overtimemarketsv2.xyz"; // base API URLconstNETWORK_ID=10; // optimism network IDconstNETWORK="optimism"; // optimism networkconstPARLAY_AMM_CONTRACT_ADDRESS="0x82B3634C0518507D5d817bE6dAb6233ebE4D68D9"; // ParlayAMM contract address on optimismconstMARKETS= ["0xb157e64720d3ff251023119a5f6557067763b08a","0xbf1e460b82308cb76d5918377eb03ac7a3c33a43","0xa73553b23799ae0e8743771a79d26cb196eca892","0x91300647b7bc3b698fd2e841d26cdfc61a4145ed",]; // market addressesconstPOSITIONS= [0,1,0,0]; // market positionsconstBUY_IN=100; // 100 sUSDconstSLIPPAGE=0.02; // slippage 2%constZERO_ADDRESS="0x0000000000000000000000000000000000000000"; // pass as a differentRecipient parameter for the buyFromParlay method// create instance of Infura provider for optimism networkconstprovider=newethers.providers.InfuraProvider( { chainId:Number(NETWORK_ID), name:NETWORK },process.env.INFURA);// create wallet instance for provided private key and providerconstwallet=newethers.Wallet(process.env.PRIVATE_KEY, provider);// create instance of Parlay AMM contractconstparlayAMM=newethers.Contract(PARLAY_AMM_CONTRACT_ADDRESS, parlayAMMContractAbi, wallet);constbuyFromParlay=async () => {try {// get a quote from Overtime API for provided market addresses, market positions and buy-in amount on optimism networkconstquoteResponse=awaitaxios.get(`${API_URL}/overtime/networks/${NETWORK_ID}/parlay/quote?markets=${MARKETS.join("," )}&positions=${POSITIONS.join(",")}&buyIn=${BUY_IN}` );constquoteData=quoteResponse.data;console.log("Quote data", quoteData);// convert payout got from API to BigNumberconstparsedPayout=ethers.utils.parseEther(quoteData.payout.toString());// convert buy-in amount to BigNumberconstparsedBuyInAmount=ethers.utils.parseEther(BUY_IN.toString());// convert slippage tolerance to BigNumberconstparsedSlippage=ethers.utils.parseEther(SLIPPAGE.toString());// call buyFromParlay method on Parlay AMM contractconsttx=awaitparlayAMM.buyFromParlay(MARKETS,POSITIONS, parsedBuyInAmount, parsedSlippage, parsedPayout,ZERO_ADDRESS, { type:2, maxPriorityFeePerGas:w3utils.toWei("0.00000000000000001"), } );// wait for the resultconsttxResult=awaittx.wait();console.log(`Successfully bought from Parlay AMM. Transaction hash: ${txResult.transactionHash}` ); } catch (e) {console.log("Failed to buy from Parlay AMM", e); }};buyFromParlay();