Guides
Economy and coins
Build a coin system with /daily, /balance, /give and a shop that sells roles.
You will build a small economy:
| Command | What it does |
|---|---|
/daily | Gives 100 coins, once every 24 hours |
/balance | Shows how many coins someone has |
/give | Sends coins to another member |
/shop | Lists what you can buy |
/buy | Buys a role with coins |
Works on every plan.
What you need#
- About 15 minutes.
- For the shop: the roles you want to sell, and the bot's role above them in Server Settings → Roles.
Coins are saved in a Mongo database called economy, with one row per member. It is made the first time someone gets coins. See Saving data.
Note
Every command below goes in the Pre-hook box of a slash command. Leave the Response box empty. set_content writes the reply.
1. /daily#
Open Create → Slash Command. Name it daily, description Claim your daily coins. Pre-hook:
cooldown("24 hours", error_message="You already claimed today. Come back %relative%.")
bank = SlashMongo("economy")
uid = str(user.id)
await bank.update_one({"_id": uid}, {"$inc": {"coins": 100}}, upsert=True)
doc = await bank.find_one({"_id": uid})
set_content(f"You got **100** coins. You now have **{intcomma(doc['coins'])}**.")cooldownstops the command for 24 hours per member. The wait is saved, so a bot restart does not reset it.%relative%becomes "in 5 hours", and Discord counts it down live.$incadds to the number.upsert=Truemakes the row for a new member.
2. /balance#
Name it balance. Add a Member argument named member, with Required off. Pre-hook:
target = member or user
doc = await SlashMongo("economy").find_one({"_id": str(target.id)})
coins = doc["coins"] if doc else 0
set_content(f"**{target.display_name}** has **{intcomma(coins)}** coins.")3. /give#
Name it give. Add two arguments:
| Type | Name | Required |
|---|---|---|
| Member | member | On |
| Integer | amount | On |
Set the Minimum of amount to 1. Pre-hook:
if member.id == user.id or member.is_bot:
set_error("Pick another member.")
bank = SlashMongo("economy")
# Take the coins only if the giver has enough. One step, so two
# /give at the same time cannot spend the same coins twice.
taken = await bank.update_one(
{"_id": str(user.id), "coins": {"$gte": amount}},
{"$inc": {"coins": -amount}},
)
if taken.modified_count == 0:
set_error("You do not have enough coins.")
await bank.update_one(
{"_id": str(member.id)},
{"$inc": {"coins": amount}},
upsert=True,
)
set_content(f"{user.mention} gave **{intcomma(amount)}** coins to {member.mention}.")set_error stops the command and shows the text to the user. Nothing after it runs.
4. /shop#
Name it shop. Pre-hook:
SHOP = {
"vip": {"price": 5000, "role": "VIP"},
"red": {"price": 1000, "role": "Red"},
}
lines = []
for key, item in SHOP.items():
lines.append(f"`{key}` — **{item['role']}** role, {intcomma(item['price'])} coins")
set_embed(Message(
title="Shop",
description="\n".join(lines) + "\n\nBuy with `/buy`.",
color="#F1C40F",
))Change SHOP to your own items. role is the exact role name in your server.
5. /buy#
Name it buy. Add a Text argument named item, Required on. Under Choices, keep Fixed list and add one value per item: vip, red. Members then pick from a list instead of typing.
Pre-hook:
SHOP = {
"vip": {"price": 5000, "role": "VIP"},
"red": {"price": 1000, "role": "Red"},
}
choice = SHOP.get(item)
if choice is None:
set_error("That item is not in the shop.")
if has_role(user, choice["role"]):
set_error("You already have that role.")
bank = SlashMongo("economy")
uid = str(user.id)
paid = await bank.update_one(
{"_id": uid, "coins": {"$gte": choice["price"]}},
{"$inc": {"coins": -choice["price"]}},
)
if paid.modified_count == 0:
set_error(f"You need {intcomma(choice['price'])} coins.")
try:
add_roles(user, choice["role"])
except Exception:
# Give the coins back if the role could not be given.
await bank.update_one({"_id": uid}, {"$inc": {"coins": choice["price"]}})
set_error("Could not give the role. Your coins were returned.")
set_content(f"You bought the **{choice['role']}** role!")Tip
Keep the SHOP list the same in /shop and /buy. When you add an item, change both, and add its value to the item choices.
6. Test it#
- Run
/daily. You get 100 coins. - Run
/dailyagain. It says when you can claim next. - Run
/givewith a friend and50. Check both with/balance. - Lower a price to
50and try/buy.
Errors from your code show in Logs → Error Logs on the dashboard.
Ideas#
- Coins for chatting. Use the Message event from Levels and XP and
$inccoins instead of XP. Needs premium. - Rich list. Copy
/leaderboardfrom the levels guide and sort bycoins. - Gambling. A
/coinflipthat bets coins. Start from the coin flip example. - Staff tools. A
/addcoinscommand for admins. Set its Discord permissions to Manage Server so only staff see it.