* Answer datatype and MULTI outcome type for Contract
* Create free answer contract
* Automatically sort Tailwind classes with Prettier (#45)
* Add Prettier Tailwind plugin
* Autoformat Tailwind classes with Prettier
* Allow for non-binary contracts in contract page and related components
* logo with white inside, transparent bg
* Create answer
* Some UI for showing answers
* Answer bet panel
* Convert rest of calcuate file to generic multi contracts
* Working betting with ante'd NONE answer
* Numbered answers. Layout & calculation tweaks
* Can bet. More layout tweaks!
* Resolve answer UI
* Resolve multi market
* Resolved market UI
* Fix feed and cards for multi contracts
* Sell bets. Various fixes
* Tweaks for trades page
* Always dev mode
* Create answer bet has isAnte: true
* Fix card showing 0% for multi contracts
* Fix grouped bets feed for multi outcomes
* None option converted to none of the above label at bottom of list. Button to resolve none.
* Tweaks to no answers yet, resolve button layout
* Show ante bets on new answers in the feed
* Update placeholder text for description
* Consolidate firestore rules for subcollections
* Remove Contract and Bet type params. Use string type for outcomes.
* Increase char limit to 10k for answers. Preserve line breaks.
* Don't show resolve options after answer chosen
* Fix type error in script
* Remove NONE resolution option
* Change outcomeType to include 'MULTI' and 'FREE_RESPONSE'
* Show bet probability change and payout when creating answer
* User info change: also change answers
* Append answers to contract field 'answers'
* sort trades by resolved
* Don't include trailing !:,.; in links
* Stop flooring inputs into formatMoney
* Revert "Stop flooring inputs into formatMoney"
This reverts commit 2f7ab18429
.
* Consistently floor user.balance
* Expand create panel on focus
From Richard Hanania's feedback
* welcome email: include link to manifold
* Fix home page in dev on branches that are not free-response
* Close emails (#50)
* script init for stephen dev
* market close emails
* order of operations
* template email
* sendMarketCloseEmail: handle unsubscribe
* remove debugging
* marketCloseEmails: every hour
* sendMarketCloseEmails: check undefined
* marketCloseEmails: "every hour" => "every 1 hours"
* Set up a read API using Vercel serverless functions (#49)
* Set up read API using Vercel serverless functions
Featuring:
/api/v0/markets
/api/v0/market/[contractId]
/api/v0/slug/[contractSlug]
* Include tags in API
* Tweaks. Remove filter for only binary contract
* Fix bet probability change for NO bets
* Put back isProd calculation
Co-authored-by: Austin Chen <akrolsmir@gmail.com>
Co-authored-by: mantikoros <sgrugett@gmail.com>
Co-authored-by: mantikoros <95266179+mantikoros@users.noreply.github.com>
132 lines
3.2 KiB
TypeScript
132 lines
3.2 KiB
TypeScript
import _ = require('lodash')
|
|
import { getProbability } from '../../common/calculate'
|
|
import { Contract } from '../../common/contract'
|
|
import { CREATOR_FEE } from '../../common/fees'
|
|
import { PrivateUser, User } from '../../common/user'
|
|
import { formatMoney, formatPercent } from '../../common/util/format'
|
|
import { sendTemplateEmail, sendTextEmail } from './send-email'
|
|
import { getPrivateUser, getUser } from './utils'
|
|
|
|
type market_resolved_template = {
|
|
userId: string
|
|
name: string
|
|
creatorName: string
|
|
question: string
|
|
outcome: string
|
|
payout: string
|
|
url: string
|
|
}
|
|
|
|
const toDisplayResolution = (outcome: string, prob: number) => {
|
|
const display = {
|
|
YES: 'YES',
|
|
NO: 'NO',
|
|
CANCEL: 'N/A',
|
|
MKT: formatPercent(prob),
|
|
}[outcome]
|
|
|
|
return display === undefined ? `#${outcome}` : display
|
|
}
|
|
|
|
export const sendMarketResolutionEmail = async (
|
|
userId: string,
|
|
payout: number,
|
|
creator: User,
|
|
contract: Contract,
|
|
resolution: 'YES' | 'NO' | 'CANCEL' | 'MKT' | string,
|
|
resolutionProbability?: number
|
|
) => {
|
|
const privateUser = await getPrivateUser(userId)
|
|
if (
|
|
!privateUser ||
|
|
privateUser.unsubscribedFromResolutionEmails ||
|
|
!privateUser.email
|
|
)
|
|
return
|
|
|
|
const user = await getUser(userId)
|
|
if (!user) return
|
|
|
|
const prob = resolutionProbability ?? getProbability(contract.totalShares)
|
|
|
|
const outcome = toDisplayResolution(resolution, prob)
|
|
|
|
const subject = `Resolved ${outcome}: ${contract.question}`
|
|
|
|
const templateData: market_resolved_template = {
|
|
userId: user.id,
|
|
name: user.name,
|
|
creatorName: creator.name,
|
|
question: contract.question,
|
|
outcome,
|
|
payout: `${Math.round(payout)}`,
|
|
url: `https://manifold.markets/${creator.username}/${contract.slug}`,
|
|
}
|
|
|
|
// Modify template here:
|
|
// https://app.mailgun.com/app/sending/domains/mg.manifold.markets/templates/edit/market-resolved/initial
|
|
// Mailgun username: james@mantic.markets
|
|
|
|
await sendTemplateEmail(
|
|
privateUser.email,
|
|
subject,
|
|
'market-resolved',
|
|
templateData
|
|
)
|
|
}
|
|
|
|
export const sendWelcomeEmail = async (
|
|
user: User,
|
|
privateUser: PrivateUser
|
|
) => {
|
|
const firstName = user.name.split(' ')[0]
|
|
|
|
await sendTextEmail(
|
|
privateUser.email || '',
|
|
'Welcome to Manifold Markets!',
|
|
`Hi ${firstName},
|
|
|
|
Thanks for joining us! We can't wait to see what markets you create.
|
|
Questions? Feedback? I'd love to hear from you - just reply to this email!
|
|
Or come chat with us on Discord: https://discord.gg/eHQBNBqXuh
|
|
|
|
Best,
|
|
Austin from Manifold
|
|
https://manifold.markets/`
|
|
)
|
|
}
|
|
|
|
export const sendMarketCloseEmail = async (
|
|
user: User,
|
|
privateUser: PrivateUser,
|
|
contract: Contract
|
|
) => {
|
|
if (
|
|
!privateUser ||
|
|
privateUser.unsubscribedFromResolutionEmails ||
|
|
!privateUser.email
|
|
)
|
|
return
|
|
|
|
const { username, name, id: userId } = user
|
|
const firstName = name.split(' ')[0]
|
|
|
|
const { question, pool: pools, slug } = contract
|
|
const pool = formatMoney(_.sum(_.values(pools)))
|
|
const url = `https://manifold.markets/${username}/${slug}`
|
|
|
|
await sendTemplateEmail(
|
|
privateUser.email,
|
|
'Your market has closed',
|
|
'market-close',
|
|
{
|
|
name: firstName,
|
|
question,
|
|
pool,
|
|
url,
|
|
userId,
|
|
creatorFee: (CREATOR_FEE * 100).toString(),
|
|
}
|
|
)
|
|
}
|