169 lines
4.7 KiB
TypeScript
169 lines
4.7 KiB
TypeScript
import { Challenge } from './challenge'
|
|
import { BinaryContract, Contract } from './contract'
|
|
import { getFormattedMappedValue } from './pseudo-numeric'
|
|
import { getProbability } from './calculate'
|
|
import { richTextToString } from './util/parse'
|
|
import { getCpmmProbability } from './calculate-cpmm'
|
|
import { getDpmProbability } from './calculate-dpm'
|
|
import { formatMoney, formatPercent } from './util/format'
|
|
|
|
export function contractMetrics(contract: Contract) {
|
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
const dayjs = require('dayjs')
|
|
const { createdTime, resolutionTime, isResolved } = contract
|
|
|
|
const createdDate = dayjs(createdTime).format('MMM D')
|
|
|
|
const resolvedDate = isResolved
|
|
? dayjs(resolutionTime).format('MMM D')
|
|
: undefined
|
|
|
|
const volumeLabel = `${formatMoney(contract.volume)} bet`
|
|
|
|
return { volumeLabel, createdDate, resolvedDate }
|
|
}
|
|
|
|
// String version of the above, to send to the OpenGraph image generator
|
|
export function contractTextDetails(contract: Contract) {
|
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
const dayjs = require('dayjs')
|
|
const { closeTime, groupLinks } = contract
|
|
const { createdDate, resolvedDate, volumeLabel } = contractMetrics(contract)
|
|
|
|
const groupHashtags = groupLinks?.map((g) => `#${g.name.replace(/ /g, '')}`)
|
|
|
|
return (
|
|
`${resolvedDate ? `${createdDate} - ${resolvedDate}` : createdDate}` +
|
|
(closeTime
|
|
? ` • ${closeTime > Date.now() ? 'Closes' : 'Closed'} ${dayjs(
|
|
closeTime
|
|
).format('MMM D, h:mma')}`
|
|
: '') +
|
|
` • ${volumeLabel}` +
|
|
(groupHashtags ? ` • ${groupHashtags.join(' ')}` : '')
|
|
)
|
|
}
|
|
|
|
export function getBinaryProb(contract: BinaryContract) {
|
|
const { pool, resolutionProbability, mechanism } = contract
|
|
|
|
return (
|
|
resolutionProbability ??
|
|
(mechanism === 'cpmm-1'
|
|
? getCpmmProbability(pool, contract.p)
|
|
: getDpmProbability(contract.totalShares))
|
|
)
|
|
}
|
|
|
|
export const getOpenGraphProps = (contract: Contract) => {
|
|
const {
|
|
resolution,
|
|
question,
|
|
creatorName,
|
|
creatorUsername,
|
|
outcomeType,
|
|
creatorAvatarUrl,
|
|
description: desc,
|
|
} = contract
|
|
const probPercent =
|
|
outcomeType === 'BINARY'
|
|
? formatPercent(getBinaryProb(contract))
|
|
: undefined
|
|
|
|
const numericValue =
|
|
outcomeType === 'PSEUDO_NUMERIC'
|
|
? getFormattedMappedValue(contract)(getProbability(contract))
|
|
: undefined
|
|
|
|
const stringDesc = typeof desc === 'string' ? desc : richTextToString(desc)
|
|
|
|
const description = resolution
|
|
? `Resolved ${resolution}. ${stringDesc}`
|
|
: probPercent
|
|
? `${probPercent} chance. ${stringDesc}`
|
|
: stringDesc
|
|
|
|
return {
|
|
question,
|
|
probability: probPercent,
|
|
metadata: contractTextDetails(contract),
|
|
creatorName,
|
|
creatorUsername,
|
|
creatorAvatarUrl,
|
|
description,
|
|
numericValue,
|
|
resolution,
|
|
}
|
|
}
|
|
|
|
export type OgCardProps = {
|
|
question: string
|
|
probability?: string
|
|
metadata: string
|
|
creatorName: string
|
|
creatorUsername: string
|
|
creatorAvatarUrl?: string
|
|
numericValue?: string
|
|
resolution?: string
|
|
}
|
|
|
|
export function buildCardUrl(props: OgCardProps, challenge?: Challenge) {
|
|
const {
|
|
creatorAmount,
|
|
acceptances,
|
|
acceptorAmount,
|
|
creatorOutcome,
|
|
acceptorOutcome,
|
|
} = challenge || {}
|
|
const {
|
|
probability,
|
|
numericValue,
|
|
resolution,
|
|
creatorAvatarUrl,
|
|
question,
|
|
metadata,
|
|
creatorUsername,
|
|
creatorName,
|
|
} = props
|
|
const { userName, userAvatarUrl } = acceptances?.[0] ?? {}
|
|
|
|
const probabilityParam =
|
|
probability === undefined
|
|
? ''
|
|
: `&probability=${encodeURIComponent(probability ?? '')}`
|
|
|
|
const numericValueParam =
|
|
numericValue === undefined
|
|
? ''
|
|
: `&numericValue=${encodeURIComponent(numericValue ?? '')}`
|
|
|
|
const creatorAvatarUrlParam =
|
|
creatorAvatarUrl === undefined
|
|
? ''
|
|
: `&creatorAvatarUrl=${encodeURIComponent(creatorAvatarUrl ?? '')}`
|
|
|
|
const challengeUrlParams = challenge
|
|
? `&creatorAmount=${creatorAmount}&creatorOutcome=${creatorOutcome}` +
|
|
`&challengerAmount=${acceptorAmount}&challengerOutcome=${acceptorOutcome}` +
|
|
`&acceptedName=${userName ?? ''}&acceptedAvatarUrl=${userAvatarUrl ?? ''}`
|
|
: ''
|
|
|
|
const resolutionUrlParam = resolution
|
|
? `&resolution=${encodeURIComponent(resolution)}`
|
|
: ''
|
|
|
|
// URL encode each of the props, then add them as query params
|
|
return (
|
|
`https://manifold-og-image.vercel.app/m.png` +
|
|
`?question=${encodeURIComponent(question)}` +
|
|
probabilityParam +
|
|
numericValueParam +
|
|
`&metadata=${encodeURIComponent(metadata)}` +
|
|
`&creatorName=${encodeURIComponent(creatorName)}` +
|
|
creatorAvatarUrlParam +
|
|
`&creatorUsername=${encodeURIComponent(creatorUsername)}` +
|
|
challengeUrlParams +
|
|
resolutionUrlParam
|
|
)
|
|
}
|