Cancel bet endpoint.

This commit is contained in:
James Grugett 2022-07-05 11:50:15 -04:00
parent 83557515ad
commit f98bc17bc1
5 changed files with 67 additions and 19 deletions

View File

@ -0,0 +1,35 @@
import * as admin from 'firebase-admin'
import { z } from 'zod'
import { APIError, newEndpoint, validate } from './api'
import { LimitBet } from '../../common/bet'
const bodySchema = z.object({
betId: z.string(),
})
export const cancelbet = newEndpoint({}, async (req, auth) => {
const { betId } = validate(bodySchema, req.body)
const result = await firestore.runTransaction(async (trans) => {
const snap = await trans.get(
firestore.collectionGroup('bets').where('id', '==', betId)
)
const betDoc = snap.docs[0]
if (!betDoc?.exists) throw new APIError(400, 'Bet not found.')
const bet = betDoc.data() as LimitBet
if (bet.userId !== auth.uid)
throw new APIError(400, 'Not authorized to cancel bet.')
if (bet.limitProb === undefined)
throw new APIError(400, 'Not a limit bet: Cannot cancel.')
if (bet.isCancelled) throw new APIError(400, 'Bet already cancelled.')
trans.update(betDoc.ref, { isCancelled: true })
return { ...bet, isCancelled: true }
})
return result
})
const firestore = admin.firestore()

View File

@ -32,6 +32,7 @@ export * from './on-update-user'
// v2 // v2
export * from './health' export * from './health'
export * from './place-bet' export * from './place-bet'
export * from './cancel-bet'
export * from './sell-bet' export * from './sell-bet'
export * from './sell-shares' export * from './sell-shares'
export * from './create-contract' export * from './create-contract'

View File

@ -1,5 +1,7 @@
import * as admin from 'firebase-admin' import * as admin from 'firebase-admin'
import { z } from 'zod' import { z } from 'zod'
import { Query } from 'firebase-admin/firestore'
import { sumBy } from 'lodash'
import { APIError, newEndpoint, validate } from './api' import { APIError, newEndpoint, validate } from './api'
import { Contract, CPMM_MIN_POOL_QTY } from '../../common/contract' import { Contract, CPMM_MIN_POOL_QTY } from '../../common/contract'
@ -11,12 +13,10 @@ import {
getNumericBetsInfo, getNumericBetsInfo,
} from '../../common/new-bet' } from '../../common/new-bet'
import { addObjects, removeUndefinedProps } from '../../common/util/object' import { addObjects, removeUndefinedProps } from '../../common/util/object'
import { LimitBet } from '../../common/bet'
import { floatingEqual } from '../../common/util/math'
import { redeemShares } from './redeem-shares' import { redeemShares } from './redeem-shares'
import { log } from './utils' import { log } from './utils'
import { LimitBet } from 'common/bet'
import { Query } from 'firebase-admin/firestore'
import { sumBy } from 'lodash'
import { floatingEqual } from 'common/util/math'
const bodySchema = z.object({ const bodySchema = z.object({
contractId: z.string(), contractId: z.string(),

View File

@ -3,7 +3,10 @@ import { LimitBet } from 'common/bet'
import { formatPercent } from 'common/lib/util/format' import { formatPercent } from 'common/lib/util/format'
import { formatMoney } from 'common/util/format' import { formatMoney } from 'common/util/format'
import { sortBy, sumBy } from 'lodash' import { sortBy, sumBy } from 'lodash'
import { useState } from 'react'
import { cancelBet } from 'web/lib/firebase/api-call'
import { Col } from './layout/col' import { Col } from './layout/col'
import { LoadingIndicator } from './loading-indicator'
import { BinaryOutcomeLabel } from './outcome-label' import { BinaryOutcomeLabel } from './outcome-label'
export function OpenBets(props: { bets: LimitBet[]; className?: string }) { export function OpenBets(props: { bets: LimitBet[]; className?: string }) {
@ -16,13 +19,7 @@ export function OpenBets(props: { bets: LimitBet[]; className?: string }) {
<table className="table-compact table w-full rounded text-gray-500"> <table className="table-compact table w-full rounded text-gray-500">
<tbody> <tbody>
{recentBets.map((bet) => ( {recentBets.map((bet) => (
<LimitBet <LimitBet key={bet.id} bet={bet} />
key={bet.id}
bet={bet}
onCancel={() => {
console.log('Cancel', bet)
}}
/>
))} ))}
</tbody> </tbody>
</table> </table>
@ -30,9 +27,16 @@ export function OpenBets(props: { bets: LimitBet[]; className?: string }) {
) )
} }
function LimitBet(props: { bet: LimitBet; onCancel: () => void }) { function LimitBet(props: { bet: LimitBet }) {
const { bet, onCancel } = props const { bet } = props
const filledAmount = sumBy(bet.fills, (fill) => fill.amount) const filledAmount = sumBy(bet.fills, (fill) => fill.amount)
const [isCancelling, setIsCancelling] = useState(false)
const onCancel = () => {
cancelBet({ betId: bet.id })
setIsCancelling(true)
}
return ( return (
<tr> <tr>
<td> <td>
@ -43,12 +47,16 @@ function LimitBet(props: { bet: LimitBet; onCancel: () => void }) {
<td>{formatMoney(bet.amount - filledAmount)}</td> <td>{formatMoney(bet.amount - filledAmount)}</td>
<td>{formatPercent(bet.limitProb)}</td> <td>{formatPercent(bet.limitProb)}</td>
<td> <td>
<button {isCancelling ? (
className="btn btn-xs btn-outline my-auto normal-case" <LoadingIndicator />
onClick={onCancel} ) : (
> <button
Cancel className="btn btn-xs btn-outline my-auto normal-case"
</button> onClick={onCancel}
>
Cancel
</button>
)}
</td> </td>
</tr> </tr>
) )

View File

@ -62,6 +62,10 @@ export function placeBet(params: any) {
return call(getFunctionUrl('placebet'), 'POST', params) return call(getFunctionUrl('placebet'), 'POST', params)
} }
export function cancelBet(params: { betId: string }) {
return call(getFunctionUrl('cancelbet'), 'POST', params)
}
export function sellShares(params: any) { export function sellShares(params: any) {
return call(getFunctionUrl('sellshares'), 'POST', params) return call(getFunctionUrl('sellshares'), 'POST', params)
} }