Remove Contract and Bet type params. Use string type for outcomes.

This commit is contained in:
James Grugett 2022-02-16 23:05:45 -06:00
parent 18376f8a3f
commit f161661e7e
17 changed files with 56 additions and 91 deletions

View File

@ -64,7 +64,7 @@ export function getAnteBets(
export function getFreeAnswerAnte(
creator: User,
contract: Contract<'MULTI'>,
contract: Contract,
anteBetId: string
) {
const { totalBets, totalShares } = contract
@ -73,7 +73,7 @@ export function getFreeAnswerAnte(
const { createdTime } = contract
const anteBet: Bet<'MULTI'> = {
const anteBet: Bet = {
id: anteBetId,
userId: creator.id,
contractId: contract.id,

View File

@ -1,13 +1,10 @@
export type Bet<outcomeType extends 'BINARY' | 'MULTI' = 'BINARY'> = {
export type Bet = {
id: string
userId: string
contractId: string
amount: number // bet size; negative if SELL bet
outcome: {
BINARY: 'YES' | 'NO'
MULTI: string
}[outcomeType]
outcome: string
shares: number // dynamic parimutuel pool weight; negative if SELL bet
probBefore: number

View File

@ -3,7 +3,8 @@ import { Bet } from './bet'
import { Contract } from './contract'
import { FEES } from './fees'
export function getProbability(totalShares: { YES: number; NO: number }) {
export function getProbability(totalShares: { [outcome: string]: number }) {
// For binary contracts only.
return getOutcomeProbability(totalShares, 'YES')
}
@ -70,9 +71,9 @@ export function calculateRawShareValue(
return currentValue - postSaleValue
}
export function calculateMoneyRatio<T extends 'BINARY' | 'MULTI'>(
contract: Contract<T>,
bet: Bet<T>,
export function calculateMoneyRatio(
contract: Contract,
bet: Bet,
shareValue: number
) {
const { totalShares, totalBets, pool } = contract
@ -115,11 +116,7 @@ export function calculateSaleAmount(contract: Contract, bet: Bet) {
return deductFees(amount, winnings)
}
export function calculatePayout(
contract: Contract,
bet: Bet,
outcome: 'YES' | 'NO' | 'CANCEL' | 'MKT'
) {
export function calculatePayout(contract: Contract, bet: Bet, outcome: string) {
if (outcome === 'CANCEL') return calculateCancelPayout(contract, bet)
if (outcome === 'MKT') return calculateMktPayout(contract, bet)
@ -182,7 +179,7 @@ function calculateMktPayout(contract: Contract, bet: Bet) {
if (contract.outcomeType === 'BINARY')
return calculateBinaryMktPayout(contract, bet)
const { totalShares, pool } = contract as any as Contract<'MULTI'>
const { totalShares, pool } = contract
const totalPool = _.sum(Object.values(pool))
const sharesSquareSum = _.sumBy(
@ -206,16 +203,17 @@ function calculateMktPayout(contract: Contract, bet: Bet) {
}
function calculateBinaryMktPayout(contract: Contract, bet: Bet) {
const { resolutionProbability, totalShares, phantomShares } = contract
const p =
contract.resolutionProbability !== undefined
? contract.resolutionProbability
: getProbability(contract.totalShares)
resolutionProbability !== undefined
? resolutionProbability
: getProbability(totalShares)
const pool = contract.pool.YES + contract.pool.NO
const weightedShareTotal =
p * (contract.totalShares.YES - contract.phantomShares.YES) +
(1 - p) * (contract.totalShares.NO - contract.phantomShares.NO)
p * (totalShares.YES - (phantomShares?.YES ?? 0)) +
(1 - p) * (totalShares.NO - (phantomShares?.NO ?? 0))
const { outcome, amount, shares } = bet

View File

@ -1,4 +1,4 @@
export type Contract<outcomeType extends 'BINARY' | 'MULTI' = 'BINARY'> = {
export type Contract = {
id: string
slug: string // auto-generated; must be unique
@ -13,29 +13,14 @@ export type Contract<outcomeType extends 'BINARY' | 'MULTI' = 'BINARY'> = {
lowercaseTags: string[]
visibility: 'public' | 'unlisted'
outcomeType: outcomeType
outcomes: {
BINARY: undefined
MULTI: 'FREE_ANSWER' | string[]
}[outcomeType]
outcomeType: 'BINARY' | 'MULTI'
outcomes?: 'FREE_ANSWER' | string[]
mechanism: 'dpm-2'
phantomShares: {
BINARY: { YES: number; NO: number }
MULTI: undefined
}[outcomeType]
pool: {
BINARY: { YES: number; NO: number }
MULTI: { [answerId: string]: number }
}[outcomeType]
totalShares: {
BINARY: { YES: number; NO: number }
MULTI: { [answerId: string]: number }
}[outcomeType]
totalBets: {
BINARY: { YES: number; NO: number }
MULTI: { [answerId: string]: number }
}[outcomeType]
phantomShares?: { [outcome: string]: number }
pool: { [outcome: string]: number }
totalShares: { [outcome: string]: number }
totalBets: { [outcome: string]: number }
createdTime: number // Milliseconds since epoch
lastUpdatedTime: number // If the question or description was changed
@ -43,14 +28,9 @@ export type Contract<outcomeType extends 'BINARY' | 'MULTI' = 'BINARY'> = {
isResolved: boolean
resolutionTime?: number // When the contract creator resolved the market
resolution?: {
BINARY: outcome
MULTI: string
}[outcomeType]
resolution?: string
resolutionProbability?: number
volume24Hours: number
volume7Days: number
}
export type outcome = 'YES' | 'NO' | 'CANCEL' | 'MKT'

View File

@ -61,7 +61,7 @@ export const getNewMultiBetInfo = (
user: User,
outcome: string,
amount: number,
contract: Contract<'MULTI'>,
contract: Contract,
newBetId: string
) => {
const { pool, totalShares, totalBets } = contract
@ -80,7 +80,7 @@ export const getNewMultiBetInfo = (
const probBefore = getOutcomeProbability(totalShares, outcome)
const probAfter = getOutcomeProbability(newTotalShares, outcome)
const newBet: Bet<'MULTI'> = {
const newBet: Bet = {
id: newBetId,
userId: user.id,
contractId: contract.id,

View File

@ -26,7 +26,7 @@ export function getNewContract(
? getBinaryProps(initialProb, ante)
: getFreeAnswerProps(ante)
const contract: Contract<'BINARY' | 'MULTI'> = removeUndefinedProps({
const contract: Contract = removeUndefinedProps({
id,
slug,
mechanism: 'dpm-2',

View File

@ -2,7 +2,7 @@ import * as _ from 'lodash'
import { Bet } from './bet'
import { deductFees, getProbability } from './calculate'
import { Contract, outcome } from './contract'
import { Contract } from './contract'
import { CREATOR_FEE, FEES } from './fees'
export const getCancelPayouts = (contract: Contract, bets: Bet[]) => {
@ -100,7 +100,7 @@ export const getMktPayouts = (
}
export const getPayouts = (
outcome: outcome,
outcome: string,
contract: Contract,
bets: Bet[],
resolutionProbability?: number

View File

@ -42,7 +42,7 @@ export const createAnswer = functions.runWith({ minInstances: 1 }).https.onCall(
const contractSnap = await transaction.get(contractDoc)
if (!contractSnap.exists)
return { status: 'error', message: 'Invalid contract' }
const contract = contractSnap.data() as Contract<'MULTI'>
const contract = contractSnap.data() as Contract
if (
contract.outcomeType !== 'MULTI' ||

View File

@ -100,7 +100,7 @@ export const createContract = functions
const { yesBet, noBet } = getAnteBets(
creator,
contract as Contract<'BINARY'>,
contract,
yesBetDoc.id,
noBetDoc.id
)
@ -116,11 +116,7 @@ export const createContract = functions
const anteBetDoc = firestore
.collection(`contracts/${contract.id}/bets`)
.doc()
const anteBet = getFreeAnswerAnte(
creator,
contract as Contract<'MULTI'>,
anteBetDoc.id
)
const anteBet = getFreeAnswerAnte(creator, contract, anteBetDoc.id)
await anteBetDoc.set(anteBet)
}
}

View File

@ -35,10 +35,7 @@ import { useAnswers } from '../hooks/use-answers'
import { ResolveConfirmationButton } from './confirmation-button'
import { tradingAllowed } from '../lib/firebase/contracts'
export function AnswersPanel(props: {
contract: Contract<'MULTI'>
answers: Answer[]
}) {
export function AnswersPanel(props: { contract: Contract; answers: Answer[] }) {
const { contract } = props
const { creatorId, resolution } = contract
@ -101,7 +98,7 @@ export function AnswersPanel(props: {
function AnswerItem(props: {
answer: Answer
contract: Contract<'MULTI'>
contract: Contract
showChoice: boolean
isChosen: boolean
onChoose: () => void
@ -209,7 +206,7 @@ function AnswerItem(props: {
function AnswerBetPanel(props: {
answer: Answer
contract: Contract<'MULTI'>
contract: Contract
closePanel: () => void
}) {
const { answer, contract, closePanel } = props
@ -267,14 +264,11 @@ function AnswerBetPanel(props: {
const shares = calculateShares(contract.totalShares, betAmount ?? 0, answerId)
const currentPayout = betAmount
? calculatePayoutAfterCorrectBet(
contract as any as Contract,
{
outcome: answerId,
amount: betAmount,
shares,
} as Bet
)
? calculatePayoutAfterCorrectBet(contract, {
outcome: answerId,
amount: betAmount,
shares,
} as Bet)
: 0
const currentReturn = betAmount ? (currentPayout - betAmount) / betAmount : 0
@ -351,7 +345,7 @@ function AnswerBetPanel(props: {
)
}
function CreateAnswerInput(props: { contract: Contract<'MULTI'> }) {
function CreateAnswerInput(props: { contract: Contract }) {
const { contract } = props
const [text, setText] = useState('')
const [betAmount, setBetAmount] = useState<number | undefined>(10)
@ -426,7 +420,7 @@ function CreateAnswerInput(props: { contract: Contract<'MULTI'> }) {
}
function AnswerResolvePanel(props: {
contract: Contract<'MULTI'>
contract: Contract
resolveOption: 'CHOOSE' | 'NONE' | 'CANCEL' | undefined
setResolveOption: (option: 'CHOOSE' | 'NONE' | 'CANCEL' | undefined) => void
answer: string | undefined

View File

@ -49,6 +49,7 @@ export function BetPanel(props: {
}, [])
const { contract, className, title, selected, onBetSuccess } = props
const { totalShares, phantomShares } = contract
const user = useUser()
@ -179,8 +180,8 @@ export function BetPanel(props: {
shares
)} / ${formatWithCommas(
shares +
contract.totalShares[betChoice] -
contract.phantomShares[betChoice]
totalShares[betChoice] -
(phantomShares ? phantomShares[betChoice] : 0)
)} ${betChoice} shares`}
/>
</Row>

View File

@ -31,6 +31,7 @@ import {
import { sellBet } from '../lib/firebase/api-call'
import { ConfirmationButton } from './confirmation-button'
import { OutcomeLabel, YesLabel, NoLabel } from './outcome-label'
import { filterDefined } from '../../common/util/array'
type BetSort = 'newest' | 'profit'
@ -49,7 +50,7 @@ export function BetsList(props: { user: User }) {
let disposed = false
Promise.all(contractIds.map((id) => getContractFromId(id))).then(
(contracts) => {
if (!disposed) setContracts(contracts.filter(Boolean) as Contract[])
if (!disposed) setContracts(filterDefined(contracts))
}
)

View File

@ -21,7 +21,6 @@ import {
contractPath,
updateContract,
tradingAllowed,
getBinaryProbPercent,
} from '../lib/firebase/contracts'
import { useUser } from '../hooks/use-user'
import { Linkify } from './linkify'
@ -38,7 +37,6 @@ import { useBets } from '../hooks/use-bets'
import { Bet } from '../lib/firebase/bets'
import { Comment, mapCommentsByBetId } from '../lib/firebase/comments'
import { JoinSpans } from './join-spans'
import { outcome } from '../../common/contract'
import { fromNow } from '../lib/util/time'
import BetRow from './bet-row'
import { parseTags } from '../../common/util/parse'
@ -382,7 +380,7 @@ function FeedDescription(props: { contract: Contract }) {
)
}
function OutcomeIcon(props: { outcome?: outcome }) {
function OutcomeIcon(props: { outcome?: string }) {
const { outcome } = props
switch (outcome) {
case 'YES':

View File

@ -13,7 +13,9 @@ export function ContractProbGraph(props: { contract: Contract; bets: Bet[] }) {
const bets = useBetsWithoutAntes(contract, props.bets)
const startProb = getProbability(phantomShares)
const startProb = getProbability(
phantomShares as { [outcome: string]: number }
)
const times = bets
? [contract.createdTime, ...bets.map((bet) => bet.createdTime)].map(

View File

@ -49,7 +49,7 @@ export function getBinaryProbPercent(contract: Contract) {
return probPercent
}
export function tradingAllowed(contract: Contract<'BINARY' | 'MULTI'>) {
export function tradingAllowed(contract: Contract) {
return (
!contract.isResolved &&
(!contract.closeTime || contract.closeTime > Date.now())
@ -84,9 +84,7 @@ export async function getContractFromSlug(slug: string) {
const q = query(contractCollection, where('slug', '==', slug))
const snapshot = await getDocs(q)
return snapshot.empty
? undefined
: (snapshot.docs[0].data() as Contract<'BINARY' | 'MULTI'>)
return snapshot.empty ? undefined : (snapshot.docs[0].data() as Contract)
}
export async function deleteContract(contractId: string) {

View File

@ -186,7 +186,7 @@ function BetsSection(props: {
)
}
const getOpenGraphProps = (contract: Contract<'BINARY'>) => {
const getOpenGraphProps = (contract: Contract) => {
const { resolution, question, creatorName, creatorUsername } = contract
const probPercent = getBinaryProbPercent(contract)

View File

@ -26,7 +26,7 @@ type Prediction = {
}
function toPrediction(contract: Contract): Prediction {
const startProb = getProbability(contract.phantomShares)
const startProb = getProbability(contract.totalShares)
return {
question: contract.question,
description: contract.description,