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`
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:
- `outcome`: Required. One of `YES`, `NO`, or a `number` indicating the numeric
bucket ID, depending on the market type.
- `outcome`: Optional. One of `YES`, or `NO`. If you leave it off, and you only
own one kind of shares, you will sell that kind of shares.
- `shares`: Optional. The amount of shares to sell of the outcome given
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 { z } from 'zod'
@ -9,7 +9,7 @@ import { getCpmmSellBetInfo } from '../../common/sell-bet'
import { addObjects, removeUndefinedProps } from '../../common/util/object'
import { getValues, log } from './utils'
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 { FieldValue } from 'firebase-admin/firestore'
import { redeemShares } from './redeem-shares'
@ -17,7 +17,7 @@ import { redeemShares } from './redeem-shares'
const bodySchema = z.object({
contractId: z.string(),
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) => {
@ -46,9 +46,31 @@ export const sellshares = newEndpoint({}, async (req, auth) => {
throw new APIError(400, 'Trading is closed.')
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)
const maxShares = sumBy(outcomeBets, (bet) => bet.shares)
let chosenOutcome: 'YES' | 'NO'
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
if (!floatingLesserEqual(sharesToSell, maxShares))
@ -63,7 +85,7 @@ export const sellshares = newEndpoint({}, async (req, auth) => {
const { newBet, newPool, newP, fees, makers } = getCpmmSellBetInfo(
soldShares,
outcome,
chosenOutcome,
contract,
prevLoanAmount,
unfilledBets