Donate currency to player In-game

So I wanted to add a feature in my game where you can give the amount of coins you have to another player by typing in the amount that you want to donate and selecting the player to give it to.

Example:
Player1 has 1000 credits
Player2 has 0 credits

Player1 donates 500 to Player2

Player1 has 500
Player2 has 500

If Player1 tries to donate x>current # of credits, it doesn’t work

local d = player1.donation
local n = player1.credits
if d > n then return end

local t = player2.credits
player1.credits -= d
t += d
local function Donate(player1, player2, num)
  local n = player1.credits
  if num > n then return end

 player1.credits -= num
 player2.credits += num
end

Donate()

of course you would need a value ‘credits’ that could either be table data or an IntValue

–// so something like, in a script:

game.Players:PlayerAdded:Connect(function(player:Player)
 local character = player.Character or player.CharacterAdded:Wait()   
 local credits:IntValue = Instance.new("IntValue")
 credits.Name = "credits"
 credits.Value = *a default value*
 credits.Parent = character
end)

then you have the IntValue credits,
you would need a GUI element for the player to call Donate() to
how you handle specifying player2 i don’t know

of course with the above code there’s always that possibility an exploiter just modifies the intvalue and there’s not anything the server can do, so you want to handle that on the server.

you’re ignoring sanity checking the arguments, a player can donate negative value (and do it without any other player in the server)

local donatePlayer = game:GetService("ReplicatedStorage"):WaitForChild("Donate")
donatePlayer:FireServer({credits = 0}, -999999)

haha yeah very true

local function Donate(player1, player2, num)
  if num <= 0 then return end

  local n = player1.credits
  if num > n then return end

 local p2 = game.Players:FindFirstChild(player2.Name)
 if not p2 then return end

 player1.credits -= num
 player2.credits += num
end

Donate()

this isn’t really the best way to do this, you can implement typechecking to prevent errors
shameless post plug
https://devforum.roblox.com/t/avoiding-exploits-in-instance-based-remote-parameters/1858928

well yeah if you’re firing a remote from the client than you’d need to fortify the method fairly extensive and use typeof() on all the parameters as well as value-checking,
but that all beyond the scope of the concept

if this was remotely fired from the client than you’d need to fortify it
however, even with typechecking and valuechecking there could still be an exploitable environment where an exploiter fires the event with somebody else’s player. how do you check if player1 is actually the player who fired the event??
A exploiter could fire this donate event with two random people, whenever they want. So you would then need a boolean value to evaluate to whether the specified player is indeed the one donating… even Avoiding exploits in instance-based remote parameters - Development Discussion - DevForum | Roblox doesn’t protect against that circumstance.
anyhow, validation is an important concept and should never be overlooked when finalizing an implementation, however it is a constantly evolving concept and is likely to be re-implemented at a later time because it is big; validation is entirely different ballgame

local function Donate(player1, player2, donation:number)
 if typeof(player1) ~= "Player" or typeof(player2) ~= "Player" 
or game.Players:FindFirstChild(player1.Name) == nil 
or game.Players:FindFirstChild(player2.Name) == nil
or player1.Character:FindFirstChild("credits") == nil 
or player2.Character:FindFirstChild("credits") == nil 
or donation <= 0 or donation > player1.Character:FindFirstChild("credits").Value then
return
end

 player1.Character:FindFirstChild("credits").Value -= donation
 player2.Character:FindFirstChild("credits").Value += donation
end