From 0b1d59a2ac7a1c1918de4ecd3e9c0ab33a75ae43 Mon Sep 17 00:00:00 2001 From: mantikoros Date: Fri, 17 Dec 2021 19:47:46 -0600 Subject: [PATCH] initial commit --- functions/src/api-call.ts | 16 +++++++ functions/src/index.ts | 3 +- functions/src/place-bet.ts | 93 ++++++++++++++++++------------------ web/components/bet-panel.tsx | 10 +++- web/lib/firebase/api-call.ts | 9 ++++ 5 files changed, 81 insertions(+), 50 deletions(-) create mode 100644 functions/src/api-call.ts create mode 100644 web/lib/firebase/api-call.ts diff --git a/functions/src/api-call.ts b/functions/src/api-call.ts new file mode 100644 index 00000000..0656a1b6 --- /dev/null +++ b/functions/src/api-call.ts @@ -0,0 +1,16 @@ +import * as functions from 'firebase-functions' +import { placeBetLogic } from '.' + +const apiFunctions = { + 'place-bet': placeBetLogic, +} + +export const apiCall = functions.firestore + .document('api-calls/{apiCallId}') + .onCreate(async (snap, context) => { + const data = snap.data() as any + console.log('data:', data) + + const apiFunction = apiFunctions[data.name as keyof typeof apiFunctions] + await apiFunction(data) + }) diff --git a/functions/src/index.ts b/functions/src/index.ts index cde0b30c..f994b402 100644 --- a/functions/src/index.ts +++ b/functions/src/index.ts @@ -3,4 +3,5 @@ import * as admin from 'firebase-admin' admin.initializeApp() export * from './place-bet' -export * from './resolve-market' \ No newline at end of file +export * from './resolve-market' +export * from './api-call' diff --git a/functions/src/place-bet.ts b/functions/src/place-bet.ts index 9e773848..63ca6c10 100644 --- a/functions/src/place-bet.ts +++ b/functions/src/place-bet.ts @@ -5,63 +5,62 @@ 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 - ) => { - const userId = context?.auth?.uid - if (!userId) return { status: 'error', message: 'Not authorized' } +export const placeBet = functions + .runWith({ minInstances: 1 }) + .https.onCall((data, context) => { + placeBetLogic({ ...data, userId: context?.auth?.uid }) + }) - const { amount, outcome, contractId } = data +export const placeBetLogic = async (data: { + amount: number + outcome: string + contractId: string + userId: string +}) => { + console.log('placeBet called') + // if (!userId) return { status: 'error', message: 'Not authorized' } - if (outcome !== 'YES' && outcome !== 'NO') - return { status: 'error', message: 'Invalid outcome' } + const { amount, outcome, contractId, userId } = data - // run as transaction to prevent race conditions - 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' } - const user = userSnap.data() as User + if (outcome !== 'YES' && outcome !== 'NO') + return { status: 'error', message: 'Invalid outcome' } - if (user.balance < amount) - return { status: 'error', message: 'Insufficient balance' } + // run as transaction to prevent race conditions + 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' } + const user = userSnap.data() as User - const contractDoc = firestore.doc(`contracts/${contractId}`) - const contractSnap = await transaction.get(contractDoc) - if (!contractSnap.exists) - return { status: 'error', message: 'Invalid contract' } - const contract = contractSnap.data() as Contract + if (user.balance < amount) + return { status: 'error', message: 'Insufficient balance' } - const newBetDoc = firestore - .collection(`contracts/${contractId}/bets`) - .doc() + const contractDoc = firestore.doc(`contracts/${contractId}`) + const contractSnap = await transaction.get(contractDoc) + if (!contractSnap.exists) + return { status: 'error', message: 'Invalid contract' } + const contract = contractSnap.data() as Contract - const { newBet, newPool, newDpmWeights, newBalance } = getNewBetInfo( - user, - outcome, - amount, - contract, - newBetDoc.id - ) + const newBetDoc = firestore.collection(`contracts/${contractId}/bets`).doc() - transaction.create(newBetDoc, newBet) - transaction.update(contractDoc, { - pool: newPool, - dpmWeights: newDpmWeights, - }) - transaction.update(userDoc, { balance: newBalance }) + const { newBet, newPool, newDpmWeights, newBalance } = getNewBetInfo( + user, + outcome, + amount, + contract, + newBetDoc.id + ) - return { status: 'success' } + transaction.create(newBetDoc, newBet) + transaction.update(contractDoc, { + pool: newPool, + dpmWeights: newDpmWeights, }) - } -) + transaction.update(userDoc, { balance: newBalance }) + + return { status: 'success' } + }) +} const firestore = admin.firestore() diff --git a/web/components/bet-panel.tsx b/web/components/bet-panel.tsx index 49513214..80898360 100644 --- a/web/components/bet-panel.tsx +++ b/web/components/bet-panel.tsx @@ -15,6 +15,7 @@ import { getDpmWeight, getProbabilityAfterBet, } from '../lib/calculation/contract' +import { apiCall } from '../lib/firebase/api-call' export function BetPanel(props: { contract: Contract; className?: string }) { const { contract, className } = props @@ -61,6 +62,7 @@ export function BetPanel(props: { contract: Contract; className?: string }) { amount: betAmount, outcome: betChoice, contractId: contract.id, + userId: user.id, }).then((r) => r.data as any) console.log('placed bet. Result:', result) @@ -171,5 +173,9 @@ export function BetPanel(props: { contract: Contract; className?: string }) { ) } -const functions = getFunctions() -export const placeBet = httpsCallable(functions, 'placeBet') +// const functions = getFunctions() +// export const placeBet = httpsCallable(functions, 'placeBet') +export const placeBet = async (bet: any) => { + await apiCall({ ...bet, name: 'place-bet' }) + return { data: { success: true } } +} diff --git a/web/lib/firebase/api-call.ts b/web/lib/firebase/api-call.ts new file mode 100644 index 00000000..d7d25990 --- /dev/null +++ b/web/lib/firebase/api-call.ts @@ -0,0 +1,9 @@ +import { app } from './init' +import { doc, collection, getFirestore, setDoc } from 'firebase/firestore' + +const db = getFirestore(app) + +export async function apiCall(apiCallDoc: any) { + const apiCallRef = doc(collection(db, 'api-calls')) + await setDoc(apiCallRef, apiCallDoc) +}