2022-03-02 21:12:27 +00:00
|
|
|
import * as _ from 'lodash'
|
|
|
|
import { Bet } from './bet'
|
2022-03-03 17:19:18 +00:00
|
|
|
import { deductFixedFees } from './calculate-fixed-payouts'
|
2022-03-02 21:12:27 +00:00
|
|
|
import { Binary, CPMM, FullContract } from './contract'
|
2022-03-03 17:19:18 +00:00
|
|
|
import { CREATOR_FEE } from './fees'
|
2022-03-02 21:12:27 +00:00
|
|
|
|
|
|
|
export function getCpmmProbability(pool: { [outcome: string]: number }) {
|
|
|
|
// For binary contracts only.
|
|
|
|
const { YES, NO } = pool
|
|
|
|
return NO / (YES + NO)
|
|
|
|
}
|
|
|
|
|
2022-03-03 17:06:24 +00:00
|
|
|
export function getCpmmOutcomeProbabilityAfterBet(
|
2022-03-02 21:12:27 +00:00
|
|
|
contract: FullContract<CPMM, Binary>,
|
|
|
|
outcome: string,
|
|
|
|
bet: number
|
|
|
|
) {
|
|
|
|
const { newPool } = calculateCpmmPurchase(contract, bet, outcome)
|
2022-03-03 17:06:24 +00:00
|
|
|
const p = getCpmmProbability(newPool)
|
|
|
|
return outcome === 'NO' ? 1 - p : p
|
2022-03-02 21:12:27 +00:00
|
|
|
}
|
|
|
|
|
2022-03-07 23:49:55 +00:00
|
|
|
// before liquidity fee
|
|
|
|
function calculateCpmmShares(
|
2022-03-02 21:12:27 +00:00
|
|
|
pool: {
|
|
|
|
[outcome: string]: number
|
|
|
|
},
|
|
|
|
bet: number,
|
|
|
|
betChoice: string
|
|
|
|
) {
|
|
|
|
const { YES: y, NO: n } = pool
|
2022-03-07 23:49:55 +00:00
|
|
|
const numerator = bet ** 2 + bet * (y + n)
|
2022-03-02 21:12:27 +00:00
|
|
|
const denominator = betChoice === 'YES' ? bet + n : bet + y
|
|
|
|
const shares = numerator / denominator
|
|
|
|
return shares
|
|
|
|
}
|
|
|
|
|
2022-03-08 18:19:38 +00:00
|
|
|
export const CPMM_LIQUIDITY_FEE = 0.02
|
2022-03-07 23:49:55 +00:00
|
|
|
|
|
|
|
export function getCpmmLiquidityFee(
|
|
|
|
contract: FullContract<CPMM, Binary>,
|
|
|
|
bet: number,
|
|
|
|
outcome: string
|
|
|
|
) {
|
|
|
|
const p = getCpmmProbability(contract.pool)
|
|
|
|
const betP = outcome === 'YES' ? 1 - p : p
|
|
|
|
const fee = CPMM_LIQUIDITY_FEE * betP * bet
|
|
|
|
const remainingBet = bet - fee
|
|
|
|
return { fee, remainingBet }
|
|
|
|
}
|
|
|
|
|
|
|
|
export function calculateCpmmSharesAfterFee(
|
|
|
|
contract: FullContract<CPMM, Binary>,
|
|
|
|
bet: number,
|
|
|
|
outcome: string
|
|
|
|
) {
|
|
|
|
const { pool } = contract
|
|
|
|
const { remainingBet } = getCpmmLiquidityFee(contract, bet, outcome)
|
|
|
|
|
|
|
|
return calculateCpmmShares(pool, remainingBet, outcome)
|
|
|
|
}
|
|
|
|
|
2022-03-02 21:12:27 +00:00
|
|
|
export function calculateCpmmPurchase(
|
|
|
|
contract: FullContract<CPMM, Binary>,
|
|
|
|
bet: number,
|
|
|
|
outcome: string
|
|
|
|
) {
|
2022-03-07 17:29:58 +00:00
|
|
|
const { pool } = contract
|
2022-03-07 23:49:55 +00:00
|
|
|
const { remainingBet } = getCpmmLiquidityFee(contract, bet, outcome)
|
2022-03-02 21:12:27 +00:00
|
|
|
|
2022-03-07 23:49:55 +00:00
|
|
|
const shares = calculateCpmmShares(pool, remainingBet, outcome)
|
2022-03-02 21:12:27 +00:00
|
|
|
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
|
|
|
|
) {
|
2022-03-07 17:29:58 +00:00
|
|
|
const { pool } = contract
|
2022-03-02 21:12:27 +00:00
|
|
|
const { YES: y, NO: n } = pool
|
|
|
|
|
|
|
|
const poolChange = outcome === 'YES' ? shares + y - n : shares + n - y
|
2022-03-07 17:29:58 +00:00
|
|
|
const k = y * n
|
2022-03-02 21:12:27 +00:00
|
|
|
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
|
|
|
|
|
2022-03-07 23:49:55 +00:00
|
|
|
const rawSaleValue = calculateCpmmShareValue(contract, shares, outcome)
|
|
|
|
|
|
|
|
const { fee, remainingBet: saleValue } = getCpmmLiquidityFee(
|
|
|
|
contract,
|
|
|
|
rawSaleValue,
|
|
|
|
outcome === 'YES' ? 'NO' : 'YES'
|
|
|
|
)
|
2022-03-02 21:12:27 +00:00
|
|
|
|
|
|
|
const { pool } = contract
|
|
|
|
const { YES: y, NO: n } = pool
|
|
|
|
|
|
|
|
const [newY, newN] =
|
|
|
|
outcome === 'YES'
|
2022-03-07 23:49:55 +00:00
|
|
|
? [y + shares - saleValue + fee, n - saleValue + fee]
|
|
|
|
: [y - saleValue + fee, n + shares - saleValue + fee]
|
2022-03-02 21:12:27 +00:00
|
|
|
|
|
|
|
const newPool = { YES: newY, NO: newN }
|
|
|
|
|
2022-03-03 17:19:18 +00:00
|
|
|
const profit = saleValue - bet.amount
|
|
|
|
const creatorFee = CREATOR_FEE * Math.max(0, profit)
|
|
|
|
const saleAmount = deductFixedFees(bet.amount, saleValue)
|
|
|
|
|
|
|
|
return { saleValue, newPool, creatorFee, saleAmount }
|
2022-03-02 21:12:27 +00:00
|
|
|
}
|
|
|
|
|
2022-03-03 05:32:33 +00:00
|
|
|
export function getCpmmProbabilityAfterSale(
|
|
|
|
contract: FullContract<CPMM, Binary>,
|
|
|
|
bet: Bet
|
|
|
|
) {
|
|
|
|
const { newPool } = calculateCpmmSale(contract, bet)
|
|
|
|
return getCpmmProbability(newPool)
|
|
|
|
}
|
2022-03-07 17:29:58 +00:00
|
|
|
|
|
|
|
export const calcCpmmInitialPool = (initialProbInt: number, ante: number) => {
|
|
|
|
const p = initialProbInt / 100.0
|
|
|
|
|
|
|
|
const [poolYes, poolNo] =
|
|
|
|
p >= 0.5 ? [ante * (1 / p - 1), ante] : [ante, ante * (1 / (1 - p) - 1)]
|
|
|
|
|
|
|
|
return { poolYes, poolNo }
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getCpmmLiquidity(pool: { [outcome: string]: number }) {
|
|
|
|
// For binary contracts only.
|
|
|
|
const { YES, NO } = pool
|
|
|
|
return Math.sqrt(YES * NO)
|
|
|
|
}
|
|
|
|
|
|
|
|
export function addCpmmLiquidity(
|
|
|
|
contract: FullContract<CPMM, Binary>,
|
|
|
|
amount: number
|
|
|
|
) {
|
|
|
|
const { YES, NO } = contract.pool
|
|
|
|
const p = getCpmmProbability({ YES, NO })
|
|
|
|
|
|
|
|
const [newYes, newNo] =
|
|
|
|
p >= 0.5
|
|
|
|
? [amount * (1 / p - 1), amount]
|
|
|
|
: [amount, amount * (1 / (1 - p) - 1)]
|
|
|
|
|
|
|
|
const betAmount = Math.abs(newYes - newNo)
|
|
|
|
const betOutcome = p >= 0.5 ? 'YES' : 'NO'
|
|
|
|
|
|
|
|
const poolLiquidity = getCpmmLiquidity({ YES, NO })
|
|
|
|
const newPool = { YES: YES + newYes, NO: NO + newNo }
|
|
|
|
const resultingLiquidity = getCpmmLiquidity(newPool)
|
|
|
|
const liquidity = resultingLiquidity - poolLiquidity
|
|
|
|
|
|
|
|
return { newPool, liquidity, betAmount, betOutcome }
|
|
|
|
}
|
|
|
|
|
|
|
|
export function removeCpmmLiquidity(
|
|
|
|
contract: FullContract<CPMM, Binary>,
|
|
|
|
liquidity: number
|
|
|
|
) {
|
|
|
|
const { YES, NO } = contract.pool
|
|
|
|
const poolLiquidity = getCpmmLiquidity({ YES, NO })
|
|
|
|
const p = getCpmmProbability({ YES, NO })
|
|
|
|
|
|
|
|
const f = liquidity / poolLiquidity
|
|
|
|
const [payoutYes, payoutNo] = [f * YES, f * NO]
|
|
|
|
|
|
|
|
const betAmount = Math.abs(payoutYes - payoutNo)
|
|
|
|
const betOutcome = p >= 0.5 ? 'NO' : 'YES' // opposite side as adding liquidity
|
|
|
|
const payout = Math.min(payoutYes, payoutNo)
|
|
|
|
|
|
|
|
const newPool = { YES: YES - payoutYes, NO: NO - payoutNo }
|
|
|
|
|
|
|
|
return { newPool, payout, betAmount, betOutcome }
|
|
|
|
}
|