separate out creator, liquidity fees in payouts and deduct from profits

This commit is contained in:
mantikoros 2022-05-09 15:56:24 -04:00
parent 6aba2b00f6
commit 2c9e10c841
6 changed files with 124 additions and 81 deletions

View File

@ -27,7 +27,12 @@ export const getDpmCancelPayouts = (
payout: (bet.amount / betSum) * poolTotal, payout: (bet.amount / betSum) * poolTotal,
})) }))
return [payouts, contract.collectedFees ?? noFees] return {
payouts,
creatorPayout: 0,
liquidityPayouts: [],
collectedFees: contract.collectedFees ?? noFees,
}
} }
export const getDpmStandardPayouts = ( export const getDpmStandardPayouts = (
@ -59,7 +64,10 @@ export const getDpmStandardPayouts = (
liquidityFee: 0, liquidityFee: 0,
} }
const fees = addObjects<Fees>(finalFees, contract.collectedFees ?? {}) const collectedFees = addObjects<Fees>(
finalFees,
contract.collectedFees ?? {}
)
console.log( console.log(
'resolved', 'resolved',
@ -72,11 +80,12 @@ export const getDpmStandardPayouts = (
creatorFee creatorFee
) )
const totalPayouts = payouts return {
.map(({ userId, payout }) => ({ userId, payout })) payouts: payouts.map(({ userId, payout }) => ({ userId, payout })),
.concat([{ userId: contract.creatorId, payout: creatorFee }]) // add creator fee creatorPayout: creatorFee,
liquidityPayouts: [],
return [totalPayouts, fees] collectedFees,
}
} }
export const getDpmMktPayouts = ( export const getDpmMktPayouts = (
@ -114,7 +123,10 @@ export const getDpmMktPayouts = (
liquidityFee: 0, liquidityFee: 0,
} }
const fees = addObjects<Fees>(finalFees, contract.collectedFees ?? {}) const collectedFees = addObjects<Fees>(
finalFees,
contract.collectedFees ?? {}
)
console.log( console.log(
'resolved MKT', 'resolved MKT',
@ -127,11 +139,12 @@ export const getDpmMktPayouts = (
creatorFee creatorFee
) )
const totalPayouts = payouts return {
.map(({ userId, payout }) => ({ userId, payout })) payouts: payouts.map(({ userId, payout }) => ({ userId, payout })),
.concat([{ userId: contract.creatorId, payout: creatorFee }]) // add creator fee creatorPayout: creatorFee,
liquidityPayouts: [],
return [totalPayouts, fees] collectedFees,
}
} }
export const getPayoutsMultiOutcome = ( export const getPayoutsMultiOutcome = (
@ -169,7 +182,10 @@ export const getPayoutsMultiOutcome = (
liquidityFee: 0, liquidityFee: 0,
} }
const fees = addObjects<Fees>(finalFees, contract.collectedFees ?? noFees) const collectedFees = addObjects<Fees>(
finalFees,
contract.collectedFees ?? noFees
)
console.log( console.log(
'resolved', 'resolved',
@ -181,10 +197,10 @@ export const getPayoutsMultiOutcome = (
'creator fee', 'creator fee',
creatorFee creatorFee
) )
return {
const totalPayouts = payouts payouts: payouts.map(({ userId, payout }) => ({ userId, payout })),
.map(({ userId, payout }) => ({ userId, payout })) creatorPayout: creatorFee,
.concat([{ userId: contract.creatorId, payout: creatorFee }]) // add creator fee liquidityPayouts: [],
collectedFees,
return [totalPayouts, fees] }
} }

View File

