Place a bet
Estimate, place, and reconcile a market bet on the Bento markets host.
By the end: you'll have estimated a bet, placed it with placeBetFromEstimate, and read your position back.
Prerequisites
- Markets host + Builder API key — Environments
- Bearer JWT on
createBentoSdk— Authentication - Funded managed account (testnet: auto-mint faucet)
- For private markets: membership via
duelInvitations.userJoinbefore betting — Create a market
Flow
import { createBentoSdk, walletAuthProvider } from '@bento.fun/sdk';
const sdk = createBentoSdk({
baseUrl: process.env.BENTO_URL!, // https://internal-server.bento.fun
apiKey: process.env.BENTO_BUILDER_API_KEY!,
auth: walletAuthProvider(() => ({ Authorization: `Bearer ${token}` })),
});
const duelId = 'your-duel-id'; // from listDuels row.duelId — NOT row.id
const market = await sdk.public.getDuelById({ duelId });
// 1. Estimate (optionIndex is 0|1; amount is collateral wei)
// Platform minimum bet is **5** collateral units, in the collateral's decimals
// (18 for credits / BSC USDC, 6 for Base USDC).
// `estimateBuy` does not enforce the floor: a sub-5 amount can quote then 500 at place.
const stake = '10000000000000000000'; // 10 units
const est = await sdk.user.bets.estimateBuy({
duelId,
optionIndex: 0,
betAmountUsdc: stake,
slippageBps: 100,
});
if (!est.success) throw new Error('estimate rejected'); // narrows to success variant
// 2. Place (HTTP acceptance). Prefer `placeBetFromEstimate`: it maps the quote
// and derives the slippage floor from `sharesOut`. Do NOT hand-build from
// `estimate.min_shares_out` — on larger bets the engine returns it ABOVE
// `sharesOut`, emptying the slippage window ("Slippage exceeded").
// `bet` is the option label text (prediction often YES/NO; versus uses optionA/optionB text).
await sdk.user.placeBetFromEstimate(
{
estimate: est.estimate,
duelId,
duelType: market.duelType ?? 'PREDICTION', // or 'VERSUS'
bet: market.options?.[0] ?? 'YES',
optionIndex: 0,
betAmount: stake,
betAmountUsdc: stake,
slippageBps: 100,
tokenDecimals: 18,
},
{ idempotencyKey: crypto.randomUUID() }, // stable per attempt, not Date.now()
);
// 3. Reconcile — `address` is the managed account from login, not your EOA
const shares = await sdk.user.bets.getUserShares({
duelId,
address: managedAccountAddress,
});A write returns when the server accepted it, not when the chain settled. Poll reads to confirm. → Acceptance vs finality
Related
- Quickstart: full zero → bet script
- Create a market: public create, private invite/join
- Cookbook: method shortlist