Skip to content

Commit

Permalink
Update metrics with contract data on user profile
Browse files Browse the repository at this point in the history
  • Loading branch information
IanPhilips committed Nov 28, 2024
1 parent e658dbe commit 6255d0a
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 64 deletions.
55 changes: 25 additions & 30 deletions backend/api/src/get-user-contract-metrics-with-contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { z } from 'zod'
import { MaybeAuthedEndpoint, validate } from './helpers/endpoint'
import { getContractPrivacyWhereSQLFilter } from 'shared/supabase/contracts'
import { createSupabaseDirectClient } from 'shared/supabase/init'
import { Dictionary } from 'lodash'
import { ContractMetric } from 'common/contract-metric'
import { Contract } from 'common/contract'
import { calculateUpdatedMetricsForContracts } from 'common/calculate-metrics'

const bodySchema = z
.object({
Expand All @@ -23,35 +23,30 @@ export const getusercontractmetricswithcontracts = MaybeAuthedEndpoint(
'c.id'
)
const pg = createSupabaseDirectClient()
const metricsByContract = {} as Dictionary<ContractMetric>
const contracts = [] as Contract[]
try {
const q = `select ucm.contract_id,
ucm.data as metrics,
c.data as contract
from user_contract_metrics as ucm
join contracts as c on c.id = ucm.contract_id
where ${visibilitySQL}
and ucm.user_id='${userId}'
and ucm.data->'lastBetTime' is not null
and ucm.answer_id is null
order by ((ucm.data)->'lastBetTime')::bigint desc offset $1
limit $2`
await pg.map(
q,
[offset, limit],
(data: {
contract_id: string
metrics: ContractMetric
contract: Contract
}) => {
metricsByContract[data.contract_id] = data.metrics as ContractMetric
contracts.push(data.contract as Contract)
}
)
return { status: 'success', data: { metricsByContract, contracts } }
} catch (error) {
return { status: 'failure', data: error }
const q = `
SELECT
c.data as contract,
jsonb_agg(ucm.data) as metrics
FROM contracts c
JOIN user_contract_metrics ucm ON c.id = ucm.contract_id
WHERE ${visibilitySQL}
AND ucm.user_id = $1
and case when c.mechanism = 'cpmm-multi-1' then ucm.answer_id is not null else true end
GROUP BY c.id, c.data
ORDER BY max((ucm.data->>'lastBetTime')::bigint) DESC
OFFSET $2 LIMIT $3
`
const results = await pg.map(
q,
[userId, offset, limit],
(row) => row as { contract: Contract; metrics: ContractMetric[] }
)

const { metricsByContract } = calculateUpdatedMetricsForContracts(results)

return {
metricsByContract,
contracts: results.map((r) => r.contract),
}
}
)
53 changes: 53 additions & 0 deletions common/src/calculate-metrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -548,3 +548,56 @@ export const applyMetricToSummary = <
// summaryMetric.hasShares
return summary
}

export const calculateUpdatedMetricsForContracts = (
contractsWithMetrics: {
contract: Contract
metrics: ContractMetric[]
}[]
) => {
const metricsByContract: Dictionary<Omit<ContractMetric, 'id'>> = {}
const contracts: Contract[] = []

for (const { contract, metrics } of contractsWithMetrics) {
const contractId = contract.id
const userId = metrics[0].userId
contracts.push(contract)

if (contract.mechanism === 'cpmm-1') {
// For binary markets, update metrics with current probability
const metric = metrics.find((m) => m.answerId === null)
if (metric) {
metricsByContract[contractId] = calculateProfitMetricsWithProb(
contract.prob,
metric
)
}
} else if (contract.mechanism === 'cpmm-multi-1') {
// For multiple choice markets, update each answer's metrics and compute summary
const answerMetrics = metrics.filter((m) => m.answerId !== null)

const updatedAnswerMetrics = answerMetrics.map((m) => {
const answer = contract.answers.find((a) => a.id === m.answerId)
return answer
? calculateProfitMetricsWithProb(
answer.resolution === 'YES'
? 1
: answer.resolution === 'NO'
? 0
: answer.prob,
m
)
: m
})

// Calculate summary metrics
const summaryMetric = getDefaultMetric(userId, contractId, null)
updatedAnswerMetrics.forEach((m) =>
applyMetricToSummary(m, summaryMetric, true)
)
metricsByContract[contractId] = summaryMetric
}
}

return { metricsByContract, contracts }
}
7 changes: 1 addition & 6 deletions web/components/bet/user-bets-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,7 @@ export function UserBetsTable(props: { user: User }) {
offset: 0,
limit: 5000,
}).then((res) => {
const { data, error } = res
if (error) {
console.error(error)
return
}
const { contracts, metricsByContract } = data
const { contracts, metricsByContract } = res
setMetricsByContract(metricsByContract)
setInitialContracts((c) =>
uniqBy(buildArray([...(c ?? []), ...contracts]), 'id')
Expand Down
36 changes: 8 additions & 28 deletions web/hooks/use-saved-contract-metrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,7 @@ import { useEffect, useState } from 'react'
import { usePersistentLocalState } from './use-persistent-local-state'
import { useEvent } from 'web/hooks/use-event'
import { useApiSubscription } from 'web/hooks/use-api-subscription'
import {
calculateProfitMetricsWithProb,
getDefaultMetric,
applyMetricToSummary,
} from 'common/calculate-metrics'
import { calculateUpdatedMetricsForContracts } from 'common/calculate-metrics'
import { useUser } from './use-user'
import { useBatchedGetter } from './use-batched-getter'

Expand All @@ -28,29 +24,13 @@ export const useSavedContractMetrics = (

const updateMetricsWithNewProbs = (metrics: ContractMetric[]) => {
if (!user) return metrics
if (contract.mechanism === 'cpmm-1') {
return [calculateProfitMetricsWithProb(contract.prob, metrics[0])]
}
if (contract.mechanism === 'cpmm-multi-1') {
const updatedMetrics = metrics.map((metric) => {
const answer = contract.answers.find((a) => a.id === metric.answerId)
return answer
? calculateProfitMetricsWithProb(
answer.resolution === 'YES'
? 1
: answer.resolution === 'NO'
? 0
: answer.prob,
metric
)
: metric
})
const nonNullMetrics = updatedMetrics.filter((m) => m.answerId != null)
const nullMetric = getDefaultMetric(user.id, contract.id, null)
nonNullMetrics.forEach((m) => applyMetricToSummary(m, nullMetric, true))
return [...nonNullMetrics, nullMetric] as ContractMetric[]
}
return metrics
const { metricsByContract } = calculateUpdatedMetricsForContracts([
{ contract, metrics },
])
return metrics.map((metric) => ({
...metricsByContract[metric.contractId],
id: metric.id,
}))
}

const refreshMyMetrics = useEvent(async () => {
Expand Down

0 comments on commit 6255d0a

Please sign in to comment.