Skip to content

Repository files navigation

Infinite Flow Engine

One Soul. Infinite Worlds. Verifiable Outcomes.

An open-source, composable engine for versioned Scenes and bounded on-chain Runs.

Built on Sui. Powered by Soulidity.

Status: Experimental P0 reference implementation. Not independently audited; the checked-in production release gate remains blocked.

Infinite Flow Engine combines immutable Scene versions, continuous Soul identity, solo Runs, Sui-native randomness, asset settlement, and frozen receipts into an on-chain execution model.

The name refers to one Soul moving through many independently authored Scenes. A single Run is deliberately bounded by turn limits, deadlines, and terminal states.

This is not a backend that uploads a result after the game. External rule packages advance each Run on-chain, and randomness comes from 0x8::random::Random. State transitions and asset changes are atomic. Randomness uses two transactions: the first draws and commits a result, while the second deterministically applies it and opens settlement. Objects and events let an observer verify lifecycle, settlement, final state, and rolling commitments. Exact action replay additionally requires the transaction inputs or committed preimages supplied by the template or indexer.

Infinite Flow Engine is not affiliated with the Flow blockchain.

Current scope

  • SceneRegistry, SceneRoot, and immutable SceneVersion objects;
  • SceneAdminCap and generic SceneTemplateCap<T> capabilities;
  • one Profile per Soul and at most one active Run per Profile;
  • a complete solo Run state machine with deterministic timeout and ownership-change aborts;
  • bounded Sui Random usage with no controllable abort path after the draw;
  • exact RewardVault/Treasury binding, reward reservation, Run escrow, and abandonment loss;
  • deterministic keeper progression and settlement after a committed draw;
  • frozen RunReceipt and AcceptedOutcome facts;
  • immutable Soul-bound badges, transferable unbound items, and recoverable immutable Injury facts;
  • events, read-only getters, abort codes, and Move invariant tests;
  • a source-distributed TypeScript SDK for object types, event parsing, queries, and PTB builders;
  • a cross-module mock_template proving that games can compose the engine without modifying it.

Party play, commit-reveal, mutable inventory, namespace ledgers, automatic fee splitting, and high-value audited deployment are outside the current P0 scope.

Repository layout

sources/
  registry.move          Scene supply, immutable versions, template capabilities
  runtime.move           Profiles, Runs, randomness, economy, and settlement
  mock_template.move     Test-only external rule-package facade
  runtime_tests.move     State-machine and contract invariants
sdk/
  src/                   TypeScript queries, events, and PTB helpers
vendor/soulidity/        Reproducible Soulidity Move source snapshot
scripts/                 Immutable publish and effects verification
release/                 Release schemas and dependency-governance records
ARCHITECTURE.md
SECURITY.md
ERRORS.md
DEPLOYMENT.md
MIGRATION.md

Local verification

Soulidity is fully vendored, so the build does not depend on a sibling workspace:

soulidity = { local = "vendor/soulidity" }

Run the complete local checks:

sui move build --warnings-are-errors
sui move test --statistics

cd sdk
npm ci
npm test
npm run typecheck

Before any release, also run the read-only preview in ./scripts/publish-immutable.sh.

The SDK package is currently source-only inside this repository and deliberately marked private; it has not been published to npm.

Integrating an external game package

Each game template defines a zero-field witness that callers outside its module cannot construct:

module my_game::expedition;

use infinite_flow_engine::registry::{SceneTemplateCap, SceneVersion};
use infinite_flow_engine::runtime::{Self as runtime, SoloRun};

public struct EXPEDITION has drop {}

public fun lock(
    cap: &SceneTemplateCap<EXPEDITION>,
    version: &SceneVersion,
    run: &mut SoloRun,
    state: &soulidity::soul::SoulState,
    clock: &sui::clock::Clock,
    ctx: &TxContext,
) {
    runtime::lock_run(EXPEDITION {}, cap, version, run, state, clock, ctx)
}

The template facade freezes hit rates, damage, drops, events, and Outcome parameters inside its own package. A shared SceneTemplateCap<EXPEDITION> is insufficient to bypass those rules because an external caller cannot construct EXPEDITION {}.

The main composition surface includes:

  • registry::publish_version[_shared]<T>;
  • runtime::new_solo_run<T>;
  • lock_run, begin_route_choice, choose_route, and submit_action;
  • resolve_random_turn, settle_committed_random_result, open_continue_or_retreat, and continue_run;
  • committed_random_result, available only after transaction B applies the result;
  • record_template_event and finalize_run;
  • keeper-only record/open/continue/finalize_committed_* functions;
  • permissionless abort_after_timeout and abort_for_ownership_change functions.

sources/mock_template.move demonstrates a complete facade.

new_solo_run requires a mutable SoulPlayProfile, the exact RewardVault, and the exact SceneTreasury. It atomically claims the Profile's active_run_id, reserves policy.max_reward, and pins all three object IDs in the Run. A Profile cannot open concurrent Runs, and a Vault cannot oversell future rewards.

Wallet-callable engine facades

The following public functions can be placed directly in a PTB:

  • registry::create_scene
  • runtime::create_profile
  • runtime::create_economy
  • runtime::fund_vault
  • runtime::withdraw_treasury
  • runtime::abort_after_timeout
  • runtime::abort_for_ownership_change
  • runtime::recover_injury

