Free response markets with investment cap (#157)

* Show error message for FR bet

* Allow M$ limit for markets

* Allow M$ limit for markets

* Apply M$ limit to FR answer bets

* Improve error message

* Improve error message

* Only check stats if mana limit set

* Consolidate logic

* Remove unused variable

* absolute import

* absolute imports
This commit is contained in:
Boa 2022-05-09 14:09:07 -06:00 committed by GitHub
parent d55990d5d4
commit a5b0372a6e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 68 additions and 6 deletions

View File

@ -161,6 +161,7 @@ export function getContractBetMetrics(contract: Contract, yourBets: Bet[]) {
return { return {
invested: Math.max(0, currentInvested), invested: Math.max(0, currentInvested),
currentInvested,
payout, payout,
netPayout, netPayout,
profit, profit,
@ -189,3 +190,29 @@ export function getTopAnswer(contract: FreeResponseContract) {
) )
return top?.answer return top?.answer
} }
export function hasUserHitManaLimit(
contract: FreeResponseContract,
bets: Bet[],
amount: number
) {
const { manaLimitPerUser } = contract
if (manaLimitPerUser) {
const contractMetrics = getContractBetMetrics(contract, bets)
const currentInvested = contractMetrics.currentInvested
console.log('user current invested amount', currentInvested)
console.log('mana limit:', manaLimitPerUser)
if (currentInvested + amount > manaLimitPerUser) {
const manaAllowed = manaLimitPerUser - currentInvested
return {
status: 'error',
message: `Market bet cap is M$${manaLimitPerUser}, you've M$${manaAllowed} left`,
}
}
}
return {
status: 'success',
message: '',
}
}

View File

@ -31,6 +31,8 @@ export type FullContract<
closeEmailsSent?: number closeEmailsSent?: number
manaLimitPerUser?: number
volume: number volume: number
volume24Hours: number volume24Hours: number
volume7Days: number volume7Days: number

View File

@ -22,7 +22,8 @@ export function getNewContract(
initialProb: number, initialProb: number,
ante: number, ante: number,
closeTime: number, closeTime: number,
extraTags: string[] extraTags: string[],
manaLimitPerUser: number
) { ) {
const tags = parseTags( const tags = parseTags(
`${question} ${description} ${extraTags.map((tag) => `#${tag}`).join(' ')}` `${question} ${description} ${extraTags.map((tag) => `#${tag}`).join(' ')}`
@ -64,6 +65,7 @@ export function getNewContract(
liquidityFee: 0, liquidityFee: 0,
platformFee: 0, platformFee: 0,
}, },
manaLimitPerUser,
}) })
return contract as Contract return contract as Contract

View File

@ -12,7 +12,11 @@ import { getLoanAmount, getNewMultiBetInfo } from '../../common/new-bet'
import { Answer, MAX_ANSWER_LENGTH } from '../../common/answer' import { Answer, MAX_ANSWER_LENGTH } from '../../common/answer'
import { getContract, getValues } from './utils' import { getContract, getValues } from './utils'
import { sendNewAnswerEmail } from './emails' import { sendNewAnswerEmail } from './emails'
import { Bet } from '../../common/bet' import { Bet } from 'common/bet'
import {
getContractBetMetrics,
hasUserHitManaLimit,
} from 'common/calculate'
export const createAnswer = functions.runWith({ minInstances: 1 }).https.onCall( export const createAnswer = functions.runWith({ minInstances: 1 }).https.onCall(
async ( async (
@ -66,6 +70,13 @@ export const createAnswer = functions.runWith({ minInstances: 1 }).https.onCall(
) )
const yourBets = yourBetsSnap.docs.map((doc) => doc.data() as Bet) const yourBets = yourBetsSnap.docs.map((doc) => doc.data() as Bet)
const { status, message } = hasUserHitManaLimit(
contract,
yourBets,
amount
)
if (status === 'error') return { status, message: message }
const [lastAnswer] = await getValues<Answer>( const [lastAnswer] = await getValues<Answer>(
firestore firestore
.collection(`contracts/${contractId}/answers`) .collection(`contracts/${contractId}/answers`)

View File

@ -39,6 +39,7 @@ export const createContract = functions
ante: number ante: number
closeTime: number closeTime: number
tags?: string[] tags?: string[]
manaLimitPerUser?: number
}, },
context context
) => { ) => {
@ -48,7 +49,14 @@ export const createContract = functions
const creator = await getUser(userId) const creator = await getUser(userId)
if (!creator) return { status: 'error', message: 'User not found' } if (!creator) return { status: 'error', message: 'User not found' }
let { question, description, initialProb, closeTime, tags } = data let {
question,
description,
initialProb,
closeTime,
tags,
manaLimitPerUser,
} = data
if (!question || typeof question != 'string') if (!question || typeof question != 'string')
return { status: 'error', message: 'Missing or invalid question field' } return { status: 'error', message: 'Missing or invalid question field' }
@ -115,7 +123,8 @@ export const createContract = functions
initialProb, initialProb,
ante, ante,
closeTime, closeTime,
tags ?? [] tags ?? [],
manaLimitPerUser ?? 0
) )
if (!isFree && ante) await chargeUser(creator.id, ante) if (!isFree && ante) await chargeUser(creator.id, ante)

View File

@ -12,7 +12,11 @@ import {
import { addObjects, removeUndefinedProps } from '../../common/util/object' import { addObjects, removeUndefinedProps } from '../../common/util/object'
import { Bet } from '../../common/bet' import { Bet } from '../../common/bet'
import { redeemShares } from './redeem-shares' import { redeemShares } from './redeem-shares'
import { Fees } from '../../common/fees' import { Fees } from 'common/fees'
import {
getContractBetMetrics,
hasUserHitManaLimit,
} from 'common/calculate'
export const placeBet = functions.runWith({ minInstances: 1 }).https.onCall( export const placeBet = functions.runWith({ minInstances: 1 }).https.onCall(
async ( async (
@ -69,6 +73,13 @@ export const placeBet = functions.runWith({ minInstances: 1 }).https.onCall(
) )
if (!answerSnap.exists) if (!answerSnap.exists)
return { status: 'error', message: 'Invalid contract' } return { status: 'error', message: 'Invalid contract' }
const { status, message } = hasUserHitManaLimit(
contract,
yourBets,
amount
)
if (status === 'error') return { status, message: message }
} }
const newBetDoc = firestore const newBetDoc = firestore

View File

@ -66,7 +66,7 @@ export function AnswerBetPanel(props: {
setBetAmount(undefined) setBetAmount(undefined)
props.closePanel() props.closePanel()
} else { } else {
setError(result?.error || 'Error placing bet') setError(result?.message || 'Error placing bet')
setIsSubmitting(false) setIsSubmitting(false)
} }
} }