[econ] owner currency 0 amount purchase

This commit is contained in:
Devin Zuczek
2026-10-22 12:32:54 -04:00
parent 605a35c36b
commit 2222a545ff
2 changed files with 31 additions and 2 deletions
+13 -2
View File
@@ -6651,7 +6651,10 @@ const app = new Hono<App>({ strict: false })
'NOBODY IS PAID — unlike the token sale, the price does not reach the room’s owner.',
'',
'`RequestedPurchaseCurrencyId` must be the key’s own `PurchaseCurrencyId` and',
'`RequestedPrice` its `Price`. A key priced in TOKENS (a null `PurchaseCurrencyId`)',
'`RequestedPrice` its `Price` — except that the room’s creator or a CO-OWNER gets',
'their own room’s keys free: the client asks them `RequestedPrice=0` (the stored',
'price is accepted too) and nothing is subtracted.',
'A key priced in TOKENS (a null `PurchaseCurrencyId`)',
'is not sold here — that is `GET /api/storefronts/v1/buyRoomKey`.',
'',
'Answers the client’s `RoomKeyPurchaseWithCurrencyResponseDTO`, a bare object with no',
@@ -6710,13 +6713,21 @@ const app = new Hono<App>({ strict: false })
if (requestedCurrencyId.toLowerCase() !== key.PurchaseCurrencyId.toLowerCase()) {
return answer(false)
}
if (int(body.RequestedPrice) !== key.Price) return answer(false)
// The room's creator and co-owners get their own room's keys free, as with the token
// sale — the client asks them `RequestedPrice=0` — and are never charged.
const canManage = await canManageRoomById(c.env.DB, key.RoomId, id)
if (canManage === null) return answer(false)
const requestedPrice = int(body.RequestedPrice)
if (requestedPrice !== key.Price && !(canManage && requestedPrice === 0)) {
return answer(false)
}
// Claim the key BEFORE charging, as the token sale does: the insert is atomic, so of
// two concurrent buys only one is charged. A buyer who cannot pay gives it back.
if (!(await claimRoomKey(c.env.DB, id, key.RoomKeyId))) return answer(false)
if (
key.Price > 0 &&
!canManage &&
!(await spendRoomCurrency(c.env.DB, key.PurchaseCurrencyId, id, key.Price))
) {
await releaseRoomKey(c.env.DB, id, key.RoomKeyId)
@@ -3238,6 +3238,24 @@ describe('econ endpoints', () => {
)
expect(await held(coin, 7501)).toBe(500)
// A non-manager cannot buy it for 0; the room's managers can — the co-owner at the 0
// the client asks them, the owner at the stored price — and nothing is subtracted.
expect(await (await purchase('7502', key.RoomKeyId, 0, coin)).json()).toEqual(
refused(7502, coin, 999)
)
await give(coin, 2, 10)
const coOwner = (await (await purchase('2', key.RoomKeyId, 0, coin)).json()) as {
Balance: { Balance: number }
RoomKeyResponse: { Status: number }
}
expect(coOwner.RoomKeyResponse.Status).toBe(0)
expect(coOwner.Balance.Balance).toBe(10)
const own = (await (await purchase('1', key.RoomKeyId, 1000, coin)).json()) as typeof coOwner
expect(own.RoomKeyResponse.Status).toBe(0)
expect(own.Balance.Balance).toBe(0)
expect(await holders(key.RoomKeyId)).toEqual([1, 2, 7501])
expect([await held(coin, 1), await held(coin, 2)]).toEqual([0, 10])
await env.DB.prepare('DELETE FROM room_key_player').run()
await env.DB.prepare('DELETE FROM room_key').run()
await env.DB.prepare('DELETE FROM room_balance WHERE currency_id IN (?1, ?2)')