diff --git a/common/calculate.ts b/common/calculate.ts index 2e69690e..fbbfd66f 100644 --- a/common/calculate.ts +++ b/common/calculate.ts @@ -104,7 +104,7 @@ export function calculateShareValue(contract: Contract, bet: Bet) { } export function calculateSaleAmount(contract: Contract, bet: Bet) { - return (1 - 2 * FEES) * calculateShareValue(contract, bet) + return (1 - FEES) * calculateShareValue(contract, bet) } export function calculatePayout( @@ -145,7 +145,7 @@ export function calculateStandardPayout( totalShares[outcome] - phantomShares[outcome] - totalBets[outcome] const winningsPool = truePool - totalBets[outcome] - return amount + (1 - 2 * FEES) * ((shares - amount) / total) * winningsPool + return amount + (1 - FEES) * ((shares - amount) / total) * winningsPool } export function calculatePayoutAfterCorrectBet(contract: Contract, bet: Bet) { @@ -204,7 +204,7 @@ function calculateMktPayout(contract: Contract, bet: Bet) { return ( betP * bet.amount + - (1 - 2 * FEES) * + (1 - FEES) * ((betP * (bet.shares - bet.amount)) / weightedShareTotal) * winningsPool ) diff --git a/common/fees.ts b/common/fees.ts index 718cdbcb..767107ed 100644 --- a/common/fees.ts +++ b/common/fees.ts @@ -1,4 +1,4 @@ -export const PLATFORM_FEE = 0.01 // == 1% -export const CREATOR_FEE = 0.01 +export const PLATFORM_FEE = 0.01 +export const CREATOR_FEE = 0.09 export const FEES = PLATFORM_FEE + CREATOR_FEE diff --git a/common/payouts.ts b/common/payouts.ts index c4010ba2..77630502 100644 --- a/common/payouts.ts +++ b/common/payouts.ts @@ -38,12 +38,12 @@ export const getStandardPayouts = ( userId: bet.userId, payout: bet.amount + - (1 - 2 * FEES) * + (1 - FEES) * ((bet.shares - bet.amount) / shareDifferenceSum) * winningsPool, })) - const creatorPayout = 2 * CREATOR_FEE * winningsPool + const creatorPayout = CREATOR_FEE * winningsPool console.log( 'resolved', @@ -98,7 +98,7 @@ export const getMktPayouts = ( userId: bet.userId, payout: p * bet.amount + - (1 - 2 * FEES) * + (1 - FEES) * ((p * (bet.shares - bet.amount)) / weightedShareTotal) * winningsPool, })) @@ -107,12 +107,12 @@ export const getMktPayouts = ( userId: bet.userId, payout: (1 - p) * bet.amount + - (1 - 2 * FEES) * + (1 - FEES) * (((1 - p) * (bet.shares - bet.amount)) / weightedShareTotal) * winningsPool, })) - const creatorPayout = 2 * CREATOR_FEE * winningsPool + const creatorPayout = CREATOR_FEE * winningsPool return [ ...yesPayouts, diff --git a/common/sell-bet.ts b/common/sell-bet.ts index e3080644..eeeed355 100644 --- a/common/sell-bet.ts +++ b/common/sell-bet.ts @@ -36,8 +36,8 @@ export const getSellBetInfo = ( const probBefore = getProbability(contract.totalShares) const probAfter = getProbability(newTotalShares) - const creatorFee = 2 * CREATOR_FEE * adjShareValue - const saleAmount = (1 - 2 * FEES) * adjShareValue + const creatorFee = CREATOR_FEE * adjShareValue + const saleAmount = (1 - FEES) * adjShareValue console.log( 'SELL M$', diff --git a/web/components/contract-feed.tsx b/web/components/contract-feed.tsx index fe1cbaaa..2279e2fb 100644 --- a/web/components/contract-feed.tsx +++ b/web/components/contract-feed.tsx @@ -130,6 +130,11 @@ function FeedBet(props: { activityItem: any }) { className="textarea textarea-bordered w-full" placeholder="Add a comment..." rows={3} + onKeyDown={(e) => { + if (e.key === 'Enter' && e.ctrlKey) { + submitComment() + } + }} /> ) diff --git a/web/components/resolution-panel.tsx b/web/components/resolution-panel.tsx index 1a409f7e..a31072c4 100644 --- a/web/components/resolution-panel.tsx +++ b/web/components/resolution-panel.tsx @@ -11,6 +11,7 @@ import { ConfirmationButton as ConfirmationButton } from './confirmation-button' import { resolveMarket } from '../lib/firebase/api-call' import { ProbabilitySelector } from './probability-selector' import { getProbability } from '../../common/calculate' +import { CREATOR_FEE } from '../../common/fees' export function ResolutionPanel(props: { creator: User @@ -79,16 +80,20 @@ export function ResolutionPanel(props: {
{outcome === 'YES' ? ( <> - Winnings will be paid out to YES bettors. You earn 1% of the pool. + Winnings will be paid out to YES bettors. You earn{' '} + {CREATOR_FEE * 100}%. ) : outcome === 'NO' ? ( - <>Winnings will be paid out to NO bettors. You earn 1% of the pool. + <> + Winnings will be paid out to NO bettors. You earn{' '} + {CREATOR_FEE * 100}%. + ) : outcome === 'CANCEL' ? ( <>The pool will be returned to traders with no fees. ) : outcome === 'MKT' ? ( <> - Traders will be paid out at the probability you specify. You earn 1% - of the pool. + Traders will be paid out at the probability you specify. You earn{' '} + {CREATOR_FEE * 100}%. ) : ( <>Resolving this market will immediately pay out traders. diff --git a/web/components/tags-input.tsx b/web/components/tags-input.tsx index 24b4a20c..1e1678dc 100644 --- a/web/components/tags-input.tsx +++ b/web/components/tags-input.tsx @@ -27,7 +27,7 @@ export function TagsInput(props: { contract: Contract; className?: string }) { return ( - `#${tag}`)} /> + {!noLabel &&
Tags
} {tags.map((tag) => ( - + ))}
) diff --git a/web/pages/about.tsx b/web/pages/about.tsx index a0d7659e..47e796a7 100644 --- a/web/pages/about.tsx +++ b/web/pages/about.tsx @@ -1,7 +1,7 @@ import { cloneElement } from 'react' +import { CREATOR_FEE } from '../../common/fees' import { Page } from '../components/page' import { SEO } from '../components/SEO' -import { useContracts } from '../hooks/use-contracts' import styles from './about.module.css' export default function About() { @@ -132,8 +132,9 @@ function Contents() {

How are markets resolved?

- The creator of the prediction market decides the outcome and earns 1% of - the betting pool for their effort. + The creator of the prediction market decides the outcome and earns{' '} + {CREATOR_FEE * 100}% of the winnings as a commission for creating and + resolving the market.

This simple resolution mechanism has surprising benefits in allowing a diff --git a/web/pages/create.tsx b/web/pages/create.tsx index 0dddd6f1..bc747fc7 100644 --- a/web/pages/create.tsx +++ b/web/pages/create.tsx @@ -177,7 +177,7 @@ export function NewContract(props: { question: string; tag?: string }) { Market ante []) : [] + const betsPromise = Promise.all( + contracts.map((contract) => listAllBets(contract.id)) + ) + const [contractComments, contractRecentBets] = await Promise.all([ Promise.all( contracts.map((contract) => listAllComments(contract.id).catch((_) => [])) @@ -79,17 +83,16 @@ export async function getStaticProps(props: { params: { slugs: string[] } }) { contractComments[contracts.findIndex((c) => c.id === contract.id)] ) - const curator = await curatorPromise - - const bets = await Promise.all( - contracts.map((contract) => listAllBets(contract.id)) - ) + const bets = await betsPromise const creatorScores = scoreCreators(contracts, bets) - const topCreators = await toTopUsers(creatorScores) - const traderScores = scoreTraders(contracts, bets) - const topTraders = await toTopUsers(traderScores) + const [topCreators, topTraders] = await Promise.all([ + toTopUsers(creatorScores), + toTopUsers(traderScores), + ]) + + const curator = await curatorPromise return { props: { @@ -338,7 +341,7 @@ function FoldOverview(props: { fold: Fold; curator: User }) { Includes markets matching any of these tags:

- `#${tag}`)} noLabel /> + ) diff --git a/web/pages/folds.tsx b/web/pages/folds.tsx index cc3d1dea..f4583bfc 100644 --- a/web/pages/folds.tsx +++ b/web/pages/folds.tsx @@ -8,6 +8,7 @@ import { Col } from '../components/layout/col' import { Row } from '../components/layout/row' import { Page } from '../components/page' import { SiteLink } from '../components/site-link' +import { TagsList } from '../components/tags-list' import { Title } from '../components/title' import { UserLink } from '../components/user-page' import { useFolds } from '../hooks/use-fold' @@ -63,7 +64,7 @@ export default function Folds(props: { return ( - + @@ -76,7 +77,7 @@ export default function Folds(props: { </div> </Col> - <Col className="gap-2"> + <Col className="gap-4"> {folds.map((fold) => ( <FoldCard key={fold.id} @@ -93,16 +94,17 @@ export default function Folds(props: { function FoldCard(props: { fold: Fold; curator: User | undefined }) { const { fold, curator } = props + const tags = fold.tags.slice(1) return ( <Col key={fold.id} - className="bg-white hover:bg-gray-100 p-4 rounded-xl gap-1 shadow-md relative" + className="bg-white hover:bg-gray-100 p-8 rounded-xl gap-1 shadow-md relative" > <Link href={foldPath(fold)}> <a className="absolute left-0 right-0 top-0 bottom-0" /> </Link> <Row className="justify-between items-center gap-2"> - <SiteLink href={foldPath(fold)}>{fold.name}</SiteLink> + <span className="text-xl">{fold.name}</span> <FollowFoldButton className="z-10 mb-1" fold={fold} /> </Row> <Row className="items-center gap-2 text-gray-500 text-sm"> @@ -118,6 +120,9 @@ function FoldCard(props: { fold: Fold; curator: User | undefined }) { </Row> </Row> <div className="text-gray-500 text-sm">{fold.about}</div> + {tags.length > 0 && ( + <TagsList className="mt-4" tags={tags} noLink noLabel /> + )} </Col> ) } diff --git a/web/pages/home.tsx b/web/pages/home.tsx index 187706d2..96ee0a99 100644 --- a/web/pages/home.tsx +++ b/web/pages/home.tsx @@ -17,6 +17,7 @@ import { Fold } from '../../common/fold' import { filterDefined } from '../../common/util/array' import { useUserBets } from '../hooks/use-user-bets' import { LoadingIndicator } from '../components/loading-indicator' +import { TagsList } from '../components/tags-list' export async function getStaticProps() { const [contracts, folds] = await Promise.all([ @@ -131,6 +132,18 @@ const Home = (props: { contracts: Contract[]; folds: Fold[] }) => { <Col className="max-w-3xl w-full"> <FeedCreate user={user ?? undefined} /> <Spacer h={4} /> + <TagsList + className="mx-2" + tags={[ + '#politics', + '#crypto', + '#covid', + '#sports', + '#meta', + '#science', + ]} + /> + <Spacer h={4} /> {activeContracts ? ( <ActivityFeed contracts={activeContracts}