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:
parent
d55990d5d4
commit
a5b0372a6e
|
@ -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: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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`)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user