Problems with dev products!

Hmm yeah so i have been experimenting a bit but i keep getting an error. Maybe you can figure out why?

Here is the handle purchase script:

local MarketplaceService = game:GetService("MarketplaceService")
local itemAmount = 0

local function GivePlayerItemsFunction(player, itemAmount)
	for i, v in pairs(player:FindFirstChild("leaderstats")) do
		if v:FindFirstChild("Items") then 
			local Items = v:FindFirstChild("Items")
			Items = Items + itemAmount
			print("Found the right folder")
		end
	end
end

local function onProductPurchased(info)
	
	local ReceivedProductID = info.ProductId
	local Player = game.Players:GetPlayerByUserId(info.PlayerId)
	
	if info.ReceivedProductID == 2657161178  then
		for _, player in ipairs(game.Players:GetPlayers()) do
			if player ~= Player then
				player.Character:BreakJoints()
			end
		end
	elseif ReceivedProductID == 2651257892 then 		
		GivePlayerItemsFunction(Player, 5)
	elseif ReceivedProductID == 2657163227 then
		GivePlayerItemsFunction(Player, 10)
	end
end

MarketplaceService.ProcessReceipt = function(receiptInfo)
	print("Purchase Succeded")
	onProductPurchased()
end

And here is one of the scripts thatā€™s supposed to prompt:

local MarketplaceService = game:GetService("MarketplaceService")
local ProductId = 2651257892

script.Parent.MouseButton1Click:Connect(function()
	MarketplaceService:PromptProductPurchase(game.Players.LocalPlayer, ProductId)
end)

Whatā€™s the error?

wait nevermind i found issue hold on a sec

Oh ye mb, here it is:

ServerScriptService.ProcessRecieptScript:16: attempt to index nil with ā€˜ProductIdā€™

yeah so you see here:

you arenā€™t giving the info to the function. Just change this to:
MarketplaceService.ProcessReceipt = onProductPurchased

Yeah that fixed the problem but how would i the go about still including onProductPurchased() if it isnā€™t a function?

What do you mean? Assigning onProductPurchase to ProcessReceipt means it will be called on ProcessReceipt. If we added parenthesis, it would assign the return result.

Donā€™t forget to make onProductPurchase return an Enum.ProductPurchaseDecision.

Ah yeah good point . How would i go about making the Enum? Im new to marketplaceservice and everything under it.

Try using this structure I sent. Itā€™ll make it a lot easier.

Anyhow, you just need to return PurchaseGranted if it all went well and NotProcessedYet if it failed and something went wrong purchasing it. So, if anything goes wrong, return NotProcessedYet. You could use a pcall to help achieve this.

Okay thanks. Iā€™ll have to go now but iā€™ll test this later. Thanks for the help!

1 Like

put this in serverscript

local ID = 000
game:GetService("MarketplaceService").PromptProductPurchaseFinished:Connect(function(userID, productID, isPurchased)
	if isPurchased == false then return end
	--Do Stuff
	if productID == ID then
		--kill
	end
end)

Donā€™t use PromptProductPurchaseFinished to process product purchases - it even says so on the documentation. Itā€™s vulnerable to exploits because exploiters can just call MarketplaceService:SignalPromptProductPurchaseFinished() to fake a purchase and get free stuff. Thereā€™s also no way to signal to Roblox whether a purchase was successful or not.

sorry for that,

i got a bit carried away :grin:
letā€™s pretend i never said anything

wait, so the isPurchased can return True even if its not?

Yes. So, basically, since exploiters have full control over their machine, they can call MarketplaceService:SignalPromptProductPurchaseFinished() (which is only callable by core scripts with a thread level of 8) with incorrect parameters to send to the server. They elevate the permissions level of a script to 8 and then call it through there.

So, they can do this:

MarketplaceService:SignalPromptProductPurchaseFinished(
    game:GetService("Players").LocalPlayer.UserId,
    0, --product ID
    true
)

which tricks MarketplaceService into thinking a product prompt was just finished. The third parameter when they call it, true, is now referenced by isPurchased, even though they didnā€™t buy it. This tricks your script into giving them benefits they didnā€™t pay for.

MarketplaceService.ProcessReceipt doesnā€™t have this security flaw.

1 Like

got it, il keep that in mind, i was thinking of switching to prompproductpurchasefinish cuz its easier, but i guess it will compromise my security, Thanks

1 Like

Okay well I might be slightly stupid here (Im quite new to scripting) but where exactly am i supposed to write the new stuff? Like where in the script and how do i intergrate it?

Okay wait i might have figured it out although it doesnā€™t work. (Im probably doing something wrong here)

Here is my script in itā€™s current state, am i forgetting smth? Like there is a place where it says string. Should that be changed?

local function GivePlayerItemsFunction(player, itemAmount)
	for i, v in pairs(player:FindFirstChild("leaderstats")) do
		if v:FindFirstChild("Items") then 
			local Items = v:FindFirstChild("Items")
			Items = Items + itemAmount
			print("Found the right folder")
		end
	end
