How to fix the t shirt purchase exploit for donation games

I guess when opening a prompt, tell the server, then it’ll start listening for purchases and you can buy the thing, while it spam checks until you close the prompt. The game will show the donation as the lowest price found. Or maybe check price when just opening the prompt instead.

3 Likes

but how will we tell the server? if it’s client sided they can just get rid of it

2 Likes

If they delete it the server won’t accept their donation.

3 Likes

like if they delete the event that lets the server know the prompt is fired?

2 Likes

If they delete the event, the server won’t start listening for donations because nobody told it to.

2 Likes

I think you can get price porperty. Heres a Forum telling you about it.

Just get the Original price and compare with current price

3 Likes

aw i see. and you saying this wouldn’t exceed rate limit?

3 Likes

i was meaning like it wouldn’t help in this circumstance because of how the purchases are client sided with roblox core gui but if we do what oddcraft was saying then maybe that would work. as far as i know the price value holds true it’s just not the updated value that holds true. which is a bit weird. and it’s just that way for shirts

2 Likes

I guess you can delete the Ui for the gamepass purchase by checking everytime if this is the same price as its set too. But This might be for billboard UI. Also try some testing with the Price thing, it could work

3 Likes

Oh, so you mean like when they hit okay button then the amount they donated will be added in a number value?

3 Likes

yeah when they hit okay thats what the game registers. when they prompt and hit buy thats what roblox registers.

2 Likes

Wait so are you saying that when the Prompt shows up, its going to be the same price before they changed it or are you talking about adding points to your game when you buy something?

3 Likes

You can use a attribute to store what user is buying at what price.

This basically prompting user to buy that shirt and sending the product id and price to server.

Then server sets player attribute to the asset they are purchasing,
once the prompt is purchased we are checking if assetid is same as the asset player is buying by checking player’s attribute, if its true then we will get old price of the asset and add it in donated numbervalue, then we will remove those attribute once everything is done.

4 Likes

iwe’re wanting to understand how much they bought what they bought for yeah. or else i dont think this would be an issue.
in short
they change price to say 1 robux
then prompt and buy
they change price to say 1 million robux
then press okay

roblox reads the value as what they pressed buy for (what the prompt was for)
your game server reads the prompt as what the value was when they press okay

in theory though, if what oddcraft was saying is true and the price value holds true (which i believe it does, it’s just the updated that is chached and does not hold true) then this should be a fix…

although my quesstion is the rate limit. if we have multiple players in a game going through this process would it work?

2 Likes

You can test that your self with multiple of friends or devices. I’m not sure if its rate limited because PLS donate definetly might have the same syste,

3 Likes

but that is client sided so if we’re getting price from client they could manipulate that. is it not a better option to have an event fire to server letting the server know a player is making a purchase and then repeatedly checking the price to get what holds true? then if there isnt any pending transaction we just dont count it.

3 Likes

well you can do that too, just pass the asset id to server and get the product info from there.

3 Likes

preview ig??

Client

-- Client
local marketplace = game:GetService("MarketplaceService")
local shirtId = 8245844314
local remote = game:GetService("ReplicatedStorage"):WaitForChild("thingIdk")

script.Parent.MouseButton1Click:Connect(function()
	marketplace:PromptPurchase(game.Players.LocalPlayer,shirtId)
	remote:FireServer(shirtId)
end)

Server

-- Server
local remote = game:GetService("ReplicatedStorage"):WaitForChild("thingIdk")
local marketplace = game:GetService("MarketplaceService")
local players = game:GetService("Players")

players.PlayerAdded:Connect(function(plr)
	local leaderstats = Instance.new("Folder",plr)
	leaderstats.Name = "leaderstats"
	
	local num = Instance.new("NumberValue", leaderstats)
	num.Name = "Donated"
end)

remote.OnServerEvent:Connect(function(plr, shirtId)
	local info = marketplace:GetProductInfo(shirtId,Enum.InfoType.Asset)
	local oldPrice = info.PriceInRobux
	plr:SetAttribute("shirtId", shirtId)
	plr:SetAttribute("price", oldPrice)
end)

marketplace.PromptPurchaseFinished:Connect(function(player, assetId, ispurchased)
	if ispurchased then
		local shirtId = player:GetAttribute("shirtId")
		local price = player:GetAttribute("price")

		if shirtId == assetId then
			player.leaderstats.Donated.Value += price
			player:SetAttribute("shirtId", nil)
			player:SetAttribute("price", nil)
		end
	end
end)
3 Likes

i wonder if they can change price like you did before pressing buy too. i thought they did it after buy and before okay.

yeah and then you’d make a web request every 0.5 seconds or so to get price until purchase in creased to see if it had been modified.

3 Likes

You dont really have to do that if you just store the price whenever the prompt is shown to the player.

As you can see the old price got added instead of the new price which is 99999.

3 Likes