diff --git a/api/swagger/swagger-v1.yaml b/api/swagger/swagger-v1.yaml index ba4da9d5..981f78af 100644 --- a/api/swagger/swagger-v1.yaml +++ b/api/swagger/swagger-v1.yaml @@ -30,6 +30,8 @@ tags: description: Explore related operations - name: rewards description: Rewards related operations +- name: prizes + description: Prize claiming related operations paths: /challenges/undisbursed: get: @@ -4106,6 +4108,74 @@ paths: "500": description: Server error content: {} + /prizes: + get: + tags: + - prizes + operationId: Get Prizes + description: 'Gets a list of active prizes available for claiming. Excludes sensitive information like download URLs.' + responses: + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/prizes_response' + "500": + description: Server error + content: {} + /prizes/claim: + post: + tags: + - prizes + operationId: Claim Prize + description: 'Claims a prize by verifying a Solana transaction. User must send exactly 2 YAK to the prize receiver address. Returns the prize won and any redeem codes/URLs.' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/prize_claim_request' + responses: + "200": + description: Success - Prize claimed + content: + application/json: + schema: + $ref: '#/components/schemas/prize_claim_response' + "400": + description: Bad request - Transaction not found, invalid, or signature already used + content: {} + "500": + description: Server error + content: {} + /wallet/{wallet}/prizes: + get: + tags: + - prizes + operationId: Get Wallet Prizes + description: 'Gets all claimed prizes for a wallet. Public endpoint - no authentication required. Excludes sensitive action_data for security.' + parameters: + - name: wallet + in: path + description: The wallet address to get prizes for + required: true + schema: + type: string + example: "HLnpSz9h2S4hiLQ43rnSD9XkcUThA7B8hQMKmDaiTLcC" + responses: + "200": + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/claimed_prizes_response' + "400": + description: Bad request - Missing wallet parameter + content: {} + "500": + description: Server error + content: {} components: schemas: diff --git a/api/v1_coins_post_redeem.go b/api/v1_coins_post_redeem.go index 29b3c026..15c30089 100644 --- a/api/v1_coins_post_redeem.go +++ b/api/v1_coins_post_redeem.go @@ -179,6 +179,7 @@ func (app *ApiServer) v1CoinsPostRedeem(c *fiber.Ctx) error { // Read and burn code in one go // Use CTE to capture old remaining_uses value before updating + // Only update if remaining_uses > 0 to prevent race conditions sql := `WITH old_row AS ( SELECT remaining_uses, reward_address, amount FROM reward_codes @@ -186,10 +187,11 @@ func (app *ApiServer) v1CoinsPostRedeem(c *fiber.Ctx) error { AND mint = @mint ) UPDATE reward_codes - SET remaining_uses = GREATEST(reward_codes.remaining_uses - 1, 0) + SET remaining_uses = reward_codes.remaining_uses - 1 FROM old_row WHERE reward_codes.code = @code AND reward_codes.mint = @mint + AND reward_codes.remaining_uses > 0 RETURNING reward_codes.reward_address, reward_codes.amount,