Shiftora / Product & contract design

One space.
Exact state.

A deterministic 3×3 sliding puzzle.
Not a competition, draw or financial product.

One legal move, illustrated — not live data

Move the neighbor.
Advance the state.

Before: round 1 · move 0

After: round 1 · move 1

slide(cell 7, expectedRound 1, expectedMoves 0) emits the exact new board.

Purpose

A rule that fits
on a small board.

Shiftora is a simple wallet-isolated sliding puzzle. Eight tiles and one empty cell occupy a 3×3 board. Only an orthogonally adjacent tile can move into the space. No operator decides an outcome or assigns a prize.

The deterministic initial board is intentionally only two moves from the target. This demonstrates exact state transitions, not difficulty, random fairness, ranking or proof of a person's skill.

Board model

Nine cells.
One compact state.

The contract stores a wallet's round (uint64), moves (uint32), packed board (uint64), empty-cell index (uint8) and active flag. Cell indices 0–8 run left to right, top to bottom; each cell occupies a four-bit nibble, with zero denoting the space.

INITIAL_BOARD is the row-major arrangement [1,2,3,4,0,6,7,5,8]. SOLVED_BOARD is [1,2,3,4,5,6,7,8,0].

A valid move

Beside the space.
Not across the board.

reset() increments the caller's round, sets moves to zero, loads the fixed initial board, places the space at cell 4 and marks the round active. Reset can replace an active or completed round; no prior progress is preserved as current state.

slide(uint8 cell,uint64 expectedRound,uint32 expectedMoves) rejects an inactive round, stale round/move count, cell above 8 and any non-neighbor, including diagonal moves and row-boundary wrap. It swaps the selected tile into the empty cell and increments moves. A solved board becomes inactive.

State & events

A confirmed move.
A checkable record.

puzzles(account)
The account's current round/moves/board/empty/active tuple. The default zero state is unstarted, not a valid tile permutation.
Reset
Emits indexed account, exact new round and initial packed board.
Slid
Emits indexed account, round, selected cell, resulting board, move count and solved flag.

Expected round/moves provide an atomic stale-state guard for slides. Reset has no expected-state arguments; the frontend rechecks current state before sending, but cannot reserve it while a wallet dialog is pending. Receipt matching must verify the exact predicted event, not just any successful transaction.

Events are historical. Another later transaction can change current state; a confirmed event is not a guarantee the board still matches it. There is no global leaderboard, replay indexer, account count or public community feed in this Demo.

Authority & gas

No substitute caller.
No funds held.

Identity comes from msg.sender. No action accepts another player's author address. There is no owner, admin, proxy, token, wager, reward, native-currency transfer or application fee. Business writes are nonpayable.

A future user pays network execution gas. The review binds action, full current board state, round/moves, wallet, network, runtime code, gas limit and fixed fee cap. It expires after 60 seconds. Final submit checks state/context/fees/balance again and explicitly binds the reviewed chain. Chain-specific extra fees require separate target-network validation.

Deployment

Ready to inspect.
Not silently live.

This project includes its own unchanged ShiftoraTiles source, pinned compiler, real ephemeral-chain business and adapter tests, and a non-broadcast deployment preview. Public network/address/explorer remain unset. Onchain reads/writes cannot be enabled by Connect Wallet.

Public deployment needs a separate explicit authorization plus controlled local CLI signer, compatible network/account/balance/gas preflight and receipt/runtime checks. Private keys never belong in a webpage. Rule changes use a new reviewed address, not a hidden proxy upgrade.

Practice results are not chain results.

Practice has no real wallet, shared state, signature, gas or saved progress. Reload clears it. A successful local solve is not a transaction or reward entitlement.

Try local practice