cpmm initial commit: common logic, cloud functions
This commit is contained in:
parent
a6657a28fd
commit
f830119023
|
@ -1,11 +1,50 @@
|
||||||
import { Bet } from './bet'
|
import { Bet } from './bet'
|
||||||
import { getProbability } from './calculate'
|
import { getProbability } from './calculate'
|
||||||
import { Contract } from './contract'
|
import { getCpmmProbability } from './calculate-cpmm'
|
||||||
|
import { Binary, CPMM, DPM, FreeResponse, FullContract } from './contract'
|
||||||
import { User } from './user'
|
import { User } from './user'
|
||||||
|
|
||||||
export const PHANTOM_ANTE = 0.001
|
export const PHANTOM_ANTE = 0.001
|
||||||
export const MINIMUM_ANTE = 10
|
export const MINIMUM_ANTE = 10
|
||||||
|
|
||||||
|
export const calcStartCpmmPool = (initialProbInt: number, ante: number) => {
|
||||||
|
const p = initialProbInt / 100.0
|
||||||
|
const invP = 1.0 / p - 1
|
||||||
|
const otherAnte = ante / invP
|
||||||
|
|
||||||
|
const [poolYes, poolNo] = p >= 0.5 ? [otherAnte, ante] : [ante, otherAnte]
|
||||||
|
const k = poolYes * poolNo
|
||||||
|
|
||||||
|
return { poolYes, poolNo, k }
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCpmmAnteBet(
|
||||||
|
creator: User,
|
||||||
|
contract: FullContract<CPMM, Binary>,
|
||||||
|
anteId: string,
|
||||||
|
amount: number,
|
||||||
|
outcome: 'YES' | 'NO'
|
||||||
|
) {
|
||||||
|
const p = getCpmmProbability(contract.pool)
|
||||||
|
|
||||||
|
const { createdTime } = contract
|
||||||
|
|
||||||
|
const bet: Bet = {
|
||||||
|
id: anteId,
|
||||||
|
userId: creator.id,
|
||||||
|
contractId: contract.id,
|
||||||
|
amount: amount,
|
||||||
|
shares: amount,
|
||||||
|
outcome,
|
||||||
|
probBefore: p,
|
||||||
|
probAfter: p,
|
||||||
|
createdTime,
|
||||||
|
isAnte: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
return bet
|
||||||
|
}
|
||||||
|
|
||||||
export const calcStartPool = (initialProbInt: number, ante = 0) => {
|
export const calcStartPool = (initialProbInt: number, ante = 0) => {
|
||||||
const p = initialProbInt / 100.0
|
const p = initialProbInt / 100.0
|
||||||
const totalAnte = PHANTOM_ANTE + ante
|
const totalAnte = PHANTOM_ANTE + ante
|
||||||
|
@ -24,7 +63,7 @@ export const calcStartPool = (initialProbInt: number, ante = 0) => {
|
||||||
|
|
||||||
export function getAnteBets(
|
export function getAnteBets(
|
||||||
creator: User,
|
creator: User,
|
||||||
contract: Contract,
|
contract: FullContract<DPM, Binary>,
|
||||||
yesAnteId: string,
|
yesAnteId: string,
|
||||||
noAnteId: string
|
noAnteId: string
|
||||||
) {
|
) {
|
||||||
|
@ -64,7 +103,7 @@ export function getAnteBets(
|
||||||
|
|
||||||
export function getFreeAnswerAnte(
|
export function getFreeAnswerAnte(
|
||||||
creator: User,
|
creator: User,
|
||||||
contract: Contract,
|
contract: FullContract<DPM, FreeResponse>,
|
||||||
anteBetId: string
|
anteBetId: string
|
||||||
) {
|
) {
|
||||||
const { totalBets, totalShares } = contract
|
const { totalBets, totalShares } = contract
|
||||||
|
|
134
common/calculate-cpmm.ts
Normal file
134
common/calculate-cpmm.ts
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
import * as _ from 'lodash'
|
||||||
|
import { Bet } from './bet'
|
||||||
|
import { Binary, CPMM, FullContract } from './contract'
|
||||||
|
import { FEES } from './fees'
|
||||||
|
|
||||||
|
export function getCpmmProbability(pool: { [outcome: string]: number }) {
|
||||||
|
// For binary contracts only.
|
||||||
|
const { YES, NO } = pool
|
||||||
|
return NO / (YES + NO)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCpmmProbabilityAfterBet(
|
||||||
|
contract: FullContract<CPMM, Binary>,
|
||||||
|
outcome: string,
|
||||||
|
bet: number
|
||||||
|
) {
|
||||||
|
const { newPool } = calculateCpmmPurchase(contract, bet, outcome)
|
||||||
|
return getCpmmProbability(newPool)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function calculateCpmmShares(
|
||||||
|
pool: {
|
||||||
|
[outcome: string]: number
|
||||||
|
},
|
||||||
|
k: number,
|
||||||
|
bet: number,
|
||||||
|
betChoice: string
|
||||||
|
) {
|
||||||
|
const { YES: y, NO: n } = pool
|
||||||
|
const numerator = bet ** 2 + bet * (y + n) - k + y * n
|
||||||
|
const denominator = betChoice === 'YES' ? bet + n : bet + y
|
||||||
|
const shares = numerator / denominator
|
||||||
|
return shares
|
||||||
|
}
|
||||||
|
|
||||||
|
export function calculateCpmmPurchase(
|
||||||
|
contract: FullContract<CPMM, Binary>,
|
||||||
|
bet: number,
|
||||||
|
outcome: string
|
||||||
|
) {
|
||||||
|
const { pool, k } = contract
|
||||||
|
|
||||||
|
const shares = calculateCpmmShares(pool, k, bet, outcome)
|
||||||
|
const { YES: y, NO: n } = pool
|
||||||
|
|
||||||
|
const [newY, newN] =
|
||||||
|
outcome === 'YES'
|
||||||
|
? [y - shares + bet, n + bet]
|
||||||
|
: [y + bet, n - shares + bet]
|
||||||
|
|
||||||
|
const newPool = { YES: newY, NO: newN }
|
||||||
|
|
||||||
|
return { shares, newPool }
|
||||||
|
}
|
||||||
|
|
||||||
|
export function calculateCpmmShareValue(
|
||||||
|
contract: FullContract<CPMM, Binary>,
|
||||||
|
shares: number,
|
||||||
|
outcome: string
|
||||||
|
) {
|
||||||
|
const { pool, k } = contract
|
||||||
|
const { YES: y, NO: n } = pool
|
||||||
|
|
||||||
|
const poolChange = outcome === 'YES' ? shares + y - n : shares + n - y
|
||||||
|
|
||||||
|
const shareValue = 0.5 * (shares + y + n - Math.sqrt(4 * k + poolChange ** 2))
|
||||||
|
return shareValue
|
||||||
|
}
|
||||||
|
|
||||||
|
export function calculateCpmmSale(
|
||||||
|
contract: FullContract<CPMM, Binary>,
|
||||||
|
bet: Bet
|
||||||
|
) {
|
||||||
|
const { shares, outcome } = bet
|
||||||
|
|
||||||
|
const saleValue = calculateCpmmShareValue(contract, shares, outcome)
|
||||||
|
|
||||||
|
const { pool } = contract
|
||||||
|
const { YES: y, NO: n } = pool
|
||||||
|
|
||||||
|
const [newY, newN] =
|
||||||
|
outcome === 'YES'
|
||||||
|
? [y + shares - saleValue, n - saleValue]
|
||||||
|
: [y - saleValue, n + shares - saleValue]
|
||||||
|
|
||||||
|
const newPool = { YES: newY, NO: newN }
|
||||||
|
|
||||||
|
return { saleValue, newPool }
|
||||||
|
}
|
||||||
|
|
||||||
|
export function calculateFixedPayout(
|
||||||
|
contract: FullContract<CPMM, Binary>,
|
||||||
|
bet: Bet,
|
||||||
|
outcome: string
|
||||||
|
) {
|
||||||
|
if (outcome === 'CANCEL') return calculateFixedCancelPayout(bet)
|
||||||
|
if (outcome === 'MKT') return calculateFixedMktPayout(contract, bet)
|
||||||
|
|
||||||
|
return calculateStandardFixedPayout(bet, outcome)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function calculateFixedCancelPayout(bet: Bet) {
|
||||||
|
return bet.amount
|
||||||
|
}
|
||||||
|
|
||||||
|
export function calculateStandardFixedPayout(bet: Bet, outcome: string) {
|
||||||
|
const { amount, outcome: betOutcome, shares } = bet
|
||||||
|
if (betOutcome !== outcome) return 0
|
||||||
|
return deductCpmmFees(amount, shares - amount)
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateFixedMktPayout(
|
||||||
|
contract: FullContract<CPMM, Binary>,
|
||||||
|
bet: Bet
|
||||||
|
) {
|
||||||
|
const { resolutionProbability, pool } = contract
|
||||||
|
const p =
|
||||||
|
resolutionProbability !== undefined
|
||||||
|
? resolutionProbability
|
||||||
|
: getCpmmProbability(pool)
|
||||||
|
|
||||||
|
const { outcome, amount, shares } = bet
|
||||||
|
|
||||||
|
const betP = outcome === 'YES' ? p : 1 - p
|
||||||
|
const winnings = betP * shares
|
||||||
|
|
||||||
|
return deductCpmmFees(amount, winnings)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const deductCpmmFees = (betAmount: number, winnings: number) => {
|
||||||
|
return winnings > betAmount
|
||||||
|
? betAmount + (1 - FEES) * (winnings - betAmount)
|
||||||
|
: winnings
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
import * as _ from 'lodash'
|
import * as _ from 'lodash'
|
||||||
import { Bet } from './bet'
|
import { Bet } from './bet'
|
||||||
import { Contract } from './contract'
|
import { Binary, DPM, FullContract } from './contract'
|
||||||
import { FEES } from './fees'
|
import { FEES } from './fees'
|
||||||
|
|
||||||
export function getProbability(totalShares: { [outcome: string]: number }) {
|
export function getProbability(totalShares: { [outcome: string]: number }) {
|
||||||
|
@ -86,7 +86,7 @@ export function calculateRawShareValue(
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculateMoneyRatio(
|
export function calculateMoneyRatio(
|
||||||
contract: Contract,
|
contract: FullContract<DPM, any>,
|
||||||
bet: Bet,
|
bet: Bet,
|
||||||
shareValue: number
|
shareValue: number
|
||||||
) {
|
) {
|
||||||
|
@ -112,7 +112,10 @@ export function calculateMoneyRatio(
|
||||||
return actual / expected
|
return actual / expected
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculateShareValue(contract: Contract, bet: Bet) {
|
export function calculateShareValue(
|
||||||
|
contract: FullContract<DPM, any>,
|
||||||
|
bet: Bet
|
||||||
|
) {
|
||||||
const { pool, totalShares } = contract
|
const { pool, totalShares } = contract
|
||||||
const { shares, outcome } = bet
|
const { shares, outcome } = bet
|
||||||
|
|
||||||
|
@ -124,20 +127,30 @@ export function calculateShareValue(contract: Contract, bet: Bet) {
|
||||||
return adjShareValue
|
return adjShareValue
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculateSaleAmount(contract: Contract, bet: Bet) {
|
export function calculateSaleAmount(
|
||||||
|
contract: FullContract<DPM, any>,
|
||||||
|
bet: Bet
|
||||||
|
) {
|
||||||
const { amount } = bet
|
const { amount } = bet
|
||||||
const winnings = calculateShareValue(contract, bet)
|
const winnings = calculateShareValue(contract, bet)
|
||||||
return deductFees(amount, winnings)
|
return deductFees(amount, winnings)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculatePayout(contract: Contract, bet: Bet, outcome: string) {
|
export function calculatePayout(
|
||||||
|
contract: FullContract<DPM, any>,
|
||||||
|
bet: Bet,
|
||||||
|
outcome: string
|
||||||
|
) {
|
||||||
if (outcome === 'CANCEL') return calculateCancelPayout(contract, bet)
|
if (outcome === 'CANCEL') return calculateCancelPayout(contract, bet)
|
||||||
if (outcome === 'MKT') return calculateMktPayout(contract, bet)
|
if (outcome === 'MKT') return calculateMktPayout(contract, bet)
|
||||||
|
|
||||||
return calculateStandardPayout(contract, bet, outcome)
|
return calculateStandardPayout(contract, bet, outcome)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculateCancelPayout(contract: Contract, bet: Bet) {
|
export function calculateCancelPayout(
|
||||||
|
contract: FullContract<DPM, any>,
|
||||||
|
bet: Bet
|
||||||
|
) {
|
||||||
const { totalBets, pool } = contract
|
const { totalBets, pool } = contract
|
||||||
const betTotal = _.sum(Object.values(totalBets))
|
const betTotal = _.sum(Object.values(totalBets))
|
||||||
const poolTotal = _.sum(Object.values(pool))
|
const poolTotal = _.sum(Object.values(pool))
|
||||||
|
@ -146,7 +159,7 @@ export function calculateCancelPayout(contract: Contract, bet: Bet) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculateStandardPayout(
|
export function calculateStandardPayout(
|
||||||
contract: Contract,
|
contract: FullContract<DPM, any>,
|
||||||
bet: Bet,
|
bet: Bet,
|
||||||
outcome: string
|
outcome: string
|
||||||
) {
|
) {
|
||||||
|
@ -166,7 +179,10 @@ export function calculateStandardPayout(
|
||||||
return amount + (1 - FEES) * Math.max(0, winnings - amount)
|
return amount + (1 - FEES) * Math.max(0, winnings - amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculatePayoutAfterCorrectBet(contract: Contract, bet: Bet) {
|
export function calculatePayoutAfterCorrectBet(
|
||||||
|
contract: FullContract<DPM, any>,
|
||||||
|
bet: Bet
|
||||||
|
) {
|
||||||
const { totalShares, pool, totalBets } = contract
|
const { totalShares, pool, totalBets } = contract
|
||||||
const { shares, amount, outcome } = bet
|
const { shares, amount, outcome } = bet
|
||||||
|
|
||||||
|
@ -193,7 +209,7 @@ export function calculatePayoutAfterCorrectBet(contract: Contract, bet: Bet) {
|
||||||
return calculateStandardPayout(newContract, bet, outcome)
|
return calculateStandardPayout(newContract, bet, outcome)
|
||||||
}
|
}
|
||||||
|
|
||||||
function calculateMktPayout(contract: Contract, bet: Bet) {
|
function calculateMktPayout(contract: FullContract<DPM, any>, bet: Bet) {
|
||||||
if (contract.outcomeType === 'BINARY')
|
if (contract.outcomeType === 'BINARY')
|
||||||
return calculateBinaryMktPayout(contract, bet)
|
return calculateBinaryMktPayout(contract, bet)
|
||||||
|
|
||||||
|
@ -201,7 +217,7 @@ function calculateMktPayout(contract: Contract, bet: Bet) {
|
||||||
|
|
||||||
const totalPool = _.sum(Object.values(pool))
|
const totalPool = _.sum(Object.values(pool))
|
||||||
const sharesSquareSum = _.sumBy(
|
const sharesSquareSum = _.sumBy(
|
||||||
Object.values(totalShares),
|
Object.values(totalShares) as number[],
|
||||||
(shares) => shares ** 2
|
(shares) => shares ** 2
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -220,7 +236,10 @@ function calculateMktPayout(contract: Contract, bet: Bet) {
|
||||||
return deductFees(amount, winnings)
|
return deductFees(amount, winnings)
|
||||||
}
|
}
|
||||||
|
|
||||||
function calculateBinaryMktPayout(contract: Contract, bet: Bet) {
|
function calculateBinaryMktPayout(
|
||||||
|
contract: FullContract<DPM, Binary>,
|
||||||
|
bet: Bet
|
||||||
|
) {
|
||||||
const { resolutionProbability, totalShares, phantomShares } = contract
|
const { resolutionProbability, totalShares, phantomShares } = contract
|
||||||
const p =
|
const p =
|
||||||
resolutionProbability !== undefined
|
resolutionProbability !== undefined
|
||||||
|
@ -241,7 +260,7 @@ function calculateBinaryMktPayout(contract: Contract, bet: Bet) {
|
||||||
return deductFees(amount, winnings)
|
return deductFees(amount, winnings)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolvedPayout(contract: Contract, bet: Bet) {
|
export function resolvedPayout(contract: FullContract<DPM, any>, bet: Bet) {
|
||||||
if (contract.resolution)
|
if (contract.resolution)
|
||||||
return calculatePayout(contract, bet, contract.resolution)
|
return calculatePayout(contract, bet, contract.resolution)
|
||||||
throw new Error('Contract was not resolved')
|
throw new Error('Contract was not resolved')
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import { Answer } from './answer'
|
import { Answer } from './answer'
|
||||||
|
|
||||||
export type Contract = {
|
export type FullContract<
|
||||||
|
M extends DPM | CPMM,
|
||||||
|
T extends Binary | Multi | FreeResponse
|
||||||
|
> = {
|
||||||
id: string
|
id: string
|
||||||
slug: string // auto-generated; must be unique
|
slug: string // auto-generated; must be unique
|
||||||
|
|
||||||
|
@ -15,16 +18,6 @@ export type Contract = {
|
||||||
lowercaseTags: string[]
|
lowercaseTags: string[]
|
||||||
visibility: 'public' | 'unlisted'
|
visibility: 'public' | 'unlisted'
|
||||||
|
|
||||||
outcomeType: 'BINARY' | 'MULTI' | 'FREE_RESPONSE'
|
|
||||||
multiOutcomes?: string[] // Used for outcomeType 'MULTI'.
|
|
||||||
answers?: Answer[] // Used for outcomeType 'FREE_RESPONSE'.
|
|
||||||
|
|
||||||
mechanism: 'dpm-2'
|
|
||||||
phantomShares?: { [outcome: string]: number }
|
|
||||||
pool: { [outcome: string]: number }
|
|
||||||
totalShares: { [outcome: string]: number }
|
|
||||||
totalBets: { [outcome: string]: number }
|
|
||||||
|
|
||||||
createdTime: number // Milliseconds since epoch
|
createdTime: number // Milliseconds since epoch
|
||||||
lastUpdatedTime: number // If the question or description was changed
|
lastUpdatedTime: number // If the question or description was changed
|
||||||
closeTime?: number // When no more trading is allowed
|
closeTime?: number // When no more trading is allowed
|
||||||
|
@ -32,12 +25,48 @@ export type Contract = {
|
||||||
isResolved: boolean
|
isResolved: boolean
|
||||||
resolutionTime?: number // When the contract creator resolved the market
|
resolutionTime?: number // When the contract creator resolved the market
|
||||||
resolution?: string
|
resolution?: string
|
||||||
resolutionProbability?: number // Used for BINARY markets resolved to MKT
|
|
||||||
resolutions?: { [outcome: string]: number } // Used for outcomeType FREE_RESPONSE resolved to MKT
|
|
||||||
closeEmailsSent?: number
|
closeEmailsSent?: number
|
||||||
|
|
||||||
volume24Hours: number
|
volume24Hours: number
|
||||||
volume7Days: number
|
volume7Days: number
|
||||||
|
} & M &
|
||||||
|
T
|
||||||
|
|
||||||
|
export type Contract = FullContract<DPM | CPMM, Binary | Multi | FreeResponse>
|
||||||
|
|
||||||
|
export type DPM = {
|
||||||
|
mechanism: 'dpm-2'
|
||||||
|
|
||||||
|
pool: { [outcome: string]: number }
|
||||||
|
phantomShares?: { [outcome: string]: number }
|
||||||
|
totalShares: { [outcome: string]: number }
|
||||||
|
totalBets: { [outcome: string]: number }
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CPMM = {
|
||||||
|
mechanism: 'cpmm-1'
|
||||||
|
|
||||||
|
pool: { [outcome: string]: number }
|
||||||
|
k: number // liquidity constant
|
||||||
|
liquidity: { [userId: string]: { [outcome: string]: number } } // track liquidity providers
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Binary = {
|
||||||
|
outcomeType: 'BINARY'
|
||||||
|
resolutionProbability?: number // Used for BINARY markets resolved to MKT
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Multi = {
|
||||||
|
outcomeType: 'MULTI'
|
||||||
|
multiOutcomes: string[] // Used for outcomeType 'MULTI'.
|
||||||
|
resolutions?: { [outcome: string]: number } // Used for PROB
|
||||||
|
}
|
||||||
|
|
||||||
|
export type FreeResponse = {
|
||||||
|
outcomeType: 'FREE_RESPONSE'
|
||||||
|
answers: Answer[] // Used for outcomeType 'FREE_RESPONSE'.
|
||||||
|
resolutions?: { [outcome: string]: number } // Used for PROB
|
||||||
}
|
}
|
||||||
|
|
||||||
export type outcomeType = 'BINARY' | 'MULTI' | 'FREE_RESPONSE'
|
export type outcomeType = 'BINARY' | 'MULTI' | 'FREE_RESPONSE'
|
||||||
|
|
|
@ -4,14 +4,60 @@ import {
|
||||||
getProbability,
|
getProbability,
|
||||||
getOutcomeProbability,
|
getOutcomeProbability,
|
||||||
} from './calculate'
|
} from './calculate'
|
||||||
import { Contract } from './contract'
|
import { calculateCpmmShares, getCpmmProbability } from './calculate-cpmm'
|
||||||
|
import {
|
||||||
|
Binary,
|
||||||
|
CPMM,
|
||||||
|
DPM,
|
||||||
|
FreeResponse,
|
||||||
|
FullContract,
|
||||||
|
Multi,
|
||||||
|
} from './contract'
|
||||||
import { User } from './user'
|
import { User } from './user'
|
||||||
|
|
||||||
export const getNewBinaryBetInfo = (
|
export const getNewBinaryCpmmBetInfo = (
|
||||||
user: User,
|
user: User,
|
||||||
outcome: 'YES' | 'NO',
|
outcome: 'YES' | 'NO',
|
||||||
amount: number,
|
amount: number,
|
||||||
contract: Contract,
|
contract: FullContract<CPMM, Binary>,
|
||||||
|
newBetId: string
|
||||||
|
) => {
|
||||||
|
const { pool, k } = contract
|
||||||
|
|
||||||
|
const shares = calculateCpmmShares(pool, k, amount, outcome)
|
||||||
|
const { YES: y, NO: n } = pool
|
||||||
|
|
||||||
|
const [newY, newN] =
|
||||||
|
outcome === 'YES'
|
||||||
|
? [y - shares + amount, amount]
|
||||||
|
: [amount, n - shares + amount]
|
||||||
|
|
||||||
|
const newBalance = user.balance - amount
|
||||||
|
|
||||||
|
const probBefore = getCpmmProbability(pool)
|
||||||
|
const newPool = { YES: newY, NO: newN }
|
||||||
|
const probAfter = getCpmmProbability(newPool)
|
||||||
|
|
||||||
|
const newBet: Bet = {
|
||||||
|
id: newBetId,
|
||||||
|
userId: user.id,
|
||||||
|
contractId: contract.id,
|
||||||
|
amount,
|
||||||
|
shares,
|
||||||
|
outcome,
|
||||||
|
probBefore,
|
||||||
|
probAfter,
|
||||||
|
createdTime: Date.now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
return { newBet, newPool, newBalance }
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getNewBinaryDpmBetInfo = (
|
||||||
|
user: User,
|
||||||
|
outcome: 'YES' | 'NO',
|
||||||
|
amount: number,
|
||||||
|
contract: FullContract<DPM, Binary>,
|
||||||
newBetId: string
|
newBetId: string
|
||||||
) => {
|
) => {
|
||||||
const { YES: yesPool, NO: noPool } = contract.pool
|
const { YES: yesPool, NO: noPool } = contract.pool
|
||||||
|
@ -61,7 +107,7 @@ export const getNewMultiBetInfo = (
|
||||||
user: User,
|
user: User,
|
||||||
outcome: string,
|
outcome: string,
|
||||||
amount: number,
|
amount: number,
|
||||||
contract: Contract,
|
contract: FullContract<DPM, Multi | FreeResponse>,
|
||||||
newBetId: string
|
newBetId: string
|
||||||
) => {
|
) => {
|
||||||
const { pool, totalShares, totalBets } = contract
|
const { pool, totalShares, totalBets } = contract
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
import { calcStartPool } from './antes'
|
import { calcStartPool, calcStartCpmmPool } from './antes'
|
||||||
import { Contract, outcomeType } from './contract'
|
import {
|
||||||
|
Binary,
|
||||||
|
Contract,
|
||||||
|
CPMM,
|
||||||
|
DPM,
|
||||||
|
FreeResponse,
|
||||||
|
outcomeType,
|
||||||
|
} from './contract'
|
||||||
import { User } from './user'
|
import { User } from './user'
|
||||||
import { parseTags } from './util/parse'
|
import { parseTags } from './util/parse'
|
||||||
import { removeUndefinedProps } from './util/object'
|
import { removeUndefinedProps } from './util/object'
|
||||||
|
@ -23,13 +30,12 @@ export function getNewContract(
|
||||||
|
|
||||||
const propsByOutcomeType =
|
const propsByOutcomeType =
|
||||||
outcomeType === 'BINARY'
|
outcomeType === 'BINARY'
|
||||||
? getBinaryProps(initialProb, ante)
|
? getBinaryCpmmProps(initialProb, ante, creator.id) // getBinaryDpmProps(initialProb, ante)
|
||||||
: getFreeAnswerProps(ante)
|
: getFreeAnswerProps(ante)
|
||||||
|
|
||||||
const contract: Contract = removeUndefinedProps({
|
const contract = removeUndefinedProps({
|
||||||
id,
|
id,
|
||||||
slug,
|
slug,
|
||||||
mechanism: 'dpm-2',
|
|
||||||
outcomeType,
|
outcomeType,
|
||||||
...propsByOutcomeType,
|
...propsByOutcomeType,
|
||||||
|
|
||||||
|
@ -52,28 +58,55 @@ export function getNewContract(
|
||||||
volume7Days: 0,
|
volume7Days: 0,
|
||||||
})
|
})
|
||||||
|
|
||||||
return contract
|
return contract as Contract
|
||||||
}
|
}
|
||||||
|
|
||||||
const getBinaryProps = (initialProb: number, ante: number) => {
|
const getBinaryDpmProps = (initialProb: number, ante: number) => {
|
||||||
const { sharesYes, sharesNo, poolYes, poolNo, phantomYes, phantomNo } =
|
const { sharesYes, sharesNo, poolYes, poolNo, phantomYes, phantomNo } =
|
||||||
calcStartPool(initialProb, ante)
|
calcStartPool(initialProb, ante)
|
||||||
|
|
||||||
return {
|
const system: DPM & Binary = {
|
||||||
|
mechanism: 'dpm-2',
|
||||||
|
outcomeType: 'BINARY',
|
||||||
phantomShares: { YES: phantomYes, NO: phantomNo },
|
phantomShares: { YES: phantomYes, NO: phantomNo },
|
||||||
pool: { YES: poolYes, NO: poolNo },
|
pool: { YES: poolYes, NO: poolNo },
|
||||||
totalShares: { YES: sharesYes, NO: sharesNo },
|
totalShares: { YES: sharesYes, NO: sharesNo },
|
||||||
totalBets: { YES: poolYes, NO: poolNo },
|
totalBets: { YES: poolYes, NO: poolNo },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return system
|
||||||
|
}
|
||||||
|
|
||||||
|
const getBinaryCpmmProps = (
|
||||||
|
initialProb: number,
|
||||||
|
ante: number,
|
||||||
|
userId: string
|
||||||
|
) => {
|
||||||
|
const { poolYes, poolNo, k } = calcStartCpmmPool(initialProb, ante)
|
||||||
|
const pool = { YES: poolYes, NO: poolNo }
|
||||||
|
|
||||||
|
const system: CPMM & Binary = {
|
||||||
|
mechanism: 'cpmm-1',
|
||||||
|
outcomeType: 'BINARY',
|
||||||
|
pool: pool,
|
||||||
|
k,
|
||||||
|
liquidity: { [userId]: pool },
|
||||||
|
}
|
||||||
|
|
||||||
|
return system
|
||||||
}
|
}
|
||||||
|
|
||||||
const getFreeAnswerProps = (ante: number) => {
|
const getFreeAnswerProps = (ante: number) => {
|
||||||
return {
|
const system: DPM & FreeResponse = {
|
||||||
|
mechanism: 'dpm-2',
|
||||||
|
outcomeType: 'FREE_RESPONSE',
|
||||||
pool: { '0': ante },
|
pool: { '0': ante },
|
||||||
totalShares: { '0': ante },
|
totalShares: { '0': ante },
|
||||||
totalBets: { '0': ante },
|
totalBets: { '0': ante },
|
||||||
answers: [],
|
answers: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return system
|
||||||
}
|
}
|
||||||
|
|
||||||
const getMultiProps = (
|
const getMultiProps = (
|
||||||
|
|
|
@ -2,10 +2,21 @@ import * as _ from 'lodash'
|
||||||
|
|
||||||
import { Bet } from './bet'
|
import { Bet } from './bet'
|
||||||
import { deductFees, getProbability } from './calculate'
|
import { deductFees, getProbability } from './calculate'
|
||||||
import { Contract } from './contract'
|
import {
|
||||||
|
Binary,
|
||||||
|
Contract,
|
||||||
|
CPMM,
|
||||||
|
DPM,
|
||||||
|
FreeResponse,
|
||||||
|
FullContract,
|
||||||
|
Multi,
|
||||||
|
} from './contract'
|
||||||
import { CREATOR_FEE, FEES } from './fees'
|
import { CREATOR_FEE, FEES } from './fees'
|
||||||
|
|
||||||
export const getCancelPayouts = (contract: Contract, bets: Bet[]) => {
|
export const getDpmCancelPayouts = (
|
||||||
|
contract: FullContract<DPM, any>,
|
||||||
|
bets: Bet[]
|
||||||
|
) => {
|
||||||
const { pool } = contract
|
const { pool } = contract
|
||||||
const poolTotal = _.sum(Object.values(pool))
|
const poolTotal = _.sum(Object.values(pool))
|
||||||
console.log('resolved N/A, pool M$', poolTotal)
|
console.log('resolved N/A, pool M$', poolTotal)
|
||||||
|
@ -18,9 +29,59 @@ export const getCancelPayouts = (contract: Contract, bets: Bet[]) => {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getFixedCancelPayouts = (bets: Bet[]) => {
|
||||||
|
return bets.map((bet) => ({
|
||||||
|
userId: bet.userId,
|
||||||
|
payout: bet.amount,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getStandardFixedPayouts = (
|
||||||
|
outcome: string,
|
||||||
|
contract: FullContract<CPMM, Binary>,
|
||||||
|
bets: Bet[]
|
||||||
|
) => {
|
||||||
|
const winningBets = bets.filter((bet) => bet.outcome === outcome)
|
||||||
|
|
||||||
|
const payouts = winningBets.map(({ userId, amount, shares }) => {
|
||||||
|
const winnings = shares
|
||||||
|
const profit = winnings - amount
|
||||||
|
|
||||||
|
const payout = amount + (1 - FEES) * profit
|
||||||
|
return { userId, profit, payout }
|
||||||
|
})
|
||||||
|
|
||||||
|
const profits = _.sumBy(payouts, (po) => Math.max(0, po.profit))
|
||||||
|
const creatorPayout = CREATOR_FEE * profits
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
'resolved',
|
||||||
|
outcome,
|
||||||
|
'pool',
|
||||||
|
contract.pool,
|
||||||
|
'profits',
|
||||||
|
profits,
|
||||||
|
'creator fee',
|
||||||
|
creatorPayout
|
||||||
|
)
|
||||||
|
|
||||||
|
return payouts
|
||||||
|
.map(({ userId, payout }) => ({ userId, payout }))
|
||||||
|
.concat([{ userId: contract.creatorId, payout: creatorPayout }]) // add creator fee
|
||||||
|
.concat(getLiquidityPoolPayouts(contract, outcome))
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getLiquidityPoolPayouts = (
|
||||||
|
contract: FullContract<CPMM, Binary>,
|
||||||
|
outcome: string
|
||||||
|
) => {
|
||||||
|
const { creatorId, pool } = contract
|
||||||
|
return [{ userId: creatorId, payout: pool[outcome] }]
|
||||||
|
}
|
||||||
|
|
||||||
export const getStandardPayouts = (
|
export const getStandardPayouts = (
|
||||||
outcome: string,
|
outcome: string,
|
||||||
contract: Contract,
|
contract: FullContract<DPM, any>,
|
||||||
bets: Bet[]
|
bets: Bet[]
|
||||||
) => {
|
) => {
|
||||||
const winningBets = bets.filter((bet) => bet.outcome === outcome)
|
const winningBets = bets.filter((bet) => bet.outcome === outcome)
|
||||||
|
@ -57,7 +118,7 @@ export const getStandardPayouts = (
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getMktPayouts = (
|
export const getMktPayouts = (
|
||||||
contract: Contract,
|
contract: FullContract<DPM, any>,
|
||||||
bets: Bet[],
|
bets: Bet[],
|
||||||
resolutionProbability?: number
|
resolutionProbability?: number
|
||||||
) => {
|
) => {
|
||||||
|
@ -99,12 +160,71 @@ export const getMktPayouts = (
|
||||||
.concat([{ userId: contract.creatorId, payout: creatorPayout }]) // add creator fee
|
.concat([{ userId: contract.creatorId, payout: creatorPayout }]) // add creator fee
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getMktFixedPayouts = (
|
||||||
|
contract: FullContract<CPMM, Binary>,
|
||||||
|
bets: Bet[],
|
||||||
|
resolutionProbability?: number
|
||||||
|
) => {
|
||||||
|
const p =
|
||||||
|
resolutionProbability === undefined
|
||||||
|
? getProbability(contract.pool)
|
||||||
|
: resolutionProbability
|
||||||
|
|
||||||
|
const payouts = bets.map(({ userId, outcome, amount, shares }) => {
|
||||||
|
const betP = outcome === 'YES' ? p : 1 - p
|
||||||
|
const winnings = betP * shares
|
||||||
|
const profit = winnings - amount
|
||||||
|
const payout = deductFees(amount, winnings)
|
||||||
|
return { userId, profit, payout }
|
||||||
|
})
|
||||||
|
|
||||||
|
const profits = _.sumBy(payouts, (po) => Math.max(0, po.profit))
|
||||||
|
const creatorPayout = CREATOR_FEE * profits
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
'resolved MKT',
|
||||||
|
p,
|
||||||
|
'pool',
|
||||||
|
contract.pool,
|
||||||
|
'profits',
|
||||||
|
profits,
|
||||||
|
'creator fee',
|
||||||
|
creatorPayout
|
||||||
|
)
|
||||||
|
|
||||||
|
return payouts
|
||||||
|
.map(({ userId, payout }) => ({ userId, payout }))
|
||||||
|
.concat([{ userId: contract.creatorId, payout: creatorPayout }]) // add creator fee
|
||||||
|
.concat(getLiquidityPoolProbPayouts(contract, p))
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getLiquidityPoolProbPayouts = (
|
||||||
|
contract: FullContract<CPMM, Binary>,
|
||||||
|
p: number
|
||||||
|
) => {
|
||||||
|
const { creatorId, pool } = contract
|
||||||
|
const payout = p * pool.YES + (1 - p) * pool.NO
|
||||||
|
return [{ userId: creatorId, payout }]
|
||||||
|
}
|
||||||
|
|
||||||
export const getPayouts = (
|
export const getPayouts = (
|
||||||
outcome: string,
|
outcome: string,
|
||||||
contract: Contract,
|
contract: Contract,
|
||||||
bets: Bet[],
|
bets: Bet[],
|
||||||
resolutionProbability?: number
|
resolutionProbability?: number
|
||||||
) => {
|
) => {
|
||||||
|
if (contract.mechanism === 'cpmm-1') {
|
||||||
|
switch (outcome) {
|
||||||
|
case 'YES':
|
||||||
|
case 'NO':
|
||||||
|
return getStandardFixedPayouts(outcome, contract as any, bets)
|
||||||
|
case 'MKT':
|
||||||
|
return getMktFixedPayouts(contract as any, bets, resolutionProbability)
|
||||||
|
case 'CANCEL':
|
||||||
|
return getFixedCancelPayouts(bets)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (outcome) {
|
switch (outcome) {
|
||||||
case 'YES':
|
case 'YES':
|
||||||
case 'NO':
|
case 'NO':
|
||||||
|
@ -112,7 +232,7 @@ export const getPayouts = (
|
||||||
case 'MKT':
|
case 'MKT':
|
||||||
return getMktPayouts(contract, bets, resolutionProbability)
|
return getMktPayouts(contract, bets, resolutionProbability)
|
||||||
case 'CANCEL':
|
case 'CANCEL':
|
||||||
return getCancelPayouts(contract, bets)
|
return getDpmCancelPayouts(contract, bets)
|
||||||
default:
|
default:
|
||||||
// Multi outcome.
|
// Multi outcome.
|
||||||
return getStandardPayouts(outcome, contract, bets)
|
return getStandardPayouts(outcome, contract, bets)
|
||||||
|
@ -121,7 +241,7 @@ export const getPayouts = (
|
||||||
|
|
||||||
export const getPayoutsMultiOutcome = (
|
export const getPayoutsMultiOutcome = (
|
||||||
resolutions: { [outcome: string]: number },
|
resolutions: { [outcome: string]: number },
|
||||||
contract: Contract,
|
contract: FullContract<DPM, Multi | FreeResponse>,
|
||||||
bets: Bet[]
|
bets: Bet[]
|
||||||
) => {
|
) => {
|
||||||
const poolTotal = _.sum(Object.values(contract.pool))
|
const poolTotal = _.sum(Object.values(contract.pool))
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import * as _ from 'lodash'
|
import * as _ from 'lodash'
|
||||||
import { Bet } from './bet'
|
import { Bet } from './bet'
|
||||||
import { Contract } from './contract'
|
import { Binary, Contract, FullContract } from './contract'
|
||||||
import { getPayouts } from './payouts'
|
import { getPayouts } from './payouts'
|
||||||
|
|
||||||
export function scoreCreators(contracts: Contract[], bets: Bet[][]) {
|
export function scoreCreators(contracts: Contract[], bets: Bet[][]) {
|
||||||
|
@ -23,7 +23,10 @@ export function scoreTraders(contracts: Contract[], bets: Bet[][]) {
|
||||||
return userScores
|
return userScores
|
||||||
}
|
}
|
||||||
|
|
||||||
export function scoreUsersByContract(contract: Contract, bets: Bet[]) {
|
export function scoreUsersByContract(
|
||||||
|
contract: FullContract<any, Binary>,
|
||||||
|
bets: Bet[]
|
||||||
|
) {
|
||||||
const { resolution, resolutionProbability } = contract
|
const { resolution, resolutionProbability } = contract
|
||||||
|
|
||||||
const [closedBets, openBets] = _.partition(
|
const [closedBets, openBets] = _.partition(
|
||||||
|
|
|
@ -1,13 +1,18 @@
|
||||||
import { Bet } from './bet'
|
import { Bet } from './bet'
|
||||||
import { calculateShareValue, deductFees, getProbability } from './calculate'
|
import { calculateShareValue, deductFees, getProbability } from './calculate'
|
||||||
import { Contract } from './contract'
|
import {
|
||||||
|
calculateCpmmSale,
|
||||||
|
calculateCpmmShareValue,
|
||||||
|
getCpmmProbability,
|
||||||
|
} from './calculate-cpmm'
|
||||||
|
import { Binary, DPM, CPMM, FullContract } from './contract'
|
||||||
import { CREATOR_FEE } from './fees'
|
import { CREATOR_FEE } from './fees'
|
||||||
import { User } from './user'
|
import { User } from './user'
|
||||||
|
|
||||||
export const getSellBetInfo = (
|
export const getSellBetInfo = (
|
||||||
user: User,
|
user: User,
|
||||||
bet: Bet,
|
bet: Bet,
|
||||||
contract: Contract,
|
contract: FullContract<DPM, any>,
|
||||||
newBetId: string
|
newBetId: string
|
||||||
) => {
|
) => {
|
||||||
const { pool, totalShares, totalBets } = contract
|
const { pool, totalShares, totalBets } = contract
|
||||||
|
@ -68,3 +73,57 @@ export const getSellBetInfo = (
|
||||||
creatorFee,
|
creatorFee,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getCpmmSellBetInfo = (
|
||||||
|
user: User,
|
||||||
|
bet: Bet,
|
||||||
|
contract: FullContract<CPMM, Binary>,
|
||||||
|
newBetId: string
|
||||||
|
) => {
|
||||||
|
const { pool } = contract
|
||||||
|
const { id: betId, amount, shares, outcome } = bet
|
||||||
|
|
||||||
|
const { saleValue, newPool } = calculateCpmmSale(contract, bet)
|
||||||
|
|
||||||
|
const probBefore = getCpmmProbability(pool)
|
||||||
|
const probAfter = getCpmmProbability(newPool)
|
||||||
|
|
||||||
|
const profit = saleValue - amount
|
||||||
|
const creatorFee = CREATOR_FEE * Math.max(0, profit)
|
||||||
|
const saleAmount = deductFees(amount, profit)
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
'SELL M$',
|
||||||
|
amount,
|
||||||
|
outcome,
|
||||||
|
'for M$',
|
||||||
|
saleAmount,
|
||||||
|
'creator fee: M$',
|
||||||
|
creatorFee
|
||||||
|
)
|
||||||
|
|
||||||
|
const newBet: Bet = {
|
||||||
|
id: newBetId,
|
||||||
|
userId: user.id,
|
||||||
|
contractId: contract.id,
|
||||||
|
amount: -saleValue,
|
||||||
|
shares: -shares,
|
||||||
|
outcome,
|
||||||
|
probBefore,
|
||||||
|
probAfter,
|
||||||
|
createdTime: Date.now(),
|
||||||
|
sale: {
|
||||||
|
amount: saleAmount,
|
||||||
|
betId,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const newBalance = user.balance + saleAmount
|
||||||
|
|
||||||
|
return {
|
||||||
|
newBet,
|
||||||
|
newPool,
|
||||||
|
newBalance,
|
||||||
|
creatorFee,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,12 +2,21 @@ import * as functions from 'firebase-functions'
|
||||||
import * as admin from 'firebase-admin'
|
import * as admin from 'firebase-admin'
|
||||||
|
|
||||||
import { chargeUser, getUser } from './utils'
|
import { chargeUser, getUser } from './utils'
|
||||||
import { Contract, outcomeType } from '../../common/contract'
|
import {
|
||||||
|
Binary,
|
||||||
|
Contract,
|
||||||
|
CPMM,
|
||||||
|
DPM,
|
||||||
|
FreeResponse,
|
||||||
|
FullContract,
|
||||||
|
outcomeType,
|
||||||
|
} from '../../common/contract'
|
||||||
import { slugify } from '../../common/util/slugify'
|
import { slugify } from '../../common/util/slugify'
|
||||||
import { randomString } from '../../common/util/random'
|
import { randomString } from '../../common/util/random'
|
||||||
import { getNewContract } from '../../common/new-contract'
|
import { getNewContract } from '../../common/new-contract'
|
||||||
import {
|
import {
|
||||||
getAnteBets,
|
getAnteBets,
|
||||||
|
getCpmmAnteBet,
|
||||||
getFreeAnswerAnte,
|
getFreeAnswerAnte,
|
||||||
MINIMUM_ANTE,
|
MINIMUM_ANTE,
|
||||||
} from '../../common/antes'
|
} from '../../common/antes'
|
||||||
|
@ -89,7 +98,7 @@ export const createContract = functions
|
||||||
await contractRef.create(contract)
|
await contractRef.create(contract)
|
||||||
|
|
||||||
if (ante) {
|
if (ante) {
|
||||||
if (outcomeType === 'BINARY') {
|
if (outcomeType === 'BINARY' && contract.mechanism === 'dpm-2') {
|
||||||
const yesBetDoc = firestore
|
const yesBetDoc = firestore
|
||||||
.collection(`contracts/${contract.id}/bets`)
|
.collection(`contracts/${contract.id}/bets`)
|
||||||
.doc()
|
.doc()
|
||||||
|
@ -100,23 +109,51 @@ export const createContract = functions
|
||||||
|
|
||||||
const { yesBet, noBet } = getAnteBets(
|
const { yesBet, noBet } = getAnteBets(
|
||||||
creator,
|
creator,
|
||||||
contract,
|
contract as FullContract<DPM, Binary>,
|
||||||
yesBetDoc.id,
|
yesBetDoc.id,
|
||||||
noBetDoc.id
|
noBetDoc.id
|
||||||
)
|
)
|
||||||
|
|
||||||
await yesBetDoc.set(yesBet)
|
await yesBetDoc.set(yesBet)
|
||||||
await noBetDoc.set(noBet)
|
await noBetDoc.set(noBet)
|
||||||
|
} else if (outcomeType === 'BINARY') {
|
||||||
|
const { YES: y, NO: n } = contract.pool
|
||||||
|
const anteBet = Math.abs(y - n)
|
||||||
|
|
||||||
|
if (anteBet) {
|
||||||
|
const betDoc = firestore
|
||||||
|
.collection(`contracts/${contract.id}/bets`)
|
||||||
|
.doc()
|
||||||
|
|
||||||
|
const outcome = y > n ? 'NO' : 'YES' // more in YES pool if prob leans NO
|
||||||
|
|
||||||
|
const bet = await getCpmmAnteBet(
|
||||||
|
creator,
|
||||||
|
contract as FullContract<CPMM, Binary>,
|
||||||
|
betDoc.id,
|
||||||
|
anteBet,
|
||||||
|
outcome
|
||||||
|
)
|
||||||
|
|
||||||
|
await betDoc.set(bet)
|
||||||
|
}
|
||||||
} else if (outcomeType === 'FREE_RESPONSE') {
|
} else if (outcomeType === 'FREE_RESPONSE') {
|
||||||
const noneAnswerDoc = firestore
|
const noneAnswerDoc = firestore
|
||||||
.collection(`contracts/${contract.id}/answers`)
|
.collection(`contracts/${contract.id}/answers`)
|
||||||
.doc('0')
|
.doc('0')
|
||||||
|
|
||||||
const noneAnswer = getNoneAnswer(contract.id, creator)
|
const noneAnswer = getNoneAnswer(contract.id, creator)
|
||||||
await noneAnswerDoc.set(noneAnswer)
|
await noneAnswerDoc.set(noneAnswer)
|
||||||
|
|
||||||
const anteBetDoc = firestore
|
const anteBetDoc = firestore
|
||||||
.collection(`contracts/${contract.id}/bets`)
|
.collection(`contracts/${contract.id}/bets`)
|
||||||
.doc()
|
.doc()
|
||||||
const anteBet = getFreeAnswerAnte(creator, contract, anteBetDoc.id)
|
|
||||||
|
const anteBet = getFreeAnswerAnte(
|
||||||
|
creator,
|
||||||
|
contract as FullContract<DPM, FreeResponse>,
|
||||||
|
anteBetDoc.id
|
||||||
|
)
|
||||||
await anteBetDoc.set(anteBet)
|
await anteBetDoc.set(anteBet)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,12 @@ import * as admin from 'firebase-admin'
|
||||||
|
|
||||||
import { Contract } from '../../common/contract'
|
import { Contract } from '../../common/contract'
|
||||||
import { User } from '../../common/user'
|
import { User } from '../../common/user'
|
||||||
import { getNewBinaryBetInfo, getNewMultiBetInfo } from '../../common/new-bet'
|
import {
|
||||||
|
getNewBinaryCpmmBetInfo,
|
||||||
|
getNewBinaryDpmBetInfo,
|
||||||
|
getNewMultiBetInfo,
|
||||||
|
} from '../../common/new-bet'
|
||||||
|
import { removeUndefinedProps } from '../../common/util/object'
|
||||||
|
|
||||||
export const placeBet = functions.runWith({ minInstances: 1 }).https.onCall(
|
export const placeBet = functions.runWith({ minInstances: 1 }).https.onCall(
|
||||||
async (
|
async (
|
||||||
|
@ -42,7 +47,7 @@ export const placeBet = functions.runWith({ minInstances: 1 }).https.onCall(
|
||||||
return { status: 'error', message: 'Invalid contract' }
|
return { status: 'error', message: 'Invalid contract' }
|
||||||
const contract = contractSnap.data() as Contract
|
const contract = contractSnap.data() as Contract
|
||||||
|
|
||||||
const { closeTime, outcomeType } = contract
|
const { closeTime, outcomeType, mechanism } = contract
|
||||||
if (closeTime && Date.now() > closeTime)
|
if (closeTime && Date.now() > closeTime)
|
||||||
return { status: 'error', message: 'Trading is closed' }
|
return { status: 'error', message: 'Trading is closed' }
|
||||||
|
|
||||||
|
@ -60,21 +65,40 @@ export const placeBet = functions.runWith({ minInstances: 1 }).https.onCall(
|
||||||
|
|
||||||
const { newBet, newPool, newTotalShares, newTotalBets, newBalance } =
|
const { newBet, newPool, newTotalShares, newTotalBets, newBalance } =
|
||||||
outcomeType === 'BINARY'
|
outcomeType === 'BINARY'
|
||||||
? getNewBinaryBetInfo(
|
? mechanism === 'dpm-2'
|
||||||
|
? getNewBinaryDpmBetInfo(
|
||||||
|
user,
|
||||||
|
outcome as 'YES' | 'NO',
|
||||||
|
amount,
|
||||||
|
contract,
|
||||||
|
newBetDoc.id
|
||||||
|
)
|
||||||
|
: (getNewBinaryCpmmBetInfo(
|
||||||
|
user,
|
||||||
|
outcome as 'YES' | 'NO',
|
||||||
|
amount,
|
||||||
|
contract,
|
||||||
|
newBetDoc.id
|
||||||
|
) as any)
|
||||||
|
: getNewMultiBetInfo(
|
||||||
user,
|
user,
|
||||||
outcome as 'YES' | 'NO',
|
outcome,
|
||||||
amount,
|
amount,
|
||||||
contract,
|
contract as any,
|
||||||
newBetDoc.id
|
newBetDoc.id
|
||||||
)
|
)
|
||||||
: getNewMultiBetInfo(user, outcome, amount, contract, newBetDoc.id)
|
|
||||||
|
|
||||||
transaction.create(newBetDoc, newBet)
|
transaction.create(newBetDoc, newBet)
|
||||||
transaction.update(contractDoc, {
|
|
||||||
pool: newPool,
|
transaction.update(
|
||||||
totalShares: newTotalShares,
|
contractDoc,
|
||||||
totalBets: newTotalBets,
|
removeUndefinedProps({
|
||||||
})
|
pool: newPool,
|
||||||
|
totalShares: newTotalShares,
|
||||||
|
totalBets: newTotalBets,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
transaction.update(userDoc, { balance: newBalance })
|
transaction.update(userDoc, { balance: newBalance })
|
||||||
|
|
||||||
return { status: 'success', betId: newBetDoc.id }
|
return { status: 'success', betId: newBetDoc.id }
|
||||||
|
|
|
@ -89,7 +89,7 @@ export const resolveMarket = functions
|
||||||
|
|
||||||
const payouts =
|
const payouts =
|
||||||
outcomeType === 'FREE_RESPONSE' && resolutions
|
outcomeType === 'FREE_RESPONSE' && resolutions
|
||||||
? getPayoutsMultiOutcome(resolutions, contract, openBets)
|
? getPayoutsMultiOutcome(resolutions, contract as any, openBets)
|
||||||
: getPayouts(outcome, contract, openBets, resolutionProbability)
|
: getPayouts(outcome, contract, openBets, resolutionProbability)
|
||||||
|
|
||||||
console.log('payouts:', payouts)
|
console.log('payouts:', payouts)
|
||||||
|
|
|
@ -4,7 +4,8 @@ import * as functions from 'firebase-functions'
|
||||||
import { Contract } from '../../common/contract'
|
import { Contract } from '../../common/contract'
|
||||||
import { User } from '../../common/user'
|
import { User } from '../../common/user'
|
||||||
import { Bet } from '../../common/bet'
|
import { Bet } from '../../common/bet'
|
||||||
import { getSellBetInfo } from '../../common/sell-bet'
|
import { getCpmmSellBetInfo, getSellBetInfo } from '../../common/sell-bet'
|
||||||
|
import { removeUndefinedProps } from '../../common/util/object'
|
||||||
|
|
||||||
export const sellBet = functions.runWith({ minInstances: 1 }).https.onCall(
|
export const sellBet = functions.runWith({ minInstances: 1 }).https.onCall(
|
||||||
async (
|
async (
|
||||||
|
@ -33,7 +34,7 @@ export const sellBet = functions.runWith({ minInstances: 1 }).https.onCall(
|
||||||
return { status: 'error', message: 'Invalid contract' }
|
return { status: 'error', message: 'Invalid contract' }
|
||||||
const contract = contractSnap.data() as Contract
|
const contract = contractSnap.data() as Contract
|
||||||
|
|
||||||
const { closeTime } = contract
|
const { closeTime, mechanism } = contract
|
||||||
if (closeTime && Date.now() > closeTime)
|
if (closeTime && Date.now() > closeTime)
|
||||||
return { status: 'error', message: 'Trading is closed' }
|
return { status: 'error', message: 'Trading is closed' }
|
||||||
|
|
||||||
|
@ -55,7 +56,15 @@ export const sellBet = functions.runWith({ minInstances: 1 }).https.onCall(
|
||||||
newTotalBets,
|
newTotalBets,
|
||||||
newBalance,
|
newBalance,
|
||||||
creatorFee,
|
creatorFee,
|
||||||
} = getSellBetInfo(user, bet, contract, newBetDoc.id)
|
} =
|
||||||
|
mechanism === 'dpm-2'
|
||||||
|
? getSellBetInfo(user, bet, contract, newBetDoc.id)
|
||||||
|
: (getCpmmSellBetInfo(
|
||||||
|
user,
|
||||||
|
bet,
|
||||||
|
contract as any,
|
||||||
|
newBetDoc.id
|
||||||
|
) as any)
|
||||||
|
|
||||||
if (contract.creatorId === userId) {
|
if (contract.creatorId === userId) {
|
||||||
transaction.update(userDoc, { balance: newBalance + creatorFee })
|
transaction.update(userDoc, { balance: newBalance + creatorFee })
|
||||||
|
@ -74,11 +83,14 @@ export const sellBet = functions.runWith({ minInstances: 1 }).https.onCall(
|
||||||
|
|
||||||
transaction.update(betDoc, { isSold: true })
|
transaction.update(betDoc, { isSold: true })
|
||||||
transaction.create(newBetDoc, newBet)
|
transaction.create(newBetDoc, newBet)
|
||||||
transaction.update(contractDoc, {
|
transaction.update(
|
||||||
pool: newPool,
|
contractDoc,
|
||||||
totalShares: newTotalShares,
|
removeUndefinedProps({
|
||||||
totalBets: newTotalBets,
|
pool: newPool,
|
||||||
})
|
totalShares: newTotalShares,
|
||||||
|
totalBets: newTotalBets,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
return { status: 'success' }
|
return { status: 'success' }
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue
Block a user