Your outcome/cost=> acceptorOutcome/cost

This commit is contained in:
Ian Philips 2022-08-03 08:57:09 -06:00
parent 5cb6f44c9c
commit 4252157290
7 changed files with 58 additions and 94 deletions

View File

@ -19,7 +19,8 @@ export type Challenge = {
creatorOutcome: string
// Different than the creator
yourOutcome: string
acceptorOutcome: string
acceptorAmount: number
// The probability the challenger thinks
creatorOutcomeProb: number
@ -51,9 +52,6 @@ export type Acceptance = {
userName: string
userAvatarUrl: string
// The amount acceptor put up
amount: number
// The ID of the successful bet that tracks the money moved
betId: string

View File

@ -50,13 +50,15 @@ export const acceptchallenge = newEndpoint({}, async (req, auth) => {
if (!creatorSnap.exists) throw new APIError(400, 'User not found.')
const creator = creatorSnap.data() as User
const { creatorAmount, yourOutcome, creatorOutcome, creatorOutcomeProb } =
challenge
const {
creatorAmount,
acceptorOutcome,
creatorOutcome,
creatorOutcomeProb,
acceptorAmount,
} = challenge
const yourCost =
((1 - creatorOutcomeProb) / creatorOutcomeProb) * creatorAmount
if (user.balance < yourCost)
if (user.balance < acceptorAmount)
throw new APIError(400, 'Insufficient balance.')
const contract = anyContract as CPMMBinaryContract
@ -67,21 +69,21 @@ export const acceptchallenge = newEndpoint({}, async (req, auth) => {
'Creating challenge bet for',
user.username,
shares,
yourOutcome,
acceptorOutcome,
'shares',
'at',
formatPercent(creatorOutcomeProb),
'for',
formatMoney(yourCost)
formatMoney(acceptorAmount)
)
const yourNewBet: CandidateBet = removeUndefinedProps({
orderAmount: yourCost,
amount: yourCost,
orderAmount: acceptorAmount,
amount: acceptorAmount,
shares: shares,
isCancelled: false,
contractId: contract.id,
outcome: yourOutcome,
outcome: acceptorOutcome,
probBefore: creatorOutcomeProb,
probAfter: creatorOutcomeProb,
loanAmount: 0,
@ -134,7 +136,7 @@ export const acceptchallenge = newEndpoint({}, async (req, auth) => {
userId: user.id,
betId: yourNewBetDoc.id,
createdTime,
amount: yourCost,
amount: acceptorAmount,
userUsername: user.username,
userName: user.name,
userAvatarUrl: user.avatarUrl,
@ -147,7 +149,7 @@ export const acceptchallenge = newEndpoint({}, async (req, auth) => {
user,
creator,
challenge,
yourCost,
acceptorAmount,
contract
)
log('Done, sent notification.')

View File

@ -17,7 +17,7 @@ function buildCardUrl(props: OgCardProps, challenge?: Challenge) {
acceptances,
creatorOutcomeProb,
creatorOutcome,
yourOutcome,
acceptorOutcome,
} = challenge || {}
const { userName, userAvatarUrl } = acceptances?.[0] ?? {}
const challengeAmount =
@ -35,7 +35,7 @@ function buildCardUrl(props: OgCardProps, challenge?: Challenge) {
const challengeUrlParams = challenge
? `&creatorAmount=${creatorAmount}&creatorOutcome=${creatorOutcome}` +
`&challengerAmount=${challengeAmount}&challengerOutcome=${yourOutcome}` +
`&challengerAmount=${challengeAmount}&challengerOutcome=${acceptorOutcome}` +
`&acceptedName=${userName ?? ''}&acceptedAvatarUrl=${userAvatarUrl ?? ''}`
: ''

View File

@ -21,9 +21,8 @@ export function AcceptChallengeButton(props: {
const [open, setOpen] = useState(false)
const [errorText, setErrorText] = useState('')
const [loading, setLoading] = useState(false)
const { creatorOutcomeProb, creatorAmount } = challenge
const yourCost =
((1 - creatorOutcomeProb) / creatorOutcomeProb) * creatorAmount
const { acceptorAmount } = challenge
useEffect(() => {
setErrorText('')
}, [open])
@ -69,7 +68,9 @@ export function AcceptChallengeButton(props: {
<Col className="w-full items-center justify-start gap-2">
<Row className={'w-full justify-start gap-20'}>
<span className={'min-w-[4rem] font-bold'}>Cost to you:</span>{' '}
<span className={'text-red-500'}>{formatMoney(yourCost)}</span>
<span className={'text-red-500'}>
{formatMoney(acceptorAmount)}
</span>
</Row>
{/*<Row className={'w-full justify-start gap-8'}>*/}
{/* <span className={'min-w-[4rem] font-bold'}>Probability:</span>{' '}*/}

View File

@ -23,7 +23,7 @@ type challengeInfo = {
expiresTime: number | null
message: string
outcome: 'YES' | 'NO' | number
prob: number
acceptorAmount: number
}
export function CreateChallengeButton(props: {
user: User | null | undefined
@ -45,10 +45,10 @@ export function CreateChallengeButton(props: {
onCreate={async (newChallenge) => {
const challenge = await createChallenge({
creator: user,
amount: newChallenge.amount,
creatorAmount: newChallenge.amount,
expiresTime: newChallenge.expiresTime,
message: newChallenge.message,
prob: newChallenge.prob / 100,
acceptorAmount: newChallenge.acceptorAmount,
outcome: newChallenge.outcome,
contract: contract,
})
@ -90,7 +90,7 @@ function CreateChallengeForm(props: {
expiresTime: dayjs().add(2, defaultExpire).valueOf(),
outcome: 'YES',
amount: 100,
prob: prob * 100,
acceptorAmount: 100,
message: defaultMessage,
})
useEffect(() => {
@ -119,7 +119,8 @@ function CreateChallengeForm(props: {
<Title className="!mt-2" text="Challenge a friend to bet " />
{/*<Row className="label ">How much?</Row>*/}
<div className="mt-2 flex flex-col flex-wrap gap-x-5 gap-y-2">
<div className="mb-4 italic">{contract.question}</div>
{/*<div>Question:</div>*/}
{/*<div className="mb-4 italic">{contract.question}</div>*/}
<div>You are betting:</div>
<Row className={'form-control w-full justify-start gap-4'}>
@ -166,52 +167,6 @@ function CreateChallengeForm(props: {
<span className="bold">{formatMoney(friendCost)}</span> on{' '}
{challengeInfo.outcome === 'YES' ? <NoLabel /> : <YesLabel />}
</div>
{/*<div className="form-control flex flex-row gap-8">*/}
{/* /!*<Col className={'mt-9 justify-center'}>at</Col>*!/*/}
{/* <Col>*/}
{/* <label className="label ">At</label>*/}
{/* <div className="relative">*/}
{/* <input*/}
{/* className="input input-bordered max-w-[5rem]"*/}
{/* type="number"*/}
{/* min={1}*/}
{/* max={100}*/}
{/* value={challengeInfo.prob}*/}
{/* onChange={(e) =>*/}
{/* setChallengeInfo((m: challengeInfo) => {*/}
{/* return {*/}
{/* ...m,*/}
{/* prob: parseFloat(e.target.value),*/}
{/* }*/}
{/* })*/}
{/* }*/}
{/* />*/}
{/* <span className="absolute top-3.5 -right-5 text-sm text-gray-600">*/}
{/* %*/}
{/* </span>*/}
{/* </div>*/}
{/* </Col>*/}
{/*</div>*/}
{/*<div className="form-control w-full">*/}
{/* <label className="label">Message</label>*/}
{/* <Textarea*/}
{/* placeholder={defaultMessage}*/}
{/* className="input input-bordered resize-none"*/}
{/* autoFocus*/}
{/* value={*/}
{/* challengeInfo.message !== defaultMessage*/}
{/* ? challengeInfo.message*/}
{/* : ''*/}
{/* }*/}
{/* rows={2}*/}
{/* onChange={(e) =>*/}
{/* setChallengeInfo((m: challengeInfo) => {*/}
{/* return { ...m, message: e.target.value }*/}
{/* })*/}
{/* }*/}
{/* />*/}
{/*</div>*/}
</div>
<Row className={'justify-end'}>
<Button

View File

@ -25,14 +25,21 @@ export function getChallengeUrl(challenge: Challenge) {
export async function createChallenge(data: {
creator: User
outcome: 'YES' | 'NO' | number
prob: number
contract: Contract
amount: number
creatorAmount: number
acceptorAmount: number
expiresTime: number | null
message: string
}) {
const { creator, amount, expiresTime, message, prob, contract, outcome } =
data
const {
creator,
creatorAmount,
expiresTime,
message,
contract,
outcome,
acceptorAmount,
} = data
// At 100 IDs per hour, using this alphabet and 8 chars, there's a 1% chance of collision in 2 years
// See https://zelark.github.io/nano-id-cc/
@ -42,7 +49,10 @@ export async function createChallenge(data: {
)
const slug = nanoid()
if (amount <= 0 || isNaN(amount) || !isFinite(amount)) return null
if (creatorAmount <= 0 || isNaN(creatorAmount) || !isFinite(creatorAmount))
return null
const prob = 1 / (acceptorAmount / creatorAmount + 1)
const challenge: Challenge = {
slug,
@ -50,12 +60,13 @@ export async function createChallenge(data: {
creatorUsername: creator.username,
creatorName: creator.name,
creatorAvatarUrl: creator.avatarUrl,
creatorAmount: amount,
creatorAmount: creatorAmount,
contractSlug: contract.slug,
contractId: contract.id,
creatorOutcome: outcome.toString(),
yourOutcome: outcome === 'YES' ? 'NO' : 'YES',
acceptorOutcome: outcome === 'YES' ? 'NO' : 'YES',
creatorOutcomeProb: prob,
acceptorAmount,
createdTime: Date.now(),
expiresTime,
maxUses: 1,

View File

@ -141,7 +141,8 @@ function ClosedChallengeContent(props: {
creatorAmount,
creatorOutcome,
creatorOutcomeProb,
yourOutcome,
acceptorOutcome,
acceptorAmount,
} = challenge
const user = useUserById(acceptances[0].userId)
@ -155,9 +156,7 @@ function ClosedChallengeContent(props: {
}, [acceptances])
const creatorWon = resolution === creatorOutcome
// const amountWon = creatorWon ? acceptances[0].amount : creatorAmount
const yourCost =
((1 - creatorOutcomeProb) / creatorOutcomeProb) * creatorAmount
const amountWon = creatorWon ? acceptorAmount : creatorAmount
const href = `https://${DOMAIN}${contractPath(contract)}`
@ -211,8 +210,8 @@ function ClosedChallengeContent(props: {
<UserBetColumn
challenger={user?.id === creator.id ? undefined : user}
outcome={yourOutcome}
amount={yourCost}
outcome={acceptorOutcome}
amount={acceptorAmount}
isResolved={!!resolution}
/>
</Col>
@ -240,14 +239,12 @@ function OpenChallengeContent(props: {
creatorAmount,
creatorId,
creatorOutcome,
creatorOutcomeProb,
yourOutcome,
acceptorAmount,
acceptorOutcome,
} = challenge
const yourCost =
((1 - creatorOutcomeProb) / creatorOutcomeProb) * creatorAmount
const href = `https://${DOMAIN}${contractPath(contract)}`
const title = `${creator.name} is challenging you to bet`
return (
@ -276,8 +273,8 @@ function OpenChallengeContent(props: {
<UserBetColumn
challenger={user?.id === creatorId ? undefined : user}
outcome={yourOutcome}
amount={yourCost}
outcome={acceptorOutcome}
amount={acceptorAmount}
/>
</Col>