useBets
The useBets hook is used to fetch betting history of a specific bettor.
If you need to get older bets from v2 Azuro Protocol use useLegacyBets
Hook represents a logic wrapper over TanStack Query’s useInfiniteQuery hook. Explore TanStack Query docs to understand what data the hook returns.
Usage
import { useBets } from '@azuro-org/sdk'
const { data, hasNextPage, isFetching, fetchNextPage } = useBets(props)
const { pages } = data || {}
// render pages
<>
{
pages?.map(({ bets, nextPage }) => {
return (
<React.Fragment key={`${nextPage}`}>
{
bets.map(bet => (
<BetComponent key={`${bet.createdAt}-${bet.tokenId}`} bet={bet} />
))
}
</React.Fragment>
)
})
}
<>Props
{
filter: BetsFilter
chainId?: ChainId
itemsPerPage?: number
query?: InfiniteQueryParameters<QueryResult>
}useBets does not accept orderBy / orderDir — those are useLegacyBets-only props, kept there
because the legacy v2 subgraph is queried directly. useBets always orders by creation time descending.
type BetsFilter = {
bettor: Address // bettor address
affiliate?: Address // affiliate address
status?: BetStatusFilter // lifecycle preset - narrows both the bet list and its report
kind?: BetKind // single (Ordinar) vs combo (Express)
createdFrom?: number // inclusive lower bound, unix seconds (matches `Bet.createdAt`)
createdTo?: number // inclusive upper bound, unix seconds
isFreebet?: boolean // `true` = freebet-funded only, `false` = own-funds only, omit = both
/** @deprecated renamed to `status` - when both are set, `status` wins */
type?: BetStatusFilter
}
enum BetStatusFilter {
Unredeemed = 'unredeemed', // ready to redeem bets
Pending = 'pending', // not yet accepted on-chain
Accepted = 'accepted', // accepted, not yet resolved
Settled = 'settled', // resolved bets
CashedOut = 'cashedOut', // cashed out bets
}
enum BetKind {
Single = 'single',
Combo = 'combo',
}
type ChainId =
| 100 // Gnosis
| 137 // Polygon
| 80002 // Polygon Amoy
| 88888 // Chiliz
| 88882 // Chiliz Spicy
| 8453 // Base
| 84532 // Base Sepolia
| 97 // BSC Testnet
| 56 // BSC
type QueryResult = {
bets: Bet[],
nextPage: number | undefined,
}
import { type Address } from 'viem'BetType → BetStatusFilter
The enum previously used for filter.type has been renamed to BetStatusFilter (these are lifecycle
statuses, not bet types — for single/combo use the new filter.kind with BetKind). filter.type is
now deprecated in favour of filter.status; when both are set, status wins. BetType is kept as a
working alias of the very same enum object — BetType.Accepted === BetStatusFilter.Accepted — so it
type-checks and behaves identically. No migration is required of existing code that imports
BetType or sets filter.type.
BetStatusFilter.Pending has no representation in the subgraph this hook queries — orders that
aren’t yet confirmed on-chain simply aren’t in that data set. Passing status: BetStatusFilter.Pending
(or the deprecated type: BetType.Pending) is therefore intentionally unhandled: it adds no status
constraint at all, rather than narrowing the result down to pending bets.
Return Value
UseInfiniteQueryResult<QueryResult>import { type UseInfiniteQueryResult } from '@tanstack/react-query'
import { type Address, type Hex } from 'viem'
import { type BetOrderState, type GraphBetStatus } from '@azuro-org/toolkit'
type Selection = {
conditionId: string
outcomeId: string
}
type BetOutcome = {
selectionName: string
odds: number
marketName: string
game: GameData // game on which the bet is placed
isLive: boolean
isWin: boolean | null // true = won, false = settled but not won, null = still pending
isLose: boolean | null // true = lost, false = settled but not lost, null = still pending
isCanceled: boolean // true = voided, stake refunded for this leg
} & Selection
type Bet = {
orderId: string // bettorAddressLowerCase_nonce
actor: Address // bettor address
affiliate: Address // affiliate address
tokenId: string // id of the bet's NFT
freebetId: string | null // id of the freebet, `null` for a bet funded by the bettor
isFreebetAmountReturnable: boolean | null // decides a freebet's share of a win (see below); null counts as returnable
paymaster: Address | null // freebet contract address, `null` for a bet funded by the bettor
totalOdds: number // total odds as the subgraph records them (up to 12 decimals) - settled odds leave a voided leg out, a canceled bet has 1
coreAddress: Address // core contract address
lpAddress: Address // lp contract address
outcomes: BetOutcome[] // bet's outcomes list
txHash: Hex | null // bet's transaction hash
redeemedTxHash: Hex | null // redeem transaction hash
orderState: BetOrderState // order state, derived from the subgraph status
status: GraphBetStatus | null // subgraph bet status
rejectedErrorCode: string | null // contract error code of a rejected order
amount: string // bet's amount in the bet token
possibleWin: number // potential payout as recorded - for a freebet, the bettor's share; a lost bet keeps the missed win
payout: number | null // claimable amount - `null` unless the bet won or was canceled, is redeemable and not cashed out; for a freebet, the bettor's share; gates a redeem action
settledPayout: number | null // payout as recorded once the bet is settled (0 if lost), the amount actually paid once redeemed; `null` before settlement; for a freebet, the bettor's share
createdAt: number // created date, unix seconds
resolvedAt: number | null // resolved date, unix seconds
redeemedAt?: number | null // redeemed date, unix seconds
cashout?: string // cashout amount in the bet token, set only on a cashed-out bet
isWin: boolean // flag indicates the bet's win
isLose: boolean // flag indicates the bet's lose
isRedeemable: boolean // flag indicates the possibility of redeeming the bet
isRedeemed: boolean // flag indicates whether the bet has been redeemed
isCanceled: boolean // flag indicates whether the bet has been canceled
isRejected: boolean // flag indicates whether the order was rejected
isCashedOut: boolean // flag indicates whether the bet is cashed out
}A voided leg is isCanceled, not “pending”.
Settlement is per-outcome: within one condition, one outcome can win, another lose and a third be voided
(refunded). A voided leg of a bet now reports { isWin: false, isLose: false, isCanceled: true }. It used
to report { isWin: null, isLose: null, isCanceled: false } — indistinguishable from a leg that hadn’t
settled yet.
Check isCanceled before treating isWin === null as “pending”:
if (outcome.isCanceled) {
return <Refunded />
}
if (outcome.isWin === null) {
return <Pending />
}
return outcome.isWin ? <Won /> : <Lost />Won, lost, voided and pending are mutually exclusive: a settled leg never reports null, and a pending
leg reports isWin: null / isLose: null with isCanceled: false.
A leg is voided exactly when the subgraph records its selection result as Canceled, even when its
outcome settles won or lost (a leg rejected from a combo).
Figures are read as the bets subgraph records them. totalOdds, possibleWin, payout and
settledPayout come straight from the subgraph, already priced by the protocol’s rule; nothing is
re-priced on the client. totalOdds carries the subgraph’s precision (up to 12 decimals), so format it
for display.
| State | totalOdds | possibleWin | payout | settledPayout |
|---|---|---|---|---|
| pending | the placed odds | the potential payout | null | null |
| won | the settled odds | the potential payout | the payout while redeemable | the payout |
| lost | the placed odds | the potential payout - the win the bettor missed | null | 0 |
| canceled | 1 | the stake (0 for a freebet) | the stake (0 for a freebet) while redeemable | the stake (0 for a freebet) |
| cashed out | the settled odds, else the placed odds | the potential payout | null | the recorded payout once settled |
For a freebet, every money figure is the bettor’s share (see below). Settled odds leave a voided leg out.
A redeemed bet’s settledPayout is the amount actually paid. For a
cashed-out bet read cashout for what it paid: its settledPayout is the recorded payout, not the
cash-out amount.
These figures and the freebet rule below describe bets from useBets. Bets from
useLegacyBets keep the v2 figures.
A freebet’s money figures are the bettor’s share. The liquidity pool pays a freebet’s whole payout to
the freebet contract, which splits it between the bettor and the freebet fund. possibleWin, payout
and settledPayout of a freebet are what the bettor receives:
- payout no greater than the stake (a lost freebet, a canceled one):
0; - the freebet’s amount is returnable: payout minus the stake;
isFreebetAmountReturnableisfalse: the whole payout.
A freebet with no flag (null) counts as returnable. For example, a returnable freebet of 1.00 won at
1.50 has possibleWin, payout and settledPayout of 0.50; a non-returnable one has 1.50; a canceled
freebet has 0. This is the same rule the toolkit exports as calcFreebetBettorShare. The gross payout
of the pool is not on Bet. Real-money bets are unchanged.
Changed in SDK v8.2.0: a freebet’s payout and settledPayout used to be the pool’s whole payout
(the type is unchanged).
payout vs settledPayout
payout is gated on redeemability — it answers “is there money to claim?” and becomes null once
the bet is redeemed. settledPayout answers “what did this bet return?” and stays populated after
redemption. Use settledPayout for historical and aggregate views; use payout only to gate a redeem
action.
Both are the payout the subgraph recorded: 0 for a lost bet, the stake for a canceled one, and once
redeemed the amount actually paid. payout also needs the bet not to be cashed out. For a freebet both
are the bettor’s share, and a won freebet whose share is 0 has payout 0, not null.
A redeem through useRedeemBet sets the bet’s payout to
null in the cached list as soon as the transaction is confirmed, along with isRedeemed and
isRedeemable, without waiting for the next read.