Merge branch 'main' into limit-orders

This commit is contained in:
James Grugett 2022-07-10 13:01:33 -05:00
commit a1557bc112
10 changed files with 55 additions and 52 deletions

View File

@ -272,16 +272,16 @@ export function getCpmmLiquidityPoolWeights(
const liquidityShares = liquidities.map(calcLiqudity) const liquidityShares = liquidities.map(calcLiqudity)
const shareSum = sum(liquidityShares) const shareSum = sum(liquidityShares)
const includedLiquidities = excludeAntes const weights = liquidityShares.map((shares, i) => ({
? liquidityShares.filter((_, i) => !liquidities[i].isAnte) weight: shares / shareSum,
: liquidityShares
const weights = includedLiquidities.map((s, i) => ({
weight: s / shareSum,
providerId: liquidities[i].userId, providerId: liquidities[i].userId,
})) }))
const userWeights = groupBy(weights, (w) => w.providerId) const includedWeights = excludeAntes
? weights.filter((_, i) => !liquidities[i].isAnte)
: weights
const userWeights = groupBy(includedWeights, (w) => w.providerId)
const totalUserWeights = mapValues(userWeights, (userWeight) => const totalUserWeights = mapValues(userWeights, (userWeight) =>
sumBy(userWeight, (w) => w.weight) sumBy(userWeight, (w) => w.weight)
) )

View File

@ -3,7 +3,6 @@ import * as admin from 'firebase-admin'
admin.initializeApp() admin.initializeApp()
// v1 // v1
export * from './transact'
export * from './stripe' export * from './stripe'
export * from './create-user' export * from './create-user'
export * from './on-create-bet' export * from './on-create-bet'
@ -28,6 +27,7 @@ export * from './on-create-txn'
// v2 // v2
export * from './health' export * from './health'
export * from './transact'
export * from './change-user-info' export * from './change-user-info'
export * from './create-answer' export * from './create-answer'
export * from './place-bet' export * from './place-bet'

View File

@ -1,4 +1,4 @@
import * as functions from 'firebase-functions' import { onRequest } from 'firebase-functions/v2/https'
import * as admin from 'firebase-admin' import * as admin from 'firebase-admin'
import Stripe from 'stripe' import Stripe from 'stripe'
@ -42,9 +42,9 @@ const manticDollarStripePrice = isProd()
10000: 'price_1K8bEiGdoFKoCJW7Us4UkRHE', 10000: 'price_1K8bEiGdoFKoCJW7Us4UkRHE',
} }
export const createCheckoutSession = functions export const createcheckoutsession = onRequest(
.runWith({ minInstances: 1, secrets: ['STRIPE_APIKEY'] }) { minInstances: 1, secrets: ['STRIPE_APIKEY'] },
.https.onRequest(async (req, res) => { async (req, res) => {
const userId = req.query.userId?.toString() const userId = req.query.userId?.toString()
const manticDollarQuantity = req.query.manticDollarQuantity?.toString() const manticDollarQuantity = req.query.manticDollarQuantity?.toString()
@ -86,14 +86,15 @@ export const createCheckoutSession = functions
}) })
res.redirect(303, session.url || '') res.redirect(303, session.url || '')
}) }
)
export const stripeWebhook = functions export const stripewebhook = onRequest(
.runWith({ {
minInstances: 1, minInstances: 1,
secrets: ['MAILGUN_KEY', 'STRIPE_APIKEY', 'STRIPE_WEBHOOKSECRET'], secrets: ['MAILGUN_KEY', 'STRIPE_APIKEY', 'STRIPE_WEBHOOKSECRET'],
}) },
.https.onRequest(async (req, res) => { async (req, res) => {
const stripe = initStripe() const stripe = initStripe()
let event let event
@ -115,7 +116,8 @@ export const stripeWebhook = functions
} }
res.status(200).send('success') res.status(200).send('success')
}) }
)
const issueMoneys = async (session: StripeSession) => { const issueMoneys = async (session: StripeSession) => {
const { id: sessionId } = session const { id: sessionId } = session

View File

@ -1,40 +1,40 @@
import * as functions from 'firebase-functions'
import * as admin from 'firebase-admin' import * as admin from 'firebase-admin'
import { User } from '../../common/user' import { User } from '../../common/user'
import { Txn } from '../../common/txn' import { Txn } from '../../common/txn'
import { removeUndefinedProps } from '../../common/util/object' import { removeUndefinedProps } from '../../common/util/object'
import { APIError, newEndpoint } from './api'
export type TxnData = Omit<Txn, 'id' | 'createdTime'> export type TxnData = Omit<Txn, 'id' | 'createdTime'>
export const transact = functions // TODO: We totally fail to validate most of the input to this function,
.runWith({ minInstances: 1 }) // so anyone can spam our database with malformed transactions.
.https.onCall(async (data: TxnData, context) => {
const userId = context?.auth?.uid
if (!userId) return { status: 'error', message: 'Not authorized' }
const { amount, fromType, fromId } = data export const transact = newEndpoint({}, async (req, auth) => {
const data = req.body
const { amount, fromType, fromId } = data
if (fromType !== 'USER') if (fromType !== 'USER')
return { throw new APIError(400, "From type is only implemented for type 'user'.")
status: 'error',
message: "From type is only implemented for type 'user'.",
}
if (fromId !== userId) if (fromId !== auth.uid)
return { throw new APIError(
status: 'error', 403,
message: 'Must be authenticated with userId equal to specified fromId.', 'Must be authenticated with userId equal to specified fromId.'
} )
if (isNaN(amount) || !isFinite(amount)) if (isNaN(amount) || !isFinite(amount))
return { status: 'error', message: 'Invalid amount' } throw new APIError(400, 'Invalid amount')
// Run as transaction to prevent race conditions. // Run as transaction to prevent race conditions.
return await firestore.runTransaction(async (transaction) => { return await firestore.runTransaction(async (transaction) => {
await runTxn(transaction, data) const result = await runTxn(transaction, data)
}) if (result.status == 'error') {
throw new APIError(500, result.message ?? 'An unknown error occurred.')
}
return result
}) })
})
export async function runTxn( export async function runTxn(
fbTransaction: admin.firestore.Transaction, fbTransaction: admin.firestore.Transaction,

View File

@ -11,7 +11,7 @@ import { debounce, sum } from 'lodash'
import { useEffect, useRef, useState } from 'react' import { useEffect, useRef, useState } from 'react'
import { CommentTips } from 'web/hooks/use-tip-txns' import { CommentTips } from 'web/hooks/use-tip-txns'
import { useUser } from 'web/hooks/use-user' import { useUser } from 'web/hooks/use-user'
import { transact } from 'web/lib/firebase/fn-call' import { transact } from 'web/lib/firebase/api-call'
import { track } from 'web/lib/service/analytics' import { track } from 'web/lib/service/analytics'
import { Row } from './layout/row' import { Row } from './layout/row'
import { Tooltip } from './tooltip' import { Tooltip } from './tooltip'

View File

@ -53,6 +53,11 @@ export function getFunctionUrl(name: string) {
export function createAnswer(params: any) { export function createAnswer(params: any) {
return call(getFunctionUrl('createanswer'), 'POST', params) return call(getFunctionUrl('createanswer'), 'POST', params)
} }
export function transact(params: any) {
return call(getFunctionUrl('transact'), 'POST', params)
}
export function changeUserInfo(params: any) { export function changeUserInfo(params: any) {
return call(getFunctionUrl('changeuserinfo'), 'POST', params) return call(getFunctionUrl('changeuserinfo'), 'POST', params)
} }

View File

@ -1,5 +1,4 @@
import { httpsCallable } from 'firebase/functions' import { httpsCallable } from 'firebase/functions'
import { Txn } from 'common/txn'
import { User } from 'common/user' import { User } from 'common/user'
import { randomString } from 'common/util/random' import { randomString } from 'common/util/random'
import './init' import './init'
@ -9,11 +8,6 @@ import { safeLocalStorage } from '../util/local'
export const cloudFunction = <RequestData, ResponseData>(name: string) => export const cloudFunction = <RequestData, ResponseData>(name: string) =>
httpsCallable<RequestData, ResponseData>(functions, name) httpsCallable<RequestData, ResponseData>(functions, name)
export const transact = cloudFunction<
Omit<Txn, 'id' | 'createdTime'>,
{ status: 'error' | 'success'; message?: string; txn?: Txn }
>('transact')
export const createUser: () => Promise<User | null> = () => { export const createUser: () => Promise<User | null> = () => {
const local = safeLocalStorage() const local = safeLocalStorage()
let deviceToken = local?.getItem('device-token') let deviceToken = local?.getItem('device-token')

View File

@ -39,6 +39,9 @@ import { filterDefined } from 'common/util/array'
import { addUserToGroupViaSlug } from 'web/lib/firebase/groups' import { addUserToGroupViaSlug } from 'web/lib/firebase/groups'
import { removeUndefinedProps } from 'common/util/object' import { removeUndefinedProps } from 'common/util/object'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import utc from 'dayjs/plugin/utc'
dayjs.extend(utc)
import { track } from '@amplitude/analytics-browser' import { track } from '@amplitude/analytics-browser'
export const users = coll<User>('users') export const users = coll<User>('users')

View File

@ -1,12 +1,11 @@
import { PROJECT_ID } from 'common/envs/constants' import { getFunctionUrl } from 'web/lib/firebase/api-call'
export const checkoutURL = ( export const checkoutURL = (
userId: string, userId: string,
manticDollarQuantity: number, manticDollarQuantity: number,
referer = '' referer = ''
) => { ) => {
const endpoint = `https://us-central1-${PROJECT_ID}.cloudfunctions.net/createCheckoutSession` const endpoint = getFunctionUrl('createcheckoutsession')
return `${endpoint}?userId=${userId}&manticDollarQuantity=${manticDollarQuantity}&referer=${encodeURIComponent( return `${endpoint}?userId=${userId}&manticDollarQuantity=${manticDollarQuantity}&referer=${encodeURIComponent(
referer referer
)}` )}`

View File

@ -10,7 +10,7 @@ import { Spacer } from 'web/components/layout/spacer'
import { User } from 'common/user' import { User } from 'common/user'
import { useUser } from 'web/hooks/use-user' import { useUser } from 'web/hooks/use-user'
import { Linkify } from 'web/components/linkify' import { Linkify } from 'web/components/linkify'
import { transact } from 'web/lib/firebase/fn-call' import { transact } from 'web/lib/firebase/api-call'
import { charities, Charity } from 'common/charity' import { charities, Charity } from 'common/charity'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import Custom404 from '../404' import Custom404 from '../404'