diff --git a/functions/src/accept-challenge.ts b/functions/src/accept-challenge.ts index 8f319887..08f7af10 100644 --- a/functions/src/accept-challenge.ts +++ b/functions/src/accept-challenge.ts @@ -64,6 +64,8 @@ export const acceptchallenge = newEndpoint({}, async (req, auth) => { const contract = anyContract as CPMMBinaryContract const shares = (1 / creatorOutcomeProb) * creatorAmount const createdTime = Date.now() + const probOfYes = + creatorOutcome === 'YES' ? creatorOutcomeProb : 1 - creatorOutcomeProb log( 'Creating challenge bet for', @@ -80,12 +82,12 @@ export const acceptchallenge = newEndpoint({}, async (req, auth) => { const yourNewBet: CandidateBet = removeUndefinedProps({ orderAmount: acceptorAmount, amount: acceptorAmount, - shares: shares, + shares, isCancelled: false, contractId: contract.id, outcome: acceptorOutcome, - probBefore: creatorOutcomeProb, - probAfter: creatorOutcomeProb, + probBefore: probOfYes, + probAfter: probOfYes, loanAmount: 0, createdTime, fees: noFees, @@ -103,12 +105,12 @@ export const acceptchallenge = newEndpoint({}, async (req, auth) => { const creatorNewBet: CandidateBet = removeUndefinedProps({ orderAmount: creatorAmount, amount: creatorAmount, - shares: shares, + shares, isCancelled: false, contractId: contract.id, outcome: creatorOutcome, - probBefore: creatorOutcomeProb, - probAfter: creatorOutcomeProb, + probBefore: probOfYes, + probAfter: probOfYes, loanAmount: 0, createdTime, fees: noFees, diff --git a/web/components/SEO.tsx b/web/components/SEO.tsx index 0d43f9b0..b1e0ca5f 100644 --- a/web/components/SEO.tsx +++ b/web/components/SEO.tsx @@ -15,15 +15,12 @@ function buildCardUrl(props: OgCardProps, challenge?: Challenge) { const { creatorAmount, acceptances, - creatorOutcomeProb, + acceptorAmount, creatorOutcome, acceptorOutcome, } = challenge || {} const { userName, userAvatarUrl } = acceptances?.[0] ?? {} - const challengeAmount = - creatorOutcomeProb && - creatorAmount && - Math.round(((1 - creatorOutcomeProb) / creatorOutcomeProb) * creatorAmount) + const probabilityParam = props.probability === undefined ? '' @@ -35,7 +32,7 @@ function buildCardUrl(props: OgCardProps, challenge?: Challenge) { const challengeUrlParams = challenge ? `&creatorAmount=${creatorAmount}&creatorOutcome=${creatorOutcome}` + - `&challengerAmount=${challengeAmount}&challengerOutcome=${acceptorOutcome}` + + `&challengerAmount=${acceptorAmount}&challengerOutcome=${acceptorOutcome}` + `&acceptedName=${userName ?? ''}&acceptedAvatarUrl=${userAvatarUrl ?? ''}` : '' diff --git a/web/components/challenges/create-challenge-button.tsx b/web/components/challenges/create-challenge-button.tsx index cc03c0ba..c1f9a256 100644 --- a/web/components/challenges/create-challenge-button.tsx +++ b/web/components/challenges/create-challenge-button.tsx @@ -1,7 +1,12 @@ import clsx from 'clsx' import dayjs from 'dayjs' import { useEffect, useState } from 'react' -import { DuplicateIcon } from '@heroicons/react/outline' +import { + AdjustmentsIcon, + CogIcon, + DuplicateIcon, + PencilIcon, +} from '@heroicons/react/outline' import { Col } from '../layout/col' import { Row } from '../layout/row' @@ -80,12 +85,11 @@ function CreateChallengeForm(props: { const [isCreating, setIsCreating] = useState(false) const [finishedCreating, setFinishedCreating] = useState(false) const [error, setError] = useState('') + const [editingAcceptorAmount, setEditingAcceptorAmount] = useState(false) const defaultExpire = 'week' const defaultMessage = `${user.name} is challenging you to a bet! Do you think ${contract.question}` - const prob = Math.round(getOutcomeProbability(contract, 'YES') * 100) / 100 // round to whole percentage - const [challengeInfo, setChallengeInfo] = useState({ expiresTime: dayjs().add(2, defaultExpire).valueOf(), outcome: 'YES', @@ -97,10 +101,6 @@ function CreateChallengeForm(props: { setError('') }, [challengeInfo]) - const p = challengeInfo.outcome === 'YES' ? prob : 1 - prob - - const friendCost = ((1 - p) / p) * challengeInfo.amount - return ( <> {!finishedCreating && ( @@ -117,7 +117,6 @@ function CreateChallengeForm(props: { }} > - {/*<Row className="label ">How much?</Row>*/} <div className="mt-2 flex flex-col flex-wrap gap-x-5 gap-y-2"> {/*<div>Question:</div>*/} {/*<div className="mb-4 italic">{contract.question}</div>*/} @@ -136,7 +135,13 @@ function CreateChallengeForm(props: { value={challengeInfo.amount} onChange={(e) => setChallengeInfo((m: challengeInfo) => { - return { ...m, amount: parseInt(e.target.value) } + return { + ...m, + amount: parseInt(e.target.value), + acceptorAmount: editingAcceptorAmount + ? m.acceptorAmount + : parseInt(e.target.value), + } }) } /> @@ -162,11 +167,55 @@ function CreateChallengeForm(props: { </Col> </Row> <Spacer h={2} /> - <div>They will bet:</div> - <div> - <span className="bold">{formatMoney(friendCost)}</span> on{' '} - {challengeInfo.outcome === 'YES' ? <NoLabel /> : <YesLabel />} - </div> + <Row className={'items-center'}>They will bet:</Row> + <Row className={'items-center gap-2'}> + <div className={'ml-1 min-w-[90px]'}> + {editingAcceptorAmount ? ( + <Col> + <div className="relative"> + <span className="absolute mx-3 mt-3.5 text-sm text-gray-400"> + M$ + </span> + <input + className="input input-bordered w-40 pl-10" + type="number" + min={1} + value={challengeInfo.acceptorAmount} + onChange={(e) => + setChallengeInfo((m: challengeInfo) => { + return { + ...m, + acceptorAmount: parseInt(e.target.value), + } + }) + } + /> + </div> + </Col> + ) : ( + <span className="font-bold"> + {formatMoney(challengeInfo.acceptorAmount)} + </span> + )} + </div> + <Row className={'items-center gap-3'}> + on + {challengeInfo.outcome === 'YES' ? <NoLabel /> : <YesLabel />} + {!editingAcceptorAmount && ( + <Button + color={'gray'} + onClick={() => + setEditingAcceptorAmount(!editingAcceptorAmount) + } + className={ + 'flex flex-row gap-2 !bg-transparent py-1 hover:!bg-gray-100' + } + > + Edit + </Button> + )} + </Row> + </Row> </div> <Row className={'justify-end'}> <Button diff --git a/web/lib/firebase/challenges.ts b/web/lib/firebase/challenges.ts index 81b784d6..f3a034cb 100644 --- a/web/lib/firebase/challenges.ts +++ b/web/lib/firebase/challenges.ts @@ -52,21 +52,19 @@ export async function createChallenge(data: { if (creatorAmount <= 0 || isNaN(creatorAmount) || !isFinite(creatorAmount)) return null - const prob = 1 / (acceptorAmount / creatorAmount + 1) - const challenge: Challenge = { slug, creatorId: creator.id, creatorUsername: creator.username, creatorName: creator.name, creatorAvatarUrl: creator.avatarUrl, - creatorAmount: creatorAmount, + creatorAmount, + creatorOutcome: outcome.toString(), + creatorOutcomeProb: creatorAmount / (creatorAmount + acceptorAmount), + acceptorOutcome: outcome === 'YES' ? 'NO' : 'YES', + acceptorAmount, contractSlug: contract.slug, contractId: contract.id, - creatorOutcome: outcome.toString(), - acceptorOutcome: outcome === 'YES' ? 'NO' : 'YES', - creatorOutcomeProb: prob, - acceptorAmount, createdTime: Date.now(), expiresTime, maxUses: 1, diff --git a/web/pages/challenges/[username]/[contractSlug]/[challengeSlug].tsx b/web/pages/challenges/[username]/[contractSlug]/[challengeSlug].tsx index af934cc8..a965d9fc 100644 --- a/web/pages/challenges/[username]/[contractSlug]/[challengeSlug].tsx +++ b/web/pages/challenges/[username]/[contractSlug]/[challengeSlug].tsx @@ -140,7 +140,6 @@ function ClosedChallengeContent(props: { acceptances, creatorAmount, creatorOutcome, - creatorOutcomeProb, acceptorOutcome, acceptorAmount, } = challenge @@ -156,7 +155,6 @@ function ClosedChallengeContent(props: { }, [acceptances]) const creatorWon = resolution === creatorOutcome - const amountWon = creatorWon ? acceptorAmount : creatorAmount const href = `https://${DOMAIN}${contractPath(contract)}`