@ -4,6 +4,7 @@ import { Bet } from './bet'
import { getProbability } from './calculate' import { getProbability } from './calculate'
import { getCpmmLiquidityPoolWeights } from './calculate-cpmm' import { getCpmmLiquidityPoolWeights } from './calculate-cpmm'
import { Binary, CPMM, FixedPayouts, FullContract } from './contract' import { Binary, CPMM, FixedPayouts, FullContract } from './contract'
import { noFees } from './fees'
import { LiquidityProvision } from './liquidity-provision' import { LiquidityProvision } from './liquidity-provision'
export const getFixedCancelPayouts = ( export const getFixedCancelPayouts = (
@ -15,13 +16,16 @@ export const getFixedCancelPayouts = (
payout: lp.amount, payout: lp.amount,
})) }))
return bets const payouts = bets
.filter((b) => !b.isAnte && !b.isLiquidityProvision) .filter((b) => !b.isAnte && !b.isLiquidityProvision)
.map((bet) => ({ .map((bet) => ({
userId: bet.userId, userId: bet.userId,
payout: bet.amount, payout: bet.amount,
})) }))
.concat(liquidityPayouts)
const creatorPayout = 0
return { payouts, creatorPayout, liquidityPayouts, collectedFees: noFees }
} }
export const getStandardFixedPayouts = ( export const getStandardFixedPayouts = (
@ -37,7 +41,8 @@ export const getStandardFixedPayouts = (
payout: shares, payout: shares,
})) }))
const creatorPayout = contract.collectedFees.creatorFee const { collectedFees } = contract
const creatorPayout = collectedFees.creatorFee
console.log( console.log(
'resolved', 'resolved',
@ -50,10 +55,13 @@ export const getStandardFixedPayouts = (
creatorPayout creatorPayout
) )
return payouts const liquidityPayouts = getLiquidityPoolPayouts(
.map(({ userId, payout }) => ({ userId, payout })) contract,
.concat([{ userId: contract.creatorId, payout: creatorPayout }]) // add creator fee outcome,
.concat(getLiquidityPoolPayouts(contract, outcome, liquidities)) liquidities
)
return { payouts, creatorPayout, liquidityPayouts, collectedFees }
} }
export const getLiquidityPoolPayouts = ( export const getLiquidityPoolPayouts = (
@ -88,7 +96,8 @@ export const getMktFixedPayouts = (
return { userId, payout: betP * shares } return { userId, payout: betP * shares }
}) })
const creatorPayout = contract.collectedFees.creatorFee const { collectedFees } = contract
const creatorPayout = collectedFees.creatorFee
console.log( console.log(
'resolved PROB', 'resolved PROB',
@ -101,10 +110,9 @@ export const getMktFixedPayouts = (
creatorPayout creatorPayout
) )
return payouts const liquidityPayouts = getLiquidityPoolProbPayouts(contract, p, liquidities)
.map(({ userId, payout }) => ({ userId, payout }))
.concat([{ userId: contract.creatorId, payout: creatorPayout }]) // add creator fee return { payouts, creatorPayout, liquidityPayouts, collectedFees }
.concat(getLiquidityPoolProbPayouts(contract, p, liquidities))
} }
export const getLiquidityPoolProbPayouts = ( export const getLiquidityPoolProbPayouts = (

View File

@ -38,6 +38,18 @@ export const getLoanPayouts = (bets: Bet[]): Payout[] => {
return _.toPairs(loansByUser).map(([userId, payout]) => ({ userId, payout })) return _.toPairs(loansByUser).map(([userId, payout]) => ({ userId, payout }))
} }
export const groupPayoutsByUser = (payouts: Payout[]) => {
const groups = _.groupBy(payouts, (payout) => payout.userId)
return _.mapValues(groups, (group) => _.sumBy(group, (g) => g.payout))
}
export type PayoutInfo = {
payouts: Payout[]
creatorPayout: number
liquidityPayouts: Payout[]
collectedFees: Fees
}
export const getPayouts = ( export const getPayouts = (
outcome: string, outcome: string,
resolutions: { resolutions: {
@ -47,16 +59,15 @@ export const getPayouts = (
bets: Bet[], bets: Bet[],
liquidities: LiquidityProvision[], liquidities: LiquidityProvision[],
resolutionProbability?: number resolutionProbability?: number
): [Payout[], Fees] => { ): PayoutInfo => {
if (contract.mechanism === 'cpmm-1' && contract.outcomeType === 'BINARY') { if (contract.mechanism === 'cpmm-1' && contract.outcomeType === 'BINARY') {
const payouts = getFixedPayouts( return getFixedPayouts(
outcome, outcome,
contract, contract,
bets, bets,
liquidities, liquidities,
resolutionProbability resolutionProbability
) )
return [payouts, contract.collectedFees]
} }
return getDpmPayouts( return getDpmPayouts(
@ -74,7 +85,7 @@ export const getFixedPayouts = (
bets: Bet[], bets: Bet[],
liquidities: LiquidityProvision[], liquidities: LiquidityProvision[],
resolutionProbability?: number resolutionProbability?: number
): Payout[] => { ) => {
switch (outcome) { switch (outcome) {
case 'YES': case 'YES':
case 'NO': case 'NO':
@ -100,36 +111,27 @@ export const getDpmPayouts = (
contract: Contract, contract: Contract,
bets: Bet[], bets: Bet[],
resolutionProbability?: number resolutionProbability?: number
) => { ): PayoutInfo => {
const openBets = bets.filter((b) => !b.isSold && !b.sale) const openBets = bets.filter((b) => !b.isSold && !b.sale)
switch (outcome) { switch (outcome) {
case 'YES': case 'YES':
case 'NO': case 'NO':
return getDpmStandardPayouts(outcome, contract, openBets) as [ return getDpmStandardPayouts(outcome, contract, openBets)
Payout[],
Fees
]
case 'MKT': case 'MKT':
return contract.outcomeType === 'FREE_RESPONSE' return contract.outcomeType === 'FREE_RESPONSE'
? (getPayoutsMultiOutcome( ? getPayoutsMultiOutcome(
resolutions, resolutions,
contract as FullContract<DPM, Multi | FreeResponse>, contract as FullContract<DPM, Multi | FreeResponse>,
openBets openBets
) as [Payout[], Fees]) )
: (getDpmMktPayouts(contract, openBets, resolutionProbability) as [ : getDpmMktPayouts(contract, openBets, resolutionProbability)
Payout[],
Fees
])
case 'CANCEL': case 'CANCEL':
return getDpmCancelPayouts(contract, openBets) as [Payout[], Fees] return getDpmCancelPayouts(contract, openBets)
default: default:
// Outcome is a free response answer id. // Outcome is a free response answer id.
return getDpmStandardPayouts(outcome, contract, openBets) as [ return getDpmStandardPayouts(outcome, contract, openBets)
Payout[],
Fees
]
} }
} }

View File

@ -34,7 +34,7 @@ export function scoreUsersByContract(
bets, bets,
(bet) => bet.isSold || bet.sale (bet) => bet.isSold || bet.sale
) )
const [resolvePayouts] = getPayouts( const { payouts: resolvePayouts } = getPayouts(
resolution, resolution,
{}, {},
contract, contract,

View File

@ -7,7 +7,12 @@ import { User } from '../../common/user'
import { Bet } from '../../common/bet' import { Bet } from '../../common/bet'
import { getUser, isProd, payUser } from './utils' import { getUser, isProd, payUser } from './utils'
import { sendMarketResolutionEmail } from './emails' import { sendMarketResolutionEmail } from './emails'
import { getLoanPayouts, getPayouts } from '../../common/payouts' import {
getLoanPayouts,
getPayouts,
groupPayoutsByUser,
Payout,
} from '../../common/payouts'
import { removeUndefinedProps } from '../../common/util/object' import { removeUndefinedProps } from '../../common/util/object'
import { LiquidityProvision } from '../../common/liquidity-provision' import { LiquidityProvision } from '../../common/liquidity-provision'
@ -89,14 +94,15 @@ export const resolveMarket = functions
(doc) => doc.data() as LiquidityProvision (doc) => doc.data() as LiquidityProvision
) )
const [payouts, collectedFees] = getPayouts( const { payouts, creatorPayout, liquidityPayouts, collectedFees } =
outcome, getPayouts(
resolutions ?? {}, outcome,
contract, resolutions ?? {},
bets, contract,
liquidities, bets,
resolutionProbability liquidities,
) resolutionProbability
)
await contractDoc.update( await contractDoc.update(
removeUndefinedProps({ removeUndefinedProps({
@ -115,28 +121,26 @@ export const resolveMarket = functions
const openBets = bets.filter((b) => !b.isSold && !b.sale) const openBets = bets.filter((b) => !b.isSold && !b.sale)
const loanPayouts = getLoanPayouts(openBets) const loanPayouts = getLoanPayouts(openBets)
if (!isProd) console.log('payouts:', payouts) if (!isProd)
console.log(
'payouts:',
payouts,
'creator payout:',
creatorPayout,
'liquidity payout:'
)
const groups = _.groupBy( if (creatorPayout)
[...payouts, ...loanPayouts], await processPayouts(
(payout) => payout.userId [{ userId: creatorId, payout: creatorPayout }],
) true
const userPayouts = _.mapValues(groups, (group) => )
_.sumBy(group, (g) => g.payout)
)
const groupsWithoutLoans = _.groupBy(payouts, (payout) => payout.userId) await processPayouts(liquidityPayouts, true)
const userPayoutsWithoutLoans = _.mapValues(groupsWithoutLoans, (group) =>
_.sumBy(group, (g) => g.payout)
)
const payoutPromises = Object.entries(userPayouts).map( const result = await processPayouts([...payouts, ...loanPayouts])
([userId, payout]) => payUser(userId, payout)
)
const result = await Promise.all(payoutPromises) const userPayoutsWithoutLoans = groupPayoutsByUser(payouts)
.catch((e) => ({ status: 'error', message: e }))
.then(() => ({ status: 'success' }))
await sendResolutionEmails( await sendResolutionEmails(
openBets, openBets,
@ -152,6 +156,18 @@ export const resolveMarket = functions
} }
) )
const processPayouts = async (payouts: Payout[], isDeposit = false) => {
const userPayouts = groupPayoutsByUser(payouts)
const payoutPromises = Object.entries(userPayouts).map(([userId, payout]) =>
payUser(userId, payout, isDeposit)
)
return await Promise.all(payoutPromises)
.catch((e) => ({ status: 'error', message: e }))
.then(() => ({ status: 'success' }))
}
const sendResolutionEmails = async ( const sendResolutionEmails = async (
openBets: Bet[], openBets: Bet[],
userPayouts: { [userId: string]: number }, userPayouts: { [userId: string]: number },

View File

@ -24,7 +24,8 @@ async function checkIfPayOutAgain(contractRef: DocRef, contract: Contract) {
if (loanedBets.length && contract.resolution) { if (loanedBets.length && contract.resolution) {
const { resolution, resolutions, resolutionProbability } = contract as any const { resolution, resolutions, resolutionProbability } = contract as any
const [payouts] = getPayouts(
const { payouts } = getPayouts(
resolution, resolution,
resolutions, resolutions,
contract, contract,