Cork Rollover is a Solidity/Foundry protocol for signed rollover orders
between Cork Phoenix pools. Phoenix pools
issue a dual share pair — cPT (principal) and cST (swap) — against a
collateral asset and mature at a fixed expiry. Rollover lets a cPT holder
move a cST position from an expiring source pool into a destination pool in a
single signed flow: a filler pushes source cST into the cPT holder's rollover contract,
the rollover contract performs the Phoenix unwindMint/deposit leg under a signed hook
plan, and the filler later pays a premium to claim the produced destination
cST — or the residual is reclaimed if the premium never arrives.
The protocol combines an ERC-7683-compatible settler pair (exact and partial
fill modes), per-cPT-holder clones with immutable arguments (CWIA), ERC-7484
module attestation for hook targets, and filler-side orchestration through
BaseFiller. Runtime order execution is single-chain: admission requires
originChainId == block.chainid and destinationChainId == block.chainid.
Code in src/ is the source of truth. The protocol spec
and invariant ledger explain the integration contracts.
These documents do not establish a security-review level.
0.2.0 identifies this Rollover source release. A review-branch snapshot does not establish publication. Published release records are listed in Rollover releases; current deployment information belongs in the Cork documentation.
CorkRolloverContract, CorkRolloverContractFactory, ExactSettler, and
PartialSettler retain a version() return value of 1.0.0. The mismatch
with 0.2.0 is intentional for this preparation and departs from the release
policy's source/getter equality requirement; it is not dual-namespace compliance.
The getter alone cannot distinguish this distribution from earlier source.
Identify an installation by its exact source commit and verified deployment
runtime-code hash. The EIP-712 signing domain remains CorkSettler/1.0.0.
Earlier on-chain addresses are not automatically 0.2.0 deployments. Use the explicit deployment records rather than inferring a version from an address or getter. Verification does not establish a security-review level, production authorization, or retirement of earlier deployments.
The deployment manifest records shadow
deployment observations from 2026-09-11 on Base and Arbitrum: 13 canonical
components plus BaseFiller, with deployed addresses, artifact ABIs, runtime-code
hashes, transaction receipts, and binding checks at the stated finalized blocks.
Its artifact evidence compares deployed ABIs and bytecode templates with the
candidate source. These observations are preserved, not refreshed by this revision.
source_release_version is 0.2.0; the embedded release manifest retains the
deployment campaign identifier 0.1.0-rc.2 without relabeling the deployment.
This file is not production or publication authorization.
The historical filename is retained, but consumers must dispatch on
schema_version: this is rollover-shadow-release-bundle-v2, validated by the
v2 structural schema.
V2 replaces original build commit/tree pointers with source_identity_digest.
The top-level source_identity lists SHA-256 hashes of 65 tracked production/build
files and four root dependency gitlinks; recursive pins are inherited from those
gitlinks. It excludes release prose and this manifest to avoid self-reference.
JSON digests are SHA-256 of Python json.dumps(value, sort_keys=True, separators=(",", ":"), ensure_ascii=True).encode("utf-8"), prefixed sha256:.
File hashes cover exact bytes. Consumers must verify these hashes and all nested
digests in addition to the schema. The content identity does not claim an original
deployment commit or an already-published tag. Release and Distribution records
must bind the final public commit separately after it exists.
This source distribution uses public Market Registry 0.5.0. The Registry dependency and its recursive dependencies are pinned by the repository's submodules; use those pins rather than substituting an older Registry interface.
BaseFiller.JITMarketParamsincludesoracleSalt. Adding this tuple field changes theexecuteWithMarketandhashJITMarketParamsselectors. Rebuild calldata and bindings against this interface; do not reuse the older tuple.- The just-in-time (JIT) market commitment preimage includes
oracleSalt. Off-chain builders must include it when computingRolloverParams.jitMarketHash; usehashJITMarketParamsas the canonical commitment helper. Changing only calldata without rebuilding the committed hash is not sufficient. - Registry-backed recipe paths require registered assets. Recipe verification
receives the expiry timestamp and
creatingcontext, and runs for both new and existing pools. Integrations must provide the creation/expiry-aware recipe interface, not the earlier verification signature. - Controller market creation and PoolManager market-return tuples use the
ten-field, fee-bearing
Marketstructure, includingswapFeePercentageandunwindSwapFeePercentage. Both fees are immutable pool-identity inputs in 18-decimal percentage units (1e18 = 1%). Update encoders and decoders together.
See CHANGELOG.md for compatibility and support-status disclosures.
| Term | Meaning |
|---|---|
| cPT / cST | Cork Principal Token / Cork Swap Token — the dual shares a Phoenix pool mints 1:1 on deposit. Rollover orders move cST. |
| CA | Collateral asset of a Phoenix pool (e.g. USDC). unwindMint burns cPT+cST for CA; deposit mints them from CA. |
| cPT holder | Owner of a CorkRolloverContract clone; signs OrderData that commits the hook plan through OrderData.rolloverIntentHash. |
| Rollover contract | Per-cPT-holder CWIA clone that holds positions and executes the Phoenix unwind/deposit leg. Must be whitelisted on Phoenix. |
| Filler | Party that supplies source cST in the ROLLOVER fill and pays the premium in the PREMIUM fill. |
| Hook plan | Sequence of hook modules committed by the cPT-holder-signed OrderData.rolloverIntentHash, each attested in the ERC-7484 registry. |
| Latch | Transient (rolloverContract, orderDigest, settler) record the factory holds during a fill frame. |
| Residual | Destination cST measured after the rollover leg, held until the premium fires or it is reclaimed. |
Full terminology: protocol glossary.
sequenceDiagram
participant User
participant Filler
participant Settler
participant Factory as CorkRolloverContractFactory
participant Rollover as CorkRolloverContract
participant Phoenix as Phoenix PoolManager
User->>Settler: open / openFor (signed ERC-7683 order)
Filler->>Settler: fill(..., ROLLOVER) with srcCST
Settler->>Factory: executeIntentHooks (approved-settler gate, latch)
Factory->>Rollover: forward intent
Rollover->>Rollover: verify cPT-holder OrderData signature,<br/>check committed hooks vs ERC-7484 registry
Rollover->>Phoenix: unwindMint (source pool, burn cPT+cST → CA)
Rollover->>Phoenix: deposit (destination pool, CA → cPT+cST)
Rollover-->>Settler: measured dstCST residual
Filler->>Settler: fill(..., PREMIUM) — premium routed to rollover contract
Settler-->>Filler: release dstCST residual to the recorded destination
- A user signs an ERC-7683
GaslessCrossChainOrdercarryingOrderData(EIP-712 domainCorkSettler/1.0.0, ERC-1271 supported). - A relayer or filler calls
Settler.open/openFor, or a filler fills atomically without a prior open where the state path allows it. fill(..., ROLLOVER)pullssrcCSTfrom the filler, pushes it to the user's rollover contract, and dispatches throughCorkRolloverContractFactory.executeIntentHooks. The factory checks the caller against its default-deny settler allowlist and latches the in-flight(rolloverContract, orderDigest, settler)triple.- The rollover contract verifies the cPT holder's
OrderDatasignature for the dispatch, checks the committedRolloverIntenthook targets against the ERC-7484 registry by hook bucket, unwinds the source Phoenix pool, optionally runs mid-rollover hooks, deposits into the destination pool, and returns measureddstCSTto the settler. fill(..., PREMIUM)collects the filler's premium, records the premium-fired latch, and releases the recorded dstCST residual in-frame.markExpired,cancel, and async-onlyreclaimfinalize stopped orders or route unpaid residuals.
Order status is one of None, Opened, Settled, Expired, Cancelled,
Closing (src/types/RolloverTypes.sol). Settled, Expired, and
Cancelled are hard terminals. The gates in src/types/SettlerTypes.sol
define what each action admits: cancel is blocked from the terminals and
from Closing; markExpired admits Opened and Closing after the fill
deadline; reclaim is blocked only from Settled and Cancelled. The
exact settler keeps one order-level fill record; the partial settler keeps
per-filler records, premium latches, and residuals, so multiple fillers can
each roll a portion and settle independently.
fillerData is a canonical 11-field payload with premiumFor after destination. In
ROLLOVER, premiumFor must be zero and the record is keyed by msg.sender.
In PREMIUM, premiumFor is mandatory and must identify the recorded rollover
filler being paid for. The payer supplies premium tokens but never controls
the settlement destination: settlement always uses the destination recorded
during ROLLOVER, and PREMIUM payloads that try to change it revert. No legacy
fillerData shape is accepted.
| Contract | Role |
|---|---|
BaseSettler |
Shared ERC-7683 lifecycle, admission, signatures, token movement, premium accounting, cancellation, expiry and reclaim. |
ExactSettler |
One order-level fill record and residual. |
PartialSettler |
Per-filler records, premium latches and residuals. |
CorkRolloverContractFactory |
Per-cPT-holder clones, default-deny settler allowlist, transient dispatch latch and role-gated trust configuration. |
CorkRolloverContract |
Signed hook-plan execution, Phoenix unwind/deposit and timelocked trust changes. |
BaseFiller |
Atomic filler orchestration, optional destination-market creation and premium-cap refunds. |
EvcRolloverAdapter |
Euler Vault Connector (EVC) adapter with Permit2 funding; documented separately as adapter context. |
src/modules/ |
Stateless delegatecall modules for committed hook plans. |
Phoenix and the ERC-7484 attestation registry are trusted external dependencies.
Rollover contracts must be whitelisted on Phoenix to call unwindMint/deposit.
Hook targets must be attested for their committed module-type buckets. Market
Registry recipe approval and asset registration are separate integration requirements
from ERC-7484 hook attestation.
Requirements: Foundry (the consumer CI workflow pins v1.7.1), Solidity
0.8.34, Python 3.12 for consistency checks, and recursive git submodules.
Only after the public v0.2.0 tag and release are published, a pinned
Foundry dependency installation will be:
forge install Cork-Technology/rollover@v0.2.0That example is conditional, not a claim that the tag is available now. For an already obtained checkout of this candidate, initialize its pinned dependencies and build/test locally:
git submodule update --init --recursive
forge build
forge testThe repository uses Cancun transient storage. Build-profile settings are in
foundry.toml; use the deploy profile for production-bytecode size checks,
not the default test profile:
FOUNDRY_PROFILE=deploy forge build --sizes srcThese commands describe how to validate the checkout; they are not a statement that this candidate has passed those checks or that its bytecode is deployed.
FOUNDRY_PROFILE=ci forge test --match-path "test/unit/**/*.t.sol" -vvv
FOUNDRY_PROFILE=ci forge test --match-path "test/integration/**/*.t.sol" -vvv
FOUNDRY_PROFILE=ci forge test --match-path "test/invariant/**/*.t.sol" -vvvThe retained consumer workflow covers formatting, compilation, contract size, unit/integration/invariant tests, NatSpec, static analysis and consistency checks. See the workflow for exact commands and tool pins. Static analysis and passing tests do not establish a security-review level.
The invariant ledger and both files under docs/agent-context/spec/ are consumer
test inputs, not disposable documentation. Keep them in source checkouts.
The citation checkers verify reference structure and line bounds; they do not
prove that prose is semantically equivalent to the cited code. Some inherited
source-line references have weak alignment with their named symbols; semantic
citation review remains outstanding for this unpublished candidate.
| Path | Contents |
|---|---|
src/ |
Production contracts, interfaces, libraries, modules and types. |
test/ |
Retained consumer tests, fixtures, harnesses and mocks. |
scripts/ci/ |
Consumer consistency checks. |
| docs/INVARIANTS.md | Canonical invariant IDs cross-referenced by NatSpec and tests. |
| docs/spec/SPEC.md | Protocol reference and reading order. |
| docs/spec/AUDIT-GLOSSARY.md | Technical terms and stable spec identifiers. |
| Design notes | Retained design reference and runtime-read fixture. |
| Threat-model fixture | Defensive assumptions and runtime-read fixture; not a completed review. |
| CHANGELOG.md | Draft version and compatibility record. |
Tracked Solidity sources carry SPDX identifiers, primarily BUSL-1.1; the
vendored narrow external interfaces IERC7484, IPoolManager, and
IPoolShare are MIT. No root license file is tracked.