Skip to main content
Devlog

Game Shop: free to play, live data, every payment checked, blockchain and NFTs managed

The shop of Kugle

Kugle is free to play: the shop is what pays the studio. One shop for four stores, seven ways to pay, and it changes without a new version of the game.

  • Data, not code: every item is set up in the admin dashboard, in production and in development.
  • Every payment checked by the server, with each store: the game is never trusted.
  • On-chain when it matters: eggs and tokens go to the player's wallet, the rest stays a fast database.

In-app payments: every way to pay, all integrated​

Seven ways to pay, each one integrated end to end: the purchase in the game, the server that checks it, the refunds that come back later. The game only asks; the server decides.

App Store
App Store
Google Play
Google Play
Steam
Steam
Stripe (card)
Stripe (card)
Apple Pay
Apple Pay
Google Pay
Google Pay
PayPal
PayPal
Pays withIntegrationChecked by the server
App StoreUnity IAP (StoreKit), App Store Server Librarythe signed transaction, against Apple's root certificates; server notifications for refunds
Google PlayUnity IAP (Play Billing), Google Play Developer APIthe purchase token, then acknowledged (or Google refunds it after 3 days); real-time notifications
SteamSteam microtransactions (ISteamMicroTxn), with a sandboxthe price in the player's currency, the order finalized by the server, re-checked every day, refunds flagged
Card, Apple Pay, Google PayStripe Checkouta signed webhook, then the waiting sale is completed
PayPalPayPal Orders: create, then capturethe capture, and a signed webhook
GU on-chainwallet transferthe transfer matched to the waiting sale

A confirmation that arrives twice never credits twice. The server also enforces the rules: stock, limit per player, cooldown between two tickets, "coming soon".

Show the code: one purchase, four currencies
public async buyItem(user: User, purchaseData: ShopPurchaseData): Promise<Sale> {
const shopItem = await this.shopDao.getItemByPackId(purchaseData.packId);
if (!shopItem) {
throw applicationError("Shop item not found", 404);
}

await this.assertItemIsPurchasable(user, shopItem); // stock, limit per player, coming soon
this.assertClaimCooldownElapsed(user, shopItem); // tickets: hours between two claims

const paymentOption = this.resolvePaymentOption(shopItem, purchaseData.paymentCurrency);

// Free items are given right away
if (paymentOption.price === 0) {
return this.finalizeImmediateSale(user, shopItem, () =>
this.shopDao.createSale(user, shopItem, purchaseData, paymentOption, true, undefined, SaleProvider.Free)
);
}

switch (paymentOption.currency) {
case PaymentCurrency.Ticket:
case PaymentCurrency.GUV:
// paid from the balance in the database: settled now
return this.buyWithLoot(user, shopItem, purchaseData, paymentOption);
case PaymentCurrency.GU:
case PaymentCurrency.USD:
// paid outside (on-chain, store, card): the sale waits for the confirmation
return await this.shopDao.createSale(user, shopItem, purchaseData, paymentOption);
}
}

What is sold​

Two currencies, Diamonds and GU, plus tickets and real money. Seven kinds of items: food and power-ups, emotes, potions, tickets that refill on a timer, egg boosters of an edition, tokens (Heat, Carbon) and in-app packs.

Utilities
Utilities
Emotes, bought or free
Emotes, bought or free
GU packs, real money
GU packs, real money
Heat and Carbon
Heat and Carbon

Data, not code: the shop is set up live​

An item is a document in the database: name, picture, price in each currency, stock, limit per player, "coming soon", order on the screen. The team creates and changes them in the admin dashboard, in PROD and in DEV: a new pack, a sale, a price test, the monthly event items. No build, no store review.

Every tab of the shop, in the dashboard: one row per item, its price in each currency, its stock, and the Switch that opens or closes the whole shop.

The In-App Items tab: seven Diamond packs, from 2,99 USD for 300 to 99,99 USD for 12,500

Live switches too: open or close the shop, and a Steam-friendly mode that hides everything blockchain in the Steam build (Steam does not allow it).

On-chain when it matters​

An egg booster is minted from its edition's smart contract, straight into the player's wallet. When the player pays in Diamonds, the studio pays the transaction for them: no wallet to fund, no gas to understand. Players can also sell their Kugles to each other on a player marketplace.

In the dashboard: the numbers​

Every sale is recorded with its currency and who took the payment: the dashboard shows the month's sales, the totals per currency and the detail per item.

The Stats du shop page of the dashboard, with example figures (marked as such): items sold in the month, the totals in GU, GUV, USD and tickets, and the detail of the sales per item

The page of the dashboard, filled with example data, not Kugle's real figures.

info

The shop of Kugle: Unity and C# in the game, Node.js and TypeScript for the API, Solidity for the contracts, React for the dashboard. Contact me if you are interested.

See also​

  • Kugle Corp: the studio, and free to play run on numbers.
  • Kugle: the game and its monetization.