Allow unspecfied outcome as input to sellshares (#706)

* Allow unspecfied outcome as input to `sellshares`

* Fix small details
This commit is contained in:
Marshall Polaris 2022-08-01 23:53:12 -07:00 committed by GitHub
parent 0b06ded5e5
commit 6901507461
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 31 additions and 9 deletions

View File

@ -599,12 +599,12 @@ $ curl https://manifold.markets/api/v0/market/{marketId}/resolve -X POST \
### `POST /v0/market/[marketId]/sell` ### `POST /v0/market/[marketId]/sell`
Sells some quantity of shares in a market on behalf of the authorized user. Sells some quantity of shares in a binary market on behalf of the authorized user.
Parameters: Parameters:
- `outcome`: Required. One of `YES`, `NO`, or a `number` indicating the numeric - `outcome`: Optional. One of `YES`, or `NO`. If you leave it off, and you only
bucket ID, depending on the market type. own one kind of shares, you will sell that kind of shares.
- `shares`: Optional. The amount of shares to sell of the outcome given - `shares`: Optional. The amount of shares to sell of the outcome given
above. If not provided, all the shares you own will be sold. above. If not provided, all the shares you own will be sold.

View File

@ -1,4 +1,4 @@
import { sumBy, uniq } from 'lodash' import { mapValues, groupBy, sumBy, uniq } from 'lodash'
import * as admin from 'firebase-admin' import * as admin from 'firebase-admin'
import { z } from 'zod' import { z } from 'zod'
@ -9,7 +9,7 @@ import { getCpmmSellBetInfo } from '../../common/sell-bet'
import { addObjects, removeUndefinedProps } from '../../common/util/object' import { addObjects, removeUndefinedProps } from '../../common/util/object'
import { getValues, log } from './utils' import { getValues, log } from './utils'
import { Bet } from '../../common/bet' import { Bet } from '../../common/bet'
import { floatingLesserEqual } from '../../common/util/math' import { floatingEqual, floatingLesserEqual } from '../../common/util/math'
import { getUnfilledBetsQuery, updateMakers } from './place-bet' import { getUnfilledBetsQuery, updateMakers } from './place-bet'
import { FieldValue } from 'firebase-admin/firestore' import { FieldValue } from 'firebase-admin/firestore'
import { redeemShares } from './redeem-shares' import { redeemShares } from './redeem-shares'
@ -17,7 +17,7 @@ import { redeemShares } from './redeem-shares'
const bodySchema = z.object({ const bodySchema = z.object({
contractId: z.string(), contractId: z.string(),
shares: z.number().optional(), // leave it out to sell all shares shares: z.number().optional(), // leave it out to sell all shares
outcome: z.enum(['YES', 'NO']), outcome: z.enum(['YES', 'NO']).optional(), // leave it out to sell whichever you have
}) })
export const sellshares = newEndpoint({}, async (req, auth) => { export const sellshares = newEndpoint({}, async (req, auth) => {
@ -46,9 +46,31 @@ export const sellshares = newEndpoint({}, async (req, auth) => {
throw new APIError(400, 'Trading is closed.') throw new APIError(400, 'Trading is closed.')
const prevLoanAmount = sumBy(userBets, (bet) => bet.loanAmount ?? 0) const prevLoanAmount = sumBy(userBets, (bet) => bet.loanAmount ?? 0)
const betsByOutcome = groupBy(userBets, (bet) => bet.outcome)
const sharesByOutcome = mapValues(betsByOutcome, (bets) =>
sumBy(bets, (b) => b.shares)
)
const outcomeBets = userBets.filter((bet) => bet.outcome == outcome) let chosenOutcome: 'YES' | 'NO'
const maxShares = sumBy(outcomeBets, (bet) => bet.shares) if (outcome != null) {
chosenOutcome = outcome
} else {
const nonzeroShares = Object.entries(sharesByOutcome).filter(
([_k, v]) => !floatingEqual(0, v)
)
if (nonzeroShares.length == 0) {
throw new APIError(400, "You don't own any shares in this market.")
}
if (nonzeroShares.length > 1) {
throw new APIError(
400,
`You own multiple kinds of shares, but did not specify which to sell.`
)
}
chosenOutcome = nonzeroShares[0][0] as 'YES' | 'NO'
}
const maxShares = sharesByOutcome[chosenOutcome]
const sharesToSell = shares ?? maxShares const sharesToSell = shares ?? maxShares
if (!floatingLesserEqual(sharesToSell, maxShares)) if (!floatingLesserEqual(sharesToSell, maxShares))
@ -63,7 +85,7 @@ export const sellshares = newEndpoint({}, async (req, auth) => {
const { newBet, newPool, newP, fees, makers } = getCpmmSellBetInfo( const { newBet, newPool, newP, fees, makers } = getCpmmSellBetInfo(
soldShares, soldShares,
outcome, chosenOutcome,
contract, contract,
prevLoanAmount, prevLoanAmount,
unfilledBets unfilledBets