BlockchainSolidity10 min readUpdated

Restaurant Loyalty Token: ERC20 for Points, Tiers, and Free Dishes

By Mudassir Khan — Agentic AI Consultant & AI Systems Architect, Islamabad, Pakistan

Cover illustration for: Restaurant Loyalty Token: ERC20 for Points, Tiers, and Free Dishes

Section 01 · Introduction

Why restaurants are putting loyalty points on chain

Loyalty programs run on a database somewhere. The database belongs to a vendor. The vendor charges per active customer. The restaurant never owns the data.

Quick answer

How does a restaurant loyalty token work? A restaurant loyalty token is an ERC20 contract where the restaurant mints points to customers when they pay a bill, and burns those points when customers redeem them for free dishes or discounts. The customer's wallet holds the points. The restaurant's POS reads the balance to confirm tier discounts. Customers can gift points to friends through a normal ERC20 transfer.

A traditional loyalty program is a vendor SaaS — Loyverse, Square Loyalty, OpenTable Rewards. The vendor stores the points database. The restaurant pays per active customer. When a customer leaves and joins a competitor, the points die with the account.

An ERC20 loyalty token flips the model. The points live in the customer's own wallet. The restaurant operates the mint and burn keys but does not hold the balances. A chain of restaurants under one brand shares one contract, so a customer earns at the Defence branch and redeems at the Gulshan branch without integration headaches.

The companion piece on creating an ERC20 token in Remix walks through the base contract this builds on.

ERC20 with zero decimals = whole point amounts

Most ERC20 tokens use 18 decimals to imitate float arithmetic. Loyalty points are always whole numbers — 50 points, 200 points. Setting decimals to 0 makes the user experience match the mental model and avoids any rounding surprise.

Section 02 · The Contract

A 60 line ERC20 with cashier and kitchen roles

The whole loyalty system is OpenZeppelin's ERC20 plus two AccessControl roles. The cashier mints. The kitchen burns. Nobody else can change supply.

solidity
// Restaurant loyalty token — ERC20 with controlled mint and redeem
contract RestaurantPoints is ERC20, AccessControl {
    bytes32 public constant CASHIER_ROLE = keccak256("CASHIER_ROLE");
    bytes32 public constant KITCHEN_ROLE = keccak256("KITCHEN_ROLE");

    uint8 private constant DECIMALS = 0; // points are whole numbers

    event Earned(address indexed customer, uint256 amount, uint256 billRupees);
    event Redeemed(address indexed customer, uint256 amount, string item);

    constructor() ERC20("Tasty Points", "TASTY") {
        _grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
    }

    function decimals() public pure override returns (uint8) {
        return DECIMALS;
    }

    // 1 point per 100 rupees spent — cashier calls after the bill settles
    function earn(address customer, uint256 billRupees)
        external
        onlyRole(CASHIER_ROLE)
    {
        uint256 points = billRupees / 100;
        require(points > 0, "Loyalty: bill too small");
        _mint(customer, points);
        emit Earned(customer, points, billRupees);
    }

    // Kitchen confirms the dish was served, points are burned
    function redeem(address customer, uint256 amount, string calldata item)
        external
        onlyRole(KITCHEN_ROLE)
    {
        require(balanceOf(customer) >= amount, "Loyalty: not enough points");
        _burn(customer, amount);
        emit Redeemed(customer, amount, item);
    }
}

The two roles split the trust surface neatly. The cashier wallet sits inside the POS terminal at the front of house and can only mint. The kitchen wallet sits inside the kitchen display system and can only burn. If a cashier device is compromised, the attacker can inflate someone's points but cannot drain anyone's balance. If the kitchen device is compromised, the attacker can burn points but cannot mint to themselves.

Six step restaurant loyalty flow diagram: customer pays bill, POS reads wallet address, cashier role mints points equal to bill divided by 100, customer browses tiered menu in app, kitchen confirms dish, kitchen role burns redeemed points, transfer arrows show customer can gift points to friends.
The end to end loyalty loop. Earn, redeem, transfer — three contract calls, three on chain events.

The earn function takes the rupee amount of the bill, divides by the rate (100 in this example), and mints that many points to the customer's wallet. The rate is configurable per restaurant — a coffee shop might use 1 point per 50 rupees, a fine dining place might use 1 point per 500.

