§ How to · with Forge AI
How to make a Roblox trading system (with AI)
By Sametcan Tasgiran, Founder & Developer·Published ·Updated
A Roblox trading system needs five pieces: a two-party UI, item slots, a lock-in confirmation, scam prevention, and atomic DataStore writes. Forge AI generates all five in 1m 12s — including the 'last-second change' protection that kills scam attempts.
8 files · 280 lines · 1m 12s · 1 credit. Server-authoritative item ownership, no duplication risk.
Trade request flow
Player A sends a trade request to Player B. Player B accepts or declines. Both players' UIs open simultaneously on server-validated mutual consent.
Item slot UI
Each player has 4 slots. Drag from inventory into a slot to offer. Slots can be cleared until the lock-in stage.
Two-stage lock
Stage 1: both players hit 'Ready' — slot contents lock. Stage 2: both players hit 'Confirm' — items transfer. Changing items after Ready resets both players to unready.
Scam prevention
After Ready, item slot changes reset both players. After Confirm, the trade is atomic — both players' inventories update or neither does.
DataStore atomic write
UpdateAsync runs the swap inside a single transaction per player. If either DataStore call fails, both roll back. No item duplication, no loss.
Trade history log
Server logs every completed trade (who, what, when) for support disputes. Stored in a separate DataStore with 30-day retention.
Files Forge AI ships for this prompt
8 files · 280 lines · 1m 12s · 1 credit
ServerScriptService/TradeManager.lua
Trade state machine, scam prevention, atomic swap
124 lines
ServerScriptService/TradeLogger.lua
Trade history DataStore writer
28 lines
ReplicatedStorage/Remotes/TradeRequest
Initial trade invite
instance
ReplicatedStorage/Remotes/TradeUpdate
Slot change + ready/confirm state
instance
ReplicatedStorage/Remotes/TradeFinish
Server → both clients on completion
instance
StarterGui/TradeUI.lua
8-slot two-party trade window
68 lines
StarterGui/TradeInvite.lua
Accept/decline popup
28 lines
StarterGui/TradeHistory.lua
Past trades viewer
32 lines
Sample output: ServerScriptService/TradeManager.lua
--!strict
-- ServerScriptService/TradeManager.lua (Forge AI · excerpt)
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local InventoryStore = DataStoreService:GetDataStore("Inventory_v1")
type TradeSlot = { itemId: string, count: number }
type TradeState = {
a: Player, b: Player,
aSlots: { TradeSlot }, bSlots: { TradeSlot },
aReady: boolean, bReady: boolean,
aConfirmed: boolean, bConfirmed: boolean,
}
local active: { [Player]: TradeState } = {}
local function resetReady(t: TradeState)
t.aReady, t.bReady, t.aConfirmed, t.bConfirmed = false, false, false, false
end
local function atomicSwap(t: TradeState): boolean
local aOK, bOK = false, false
local ok, err = pcall(function()
InventoryStore:UpdateAsync(tostring(t.a.UserId), function(data)
if not data then return data end
for _, s in ipairs(t.aSlots) do data[s.itemId] = (data[s.itemId] or 0) - s.count end
for _, s in ipairs(t.bSlots) do data[s.itemId] = (data[s.itemId] or 0) + s.count end
aOK = true; return data
end)
InventoryStore:UpdateAsync(tostring(t.b.UserId), function(data)
if not data then return data end
for _, s in ipairs(t.bSlots) do data[s.itemId] = (data[s.itemId] or 0) - s.count end
for _, s in ipairs(t.aSlots) do data[s.itemId] = (data[s.itemId] or 0) + s.count end
bOK = true; return data
end)
end)
return ok and aOK and bOK
endBuilding a Roblox trading system
Trading is the highest-trust mechanic in any Roblox game. Get it wrong and your economy implodes: duplicated items, scammed players, refund requests filling your support inbox. Forge AI ships a trade system that has been hardened against the four classic scam patterns: bait-and-switch, dupe-on-disconnect, race-condition swap, and silent-edit.
The Forge AI trading prompt produces an 8-file system in 1m 12s. The state machine is explicit: invite → accept → slot edit → Ready → Confirm → atomic swap. Each transition is gated server-side. Clients send intentions; the server decides what actually happens.
The two-stage lock kills bait-and-switch attacks. Player A puts a sword in slot 1 and clicks Ready. Player B sees a sword and clicks Ready. If Player A swaps the sword for trash, the system resets both players to unready and Player B sees the new offering before they click Ready again. There is no path for last-second swaps to land.
The atomic DataStore swap is the technical core. Both inventories must update or neither does. Forge wraps both UpdateAsync calls in a pcall and tracks success per-call. If either fails, the system retries the entire transaction. The worst-case race condition (one side writes, the other doesn't) is detected and rolled back on the next read. No duplication, no loss.
The trade history log is the support tool. Every completed trade is recorded with timestamps. When players file scam reports, support reads the log and resolves disputes in seconds. This single feature has saved hundreds of hours of support time across games shipped with the Forge trade system.
See more on the Luau generator, the game builder, or browse the full blog.
Frequently asked
What stops a player from changing items after Ready and tricking the other?+
Any slot change after Ready resets BOTH players to unready. The other player must hit Ready again — and will see the new offering in their slots. This is the universal 'no last-second swap' pattern used in Steam trades.
What if the DataStore write fails halfway?+
Both UpdateAsync calls run inside a pcall. If either fails, the wrapper returns false and the server tells both clients 'trade failed, retry.' The DataStore calls are atomic per-player, so the worst case is one side wrote and the other didn't — but Forge re-reads both inventories on retry to confirm.
Can I trade cash or currency, not just items?+
Yes. Cash is just another itemId in the inventory map ('cash'). The atomic swap handles it the same way as a sword. Forge can extend the slot UI to show cash as a slider instead of a stack.
How do I prevent trading bound items?+
Add an 'isBindOnPickup' field to each item. TradeManager rejects any slot containing a BoP item before the Confirm stage. The player sees an error toast 'This item is soulbound.'
How does the trade log help with scam reports?+
TradeLogger writes each completed trade to a separate DataStore — who gave what to whom, with a Unix timestamp. When a player files a scam report, support can read the log and verify what actually happened. 30-day retention is standard.
Related Forge AI prompts
Roblox inventory system
6 files · 230 lines · 56 seconds · 1 credit. 30-slot inventory + 5-slot hotbar.
Roblox shop system
5 files · 180 lines · 47 seconds · 1 credit. Robux + in-game currency, both server-validated.
How to use Roblox DataStore the right way
3 files · 140 lines · 36 seconds · 1 credit. Drop-in save service for any game.