end


local productFuncs = {}

productFuncs[2651257892] = function(player: Player)
	for _, plr in ipairs(game.Players:GetPlayers()) do
		if plr ~= player then
			plr.Character:BreakJoints()
		end
	end
end

productFuncs[2651257892] = function(player: Player)
	GivePlayerItemsFunction(player, 5)
end
productFuncs[2657163227] = function(player: Player)
	GivePlayerItemsFunction(player, 10)
end


game:GetService("MarketplaceService").ProcessReceipt = function(info: {[string]: any}): Enum.ProductPurchaseDecision
	local player = game:GetService("Players"):GetPlayerByUserId(info.PlayerId)
	local callback = productFuncs[info.ProductId]

	local success = pcall(callback, player)
	return (if success then Enum.ProductPurchaseDecision.PurchaseGranted else Enum.ProductPurchaseDecision.NotProcessedYet)
end


That looks like it should work. Try adding some print statements at key points the code to help you figure out where it went wrong. If needed, you can take the error return from pcall and output it if the issueā€™s there.

local success, err = pcall(callback, player)
print(err)

Hmmm well i added some prints and as far as i can see it never enters the for loop. Here is the updated script:

local function GivePlayerItemsFunction(player, itemAmount)
	print("Entered GivePlayerItemsFunction")
	for i, v in pairs(game.Players:FindFirstChild(player.Name):FindFirstChild("leaderstats")) do
		
		print("Entered for loop")
		
		if v:FindFirstChild("Items") then 
			local Items = v:FindFirstChild("Items")
			Items = Items + itemAmount
			print("Found the right folder")
		end
	end
end


local productFuncs = {}

productFuncs[2651257892] = function(player: Player)
	print("Someone purchased Kill All!")
	for _, plr in ipairs(game.Players:GetPlayers()) do
		if plr ~= player then
			plr.Character:BreakJoints()
		end
	end
end

productFuncs[2657161178] = function(player: Player)
	GivePlayerItemsFunction(player, 5)
end
productFuncs[2657163227] = function(player: Player)
	GivePlayerItemsFunction(player, 10)
end


game:GetService("MarketplaceService").ProcessReceipt = function(info: {[string]: any}): Enum.ProductPurchaseDecision
	local player = game:GetService("Players"):GetPlayerByUserId(info.PlayerId)
	local callback = productFuncs[info.ProductId]

	local success = pcall(callback, player)
	return (if success then Enum.ProductPurchaseDecision.PurchaseGranted else Enum.ProductPurchaseDecision.NotProcessedYet)
end

This was all it printed, never anything about print(ā€œEntered for loopā€):

10:50:36.701 Entered GivePlayerItemsFunction - Server - ProcessRecieptScript:37

Okay so i changed it up a bit and it seems to work fine now! Hereā€™s the script for anyone wondering:


local function GivePlayerItemsFunction(player, itemAmount)
	if not player then
		warn("Player is nil in GivePlayerItemsFunction!")
		return
	end

	print("Entered GivePlayerItemsFunction")
	print("Player: "..player.Name)

	-- Access player's leaderstats
	local leaderstats = player:FindFirstChild("leaderstats")
	if not leaderstats then
		warn("Leaderstats not found for player: "..player.Name)
		return
	end

	-- Iterate over leaderstats
	for _, stat in pairs(leaderstats:GetChildren()) do
		print("Checking stat: "..stat.Name)

		-- Check for "Items" value
		if stat.Name == "Items" and stat:IsA("IntValue") then
			stat.Value = stat.Value + itemAmount
			print("Updated Items for "..player.Name.." by "..itemAmount)
		end
	end
end

-- Product Functions
local productFuncs = {}

productFuncs[2651257892] = function(player)
	print("Someone purchased Kill All!")
	for _, plr in ipairs(game.Players:GetPlayers()) do
		if plr ~= player then
			plr.Character:BreakJoints()
		end
	end
end

productFuncs[2657161178] = function(player)
	GivePlayerItemsFunction(player, 1)
end

productFuncs[2657163227] = function(player)
	GivePlayerItemsFunction(player, 2)
end

-- Process Receipt
game:GetService("MarketplaceService").ProcessReceipt = function(info)
	local player = game:GetService("Players"):GetPlayerByUserId(info.PlayerId)
	if not player then
		warn("Player not found for user ID: "..info.PlayerId)
		return Enum.ProductPurchaseDecision.NotProcessedYet
	end

	local callback = productFuncs[info.ProductId]
	if callback then
		local success, err = pcall(callback, player)
		if not success then
			warn("Error in product callback: "..err)
			return Enum.ProductPurchaseDecision.NotProcessedYet
		end
		return Enum.ProductPurchaseDecision.PurchaseGranted
	else
		warn("No product function found for ProductId: "..info.ProductId)
		return Enum.ProductPurchaseDecision.NotProcessedYet
	end
end


Thanks to anyone who helped!