manifold/web/components/answers/answers-panel.tsx
mantikoros c183e00d47
Cfmm (#64)
* cpmm initial commit: common logic, cloud functions

* remove unnecessary property

* contract type

* rename 'calculate.ts' => 'calculate-dpm.ts'

* rename dpm calculations

* use focus hook

* mechanism-agnostic calculations

* bet panel: use new calculations

* use new calculations

* delete markets cloud function

* use correct contract type in scripts / functions

* calculate fixed payouts; bets list calculations

* new bet: use calculateCpmmPurchase

* getOutcomeProbabilityAfterBet

* use deductFixedFees

* fix auto-refactor

* fix antes

* separate logic to payouts-dpm, payouts-fixed

* liquidity provision tracking

* remove comment

* liquidity label

* create liquidity provision even if no ante bet

* liquidity fee

* use all bets for getFixedCancelPayouts

* updateUserBalance: allow negative balances

* store initialProbability in contracts

* turn on liquidity fee; turn off creator fee

* Include time param in tweet url, so image preview is re-fetched

* share redemption

* cpmm ContractBetsTable display

* formatMoney: handle minus zero

* filter out redemption bets

* track fees on contract and bets; change fee schedule for cpmm markets; only pay out creator fees at resolution

* small fixes

* small fixes

* Redeem shares pays back loans first

* Fix initial point on graph

* calculateCpmmPurchase: deduct creator fee

* Filter out redemption bets from feed

* set env to dev for user-testing purposes

* creator fees messaging

* new cfmm: k = y^(1-p) * n^p

* addCpmmLiquidity

* correct price function

* enable fees

* handle overflow

* liquidity provision tracking

* raise fees

* Fix merge error

* fix dpm free response payout for single outcome

* Fix DPM payout calculation

* Remove hardcoding as dev

Co-authored-by: James Grugett <jahooma@gmail.com>
2022-03-15 17:27:51 -05:00

125 lines
3.5 KiB
TypeScript

import _ from 'lodash'
import { useLayoutEffect, useState } from 'react'
import { Answer } from '../../../common/answer'
import { DPM, FreeResponse, FullContract } from '../../../common/contract'
import { Col } from '../layout/col'
import { formatPercent } from '../../../common/util/format'
import { useUser } from '../../hooks/use-user'
import { getDpmOutcomeProbability } from '../../../common/calculate-dpm'
import { useAnswers } from '../../hooks/use-answers'
import { tradingAllowed } from '../../lib/firebase/contracts'
import { AnswerItem } from './answer-item'
import { CreateAnswerPanel } from './create-answer-panel'
import { AnswerResolvePanel } from './answer-resolve-panel'
export function AnswersPanel(props: {
contract: FullContract<DPM, FreeResponse>
answers: Answer[]
}) {
const { contract } = props
const { creatorId, resolution, resolutions, totalBets } = contract
const answers = useAnswers(contract.id) ?? props.answers
const [winningAnswers, otherAnswers] = _.partition(
answers.filter(
(answer) => answer.id !== '0' && totalBets[answer.id] > 0.000000001
),
(answer) =>
answer.id === resolution || (resolutions && resolutions[answer.id])
)
const sortedAnswers = [
..._.sortBy(winningAnswers, (answer) =>
resolutions ? -1 * resolutions[answer.id] : 0
),
..._.sortBy(
otherAnswers,
(answer) => -1 * getDpmOutcomeProbability(contract.totalShares, answer.id)
),
]
const user = useUser()
const [resolveOption, setResolveOption] = useState<
'CHOOSE' | 'CHOOSE_MULTIPLE' | 'CANCEL' | undefined
>()
const [chosenAnswers, setChosenAnswers] = useState<{
[answerId: string]: number
}>({})
const chosenTotal = _.sum(Object.values(chosenAnswers))
const onChoose = (answerId: string, prob: number) => {
if (resolveOption === 'CHOOSE') {
setChosenAnswers({ [answerId]: prob })
} else {
setChosenAnswers((chosenAnswers) => {
return {
...chosenAnswers,
[answerId]: prob,
}
})
}
}
const onDeselect = (answerId: string) => {
setChosenAnswers((chosenAnswers) => {
const newChosenAnswers = { ...chosenAnswers }
delete newChosenAnswers[answerId]
return newChosenAnswers
})
}
useLayoutEffect(() => {
setChosenAnswers({})
}, [resolveOption])
const showChoice = resolution
? undefined
: resolveOption === 'CHOOSE'
? 'radio'
: resolveOption === 'CHOOSE_MULTIPLE'
? 'checkbox'
: undefined
return (
<Col className="gap-3">
{sortedAnswers.map((answer) => (
<AnswerItem
key={answer.id}
answer={answer}
contract={contract}
user={user}
showChoice={showChoice}
chosenProb={chosenAnswers[answer.id]}
totalChosenProb={chosenTotal}
onChoose={onChoose}
onDeselect={onDeselect}
/>
))}
{sortedAnswers.length === 0 ? (
<div className="p-4 text-gray-500">No answers yet...</div>
) : (
<div className="self-end p-4 text-gray-500">
None of the above:{' '}
{formatPercent(getDpmOutcomeProbability(contract.totalShares, '0'))}
</div>
)}
{tradingAllowed(contract) && !resolveOption && (
<CreateAnswerPanel contract={contract} />
)}
{user?.id === creatorId && !resolution && (
<AnswerResolvePanel
contract={contract}
resolveOption={resolveOption}
setResolveOption={setResolveOption}
chosenAnswers={chosenAnswers}
/>
)}
</Col>
)
}