diff --git a/common/categories.ts b/common/categories.ts index 12788f53..9d290d66 100644 --- a/common/categories.ts +++ b/common/categories.ts @@ -1,21 +1,17 @@ export const CATEGORIES = { politics: 'Politics', technology: 'Technology', - sports: 'Sports', - gaming: 'Gaming', - manifold: 'Manifold', science: 'Science', world: 'World', - fun: 'Fun', - personal: 'Personal', + sports: 'Sports', economics: 'Economics', + personal: 'Personal', + culture: 'Culture', + manifold: 'Manifold', + covid: 'Covid', crypto: 'Crypto', - health: 'Health', - // entertainment: 'Entertainment', - // society: 'Society', - // friends: 'Friends / Community', - // business: 'Business', - // charity: 'Charities / Non-profits', + gaming: 'Gaming', + fun: 'Fun', } as { [category: string]: string } export const TO_CATEGORY = Object.fromEntries( diff --git a/common/envs/prod.ts b/common/envs/prod.ts index 20866429..01c33016 100644 --- a/common/envs/prod.ts +++ b/common/envs/prod.ts @@ -43,7 +43,7 @@ export const PROD_CONFIG: EnvConfig = { ], visibility: 'PUBLIC', - moneyMoniker: 'M$', + moneyMoniker: 'ϻ', navbarLogoPath: '', faviconPath: '/favicon.ico', newQuestionPlaceholders: [ diff --git a/common/new-contract.ts b/common/new-contract.ts index 764d32d3..f6b6829c 100644 --- a/common/new-contract.ts +++ b/common/new-contract.ts @@ -35,8 +35,6 @@ export function getNewContract( ? getBinaryCpmmProps(initialProb, ante) // getBinaryDpmProps(initialProb, ante) : getFreeAnswerProps(ante) - const volume = outcomeType === 'BINARY' ? 0 : ante - const contract: Contract = removeUndefinedProps({ id, slug, @@ -56,7 +54,7 @@ export function getNewContract( createdTime: Date.now(), closeTime, - volume, + volume: 0, volume24Hours: 0, volume7Days: 0, diff --git a/common/user.ts b/common/user.ts index 8713717d..b93ed4d6 100644 --- a/common/user.ts +++ b/common/user.ts @@ -35,4 +35,5 @@ export type PrivateUser = { unsubscribedFromGenericEmails?: boolean initialDeviceToken?: string initialIpAddress?: string + apiKey?: string } diff --git a/common/util/random.ts b/common/util/random.ts index 740379e5..3026dcde 100644 --- a/common/util/random.ts +++ b/common/util/random.ts @@ -1,7 +1,11 @@ -export const randomString = (length = 12) => - Math.random() - .toString(16) - .substring(2, length + 2) +// Returns a cryptographically random hexadecimal string of length `length` +// (thus containing 4*`length` bits of entropy). +export const randomString = (length = 12) => { + const bytes = new Uint8Array(Math.ceil(length / 2)) + crypto.getRandomValues(bytes) + const hex = bytes.reduce((s, b) => s + ('0' + b.toString(16)).slice(-2), '') + return hex.substring(0, length) +} export function genHash(str: string) { // xmur3 @@ -42,8 +46,6 @@ export function createRNG(seed: string) { export const shuffle = (array: any[], rand: () => number) => { for (let i = 0; i < array.length; i++) { const swapIndex = Math.floor(rand() * (array.length - i)) - const temp = array[i] - array[i] = array[swapIndex] - array[swapIndex] = temp + ;[array[i], array[swapIndex]] = [array[swapIndex], array[i]] } } diff --git a/firestore.rules b/firestore.rules index 24ab0941..feba35d9 100644 --- a/firestore.rules +++ b/firestore.rules @@ -21,6 +21,9 @@ service cloud.firestore { match /private-users/{userId} { allow read: if resource.data.id == request.auth.uid || isAdmin(); + allow update: if (resource.data.id == request.auth.uid || isAdmin()) + && request.resource.data.diff(resource.data).affectedKeys() + .hasOnly(['apiKey']); } match /private-users/{userId}/views/{viewId} { diff --git a/functions/src/add-liquidity.ts b/functions/src/add-liquidity.ts index 0fdf97c9..34d3f7c6 100644 --- a/functions/src/add-liquidity.ts +++ b/functions/src/add-liquidity.ts @@ -1,11 +1,11 @@ import * as functions from 'firebase-functions' import * as admin from 'firebase-admin' -import { Contract } from 'common/contract' -import { User } from 'common/user' -import { removeUndefinedProps } from 'common/util/object' +import { Contract } from '../../common/contract' +import { User } from '../../common/user' +import { removeUndefinedProps } from '../../common/util/object' import { redeemShares } from './redeem-shares' -import { getNewLiquidityProvision } from 'common/add-liquidity' +import { getNewLiquidityProvision } from '../../common/add-liquidity' export const addLiquidity = functions.runWith({ minInstances: 1 }).https.onCall( async ( diff --git a/functions/src/change-user-info.ts b/functions/src/change-user-info.ts index f85d45b3..ab15eb70 100644 --- a/functions/src/change-user-info.ts +++ b/functions/src/change-user-info.ts @@ -2,12 +2,12 @@ import * as functions from 'firebase-functions' import * as admin from 'firebase-admin' import { getUser } from './utils' -import { Contract } from 'common/contract' -import { Comment } from 'common/comment' -import { User } from 'common/user' -import { cleanUsername } from 'common/util/clean-username' -import { removeUndefinedProps } from 'common/util/object' -import { Answer } from 'common/answer' +import { Contract } from '../../common/contract' +import { Comment } from '../../common/comment' +import { User } from '../../common/user' +import { cleanUsername } from '../../common/util/clean-username' +import { removeUndefinedProps } from '../../common/util/object' +import { Answer } from '../../common/answer' export const changeUserInfo = functions .runWith({ minInstances: 1 }) diff --git a/functions/src/create-answer.ts b/functions/src/create-answer.ts index 45f42291..aa18351d 100644 --- a/functions/src/create-answer.ts +++ b/functions/src/create-answer.ts @@ -1,10 +1,15 @@ import * as functions from 'firebase-functions' import * as admin from 'firebase-admin' -import { Contract, DPM, FreeResponse, FullContract } from 'common/contract' -import { User } from 'common/user' -import { getNewMultiBetInfo } from 'common/new-bet' -import { Answer, MAX_ANSWER_LENGTH } from 'common/answer' +import { + Contract, + DPM, + FreeResponse, + FullContract, +} from '../../common/contract' +import { User } from '../../common/user' +import { getNewMultiBetInfo } from '../../common/new-bet' +import { Answer, MAX_ANSWER_LENGTH } from '../../common/answer' import { getContract, getValues } from './utils' import { sendNewAnswerEmail } from './emails' import { Bet } from '../../common/bet' diff --git a/functions/src/create-contract.ts b/functions/src/create-contract.ts index 5fa0c036..2ebe6e6c 100644 --- a/functions/src/create-contract.ts +++ b/functions/src/create-contract.ts @@ -14,10 +14,10 @@ import { MAX_QUESTION_LENGTH, MAX_TAG_LENGTH, outcomeType, -} from 'common/contract' -import { slugify } from 'common/util/slugify' -import { randomString } from 'common/util/random' -import { getNewContract } from 'common/new-contract' +} from '../../common/contract' +import { slugify } from '../../common/util/slugify' +import { randomString } from '../../common/util/random' +import { getNewContract } from '../../common/new-contract' import { FIXED_ANTE, getAnteBets, @@ -25,8 +25,8 @@ import { getFreeAnswerAnte, HOUSE_LIQUIDITY_PROVIDER_ID, MINIMUM_ANTE, -} from 'common/antes' -import { getNoneAnswer } from 'common/answer' +} from '../../common/antes' +import { getNoneAnswer } from '../../common/answer' export const createContract = functions .runWith({ minInstances: 1 }) diff --git a/functions/src/create-fold.ts b/functions/src/create-fold.ts index 5cf40b22..36d1d269 100644 --- a/functions/src/create-fold.ts +++ b/functions/src/create-fold.ts @@ -3,10 +3,10 @@ import * as admin from 'firebase-admin' import * as _ from 'lodash' import { getUser } from './utils' -import { Contract } from 'common/contract' -import { slugify } from 'common/util/slugify' -import { randomString } from 'common/util/random' -import { Fold } from 'common/fold' +import { Contract } from '../../common/contract' +import { slugify } from '../../common/util/slugify' +import { randomString } from '../../common/util/random' +import { Fold } from '../../common/fold' export const createFold = functions.runWith({ minInstances: 1 }).https.onCall( async ( diff --git a/functions/src/create-user.ts b/functions/src/create-user.ts index dd2b5275..fdbb0edd 100644 --- a/functions/src/create-user.ts +++ b/functions/src/create-user.ts @@ -6,12 +6,15 @@ import { STARTING_BALANCE, SUS_STARTING_BALANCE, User, -} from 'common/user' +} from '../../common/user' import { getUser, getUserByUsername } from './utils' -import { randomString } from 'common/util/random' -import { cleanDisplayName, cleanUsername } from 'common/util/clean-username' +import { randomString } from '../../common/util/random' +import { + cleanDisplayName, + cleanUsername, +} from '../../common/util/clean-username' import { sendWelcomeEmail } from './emails' -import { isWhitelisted } from 'common/envs/constants' +import { isWhitelisted } from '../../common/envs/constants' export const createUser = functions .runWith({ minInstances: 1 }) @@ -39,8 +42,7 @@ export const createUser = functions const name = cleanDisplayName(rawName) let username = cleanUsername(name) - const sameNameUser = await getUserByUsername(username) - if (sameNameUser) { + while (await getUserByUsername(username)) { username += randomString(4) } diff --git a/functions/src/email-templates/thank-you.html b/functions/src/email-templates/thank-you.html index e6217334..ec426fb9 100644 --- a/functions/src/email-templates/thank-you.html +++ b/functions/src/email-templates/thank-you.html @@ -302,7 +302,7 @@ font-family: Arial, sans-serif; font-size: 18px; " - >Best of luck with you forecasting!Best of luck with your forecasting!

{ return await firestore.runTransaction(async (transaction) => { diff --git a/functions/src/resolve-market.ts b/functions/src/resolve-market.ts index ac9eb7a0..0ef416a7 100644 --- a/functions/src/resolve-market.ts +++ b/functions/src/resolve-market.ts @@ -2,9 +2,9 @@ import * as functions from 'firebase-functions' import * as admin from 'firebase-admin' import * as _ from 'lodash' -import { Contract } from 'common/contract' -import { User } from 'common/user' -import { Bet } from 'common/bet' +import { Contract } from '../../common/contract' +import { User } from '../../common/user' +import { Bet } from '../../common/bet' import { getUser, isProd, payUser } from './utils' import { sendMarketResolutionEmail } from './emails' import { @@ -12,9 +12,9 @@ import { getPayouts, groupPayoutsByUser, Payout, -} from 'common/payouts' -import { removeUndefinedProps } from 'common/util/object' -import { LiquidityProvision } from 'common/liquidity-provision' +} from '../../common/payouts' +import { removeUndefinedProps } from '../../common/util/object' +import { LiquidityProvision } from '../../common/liquidity-provision' export const resolveMarket = functions .runWith({ minInstances: 1 }) diff --git a/functions/src/scripts/cache-views.ts b/functions/src/scripts/cache-views.ts index c7ed661f..c7145a1e 100644 --- a/functions/src/scripts/cache-views.ts +++ b/functions/src/scripts/cache-views.ts @@ -5,9 +5,9 @@ import { initAdmin } from './script-init' initAdmin() import { getValues } from '../utils' -import { View } from 'common/tracking' -import { User } from 'common/user' -import { batchedWaitAll } from 'common/util/promise' +import { View } from '../../../common/tracking' +import { User } from '../../../common/user' +import { batchedWaitAll } from '../../../common/util/promise' const firestore = admin.firestore() diff --git a/functions/src/scripts/correct-bet-probability.ts b/functions/src/scripts/correct-bet-probability.ts index e65b4ddf..3b57dbeb 100644 --- a/functions/src/scripts/correct-bet-probability.ts +++ b/functions/src/scripts/correct-bet-probability.ts @@ -4,9 +4,9 @@ import * as _ from 'lodash' import { initAdmin } from './script-init' initAdmin() -import { Bet } from 'common/bet' -import { getDpmProbability } from 'common/calculate-dpm' -import { Binary, Contract, DPM, FullContract } from 'common/contract' +import { Bet } from '../../../common/bet' +import { getDpmProbability } from '../../../common/calculate-dpm' +import { Binary, Contract, DPM, FullContract } from '../../../common/contract' type DocRef = admin.firestore.DocumentReference const firestore = admin.firestore() diff --git a/functions/src/scripts/create-private-users.ts b/functions/src/scripts/create-private-users.ts index a83bb53e..8051a447 100644 --- a/functions/src/scripts/create-private-users.ts +++ b/functions/src/scripts/create-private-users.ts @@ -4,7 +4,7 @@ import * as _ from 'lodash' import { initAdmin } from './script-init' initAdmin() -import { PrivateUser, STARTING_BALANCE, User } from 'common/user' +import { PrivateUser, STARTING_BALANCE, User } from '../../../common/user' const firestore = admin.firestore() diff --git a/functions/src/scripts/get-json-dump.ts b/functions/src/scripts/get-json-dump.ts index 3027ce45..b9909132 100644 --- a/functions/src/scripts/get-json-dump.ts +++ b/functions/src/scripts/get-json-dump.ts @@ -5,10 +5,10 @@ import * as fs from 'fs' import { initAdmin } from './script-init' initAdmin() -import { Bet } from 'common/bet' -import { Contract } from 'common/contract' +import { Bet } from '../../../common/bet' +import { Contract } from '../../../common/contract' import { getValues } from '../utils' -import { Comment } from 'common/comment' +import { Comment } from '../../../common/comment' const firestore = admin.firestore() diff --git a/functions/src/scripts/lowercase-fold-tags.ts b/functions/src/scripts/lowercase-fold-tags.ts index f5d01bfe..80b79a33 100644 --- a/functions/src/scripts/lowercase-fold-tags.ts +++ b/functions/src/scripts/lowercase-fold-tags.ts @@ -5,7 +5,7 @@ import { initAdmin } from './script-init' initAdmin() import { getValues } from '../utils' -import { Fold } from 'common/fold' +import { Fold } from '../../../common/fold' async function lowercaseFoldTags() { const firestore = admin.firestore() diff --git a/functions/src/scripts/make-contracts-public.ts b/functions/src/scripts/make-contracts-public.ts index 5d958f13..19d2e196 100644 --- a/functions/src/scripts/make-contracts-public.ts +++ b/functions/src/scripts/make-contracts-public.ts @@ -4,7 +4,7 @@ import * as _ from 'lodash' import { initAdmin } from './script-init' initAdmin() -import { Contract } from 'common/contract' +import { Contract } from '../../../common/contract' const firestore = admin.firestore() diff --git a/functions/src/scripts/migrate-contract.ts b/functions/src/scripts/migrate-contract.ts index 7127f371..718cf62e 100644 --- a/functions/src/scripts/migrate-contract.ts +++ b/functions/src/scripts/migrate-contract.ts @@ -4,8 +4,8 @@ import * as _ from 'lodash' import { initAdmin } from './script-init' initAdmin() -import { Bet } from 'common/bet' -import { Contract } from 'common/contract' +import { Bet } from '../../../common/bet' +import { Contract } from '../../../common/contract' type DocRef = admin.firestore.DocumentReference diff --git a/functions/src/scripts/migrate-to-cfmm.ts b/functions/src/scripts/migrate-to-cfmm.ts index 9dd8c63e..874011ca 100644 --- a/functions/src/scripts/migrate-to-cfmm.ts +++ b/functions/src/scripts/migrate-to-cfmm.ts @@ -4,13 +4,22 @@ import * as _ from 'lodash' import { initAdmin } from './script-init' initAdmin() -import { Binary, Contract, CPMM, DPM, FullContract } from 'common/contract' -import { Bet } from 'common/bet' -import { calculateDpmPayout, getDpmProbability } from 'common/calculate-dpm' -import { User } from 'common/user' -import { getCpmmInitialLiquidity } from 'common/antes' -import { noFees } from 'common/fees' -import { addObjects } from 'common/util/object' +import { + Binary, + Contract, + CPMM, + DPM, + FullContract, +} from '../../../common/contract' +import { Bet } from '../../../common/bet' +import { + calculateDpmPayout, + getDpmProbability, +} from '../../../common/calculate-dpm' +import { User } from '../../../common/user' +import { getCpmmInitialLiquidity } from '../../../common/antes' +import { noFees } from '../../../common/fees' +import { addObjects } from '../../../common/util/object' type DocRef = admin.firestore.DocumentReference diff --git a/functions/src/scripts/migrate-to-dpm-2.ts b/functions/src/scripts/migrate-to-dpm-2.ts index 81e99d98..2c6f066f 100644 --- a/functions/src/scripts/migrate-to-dpm-2.ts +++ b/functions/src/scripts/migrate-to-dpm-2.ts @@ -4,11 +4,14 @@ import * as _ from 'lodash' import { initAdmin } from './script-init' initAdmin() -import { Binary, Contract, DPM, FullContract } from 'common/contract' -import { Bet } from 'common/bet' -import { calculateDpmShares, getDpmProbability } from 'common/calculate-dpm' -import { getSellBetInfo } from 'common/sell-bet' -import { User } from 'common/user' +import { Binary, Contract, DPM, FullContract } from '../../../common/contract' +import { Bet } from '../../../common/bet' +import { + calculateDpmShares, + getDpmProbability, +} from '../../../common/calculate-dpm' +import { getSellBetInfo } from '../../../common/sell-bet' +import { User } from '../../../common/user' type DocRef = admin.firestore.DocumentReference diff --git a/functions/src/scripts/pay-out-contract-again.ts b/functions/src/scripts/pay-out-contract-again.ts index 68f982cd..916b9efb 100644 --- a/functions/src/scripts/pay-out-contract-again.ts +++ b/functions/src/scripts/pay-out-contract-again.ts @@ -4,10 +4,10 @@ import * as _ from 'lodash' import { initAdmin } from './script-init' initAdmin() -import { Bet } from 'common/bet' -import { Contract } from 'common/contract' -import { getLoanPayouts, getPayouts } from 'common/payouts' -import { filterDefined } from 'common/util/array' +import { Bet } from '../../../common/bet' +import { Contract } from '../../../common/contract' +import { getLoanPayouts, getPayouts } from '../../../common/payouts' +import { filterDefined } from '../../../common/util/array' type DocRef = admin.firestore.DocumentReference diff --git a/functions/src/scripts/recalculate-contract-totals.ts b/functions/src/scripts/recalculate-contract-totals.ts index 91165781..39942542 100644 --- a/functions/src/scripts/recalculate-contract-totals.ts +++ b/functions/src/scripts/recalculate-contract-totals.ts @@ -4,8 +4,8 @@ import * as _ from 'lodash' import { initAdmin } from './script-init' initAdmin() -import { Bet } from 'common/bet' -import { Contract } from 'common/contract' +import { Bet } from '../../../common/bet' +import { Contract } from '../../../common/contract' type DocRef = admin.firestore.DocumentReference diff --git a/functions/src/scripts/remove-answer-ante.ts b/functions/src/scripts/remove-answer-ante.ts index 8b026174..eb49af6c 100644 --- a/functions/src/scripts/remove-answer-ante.ts +++ b/functions/src/scripts/remove-answer-ante.ts @@ -4,8 +4,8 @@ import * as _ from 'lodash' import { initAdmin } from './script-init' initAdmin() -import { Bet } from 'common/bet' -import { Contract } from 'common/contract' +import { Bet } from '../../../common/bet' +import { Contract } from '../../../common/contract' import { getValues } from '../utils' async function removeAnswerAnte() { diff --git a/functions/src/scripts/rename-user-contracts.ts b/functions/src/scripts/rename-user-contracts.ts index bcb4fea6..9b0f569b 100644 --- a/functions/src/scripts/rename-user-contracts.ts +++ b/functions/src/scripts/rename-user-contracts.ts @@ -4,7 +4,7 @@ import * as _ from 'lodash' import { initAdmin } from './script-init' initAdmin() -import { Contract } from 'common/contract' +import { Contract } from '../../../common/contract' import { getValues } from '../utils' const firestore = admin.firestore() diff --git a/functions/src/scripts/update-contract-tags.ts b/functions/src/scripts/update-contract-tags.ts index 7e671c9f..1dda5615 100644 --- a/functions/src/scripts/update-contract-tags.ts +++ b/functions/src/scripts/update-contract-tags.ts @@ -4,8 +4,8 @@ import * as _ from 'lodash' import { initAdmin } from './script-init' initAdmin() -import { Contract } from 'common/contract' -import { parseTags } from 'common/util/parse' +import { Contract } from '../../../common/contract' +import { parseTags } from '../../../common/util/parse' import { getValues } from '../utils' async function updateContractTags() { diff --git a/functions/src/scripts/update-feed.ts b/functions/src/scripts/update-feed.ts index d698a529..fee7398d 100644 --- a/functions/src/scripts/update-feed.ts +++ b/functions/src/scripts/update-feed.ts @@ -5,9 +5,9 @@ import { initAdmin } from './script-init' initAdmin() import { getValues } from '../utils' -import { User } from 'common/user' -import { batchedWaitAll } from 'common/util/promise' -import { Contract } from 'common/contract' +import { User } from '../../../common/user' +import { batchedWaitAll } from '../../../common/util/promise' +import { Contract } from '../../../common/contract' import { updateWordScores } from '../update-recommendations' import { computeFeed } from '../update-feed' import { getFeedContracts, getTaggedContracts } from '../get-feed-data' diff --git a/functions/src/scripts/update-last-comment-time.ts b/functions/src/scripts/update-last-comment-time.ts index 99d7f52d..ae950fbe 100644 --- a/functions/src/scripts/update-last-comment-time.ts +++ b/functions/src/scripts/update-last-comment-time.ts @@ -4,9 +4,9 @@ import * as _ from 'lodash' import { initAdmin } from './script-init' initAdmin() -import { Contract } from 'common/contract' +import { Contract } from '../../../common/contract' import { getValues } from '../utils' -import { Comment } from 'common/comment' +import { Comment } from '../../../common/comment' async function updateLastCommentTime() { const firestore = admin.firestore() diff --git a/functions/src/sell-bet.ts b/functions/src/sell-bet.ts index c685498b..fff88716 100644 --- a/functions/src/sell-bet.ts +++ b/functions/src/sell-bet.ts @@ -1,12 +1,12 @@ import * as admin from 'firebase-admin' import * as functions from 'firebase-functions' -import { Contract } from 'common/contract' -import { User } from 'common/user' -import { Bet } from 'common/bet' -import { getSellBetInfo } from 'common/sell-bet' -import { addObjects, removeUndefinedProps } from 'common/util/object' -import { Fees } from 'common/fees' +import { Contract } from '../../common/contract' +import { User } from '../../common/user' +import { Bet } from '../../common/bet' +import { getSellBetInfo } from '../../common/sell-bet' +import { addObjects, removeUndefinedProps } from '../../common/util/object' +import { Fees } from '../../common/fees' export const sellBet = functions.runWith({ minInstances: 1 }).https.onCall( async ( diff --git a/functions/src/sell-shares.ts b/functions/src/sell-shares.ts index 158a5f6a..e4dbcbc9 100644 --- a/functions/src/sell-shares.ts +++ b/functions/src/sell-shares.ts @@ -2,12 +2,12 @@ import * as _ from 'lodash' import * as admin from 'firebase-admin' import * as functions from 'firebase-functions' -import { Binary, CPMM, FullContract } from 'common/contract' -import { User } from 'common/user' -import { getCpmmSellBetInfo } from 'common/sell-bet' -import { addObjects, removeUndefinedProps } from 'common/util/object' +import { Binary, CPMM, FullContract } from '../../common/contract' +import { User } from '../../common/user' +import { getCpmmSellBetInfo } from '../../common/sell-bet' +import { addObjects, removeUndefinedProps } from '../../common/util/object' import { getValues } from './utils' -import { Bet } from 'common/bet' +import { Bet } from '../../common/bet' export const sellShares = functions.runWith({ minInstances: 1 }).https.onCall( async ( diff --git a/functions/src/stripe.ts b/functions/src/stripe.ts index c428ca88..a52b0fae 100644 --- a/functions/src/stripe.ts +++ b/functions/src/stripe.ts @@ -54,7 +54,7 @@ export const createCheckoutSession = functions } const referrer = - req.query.referer || req.headers.referer || 'https://mantic.markets' + req.query.referer || req.headers.referer || 'https://manifold.markets' const session = await stripe.checkout.sessions.create({ metadata: { diff --git a/functions/src/transact.ts b/functions/src/transact.ts index 77323638..79b5ccb8 100644 --- a/functions/src/transact.ts +++ b/functions/src/transact.ts @@ -1,9 +1,9 @@ import * as functions from 'firebase-functions' import * as admin from 'firebase-admin' -import { User } from 'common/user' -import { Txn } from 'common/txn' -import { removeUndefinedProps } from 'common/util/object' +import { User } from '../../common/user' +import { Txn } from '../../common/txn' +import { removeUndefinedProps } from '../../common/util/object' export const transact = functions .runWith({ minInstances: 1 }) diff --git a/functions/src/unsubscribe.ts b/functions/src/unsubscribe.ts index c2981358..317cf61e 100644 --- a/functions/src/unsubscribe.ts +++ b/functions/src/unsubscribe.ts @@ -2,7 +2,7 @@ import * as functions from 'firebase-functions' import * as admin from 'firebase-admin' import * as _ from 'lodash' import { getUser } from './utils' -import { PrivateUser } from 'common/user' +import { PrivateUser } from '../../common/user' export const unsubscribe = functions .runWith({ minInstances: 1 }) diff --git a/functions/src/update-contract-metrics.ts b/functions/src/update-contract-metrics.ts index 9214d2dc..c3801df6 100644 --- a/functions/src/update-contract-metrics.ts +++ b/functions/src/update-contract-metrics.ts @@ -3,9 +3,9 @@ import * as admin from 'firebase-admin' import * as _ from 'lodash' import { getValues } from './utils' -import { Contract } from 'common/contract' -import { Bet } from 'common/bet' -import { batchedWaitAll } from 'common/util/promise' +import { Contract } from '../../common/contract' +import { Bet } from '../../common/bet' +import { batchedWaitAll } from '../../common/util/promise' const firestore = admin.firestore() diff --git a/functions/src/update-feed.ts b/functions/src/update-feed.ts index c9d2def8..3c497b1f 100644 --- a/functions/src/update-feed.ts +++ b/functions/src/update-feed.ts @@ -3,9 +3,9 @@ import * as functions from 'firebase-functions' import * as admin from 'firebase-admin' import { getValue, getValues } from './utils' -import { Contract } from 'common/contract' -import { logInterpolation } from 'common/util/math' -import { DAY_MS } from 'common/util/time' +import { Contract } from '../../common/contract' +import { logInterpolation } from '../../common/util/math' +import { DAY_MS } from '../../common/util/time' import { getProbability, getOutcomeProbability, @@ -15,7 +15,7 @@ import { User } from '../../common/user' import { getContractScore, MAX_FEED_CONTRACTS, -} from 'common/recommended-contracts' +} from '../../common/recommended-contracts' import { callCloudFunction } from './call-cloud-function' import { getFeedContracts, @@ -26,18 +26,25 @@ import { CATEGORY_LIST } from '../../common/categories' const firestore = admin.firestore() +const BATCH_SIZE = 30 +const MAX_BATCHES = 50 + +const getUserBatches = async () => { + const users = _.shuffle(await getValues(firestore.collection('users'))) + let userBatches: User[][] = [] + for (let i = 0; i < users.length; i += BATCH_SIZE) { + userBatches.push(users.slice(i, i + BATCH_SIZE)) + } + + console.log('updating feed batches', MAX_BATCHES, 'of', userBatches.length) + + return userBatches.slice(0, MAX_BATCHES) +} + export const updateFeed = functions.pubsub - .schedule('every 60 minutes') + .schedule('every 5 minutes') .onRun(async () => { - const users = await getValues(firestore.collection('users')) - - const batchSize = 100 - let userBatches: User[][] = [] - for (let i = 0; i < users.length; i += batchSize) { - userBatches.push(users.slice(i, i + batchSize)) - } - - console.log('updating feed batch') + const userBatches = await getUserBatches() await Promise.all( userBatches.map((users) => @@ -72,13 +79,7 @@ export const updateFeedBatch = functions.https.onCall( export const updateCategoryFeed = functions.https.onCall( async (data: { category: string }) => { const { category } = data - const users = await getValues(firestore.collection('users')) - - const batchSize = 100 - const userBatches: User[][] = [] - for (let i = 0; i < users.length; i += batchSize) { - userBatches.push(users.slice(i, i + batchSize)) - } + const userBatches = await getUserBatches() await Promise.all( userBatches.map(async (users) => { diff --git a/functions/src/update-recommendations.ts b/functions/src/update-recommendations.ts index e18e7c0e..4e656dda 100644 --- a/functions/src/update-recommendations.ts +++ b/functions/src/update-recommendations.ts @@ -3,12 +3,12 @@ import * as admin from 'firebase-admin' import * as _ from 'lodash' import { getValue, getValues } from './utils' -import { Contract } from 'common/contract' -import { Bet } from 'common/bet' -import { User } from 'common/user' -import { ClickEvent } from 'common/tracking' -import { getWordScores } from 'common/recommended-contracts' -import { batchedWaitAll } from 'common/util/promise' +import { Contract } from '../../common/contract' +import { Bet } from '../../common/bet' +import { User } from '../../common/user' +import { ClickEvent } from '../../common/tracking' +import { getWordScores } from '../../common/recommended-contracts' +import { batchedWaitAll } from '../../common/util/promise' import { callCloudFunction } from './call-cloud-function' const firestore = admin.firestore() diff --git a/functions/src/update-user-metrics.ts b/functions/src/update-user-metrics.ts index 6f755622..70fd1bc5 100644 --- a/functions/src/update-user-metrics.ts +++ b/functions/src/update-user-metrics.ts @@ -3,11 +3,11 @@ import * as admin from 'firebase-admin' import * as _ from 'lodash' import { getValues } from './utils' -import { Contract } from 'common/contract' -import { Bet } from 'common/bet' -import { User } from 'common/user' -import { batchedWaitAll } from 'common/util/promise' -import { calculatePayout } from 'common/calculate' +import { Contract } from '../../common/contract' +import { Bet } from '../../common/bet' +import { User } from '../../common/user' +import { batchedWaitAll } from '../../common/util/promise' +import { calculatePayout } from '../../common/calculate' const firestore = admin.firestore() diff --git a/functions/src/utils.ts b/functions/src/utils.ts index d06b6ef2..c0f92f94 100644 --- a/functions/src/utils.ts +++ b/functions/src/utils.ts @@ -1,7 +1,7 @@ import * as admin from 'firebase-admin' -import { Contract } from 'common/contract' -import { PrivateUser, User } from 'common/user' +import { Contract } from '../../common/contract' +import { PrivateUser, User } from '../../common/user' export const isProd = admin.instanceId().app.options.projectId === 'mantic-markets' diff --git a/web/components/answers/answer-bet-panel.tsx b/web/components/answers/answer-bet-panel.tsx index ab4c9600..8c424bea 100644 --- a/web/components/answers/answer-bet-panel.tsx +++ b/web/components/answers/answer-bet-panel.tsx @@ -1,5 +1,4 @@ import clsx from 'clsx' -import _ from 'lodash' import { useEffect, useRef, useState } from 'react' import { XIcon } from '@heroicons/react/solid' diff --git a/web/components/answers/answer-item.tsx b/web/components/answers/answer-item.tsx index 55351083..602c9d2e 100644 --- a/web/components/answers/answer-item.tsx +++ b/web/components/answers/answer-item.tsx @@ -1,5 +1,4 @@ import clsx from 'clsx' -import _ from 'lodash' import { Answer } from 'common/answer' import { DPM, FreeResponse, FullContract } from 'common/contract' diff --git a/web/components/answers/create-answer-panel.tsx b/web/components/answers/create-answer-panel.tsx index 2075b60d..eefae83a 100644 --- a/web/components/answers/create-answer-panel.tsx +++ b/web/components/answers/create-answer-panel.tsx @@ -1,5 +1,4 @@ import clsx from 'clsx' -import _ from 'lodash' import { useState } from 'react' import Textarea from 'react-expanding-textarea' diff --git a/web/components/bet-panel.tsx b/web/components/bet-panel.tsx index 8fba3bf7..e02e14d0 100644 --- a/web/components/bet-panel.tsx +++ b/web/components/bet-panel.tsx @@ -321,11 +321,11 @@ function BuyPanel(props: {

Probability
- -
{formatPercent(initialProb)}
-
-
{formatPercent(resultProb)}
-
+
+ {formatPercent(initialProb)} + + {formatPercent(resultProb)} +
@@ -350,12 +350,12 @@ function BuyPanel(props: { {dpmTooltip && } - - +
+ {formatMoney(currentPayout)} - (+{currentReturnPercent}) - + (+{currentReturnPercent}) +
@@ -459,11 +459,11 @@ export function SellPanel(props: {
Probability
- -
{formatPercent(initialProb)}
-
-
{formatPercent(resultProb)}
-
+
+ {formatPercent(initialProb)} + + {formatPercent(resultProb)} +
diff --git a/web/components/bet-row.tsx b/web/components/bet-row.tsx index 29493473..bd1633cc 100644 --- a/web/components/bet-row.tsx +++ b/web/components/bet-row.tsx @@ -2,7 +2,6 @@ import { useState } from 'react' import clsx from 'clsx' import { BetPanelSwitcher } from './bet-panel' -import { Row } from './layout/row' import { YesNoSelector } from './yes-no-selector' import { Binary, CPMM, DPM, FullContract } from 'common/contract' import { Modal } from './layout/modal' diff --git a/web/components/contract-search.tsx b/web/components/contract-search.tsx index c4308fc0..d6127286 100644 --- a/web/components/contract-search.tsx +++ b/web/components/contract-search.tsx @@ -17,7 +17,7 @@ import { } from '../hooks/use-sort-and-query-params' import { ContractsGrid } from './contract/contracts-list' import { Row } from './layout/row' -import { useEffect, useState } from 'react' +import { useEffect, useRef, useState } from 'react' import { Spacer } from './layout/spacer' import { useRouter } from 'next/router' import { ENV } from 'common/envs/constants' @@ -143,7 +143,13 @@ export function ContractSearchInner(props: { setQuery(query) }, [query]) + const isFirstRender = useRef(true) useEffect(() => { + if (isFirstRender.current) { + isFirstRender.current = false + return + } + const sort = index.split('contracts-')[1] as Sort if (sort) { setSort(sort) diff --git a/web/components/contract/contract-card.tsx b/web/components/contract/contract-card.tsx index d1c7dd31..71e3ddbd 100644 --- a/web/components/contract/contract-card.tsx +++ b/web/components/contract/contract-card.tsx @@ -1,6 +1,5 @@ import clsx from 'clsx' import Link from 'next/link' -import _ from 'lodash' import { Row } from '../layout/row' import { formatPercent } from 'common/util/format' import { @@ -9,7 +8,6 @@ import { getBinaryProbPercent, } from 'web/lib/firebase/contracts' import { Col } from '../layout/col' -import { Spacer } from '../layout/spacer' import { Binary, CPMM, @@ -25,6 +23,8 @@ import { } from '../outcome-label' import { getOutcomeProbability, getTopAnswer } from 'common/calculate' import { AbbrContractDetails } from './contract-details' +import { TagsList } from '../tags-list' +import { CATEGORY_LIST } from 'common/categories' export function ContractCard(props: { contract: Contract @@ -35,11 +35,16 @@ export function ContractCard(props: { const { contract, showHotVolume, showCloseTime, className } = props const { question, outcomeType, resolution } = contract + const { tags } = contract + const categories = tags.filter((tag) => + CATEGORY_LIST.includes(tag.toLowerCase()) + ) + return (
-
@@ -52,35 +57,39 @@ export function ContractCard(props: { showHotVolume={showHotVolume} showCloseTime={showCloseTime} /> - - -

- {question} -

+ + +

+ {question} +

+ {outcomeType !== 'FREE_RESPONSE' && categories.length > 0 && ( + + )} + {outcomeType === 'BINARY' && ( )} - {outcomeType === 'FREE_RESPONSE' && ( - } - truncate="long" - /> - )}
-
+ + {outcomeType === 'FREE_RESPONSE' && ( + } + truncate="long" + /> + )} + + {outcomeType === 'FREE_RESPONSE' && categories.length > 0 && ( + + )} +
) } diff --git a/web/components/contract/contract-description.tsx b/web/components/contract/contract-description.tsx index dd748f50..d8b657cb 100644 --- a/web/components/contract/contract-description.tsx +++ b/web/components/contract/contract-description.tsx @@ -39,7 +39,9 @@ export function ContractDescription(props: { if (!isCreator && !contract.description.trim()) return null const { tags } = contract - const category = tags.find((tag) => CATEGORY_LIST.includes(tag.toLowerCase())) + const categories = tags.filter((tag) => + CATEGORY_LIST.includes(tag.toLowerCase()) + ) return (
- {category && ( + {categories.length > 0 && (
- +
)} diff --git a/web/components/contract/contract-details.tsx b/web/components/contract/contract-details.tsx index 21849cc4..f4619e26 100644 --- a/web/components/contract/contract-details.tsx +++ b/web/components/contract/contract-details.tsx @@ -1,5 +1,4 @@ import clsx from 'clsx' -import _ from 'lodash' import { ClockIcon, DatabaseIcon, PencilIcon } from '@heroicons/react/outline' import { TrendingUpIcon } from '@heroicons/react/solid' import { Row } from '../layout/row' diff --git a/web/components/contract/contracts-list.tsx b/web/components/contract/contracts-list.tsx index 49431744..2ce43daf 100644 --- a/web/components/contract/contracts-list.tsx +++ b/web/components/contract/contracts-list.tsx @@ -1,5 +1,3 @@ -import _ from 'lodash' - import { Contract } from '../../lib/firebase/contracts' import { User } from '../../lib/firebase/users' import { Col } from '../layout/col' diff --git a/web/components/feed/activity-feed.tsx b/web/components/feed/activity-feed.tsx index 15c7c662..3b53ee73 100644 --- a/web/components/feed/activity-feed.tsx +++ b/web/components/feed/activity-feed.tsx @@ -1,5 +1,3 @@ -import _ from 'lodash' - import { Contract } from 'web/lib/firebase/contracts' import { Comment } from 'web/lib/firebase/comments' import { Col } from '../layout/col' diff --git a/web/components/feed/category-selector.tsx b/web/components/feed/category-selector.tsx index fc51ddc6..4b3215d9 100644 --- a/web/components/feed/category-selector.tsx +++ b/web/components/feed/category-selector.tsx @@ -1,51 +1,43 @@ import clsx from 'clsx' -import _ from 'lodash' import { User } from '../../../common/user' import { Row } from '../layout/row' import { CATEGORIES, CATEGORY_LIST } from '../../../common/categories' -import { updateUser } from '../../lib/firebase/users' export function CategorySelector(props: { user: User | null | undefined + category: string + setCategory: (category: string) => void className?: string }) { - const { className, user } = props - - const followedCategories = user?.followedCategories ?? [] + const { className, user, category, setCategory } = props return (
{ if (!user?.id) return - - await updateUser(user.id, { - followedCategories: [], - }) + setCategory('all') }} /> {CATEGORY_LIST.map((cat) => ( { if (!user?.id) return - - await updateUser(user.id, { - followedCategories: [cat], - }) + setCategory(cat) }} /> ))} @@ -63,7 +55,7 @@ function CategoryButton(props: { return (
@@ -991,6 +991,12 @@ function FeedAnswerGroup(props: { /> + {type == 'answer' && ( +
+ )}
@@ -1023,9 +1029,7 @@ function FeedAnswerGroup(props: { {probPercent} diff --git a/web/components/nav/nav-bar.tsx b/web/components/nav/nav-bar.tsx index f92f6630..cab369fb 100644 --- a/web/components/nav/nav-bar.tsx +++ b/web/components/nav/nav-bar.tsx @@ -137,7 +137,7 @@ export function MobileSidebar(props: {
- +
diff --git a/web/components/nav/profile-menu.tsx b/web/components/nav/profile-menu.tsx index b25603d4..0082e4ca 100644 --- a/web/components/nav/profile-menu.tsx +++ b/web/components/nav/profile-menu.tsx @@ -1,8 +1,8 @@ +import Link from 'next/link' import { firebaseLogout, User } from 'web/lib/firebase/users' import { formatMoney } from 'common/util/format' import { Avatar } from '../avatar' import { IS_PRIVATE_MANIFOLD } from 'common/envs/constants' -import { Row } from '../layout/row' export function getNavigationOptions(user?: User | null) { if (IS_PRIVATE_MANIFOLD) { @@ -27,18 +27,18 @@ export function getNavigationOptions(user?: User | null) { ] } -export function ProfileSummary(props: { user: User | undefined }) { +export function ProfileSummary(props: { user: User }) { const { user } = props return ( - - + + + -
-
{user?.name}
-
- {user ? formatMoney(Math.floor(user.balance)) : ' '} +
+
{user.name}
+
{formatMoney(Math.floor(user.balance))}
-
- +
+ ) } diff --git a/web/components/nav/sidebar.tsx b/web/components/nav/sidebar.tsx index 80376b6c..ad031f8e 100644 --- a/web/components/nav/sidebar.tsx +++ b/web/components/nav/sidebar.tsx @@ -1,9 +1,7 @@ import { HomeIcon, - UserGroupIcon, CakeIcon, SearchIcon, - ChatIcon, BookOpenIcon, DotsHorizontalIcon, CashIcon, @@ -110,7 +108,8 @@ function MoreButton() { ) } -export default function Sidebar() { +export default function Sidebar(props: { className?: string }) { + const { className } = props const router = useRouter() const currentPage = router.pathname @@ -124,27 +123,15 @@ export default function Sidebar() { user === null ? signedOutMobileNavigation : mobileNavigation return ( -