From e34f1dbcc96d8e8fce66385fe87a5af4712f029c Mon Sep 17 00:00:00 2001 From: jahooma Date: Sun, 12 Dec 2021 15:32:06 -0600 Subject: [PATCH] Calculate probBefore, probAfter, and probAverage on placeBet cloud function --- functions/.prettierrc | 7 ++++ functions/src/place-bet.ts | 83 ++++++++++++++++++++++++++------------ functions/src/types/bet.ts | 7 ++-- 3 files changed, 69 insertions(+), 28 deletions(-) create mode 100644 functions/.prettierrc diff --git a/functions/.prettierrc b/functions/.prettierrc new file mode 100644 index 00000000..bd18729f --- /dev/null +++ b/functions/.prettierrc @@ -0,0 +1,7 @@ +{ + "tabWidth": 2, + "useTabs": false, + "semi": false, + "trailingComma": "es5", + "singleQuote": true +} diff --git a/functions/src/place-bet.ts b/functions/src/place-bet.ts index bc299164..5dc4f44f 100644 --- a/functions/src/place-bet.ts +++ b/functions/src/place-bet.ts @@ -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 } -} \ No newline at end of file +} diff --git a/functions/src/types/bet.ts b/functions/src/types/bet.ts index 327f3822..2113f812 100644 --- a/functions/src/types/bet.ts +++ b/functions/src/types/bet.ts @@ -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 } \ No newline at end of file