Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions contracts/ACCESS_CONTROL_REVIEW.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ Status: V0 launch hardening review.

The current contracts use simple ownership or self-registration patterns. They do not implement staking, slashing, token custody, rewards, production governance, verifier consensus, or upgrade admin controls.

They also do not enforce cross-contract dependency existence. For example, a work receipt or verifier report may reference a nonzero `rootfieldId` or `receiptId` that another contract has not registered. That is intentional for this optional V0 event spine: indexers and verifiers reconcile dependencies off-chain from receipts, logs, fixtures, and reports.

No current contract exposes bridge finality or a challenge lifecycle. `REORGED` is an allowed verifier-report status for local/test reconciliation, not a Solidity finality proof, production bridge state, or challenge-resolution mechanism.

## RootfieldRegistry

Owner model: each `rootfieldId` has one owner.
Expand All @@ -19,8 +23,10 @@ Owner-gated functions:
Current protections:

- zero rootfield id rejected
- zero schema hash rejected
- duplicate rootfield id rejected
- zero root rejected
- zero artifact commitment rejected for root submissions
- inactive rootfield blocks root submission and transfer
- zero new owner rejected
- ownership transfer emits both a FlowPulse status event and a dedicated ownership event
Expand Down Expand Up @@ -50,9 +56,10 @@ Submitter-gated functions:
Current protections:

- zero worker/verifier rejected
- revoked worker/verifier authorization blocks future submissions
- duplicate report/receipt id rejected
- invalid report status rejected
- invalid work lane rejected
- invalid report status rejected below and above the accepted V0 range
- invalid work lane rejected below and above the accepted V0 range
- zero target or commitment fields rejected

Launch risk to watch:
Expand Down Expand Up @@ -96,6 +103,8 @@ Owner-gated functions:
Current protections:

- zero ids and zero commitments rejected
- zero rootfield id rejected where a record belongs to a Rootfield namespace
- zero artifact schema hash rejected
- duplicate records rejected
- only the stored owner can mutate the record

Expand All @@ -113,7 +122,7 @@ Contracts:

Current boundary:

- `ReceiptVerifier` accepts first-writer receipt-report commitments and does not cryptographically verify receipts.
- `ReceiptVerifier` accepts first-writer receipt-report commitments and does not cryptographically verify receipts. It rejects zero report ids, observation ids, rootfield ids, receipt commitments, and report hashes so local-alpha reports remain reconstructable by indexers/verifiers.
- `WorkDebtScheduler` allows any scheduler to assign work to a nonzero worker and allows scheduler or worker to mark completion.
- `FlowMemoryHookAdapter` validates nonzero inputs and emits an observation event. It also exposes a dependency-light Uniswap v4-shaped `afterSwap` callback path, but it is not a production Uniswap v4 hook deployment.