Rule progression must go through a concrete game package because only that package can construct its template witness. Both abort functions also require the Profile, Vault, and Treasury pinned by the Run; another object under the same Scene is rejected.

Create and share in one PTB

Sui only permits a newly created object to become shared. Return-style APIs such as new_scene, publish_version, new_economy, and new_solo_run exist so a template can continue composing in the same PTB. The caller must invoke the matching share_* or freeze_version operation in that transaction; it cannot transfer the object first and share it later.

Prefer the atomic facades when no intermediate object is needed:

  • registry::create_scene
  • registry::publish_version_shared
  • runtime::create_economy
  • runtime::create_profile

P0 economic boundary

Entry fees, losses, and rewards settle atomically. At entry, the exact RewardVault moves max_reward into a Run reserve. Finalization pays only from that reserve and returns unused funds; timeout and ownership aborts return the full reserve. Concurrent Runs therefore cannot make a later winner discover that the Vault was oversold.

Policy enforces abandon_loss <= max_asset_loss:

  • before the first committed draw, timeout or ownership abort refunds all escrow;
  • after any committed draw, abort sends abandon_loss to the pinned Treasury and returns the rest to escrow_provider;
  • the Receipt and event record the actual loss, committed-draw status, and abort reason.

Only the matching SceneAdminCap can withdraw Treasury funds, and the recipient is pinned in SceneRoot. RewardVault has no administrator withdrawal path.

creator_bps, protocol_bps, and vault_bps are reserved commitments frozen in SceneVersion; P0 does not execute automatic three-way splitting. Official Scenes should use entry_fee = 0 until a splitting module ships.

Run state machine

Lobby
  -> Locked
  -> ChooseRoute
  -> SubmitActions
  -> ResolveTurn
  -> EncounterResult
  -> ContinueOrRetreat
       -> ChooseRoute (next turn)
       -> Finalized

Any unsettled phase
  -> Aborted (timeout or ownership-epoch change)

Owner-driven rule progression verifies Soul identity, the live owner, entry ownership epoch, template capability, pinned SceneVersion, phase, and deadline. Keeper progression after a committed draw omits only the sender requirement and retains the live Soul/owner/epoch, template/version, phase, and deadline checks. Finalization and abort paths separately enforce the exact Profile, Vault, and Treasury pinned by the Run; permissionless aborts use their explicit timeout or ownership-change condition and do not require the template or SceneVersion.

Pause gates only new Runs. An existing Run uses template-identity checks, so a creator cannot pause after escrow or a draw and block settlement. Once a draw is committed, any keeper can invoke the template's deterministic committed facade. Route choice, actions, and the draw remain owner-only.

Randomness requires two wallet transactions:

Tx A: resolve_random_turn (draw and commit; final rule call in the facade)
Tx B: settle_committed_random_result -> committed_random_result -> open/finalize

Before creating the generator, the engine locks the threshold, failure HP, success resource, settlement deadline, and transaction digest. Transaction A does not branch on success or change HP/resource after the draw. Transaction B requires a different digest and applies the locked result once. Retries are deterministic; same-transaction reads, double application, and pre-settlement continuation all abort.

The template's resolve facade must return immediately after calling the engine. It must not reuse Random or append fallible result-dependent work.

Progression, items, and Injury

SoulPlayProfile.attribute_score is a capped display total, not a trusted cross-Scene level. Permissionless Scenes can influence it, so authorization and economic decisions must aggregate facts under a trusted AcceptedOutcome.namespace instead.

A bound GameItem is frozen as an immutable Soul-bound badge keyed by Soul, source Receipt, and source SceneVersion. It is not held by a wallet. Only unbound items transfer to an address. durability is an issuance snapshot; P0 has no mutable equipment inventory.

Injury is also a frozen historical fact. The Profile stores only the currently active Injury ID, and recovery borrows &Injury without destroying it. A new owner can therefore recover the Soul after transfer. Version timeouts and individual Injuries are capped at seven days.

Release status

A fully on-chain release must publish the package and consume the returned UpgradeCap with 0x2::package::make_immutable in the same PTB. An original package ID alone does not make bytecode immutable. Production Scene creation is gated on real PTB dry-run effects, upstream verify-source --verify-deps, publisher UpgradeCap inventory, and reviewed dependency-governance evidence. See DEPLOYMENT.md.

As of 2026-07-31, the recorded governance review remains incomplete, the mainnet publish dry run has a VMVerificationOrDeserializationError blocker, vendor/soulidity/SOURCE_REVISION is a local snapshot rather than an exact upstream Git commit, and no successful source-verification artifact binds the snapshot to the target on-chain package. No immutable production package may be published until those blockers are closed.

The code has not received an independent third-party security audit. Do not use unaudited deployments for high-value assets. Read SECURITY.md before deployment and use ERRORS.md to map Move aborts.

Pre-release users of the former package name should follow MIGRATION.md.

License

MIT

About

Sui-native engine for versioned Scenes, bounded on-chain Runs, and persistent Souls—powered by Soulidity.

Topics

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages