Skip to content

Commit

Permalink
Merge branch 'main' into track-loans-on-contract-metrics
Browse files Browse the repository at this point in the history
  • Loading branch information
IanPhilips committed Sep 16, 2024
2 parents 64dabd2 + 22edf57 commit fe311a0
Show file tree
Hide file tree
Showing 27 changed files with 538 additions and 401 deletions.
10 changes: 4 additions & 6 deletions backend/api/src/convert-cash-to-mana.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { APIError, APIHandler } from './helpers/endpoint'
import { type TxnData, insertTxns } from 'shared/txn/run-txn'
import { createSupabaseDirectClient } from 'shared/supabase/init'
import { getUser } from 'shared/utils'
import { incrementBalance } from 'shared/supabase/users'
import { betsQueue } from 'shared/helpers/fn-queue'
import { CASH_TO_MANA_CONVERSION_RATE } from 'common/envs/constants'
import { calculateRedeemablePrizeCash } from 'shared/calculate-redeemable-prize-cash'

export const convertCashToMana: APIHandler<'convert-cash-to-mana'> = async (
{ amount },
Expand All @@ -15,11 +15,9 @@ export const convertCashToMana: APIHandler<'convert-cash-to-mana'> = async (
await betsQueue.enqueueFn(async () => {
// check if user has enough cash
await pg.tx(async (tx) => {
const user = await getUser(auth.uid, tx)
if (!user) throw new APIError(401, 'Your account was not found')

if (user.cashBalance < amount) {
throw new APIError(403, 'Not enough balance')
const redeemable = await calculateRedeemablePrizeCash(auth.uid, tx)
if (redeemable < amount) {
throw new APIError(403, 'Not enough redeemable balance')
}

await incrementBalance(tx, auth.uid, {
Expand Down
36 changes: 19 additions & 17 deletions backend/api/src/place-bet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { Answer } from 'common/answer'
import { CpmmState, getCpmmProbability } from 'common/calculate-cpmm'
import { ValidatedAPIParams } from 'common/api/schema'
import { onCreateBets } from 'api/on-create-bet'
import { BANNED_TRADING_USER_IDS } from 'common/envs/constants'
import { BANNED_TRADING_USER_IDS, TWOMBA_ENABLED } from 'common/envs/constants'
import * as crypto from 'crypto'
import { formatMoneyWithDecimals } from 'common/util/format'
import {
Expand Down Expand Up @@ -263,7 +263,7 @@ export const fetchContractBetDataAndValidate = async (
const queries = `
select * from users where id = $1;
select ${contractColumnsToSelect} from contracts where id = $2;
select * from answers
select * from answers
where contract_id = $2 and (
($3 is null or id in ($3:list)) or
(select (data->'shouldAnswersSumToOne')::boolean from contracts where id = $2)
Expand Down Expand Up @@ -561,22 +561,24 @@ export const executeNewBetResult = async (
)
log(`Updated user ${user.username} balance - auth ${user.id}.`)

const totalCreatorFee =
newBet.fees.creatorFee +
sumBy(otherBetResults, (r) => r.bet.fees.creatorFee)
if (totalCreatorFee !== 0) {
await incrementBalance(pgTrans, contract.creatorId, {
balance: totalCreatorFee,
totalDeposits: totalCreatorFee,
})
if (!TWOMBA_ENABLED) {
const totalCreatorFee =
newBet.fees.creatorFee +
sumBy(otherBetResults, (r) => r.bet.fees.creatorFee)
if (totalCreatorFee !== 0) {
await incrementBalance(pgTrans, contract.creatorId, {
balance: totalCreatorFee,
totalDeposits: totalCreatorFee,
})

log(
`Updated creator ${
contract.creatorUsername
} with fee gain ${formatMoneyWithDecimals(totalCreatorFee)} - ${
contract.creatorId
}.`
)
log(
`Updated creator ${
contract.creatorUsername
} with fee gain ${formatMoneyWithDecimals(totalCreatorFee)} - ${
contract.creatorId
}.`
)
}
}

const answerUpdates: {
Expand Down
1 change: 1 addition & 0 deletions common/src/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,7 @@ export type ContractParams = {
betReplies: Bet[]
cash?: {
contract: Contract
lastBetTime?: number
pointsString: string
multiPointsString: { [answerId: string]: string }
userPositionsByOutcome: ContractMetricsByOutcome
Expand Down
9 changes: 9 additions & 0 deletions common/src/fees.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { addObjects } from 'common/util/object'
import { TWOMBA_ENABLED } from './envs/constants'

export const FEE_START_TIME = 1713292320000

Expand All @@ -12,6 +13,14 @@ export const getFeesSplit = (
totalFees: number,
previouslyCollectedFees: Fees
) => {
if (TWOMBA_ENABLED) {
return {
creatorFee: 0,
platformFee: totalFees,
liquidityFee: 0,
}
}

const before1k = Math.max(
0,
CREATORS_EARN_WHOLE_FEE_UP_TO - previouslyCollectedFees.creatorFee
Expand Down
29 changes: 16 additions & 13 deletions web/components/answers/answer-components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,10 @@ export function AnswerPosition(props: {
const noWinnings = totalShares.NO ?? 0
const position = yesWinnings - noWinnings
const isCashContract = contract.token === 'CASH'
const canSell = tradingAllowed(contract, answer)
const won =
(position > 1e-7 && answer.resolution === 'YES') ||
(position < -1e-7 && answer.resolution === 'NO')

return (
<Row
Expand All @@ -554,7 +558,7 @@ export function AnswerPosition(props: {
)}
>
<Row className="gap-1">
Payout
{canSell ? 'Payout' : won ? 'Paid out' : 'Held out for'}
{position > 1e-7 ? (
<>
<span className="text-ink-700">
Expand Down Expand Up @@ -586,18 +590,17 @@ export function AnswerPosition(props: {
<MoneyDisplay amount={invested} isCashContract={isCashContract} />
</div>
</Row>
{(!contract.closeTime || contract.closeTime > Date.now()) &&
!answer.resolutionTime && (
<>
&middot;
<MultiSeller
answer={answer}
contract={contract}
userBets={userBets}
user={user}
/>
</>
)}
{canSell && (
<>
&middot;
<MultiSeller
answer={answer}
contract={contract}
userBets={userBets}
user={user}
/>
</>
)}
</Row>
)
}
13 changes: 4 additions & 9 deletions web/components/answers/answers-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ export function AnswersPanel(props: {
enabled: isAdvancedTrader && shouldShowLimitOrderChart,
})

const [shouldShowPositions, setShouldShowPositions] = useState(true)
const [shouldShowPositions, setShouldShowPositions] = useState(!allResolved)

const moreCount = answers.length - answersToShow.length
// Note: Hide answers if there is just one "Other" answer.
Expand Down Expand Up @@ -624,12 +624,7 @@ export function Answer(props: {
resolvedProb === 0 ? 'text-ink-700' : 'text-ink-900'
)

const showSellButton =
!resolution &&
hasBets &&
user &&
(!contract.closeTime || contract.closeTime > Date.now()) &&
!answer.resolutionTime
const showPosition = hasBets && user

const userHasLimitOrders =
shouldShowLimitOrderChart && (yourUnfilledBets ?? []).length > 0
Expand Down Expand Up @@ -778,7 +773,7 @@ export function Answer(props: {
}
>
<Row className="text-ink-500 gap-1.5">
{showSellButton && (
{showPosition && (
<AnswerPosition
contract={contract}
answer={answer}
Expand All @@ -787,7 +782,7 @@ export function Answer(props: {
user={user}
/>
)}
{userHasLimitOrders && showSellButton && <>&middot;</>}
{userHasLimitOrders && showPosition && <>&middot;</>}
{userHasLimitOrders && (
<AnswerOrdersButton
contract={contract}
Expand Down
30 changes: 11 additions & 19 deletions web/components/bet/bet-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ import {
TRADE_TERM,
TWOMBA_ENABLED,
} from 'common/envs/constants'
import { KYC_VERIFICATION_BONUS_CASH } from 'common/economy'
import { getFeeTotal } from 'common/fees'
import { getFormattedMappedValue } from 'common/pseudo-numeric'
import { getStonkDisplayShares, STONK_NO, STONK_YES } from 'common/stonk'
Expand All @@ -54,7 +53,7 @@ import { useIsAdvancedTrader } from 'web/hooks/use-is-advanced-trader'
import { useUser } from 'web/hooks/use-user'
import { track, withTracking } from 'web/lib/service/analytics'
import { isAndroid, isIOS } from 'web/lib/util/device'
import { Button, buttonClass } from '../buttons/button'
import { Button } from '../buttons/button'
import { WarningConfirmationButton } from '../buttons/warning-confirmation-button'
import { getAnswerColor } from '../charts/contract/choice'
import { ChoicesToggleGroup } from '../widgets/choices-toggle-group'
Expand All @@ -63,10 +62,9 @@ import LimitOrderPanel from './limit-order-panel'
import { MoneyDisplay } from './money-display'
import { OrderBookPanel, YourOrders } from './order-book'
import { YesNoSelector } from './yes-no-selector'
import Link from 'next/link'
import { blockFromSweepstakes, identityPending } from 'common/user'
import { CoinNumber } from '../widgets/coin-number'
import { CashoutLimitWarning } from './cashout-limit-warning'
import { VerifyButton } from '../twomba/toggle-verify-callout'

export type BinaryOutcomes = 'YES' | 'NO' | undefined

Expand Down Expand Up @@ -137,21 +135,15 @@ export function BuyPanel(props: {
)
} else if (contract.token === 'CASH' && user && !user.idVerified) {
return (
<Row className={'bg-canvas-50 gap-1 rounded p-4'}>
<span>
Verify your info to start trading on sweepstakes markets and earn a
bonus of{' '}
<CoinNumber
amount={KYC_VERIFICATION_BONUS_CASH}
coinType="sweepies"
isInline
/>
!
</span>
<Link className={buttonClass('md', 'indigo')} href={'/gidx/register'}>
Verify
</Link>
</Row>
<Col className="bg-canvas-50 gap-2 rounded-lg p-4">
<div className="mx-auto text-lg font-semibold">
Must be verified to {TRADE_TERM}
</div>
<p className="text-ink-700 mx-auto">
Verify your info to start trading on sweepstakes markets!
</p>
<VerifyButton />
</Col>
)
} else if (contract.token === 'CASH' && blockFromSweepstakes(user)) {
return (
Expand Down
8 changes: 6 additions & 2 deletions web/components/bet/fees.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { TRADE_TERM } from 'common/envs/constants'
import { TRADE_TERM, TWOMBA_ENABLED } from 'common/envs/constants'
import { InfoTooltip } from '../widgets/info-tooltip'
import { MoneyDisplay } from './money-display'

Expand All @@ -20,7 +20,11 @@ export const FeeDisplay = (props: {
<InfoTooltip
text={`${(amount ? (100 * totalFees) / amount : 0).toFixed(
2
)}% fee. Goes to the market creator up to 1000, then is split 50-50 with Manifold. Fees range from 0% to 7% of your ${TRADE_TERM} amount increasing the more unlikely your ${TRADE_TERM} is to pay out.`}
)}% fee. Goes to ${
TWOMBA_ENABLED
? ''
: 'the market creator up to 1000, then is split 50-50 with '
}Manifold. Fees range from 0% to 7% of your ${TRADE_TERM} amount increasing the more unlikely your ${TRADE_TERM} is to pay out.`}
className="text-ink-600 ml-1 mt-0.5"
size="sm"
/>
Expand Down
3 changes: 3 additions & 0 deletions web/components/charts/generic-charts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,7 @@ export const SingleValueHistoryChart = <P extends HistoryPoint>(props: {
hideXAxis?: boolean
onGraphClick?: () => void
areaClassName?: string
noWatermark?: boolean
className?: string
}) => {
const {
Expand All @@ -749,6 +750,7 @@ export const SingleValueHistoryChart = <P extends HistoryPoint>(props: {
hideXAxis,
onGraphClick,
areaClassName,
noWatermark,
} = props

useLayoutEffect(() => {
Expand Down Expand Up @@ -873,6 +875,7 @@ export const SingleValueHistoryChart = <P extends HistoryPoint>(props: {
pointerMode={pointerMode}
hideXAxis={hideXAxis}
yKind={yKind}
noWatermark={noWatermark}
>
{typeof color !== 'string' && (
<defs>
Expand Down
1 change: 1 addition & 0 deletions web/components/charts/stats.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export function DailyChart(props: { values: Point[]; pct?: boolean }) {
curve={curveLinear}
zoomParams={zoomParams}
showZoomer
noWatermark
/>
)}
</SizedContainer>
Expand Down
31 changes: 11 additions & 20 deletions web/components/contract/contract-overview.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { ReactNode, memo, useState, useEffect } from 'react'
import clsx from 'clsx'
import { KYC_VERIFICATION_BONUS_CASH } from 'common/economy'

import { Bet } from 'common/bet'
import { HistoryPoint, MultiPoints } from 'common/chart'
Expand Down Expand Up @@ -49,7 +48,7 @@ import { getAnswerProbability } from 'common/calculate'
import { useAnnotateChartTools } from 'web/hooks/use-chart-annotations'
import { type ChartAnnotation } from 'common/supabase/chart-annotations'
import { formatMoney, formatPercent } from 'common/util/format'
import { isAdminId, isModId } from 'common/envs/constants'
import { isAdminId, isModId, TRADE_TERM } from 'common/envs/constants'
import { LoadingIndicator } from '../widgets/loading-indicator'
import { useDataZoomFetcher } from '../charts/contract/zoom-utils'
import { AlertBox } from '../widgets/alert-box'
Expand All @@ -73,9 +72,7 @@ import {
EditChartAnnotationsButton,
} from '../charts/chart-annotations'
import { useLiveContractWithAnswers } from 'web/hooks/use-contract'
import Link from 'next/link'
import { buttonClass } from 'web/components/buttons/button'
import { CoinNumber } from 'web/components/widgets/coin-number'
import { VerifyButton } from '../twomba/toggle-verify-callout'

export const ContractOverview = memo(
(props: {
Expand Down Expand Up @@ -839,21 +836,15 @@ export function BinaryBetPanel(props: {
You can't trade on sweepstakes markets while your status is pending.
</Row>
) : contract.token === 'CASH' && user && !user.idVerified ? (
<Row className={'bg-canvas-50 items-center gap-1 rounded p-4'}>
<span>
Verify your info to start trading on sweepstakes markets and earn a
bonus of{' '}
<CoinNumber
amount={KYC_VERIFICATION_BONUS_CASH}
coinType="sweepies"
isInline
/>
!
</span>
<Link className={buttonClass('md', 'indigo')} href={'/gidx/register'}>
Verify
</Link>
</Row>
<Col className="bg-canvas-50 gap-2 rounded-lg p-4">
<div className="mx-auto text-lg font-semibold">
Must be verified to {TRADE_TERM}
</div>
<p className="text-ink-700 mx-auto">
Verify your info to start trading on sweepstakes markets!
</p>
<VerifyButton />
</Col>
) : contract.token === 'CASH' && blockFromSweepstakes(user) ? (
<Row className={'bg-canvas-50 rounded p-4'}>
You are not eligible to trade on sweepstakes markets.
Expand Down
2 changes: 2 additions & 0 deletions web/components/contract/contract-tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ export function ContractTabs(props: {
title: positionsTitle,
content: (
<UserPositionsTable
key={contract.id}
positions={
// If contract is resolved, will have to refetch positions by profit
Object.values(userPositionsByOutcome).length > 0 &&
Expand All @@ -151,6 +152,7 @@ export function ContractTabs(props: {
content: (
<Col className={'gap-4'}>
<BetsTabContent
key={contract.id}
contract={contract}
bets={bets}
totalBets={totalBets}
Expand Down
Loading

0 comments on commit fe311a0

Please sign in to comment.