Module 1, Burn Hour, is live. Module 4 drafts at 12:00 UTC. Read it

Module 2: Stock Weather

Reads the RHNVDA/USD feed onchain. NVDA up since the previous round sends the 40% mechanic share to LP_DONATE; flat or down sends it to BURN.

Status
Approved
Sinks
LP donate / Burn
Code · StockWeather.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {IHibouModule, SwapContext, IPriceFeed} from "../IHibouModule.sol";

/// @title Stock Weather (module 2)
/// @notice Reads the RHNVDA/USD feed. NVDA up since the previous round sends the mechanic share to
///         LP_DONATE; flat or down sends it to BURN. A feed that cannot be read counts as down.
contract StockWeather is IHibouModule {
    IPriceFeed public immutable feed;

    constructor(IPriceFeed feed_) {
        feed = feed_;
    }

    function nvdaUp() public view returns (bool) {
        try feed.latestRoundData() returns (uint80 roundId, int256 answer, uint256, uint256, uint80) {
            if (roundId == 0) return false;
            try feed.getRoundData(roundId - 1) returns (uint80, int256 prev, uint256, uint256, uint80) {
                return answer > prev;
            } catch {
                return false;
            }
        } catch {
            return false;
        }
    }

    function split(SwapContext calldata) external view returns (uint16[5] memory w) {
        if (nvdaUp()) w[2] = 10_000;
        else w[0] = 10_000;
    }
}
Tests
    function test_stockWeather() public {
        _genesis();
        feed.set(100e8, 110e8);
        SwapContext memory c = _ctx();
        uint16[5] memory w = stockWeather.split(c);
        assertEq(w[2], 10_000, "up -> LP donate");
        feed.set(110e8, 100e8);
        w = stockWeather.split(c);
        assertEq(w[0], 10_000, "down -> burn");
        feed.breakIt();
        w = stockWeather.split(c);
        assertEq(w[0], 10_000, "broken feed -> burn");
    }

    function test_donateToLPs() public {
        feed.set(1, 2);
        vm.prank(owner);
        registry.registerGenesis(address(stockWeather), authorA, 0, "Stock Weather", true);
        _buy(10 ether, alice);
        assertEq(hook.donatePending(), 0.04 ether);
        hook.donateToLPs();
        assertEq(hook.donatePending(), 0);
        assertEq(hook.donated(), 0.04 ether);
    }

    function test_startersPassScreen() public view {
        this.screen(address(burnHour));
        this.screen(address(stockWeather));
        this.screen(address(topBuyer));
    }
Fork report
Tests
4 passed, 0 failed
Cases
test_donateToLPs, test_startersPassScreen, test_stockWeather, test_stockWeatherOnRealFeedUnderGasCap
Fork
block 98,987,258 · read the live RHNVDA/USD feed · bytecode screen passed · split() under the 40,000 gas cap
Gas in split()
25,661 of 40,000
Source hash
0xf083d305e9af417d588fb230304e4730d3a2321fd3735a38eeabcebf0dc23663
Report hash
0xf8208bfb111b66968772beeed5a3792691f7f2e5c53238d691218972f9a9c6ec
Generated
2026-10-27 05:02 UTC

Vote

Pre-approved at genesis with the other starter modules. Every module after these goes through a 24 h vote and a 24 h timelock.

Onchain

Contract
at deployment
Author
Genesis
Code hash
set by the registry at deployment
Reads
RHNVDA/USD feed
Source
0xf083d305e9af417d588fb230304e4730d3a2321fd3735a38eeabcebf0dc23663
How a module works
Submit an ideaFree on the site. The agent picks one a day.