Selene Chain

Selene Chain is a live demo of Syndicate's programmable, onchain sequencer.

Selene Chain is a live demonstration of a programmable, onchain sequencer governed by natural cycles–in this case, the phases of the moon. By anchoring transaction sequencing to lunar cycles, Selene eliminates manual intervention and enables a system that is both autonomous and intentionally opinionated.

Built on Syndicate's infrastructure, Selene showcases how sequencing logic can be made expressive, time-based, and fully onchain—unlocking new possibilities for permissioning, ordering, and custom transaction rules.

Selene demo website

Screenshot: Selene Chain demo interface, showing lunar phase–based transaction prompts.

How It Works: Transaction Lifecycle

  1. Submission: A user submits a transaction via the Selene demo interface.
  2. Sequencing: The onchain sequencer module determines the current lunar phase and applies the corresponding rule to the transaction.
  3. Validation: If the transaction matches the active phase's criteria, it is sequenced and included onchain. If not, it is rejected and logged.
  4. Feedback: Users see immediate feedback—either a transaction hash for success or a rejection message. All rejected attempts are stored in a PostgreSQL database for transparency and analysis.

Sequencing Module: Lunar Phase Permissions

In Syndicate's programmable sequencer, modules are pluggable components that define how transactions are selected, ordered, and included onchain. The Selene demo implements a custom permission-focused sequencing module. All transaction inclusion rules are defined and enforced onchain by the sequencer. Each lunar phase activates a distinct set of permissioning rules. E.g. only low-value transactions are allowed during Waning Crescent.

This demonstrates how developers can use Syndicate to build expressive, autonomous infrastructure with dynamic, phase-based transaction policies enforced directly at the protocol layer.

Lunar Phase Calculation & Rules

The module computes the current moon phase from a timestamp, mapping it to one of 8 rule sets.

Formula:

Elapsed Time=timestamp947182440Phase Time=Elapsed Timemod2551443Phase Index=Phase Time×302551443\begin{aligned} \text{Elapsed Time} &= \text{timestamp} - 947182440 \\ \text{Phase Time} &= \text{Elapsed Time} \bmod 2551443 \\ \text{Phase Index} &= \left\lfloor \frac{\text{Phase Time} \times 30}{2551443} \right\rfloor \end{aligned}
MoonphasePermissionModule.sol
  /// @notice Computes the phase index for a given timestamp
  /// @param timestamp The timestamp to compute the phase index for
  /// @return phaseIndex The phase index
  function getPhaseIndex(uint256 timestamp) internal pure returns (uint8 phaseIndex) {
      // Known new moon: Jan 6, 2000 at 18:14 UTC
      uint256 synodicMonth = 2551443; // seconds in a synodic month (~29.5306 days)
      uint256 newMoonReference = 947182440; // reference new moon timestamp
      uint256 elapsed = timestamp - newMoonReference;
      uint256 phaseTime = elapsed % synodicMonth;
 
      // Calculate the phase from 0 to 29
      return uint8((phaseTime * 30) / synodicMonth);
  }

Then we pass the phaseIndex into the getPhaseName function to return the name of the moon phase:

MoonphasePermissionModule.sol
  function getPhaseName(uint8 phase) internal pure returns (string memory name) {
      if (phase == 0 || phase == 29) return "New Moon";
      if (phase >= 1 && phase <= 6) return "Waxing Crescent";
      if (phase == 7) return "First Quarter";
      if (phase >= 8 && phase <= 13) return "Waxing Gibbous";
      if (phase >= 14 && phase <= 15) return "Full Moon";
      if (phase >= 16 && phase <= 21) return "Waning Gibbous";
      if (phase == 22) return "Last Quarter";
      if (phase >= 23 && phase <= 28) return "Waning Crescent";
  }

Rules Table:

Moon PhaseRule Description
New MoonPrefers low calldata size
Waxing CrescentOnly broadcasts to an allowed contract
First QuarterRequires angel number donation (e.g., 111, 333, etc.)
Waxing GibbousOnly allows function calls to waxingGibbous()
Full MoonOnly allows token interactions (ERC20, ERC721, ERC1155)
Waning GibbousRequires high gas limit (≥ 21k)
Last QuarterEnforces a calldata/gas limit ratio ≥ 16
Waning CrescentOnly allows low-value transactions (≤ 0.01 ETH)

Each of these rules is implemented in MoonphasePermissionModule.sol and enforced at the sequencing layer.

Demo Architecture & Tech Stack

Selene Chain is built with a modular, extensible architecture that demonstrates how lunar phase logic can be enforced onchain and surfaced in a modern web application. Here's how the pieces fit together:

  • Sequencer: decentralized onchain sequencing

  • Sequencing module: all lunar phase logic is enforced onchain via Solidity modules (MoonphasePermissionModule.sol), which determine transaction validity based on the current phase.

  • Frontend: Built with Next.js, TypeScript, and Tailwind CSS, the UI provides interactive prompts and real-time feedback to users.

  • Backend: Uses PostgreSQL for transaction logging and Drizzle ORM for database access.

  • Development & Testing: Foundry is used for contract development and testing.

Get Started

Ready to build your appchain with Syndicate?

  1. Try the Live Demo
  2. Explore the Codebase to understand the architecture and extend the module
  3. View Onchain Sequencing Modules to start customizing ordering, permissions, and economic mechanisms for your own appchain
  4. Reach out to the Syndicate team for support or to share your experiments!

On this page