Section 03 · Tiers and Discounts

Tier benefits are pure view functions

Most loyalty programs track tier as a separate field in the database. With an ERC20 you do not need to — the tier is just a band on the current balance.

solidity
// Tier reading is a pure view function — no storage cost
function tier(address customer) external view returns (string memory) {
    uint256 bal = balanceOf(customer);
    if (bal >= 500) return "Diamond";
    if (bal >= 200) return "Gold";
    if (bal >= 50)  return "Silver";
    return "Regular";
}

// Tier specific discount lookup
function discountBps(address customer) external view returns (uint256) {
    uint256 bal = balanceOf(customer);
    if (bal >= 500) return 1500; // 15 percent
    if (bal >= 200) return 1000; // 10 percent
    if (bal >= 50)  return 500;  //  5 percent
    return 0;
}

The view function reads the balance and returns the tier name. No extra storage. No batch tier update job. A customer who crosses 200 points becomes Gold immediately, automatically, without any back end touching the database.

The POS reads discountBps at billing time and reduces the bill by the returned basis points. Diamond tier gets 15 percent off, Gold 10 percent, Silver 5 percent. The discount logic lives in the contract, not in the POS, so every branch applies the same rule.

Tier structure for a mid range restaurant chain. Tune the thresholds to your average ticket size.
TierThresholdDiscountTypical customer
Regular0–49 points0%First time or rare visitor
Silver50–199 points5%Monthly diner
Gold200–499 points10%Weekly regular
Diamond500+ points15%Birthday parties, family event host

Tier downgrade is automatic

Because tier is read from the live balance, a customer who burns 300 points on a redemption drops from Diamond to Gold without any explicit tier change. The program self heals — no scheduled job to reconcile.

Section 04 · Redemption Menu

On chain catalog locks the redemption surface

The simplest redemption is the cashier burning a free hand amount. The safer one is a fixed menu the admin sets in advance.

solidity
// On chain redemption catalog — staff cannot redeem to off menu items
mapping(bytes32 => uint256) public itemPrice; // keccak256(name) => points

function setMenuItem(string calldata item, uint256 points)
    external
    onlyRole(DEFAULT_ADMIN_ROLE)
{
    itemPrice[keccak256(bytes(item))] = points;
}

function redeemMenu(address customer, string calldata item)
    external
    onlyRole(KITCHEN_ROLE)
{
    uint256 price = itemPrice[keccak256(bytes(item))];
    require(price > 0, "Loyalty: item not on menu");
    require(balanceOf(customer) >= price, "Loyalty: not enough points");
    _burn(customer, price);
    emit Redeemed(customer, price, item);
}

The admin defines a menu of redeemable items — a free coffee for 30 points, a dessert for 50, a main course for 200. The kitchen can only redeem items that exist in the menu mapping. Off menu redemption reverts. This removes one whole class of fraud where staff burns large amounts of points against a casual customer arrangement.

Four tier ladder diagram showing point bands and discounts: Regular 0 to 49 points 0 percent, Silver 50 to 199 points 5 percent, Gold 200 to 499 points 10 percent, Diamond 500 plus points 15 percent, with arrows showing automatic promotion on earn and automatic demotion on redeem.
Tier promotion and demotion happen automatically as the balance crosses each threshold. No scheduled job, no reconciliation.

Birthday redemption — single button workflow

The customer's app shows what they can claim with their current balance. Tap a dish, sign a permit, the kitchen sees the order with the burn already authorized. No coupon code, no laminated card, no expired offer.

Promotional double points — single contract call

During a slow Tuesday, the cashier can pass an explicit multiplier to mint. A bill that would normally mint 4 points mints 8. The Earned event records the original bill so analytics stays clean.

Group dining — split points across the table

One person pays the bill, mints the points to their wallet, then transfers slices to each diner. ERC20 makes this a single batch call. The restaurant does not need to know who pays — it just knows the wallet that earned.

Section 05 · Gifting and Multi Branch

The customer benefits the SaaS loyalty programs cannot match

Two properties of ERC20 that closed loyalty databases give up — free transfer and shared state across deployments.

