Reactive Streak System in World of Rogues

Reactive Streak System in World of Rogues

World of Rogues is a post-apocalyptic multiplayer RPG that blends on-chain logic with gameplay design. One standout mechanic is a streak system, built entirely on smart contracts. It tracks daily claims and issues rewards in the form of in-game points and NFTs once players reach specific thresholds.

The core logic runs on a dedicated streak contract. NFT minting, however, is triggered on a different chain through a Reactive Network message callback — a deliberate architectural separation that allows reward logic to evolve independently of the chain used for distribution. 

This article is based on the Reactive Rogues project by Morgan Page, available on his GitHub. 


Technical Breakdown

The streak system encourages players to return daily. It works similarly to Duolingo’s streak mechanic: check in every day, maintain progress, and unlock progressively better rewards as your streak increases.

On-chain, this is handled by a set of smart contracts. The main contract, `StreakSystem`, records each player’s claim time, tracks their current streak length, and determines whether they’ve reached a predefined reward tier. There are two types of rewards:

  • Points, awarded immediately by the contract.
  • NFTs, issued via a separate cross-chain process.

When a player reaches a reward threshold that includes an NFT, the contract emits an `EarnedNFT` event. This event isn't just a log — it's a trigger.

A second contract, `StreakSystemReactive`, operates on the Reactive Network, listening for those events. When it catches one, it emits a cross-chain callback to a destination contract called `MintNFTCallback`. That contract then calls the game’s NFT smart contract `RoguesItems` to mint the actual item using the `ERC-1155` standard.

Separating logic from distribution allows the streak tracker to live on a low-cost, fast chain, while actual NFTs can be minted where players are — whether on L2s, appchains, or game-specific networks. The layers remain loosely coupled, enabling easier upgrades and broader chain support as Web3 infrastructure matures.

Contract Architecture

This system follows a modular design pattern. Each contract has a specific responsibility and clearly defined interface, making the system easy to test, extend, and maintain.

StreakSystem

This is the main contract for tracking streaks and awarding points. It uses OpenZeppelin’s `AccessControl` to restrict sensitive operations such as backdated claims or admin-only streak resets. The key function, `_claimFor`, checks claim eligibility, updates the streak, and awards points if a valid tier is hit. If the player reaches an NFT tier, the contract emits an `EarnedNFT` event:

function _claimFor(address user) private {
    if (lastClaimed[user] == 0 || (streakResetTime != 0 && block.timestamp - lastClaimed[user] > streakResetTime)) {
        streak[user] = 1;
    } else {
        require(block.timestamp - lastClaimed[user] >= streakIncrementTime, "You can't claim yet");
        streak[user]++;
    }
    lastClaimed[user] = block.timestamp;

    emit Claimed(user, streak[user], milestoneToTokenId[streak[user]]);

    if (milestoneToTokenId[streak[user]] != 0) {
        emit EarnedNFT(user, milestoneToTokenId[streak[user]]);
    }

    uint256 applicableReward = getPointReward(streak[user]);
    if (applicableReward != 0) {
        points[user] += applicableReward;
    }
}

StreakSystemReactive

This contract is deployed on the Reactive Network. It listens for `EarnedNFT` events emitted by the `StreakSystem` contract on the origin chain. 

When such an event is detected, it encodes a payload and emits a callback to the NFT-minting contract:

function react(LogRecord calldata log) external vmOnly {
    bytes memory payload = abi.encodeWithSignature(
        "callback(address,address,uint256)",
        address(0),
        address(uint160(log.topic_1)),
        log.topic_2
    );
    emit Callback(destinationChainId, callback, CALLBACK_GAS_LIMIT, payload);
}

MintNFTCallback

Deployed on the destination chain, this contract listens for cross-chain callbacks. It verifies the sender, then invokes the minting function on the actual game NFT contract:

function callback(address sender, address newNFTOwner, uint256 tokenId)
    external
    authorizedSenderOnly
    rvmIdOnly(sender)
{
    emit CallbackReceived(newNFTOwner, tokenId);
    externalERC1155.mint(newNFTOwner, tokenId, 1, "");
}

RoguesItems

The actual `ERC-1155` NFT contract that mints in-game items. Only authorized contracts like `MintNFTCallback` can mint tokens, thanks to OpenZeppelin’s `AccessControl`:

function mint(address account, uint256 id, uint256 amount, bytes memory data) public onlyRole(MINTER_ROLE) {
    _mint(account, id, amount, data);
}


Recap

The streak system in World of Rogues combines modular smart contract logic with cross-chain messaging to support a persistent gameplay mechanic. Reactive makes the system cross-chain without requiring direct contract calls between networks.

Instead of pushing transactions across chains, the `StreakSystem` contract emits events. These events are treated as triggers by Reactive, which listens, prepares a payload, and sends a callback to a contract on another chain. This separation allows streak logic to run on a low-cost chain, while rewards like NFTs are minted on whichever chain makes sense for the player.

Here’s how the full pipeline comes together in World of Rogues:

  1. A player makes a daily claim.
  2. The `StreakSystem` contract updates their streak and emits `EarnedNFT` if a milestone is reached.
  3. `StreakSystemReactive`, running on the Reactive Network, listens for that event.
  4. Upon detecting it, it emits a cross-chain `Callback`.
  5. On the destination chain, `MintNFTCallback` receives the callback and calls `RoguesItems` to mint the actual NFT.

externalERC1155.mint(newNFTOwner, tokenId, 1, "");

Ultimately, building with Reactive means thinking in terms of events, subscriptions, and callbacks. It’s not about direct interaction between contracts across chains, but about reacting to meaningful changes asynchronously.


About Reactive Network

Reactive Network—pioneered by PARSIQ—introduces Reactive Smart Contracts, an inversion-of-control programming model that lets contracts react autonomously to events on any chain. With Hyperlane-powered interoperability and $REACT as a universal gas token, Reactive is the simplest way to build truly cross-chain, event-driven dApps.