Add AnswerContract type to wrap FR, MCM, Bounty
This commit is contained in:
parent
49f60cdb80
commit
00717c90ef
|
@ -24,6 +24,7 @@ import {
|
||||||
FreeResponseContract,
|
FreeResponseContract,
|
||||||
PseudoNumericContract,
|
PseudoNumericContract,
|
||||||
MultipleChoiceContract,
|
MultipleChoiceContract,
|
||||||
|
AnswerContract,
|
||||||
} from './contract'
|
} from './contract'
|
||||||
import { floatingEqual } from './util/math'
|
import { floatingEqual } from './util/math'
|
||||||
|
|
||||||
|
@ -201,9 +202,7 @@ export function getContractBetNullMetrics() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTopAnswer(
|
export function getTopAnswer(contract: AnswerContract) {
|
||||||
contract: FreeResponseContract | MultipleChoiceContract
|
|
||||||
) {
|
|
||||||
const { answers } = contract
|
const { answers } = contract
|
||||||
const top = maxBy(
|
const top = maxBy(
|
||||||
answers?.map((answer) => ({
|
answers?.map((answer) => ({
|
||||||
|
|
|
@ -71,6 +71,10 @@ export type DPMContract = Contract & DPM
|
||||||
export type CPMMContract = Contract & CPMM
|
export type CPMMContract = Contract & CPMM
|
||||||
export type DPMBinaryContract = BinaryContract & DPM
|
export type DPMBinaryContract = BinaryContract & DPM
|
||||||
export type CPMMBinaryContract = BinaryContract & CPMM
|
export type CPMMBinaryContract = BinaryContract & CPMM
|
||||||
|
export type AnswerContract =
|
||||||
|
| FreeResponseContract
|
||||||
|
| MultipleChoiceContract
|
||||||
|
| BountyContract
|
||||||
|
|
||||||
export type DPM = {
|
export type DPM = {
|
||||||
mechanism: 'dpm-2'
|
mechanism: 'dpm-2'
|
||||||
|
|
|
@ -15,6 +15,7 @@ import {
|
||||||
getCpmmProbability,
|
getCpmmProbability,
|
||||||
} from './calculate-cpmm'
|
} from './calculate-cpmm'
|
||||||
import {
|
import {
|
||||||
|
AnswerContract,
|
||||||
CPMMBinaryContract,
|
CPMMBinaryContract,
|
||||||
DPMBinaryContract,
|
DPMBinaryContract,
|
||||||
FreeResponseContract,
|
FreeResponseContract,
|
||||||
|
@ -323,7 +324,7 @@ export const getNewBinaryDpmBetInfo = (
|
||||||
export const getNewMultiBetInfo = (
|
export const getNewMultiBetInfo = (
|
||||||
outcome: string,
|
outcome: string,
|
||||||
amount: number,
|
amount: number,
|
||||||
contract: FreeResponseContract | MultipleChoiceContract,
|
contract: AnswerContract,
|
||||||
loanAmount: number
|
loanAmount: number
|
||||||
) => {
|
) => {
|
||||||
const { pool, totalShares, totalBets } = contract
|
const { pool, totalShares, totalBets } = contract
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { sum, groupBy, sumBy, mapValues } from 'lodash'
|
||||||
import { Bet, NumericBet } from './bet'
|
import { Bet, NumericBet } from './bet'
|
||||||
import { deductDpmFees, getDpmProbability } from './calculate-dpm'
|
import { deductDpmFees, getDpmProbability } from './calculate-dpm'
|
||||||
import {
|
import {
|
||||||
|
AnswerContract,
|
||||||
DPMContract,
|
DPMContract,
|
||||||
FreeResponseContract,
|
FreeResponseContract,
|
||||||
MultipleChoiceContract,
|
MultipleChoiceContract,
|
||||||
|
@ -184,7 +185,7 @@ export const getDpmMktPayouts = (
|
||||||
|
|
||||||
export const getPayoutsMultiOutcome = (
|
export const getPayoutsMultiOutcome = (
|
||||||
resolutions: { [outcome: string]: number },
|
resolutions: { [outcome: string]: number },
|
||||||
contract: FreeResponseContract | MultipleChoiceContract,
|
contract: AnswerContract,
|
||||||
bets: Bet[]
|
bets: Bet[]
|
||||||
) => {
|
) => {
|
||||||
const poolTotal = sum(Object.values(contract.pool))
|
const poolTotal = sum(Object.values(contract.pool))
|
||||||
|
|
|
@ -36,7 +36,10 @@ export const createanswer = newEndpoint(opts, async (req, auth) => {
|
||||||
if (!contractSnap.exists) throw new APIError(400, 'Invalid contract')
|
if (!contractSnap.exists) throw new APIError(400, 'Invalid contract')
|
||||||
const contract = contractSnap.data() as Contract
|
const contract = contractSnap.data() as Contract
|
||||||
|
|
||||||
if (contract.outcomeType !== 'FREE_RESPONSE')
|
if (
|
||||||
|
contract.outcomeType !== 'FREE_RESPONSE' &&
|
||||||
|
contract.outcomeType !== 'BOUNTY'
|
||||||
|
)
|
||||||
throw new APIError(400, 'Requires a free response contract')
|
throw new APIError(400, 'Requires a free response contract')
|
||||||
|
|
||||||
const { closeTime, volume } = contract
|
const { closeTime, volume } = contract
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { z } from 'zod'
|
||||||
import { difference, uniq, mapValues, groupBy, sumBy } from 'lodash'
|
import { difference, uniq, mapValues, groupBy, sumBy } from 'lodash'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
AnswerContract,
|
||||||
Contract,
|
Contract,
|
||||||
FreeResponseContract,
|
FreeResponseContract,
|
||||||
MultipleChoiceContract,
|
MultipleChoiceContract,
|
||||||
|
@ -295,10 +296,7 @@ function getResolutionParams(contract: Contract, body: string) {
|
||||||
throw new APIError(500, `Invalid outcome type: ${outcomeType}`)
|
throw new APIError(500, `Invalid outcome type: ${outcomeType}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateAnswer(
|
function validateAnswer(contract: AnswerContract, answer: number) {
|
||||||
contract: FreeResponseContract | MultipleChoiceContract,
|
|
||||||
answer: number
|
|
||||||
) {
|
|
||||||
const validIds = contract.answers.map((a) => a.id)
|
const validIds = contract.answers.map((a) => a.id)
|
||||||
if (!validIds.includes(answer.toString())) {
|
if (!validIds.includes(answer.toString())) {
|
||||||
throw new APIError(400, `${answer} is not a valid answer ID`)
|
throw new APIError(400, `${answer} is not a valid answer ID`)
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { useEffect, useRef, useState } from 'react'
|
||||||
import { XIcon } from '@heroicons/react/solid'
|
import { XIcon } from '@heroicons/react/solid'
|
||||||
|
|
||||||
import { Answer } from 'common/answer'
|
import { Answer } from 'common/answer'
|
||||||
import { FreeResponseContract, MultipleChoiceContract } from 'common/contract'
|
import { AnswerContract } from 'common/contract'
|
||||||
import { BuyAmountInput } from '../amount-input'
|
import { BuyAmountInput } from '../amount-input'
|
||||||
import { Col } from '../layout/col'
|
import { Col } from '../layout/col'
|
||||||
import { APIError, placeBet } from 'web/lib/firebase/api'
|
import { APIError, placeBet } from 'web/lib/firebase/api'
|
||||||
|
@ -30,7 +30,7 @@ import { AlertBox } from '../alert-box'
|
||||||
|
|
||||||
export function AnswerBetPanel(props: {
|
export function AnswerBetPanel(props: {
|
||||||
answer: Answer
|
answer: Answer
|
||||||
contract: FreeResponseContract | MultipleChoiceContract
|
contract: AnswerContract
|
||||||
closePanel: () => void
|
closePanel: () => void
|
||||||
className?: string
|
className?: string
|
||||||
isModal?: boolean
|
isModal?: boolean
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
|
|
||||||
import { Answer } from 'common/answer'
|
import { Answer } from 'common/answer'
|
||||||
import { FreeResponseContract, MultipleChoiceContract } from 'common/contract'
|
import { AnswerContract } from 'common/contract'
|
||||||
import { Col } from '../layout/col'
|
import { Col } from '../layout/col'
|
||||||
import { Row } from '../layout/row'
|
import { Row } from '../layout/row'
|
||||||
import { Avatar } from '../avatar'
|
import { Avatar } from '../avatar'
|
||||||
|
@ -13,7 +13,7 @@ import { Linkify } from '../linkify'
|
||||||
|
|
||||||
export function AnswerItem(props: {
|
export function AnswerItem(props: {
|
||||||
answer: Answer
|
answer: Answer
|
||||||
contract: FreeResponseContract | MultipleChoiceContract
|
contract: AnswerContract
|
||||||
showChoice: 'radio' | 'checkbox' | undefined
|
showChoice: 'radio' | 'checkbox' | undefined
|
||||||
chosenProb: number | undefined
|
chosenProb: number | undefined
|
||||||
totalChosenProb?: number
|
totalChosenProb?: number
|
||||||
|
|
|
@ -2,7 +2,7 @@ import clsx from 'clsx'
|
||||||
import { sum } from 'lodash'
|
import { sum } from 'lodash'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
|
|
||||||
import { FreeResponseContract, MultipleChoiceContract } from 'common/contract'
|
import { AnswerContract } from 'common/contract'
|
||||||
import { Col } from '../layout/col'
|
import { Col } from '../layout/col'
|
||||||
import { APIError, resolveMarket } from 'web/lib/firebase/api'
|
import { APIError, resolveMarket } from 'web/lib/firebase/api'
|
||||||
import { Row } from '../layout/row'
|
import { Row } from '../layout/row'
|
||||||
|
@ -11,7 +11,7 @@ import { ResolveConfirmationButton } from '../confirmation-button'
|
||||||
import { removeUndefinedProps } from 'common/util/object'
|
import { removeUndefinedProps } from 'common/util/object'
|
||||||
|
|
||||||
export function AnswerResolvePanel(props: {
|
export function AnswerResolvePanel(props: {
|
||||||
contract: FreeResponseContract | MultipleChoiceContract
|
contract: AnswerContract
|
||||||
resolveOption: 'CHOOSE' | 'CHOOSE_MULTIPLE' | 'CANCEL' | undefined
|
resolveOption: 'CHOOSE' | 'CHOOSE_MULTIPLE' | 'CANCEL' | undefined
|
||||||
setResolveOption: (
|
setResolveOption: (
|
||||||
option: 'CHOOSE' | 'CHOOSE_MULTIPLE' | 'CANCEL' | undefined
|
option: 'CHOOSE' | 'CHOOSE_MULTIPLE' | 'CANCEL' | undefined
|
||||||
|
|
|
@ -5,14 +5,18 @@ import { groupBy, sortBy, sumBy } from 'lodash'
|
||||||
import { memo } from 'react'
|
import { memo } from 'react'
|
||||||
|
|
||||||
import { Bet } from 'common/bet'
|
import { Bet } from 'common/bet'
|
||||||
import { FreeResponseContract, MultipleChoiceContract } from 'common/contract'
|
import {
|
||||||
|
AnswerContract,
|
||||||
|
FreeResponseContract,
|
||||||
|
MultipleChoiceContract,
|
||||||
|
} from 'common/contract'
|
||||||
import { getOutcomeProbability } from 'common/calculate'
|
import { getOutcomeProbability } from 'common/calculate'
|
||||||
import { useWindowSize } from 'web/hooks/use-window-size'
|
import { useWindowSize } from 'web/hooks/use-window-size'
|
||||||
|
|
||||||
const NUM_LINES = 6
|
const NUM_LINES = 6
|
||||||
|
|
||||||
export const AnswersGraph = memo(function AnswersGraph(props: {
|
export const AnswersGraph = memo(function AnswersGraph(props: {
|
||||||
contract: FreeResponseContract | MultipleChoiceContract
|
contract: AnswerContract
|
||||||
bets: Bet[]
|
bets: Bet[]
|
||||||
height?: number
|
height?: number
|
||||||
}) {
|
}) {
|
||||||
|
@ -178,10 +182,7 @@ function formatTime(
|
||||||
return d.format(format)
|
return d.format(format)
|
||||||
}
|
}
|
||||||
|
|
||||||
const computeProbsByOutcome = (
|
const computeProbsByOutcome = (bets: Bet[], contract: AnswerContract) => {
|
||||||
bets: Bet[],
|
|
||||||
contract: FreeResponseContract | MultipleChoiceContract
|
|
||||||
) => {
|
|
||||||
const { totalBets, outcomeType } = contract
|
const { totalBets, outcomeType } = contract
|
||||||
|
|
||||||
const betsByOutcome = groupBy(bets, (bet) => bet.outcome)
|
const betsByOutcome = groupBy(bets, (bet) => bet.outcome)
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
import { sortBy, partition, sum, uniq } from 'lodash'
|
import { sortBy, partition, sum, uniq } from 'lodash'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
import { FreeResponseContract, MultipleChoiceContract } from 'common/contract'
|
import {
|
||||||
|
AnswerContract,
|
||||||
|
BountyContract,
|
||||||
|
FreeResponseContract,
|
||||||
|
MultipleChoiceContract,
|
||||||
|
} from 'common/contract'
|
||||||
import { Col } from '../layout/col'
|
import { Col } from '../layout/col'
|
||||||
import { useUser } from 'web/hooks/use-user'
|
import { useUser } from 'web/hooks/use-user'
|
||||||
import { getDpmOutcomeProbability } from 'common/calculate-dpm'
|
import { getDpmOutcomeProbability } from 'common/calculate-dpm'
|
||||||
|
@ -25,9 +30,7 @@ import { UserLink } from 'web/components/user-page'
|
||||||
import { Linkify } from 'web/components/linkify'
|
import { Linkify } from 'web/components/linkify'
|
||||||
import { BuyButton } from 'web/components/yes-no-selector'
|
import { BuyButton } from 'web/components/yes-no-selector'
|
||||||
|
|
||||||
export function AnswersPanel(props: {
|
export function AnswersPanel(props: { contract: AnswerContract }) {
|
||||||
contract: FreeResponseContract | MultipleChoiceContract
|
|
||||||
}) {
|
|
||||||
const { contract } = props
|
const { contract } = props
|
||||||
const { creatorId, resolution, resolutions, totalBets, outcomeType } =
|
const { creatorId, resolution, resolutions, totalBets, outcomeType } =
|
||||||
contract
|
contract
|
||||||
|
@ -136,7 +139,7 @@ export function AnswersPanel(props: {
|
||||||
<div className="pb-4 text-gray-500">No answers yet...</div>
|
<div className="pb-4 text-gray-500">No answers yet...</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{outcomeType === 'FREE_RESPONSE' &&
|
{(outcomeType === 'FREE_RESPONSE' || outcomeType === 'BOUNTY') &&
|
||||||
tradingAllowed(contract) &&
|
tradingAllowed(contract) &&
|
||||||
(!resolveOption || resolveOption === 'CANCEL') && (
|
(!resolveOption || resolveOption === 'CANCEL') && (
|
||||||
<CreateAnswerPanel contract={contract} />
|
<CreateAnswerPanel contract={contract} />
|
||||||
|
@ -158,7 +161,7 @@ export function AnswersPanel(props: {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAnswerItems(
|
function getAnswerItems(
|
||||||
contract: FreeResponseContract | MultipleChoiceContract,
|
contract: AnswerContract,
|
||||||
answers: Answer[],
|
answers: Answer[],
|
||||||
user: User | undefined | null
|
user: User | undefined | null
|
||||||
) {
|
) {
|
||||||
|
@ -184,7 +187,7 @@ function getAnswerItems(
|
||||||
}
|
}
|
||||||
|
|
||||||
function OpenAnswer(props: {
|
function OpenAnswer(props: {
|
||||||
contract: FreeResponseContract | MultipleChoiceContract
|
contract: AnswerContract
|
||||||
answer: Answer
|
answer: Answer
|
||||||
items: ActivityItem[]
|
items: ActivityItem[]
|
||||||
type: string
|
type: string
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { useState } from 'react'
|
||||||
import Textarea from 'react-expanding-textarea'
|
import Textarea from 'react-expanding-textarea'
|
||||||
import { findBestMatch } from 'string-similarity'
|
import { findBestMatch } from 'string-similarity'
|
||||||
|
|
||||||
import { FreeResponseContract } from 'common/contract'
|
import { BountyContract, FreeResponseContract } from 'common/contract'
|
||||||
import { BuyAmountInput } from '../amount-input'
|
import { BuyAmountInput } from '../amount-input'
|
||||||
import { Col } from '../layout/col'
|
import { Col } from '../layout/col'
|
||||||
import { APIError, createAnswer } from 'web/lib/firebase/api'
|
import { APIError, createAnswer } from 'web/lib/firebase/api'
|
||||||
|
@ -26,7 +26,9 @@ import { MAX_ANSWER_LENGTH } from 'common/answer'
|
||||||
import { withTracking } from 'web/lib/service/analytics'
|
import { withTracking } from 'web/lib/service/analytics'
|
||||||
import { lowerCase } from 'lodash'
|
import { lowerCase } from 'lodash'
|
||||||
|
|
||||||
export function CreateAnswerPanel(props: { contract: FreeResponseContract }) {
|
export function CreateAnswerPanel(props: {
|
||||||
|
contract: FreeResponseContract | BountyContract
|
||||||
|
}) {
|
||||||
const { contract } = props
|
const { contract } = props
|
||||||
const user = useUser()
|
const user = useUser()
|
||||||
const [text, setText] = useState('')
|
const [text, setText] = useState('')
|
||||||
|
|
|
@ -9,6 +9,7 @@ import {
|
||||||
import { contractPath, getBinaryProbPercent } from 'web/lib/firebase/contracts'
|
import { contractPath, getBinaryProbPercent } from 'web/lib/firebase/contracts'
|
||||||
import { Col } from '../layout/col'
|
import { Col } from '../layout/col'
|
||||||
import {
|
import {
|
||||||
|
AnswerContract,
|
||||||
BinaryContract,
|
BinaryContract,
|
||||||
BountyContract,
|
BountyContract,
|
||||||
Contract,
|
Contract,
|
||||||
|
@ -232,7 +233,7 @@ export function BountyValue(props: {
|
||||||
}
|
}
|
||||||
|
|
||||||
function FreeResponseTopAnswer(props: {
|
function FreeResponseTopAnswer(props: {
|
||||||
contract: FreeResponseContract | MultipleChoiceContract
|
contract: AnswerContract
|
||||||
truncate: 'short' | 'long' | 'none'
|
truncate: 'short' | 'long' | 'none'
|
||||||
className?: string
|
className?: string
|
||||||
}) {
|
}) {
|
||||||
|
|
|
@ -56,7 +56,8 @@ export function ContractTabs(props: {
|
||||||
tips={tips}
|
tips={tips}
|
||||||
user={user}
|
user={user}
|
||||||
mode={
|
mode={
|
||||||
contract.outcomeType === 'FREE_RESPONSE'
|
contract.outcomeType === 'FREE_RESPONSE' ||
|
||||||
|
contract.outcomeType === 'BOUNTY'
|
||||||
? 'free-response-comment-answer-groups'
|
? 'free-response-comment-answer-groups'
|
||||||
: 'comments'
|
: 'comments'
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { Answer } from 'common/answer'
|
||||||
import { getProbability } from 'common/calculate'
|
import { getProbability } from 'common/calculate'
|
||||||
import { getValueFromBucket } from 'common/calculate-dpm'
|
import { getValueFromBucket } from 'common/calculate-dpm'
|
||||||
import {
|
import {
|
||||||
|
AnswerContract,
|
||||||
BinaryContract,
|
BinaryContract,
|
||||||
BountyContract,
|
BountyContract,
|
||||||
Contract,
|
Contract,
|
||||||
|
@ -78,7 +79,7 @@ export function BinaryContractOutcomeLabel(props: {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function FreeResponseOutcomeLabel(props: {
|
export function FreeResponseOutcomeLabel(props: {
|
||||||
contract: FreeResponseContract | MultipleChoiceContract | BountyContract
|
contract: AnswerContract
|
||||||
resolution: string | 'CANCEL' | 'MKT'
|
resolution: string | 'CANCEL' | 'MKT'
|
||||||
truncate: 'short' | 'long' | 'none'
|
truncate: 'short' | 'long' | 'none'
|
||||||
answerClassName?: string
|
answerClassName?: string
|
||||||
|
|
Loading…
Reference in New Issue
Block a user