Calculate probBefore, probAfter, and probAverage on placeBet cloud function

This commit is contained in:
jahooma 2021-12-12 15:32:06 -06:00
parent 07d8680217
commit e34f1dbcc9
3 changed files with 69 additions and 28 deletions

7
functions/.prettierrc Normal file
View File

@ -0,0 +1,7 @@
{
"tabWidth": 2,
"useTabs": false,
"semi": false,
"trailingComma": "es5",
"singleQuote": true
}

View File

@ -5,16 +5,17 @@ import { Contract } from './types/contract'
import { User } from './types/user'
import { Bet } from './types/bet'
export const placeBet = functions
.runWith({ minInstances: 1 })
.https.onCall(async (data: {
amount: number
outcome: string
contractId: string
}, context) => {
export const placeBet = functions.runWith({ minInstances: 1 }).https.onCall(
async (
data: {
amount: number
outcome: string
contractId: string
},
context
) => {
const userId = context?.auth?.uid
if (!userId)
return { status: 'error', message: 'Not authorized' }
if (!userId) return { status: 'error', message: 'Not authorized' }
const { amount, outcome, contractId } = data
@ -22,10 +23,11 @@ export const placeBet = functions
return { status: 'error', message: 'Invalid outcome' }
// run as transaction to prevent race conditions
return await firestore.runTransaction(async transaction => {
return await firestore.runTransaction(async (transaction) => {
const userDoc = firestore.doc(`users/${userId}`)
const userSnap = await transaction.get(userDoc)
if (!userSnap.exists) return { status: 'error', message: 'User not found' }
if (!userSnap.exists)
return { status: 'error', message: 'User not found' }
const user = userSnap.data() as User
if (user.balanceUsd < amount)
@ -33,12 +35,21 @@ export const placeBet = functions
const contractDoc = firestore.doc(`contracts/${contractId}`)
const contractSnap = await transaction.get(contractDoc)
if (!contractSnap.exists) return { status: 'error', message: 'Invalid contract' }
if (!contractSnap.exists)
return { status: 'error', message: 'Invalid contract' }
const contract = contractSnap.data() as Contract
const newBetDoc = firestore.collection(`contracts/${contractId}/bets`).doc()
const newBetDoc = firestore
.collection(`contracts/${contractId}/bets`)
.doc()
const { newBet, newPot, newBalance } = getNewBetInfo(user, outcome, amount, contract, newBetDoc.id)
const { newBet, newPot, newBalance } = getNewBetInfo(
user,
outcome,
amount,
contract,
newBetDoc.id
)
transaction.create(newBetDoc, newBet)
transaction.update(contractDoc, { pot: newPot })
@ -46,16 +57,39 @@ export const placeBet = functions
return { status: 'success' }
})
})
}
)
const firestore = admin.firestore()
const getNewBetInfo = (user: User, outcome: 'YES' | 'NO', amount: number, contract: Contract, newBetId: string) => {
const getNewBetInfo = (
user: User,
outcome: 'YES' | 'NO',
amount: number,
contract: Contract,
newBetId: string
) => {
const { YES: yesPot, NO: noPot } = contract.pot
const dpmWeight = outcome === 'YES'
? amount * Math.pow(noPot, 2) / (Math.pow(yesPot, 2) + amount * yesPot)
: amount * Math.pow(yesPot, 2) / (Math.pow(noPot, 2) + amount * noPot)
const probBefore = yesPot ** 2 / (yesPot ** 2 + noPot ** 2)
const probAverage =
(amount +
noPot * Math.atan(yesPot / noPot) -
noPot * Math.atan((amount + yesPot) / noPot)) /
amount
const dpmWeight =
outcome === 'YES'
? (amount * noPot ** 2) / (yesPot ** 2 + amount * yesPot)
: (amount * yesPot ** 2) / (noPot ** 2 + amount * noPot)
const newPot =
outcome === 'YES'
? { YES: yesPot + amount, NO: noPot }
: { YES: yesPot, NO: noPot + amount }
const probAfter = newPot.YES ** 2 / (newPot.YES ** 2 + newPot.NO ** 2)
const newBet: Bet = {
id: newBetId,
@ -64,14 +98,13 @@ const getNewBetInfo = (user: User, outcome: 'YES' | 'NO', amount: number, contra
amount,
dpmWeight,
outcome,
createdTime: Date.now()
probBefore,
probAverage,
probAfter,
createdTime: Date.now(),
}
const newPot = outcome === 'YES'
? { YES: yesPot + amount, NO: noPot }
: { YES: yesPot, NO: noPot + amount }
const newBalance = user.balanceUsd - amount
return { newBet, newPot, newBalance }
}
}

View File

@ -2,10 +2,11 @@ export type Bet = {
id: string
userId: string
contractId: string
amount: number // Amount of USD bid
amount: number // Amount of bet
outcome: 'YES' | 'NO' // Chosen outcome
createdTime: number
probBefore: number
probAverage: number
probAfter: number
dpmWeight: number // Dynamic Parimutuel weight
}