Expand Down
2 changes: 2 additions & 0 deletions contracts/ArtifactRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ contract ArtifactRegistry is IArtifactRegistry {
error ZeroRootfieldId();
error ZeroArtifactType();
error ZeroCommitmentHash();
error ZeroSchemaHash();
error ArtifactAlreadyRegistered(bytes32 artifactId);
error ArtifactNotRegistered(bytes32 artifactId);
error ArtifactNotActive(bytes32 artifactId);
Expand All @@ -32,6 +33,7 @@ contract ArtifactRegistry is IArtifactRegistry {
if (rootfieldId == bytes32(0)) revert ZeroRootfieldId();
if (artifactType == bytes32(0)) revert ZeroArtifactType();
if (commitmentHash == bytes32(0)) revert ZeroCommitmentHash();
if (schemaHash == bytes32(0)) revert ZeroSchemaHash();
if (_artifacts[artifactId].exists) revert ArtifactAlreadyRegistered(artifactId);

uint64 now64 = _blockTimestamp();
Expand Down
56 changes: 56 additions & 0 deletions contracts/DEPLOYMENT_BOUNDARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,81 @@

Status: V0 local and Base Sepolia readiness boundary.

The current contracts are a compact event and commitment spine. They store intentional roots, receipt/report commitments, registry metadata hashes, counters, and status fields only. Heavy artifacts, AI memory, media, model data, verifier evidence, and receipt reconstruction data remain off-chain.

For the private/local FlowChain testnet package, these Solidity contracts are optional settlement/event anchors. They are not the private L1 runtime. The private/local runtime remains the Rust/local devnet and local services path; Solidity may mirror compact events or commitments for tests and canaries only when that boundary is explicit.

## Allowed Now

- Local Foundry tests.
- Local fixture generation and indexer/verifier/dashboard flows.
- Base Sepolia deployment dry runs and explicit broadcasts for the current V0 contracts.
- Base Sepolia reads from explicit RPC URLs.
- Guarded Base mainnet canary reads and source-verification dry runs for the documented V0 canary addresses only.
- Public docs that describe emitted events, roots, receipts, and off-chain verification paths.

## Not Allowed Yet

- Base mainnet deployment claims.
- Production-mainnet readiness claims.
- Production L1 claims.
- Claims that the Solidity contracts are the private/local FlowChain L1 runtime.
- Production Base settlement-anchor claims.
- Production bridge, production finality, or production challenge-resolution claims.
- Broad Base mainnet scans outside the documented canary reader guardrails.
- Token launch, rewards, slashing, or fee-market mechanics.
- Dynamic Uniswap v4 fee hooks.
- Custody of user tokens.
- Claims that contracts can know `txHash` or `logIndex` during execution.
- Claims that on-chain storage is free or that arbitrary AI data is stored on-chain.

## Settlement Anchor Boundary

Base anchoring is placeholder/research until separately approved. A future anchor must be scoped in its own issue or decision record with threat model, source/target chain assumptions, replay boundaries, event semantics, indexer/verifier responsibilities, and deployment review. The current V0 contracts do not implement a bridge, production settlement finality, token movement, or appchain/L1 launch path.

FlowPulse events intentionally omit `txHash` and `logIndex`; indexers derive those values after receipts and logs exist. URI fields are advisory caller-supplied log data unless a future contract explicitly validates format, length, resolvability, or content hash linkage.

No current Solidity contract exposes a challenge lifecycle or finality state machine. `VerifierReportRegistry.REORGED` is an advisory report status for off-chain reconciliation, not a bridge finality proof or challenge resolution path.

## Private/Local FlowChain Mirror Map

The private/local FlowChain runtime owns object execution and final state. The Solidity spine may mirror or anchor only compact object references:

| Private/local object | Optional Solidity mirror |
| --- | --- |
| Agent/operator identity | `WorkerRegistry` metadata commitments |
| Verifier module identity | `VerifierRegistry` metadata commitments |
| WorkReceipt | `WorkReceiptRegistry` compact receipt commitments |
| VerifierReport | `VerifierReportRegistry` or `ReceiptVerifier` report commitments |
| ArtifactAvailabilityProof or model metadata pointer | `ArtifactRegistry` commitment and schema hashes |
| Indexer checkpoint | `CursorRegistry` cursor commitments |
| MemoryCell or Rootflow state update | `RootfieldRegistry` root commitments and FlowPulse events |
| Challenge or finality state | Not mirrored by Solidity V0; handled by the Rust/local devnet and local services |

These mirrors do not make Solidity the private L1 runtime and do not create production bridge, settlement, fee, token, or validator semantics.

## Local Hardening Commands

Run these from the repository root before review:

```powershell
forge test
npm run contracts:hardening
git diff --check
```

`npm run contracts:hardening` runs the local Foundry hardening baseline and Slither when it is installed. Slither can be made mandatory with:

```powershell
npm run contracts:hardening:slither
```

Formatting can be checked explicitly with:

```powershell
.\infra\scripts\contracts-static-analysis.ps1 -CheckFormat
```

## Deployment Inputs Required

Before a Base Sepolia deployment transaction is sent, the PR or issue must record:
Expand Down
8 changes: 7 additions & 1 deletion contracts/FLOWPULSE_SCHEMA.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# FlowPulse Schema v0

FlowPulse is the first shared event stream for FlowMemory protocol activity. It is intentionally small and commitment-oriented: contracts emit roots, commitments, and advisory URI strings while indexers and verifiers reconstruct full context from receipts, logs, and off-chain artifacts.
FlowPulse is the first shared event stream for FlowMemory protocol activity. It is intentionally small and commitment-oriented: contracts emit roots, commitments, and advisory URI strings while indexers and verifiers reconstruct full context from receipts, logs, and off-chain artifacts. Contract state is compact by design; it is not an artifact store, model store, bridge state machine, or production L1 state surface.

For the private/local FlowChain testnet, FlowPulse contracts are optional anchors and event mirrors. The private L1 runtime is the Rust/local devnet and local service stack, not Solidity.

## Solidity Event

Expand Down Expand Up @@ -42,8 +44,12 @@ FlowPulse does not include `txHash` or `logIndex`. Those values are not availabl

- `pulseId` is unique within the emitting contract's domain but indexers should still key canonical observations by chain id, contract address, transaction hash, and log index.
- `uri` values are advisory by convention only. The skeleton does not enforce that they are short, resolvable, or off-chain pointers, so callers and reviewers must treat the off-chain-data boundary as a design convention rather than an enforcement guarantee.
- `RootfieldRegistry` rejects zero `rootfieldId`, zero `schemaHash`, zero committed root, and zero `artifactCommitment` so local-alpha root transitions keep enough compact state for indexers and verifiers to reconstruct the object model.
- Verifiers must validate any referenced off-chain content against the emitted `commitment`.
- Pulse type expansion should happen by reserving new numeric values and documenting their subject and commitment semantics before contracts depend on them.
- Base settlement-anchor use remains placeholder/research until a separate issue, threat model, and deployment review approve a concrete anchor design. The current event schema does not implement a bridge, appchain finality, or production settlement guarantees.
- `FlowMemoryHookAdapter` is a V0 scaffold. Its direct helper and dependency-light Uniswap v4-shaped `afterSwap` path emit the same `SWAP_MEMORY_SIGNAL` semantics, but neither path is a production hook deployment, dynamic-fee hook, or custody path.
- Current Solidity contracts do not expose challenge resolution or finality state. Verifier statuses such as `REORGED` are compact report values for off-chain reconciliation.

## Current Pulse Types

Expand Down
4 changes: 4 additions & 0 deletions contracts/ReceiptVerifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ contract ReceiptVerifier is IReceiptVerifier {

error ZeroReportId();
error ZeroObservationId();
error ZeroRootfieldId();
error ZeroReceiptCommitment();
error ZeroReportHash();
error ReceiptReportAlreadySubmitted(bytes32 reportId);
error TimestampOverflow(uint256 timestamp);

Expand All @@ -27,7 +29,9 @@ contract ReceiptVerifier is IReceiptVerifier {
) external {
if (reportId == bytes32(0)) revert ZeroReportId();
if (observationId == bytes32(0)) revert ZeroObservationId();
if (rootfieldId == bytes32(0)) revert ZeroRootfieldId();
if (receiptCommitment == bytes32(0)) revert ZeroReceiptCommitment();
if (reportHash == bytes32(0)) revert ZeroReportHash();
if (_reports[reportId].status != ReceiptStatus.Unknown) revert ReceiptReportAlreadySubmitted(reportId);

_reports[reportId] = ReceiptReport({
Expand Down
8 changes: 8 additions & 0 deletions contracts/RootfieldRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ contract RootfieldRegistry is IFlowPulse, IRootfieldRegistry {
mapping(bytes32 rootfieldId => Rootfield rootfield) private _rootfields;

error ZeroRootfieldId();
error ZeroSchemaHash();
error ZeroRoot();
error ZeroArtifactCommitment();
error RootfieldAlreadyRegistered(bytes32 rootfieldId);
error RootfieldNotRegistered(bytes32 rootfieldId);
error RootfieldInactive(bytes32 rootfieldId);
Expand All @@ -46,6 +48,9 @@ contract RootfieldRegistry is IFlowPulse, IRootfieldRegistry {
if (rootfieldId == bytes32(0)) {
revert ZeroRootfieldId();
}
if (schemaHash == bytes32(0)) {
revert ZeroSchemaHash();
}
if (_rootfields[rootfieldId].owner != address(0)) {
revert RootfieldAlreadyRegistered(rootfieldId);
}
Expand Down Expand Up @@ -85,6 +90,9 @@ contract RootfieldRegistry is IFlowPulse, IRootfieldRegistry {
if (root == bytes32(0)) {
revert ZeroRoot();
}
if (artifactCommitment == bytes32(0)) {
revert ZeroArtifactCommitment();
}

rootfield.latestRoot = root;
rootfield.rootCount += 1;
Expand Down
Loading
Loading