Merge branch 'main' into show-comments-position

This commit is contained in:
Ian Philips 2022-04-28 12:31:21 -06:00
commit 8c05eec479
10 changed files with 76 additions and 48 deletions

View File

@ -25,8 +25,9 @@ Operations with complicated contracts (e.g. buying shares) are provided in a sep
- `functions/`: Firebase cloud functions, for secure work (e.g. balances, Stripe payments, emails). Also contains in - `functions/`: Firebase cloud functions, for secure work (e.g. balances, Stripe payments, emails). Also contains in
`functions/src/scripts/` some Typescript scripts that do ad hoc CLI interaction with Firebase. `functions/src/scripts/` some Typescript scripts that do ad hoc CLI interaction with Firebase.
- `common/`: Typescript library code shared between `web/` & `functions/`. Also contains in `common/envs` configuration for - `common/`: Typescript library code shared between `web/` & `functions/`. If you want to look at how the market math
the different environments (i.e. prod, dev, Manifold for Teams instances.) works, most of that's in here (it gets called from the `placeBet` and `sellBet` endpoints in `functions/`.) Also
contains in `common/envs` configuration for the different environments (i.e. prod, dev, Manifold for Teams instances.)
- `og-image/`: The OpenGraph image generator; creates the preview images shown on Twitter/social media. - `og-image/`: The OpenGraph image generator; creates the preview images shown on Twitter/social media.
@ -34,7 +35,9 @@ Also: Our docs are currently in [a separate repo](https://github.com/manifoldmar
## Contributing ## Contributing
Since we are just now open-sourcing things, we will see how things go. Feel free to open issues, submit PRs, and chat about the process on Discord. We would prefer [small PRs][small-prs] that we can effectively evaluate and review -- maybe check in with us first if you are thinking to work on a big change. Since we are just now open-sourcing things, we will see how things go. Feel free to open issues, submit PRs, and chat about the process on [Discord][discord]. We would prefer [small PRs][small-prs] that we can effectively evaluate and review -- maybe check in with us first if you are thinking to work on a big change.
If you need additional access to any infrastructure in order to work on something (e.g. Vercel, Firebase) let us know about that on Discord as well.
[vercel]: https://vercel.com/ [vercel]: https://vercel.com/
[jamstack]: https://jamstack.org/ [jamstack]: https://jamstack.org/
@ -45,3 +48,4 @@ Since we are just now open-sourcing things, we will see how things go. Feel free
[cloud-firestore]: https://firebase.google.com/docs/firestore [cloud-firestore]: https://firebase.google.com/docs/firestore
[cloud-functions]: https://firebase.google.com/docs/functions [cloud-functions]: https://firebase.google.com/docs/functions
[small-prs]: https://google.github.io/eng-practices/review/developer/small-cls.html [small-prs]: https://google.github.io/eng-practices/review/developer/small-cls.html
[discord]: https://discord.gg/eHQBNBqXuh

View File

@ -34,9 +34,10 @@ Adapted from https://firebase.google.com/docs/functions/get-started
## Developing locally ## Developing locally
0. `$ firebase use dev` if you haven't already
1. `$ yarn serve` to spin up the emulators 1. `$ yarn serve` to spin up the emulators
The Emulator UI is at http://localhost:4000; the functions are hosted on :5001. 1. The Emulator UI is at http://localhost:4000; the functions are hosted on :5001.
Note: You have to kill and restart emulators when you change code; no hot reload =( Note: You have to kill and restart emulators when you change code; no hot reload =(
2. `$ yarn dev:emulate` in `/web` to connect to emulators with the frontend 2. `$ yarn dev:emulate` in `/web` to connect to emulators with the frontend
1. Note: emulated database is cleared after every shutdown 1. Note: emulated database is cleared after every shutdown

View File

@ -48,8 +48,8 @@ export const sendMarketResolutionEmail = async (
creatorName: creator.name, creatorName: creator.name,
question: contract.question, question: contract.question,
outcome, outcome,
investment: `${Math.round(investment)}`, investment: `${Math.floor(investment)}`,
payout: `${Math.round(payout)}`, payout: `${Math.floor(payout)}`,
url: `https://${DOMAIN}/${creator.username}/${contract.slug}`, url: `https://${DOMAIN}/${creator.username}/${contract.slug}`,
} }
@ -189,7 +189,9 @@ export const sendNewCommentEmail = async (
let betDescription = '' let betDescription = ''
if (bet) { if (bet) {
const { amount, sale } = bet const { amount, sale } = bet
betDescription = `${sale ? 'sold' : 'bought'} M$ ${Math.round(amount)}` betDescription = `${sale || amount < 0 ? 'sold' : 'bought'} ${formatMoney(
Math.abs(amount)
)}`
} }
const subject = `Comment on ${question}` const subject = `Comment on ${question}`

View File

@ -2,13 +2,15 @@
## Getting started ## Getting started
To run the development server, install [Yarn][yarn], and then in this directory: To run the development server, install [Yarn 1.x][yarn], and then in this directory:
1. `yarn` to install all dependencies 1. `yarn` to install all dependencies
2. `yarn dev:dev` starts a development web server, pointing at the development database 2. `yarn dev:dev` starts a development web server, pointing at the development database
3. Your site will be available on http://localhost:3000 3. Your site will be available on http://localhost:3000
Check package.json for other command-line tasks. (e.g. `yarn dev` will point the development server at the prod database. `yarn emulate` will run against a local emulated database, if you are serving it via `yarn serve` from the [`functions/` package][functions-readme].) Check package.json for other command-line tasks. (e.g. `yarn dev` will point the development server at the prod
database. `yarn emulate` will run against a local emulated database, if you are serving it via `yarn serve` from the
[`functions/` package][functions-readme].)
## Tech stack ## Tech stack
@ -24,16 +26,17 @@ branch (to production) and PR branches (to ephemeral staging servers that can be
Parts of the file structure that directly map to HTTP endpoints are organized specially per Next.js's prescriptions: Parts of the file structure that directly map to HTTP endpoints are organized specially per Next.js's prescriptions:
### /public ### public/
These are static files that will be [served by Next verbatim][next-static-files]. These are static files that will be [served by Next verbatim][next-static-files].
### /pages ### pages/
These are components that [Next's router][next-pages] is aware of and interprets as page roots per their filename, These are components that [Next's router][next-pages] is aware of and interprets as page roots per their filename,
e.g. the React component in pages/portfolio.tsx is rendered on the user portfolio page at /portfolio. e.g. the React component in pages/portfolio.tsx is rendered on the user portfolio page at /portfolio. You should
look in here or in `components/` to find any specific piece of UI you are interested in working on.
### /pages/api ### pages/api/
Modules under this route are specially interpreted by Next/Vercel as [functions that will be hosted by Modules under this route are specially interpreted by Next/Vercel as [functions that will be hosted by
Vercel][vercel-functions]. This is where the public Manifold HTTP API lives. Vercel][vercel-functions]. This is where the public Manifold HTTP API lives.
@ -52,7 +55,7 @@ integration][prettier-integrations] to format it in your editor.
[nextjs]: https://nextjs.org [nextjs]: https://nextjs.org
[vercel]: https://vercel.com [vercel]: https://vercel.com
[tailwind]: https://tailwindcss.com [tailwind]: https://tailwindcss.com
[yarn]: https://yarnpkg.com [yarn]: https://classic.yarnpkg.com/lang/en/docs/install/
[prettier]: https://prettier.io [prettier]: https://prettier.io
[prettier-integrations]: https://prettier.io/docs/en/editors.html [prettier-integrations]: https://prettier.io/docs/en/editors.html
[next-static-files]: https://nextjs.org/docs/basic-features/static-file-serving [next-static-files]: https://nextjs.org/docs/basic-features/static-file-serving

View File

@ -4,8 +4,11 @@ export function ProbabilitySelector(props: {
probabilityInt: number probabilityInt: number
setProbabilityInt: (p: number) => void setProbabilityInt: (p: number) => void
isSubmitting?: boolean isSubmitting?: boolean
minProb?: number
maxProb?: number
}) { }) {
const { probabilityInt, setProbabilityInt, isSubmitting } = props const { probabilityInt, setProbabilityInt, isSubmitting, minProb, maxProb } =
props
return ( return (
<Row className="items-center gap-2"> <Row className="items-center gap-2">
@ -15,19 +18,28 @@ export function ProbabilitySelector(props: {
value={probabilityInt} value={probabilityInt}
className="input input-bordered input-md text-lg" className="input input-bordered input-md text-lg"
disabled={isSubmitting} disabled={isSubmitting}
min={1} min={minProb ?? 1}
max={99} max={maxProb ?? 99}
onChange={(e) => onChange={(e) =>
setProbabilityInt(parseInt(e.target.value.substring(0, 2))) setProbabilityInt(parseInt(e.target.value.substring(0, 2)))
} }
onBlur={() =>
setProbabilityInt(
maxProb && probabilityInt > maxProb
? maxProb
: minProb && probabilityInt < minProb
? minProb
: probabilityInt
)
}
/> />
<span>%</span> <span>%</span>
</label> </label>
<input <input
type="range" type="range"
className="range range-primary" className="range range-primary"
min={1} min={minProb ?? 1}
max={99} max={maxProb ?? 99}
value={probabilityInt} value={probabilityInt}
onChange={(e) => setProbabilityInt(parseInt(e.target.value))} onChange={(e) => setProbabilityInt(parseInt(e.target.value))}
/> />

View File

@ -151,6 +151,10 @@ function getContractsActivityScores(
const activityCountScore = const activityCountScore =
0.5 + 0.5 * logInterpolation(0, 200, activtyCount) 0.5 + 0.5 * logInterpolation(0, 200, activtyCount)
const { volume7Days, volume } = contract
const combinedVolume = Math.log(volume7Days + 1) + Math.log(volume + 1)
const volumeScore = 0.5 + 0.5 * logInterpolation(4, 25, combinedVolume)
const lastBetTime = const lastBetTime =
contractMostRecentBet[contract.id]?.createdTime ?? contract.createdTime contractMostRecentBet[contract.id]?.createdTime ?? contract.createdTime
const timeSinceLastBet = Date.now() - lastBetTime const timeSinceLastBet = Date.now() - lastBetTime
@ -169,7 +173,11 @@ function getContractsActivityScores(
const probScore = 0.5 + frac * 0.5 const probScore = 0.5 + frac * 0.5
const score = const score =
newCommentScore * activityCountScore * timeAgoScore * probScore newCommentScore *
activityCountScore *
volumeScore *
timeAgoScore *
probScore
// Map score to [0.5, 1] since no recent activty is not a deal breaker. // Map score to [0.5, 1] since no recent activty is not a deal breaker.
const mappedScore = 0.5 + score / 2 const mappedScore = 0.5 + score / 2

View File

@ -106,11 +106,14 @@ export function NewContract(props: { question: string; tag?: string }) {
setIsSubmitting(true) setIsSubmitting(true)
const boundedProb =
initialProb > 90 ? 90 : initialProb < 10 ? 10 : initialProb
const result: any = await createContract({ const result: any = await createContract({
question, question,
outcomeType, outcomeType,
description, description,
initialProb, initialProb: boundedProb,
ante, ante,
closeTime, closeTime,
tags, tags,
@ -172,6 +175,8 @@ export function NewContract(props: { question: string; tag?: string }) {
<ProbabilitySelector <ProbabilitySelector
probabilityInt={initialProb} probabilityInt={initialProb}
setProbabilityInt={setInitialProb} setProbabilityInt={setInitialProb}
minProb={10}
maxProb={90}
/> />
</div> </div>
)} )}

View File

@ -1,20 +1,26 @@
import _ from 'lodash'
import { GetServerSideProps } from 'next' import { GetServerSideProps } from 'next'
import { getServerSideSitemap } from 'next-sitemap' import { getServerSideSitemap, ISitemapField } from 'next-sitemap'
import { DOMAIN } from '../../common/envs/constants' import { DOMAIN } from '../../common/envs/constants'
import { LiteMarket } from './api/v0/_types'
export const getServerSideProps: GetServerSideProps = async (ctx) => { export const getServerSideProps: GetServerSideProps = async (ctx) => {
// Fetching data from https://docs.manifold.markets/api // Fetching data from https://manifold.markets/api
const response = await fetch(`https://${DOMAIN}/api/v0/markets`) const response = await fetch(`https://${DOMAIN}/api/v0/markets`)
const liteMarkets = await response.json() const liteMarkets = (await response.json()) as LiteMarket[]
const fields = liteMarkets.map((liteMarket: any) => ({ const sortedMarkets = _.sortBy(liteMarkets, (m) => -m.volume24Hours)
const fields = sortedMarkets.map((market) => ({
// See https://www.sitemaps.org/protocol.html // See https://www.sitemaps.org/protocol.html
loc: liteMarket.url, loc: market.url,
changefreq: 'hourly', changefreq: market.volume24Hours > 10 ? 'hourly' : 'daily',
priority: 0.2, // Individual markets aren't that important priority: market.volume24Hours + market.volume7Days > 100 ? 0.7 : 0.1,
// TODO: Add `lastmod` aka last modified time // TODO: Add `lastmod` aka last modified time
})) })) as ISitemapField[]
return getServerSideSitemap(ctx, fields)
return await getServerSideSitemap(ctx, fields)
} }
// Default export to prevent next.js errors // Default export to prevent next.js errors

View File

@ -6,5 +6,5 @@ Allow: /
Host: https://manifold.markets Host: https://manifold.markets
# Sitemaps # Sitemaps
Sitemap: https://manifold.markets/sitemap.xml
Sitemap: https://manifold.markets/server-sitemap.xml Sitemap: https://manifold.markets/server-sitemap.xml
Sitemap: https://manifold.markets/sitemap.xml

View File

@ -1,19 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:mobile="http://www.google.com/schemas/sitemap-mobile/1.0" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1"> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:mobile="http://www.google.com/schemas/sitemap-mobile/1.0" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">
<url><loc>https://manifold.markets</loc><changefreq>hourly</changefreq><priority>0.7</priority><lastmod>2022-03-24T16:51:19.526Z</lastmod></url> <url><loc>https://manifold.markets</loc><changefreq>hourly</changefreq><priority>1.0</priority></url>
<url><loc>https://manifold.markets/about</loc><changefreq>hourly</changefreq><priority>0.7</priority><lastmod>2022-03-24T16:51:19.526Z</lastmod></url> <url><loc>https://manifold.markets/markets</loc><changefreq>hourly</changefreq><priority>0.2</priority></url>
<url><loc>https://manifold.markets/account</loc><changefreq>hourly</changefreq><priority>0.7</priority><lastmod>2022-03-24T16:51:19.526Z</lastmod></url> <url><loc>https://manifold.markets/leaderboards</loc><changefreq>daily</changefreq><priority>0.2</priority></url>
<url><loc>https://manifold.markets/add-funds</loc><changefreq>hourly</changefreq><priority>0.7</priority><lastmod>2022-03-24T16:51:19.526Z</lastmod></url>
<url><loc>https://manifold.markets/analytics</loc><changefreq>hourly</changefreq><priority>0.7</priority><lastmod>2022-03-24T16:51:19.526Z</lastmod></url>
<url><loc>https://manifold.markets/create</loc><changefreq>hourly</changefreq><priority>0.7</priority><lastmod>2022-03-24T16:51:19.526Z</lastmod></url>
<url><loc>https://manifold.markets/embed/analytics</loc><changefreq>hourly</changefreq><priority>0.7</priority><lastmod>2022-03-24T16:51:19.526Z</lastmod></url>
<url><loc>https://manifold.markets/folds</loc><changefreq>hourly</changefreq><priority>0.7</priority><lastmod>2022-03-24T16:51:19.526Z</lastmod></url>
<url><loc>https://manifold.markets/home</loc><changefreq>hourly</changefreq><priority>0.7</priority><lastmod>2022-03-24T16:51:19.526Z</lastmod></url>
<url><loc>https://manifold.markets/landing-page</loc><changefreq>hourly</changefreq><priority>0.7</priority><lastmod>2022-03-24T16:51:19.526Z</lastmod></url>
<url><loc>https://manifold.markets/leaderboards</loc><changefreq>hourly</changefreq><priority>0.7</priority><lastmod>2022-03-24T16:51:19.526Z</lastmod></url>
<url><loc>https://manifold.markets/make-predictions</loc><changefreq>hourly</changefreq><priority>0.7</priority><lastmod>2022-03-24T16:51:19.526Z</lastmod></url>
<url><loc>https://manifold.markets/markets</loc><changefreq>hourly</changefreq><priority>0.7</priority><lastmod>2022-03-24T16:51:19.526Z</lastmod></url>
<url><loc>https://manifold.markets/profile</loc><changefreq>hourly</changefreq><priority>0.7</priority><lastmod>2022-03-24T16:51:19.526Z</lastmod></url>
<url><loc>https://manifold.markets/simulator</loc><changefreq>hourly</changefreq><priority>0.7</priority><lastmod>2022-03-24T16:51:19.526Z</lastmod></url>
<url><loc>https://manifold.markets/portfolio</loc><changefreq>hourly</changefreq><priority>0.7</priority><lastmod>2022-03-24T16:51:19.526Z</lastmod></url>
</urlset> </urlset>