Merge branch 'main' into custom-feed
This commit is contained in:
commit
e5f553fa1a
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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$',
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<button
|
||||
className="btn btn-outline btn-sm mt-1"
|
||||
|
@ -195,6 +200,11 @@ export function ContractDescription(props: {
|
|||
description.length
|
||||
)
|
||||
}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter' && e.ctrlKey) {
|
||||
saveDescription(e)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Row className="gap-2">
|
||||
<button
|
||||
|
@ -540,7 +550,8 @@ function FeedBetGroup(props: { activityItem: any }) {
|
|||
|
||||
const [yesBets, noBets] = _.partition(bets, (bet) => bet.outcome === 'YES')
|
||||
|
||||
const createdTime = bets[0].createdTime
|
||||
// Use the time of the last bet for the entire group
|
||||
const createdTime = bets[bets.length - 1].createdTime
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
@ -262,7 +262,7 @@ export function SearchableGrid(props: {
|
|||
onChange={(e) => setSort(e.target.value as Sort)}
|
||||
>
|
||||
<option value="most-traded">Most traded</option>
|
||||
<option value="24-hour-vol">24 hour volume</option>
|
||||
<option value="24-hour-vol">24h volume</option>
|
||||
<option value="close-date">Closing soon</option>
|
||||
<option value="newest">Newest</option>
|
||||
|
||||
|
|
|
@ -105,7 +105,7 @@ export function EditFoldButton(props: { fold: Fold; className?: string }) {
|
|||
</div>
|
||||
|
||||
<Spacer h={4} />
|
||||
<TagsList tags={tags.map((tag) => `#${tag}`)} noLink noLabel />
|
||||
<TagsList tags={tags} noLink noLabel />
|
||||
<Spacer h={4} />
|
||||
|
||||
<div className="modal-action">
|
||||
|
|
|
@ -37,10 +37,7 @@ export function FollowFoldButton(props: { fold: Fold; className?: string }) {
|
|||
}
|
||||
|
||||
return (
|
||||
<button
|
||||
className={clsx('btn btn-secondary bg-indigo-500 btn-sm', className)}
|
||||
onClick={onFollow}
|
||||
>
|
||||
<button className={clsx('btn btn-sm', className)} onClick={onFollow}>
|
||||
Follow
|
||||
</button>
|
||||
)
|
||||
|
|
|
@ -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: {
|
|||
<div>
|
||||
{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.</>
|
||||
|
|
|
@ -27,7 +27,7 @@ export function TagsInput(props: { contract: Contract; className?: string }) {
|
|||
|
||||
return (
|
||||
<Col className={clsx('gap-4', className)}>
|
||||
<TagsList tags={newTags.map((tag) => `#${tag}`)} />
|
||||
<TagsList tags={newTags} />
|
||||
|
||||
<Row className="items-center gap-4">
|
||||
<input
|
||||
|
|
|
@ -3,7 +3,7 @@ import { Row } from './layout/row'
|
|||
import { SiteLink } from './site-link'
|
||||
import { Fold } from '../../common/fold'
|
||||
|
||||
export function Hashtag(props: { tag: string; noLink?: boolean }) {
|
||||
function Hashtag(props: { tag: string; noLink?: boolean }) {
|
||||
const { tag, noLink } = props
|
||||
const body = (
|
||||
<div
|
||||
|
@ -35,7 +35,11 @@ export function TagsList(props: {
|
|||
<Row className={clsx('items-center flex-wrap gap-2', className)}>
|
||||
{!noLabel && <div className="text-gray-500 mr-1">Tags</div>}
|
||||
{tags.map((tag) => (
|
||||
<Hashtag key={tag} tag={tag} noLink={noLink} />
|
||||
<Hashtag
|
||||
key={tag}
|
||||
tag={tag.startsWith('#') ? tag : `#${tag}`}
|
||||
noLink={noLink}
|
||||
/>
|
||||
))}
|
||||
</Row>
|
||||
)
|
||||
|
|
|
@ -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() {
|
|||
</p>
|
||||
<h3 id="how-are-markets-resolved-">How are markets resolved?</h3>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
<p>
|
||||
This simple resolution mechanism has surprising benefits in allowing a
|
||||
|
|
|
@ -177,7 +177,7 @@ export function NewContract(props: { question: string; tag?: string }) {
|
|||
<span>Market ante</span>
|
||||
<InfoTooltip
|
||||
text={`Subsidize your market to encourage trading. Ante bets are set to match your initial probability.
|
||||
You earn ${CREATOR_FEE * 100}% of trading volume.`}
|
||||
You earn ${CREATOR_FEE * 100}% of the winnings.`}
|
||||
/>
|
||||
</label>
|
||||
<AmountInput
|
||||
|
|
|
@ -48,6 +48,10 @@ export async function getStaticProps(props: { params: { slugs: string[] } }) {
|
|||
|
||||
const contracts = fold ? await getFoldContracts(fold).catch((_) => []) : []
|
||||
|
||||
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:
|
||||
</div>
|
||||
|
||||
<TagsList tags={tags.map((tag) => `#${tag}`)} noLabel />
|
||||
<TagsList tags={tags} noLabel />
|
||||
</Col>
|
||||
</Col>
|
||||
)
|
||||
|
|
|
@ -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 (
|
||||
<Page>
|
||||
<Col className="items-center">
|
||||
<Col className="max-w-lg w-full">
|
||||
<Col className="max-w-xl w-full">
|
||||
<Col className="px-4 sm:px-0">
|
||||
<Row className="justify-between items-center">
|
||||
<Title text="Explore communities" />
|
||||
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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}
|
||||
|
|
Loading…
Reference in New Issue
Block a user