manifold/common/new-contract.ts
2022-08-14 21:09:48 -07:00

229 lines
5.0 KiB
TypeScript

import { range } from 'lodash'
import {
Binary,
Bounty,
Contract,
CPMM,
DPM,
FreeResponse,
MultipleChoice,
Numeric,
outcomeType,
PseudoNumeric,
} from './contract'
import { User } from './user'
import { parseTags, richTextToString } from './util/parse'
import { removeUndefinedProps } from './util/object'
import { JSONContent } from '@tiptap/core'
export function getNewContract(
id: string,
slug: string,
creator: User,
question: string,
outcomeType: outcomeType,
description: JSONContent,
initialProb: number,
ante: number,
closeTime: number,
extraTags: string[],
// used for numeric markets
bucketCount: number,
min: number,
max: number,
isLogScale: boolean,
// for multiple choice
answers: string[]
) {
const tags = parseTags(
[
question,
richTextToString(description),
...extraTags.map((tag) => `#${tag}`),
].join(' ')
)
const lowercaseTags = tags.map((tag) => tag.toLowerCase())
const PROPS = {
BINARY: getBinaryCpmmProps(initialProb, ante), // getBinaryDpmProps(initialProb, ante)
PSEUDO_NUMERIC: getPseudoNumericCpmmProps(
initialProb,
ante,
min,
max,
isLogScale
),
FREE_RESPONSE: getFreeAnswerProps(ante),
MULTIPLE_CHOICE: getMultipleChoiceProps(ante, answers),
NUMERIC: getNumericProps(ante, bucketCount, min, max),
BOUNTY: getBountyProps(ante, creator),
}
const propsByOutcomeType = PROPS[outcomeType] || PROPS['FREE_RESPONSE']
const contract: Contract = removeUndefinedProps({
id,
slug,
...propsByOutcomeType,
creatorId: creator.id,
creatorName: creator.name,
creatorUsername: creator.username,
creatorAvatarUrl: creator.avatarUrl,
question: question.trim(),
description,
tags,
lowercaseTags,
visibility: 'public',
isResolved: false,
createdTime: Date.now(),
closeTime,
volume: 0,
volume24Hours: 0,
volume7Days: 0,
collectedFees: {
creatorFee: 0,
liquidityFee: 0,
platformFee: 0,
},
})
return contract as Contract
}
/*
import { PHANTOM_ANTE } from './antes'
import { calcDpmInitialPool } from './calculate-dpm'
const getBinaryDpmProps = (initialProb: number, ante: number) => {
const { sharesYes, sharesNo, poolYes, poolNo, phantomYes, phantomNo } =
calcDpmInitialPool(initialProb, ante, PHANTOM_ANTE)
const system: DPM & Binary = {
mechanism: 'dpm-2',
outcomeType: 'BINARY',
initialProbability: initialProb / 100,
phantomShares: { YES: phantomYes, NO: phantomNo },
pool: { YES: poolYes, NO: poolNo },
totalShares: { YES: sharesYes, NO: sharesNo },
totalBets: { YES: poolYes, NO: poolNo },
}
return system
}
*/
const getBinaryCpmmProps = (initialProb: number, ante: number) => {
const pool = { YES: ante, NO: ante }
const p = initialProb / 100
const system: CPMM & Binary = {
mechanism: 'cpmm-1',
outcomeType: 'BINARY',
totalLiquidity: ante,
initialProbability: p,
p,
pool: pool,
}
return system
}
const getPseudoNumericCpmmProps = (
initialProb: number,
ante: number,
min: number,
max: number,
isLogScale: boolean
) => {
const system: CPMM & PseudoNumeric = {
...getBinaryCpmmProps(initialProb, ante),
outcomeType: 'PSEUDO_NUMERIC',
min,
max,
isLogScale,
}
return system
}
const getFreeAnswerProps = (ante: number) => {
const system: DPM & FreeResponse = {
mechanism: 'dpm-2',
outcomeType: 'FREE_RESPONSE',
pool: { '0': ante },
totalShares: { '0': ante },
totalBets: { '0': ante },
answers: [],
}
return system
}
function getBountyProps(ante: number, creator: User) {
const system: DPM & Bounty = {
...getFreeAnswerProps(ante),
outcomeType: 'BOUNTY',
prizes: {
[creator.id]: ante,
},
prizeTotal: ante,
}
return system
}
const getMultipleChoiceProps = (ante: number, answers: string[]) => {
const numAnswers = answers.length
const betAnte = ante / numAnswers
const betShares = Math.sqrt(ante ** 2 / numAnswers)
const defaultValues = (x: any) =>
Object.fromEntries(range(0, numAnswers).map((k) => [k, x]))
const system: DPM & MultipleChoice = {
mechanism: 'dpm-2',
outcomeType: 'MULTIPLE_CHOICE',
pool: defaultValues(betAnte),
totalShares: defaultValues(betShares),
totalBets: defaultValues(betAnte),
answers: [],
}
return system
}
const getNumericProps = (
ante: number,
bucketCount: number,
min: number,
max: number
) => {
const buckets = range(0, bucketCount).map((i) => i.toString())
const betAnte = ante / bucketCount
const pool = Object.fromEntries(buckets.map((answer) => [answer, betAnte]))
const totalBets = pool
const betShares = Math.sqrt(ante ** 2 / bucketCount)
const totalShares = Object.fromEntries(
buckets.map((answer) => [answer, betShares])
)
const system: DPM & Numeric = {
mechanism: 'dpm-2',
outcomeType: 'NUMERIC',
pool,
totalBets,
totalShares,
bucketCount,
min,
max,
}
return system
}