PariBox.tsx
Importing Dependencies
We will start by importing the necessary dependencies needed for our PariBox
component.
The dependencies that will be utilized are as follows:
import { useConnection } from "@solana/wallet-adapter-react";
import { FC, useState } from "react";
import {
ParimutuelWeb3,
MarketPairEnum,
getMarketPubkeys,
calculateNetOdd,
} from "@hxronetwork/parimutuelsdk";
import { useEffect } from "react";
import { PariConfig } from "./Config";
With these dependencies in place, we are now ready to start building our PariBox
component.
Before diving in, let's first prepare a few essential elements under our imports that will be utilized later on:
Create a
PariObj
interface to store the contest information, including the Long and Short Pools' amounts, odds, and pubkey.
interface PariObj {
longPool: any; // This is how much money is in the Long Pool of the contest
shortPool: any; // This is how much money is in the Short Pool of the contest
longOdds: string; // This is the weighted odds of the Long Pool
shortOdds: string; // This is the weighted odds of the Short Pool
pubkey: string; // This is the contest pubkey
}Next, create a constant named TimeInterval to store various time intervals for ease of use.
Create a constant named TimeInterval to store various time intervals for ease of use.
const TimeInterval = [
{
interval: '1M',
seconds: 60,
title: "1 MINUTE",
},
{
interval: '5M',
seconds: 300,
title: "5 MINUTE",
},
{
interval: '15M',
seconds: 900,
title: "15 MINUTE",
},
{
interval: '1H',
seconds: 3600,
title: "1 HOUR",
},
{
interval: '1D',
seconds: 86400,
title: "1 DAY",
},
];
Setting up our component
Start by creating a functional component called
PariBox
. It will take in a prop calledtime
.
export const PariBox: FC<{ time: string }> = (props) => {
const { time } = props;
Next, filter the
TimeInterval
array to find the object that matches thetime
prop passed in.
const selectedTime = TimeInterval.filter((data) => data.interval === time);
Extract the
seconds
andtitle
properties from the selected object.
const timeSeconds = selectedTime[0].seconds
const timeTitle = selectedTime[0].title
Define a state variable to store the PariObj data. The
useState
hook is used to manage this state in the function component.
const [pariObj, setPariObj] = useState<PariObj>();
Define a state variable to store the countDownTime data. The
useState
hook is used to manage this state in the function component.
const [countDownTime, setCountDownTime] = useState<string>("");
Create a constant
config
that holds the configuration values imported from theConfig.tsx
file
const { config } = PariConfig;
Create constant
**connection**
, which handles the connection to Solana depending on the user's wallet, and instantiate a newParimutuelWeb3
object withconfig
andconnection
as parameters.
const { connection } = useConnection();
const parimutuelWeb3 = new ParimutuelWeb3(config, connection);
Define the
marketPair
with**MarketPairEnum**
to select the market that we want to get the contests from. Formarkets
, use the**getMarketPubkeys**
method to retrieve all of the Pubkeys of the specified market/s, and create amarketsByTime
variable that filters themarkets
based on whether the duration is the same astimeSeconds
value so that we get only the contests from the desired time interval.
// To get only the BTC-USD Market Contests
const marketPair = MarketPairEnum.BTCUSD;
const markets = getMarketPubkeys(config, marketPair);
const marketsByTime = markets.filter(
(market) => market.duration === timeSeconds
);
Getting contest data
Use the
useEffect
hook to run a specific effect when the component is rendered. In this case, the effect will fetch data about the contest and set it in thepariObj
state.
useEffect(() => {
const getPariData = async () => {
// make sure that we don't exceed the localStorage 10MB capacity when
// calling our data
localStorage.clear();
// Fetch contest data and set it in the pariObj state
};
fetchData();
}, []);
Retrieving contests
Use the
parimutuelWeb3.getParimutuels
method to retrieve the parimutuel data from theparimutuels
arraymarketsByTerm
, and retrieve the duration of the selected parimutuel market.
const parimutuels = await parimutuelWeb3.getParimutuels(marketsByTime);
const duration = marketsByTime[0].duration;
Use the
parimutuelWeb3.getMarkets
method to retrieve the market data.
const getMarkets = await parimutuelWeb3.getMarkets(market)
To retrieve only the next-in-line contests, filter the
parimutuels
array to find the parimutuel accounts that match the conditions.
const pari_markets = parimutuels.filter(
(account) =>
account.info.parimutuel.timeWindowStart.toNumber() > Date.now() &&
account.info.parimutuel.timeWindowStart.toNumber() <
Date.now() + duration * 1000
);
Extracting data from contests
Assigning data to variables:
// Assign active long and active short pools and divide them by USDC
// decimal size to get the real amount
let longPool: any =
(pari_markets[0].info.parimutuel.activeLongPositions.toNumber() /
1_000_000_000);
let shortPool: any =
(pari_markets[0].info.parimutuel.activeShortPositions.toNumber() /
1_000_000_000);
// Calculate the odds for long and short pools with the
// calculateNetOdds(side, totalPool, rake) method from the SDK
// by passing it in the respective pool side, total pool size,
// and the rake which is the fee that the Parimutuel protocol takes which is 3%
const longOdds = calculateNetOdd(longPool, longPool + shortPool, 0.03);
const shortOdds = calculateNetOdd(shortPool, longPool + shortPool, 0.03);
// Get the public key of the selected parimutuel contract and turn it
// into a string
const pubkey = pari_markets[0].pubkey.toString();
// Get the lock time of the selected parimutuel contract
const locksTime =
pari_markets[0].info.parimutuel.timeWindowStart.toNumber();
// Round the values of long and short pools to 2 decimal places
//
longPool = longPool.toFixed(2)
shortPool = shortPool.toFixed(2)
// Now we can update our contest by setting the state of our pariObj
// object with this data
setPariObj({ longPool, shortPool, longOdds, shortOdds, pubkey });
Formatting countdown timer to display:
// We declare a variable formattedTime and initialize it with "00:00:00".
var formattedTime = "00:00:00";
// Next, we have an if statement that checks if locksTime is truthy.
if (locksTime) {
//If locksTime is truthy, we calculate the difference between locksTime
// and the current time in milliseconds. We store this difference in the
// timeDiff variable.
const currentTime = new Date().getTime();
const timeDiff = locksTime - currentTime;
// We then use the Math.floor method to calculate the number of hours,
// minutes, and seconds from timeDiff.
const hours = Math.floor(timeDiff / (1000 * 60 * 60));
const minutes = Math.floor((timeDiff % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((timeDiff % (1000 * 60)) / 1000);
// Next, we use template literals to format hours, minutes, and seconds
// into a string that has the format "hh:mm:ss". If hours, minutes, or
// seconds is less than 10, we add a leading "0".
formattedTime = `${hours < 10 ? "0" + hours : hours}:${minutes < 10 ? "0" + minutes : minutes
}:${seconds < 10 ? "0" + seconds : seconds}`;
}
// Finally, we can setCountDownTime with formattedTime as its argument.
setCountDownTime(formattedTime);
};
Here, we can close our getPariStats()
function.
Calling our data
To start a recurring function call, use the setInterval()
function. The setInterval()
function takes two parameters: the first parameter is the function that you want to call repeatedly, and the second parameter is the interval in milliseconds.
Here, we want to call the getPariData()
function every second, so the interval is set to 1000 milliseconds or 1 second.
const intervalId = setInterval(() => getPariData(), 1000);
To avoid memory leaks, it's important to clean up any recurring functions when the component that started it unmounts. To do this, return a function that calls clearInterval()
and pass in the intervalId
.
return () => clearInterval(intervalId);
}, []);
Now, we have a function that updates our data every second until the component unmounts and the interval is cleared.
Rendering Our Data
Let's build the UI of our Pari Box component.
return (
// Render contents here
);
To make it easier, here is the code you can copy and paste inside of return
:
return (
<div>
<div style={{
padding: 10,
border: "1px solid white",
borderRadius: "10px",
boxSizing: "border-box",
width: "250px",
alignItems: "center",
}}>
<h1 style={{fontWeight: 'bold', fontSize:'30px', marginBottom:'10px'}}>{timeTitle}</h1>
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
}}
>
<div
style={{
display: "flex",
flexDirection: "column",
alignItems: "flex-start",
marginRight: "5px",
}}
>
<p style={{ color: "white" }}>Long Pool:</p>
<p style={{ color: "white" }}>Short Pool:</p>
<p style={{ color: "white" }}>Long Odds:</p>
<p style={{ color: "white" }}>Short Odds:</p>
<p style={{ color: "white" }}>Starts In:</p>
</div>
<div
style={{
display: "flex",
flexDirection: "column",
alignItems: "flex-end",
marginLeft: "5px",
}}
>
<p style={{ color: "white", fontWeight: "bold" }}></p>
<p style={{ color: "white", fontWeight: "bold" }}>
{pariObj ? pariObj.longPool : "0"}
</p>
<p style={{ color: "white", fontWeight: "bold" }}>
{pariObj ? pariObj.shortPool : "0"}
</p>
<p style={{ color: "white", fontWeight: "bold" }}>
{pariObj ? pariObj.longOdds : "0"}
</p>
<p style={{ color: "white", fontWeight: "bold" }}>
{pariObj ? pariObj.shortOdds : "0"}
</p>
<p style={{ color: "white", fontWeight: "bold" }}>{countDownTime}</p>
</div>
</div>
{/*
Here is where we are going to be using the PlacePositionBox.tsx component
<div style={{marginTop:'20px'}}>
<PlacePositionBox pubkey={pariObj? pariObj.pubkey : 'Loading'}/>
</div>
*/}
</div>
</div>
);
Now, let's test it!
Go to
src/view/home.tsx
and import PariBox.tsxImport the PariBox component
//Pari Box
import { PariBox } from '../../components/PariBox';
Use the PariBox component inside of the HomeView return and pass in
‘1M’
as the time prop to get the 1-minute market contests for BTC-USD.
<div className="mx-5 my-5 mb-5 md:mb-0"><PariBox time={'1M'} /></div>
Bonus:
Use the following code to display (in a responsive way) the latest contests for all the time intervals available:
<div className="text-center" style={{ alignContent: 'center' }}>
<div className="flex flex-col items-center justify-between md:flex-row">
<div className="mx-5 my-5 mb-5 md:mb-0"><PariBox time={'1M'} /></div>
<div className="mx-5 my-5 mb-5 md:mb-0"><PariBox time={'5M'} /></div>
<div className="mx-5 my-5 mb-5 md:mb-0"><PariBox time={'15M'} /></div>
<div className="mx-5 my-5 mb-5 md:mb-0"><PariBox time={'1H'} /></div>
<div className="mx-5 my-5 mb-5 md:mb-0 md:mb-0"><PariBox time={'1D'} /></div>
</div>
</div>
The output should look similar to this:

Last updated