From d38453b29ac1d3cc9fb2526280df23c220f22dc1 Mon Sep 17 00:00:00 2001 From: mantikoros Date: Fri, 6 May 2022 16:39:46 -0400 Subject: [PATCH] placeBet for numeric markets --- common/calculate-dpm.ts | 28 +++++++++++++++++++++++ common/new-bet.ts | 46 ++++++++++++++++++++++++++++++++++++++ functions/src/place-bet.ts | 16 ++++++++++++- 3 files changed, 89 insertions(+), 1 deletion(-) diff --git a/common/calculate-dpm.ts b/common/calculate-dpm.ts index 6dbd75da..a37bab15 100644 --- a/common/calculate-dpm.ts +++ b/common/calculate-dpm.ts @@ -9,6 +9,7 @@ import { } from './contract' import { DPM_FEES } from './fees' import { normpdf } from './normal' +import { addObjects } from './util/object' export function getDpmProbability(totalShares: { [outcome: string]: number }) { // For binary contracts only. @@ -106,6 +107,33 @@ export function calculateDpmShares( return Math.sqrt(bet ** 2 + shares ** 2 + c) - shares } +const zigZagOrder = (length: number) => { + const mid = Math.floor(length / 2) + + return _.range(0, mid) + .flatMap((i) => [i, length - i - 1]) + .concat(length % 2 === 0 ? [] : [mid]) +} + +export function calculateNumericDpmShares( + totalShares: { + [outcome: string]: number + }, + bets: [string, number][] +) { + const shares: number[] = [] + + totalShares = _.cloneDeep(totalShares) + + for (let i of zigZagOrder(bets.length)) { + const [bucket, bet] = bets[i] + shares[i] = calculateDpmShares(totalShares, bet, bucket) + totalShares = addObjects(totalShares, { [bucket]: shares[i] }) + } + + return { shares, totalShares } +} + export function calculateDpmRawShareValue( totalShares: { [outcome: string]: number diff --git a/common/new-bet.ts b/common/new-bet.ts index 92feb715..33acd2dc 100644 --- a/common/new-bet.ts +++ b/common/new-bet.ts @@ -5,6 +5,8 @@ import { calculateDpmShares, getDpmProbability, getDpmOutcomeProbability, + getNumericBets, + calculateNumericDpmShares, } from './calculate-dpm' import { calculateCpmmPurchase, getCpmmProbability } from './calculate-cpmm' import { @@ -14,9 +16,11 @@ import { FreeResponse, FullContract, Multi, + NumericContract, } from './contract' import { User } from './user' import { noFees } from './fees' +import { addObjects } from './util/object' export const getNewBinaryCpmmBetInfo = ( user: User, @@ -154,6 +158,48 @@ export const getNewMultiBetInfo = ( return { newBet, newPool, newTotalShares, newTotalBets, newBalance } } +export const getNumericBetsInfo = ( + user: User, + outcome: string, + amount: number, + contract: NumericContract +) => { + const { pool, totalShares, totalBets } = contract + + const bets = getNumericBets(contract, outcome, amount) + const newPool = addObjects(pool, Object.fromEntries(bets)) + + const { shares, totalShares: newTotalShares } = calculateNumericDpmShares( + contract.totalShares, + bets + ) + + const newTotalBets = addObjects(totalBets, Object.fromEntries(bets)) + + const newBets = bets.map(([outcome, amount], i) => { + const probBefore = getDpmOutcomeProbability(totalShares, outcome) + const probAfter = getDpmOutcomeProbability(newTotalShares, outcome) + + const newBet: Omit = { + userId: user.id, + contractId: contract.id, + amount, + shares: shares[i], + outcome, + probBefore, + probAfter, + createdTime: Date.now(), + fees: noFees, + } + + return newBet + }) + + const newBalance = user.balance - amount + + return { newBets, newPool, newTotalShares, newTotalBets, newBalance } +} + export const getLoanAmount = (yourBets: Bet[], newBetAmount: number) => { const openBets = yourBets.filter((bet) => !bet.isSold && !bet.sale) const prevLoanAmount = _.sumBy(openBets, (bet) => bet.loanAmount ?? 0) diff --git a/functions/src/place-bet.ts b/functions/src/place-bet.ts index 74487126..5da8ac57 100644 --- a/functions/src/place-bet.ts +++ b/functions/src/place-bet.ts @@ -8,6 +8,7 @@ import { getNewBinaryDpmBetInfo, getNewMultiBetInfo, getLoanAmount, + getNumericBetsInfo, } from '../../common/new-bet' import { addObjects, removeUndefinedProps } from '../../common/util/object' import { Bet } from '../../common/bet' @@ -77,6 +78,7 @@ export const placeBet = functions.runWith({ minInstances: 1 }).https.onCall( const { newBet, + newBets, newPool, newTotalShares, newTotalBets, @@ -103,6 +105,8 @@ export const placeBet = functions.runWith({ minInstances: 1 }).https.onCall( loanAmount, newBetDoc.id ) as any) + : outcomeType === 'NUMERIC' && mechanism === 'dpm-2' + ? getNumericBetsInfo(user, outcome, amount, contract) : getNewMultiBetInfo( user, outcome, @@ -119,7 +123,17 @@ export const placeBet = functions.runWith({ minInstances: 1 }).https.onCall( } } - transaction.create(newBetDoc, newBet) + if (newBet) transaction.create(newBetDoc, newBet) + + if (newBets) { + for (let newBet of newBets) { + const newBetDoc = firestore + .collection(`contracts/${contractId}/bets`) + .doc() + + transaction.create(newBetDoc, { id: newBetDoc.id, ...newBet }) + } + } transaction.update( contractDoc,