diff --git a/common/antes.ts b/common/antes.ts index c396edad..d36ef584 100644 --- a/common/antes.ts +++ b/common/antes.ts @@ -80,7 +80,7 @@ export function getFreeAnswerAnte( amount, shares, outcome: '0', - probBefore: 1, + probBefore: 0, probAfter: 1, createdTime, isAnte: true, diff --git a/common/contract.ts b/common/contract.ts index c977fdff..17c4918e 100644 --- a/common/contract.ts +++ b/common/contract.ts @@ -13,8 +13,8 @@ export type Contract = { lowercaseTags: string[] visibility: 'public' | 'unlisted' - outcomeType: 'BINARY' | 'MULTI' - outcomes?: 'FREE_ANSWER' | string[] + outcomeType: 'BINARY' | 'MULTI' | 'FREE_RESPONSE' + multiOutcomes?: string[] // Used for outcomeType 'MULTI'. mechanism: 'dpm-2' phantomShares?: { [outcome: string]: number } @@ -34,3 +34,5 @@ export type Contract = { volume24Hours: number volume7Days: number } + +export type outcomeType = 'BINARY' | 'MULTI' | 'FREE_RESPONSE' diff --git a/common/new-contract.ts b/common/new-contract.ts index c7b56c90..263877f1 100644 --- a/common/new-contract.ts +++ b/common/new-contract.ts @@ -1,5 +1,5 @@ import { calcStartPool } from './antes' -import { Contract } from './contract' +import { Contract, outcomeType } from './contract' import { User } from './user' import { parseTags } from './util/parse' import { removeUndefinedProps } from './util/object' @@ -9,7 +9,7 @@ export function getNewContract( slug: string, creator: User, question: string, - outcomeType: 'BINARY' | 'MULTI', + outcomeType: outcomeType, description: string, initialProb: number, ante: number, @@ -64,7 +64,6 @@ const getBinaryProps = (initialProb: number, ante: number) => { pool: { YES: poolYes, NO: poolNo }, totalShares: { YES: sharesYes, NO: sharesNo }, totalBets: { YES: poolYes, NO: poolNo }, - outcomes: undefined, } } @@ -73,8 +72,6 @@ const getFreeAnswerProps = (ante: number) => { pool: { '0': ante }, totalShares: { '0': ante }, totalBets: { '0': ante }, - phantomShares: undefined, - outcomes: 'FREE_ANSWER' as const, } } diff --git a/functions/src/create-answer.ts b/functions/src/create-answer.ts index 1b6d5f2f..6c28b245 100644 --- a/functions/src/create-answer.ts +++ b/functions/src/create-answer.ts @@ -44,13 +44,10 @@ export const createAnswer = functions.runWith({ minInstances: 1 }).https.onCall( return { status: 'error', message: 'Invalid contract' } const contract = contractSnap.data() as Contract - if ( - contract.outcomeType !== 'MULTI' || - contract.outcomes !== 'FREE_ANSWER' - ) + if (contract.outcomeType !== 'FREE_RESPONSE') return { status: 'error', - message: 'Requires a multi, free answer contract', + message: 'Requires a free response contract', } const { closeTime } = contract diff --git a/functions/src/create-contract.ts b/functions/src/create-contract.ts index 18042768..bb78f134 100644 --- a/functions/src/create-contract.ts +++ b/functions/src/create-contract.ts @@ -2,7 +2,7 @@ import * as functions from 'firebase-functions' import * as admin from 'firebase-admin' import { chargeUser, getUser } from './utils' -import { Contract } from '../../common/contract' +import { Contract, outcomeType } from '../../common/contract' import { slugify } from '../../common/util/slugify' import { randomString } from '../../common/util/random' import { getNewContract } from '../../common/new-contract' @@ -19,7 +19,7 @@ export const createContract = functions async ( data: { question: string - outcomeType: 'BINARY' | 'MULTI' + outcomeType: outcomeType description: string initialProb: number ante: number @@ -40,7 +40,7 @@ export const createContract = functions return { status: 'error', message: 'Missing question field' } let outcomeType = data.outcomeType ?? 'BINARY' - if (outcomeType !== 'BINARY' && outcomeType !== 'MULTI') + if (!['BINARY', 'MULTI', 'FREE_RESPONSE'].includes(outcomeType)) return { status: 'error', message: 'Invalid outcomeType' } if ( @@ -106,7 +106,7 @@ export const createContract = functions ) await yesBetDoc.set(yesBet) await noBetDoc.set(noBet) - } else if (outcomeType === 'MULTI') { + } else if (outcomeType === 'FREE_RESPONSE') { const noneAnswerDoc = firestore .collection(`contracts/${contract.id}/answers`) .doc('0') diff --git a/functions/src/place-bet.ts b/functions/src/place-bet.ts index 3be51790..e37dc12c 100644 --- a/functions/src/place-bet.ts +++ b/functions/src/place-bet.ts @@ -42,12 +42,11 @@ export const placeBet = functions.runWith({ minInstances: 1 }).https.onCall( return { status: 'error', message: 'Invalid contract' } const contract = contractSnap.data() as Contract - const { closeTime, outcomes } = contract + const { closeTime, outcomeType } = contract if (closeTime && Date.now() > closeTime) return { status: 'error', message: 'Trading is closed' } - const isFreeAnswer = outcomes === 'FREE_ANSWER' - if (isFreeAnswer) { + if (outcomeType === 'FREE_RESPONSE') { const answerSnap = await transaction.get( contractDoc.collection('answers').doc(outcome) ) @@ -60,21 +59,15 @@ export const placeBet = functions.runWith({ minInstances: 1 }).https.onCall( .doc() const { newBet, newPool, newTotalShares, newTotalBets, newBalance } = - isFreeAnswer - ? getNewMultiBetInfo( - user, - outcome, - amount, - contract as any, - newBetDoc.id - ) - : getNewBinaryBetInfo( + outcomeType === 'BINARY' + ? getNewBinaryBetInfo( user, outcome as 'YES' | 'NO', amount, contract, newBetDoc.id ) + : getNewMultiBetInfo(user, outcome, amount, contract, newBetDoc.id) transaction.create(newBetDoc, newBet) transaction.update(contractDoc, { diff --git a/functions/src/resolve-market.ts b/functions/src/resolve-market.ts index 201087d2..d0b6d1da 100644 --- a/functions/src/resolve-market.ts +++ b/functions/src/resolve-market.ts @@ -35,7 +35,7 @@ export const resolveMarket = functions if (outcomeType === 'BINARY') { if (!['YES', 'NO', 'MKT', 'CANCEL'].includes(outcome)) return { status: 'error', message: 'Invalid outcome' } - } else if (outcomeType === 'MULTI') { + } else if (outcomeType === 'FREE_RESPONSE') { if (outcome !== 'CANCEL' && isNaN(+outcome)) return { status: 'error', message: 'Invalid outcome' } } else { diff --git a/web/pages/[username]/[contractSlug].tsx b/web/pages/[username]/[contractSlug].tsx index fec1880d..98c314a4 100644 --- a/web/pages/[username]/[contractSlug].tsx +++ b/web/pages/[username]/[contractSlug].tsx @@ -42,7 +42,7 @@ export async function getStaticProps(props: { const [bets, comments, answers] = await Promise.all([ contractId ? listAllBets(contractId) : [], contractId ? listAllComments(contractId) : [], - contractId && contract.outcomes === 'FREE_ANSWER' + contractId && contract.outcomeType === 'FREE_RESPONSE' ? listAllAnswers(contractId) : [], ]) @@ -120,7 +120,7 @@ export default function ContractPage(props: { comments={comments ?? []} folds={folds} > - {contract.outcomes === 'FREE_ANSWER' && ( + {contract.outcomeType === 'FREE_RESPONSE' && ( <> ('BINARY') + const [outcomeType, setOutcomeType] = useState('BINARY') const [initialProb, setInitialProb] = useState(50) const [description, setDescription] = useState('') const [tagText, setTagText] = useState(tag ?? '') @@ -143,7 +144,7 @@ export function NewContract(props: { question: string; tag?: string }) { name="opt" checked={outcomeType === 'BINARY'} value="BINARY" - onChange={(e) => setOutcomeType(e.target.value as 'BINARY')} + onChange={() => setOutcomeType('BINARY')} /> Yes / No @@ -153,9 +154,9 @@ export function NewContract(props: { question: string; tag?: string }) { className="radio" type="radio" name="opt" - checked={outcomeType === 'MULTI'} - value="MULTI" - onChange={(e) => setOutcomeType(e.target.value as 'MULTI')} + checked={outcomeType === 'FREE_RESPONSE'} + value="FREE_RESPONSE" + onChange={() => setOutcomeType('FREE_RESPONSE')} /> Free response