Skip to content

Commit

Permalink
Small resolve refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
IanPhilips committed Nov 4, 2024
1 parent 56a286a commit 1ad01d0
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 122 deletions.
180 changes: 67 additions & 113 deletions backend/shared/src/resolve-market-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,21 +34,12 @@ import {
createSupabaseDirectClient,
} from './supabase/init'
import { Answer } from 'common/answer'
import {
SPICE_PRODUCTION_ENABLED,
isAdminId,
isModId,
} from 'common/envs/constants'
import { isAdminId, isModId } from 'common/envs/constants'
import { convertTxn } from 'common/supabase/txns'
import { bulkIncrementBalances } from './supabase/users'
import { convertBet } from 'common/supabase/bets'
import { convertLiquidity } from 'common/supabase/liquidity'
import {
getAnswer,
getAnswersForContract,
updateAnswer,
updateAnswers,
} from './supabase/answers'
import { updateAnswer, updateAnswers } from './supabase/answers'
import { updateContract } from './supabase/contracts'

export type ResolutionParams = {
Expand Down Expand Up @@ -237,13 +228,12 @@ export const resolveMarketHelper = async (
}
log('processing payouts', { payouts })
await payUsersTransactions(tx, payouts, contractId, answerId, {
payoutSpice: !!contract.isSpicePayout && outcome !== 'CANCEL',
payoutCash: contract.token === 'CASH',
})

// TODO: we may want to support clawing back trader bonuses on MC markets too
if (!answerId) {
await undoUniqueBettorRewardsIfCancelResolution(tx, contract, outcome)
if (!answerId && outcome === 'CANCEL') {
await undoUniqueBettorRewardsIfCancelResolution(tx, contract)
}
return { contract, bets, payoutsWithoutLoans, updatedContractAttrs }
})
Expand Down Expand Up @@ -348,23 +338,14 @@ export const getDataAndPayoutInfo = async (
: undefined
const loanPayouts = getLoanPayouts(bets)

let answer: Answer | undefined
let answers: Answer[] | undefined
if (answerId) {
answer = (await getAnswer(pg, answerId)) ?? undefined
} else if (unresolvedContract.mechanism === 'cpmm-multi-1') {
answers = await getAnswersForContract(pg, contractId)
}

const { payouts: traderPayouts, liquidityPayouts } = getPayouts(
outcome,
unresolvedContract,
bets,
liquidities,
resolutionProbs,
resolutionProbability,
answer,
answers
answerId
)
const payoutsWithoutLoans = [
...liquidityPayouts.map((p) => ({ ...p, deposit: p.payout })),
Expand All @@ -379,7 +360,9 @@ export const getDataAndPayoutInfo = async (
'loan payouts:',
loanPayouts
)
const payouts = [...payoutsWithoutLoans, ...loanPayouts]
const payouts = [...payoutsWithoutLoans, ...loanPayouts].filter(
(p) => p.payout !== 0
)
return {
payoutsWithoutLoans,
bets,
Expand All @@ -390,54 +373,50 @@ export const getDataAndPayoutInfo = async (
}
async function undoUniqueBettorRewardsIfCancelResolution(
pg: SupabaseTransaction,
contract: Contract,
outcome: string
contract: Contract
) {
if (outcome === 'CANCEL') {
const bonusTxnsOnThisContract = await pg.map<Txn>(
`select * from txns where category = 'UNIQUE_BETTOR_BONUS'
const bonusTxnsOnThisContract = await pg.map<Txn>(
`select * from txns where category = 'UNIQUE_BETTOR_BONUS'
and to_id = $1
and data->'data'->>'contractId' = $2`,
[contract.creatorId, contract.id],
(row) => convertTxn(row)
)
[contract.creatorId, contract.id],
(row) => convertTxn(row)
)

log('total bonusTxnsOnThisContract ' + bonusTxnsOnThisContract.length)
const totalBonusAmount = sumBy(bonusTxnsOnThisContract, (txn) => txn.amount)
log('totalBonusAmount to be withdrawn ' + totalBonusAmount)
log('total bonusTxnsOnThisContract ' + bonusTxnsOnThisContract.length)
const totalBonusAmount = sumBy(bonusTxnsOnThisContract, (txn) => txn.amount)
log('totalBonusAmount to be withdrawn ' + totalBonusAmount)

if (totalBonusAmount === 0) {
log('No bonus to cancel')
return
}
if (totalBonusAmount === 0) {
log('No bonus to cancel')
return
}

const bonusTxn = {
fromId: contract.creatorId,
fromType: 'USER',
toId: isProd()
? HOUSE_LIQUIDITY_PROVIDER_ID
: DEV_HOUSE_LIQUIDITY_PROVIDER_ID,
toType: 'BANK',
amount: totalBonusAmount,
token: 'M$',
category: 'CANCEL_UNIQUE_BETTOR_BONUS',
data: {
contractId: contract.id,
},
} as Omit<CancelUniqueBettorBonusTxn, 'id' | 'createdTime'>

try {
const txn = await pg.tx((tx) => runTxn(tx, bonusTxn))
log(
`Cancel Bonus txn for user: ${contract.creatorId} completed: ${txn.id}`
)
} catch (e) {
log.error(
`Couldn't cancel bonus for user: ${contract.creatorId} - status: failure`
)
if (e instanceof APIError) {
log.error(e.message)
}
const bonusTxn = {
fromId: contract.creatorId,
fromType: 'USER',
toId: isProd()
? HOUSE_LIQUIDITY_PROVIDER_ID
: DEV_HOUSE_LIQUIDITY_PROVIDER_ID,
toType: 'BANK',
amount: totalBonusAmount,
token: 'M$',
category: 'CANCEL_UNIQUE_BETTOR_BONUS',
data: {
contractId: contract.id,
},
} as Omit<CancelUniqueBettorBonusTxn, 'id' | 'createdTime'>

try {
const txn = await pg.tx((tx) => runTxn(tx, bonusTxn))
log(`Cancel Bonus txn for user: ${contract.creatorId} completed: ${txn.id}`)
} catch (e) {
log.error(
`Couldn't cancel bonus for user: ${contract.creatorId} - status: failure`,
{ e }
)
if (e instanceof APIError) {
log.error(e.message)
}
}
}
Expand All @@ -452,11 +431,10 @@ export const payUsersTransactions = async (
contractId: string,
answerId: string | undefined,
options?: {
payoutSpice: boolean
payoutCash: boolean
}
) => {
const { payoutSpice, payoutCash } = options ?? {}
const { payoutCash } = options ?? {}
const mergedPayouts = checkAndMergePayouts(payouts)
const payoutStartTime = Date.now()

Expand All @@ -469,51 +447,27 @@ export const payUsersTransactions = async (
const txns: TxnData[] = []

for (const { userId, payout, deposit } of mergedPayouts) {
if (SPICE_PRODUCTION_ENABLED && payoutSpice) {
balanceUpdates.push({
id: userId,
spiceBalance: payout,
totalDeposits: deposit ?? 0,
})

txns.push({
category: 'PRODUCE_SPICE',
fromType: 'CONTRACT',
fromId: contractId,
toType: 'USER',
toId: userId,
amount: payout,
token: 'SPICE',
data: removeUndefinedProps({
deposit: deposit ?? 0,
payoutStartTime,
answerId,
}),
description: 'Contract payout for resolution',
})
} else {
balanceUpdates.push({
id: userId,
[payoutCash ? 'cashBalance' : 'balance']: payout,
totalDeposits: deposit ?? 0,
})
balanceUpdates.push({
id: userId,
[payoutCash ? 'cashBalance' : 'balance']: payout,
totalDeposits: deposit ?? 0,
})

txns.push({
category: 'CONTRACT_RESOLUTION_PAYOUT',
fromType: 'CONTRACT',
fromId: contractId,
toType: 'USER',
toId: userId,
amount: payout,
token: payoutCash ? 'CASH' : 'M$',
data: removeUndefinedProps({
deposit: deposit ?? 0,
payoutStartTime,
answerId,
}),
description: 'Contract payout for resolution: ' + contractId,
})
}
txns.push({
category: 'CONTRACT_RESOLUTION_PAYOUT',
fromType: 'CONTRACT',
fromId: contractId,
toType: 'USER',
toId: userId,
amount: payout,
token: payoutCash ? 'CASH' : 'M$',
data: removeUndefinedProps({
deposit: deposit ?? 0,
payoutStartTime,
answerId,
}),
description: 'Contract payout for resolution: ' + contractId,
})
}

await bulkIncrementBalances(pg, balanceUpdates)
Expand Down
23 changes: 14 additions & 9 deletions common/src/payouts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@ export const getPayouts = (
[outcome: string]: number
},
resolutionProbability?: number,
answer?: Answer | null | undefined,
allAnswers?: Answer[]
answerId?: string | undefined
): PayoutInfo => {
if (contract.mechanism === 'cpmm-1') {
const prob = getProbability(contract)
Expand All @@ -66,12 +65,16 @@ export const getPayouts = (
if (
contract.mechanism === 'cpmm-multi-1' &&
!contract.shouldAnswersSumToOne &&
answer
answerId
) {
const answer = contract.answers.find((a) => a.id === answerId)
if (!answer) {
throw new Error('getPayouts: answer not found for cpmm-multi-1')
}
return getIndependentMultiFixedPayouts(
answer,
outcome,
contract as any,
contract as CPMMMultiContract,
bets,
liquidities,
resolutionProbability ?? answer.prob
Expand All @@ -84,11 +87,13 @@ export const getPayouts = (
if (!resolutions) {
throw new Error('getPayouts: resolutions required for cpmm-multi-1')
}
if (!allAnswers) {
throw new Error('getPayouts: answers required for cpmm-multi-1')
}
// Includes equivalent of 'MKT' and 'YES/NO' resolutions.
return getMultiFixedPayouts(allAnswers, resolutions, bets, liquidities)
return getMultiFixedPayouts(
contract.answers,
resolutions,
bets,
liquidities
)
}
throw new Error('getPayouts not implemented')
}
Expand Down Expand Up @@ -122,7 +127,7 @@ export const getFixedPayouts = (
export const getIndependentMultiFixedPayouts = (
answer: Answer,
outcome: string | undefined,
contract: CPMMMultiContract & { shouldAnswersSumToOne: true },
contract: CPMMMultiContract,
bets: Bet[],
liquidities: LiquidityProvision[],
resolutionProbability: number
Expand Down

0 comments on commit 1ad01d0

Please sign in to comment.