diff --git a/common/contract.ts b/common/contract.ts index 7fa3b1be..756860a7 100644 --- a/common/contract.ts +++ b/common/contract.ts @@ -28,9 +28,9 @@ export type FullContract< isResolved: boolean resolutionTime?: number // When the market is resolved resolution?: string - resolutionType: 'manual' | 'combined' - automaticResolutionTime?: number + resolutionType: resolutionType automaticResolution?: resolution + automaticResolutionTime?: number closeEmailsSent?: number @@ -102,6 +102,7 @@ export type Numeric = { export type outcomeType = 'BINARY' | 'MULTI' | 'FREE_RESPONSE' | 'NUMERIC' export type resolutionType = 'MANUAL' | 'COMBINED' export type resolution = 'YES' | 'NO' | 'MKT' | 'CANCEL' +export const RESOLUTIONS = ['YES' , 'NO' , 'MKT' , 'CANCEL'] export const OUTCOME_TYPES = ['BINARY', 'MULTI', 'FREE_RESPONSE', 'NUMERIC'] export const RESOLUTION_TYPES = ['MANUAL', 'COMBINED'] diff --git a/common/new-contract.ts b/common/new-contract.ts index 4476a522..beb48d55 100644 --- a/common/new-contract.ts +++ b/common/new-contract.ts @@ -8,6 +8,7 @@ import { FreeResponse, Numeric, outcomeType, + resolution, resolutionType, } from './contract' import { User } from './user' @@ -27,6 +28,8 @@ export function getNewContract( closeTime: number, extraTags: string[], resolutionType: resolutionType, + automaticResolution: resolution, + automaticResolutionTime: number, // used for numeric markets bucketCount: number, @@ -64,8 +67,9 @@ export function getNewContract( isResolved: false, createdTime: Date.now(), closeTime, - resolutionType: 'manual', - resolution: undefined, + resolutionType, + automaticResolution, + automaticResolutionTime, volume: 0, volume24Hours: 0, diff --git a/functions/src/create-contract.ts b/functions/src/create-contract.ts index b65e8bb0..ee3a3d1f 100644 --- a/functions/src/create-contract.ts +++ b/functions/src/create-contract.ts @@ -12,6 +12,7 @@ import { MAX_TAG_LENGTH, Numeric, OUTCOME_TYPES, + RESOLUTIONS, RESOLUTION_TYPES } from '../../common/contract' import { slugify } from '../../common/util/slugify' @@ -46,6 +47,8 @@ export const createContract = newEndpoint(['POST'], async (req, _res) => { max, manaLimitPerUser, resolutionType, + automaticResolution, + automaticResolutionTime } = req.body || {} if (!question || typeof question != 'string') @@ -94,6 +97,17 @@ export const createContract = newEndpoint(['POST'], async (req, _res) => { if (!RESOLUTION_TYPES.includes(resolutionType)) throw new APIError(400, 'Invalid resolutionType') + automaticResolution = automaticResolution ?? 'MANUAL' + + if (!RESOLUTIONS.includes(automaticResolution)) + throw new APIError(400, 'Invalid automaticResolution') + + if (automaticResolution === 'MANUAL' && automaticResolutionTime) + throw new APIError(400, 'automaticResolutionTime specified even tho automaticResolution is \'MANUAL\'') + + if (automaticResolutionTime && automaticResolutionTime < closeTime) + throw new APIError(400, 'resolutionTime < closeTime') + // Uses utc time on server: const yesterday = new Date() yesterday.setUTCDate(yesterday.getUTCDate() - 1) @@ -143,6 +157,8 @@ export const createContract = newEndpoint(['POST'], async (req, _res) => { closeTime, tags ?? [], resolutionType, + automaticResolution, + automaticResolutionTime, NUMERIC_BUCKET_COUNT, min ?? 0, max ?? 0, diff --git a/functions/src/resolve-market.ts b/functions/src/resolve-market.ts index 183a5624..868f0beb 100644 --- a/functions/src/resolve-market.ts +++ b/functions/src/resolve-market.ts @@ -2,7 +2,7 @@ import * as functions from 'firebase-functions' import * as admin from 'firebase-admin' import { difference, uniq, mapValues, groupBy, sumBy } from 'lodash' -import { Contract } from '../../common/contract' +import { Contract, RESOLUTIONS } from '../../common/contract' import { User } from '../../common/user' import { Bet } from '../../common/bet' import { getUser, isProd, payUser } from './utils' @@ -42,7 +42,7 @@ export const resolveMarket = functions const { creatorId, outcomeType, closeTime } = contract if (outcomeType === 'BINARY') { - if (!['YES', 'NO', 'MKT', 'CANCEL'].includes(outcome)) + if (!RESOLUTIONS.includes(outcome)) return { status: 'error', message: 'Invalid outcome' } } else if (outcomeType === 'FREE_RESPONSE') { if ( diff --git a/web/components/contract/quick-bet.tsx b/web/components/contract/quick-bet.tsx index daca33a7..04d769f1 100644 --- a/web/components/contract/quick-bet.tsx +++ b/web/components/contract/quick-bet.tsx @@ -13,6 +13,7 @@ import { Binary, NumericContract, FreeResponseContract, + resolution, } from 'common/contract' import { formatLargeNumber, @@ -269,7 +270,7 @@ export function getColor(contract: Contract, previewProb?: number) { const { resolution } = contract if (resolution) { return ( - OUTCOME_TO_COLOR[resolution as 'YES' | 'NO' | 'CANCEL' | 'MKT'] ?? + OUTCOME_TO_COLOR[resolution as resolution] ?? // If resolved to a FR answer, use 'primary' 'primary' ) diff --git a/web/pages/create.tsx b/web/pages/create.tsx index f825cd38..ab66130a 100644 --- a/web/pages/create.tsx +++ b/web/pages/create.tsx @@ -11,7 +11,7 @@ import { FIXED_ANTE, MINIMUM_ANTE } from 'common/antes' import { InfoTooltip } from 'web/components/info-tooltip' import { Page } from 'web/components/page' import { Row } from 'web/components/layout/row' -import { MAX_DESCRIPTION_LENGTH, outcomeType, resolution, resolutionType } from 'common/contract' +import { MAX_DESCRIPTION_LENGTH, outcomeType, RESOLUTIONS, resolution, resolutionType } from 'common/contract' import { formatMoney } from 'common/util/format' import { useHasCreatedContractToday } from 'web/hooks/use-has-created-contract-today' import { removeUndefinedProps } from 'common/util/object' @@ -66,7 +66,7 @@ export function NewContract(props: { question: string; tag?: string }) { const [outcomeType, setOutcomeType] = useState('BINARY') const [resolutionType, setResolutionType] = useState('MANUAL') - const [automaticResolution, setAutomaticResolution] = useState('YES') + const [automaticResolution, setAutomaticResolution] = useState('CANCEL') const [initialProb, setInitialProb] = useState(50) const [minString, setMinString] = useState('') const [maxString, setMaxString] = useState('') @@ -97,7 +97,7 @@ export function NewContract(props: { question: string; tag?: string }) { const [isSubmitting, setIsSubmitting] = useState(false) const closeTime = closeDate ? dayjs(closeDate).valueOf() : undefined - const resolutionTime = resolutionDate ? dayjs(resolutionDate).valueOf() : undefined + const automaticResolutionTime = resolutionDate ? dayjs(resolutionDate).valueOf() : undefined const balance = creator?.balance || 0 @@ -154,7 +154,7 @@ export function NewContract(props: { question: string; tag?: string }) { min, max, automaticResolution, - resolutionTime + automaticResolutionTime }) ) await router.push(contractPath(result as Contract)) @@ -422,7 +422,7 @@ export function NewContract(props: { question: string; tag?: string }) {