A customer can transfer points to a friend with a normal ERC20 send. Birthday gift, family allowance, friendly handover when a member moves cities — all handled by the standard transfer function. No SaaS feature request, no custom integration.

A restaurant chain with twelve branches deploys one contract. Every branch reads and writes the same balance map. Earning in Lahore and redeeming in Karachi is the default behavior, not a migration project. Even cross brand partnerships work — a coffee chain and a bookstore can accept each other's points by reading the partner's ERC20 balance.

The points are real to the customer because they are portable

Customers behave differently toward an asset they can transfer than toward a number in someone else's database. The same one hour discount feels more valuable when it is yours to give away. That changes how often customers come back.

Section 06 · Integration

What to ship around the contract

The POS integration is the only piece that needs custom work. Everything else uses off the shelf wallet infrastructure.

The POS at checkout adds a wallet field to the bill. The customer either scans a QR from the restaurant app or types their wallet address. After payment confirms, the POS calls earn(customer, billRupees) through a relayer so the cashier device never holds gas. The customer sees a notification with the new balance.

The kitchen display reads the open order, sees the points the customer chose to redeem, and the kitchen wallet calls redeemMenu after plating. The order ticket and the burn happen in the same minute. Reconciliation is instant.

Run the deployment on Polygon, Base, or Arbitrum. A mint costs about a cent. A burn costs about a cent. A small restaurant chain with 500 customers earning twice a week pays under twenty dollars in gas per month — less than one SaaS loyalty seat.

Section 07 · FAQ

Common questions about restaurant loyalty tokens

What restaurant owners ask before they migrate from a SaaS loyalty program to an on chain one.

How does a restaurant loyalty token work?

It is an ERC20 contract with the restaurant as the issuer. When a customer pays a bill, the cashier role mints points to the customer's wallet — typically 1 point per 100 rupees spent. When the customer redeems for a free dish, the kitchen role burns the points. Tier benefits like Silver, Gold, and Diamond are computed from the live balance, not stored separately.

Can customers transfer their loyalty points to other people?

Yes. ERC20 supports transfer by default, so a customer can gift points to a friend or family member with a single wallet to wallet send. Most SaaS loyalty programs do not allow this because the points are entries in a vendor database. Letting customers move points around makes the program feel more like a real asset and increases engagement.

What stops a cashier from minting points to their own wallet?

The cashier role can mint, so a compromised cashier device could mint to an attacker wallet. Three safeguards limit the damage. First, the role is split — kitchen burns, cashier mints, and no single device can do both. Second, every mint emits an Earned event with the bill amount, which makes inflation visible in analytics. Third, the admin role can revoke a cashier instantly if a device is lost.

Does this work across multiple restaurant branches?

Yes. One contract serves the whole chain. Every branch gives points and accepts redemptions against the same balance map. A customer earning at the Lahore branch and redeeming at the Karachi branch is the default behavior — no sync, no migration, no nightly reconciliation. Adding a new branch is granting cashier and kitchen roles to two new wallets.

Do customers need a crypto wallet to use this?

Not visibly. The restaurant's app can hold a custodial wallet on the customer's behalf, exactly like an account in any rewards app. The customer sees a points balance and a redemption screen. Power users who want self custody can claim their balance to a personal wallet at any time. The contract treats both the same.

Section 08 · Next Steps

Pick the chain, deploy the contract, wire the POS

A loyalty token is a small contract with high operational leverage. The integration into the POS is the only piece that requires care.

We help restaurant chains, cafes, and subscription venues ship on chain loyalty programs, including the contract, the POS integration, the wallet inside the customer app, and the L2 deployment. The same pattern transfers to any business that wants a transferable, portable reward — salons, car washes, bookstores, and pharmacies have all been built on this shape.

Written by Mudassir Khan

Agentic AI consultant and AI systems architect based in Islamabad, Pakistan. CEO of Cube A Cloud. 38+ agentic AI launches delivered for global founders and CTOs.

View blockchain development serviceSee ChainTrust case study

Related service

Blockchain Development

See scope & pricing →

Related case study

ChainTrust Compliance Engine

Read case study →

More on this topic

Need an AI systems architect?

Book a 30-minute architecture call. I will sketch the high-level design for your use case and give you an honest view of the trade-offs.

Book a strategy call →