Cases | A gamepass info validation module for Donation Games

Cases is a Module that I made primarily for the use in Donation Games.

Get The Module 📥

❓What Does it Do?

In donation games, when a player purchases a gamepass to donate Robux, the seller can change the price to other amounts than the original price after the purchase is prompted. Since the game detects the price after the prompt is closed, it falsely gets the modified amount.

Cases solves this issue by storing the original details of the gamepass before the purchase. When the purchase is completed, the game retrieves the correct amount rather than the modified price.

📝 What is a Case?

A case is a table that contains the gamepass details.
Additionally, a case profile is a container that stores all of the player’s cases.

📖 Documentation

:CreateCase

Creates a case for a player with the given Gamepass ID, returns the case if it succeeds.

CasesModule:CreateCase(player, "Gamepass", 12345678)
:CloseCase

Closes an existing case of a player with the given Gamepass ID.

CasesModule:CloseCase(player,12345678)
:GetPlayerCases

Returns all of the cases of a player.

CasesModule:GetPlayerCases(player)
:GetCase

Returns the case of a player from GamepassID. if the case exists, it returns the case. Else, returns nil.

CasesModule:GetCase(player,12345678)
:RemoveCaseProfile

Removes the case profile. Must be used when the player leaves.

CasesModule:RemoveCaseProfile(player)

💻 Example Code

local ServerStorage = game:GetService("ServerStorage")
local MarketplaceService = game:GetService("MarketplaceService")
local Players = game:GetService("Players")
local CasesModule = require(ServerStorage.CasesModule)

Players.PlayerAdded:Connect(function(player)
	player.CharacterAdded:Wait()
	CasesModule:CreateCase(player, "Gamepass", 12345678)
	MarketplaceService:PromptGamePassPurchase(player, 12345678)
end)

MarketplaceService.PromptGamePassPurchaseFinished:Connect(function(player : Player, gamepassId, wasPurchased)
	local theCase = CasesModule:GetCase(player, gamepassId)
	if theCase~=nil then
		print(theCase)
	end
	CasesModule:CloseCase(player, gamepassId) -- Close the case after getting it
end)

Players.PlayerRemoving:Connect(function(player)
	CasesModule:RemoveCaseProfile(player) -- Remove the case profile when the player leaves (removes all of the cases)
end)

Feedback is highly appreciated!

I thought if you changed the price mid purchase, Roblox would throw an error and the purchase would be not succeed at all

Players can make a gamepass for lot of robux, then join the game and during game change the price to low amount and buy it. Your module saves the amount when the player joins the game but in-game that amount is never changed again, while it can be changed in the website

I checked your module;

  1. GetProductInfo returns cached information, which allows bypasses.
  2. It’s pretty easy to bypass this, it seems to only get the robux price, nothing with LastEdited. The player can first buy the gamepass for the fake amount then change it back to the fake amount and click OK on the prompt.
  3. An exploiter can prompt themselves the gamepass before the creator of the gamepass joins, once they buy it and don’t click “OK” yet, the creator of the gamepass changes the price back to the fake amount while not being-ingame, then joins the game and claims a booth/stand or such and then the exploiter clicks OK, if theres validation checks when the user clicks the button, the exploiter just has to trigger those correctly.