Revert "Automated market resolution (#404)"

This reverts commit a3663d03e8.
This commit is contained in:
James Grugett 2022-06-14 23:31:20 -05:00
parent 26921451a8
commit cc4b9abd9f
12 changed files with 131 additions and 492 deletions

2
.gitignore vendored
View File

@ -2,4 +2,4 @@
.idea/
.vercel
node_modules
yarn-error.log
yarn-error.log

View File

@ -31,9 +31,9 @@ export type Contract<T extends AnyContractType = AnyContractType> = {
closeTime?: number // When no more trading is allowed
isResolved: boolean
resolutionTime?: number // When the market is resolved
resolutionTime?: number // When the contract creator resolved the market
resolution?: string
autoResolutionTime?: number // When the market will be resolved automatically
closeEmailsSent?: number
volume: number
@ -90,12 +90,10 @@ export type Numeric = {
resolutionValue?: number
}
export type contractField = keyof Contract
export type outcomeType = AnyOutcomeType['outcomeType']
export type resolution = 'YES' | 'NO' | 'MKT' | 'CANCEL'
export const RESOLUTIONS = ['YES', 'NO', 'MKT', 'CANCEL'] as const
export const OUTCOME_TYPES = ['BINARY', 'FREE_RESPONSE', 'NUMERIC'] as const
export const AUTO_RESOLUTION = 'MKT' as resolution
export const MAX_QUESTION_LENGTH = 480
export const MAX_DESCRIPTION_LENGTH = 10000

View File

@ -27,8 +27,7 @@ export function getNewContract(
// used for numeric markets
bucketCount: number,
min: number,
max: number,
autoResolutionTime?: number
max: number
) {
const tags = parseTags(
`${question} ${description} ${extraTags.map((tag) => `#${tag}`).join(' ')}`
@ -60,7 +59,6 @@ export function getNewContract(
isResolved: false,
createdTime: Date.now(),
closeTime,
autoResolutionTime,
volume: 0,
volume24Hours: 0,

View File

@ -56,7 +56,7 @@ service cloud.firestore {
allow update: if request.resource.data.diff(resource.data).affectedKeys()
.hasOnly(['tags', 'lowercaseTags']);
allow update: if request.resource.data.diff(resource.data).affectedKeys()
.hasOnly(['description', 'closeTime', 'autoResolutionTime'])
.hasOnly(['description', 'closeTime'])
&& resource.data.creatorId == request.auth.uid;
allow update: if isAdmin();
}

View File

@ -27,7 +27,6 @@ import {
import { getNoneAnswer } from '../../common/answer'
import { getNewContract } from '../../common/new-contract'
import { NUMERIC_BUCKET_COUNT } from '../../common/numeric-constants'
import { DAY_MS } from '../../common/util/time'
import { User } from '../../common/user'
const bodySchema = z.object({
@ -65,8 +64,6 @@ export const createmarket = newEndpoint(['POST'], async (req, auth) => {
;({ initialProb } = validate(binarySchema, req.body))
}
const autoResolutionTime = closeTime.getTime() + 7 * DAY_MS
// Uses utc time on server:
const today = new Date()
let freeMarketResetTime = new Date().setUTCHours(16, 0, 0, 0)
@ -116,7 +113,6 @@ export const createmarket = newEndpoint(['POST'], async (req, auth) => {
ante,
closeTime.getTime(),
tags ?? [],
autoResolutionTime,
NUMERIC_BUCKET_COUNT,
min ?? 0,
max ?? 0

View File

@ -1,14 +1,8 @@
import * as functions from 'firebase-functions'
import * as admin from 'firebase-admin'
import { difference, uniq, mapValues, groupBy, sum, sumBy } from 'lodash'
import { difference, uniq, mapValues, groupBy, sumBy } from 'lodash'
import {
AUTO_RESOLUTION,
Contract,
FreeResponse,
resolution,
RESOLUTIONS,
} from '../../common/contract'
import { Contract, resolution, RESOLUTIONS } from '../../common/contract'
import { User } from '../../common/user'
import { Bet } from '../../common/bet'
import { getUser, isProd, payUser } from './utils'
@ -21,10 +15,6 @@ import {
} from '../../common/payouts'
import { removeUndefinedProps } from '../../common/util/object'
import { LiquidityProvision } from '../../common/liquidity-provision'
import { getDpmOutcomeProbability } from '../../common/calculate-dpm'
import { getValues } from './utils'
import { batchedWaitAll } from '../../common/util/promise'
import { getProbability } from '../../common/calculate'
export const resolveMarket = functions
.runWith({ minInstances: 1, secrets: ['MAILGUN_KEY'] })
@ -41,203 +31,140 @@ export const resolveMarket = functions
) => {
const userId = context?.auth?.uid
if (!userId) return { status: 'error', message: 'Not authorized' }
const contractDoc = firestore.doc(`contracts/${data.contractId}`)
const { outcome, contractId, probabilityInt, resolutions, value } = data
const contractDoc = firestore.doc(`contracts/${contractId}`)
const contractSnap = await contractDoc.get()
if (!contractSnap.exists)
return { status: 'error', message: 'Invalid contract' }
const contract = contractSnap.data() as Contract
if (contract.creatorId !== userId)
return { status: 'error', message: 'User not creator of contract' }
const { creatorId, outcomeType, closeTime } = contract
return privateResolveMarket(contract, data)
}
)
if (outcomeType === 'BINARY') {
if (!RESOLUTIONS.includes(outcome))
return { status: 'error', message: 'Invalid outcome' }
} else if (outcomeType === 'FREE_RESPONSE') {
if (
isNaN(+outcome) &&
!(outcome === 'MKT' && resolutions) &&
outcome !== 'CANCEL'
)
return { status: 'error', message: 'Invalid outcome' }
} else if (outcomeType === 'NUMERIC') {
if (isNaN(+outcome) && outcome !== 'CANCEL')
return { status: 'error', message: 'Invalid outcome' }
} else {
return { status: 'error', message: 'Invalid contract outcomeType' }
}
export const autoResolveMarkets = functions.pubsub
.schedule('every 1 minutes')
.onRun(async () => {
const contracts = await getValues<Contract>(
firestore
.collection('contracts')
.where('isResolved', '==', false)
.where('closeTime', '>', Date.now())
.where('autoResolutionTime', '<', Date.now())
)
if (value !== undefined && !isFinite(value))
return { status: 'error', message: 'Invalid value' }
await batchedWaitAll(
contracts.map((contract) => async () => {
const result = await autoResolve(contract)
console.log('resolved', contract.slug, 'result:', result)
})
)
})
const autoResolve = async (contract: Contract) => {
const data = {
outcome: AUTO_RESOLUTION,
value: undefined, // numeric
probabilityInt:
contract.outcomeType == 'BINARY'
? getProbability(contract) * 100
: undefined,
resolutions:
contract.outcomeType == 'FREE_RESPONSE'
? getFreeResponseResolutions(contract)
: undefined,
}
contract.description = contract.description.concat(
`\n\n\nContract resolved automatically.`
)
return await privateResolveMarket(contract, data)
}
const getFreeResponseResolutions = (contract: Contract & FreeResponse) => {
const answersWithProbs = getAnswersWithProbs(contract)
const totalProb = sum(Object.values(answersWithProbs))
return mapValues(answersWithProbs, (prob) => (100 * prob) / totalProb)
}
const getAnswersWithProbs = (contract: Contract & FreeResponse) => {
const answers: { [id: string]: number } = {}
for (const answer of contract.answers) {
answers[answer.id] = getDpmOutcomeProbability(
contract.totalShares,
answer.id
)
}
return answers
}
const privateResolveMarket = async (
contract: Contract,
data: {
outcome: resolution
value?: number
probabilityInt?: number
resolutions?: { [outcome: string]: number }
}
) => {
const { creatorId, id, outcomeType, closeTime } = contract
const { outcome, probabilityInt, resolutions, value } = data
switch (outcomeType) {
case 'FREE_RESPONSE':
if (
isNaN(+outcome) &&
!(outcome === 'MKT' && resolutions) &&
outcome !== 'CANCEL'
)
return { status: 'error', message: 'Invalid outcome' }
break
case 'NUMERIC':
if (isNaN(+outcome) && outcome !== 'CANCEL')
return { status: 'error', message: 'Invalid outcome' }
break
case 'BINARY':
if (!RESOLUTIONS.includes(outcome))
return { status: 'error', message: 'Invalid outcome' }
if (
outcomeType === 'BINARY' &&
probabilityInt !== undefined &&
(probabilityInt < 0 ||
probabilityInt > 100 ||
!isFinite(probabilityInt))
)
return { status: 'error', message: 'Invalid probability' }
}
if (value && !isFinite(value))
return { status: 'error', message: 'Invalid value' }
if (creatorId !== userId)
return { status: 'error', message: 'User not creator of contract' }
if (contract.resolution)
return { status: 'error', message: 'Contract already resolved' }
if (contract.resolution)
return { status: 'error', message: 'Contract already resolved' }
const creator = await getUser(creatorId)
if (!creator) return { status: 'error', message: 'Creator not found' }
const creator = await getUser(creatorId)
if (!creator) return { status: 'error', message: 'Creator not found' }
const resolutionProbability =
probabilityInt !== undefined ? probabilityInt / 100 : undefined
const resolutionProbability =
probabilityInt !== undefined ? probabilityInt / 100 : undefined
const resolutionTime = Date.now()
const newCloseTime = closeTime
? Math.min(closeTime, resolutionTime)
: closeTime
const resolutionTime = Date.now()
const newCloseTime = closeTime
? Math.min(closeTime, resolutionTime)
: closeTime
const betsSnap = await firestore.collection(`contracts/${id}/bets`).get()
const betsSnap = await firestore
.collection(`contracts/${contractId}/bets`)
.get()
const bets = betsSnap.docs.map((doc) => doc.data() as Bet)
const bets = betsSnap.docs.map((doc) => doc.data() as Bet)
const liquiditiesSnap = await firestore
.collection(`contracts/${id}/liquidity`)
.get()
const liquiditiesSnap = await firestore
.collection(`contracts/${contractId}/liquidity`)
.get()
const liquidities = liquiditiesSnap.docs.map(
(doc) => doc.data() as LiquidityProvision
const liquidities = liquiditiesSnap.docs.map(
(doc) => doc.data() as LiquidityProvision
)
const { payouts, creatorPayout, liquidityPayouts, collectedFees } =
getPayouts(
outcome,
resolutions ?? {},
contract,
bets,
liquidities,
resolutionProbability
)
await contractDoc.update(
removeUndefinedProps({
isResolved: true,
resolution: outcome,
resolutionValue: value,
resolutionTime,
closeTime: newCloseTime,
resolutionProbability,
resolutions,
collectedFees,
})
)
console.log('contract ', contractId, 'resolved to:', outcome)
const openBets = bets.filter((b) => !b.isSold && !b.sale)
const loanPayouts = getLoanPayouts(openBets)
if (!isProd)
console.log(
'payouts:',
payouts,
'creator payout:',
creatorPayout,
'liquidity payout:'
)
if (creatorPayout)
await processPayouts(
[{ userId: creatorId, payout: creatorPayout }],
true
)
await processPayouts(liquidityPayouts, true)
const result = await processPayouts([...payouts, ...loanPayouts])
const userPayoutsWithoutLoans = groupPayoutsByUser(payouts)
await sendResolutionEmails(
openBets,
userPayoutsWithoutLoans,
creator,
creatorPayout,
contract,
outcome,
resolutionProbability,
resolutions
)
return result
}
)
const { payouts, creatorPayout, liquidityPayouts, collectedFees } =
getPayouts(
outcome,
resolutions ?? {},
contract,
bets,
liquidities,
resolutionProbability
)
const contractDoc = firestore.doc(`contracts/${contract.id}`)
await contractDoc.update(
removeUndefinedProps({
isResolved: true,
resolution: outcome,
resolutionValue: value,
resolutionTime,
description: contract.description,
closeTime: newCloseTime,
resolutionProbability,
resolutions,
collectedFees,
})
)
console.log('contract ', id, 'resolved to:', outcome)
const openBets = bets.filter((b) => !b.isSold && !b.sale)
const loanPayouts = getLoanPayouts(openBets)
if (!isProd)
console.log(
'payouts:',
payouts,
'creator payout:',
creatorPayout,
'liquidity payout:'
)
if (creatorPayout)
await processPayouts([{ userId: creatorId, payout: creatorPayout }], true)
await processPayouts(liquidityPayouts, true)
const result = await processPayouts([...payouts, ...loanPayouts])
const userPayoutsWithoutLoans = groupPayoutsByUser(payouts)
await sendResolutionEmails(
openBets,
userPayoutsWithoutLoans,
creator,
creatorPayout,
contract,
outcome,
resolutionProbability,
resolutions
)
return result
}
const processPayouts = async (payouts: Payout[], isDeposit = false) => {
const userPayouts = groupPayoutsByUser(payouts)

View File

@ -1,53 +0,0 @@
// Existing contracts don't have auto resolutions. Let's add it.
import * as admin from 'firebase-admin'
import { initAdmin } from './script-init'
initAdmin()
import { getValues } from '../utils'
import { Contract } from '../../../common/contract'
import { DAY_MS } from '../../../common/util/time'
import { batchedWaitAll } from '../../../common/util/promise'
const firestore = admin.firestore()
async function addAutoResolutionToContracts() {
console.log('Adding auto resolution to existing contracts')
const contracts = await getValues<Contract>(
firestore.collection('contracts').where('isResolved', '==', false)
)
console.log('Loaded', contracts.length, 'contracts')
await batchedWaitAll(
contracts.map((c) => () => addAutoResolutionToContract(c))
)
}
async function addAutoResolutionToContract(contract: Contract) {
if (contract.autoResolutionTime) {
console.log('Skipping, already has auto resolution', contract.slug)
return
}
const contractRef = firestore.doc(`contracts/${contract.id}`)
if (!contract.closeTime) {
console.error('Has no close time, please check manually', contract.slug)
return
}
const autoResolutionTime =
contract.closeTime > Date.now()
? contract.closeTime + 7 * DAY_MS
: Date.now() + 14 * DAY_MS
console.log('Adding auto resolution', contract.slug)
await contractRef.update({
autoResolutionTime: autoResolutionTime,
} as Partial<Contract>)
}
if (require.main === module)
addAutoResolutionToContracts().then(() => process.exit())

View File

@ -1,108 +0,0 @@
// Some markets don't have a close time. Let's add it.
import * as admin from 'firebase-admin'
import { initAdmin } from './script-init'
initAdmin()
import { getValues } from '../utils'
import { Contract } from '../../../common/contract'
import { batchedWaitAll } from '../../../common/util/promise'
const firestore = admin.firestore()
async function addCloseTimeToContracts() {
console.log('Adding close times to existing contracts')
const contracts = await getValues<Contract>(
firestore.collection('contracts').where('isResolved', '==', false)
)
console.log('Loaded', contracts.length, 'contracts')
await batchedWaitAll(contracts.map((c) => () => addCloseTimeToContract(c)))
}
async function addCloseTimeToContract(contract: Contract) {
if (contract.closeTime) {
return
}
const closeTime = closeTimes.get(contract.slug)
if (!closeTime) {
console.error('No close time found', contract.slug)
return
}
const contractRef = firestore.doc(`contracts/${contract.id}`)
await contractRef.update({
closeTime,
} as Partial<Contract>)
console.log('Added close time', contract.slug, new Date(closeTime))
}
const closeTimes = new Map<string, number>([
['will-apple-ship-its-ar-glasses-by-e', 1672531200000],
['will-ethereum-switch-to-proof-of-st', 1672531200000],
['will-mantic-markets-have-over-1m', 1672531200000],
['will-aoc-challenge-chuck-schumer-in', 1672531200000],
['nancy-pelosi-announces-retirement-p', 1672531200000],
['will-activisionblizzard-solve-its-r', 1672531200000],
['test', 1656547200000],
['will-spacex-become-a-publicly-trade', 1672531200000],
['mantic-will-airdrop-crypto-to-early', 1656633600000],
['will-the-homicide-rate-in-2022-rema', 1704067200000],
['in-us-pandemic-fades-away-to-predel', 1672531200000],
['will-we-discover-life-on-mars-befor', 1704067200000],
['november-2022-yearonyear-cpi-growth', 1672531200000],
['will-2060-globally-be-warmer-than-2', 2871763200000],
['will-starship-reach-orbit-by-the-en', 1672531200000],
['will-the-runnerup-in-the-2024-us-pr', 1735689600000],
['will-joe-rogan-interview-a-guest-ab', 1672531200000],
['the-unemployment-rate-stays-between', 1672531200000],
['restaurant-and-retail-spending-cont', 1672531200000],
['will-at-the-end-of-2022-western-tee', 1672531200000],
['will-chinese-economic-growth-drop-b', 1924992000000],
['us-authorizes-another-covid-booster', 1672531200000],
['will-fbi-statistics-show-homicides-', 1672531200000],
['will-dwayne-johnson-win-the-2024-us', 1737331200000],
['democrats-go-down-at-least-one-gove', 1672531200000],
['will-congress-hold-any-hearings-abo', 1672531200000],
['will-there-be-a-2022-sarscov2-varia', 1672531200000],
['will-there-be-a-federal-mask-requir', 1667865600000],
['no-military-conflict-between-the-pr', 1672531200000],
['will-redditcomrslatestarcodex-have-', 1656633600000],
['we-will-be-getting-boosters-modifie', 1661990400000],
['will-pete-buttigieg-be-the-2024-dem', 1735689600000],
['omicron-has-a-100-or-bigger-transmi', 1672531200000],
['will-apple-reach-a-market-capitaliz', 1672531200000],
['will-the-median-rent-for-a-1bedroom', 1672531200000],
['hillary-clinton-signals-in-any-way-', 1735689600000],
['will-james-webb-space-telescope-dep', 1659312000000],
['fullselfdriving-robotaxis-generally', 1704067200000],
['will-circular-economy-become-mainst', 2272147200000],
['joe-biden-is-still-president-at-the', 1672531200000],
['will-bit-coin-hit-100k-this-year', 1672531200000],
['democrats-lose-both-houses-of-congr', 1672531200000],
['will-teslas-cybertruck-go-into-full', 1672531200000],
['will-the-sp-500-trade-below-3800-in', 1672531200000],
['will-chicago-have-more-than-12-inch', 1656547200000],
['will-a-major-norwegian-political-pa-58167546884aa', 1672531200000],
['will-i-be-a-regular-user-of-this-we', 1672531200000],
['will-apple-sell-an-apple-branded-ar', 1669852800000],
['at-the-end-of-its-ipo-day-will-redd', 1672531200000],
['will-any-major-known-associates-of-', 1672531200000],
['will-donald-trump-be-the-republican', 1735689600000],
['will-solana-have-a-higher-market-ca', 1672531200000],
['will-congress-hold-any-hearings-abo-e21f987033b3', 1672531200000],
['will-ethereum-overtake-bitcoin-in-t', 1672531200000],
['china-officially-abandons-covid-zer', 1672531200000],
['privacy-tokens-will-outgrow-status-', 1672531200000],
['republicans-will-win-the-2022-texas', 1669852800000],
['will-at-least-75-of-the-usa-covid19', 1677542400000],
['liz-cheney-loses-primary-in-2022', 1672531200000],
['will-the-us-inflation-rate-for-2022', 1688169600000],
['will-republicans-win-enough-seats-i', 1669852800000],
['will-the-world-experience-a-solar-s', 1672531200000],
])
if (require.main === module)
addCloseTimeToContracts().then(() => process.exit())

View File

@ -23,7 +23,6 @@ import { Bet } from 'common/bet'
import NewContractBadge from '../new-contract-badge'
import { CATEGORY_LIST } from 'common/categories'
import { TagsList } from '../tags-list'
import { DAY_MS } from 'common/util/time'
import { UserFollowButton } from '../follow-button'
export function MiscDetails(props: {
@ -161,19 +160,14 @@ export function ContractDetails(props: {
)}
</Row>
)}
<Row className="items-center gap-1">
<DatabaseIcon className="h-5 w-5" />
<div className="whitespace-nowrap">{volumeLabel}</div>
</Row>
{!disabled && (
<ContractInfoDialog
contract={contract}
bets={bets}
isCreator={isCreator ?? false}
/>
)}
{!disabled && <ContractInfoDialog contract={contract} bets={bets} />}
</Row>
)
}
@ -216,32 +210,15 @@ function EditableCloseDate(props: {
const newCloseTime = dayjs(closeDate).valueOf()
if (newCloseTime === closeTime) setIsEditingCloseTime(false)
else if (newCloseTime > Date.now()) {
const { description, autoResolutionTime } = contract
const { description } = contract
const formattedCloseDate = dayjs(newCloseTime).format('YYYY-MM-DD h:mm a')
let newDescription = description.concat(
`\n\nClose date updated to ${formattedCloseDate}`
)
const newDescription = `${description}\n\nClose date updated to ${formattedCloseDate}`
const update: Partial<Contract> = {
updateContract(contract.id, {
closeTime: newCloseTime,
}
description: newDescription,
})
if (autoResolutionTime) {
const newAutoResolutionTime = newCloseTime + 7 * DAY_MS
if (newAutoResolutionTime >= autoResolutionTime) {
update.autoResolutionTime = newAutoResolutionTime
const formattedNewAutoResolutionTime = dayjs(
newAutoResolutionTime
).format('YYYY-MM-DD h:mm a')
newDescription = newDescription.concat(
`\nAuto resolution date updated to ${formattedNewAutoResolutionTime}`
)
}
}
update.description = newDescription
updateContract(contract.id, update)
setIsEditingCloseTime(false)
}
}

View File

@ -1,8 +1,4 @@
import {
DotsHorizontalIcon,
PencilIcon,
CheckIcon,
} from '@heroicons/react/outline'
import { DotsHorizontalIcon } from '@heroicons/react/outline'
import clsx from 'clsx'
import dayjs from 'dayjs'
import { uniqBy } from 'lodash'
@ -15,7 +11,6 @@ import {
contractPath,
contractPool,
getBinaryProbPercent,
updateContract,
} from 'web/lib/firebase/contracts'
import { LiquidityPanel } from '../liquidity-panel'
import { CopyLinkButton } from '../copy-link-button'
@ -28,25 +23,15 @@ import { Title } from '../title'
import { TweetButton } from '../tweet-button'
import { InfoTooltip } from '../info-tooltip'
const formatTime = (dt: number) => dayjs(dt).format('MMM DD, YYYY hh:mm a z')
export function ContractInfoDialog(props: {
contract: Contract
bets: Bet[]
isCreator: boolean
}) {
const { contract, bets, isCreator } = props
export function ContractInfoDialog(props: { contract: Contract; bets: Bet[] }) {
const { contract, bets } = props
const [open, setOpen] = useState(false)
const {
createdTime,
closeTime,
resolutionTime,
mechanism,
outcomeType,
autoResolutionTime,
} = contract
const formatTime = (dt: number) => dayjs(dt).format('MMM DD, YYYY hh:mm a z')
const { createdTime, closeTime, resolutionTime, mechanism, outcomeType } =
contract
const tradersCount = uniqBy(
bets.filter((bet) => !bet.isAnte),
@ -131,14 +116,6 @@ export function ContractInfoDialog(props: {
</tr>
)}
{autoResolutionTime && !resolutionTime && (
<EditableResolutionTime
time={autoResolutionTime}
contract={contract}
isCreator={isCreator}
/>
)}
{resolutionTime && (
<tr>
<td>Market resolved</td>
@ -203,72 +180,3 @@ const getTweetText = (contract: Contract, isCreator: boolean) => {
return `${tweetQuestion}\n\n${tweetDescription}\n\n${url}`
}
export function EditableResolutionTime(props: {
time: number
contract: Contract
isCreator: boolean
}) {
const { time, contract, isCreator } = props
const [isEditing, setIsEditing] = useState(false)
const [timeString, setTimeString] = useState(time && formatTime(time))
const onSave = () => {
const newTime = dayjs(timeString).valueOf()
if (newTime === time) setIsEditing(false)
else if (
contract.closeTime &&
newTime > (contract.closeTime ?? Date.now())
) {
const formattedTime = dayjs(newTime).format('YYYY-MM-DD h:mm a')
const newDescription = `${contract.description}\n\nAuto resolution date updated to ${formattedTime}`
updateContract(contract.id, {
autoResolutionTime: newTime,
description: newDescription,
})
setIsEditing(false)
}
}
return (
<tr>
<td>
Market autoresolves
{isCreator &&
(isEditing ? (
<button className="btn btn-xs btn-ghost" onClick={onSave}>
<CheckIcon className="inline h-4 w-4" />
</button>
) : (
<button
className="btn btn-xs btn-ghost"
onClick={() => setIsEditing(true)}
>
<PencilIcon className="inline h-4 w-4" />
</button>
))}
</td>
<td>
{isEditing ? (
<div className="form-control mr-1 items-start">
<input
type="datetime-local"
className="input input-xs"
onClick={(e) => e.stopPropagation()}
onChange={(e) => setTimeString(e.target.value || '')}
min={contract.closeTime}
value={timeString}
/>
</div>
) : (
<div className="form-control mr-1 items-start">
{formatTime(time)}
</div>
)}
</td>
</tr>
)
}

View File

@ -45,7 +45,7 @@ export function Modal(props: {
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<div className="inline-block transform overflow-hidden text-left align-bottom transition-all sm:my-8 sm:w-full sm:max-w-lg sm:p-6 sm:align-middle">
<div className="inline-block transform overflow-hidden text-left align-bottom transition-all sm:my-8 sm:w-full sm:max-w-md sm:p-6 sm:align-middle">
{children}
</div>
</Transition.Child>

View File

@ -32,8 +32,6 @@ export type LiteMarket = {
volume7Days: number
volume24Hours: number
autoResolutionTime?: number
isResolved: boolean
resolution?: string
resolutionTime?: number
@ -66,7 +64,6 @@ export function toLiteMarket(contract: Contract): LiteMarket {
volume,
volume7Days,
volume24Hours,
autoResolutionTime,
isResolved,
resolution,
resolutionTime,
@ -100,7 +97,6 @@ export function toLiteMarket(contract: Contract): LiteMarket {
volume,
volume7Days,
volume24Hours,
autoResolutionTime,
isResolved,
resolution,
resolutionTime,