Skip to content

Migrate flow to V4 interpreter (eval4) + soldeer + reusable workflows #474

Description

@thedavidmeister

Goal

Bring flow onto the current rain stack so it tracks latest and can use the upstream reusable CI/deploy workflows: migrate the interpreter integration V2 → V4 (eval4), de-submodule to soldeer, and convert workflows to the rainix reusables. flow is currently the org's straggler — submodules, OZ 4.x, the deprecated V2 interpreter API, and a vestigial deploy (manual-sol-artifacts.yaml runs rainix-sol-artifacts, which requires a script/Deploy.sol flow doesn't have → it would fail on dispatch).

Why now

  • The dead magic-nix-cache already breaks flow's deploy workflow; the proper fix is the reusable, which needs soldeer + a real Deploy.sol.
  • flow is pinned to a removed/deprecated interpreter API: LibEncodedDispatch no longer exists in rain.interpreter.interface, and the flat V2 interfaces (IInterpreterV2/StoreV2, IExpressionDeployerV3, IInterpreterCallerV2) are now under deprecated/. flow on V2 may already be incompatible with current deployed interpreters.

Upstream reference (security semantics — DO NOT invent)

Follow RaindexV6 / LibRaindex (the money-moving reference already on V4). The V4 model is eval-time, no deploy-time integrity check (the IExpressionDeployer model is gone):

(StackItem[] memory stack, bytes32[] memory writes) = evaluable.interpreter.eval4(
    EvalV4({
        store: evaluable.store,
        namespace: DEFAULT_STATE_NAMESPACE.qualifyNamespace(address(this)),
        bytecode: evaluable.bytecode,           // raw bytecode, not a deployed expression address
        sourceIndex: SourceIndexV2.wrap(FLOW_ENTRYPOINT),
        context: LibContext.build(context, signedContexts),  // bytes32[][]
        inputs: new StackItem[](0),
        stateOverlay: new bytes32[](0)
    })
);
if (writes.length > 0) evaluable.store.set(namespace, writes);

Work — interpreter V2 → V4

  1. Config EvaluableConfigV3{deployer,bytecode,constants}EvaluableV4{interpreter,store,bytecode} (no deployer/constants; bytecode carries constants).
  2. EvaluableV2{interpreter,store,expression}EvaluableV4; use V4 LibEvaluable hashing for registeredFlows.
  3. _flowStack: replace eval2(...encodedDispatch...) with the eval4(EvalV4{...}) block above.
  4. Stack/writes type uint256[]StackItem[](bytes32) + uint256[]bytes32[] — ripples through LibFlow.stackToFlow, the RAIN_FLOW_SENTINEL decode, and the transfer encoding. (Biggest piece.)
  5. Drop imports: LibEncodedDispatch, IExpressionDeployerV3, IInterpreterV2/StoreV2, IInterpreterCallerV2, EvaluableConfigV3. Add: IInterpreterV4, IInterpreterStoreV3, IInterpreterCallerV4 (EvaluableV4/EvalV4/SourceIndexV2), V4 LibContext/LibEvaluable, StackItem.
  6. IFlowV5IFlowV6 (breaking): flow() takes EvaluableV4; callerContext uint256[]bytes32[]; stackToFlow() takes StackItem[]. Bump dependent flow interfaces.
  7. Security semantics: drop the init-time deployExpression2 integrity check (UnsupportedFlowInputs/InsufficientFlowOutputs); enforce flow validity at eval-time per upstream (require stack.length >= MIN_FLOW_SENTINELS).
  8. Rewrite all ~10 test files (they build EvaluableConfigV3 + deploy expressions; Flow.time.t.sol's LibStackGeneration.generateFlowStack helper, etc.).

Work — de-submodule to soldeer (remappings-only, no src edits)

foundry.toml [dependencies] + [soldeer] recursive_deps=false + remappings; remove lib/ + .gitmodules. Deps: forge-std 1.16.1, OZ (5.6.1 to track latest — note OZ 4→5 is an extra code axis: security/utils/ for ReentrancyGuard, ECDSAUpgradeable removed, Multicall*; OR pin OZ 4.9.6 to defer), rain-factory 0.1.1, rain-interpreter-interface 0.1.0, rain-math-fixedpoint 0.2.0, rain-solmem 0.1.3 + transitive. Per-file remaps for the deprecated interfaces (interface/IInterpreterCallerV2.solinterface/deprecated/v1/..., IInterpreterStoreV2deprecated/v2/...).

Work — reusable workflows (the original ask)

  • rainix.yaml (CI) → rainlanguage/rainix/.github/workflows/rainix-sol.yaml (secrets: inherit). [its inline nix was already modernised in deploy: always sign with PRIVATE_KEY (never PRIVATE_KEY_DEV) #473]
  • Add script/Deploy.sol (deterministic Zoltu deploy of the Flow impl) + BuildPointers.sol + src/generated/Flow.pointers.sol. No legacy-redeploy concern (deploy was vestigial).
  • manual-sol-artifacts.yaml → reusable rainix-manual-sol-artifacts.yaml (DEPLOYMENT_SUITE).
  • Add git-clean.yaml → reusable rainix-copy-artifacts.yaml.

Notes

  • Breaking change to a financial contract → needs design review + heavy testing.
  • Will conflict with the ~22 open PRs (touches Flow.sol + tests) — sequence after the queue drains or coordinate rebases.
  • Scoping done 2026-06-06; local WIP foundry.toml/remappings were drafted in /tmp (not pushed).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions