Merge branch 'main' into free-response
This commit is contained in:
commit
26717295b8
|
@ -3,7 +3,7 @@ import { getProbability } from './calculate'
|
||||||
import { Contract } from './contract'
|
import { Contract } from './contract'
|
||||||
import { User } from './user'
|
import { User } from './user'
|
||||||
|
|
||||||
export const PHANTOM_ANTE = 100
|
export const PHANTOM_ANTE = 0.001
|
||||||
export const MINIMUM_ANTE = 10
|
export const MINIMUM_ANTE = 10
|
||||||
|
|
||||||
export const calcStartPool = (initialProbInt: number, ante = 0) => {
|
export const calcStartPool = (initialProbInt: number, ante = 0) => {
|
||||||
|
|
|
@ -116,7 +116,9 @@ export function calculateShareValue(contract: Contract, bet: Bet) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculateSaleAmount(contract: Contract, bet: Bet) {
|
export function calculateSaleAmount(contract: Contract, bet: Bet) {
|
||||||
return (1 - FEES) * calculateShareValue(contract, bet)
|
const { amount } = bet
|
||||||
|
const winnings = calculateShareValue(contract, bet)
|
||||||
|
return deductFees(amount, winnings)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculatePayout(
|
export function calculatePayout(
|
||||||
|
@ -145,19 +147,16 @@ export function calculateStandardPayout(
|
||||||
const { amount, outcome: betOutcome, shares } = bet
|
const { amount, outcome: betOutcome, shares } = bet
|
||||||
if (betOutcome !== outcome) return 0
|
if (betOutcome !== outcome) return 0
|
||||||
|
|
||||||
const { totalShares, totalBets, phantomShares } = contract
|
const { totalShares, phantomShares } = contract
|
||||||
if (!totalShares[outcome]) return 0
|
if (!totalShares[outcome]) return 0
|
||||||
|
|
||||||
const truePool = _.sum(Object.values(totalShares))
|
const pool = _.sum(Object.values(totalShares))
|
||||||
|
|
||||||
if (totalBets[outcome] >= truePool)
|
const total = totalShares[outcome] - phantomShares[outcome]
|
||||||
return (amount / totalBets[outcome]) * truePool
|
|
||||||
|
|
||||||
const total =
|
const winnings = (shares / total) * pool
|
||||||
totalShares[outcome] - phantomShares[outcome] - totalBets[outcome]
|
// profit can be negative if using phantom shares
|
||||||
const winningsPool = truePool - totalBets[outcome]
|
return amount + (1 - FEES) * Math.max(0, winnings - amount)
|
||||||
|
|
||||||
return amount + (1 - FEES) * ((shares - amount) / total) * winningsPool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculatePayoutAfterCorrectBet(contract: Contract, bet: Bet) {
|
export function calculatePayoutAfterCorrectBet(contract: Contract, bet: Bet) {
|
||||||
|
@ -191,35 +190,18 @@ function calculateMktPayout(contract: Contract, bet: Bet) {
|
||||||
? contract.resolutionProbability
|
? contract.resolutionProbability
|
||||||
: getProbability(contract.totalShares)
|
: getProbability(contract.totalShares)
|
||||||
|
|
||||||
const weightedTotal =
|
const pool = contract.pool.YES + contract.pool.NO
|
||||||
p * contract.totalBets.YES + (1 - p) * contract.totalBets.NO
|
|
||||||
|
|
||||||
const truePool = contract.pool.YES + contract.pool.NO
|
|
||||||
|
|
||||||
const betP = bet.outcome === 'YES' ? p : 1 - p
|
|
||||||
|
|
||||||
if (weightedTotal >= truePool) {
|
|
||||||
return ((betP * bet.amount) / weightedTotal) * truePool
|
|
||||||
}
|
|
||||||
|
|
||||||
const winningsPool = truePool - weightedTotal
|
|
||||||
|
|
||||||
const weightedShareTotal =
|
const weightedShareTotal =
|
||||||
p *
|
p * (contract.totalShares.YES - contract.phantomShares.YES) +
|
||||||
(contract.totalShares.YES -
|
(1 - p) * (contract.totalShares.NO - contract.phantomShares.NO)
|
||||||
contract.phantomShares.YES -
|
|
||||||
contract.totalBets.YES) +
|
|
||||||
(1 - p) *
|
|
||||||
(contract.totalShares.NO -
|
|
||||||
contract.phantomShares.NO -
|
|
||||||
contract.totalBets.NO)
|
|
||||||
|
|
||||||
return (
|
const { outcome, amount, shares } = bet
|
||||||
betP * bet.amount +
|
|
||||||
(1 - FEES) *
|
const betP = outcome === 'YES' ? p : 1 - p
|
||||||
((betP * (bet.shares - bet.amount)) / weightedShareTotal) *
|
const winnings = ((betP * shares) / weightedShareTotal) * pool
|
||||||
winningsPool
|
|
||||||
)
|
return deductFees(amount, winnings)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolvedPayout(contract: Contract, bet: Bet) {
|
export function resolvedPayout(contract: Contract, bet: Bet) {
|
||||||
|
@ -236,3 +218,9 @@ export function currentValue(contract: Contract, bet: Bet) {
|
||||||
|
|
||||||
return prob * yesPayout + (1 - prob) * noPayout
|
return prob * yesPayout + (1 - prob) * noPayout
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const deductFees = (betAmount: number, winnings: number) => {
|
||||||
|
return winnings > betAmount
|
||||||
|
? betAmount + (1 - FEES) * (winnings - betAmount)
|
||||||
|
: winnings
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
import * as _ from 'lodash'
|
||||||
|
|
||||||
import { Bet } from './bet'
|
import { Bet } from './bet'
|
||||||
import { getProbability } from './calculate'
|
import { deductFees, getProbability } from './calculate'
|
||||||
import { Contract, outcome } from './contract'
|
import { Contract, outcome } from './contract'
|
||||||
import { CREATOR_FEE, FEES } from './fees'
|
import { CREATOR_FEE, FEES } from './fees'
|
||||||
|
|
||||||
|
@ -8,7 +10,7 @@ export const getCancelPayouts = (contract: Contract, bets: Bet[]) => {
|
||||||
const poolTotal = pool.YES + pool.NO
|
const poolTotal = pool.YES + pool.NO
|
||||||
console.log('resolved N/A, pool M$', poolTotal)
|
console.log('resolved N/A, pool M$', poolTotal)
|
||||||
|
|
||||||
const betSum = sumBy(bets, (b) => b.amount)
|
const betSum = _.sumBy(bets, (b) => b.amount)
|
||||||
|
|
||||||
return bets.map((bet) => ({
|
return bets.map((bet) => ({
|
||||||
userId: bet.userId,
|
userId: bet.userId,
|
||||||
|
@ -21,42 +23,38 @@ export const getStandardPayouts = (
|
||||||
contract: Contract,
|
contract: Contract,
|
||||||
bets: Bet[]
|
bets: Bet[]
|
||||||
) => {
|
) => {
|
||||||
const [yesBets, noBets] = partition(bets, (bet) => bet.outcome === 'YES')
|
const [yesBets, noBets] = _.partition(bets, (bet) => bet.outcome === 'YES')
|
||||||
const winningBets = outcome === 'YES' ? yesBets : noBets
|
const winningBets = outcome === 'YES' ? yesBets : noBets
|
||||||
|
|
||||||
const betSum = sumBy(winningBets, (b) => b.amount)
|
const pool = contract.pool.YES + contract.pool.NO
|
||||||
|
const totalShares = _.sumBy(winningBets, (b) => b.shares)
|
||||||
|
|
||||||
const poolTotal = contract.pool.YES + contract.pool.NO
|
const payouts = winningBets.map(({ userId, amount, shares }) => {
|
||||||
|
const winnings = (shares / totalShares) * pool
|
||||||
|
const profit = winnings - amount
|
||||||
|
|
||||||
if (betSum >= poolTotal) return getCancelPayouts(contract, winningBets)
|
// profit can be negative if using phantom shares
|
||||||
|
const payout = amount + (1 - FEES) * Math.max(0, profit)
|
||||||
|
return { userId, profit, payout }
|
||||||
|
})
|
||||||
|
|
||||||
const shareDifferenceSum = sumBy(winningBets, (b) => b.shares - b.amount)
|
const profits = _.sumBy(payouts, (po) => Math.max(0, po.profit))
|
||||||
|
const creatorPayout = CREATOR_FEE * profits
|
||||||
const winningsPool = poolTotal - betSum
|
|
||||||
|
|
||||||
const winnerPayouts = winningBets.map((bet) => ({
|
|
||||||
userId: bet.userId,
|
|
||||||
payout:
|
|
||||||
bet.amount +
|
|
||||||
(1 - FEES) *
|
|
||||||
((bet.shares - bet.amount) / shareDifferenceSum) *
|
|
||||||
winningsPool,
|
|
||||||
}))
|
|
||||||
|
|
||||||
const creatorPayout = CREATOR_FEE * winningsPool
|
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
'resolved',
|
'resolved',
|
||||||
outcome,
|
outcome,
|
||||||
'pool: M$',
|
'pool',
|
||||||
poolTotal,
|
pool,
|
||||||
'creator fee: M$',
|
'profits',
|
||||||
|
profits,
|
||||||
|
'creator fee',
|
||||||
creatorPayout
|
creatorPayout
|
||||||
)
|
)
|
||||||
|
|
||||||
return winnerPayouts.concat([
|
return payouts
|
||||||
{ userId: contract.creatorId, payout: creatorPayout },
|
.map(({ userId, payout }) => ({ userId, payout }))
|
||||||
]) // add creator fee
|
.concat([{ userId: contract.creatorId, payout: creatorPayout }]) // add creator fee
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getMktPayouts = (
|
export const getMktPayouts = (
|
||||||
|
@ -69,56 +67,37 @@ export const getMktPayouts = (
|
||||||
? getProbability(contract.totalShares)
|
? getProbability(contract.totalShares)
|
||||||
: resolutionProbability
|
: resolutionProbability
|
||||||
|
|
||||||
const poolTotal = contract.pool.YES + contract.pool.NO
|
const weightedShareTotal = _.sumBy(bets, (b) =>
|
||||||
console.log('Resolved MKT at p=', p, 'pool: $M', poolTotal)
|
b.outcome === 'YES' ? p * b.shares : (1 - p) * b.shares
|
||||||
|
)
|
||||||
|
|
||||||
const [yesBets, noBets] = partition(bets, (bet) => bet.outcome === 'YES')
|
const pool = contract.pool.YES + contract.pool.NO
|
||||||
|
|
||||||
const weightedBetTotal =
|
const payouts = bets.map(({ userId, outcome, amount, shares }) => {
|
||||||
p * sumBy(yesBets, (b) => b.amount) +
|
const betP = outcome === 'YES' ? p : 1 - p
|
||||||
(1 - p) * sumBy(noBets, (b) => b.amount)
|
const winnings = ((betP * shares) / weightedShareTotal) * pool
|
||||||
|
const profit = winnings - amount
|
||||||
|
const payout = deductFees(amount, winnings)
|
||||||
|
return { userId, profit, payout }
|
||||||
|
})
|
||||||
|
|
||||||
if (weightedBetTotal >= poolTotal) {
|
const profits = _.sumBy(payouts, (po) => Math.max(0, po.profit))
|
||||||
return bets.map((bet) => ({
|
const creatorPayout = CREATOR_FEE * profits
|
||||||
userId: bet.userId,
|
|
||||||
payout:
|
|
||||||
(((bet.outcome === 'YES' ? p : 1 - p) * bet.amount) /
|
|
||||||
weightedBetTotal) *
|
|
||||||
poolTotal,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
const winningsPool = poolTotal - weightedBetTotal
|
console.log(
|
||||||
|
'resolved MKT',
|
||||||
|
p,
|
||||||
|
'pool',
|
||||||
|
pool,
|
||||||
|
'profits',
|
||||||
|
profits,
|
||||||
|
'creator fee',
|
||||||
|
creatorPayout
|
||||||
|
)
|
||||||
|
|
||||||
const weightedShareTotal =
|
return payouts
|
||||||
p * sumBy(yesBets, (b) => b.shares - b.amount) +
|
.map(({ userId, payout }) => ({ userId, payout }))
|
||||||
(1 - p) * sumBy(noBets, (b) => b.shares - b.amount)
|
.concat([{ userId: contract.creatorId, payout: creatorPayout }]) // add creator fee
|
||||||
|
|
||||||
const yesPayouts = yesBets.map((bet) => ({
|
|
||||||
userId: bet.userId,
|
|
||||||
payout:
|
|
||||||
p * bet.amount +
|
|
||||||
(1 - FEES) *
|
|
||||||
((p * (bet.shares - bet.amount)) / weightedShareTotal) *
|
|
||||||
winningsPool,
|
|
||||||
}))
|
|
||||||
|
|
||||||
const noPayouts = noBets.map((bet) => ({
|
|
||||||
userId: bet.userId,
|
|
||||||
payout:
|
|
||||||
(1 - p) * bet.amount +
|
|
||||||
(1 - FEES) *
|
|
||||||
(((1 - p) * (bet.shares - bet.amount)) / weightedShareTotal) *
|
|
||||||
winningsPool,
|
|
||||||
}))
|
|
||||||
|
|
||||||
const creatorPayout = CREATOR_FEE * winningsPool
|
|
||||||
|
|
||||||
return [
|
|
||||||
...yesPayouts,
|
|
||||||
...noPayouts,
|
|
||||||
{ userId: contract.creatorId, payout: creatorPayout },
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getPayouts = (
|
export const getPayouts = (
|
||||||
|
@ -137,20 +116,3 @@ export const getPayouts = (
|
||||||
return getCancelPayouts(contract, bets)
|
return getCancelPayouts(contract, bets)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const partition = <T>(array: T[], f: (t: T) => boolean) => {
|
|
||||||
const yes = []
|
|
||||||
const no = []
|
|
||||||
|
|
||||||
for (let t of array) {
|
|
||||||
if (f(t)) yes.push(t)
|
|
||||||
else no.push(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
return [yes, no] as [T[], T[]]
|
|
||||||
}
|
|
||||||
|
|
||||||
const sumBy = <T>(array: T[], f: (t: T) => number) => {
|
|
||||||
const values = array.map(f)
|
|
||||||
return values.reduce((prev, cur) => prev + cur, 0)
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Bet } from './bet'
|
import { Bet } from './bet'
|
||||||
import { calculateShareValue, getProbability } from './calculate'
|
import { calculateShareValue, deductFees, getProbability } from './calculate'
|
||||||
import { Contract } from './contract'
|
import { Contract } from './contract'
|
||||||
import { CREATOR_FEE, FEES } from './fees'
|
import { CREATOR_FEE, FEES } from './fees'
|
||||||
import { User } from './user'
|
import { User } from './user'
|
||||||
|
@ -36,8 +36,9 @@ export const getSellBetInfo = (
|
||||||
const probBefore = getProbability(contract.totalShares)
|
const probBefore = getProbability(contract.totalShares)
|
||||||
const probAfter = getProbability(newTotalShares)
|
const probAfter = getProbability(newTotalShares)
|
||||||
|
|
||||||
const creatorFee = CREATOR_FEE * adjShareValue
|
const profit = adjShareValue - amount
|
||||||
const saleAmount = (1 - FEES) * adjShareValue
|
const creatorFee = CREATOR_FEE * Math.max(0, profit)
|
||||||
|
const saleAmount = deductFees(amount, adjShareValue)
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
'SELL M$',
|
'SELL M$',
|
||||||
|
|
|
@ -30,7 +30,9 @@ export const resolveMarket = functions
|
||||||
|
|
||||||
if (
|
if (
|
||||||
probabilityInt !== undefined &&
|
probabilityInt !== undefined &&
|
||||||
(probabilityInt < 1 || probabilityInt > 99 || !isFinite(probabilityInt))
|
(probabilityInt < 0 ||
|
||||||
|
probabilityInt > 100 ||
|
||||||
|
!isFinite(probabilityInt))
|
||||||
)
|
)
|
||||||
return { status: 'error', message: 'Invalid probability' }
|
return { status: 'error', message: 'Invalid probability' }
|
||||||
|
|
||||||
|
|
|
@ -23,13 +23,15 @@ import {
|
||||||
import { Row } from './layout/row'
|
import { Row } from './layout/row'
|
||||||
import { UserLink } from './user-page'
|
import { UserLink } from './user-page'
|
||||||
import {
|
import {
|
||||||
|
calculateCancelPayout,
|
||||||
calculatePayout,
|
calculatePayout,
|
||||||
calculateSaleAmount,
|
calculateSaleAmount,
|
||||||
|
getProbability,
|
||||||
resolvedPayout,
|
resolvedPayout,
|
||||||
} from '../../common/calculate'
|
} from '../../common/calculate'
|
||||||
import { sellBet } from '../lib/firebase/api-call'
|
import { sellBet } from '../lib/firebase/api-call'
|
||||||
import { ConfirmationButton } from './confirmation-button'
|
import { ConfirmationButton } from './confirmation-button'
|
||||||
import { OutcomeLabel, YesLabel, NoLabel, MarketLabel } from './outcome-label'
|
import { OutcomeLabel, YesLabel, NoLabel } from './outcome-label'
|
||||||
|
|
||||||
type BetSort = 'newest' | 'profit'
|
type BetSort = 'newest' | 'profit'
|
||||||
|
|
||||||
|
@ -119,16 +121,32 @@ export function BetsList(props: { user: User }) {
|
||||||
(c) => contractsCurrentValue[c.id]
|
(c) => contractsCurrentValue[c.id]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const totalPortfolio = currentBetsValue + user.balance
|
||||||
|
|
||||||
|
const pnl = totalPortfolio - user.totalDeposits
|
||||||
|
const totalReturn =
|
||||||
|
(pnl > 0 ? '+' : '') + ((pnl / user.totalDeposits) * 100).toFixed() + '%'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Col className="mt-6 gap-6">
|
<Col className="mt-6 gap-6">
|
||||||
<Col className="mx-4 gap-4 sm:flex-row sm:justify-between md:mx-0">
|
<Col className="mx-4 gap-4 sm:flex-row sm:justify-between md:mx-0">
|
||||||
<Row className="gap-8">
|
<Row className="gap-8">
|
||||||
|
<Col>
|
||||||
|
<div className="text-sm text-gray-500">Total portfolio</div>
|
||||||
|
<div>{formatMoney(totalPortfolio)}</div>
|
||||||
|
</Col>
|
||||||
|
<Col>
|
||||||
|
<div className="text-sm text-gray-500">Total profits & losses</div>
|
||||||
|
<div>
|
||||||
|
{formatMoney(pnl)} ({totalReturn})
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
<Col>
|
<Col>
|
||||||
<div className="text-sm text-gray-500">Currently invested</div>
|
<div className="text-sm text-gray-500">Currently invested</div>
|
||||||
<div>{formatMoney(currentInvestment)}</div>
|
<div>{formatMoney(currentInvestment)}</div>
|
||||||
</Col>
|
</Col>
|
||||||
<Col>
|
<Col>
|
||||||
<div className="text-sm text-gray-500">Current value</div>
|
<div className="text-sm text-gray-500">Current market value</div>
|
||||||
<div>{formatMoney(currentBetsValue)}</div>
|
<div>{formatMoney(currentBetsValue)}</div>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
@ -231,6 +249,7 @@ export function MyBetsSummary(props: {
|
||||||
}) {
|
}) {
|
||||||
const { bets, contract, showMKT, className } = props
|
const { bets, contract, showMKT, className } = props
|
||||||
const { resolution } = contract
|
const { resolution } = contract
|
||||||
|
calculateCancelPayout
|
||||||
|
|
||||||
const excludeSales = bets.filter((b) => !b.isSold && !b.sale)
|
const excludeSales = bets.filter((b) => !b.isSold && !b.sale)
|
||||||
const betsTotal = _.sumBy(excludeSales, (bet) => bet.amount)
|
const betsTotal = _.sumBy(excludeSales, (bet) => bet.amount)
|
||||||
|
@ -284,7 +303,10 @@ export function MyBetsSummary(props: {
|
||||||
{showMKT && (
|
{showMKT && (
|
||||||
<Col>
|
<Col>
|
||||||
<div className="whitespace-nowrap text-sm text-gray-500">
|
<div className="whitespace-nowrap text-sm text-gray-500">
|
||||||
Payout if <MarketLabel />
|
Payout at{' '}
|
||||||
|
<span className="text-blue-400">
|
||||||
|
{formatPercent(getProbability(contract.totalShares))}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="whitespace-nowrap">
|
<div className="whitespace-nowrap">
|
||||||
{formatMoney(marketWinnings)}
|
{formatMoney(marketWinnings)}
|
||||||
|
|
|
@ -25,6 +25,7 @@ export function EditFoldButton(props: { fold: Fold; className?: string }) {
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||||
|
|
||||||
const tags = parseWordsAsTags(toCamelCase(name) + ' ' + otherTags)
|
const tags = parseWordsAsTags(toCamelCase(name) + ' ' + otherTags)
|
||||||
|
const lowercaseTags = tags.map((tag) => tag.toLowerCase())
|
||||||
|
|
||||||
const saveDisabled =
|
const saveDisabled =
|
||||||
name === fold.name &&
|
name === fold.name &&
|
||||||
|
@ -38,6 +39,7 @@ export function EditFoldButton(props: { fold: Fold; className?: string }) {
|
||||||
name,
|
name,
|
||||||
about,
|
about,
|
||||||
tags,
|
tags,
|
||||||
|
lowercaseTags,
|
||||||
})
|
})
|
||||||
|
|
||||||
setIsSubmitting(false)
|
setIsSubmitting(false)
|
||||||
|
|
|
@ -21,10 +21,6 @@ export function CancelLabel() {
|
||||||
return <span className="text-yellow-400">N/A</span>
|
return <span className="text-yellow-400">N/A</span>
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MarketLabel() {
|
|
||||||
return <span className="text-blue-400">MKT</span>
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ProbLabel() {
|
export function ProbLabel() {
|
||||||
return <span className="text-blue-400">PROB</span>
|
return <span className="text-blue-400">PROB</span>
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,9 +64,9 @@ export function ResolutionPanel(props: {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Col className={clsx('rounded-md bg-white px-8 py-6', className)}>
|
<Col className={clsx('rounded-md bg-white px-8 py-6', className)}>
|
||||||
<Title className="mt-0" text="Your market" />
|
<Title className="mt-0" text="Resolve market" />
|
||||||
|
|
||||||
<div className="pt-2 pb-1 text-sm text-gray-500">Resolve outcome</div>
|
<div className="pt-2 pb-1 text-sm text-gray-500">Outcome</div>
|
||||||
|
|
||||||
<YesNoCancelSelector
|
<YesNoCancelSelector
|
||||||
className="mx-auto my-2"
|
className="mx-auto my-2"
|
||||||
|
@ -80,20 +80,30 @@ export function ResolutionPanel(props: {
|
||||||
<div>
|
<div>
|
||||||
{outcome === 'YES' ? (
|
{outcome === 'YES' ? (
|
||||||
<>
|
<>
|
||||||
Winnings will be paid out to YES bettors. You earn{' '}
|
Winnings will be paid out to YES bettors.
|
||||||
{CREATOR_FEE * 100}% of trader profits.
|
<br />
|
||||||
|
<br />
|
||||||
|
You earn {CREATOR_FEE * 100}% of trader profits.
|
||||||
</>
|
</>
|
||||||
) : outcome === 'NO' ? (
|
) : outcome === 'NO' ? (
|
||||||
<>
|
<>
|
||||||
Winnings will be paid out to NO bettors. You earn{' '}
|
Winnings will be paid out to NO bettors.
|
||||||
{CREATOR_FEE * 100}% of trader profits.
|
<br />
|
||||||
|
<br />
|
||||||
|
You earn {CREATOR_FEE * 100}% of trader profits.
|
||||||
</>
|
</>
|
||||||
) : outcome === 'CANCEL' ? (
|
) : outcome === 'CANCEL' ? (
|
||||||
<>The pool will be returned to traders with no fees.</>
|
<>The pool will be returned to traders with no fees.</>
|
||||||
) : outcome === 'MKT' ? (
|
) : outcome === 'MKT' ? (
|
||||||
<>
|
<>
|
||||||
Traders will be paid out at the probability you specify. You earn{' '}
|
Traders will be paid out at the probability you specify:
|
||||||
{CREATOR_FEE * 100}% of trader profits.
|
<Spacer h={2} />
|
||||||
|
<ProbabilitySelector
|
||||||
|
probabilityInt={Math.round(prob)}
|
||||||
|
setProbabilityInt={setProb}
|
||||||
|
/>
|
||||||
|
<Spacer h={2} />
|
||||||
|
You earn {CREATOR_FEE * 100}% of trader profits.
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>Resolving this market will immediately pay out traders.</>
|
<>Resolving this market will immediately pay out traders.</>
|
||||||
|
@ -123,20 +133,7 @@ export function ResolutionPanel(props: {
|
||||||
}}
|
}}
|
||||||
onSubmit={resolve}
|
onSubmit={resolve}
|
||||||
>
|
>
|
||||||
{outcome === 'MKT' ? (
|
<p>Are you sure you want to resolve this market?</p>
|
||||||
<>
|
|
||||||
<p className="mb-4">
|
|
||||||
What probability would you like to resolve the market to?
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<ProbabilitySelector
|
|
||||||
probabilityInt={Math.round(prob)}
|
|
||||||
setProbabilityInt={setProb}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<p>Are you sure you want to resolve this market?</p>
|
|
||||||
)}
|
|
||||||
</ConfirmationButton>
|
</ConfirmationButton>
|
||||||
</Col>
|
</Col>
|
||||||
)
|
)
|
||||||
|
|
|
@ -48,47 +48,44 @@ export function YesNoCancelSelector(props: {
|
||||||
className?: string
|
className?: string
|
||||||
btnClassName?: string
|
btnClassName?: string
|
||||||
}) {
|
}) {
|
||||||
const { selected, onSelect, className } = props
|
const { selected, onSelect } = props
|
||||||
|
|
||||||
const btnClassName = clsx('px-6 flex-1', props.btnClassName)
|
const btnClassName = clsx('px-6 flex-1', props.btnClassName)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Col>
|
<Col className="gap-2">
|
||||||
<Row className={clsx('w-full space-x-3', className)}>
|
{/* Should ideally use a radio group instead of buttons */}
|
||||||
<Button
|
<Button
|
||||||
color={selected === 'YES' ? 'green' : 'gray'}
|
color={selected === 'YES' ? 'green' : 'gray'}
|
||||||
onClick={() => onSelect('YES')}
|
onClick={() => onSelect('YES')}
|
||||||
className={btnClassName}
|
className={btnClassName}
|
||||||
>
|
>
|
||||||
YES
|
YES
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
color={selected === 'NO' ? 'red' : 'gray'}
|
color={selected === 'NO' ? 'red' : 'gray'}
|
||||||
onClick={() => onSelect('NO')}
|
onClick={() => onSelect('NO')}
|
||||||
className={btnClassName}
|
className={btnClassName}
|
||||||
>
|
>
|
||||||
NO
|
NO
|
||||||
</Button>
|
</Button>
|
||||||
</Row>
|
|
||||||
|
|
||||||
<Row className={clsx('w-full space-x-3', className)}>
|
<Button
|
||||||
<Button
|
color={selected === 'MKT' ? 'blue' : 'gray'}
|
||||||
color={selected === 'MKT' ? 'blue' : 'gray'}
|
onClick={() => onSelect('MKT')}
|
||||||
onClick={() => onSelect('MKT')}
|
className={clsx(btnClassName, 'btn-sm')}
|
||||||
className={clsx(btnClassName, 'btn-sm')}
|
>
|
||||||
>
|
PROB
|
||||||
PROB
|
</Button>
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
color={selected === 'CANCEL' ? 'yellow' : 'gray'}
|
color={selected === 'CANCEL' ? 'yellow' : 'gray'}
|
||||||
onClick={() => onSelect('CANCEL')}
|
onClick={() => onSelect('CANCEL')}
|
||||||
className={clsx(btnClassName, 'btn-sm')}
|
className={clsx(btnClassName, 'btn-sm')}
|
||||||
>
|
>
|
||||||
N/A
|
N/A
|
||||||
</Button>
|
</Button>
|
||||||
</Row>
|
|
||||||
</Col>
|
</Col>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
import { Page } from '../components/page'
|
import { Page } from '../components/page'
|
||||||
import { Grid } from 'gridjs-react'
|
import { Grid, _ as r } from 'gridjs-react'
|
||||||
import 'gridjs/dist/theme/mermaid.css'
|
import 'gridjs/dist/theme/mermaid.css'
|
||||||
import { html } from 'gridjs'
|
import { html } from 'gridjs'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { usePrivateUsers, useUsers } from '../hooks/use-users'
|
import { usePrivateUsers, useUsers } from '../hooks/use-users'
|
||||||
import { useUser } from '../hooks/use-user'
|
|
||||||
import Custom404 from './404'
|
import Custom404 from './404'
|
||||||
import { useContracts } from '../hooks/use-contracts'
|
import { useContracts } from '../hooks/use-contracts'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import { useAdmin } from '../hooks/use-admin'
|
import { useAdmin } from '../hooks/use-admin'
|
||||||
|
import { contractPath } from '../lib/firebase/contracts'
|
||||||
|
|
||||||
function avatarHtml(avatarUrl: string) {
|
function avatarHtml(avatarUrl: string) {
|
||||||
return `<img
|
return `<img
|
||||||
|
@ -111,6 +111,20 @@ function ContractsTable() {
|
||||||
let contracts = useContracts() ?? []
|
let contracts = useContracts() ?? []
|
||||||
// Sort users by createdTime descending, by default
|
// Sort users by createdTime descending, by default
|
||||||
contracts.sort((a, b) => b.createdTime - a.createdTime)
|
contracts.sort((a, b) => b.createdTime - a.createdTime)
|
||||||
|
// Render a clickable question. See https://gridjs.io/docs/examples/react-cells for docs
|
||||||
|
contracts.map((contract) => {
|
||||||
|
// @ts-ignore
|
||||||
|
contract.questionLink = r(
|
||||||
|
<div className="w-60">
|
||||||
|
<a
|
||||||
|
className="hover:underline hover:decoration-indigo-400 hover:decoration-2"
|
||||||
|
href={contractPath(contract)}
|
||||||
|
>
|
||||||
|
{contract.question}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid
|
<Grid
|
||||||
|
@ -126,9 +140,8 @@ function ContractsTable() {
|
||||||
href="/${cell}">@${cell}</a>`),
|
href="/${cell}">@${cell}</a>`),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'question',
|
id: 'questionLink',
|
||||||
name: 'Question',
|
name: 'Question',
|
||||||
formatter: (cell) => html(`<div class="w-60">${cell}</div>`),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'volume24Hours',
|
id: 'volume24Hours',
|
||||||
|
|
Loading…
Reference in New Issue
Block a user