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
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'
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 = {
affiliate: string // affiliate address
tokenId: string // id of the bet's NFT
freebetId?: string | null // id of the freebet's NFT
freebetContractAddress?: Address // freebet contract address
totalOdds: number // total odds of the bet - voided legs are excluded from the product
coreAddress: Address // core contract address
lpAddress: Address // lp contract address
outcomes: BetOutcome[] // bet's outcomes list
txHash: string // bet's transaction hash
status: BetStatus // subgraph bet status
amount: string // bet's amount in USDT
possibleWin: number // possible win amount in USDT - excludes voided legs
payout: number | null // claimable amount - `null` once the bet is redeemed or cashed out; gates a redeem action
settledPayout: number | null // what the bet actually returned - stays populated after redemption; use for historical/aggregate views
cashout: string | null // cashout amount in USDT
createdAt: number // created date
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
isLive: boolean // flag indicates whether the bet is live
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.
Voided legs are excluded from combo odds. A refunded leg no longer multiplies into a combo’s
totalOdds, so totalOdds and possibleWin for a combo containing a voided leg are lower — and correct
— than they were before. A combo whose every leg was voided has totalOdds of 1: the stake is simply
returned.
Combo odds are re-priced, so their values change. The feed applies its fee to every outcome’s
odds, and a combo is priced by removing that fee per leg and applying it once to the product —
which is what calcComboOdds does. The subgraph records the
plain product instead, compounding the fee once per leg, so totalOdds, possibleWin, payout and
settledPayout for an unredeemed combo now report higher figures than before, by more the more
legs the bet has. They are the correct ones.
This applies to every unredeemed combo, not only one with a voided leg.
Two shapes are deliberately left as they were: a combo placed before the fee existed (its leg odds are
raw, so the plain product is already right), and a bet that has been redeemed (its recorded payout is
the amount actually paid on chain). A cashed-out bet is never re-priced either — it was paid at the
price the bettor took, so read cashout for what it returned.
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 read from the protocol’s recorded payout, with one exception: a winning combo that has not
been redeemed yet. Its recorded payout compounds the feed’s fee once per leg, and still credits any
voided leg as if it had won; both figures are rebuilt from the surviving legs instead, at the same
totalOdds this hook already reports. Once redeemed, the recorded payout is the amount actually paid
and is used as is.