Skip to content

[Release] FWSS v1.3.1 + SPR v1.2.0 Mainnet Upgrade (includes Calibnet) #561

Description

@github-actions

Overview

Field Value
Stack Version v1.3.1
Upgrade Type Routine
Release-prep / rollout-tooling PR(s) #562, #565, #567, #568
Technical Owner @Kubuxu
Go/No-Go Status Phase 3 Calibnet announcement verified; wait for observed afterEpoch 3961387 before SPR/FWSS execution. Synapse and Curio remain Mainnet gates

Release Tracking

The filecoin-services GitHub release version is the stack version. It may differ from an individual contract VERSION() when the stack changes without an FWSS code change.

Item Value
Frozen deploy commit Contract source: v1.3.1 / aea9357. Exact deployed rollout ref: v1.3.1-rollout.1 / c1ae9e5. Only the deploy-all tooling differs.
GitHub pre-release v1.3.1 — FWSS + ServiceProviderRegistry Upgrade
Public status notice Calibration network FWSS v1.3.1 contract upgrade — scheduled for 2026-08-08 after epoch 3961387
Release status Pre-release; Calibnet SPR/FWSS announcement verified; implementation and StateView switches pending; Mainnet unannounced
deployments.json PR(s) Scope policy #568; live-address follow-up PR(s) pending Phase 2
Synapse SDK PR Not created: workflow run 30998238414 failed because Synapse's strict deployment schema rejects the new contracts metadata key. @rjan90 owns the schema fix and rerun; required before Mainnet unless explicitly waived. Details

Field ownership for duplicated rollout data:

Data Source of truth Mirror/update
Operator status, owner decisions, exceptions, and in-progress tx/check evidence This release issue: Release Tracking and Run Log Mirror externally useful rollout status to the GitHub Release page
Live contract state Chain state read from the FWSS proxy, implementation slot, and View contract Record observed values in the Run Log and use them for go/no-go
Consumer-facing release status, addresses, epochs, and tx links GitHub Release page Populate from the Run Log as rollout facts become final
Repo deployment snapshot service_contracts/deployments.json on main Update by follow-up PR(s) only after the relevant proxy and View switches are live

Component Versions

Component Version Changed? Notes
Stack (filecoin-services) v1.3.1 Yes Git tag / GitHub Release
FilecoinWarmStorageService 1.3.1 Yes Upgrade existing FWSS proxies; current live version is 1.3.0
ServiceProviderRegistry 1.2.0 Yes Explicit companion exception; upgrade existing SPR proxies, current live version is 1.1.0
PDPVerifier Unchanged on-chain No The stack contains a newer PDP submodule ref, but deploying/upgrading PDP is outside this rollout

Upgrade Schedule

Network Announcement mode (v1.3.1 bootstrap only) Requested delay Actual AFTER_EPOCH Status
Calibnet legacy 2880 notice + 2000 signing buffer (4880 total) 3961387 Announced at epoch 3956643; execute after observed epoch
Mainnet TBD TBD TBD Pending

Set the requested delay before proposing the Safe transaction. For the normal delay-based flow, fill in the actual AFTER_EPOCH from nextUpgrade() after the announcement executes. The observed value is the source of truth for the execute step and external communications.

v1.3.1 bootstrap only: The announcement-mode column is temporary. Record legacy for the v1.3.0 -> v1.3.1 rollout; upgrades from v1.3.1 onward use delay. Record the absolute target before Safe signing, include the notice duration and signing buffer in the requested-delay cell, and verify the same target on-chain after execution.

Run Log

The Run Log is this release issue's operator journal for rollout facts discovered during execution: deployed addresses, transaction links, validation outputs, exceptions, and owner decisions.

Keep this table current as values become known.

Network New FWSS implementation StateView / setView tx Announce tx Actual afterEpoch Execute tx Post-upgrade checks
Calibnet 0x51Bc9fB1e20280D57460a0a69a7077a9682AA164 Candidate 0x9BF9e67e83EC8613883FDdDec4D3b38AEE937177; switch pending announce 3961387 TBD Plan verified; active VERSION()=1.3.0 and View unchanged while waiting
Mainnet 0x3583e9fc40243924C6f8eBE3d17e5364Bb6A01a9 Candidate 0xdDd8F083a3fe9C66547D46bee24e5AaF56BCa0ab; switch pending TBD TBD TBD Candidate verified; active state unchanged

Scope

  • In scope: FilecoinWarmStorageService implementation upgrade behind the existing FWSS proxy.
  • Out of scope by default: FilecoinWarmStorageServiceStateView, ServiceProviderRegistry, PDPVerifier, FilecoinPay, and SessionKeyRegistry.
  • If this release needs an out-of-scope change, add a clearly labeled exception section to this issue before starting that work.

Exception — ServiceProviderRegistry v1.2.0 companion rollout

This release explicitly includes a ServiceProviderRegistry implementation upgrade so future upgrades can use announceUpgradePlan(address,uint96). Existing SPR proxy addresses and registry state must be preserved; no replacement proxy is allowed.

Network Existing SPR proxy Current implementation Current state verified 2026-07-31
Calibnet 0x839e5c9988e4e9977d40708d0094103c0839Ac9D 0x0A2E79efFC7DB1D15912E4F6722F527F493F18Ef VERSION()=1.1.0; initializer 2; nextUpgrade=(0x0,0); Safe owner matches Network Constants
Mainnet 0xf55dDbf63F1b55c3F1D4FA7e339a68AB7b64A5eB 0x01293CaFdE24DE89fF26d1A19Bfc4E36CBF74F9B VERSION()=1.1.0; initializer 2; nextUpgrade=(0x0,0); Safe owner matches Network Constants

SPR-specific release gates:

  • Target VERSION(): 1.2.0; deployment constructor reinitializer: 3, derived and cross-checked from live counter 2 + 1.
  • Deploy through the Deploy Contract workflow with contract=Warm Storage stack: run the metadata-aware dry-run first, approve the complete inventory, then use the live stack run to obtain and record the actual implementation address. The dry-run records deployment decisions and counters; it does not predict a real CREATE address.
  • Approved-scope v1.3.1 stack inventory encoded at candidate aea9357: deploy the ServiceProviderRegistry implementation, Rails, the FilecoinWarmStorageService implementation, and a new StateView; preserve every proxy plus FilecoinPay, PDPVerifier, and unchanged dependency addresses. FilecoinPay and PDPVerifier remain pinned. StateView is intentionally unpinned and requires a separate Safe setViewContract action after the FWSS implementation switch. Technical-owner final inventory approval remains pending.
  • Bootstrap with the legacy absolute-epoch announcePlannedUpgrade call because v1.1.0 does not expose the relative-delay entrypoint. Include a Safe-signing buffer, then verify the exact pending implementation and epoch on-chain.
  • Execute only the announced implementation at/after the observed epoch with upgradeToAndCall(..., migrate("1.2.0")). Verify implementation slot, version, owner, initializer 3, registry state, and cleared plan.
  • On each network, deploy both FWSS and SPR implementations before either announcement. Rehearse and complete Calibnet first. Use a recorded deterministic execution order (proposed: SPR, then FWSS), validate both, then obtain a separate Mainnet go/no-go.
  • Rollback is approved by the technical owner. Before live announce, record the exact no-migration rollback transaction and targeted fork-rehearsal evidence. Rolling SPR back to the v1.1.0 implementation cannot replay reinitializer 2 after the proxy counter reaches 3; a subsequent roll-forward must also use empty calldata because reinitializer 3 has already been consumed.

SPR Run Log

Network New SPR implementation Deploy / verification evidence Announce tx Actual afterEpoch Execute tx Post-upgrade checks
Calibnet 0x0dF90c9a20b3f1E383c7196C06943565396c0956 deploy / source announce 3961387 TBD Plan verified; active VERSION()=1.1.0 while waiting
Mainnet 0x1Bb676392272313598930FEf8D5B66FFECcE02F0 deploy / source TBD TBD TBD Candidate verified; active state unchanged

Exception — FilecoinWarmStorageServiceStateView companion rollout

This release includes a new immutable StateView on both networks so clients can use the reactivation behavior introduced by FWSS v1.3.1. The upgraded FWSS preserves the original proving activation epoch and enforces the canonical reactivation window. The candidate StateView calculates that same window, while the currently deployed v1.3.0 View reverts with ProvingPeriodNotInitialized when no proving deadline is active.

StateView-specific release gates:

  • Merged scope PR #568 unpins only FWSS_VIEW for Calibnet and Mainnet. FilecoinPay and PDPVerifier remain pinned and preserved. Final release-ref evidence: Calibnet run 30996922868 and Mainnet run 30996922569, both passed from aea9357.
  • Deploy one new StateView per network through the same approved contract=Warm Storage stack run; do not use a separate deployment path.
  • Preserve the existing FWSS proxies. Each new View must be constructed with the existing network's FWSS proxy address.
  • Record and verify each new View address before proposing a Safe action.
  • Execute setViewContract(newView) only after the FWSS v1.3.1 implementation is live and its immediate post-upgrade reads pass. Verify viewContractAddress() and reactivation-window reads afterward.
  • If rollback is required after the View switch, first set the FWSS proxy back to the previous View address, verify it, then perform the FWSS implementation rollback.
  • Release-operator scope decision recorded 2026-08-05. The final inventory is accepted for Phase 2 candidate deployment under the operator exception; technical-owner review remains mandatory before any announce, implementation switch, or setViewContract Safe action.

Cross-Repo Impact

Each pre-seeded row now has an explicit disposition, tracker, and later gate. Completing this section allows the rollout to proceed; it does not complete the Synapse build, Curio Mainnet decision, post-Calibnet filecoin-pin validation, or post-rollout address sync. Audit evidence: Phase 1 read-only audit and cross-repo disposition.

Repository Required change, PR, issue, or release Required before Mainnet? Owner/Status
FilOzone/synapse-sdk Generate the ABI/type sync PR with the Update Synapse SDK workflow against the frozen/tagged ref and require a successful integration build. Review the generated PDPVerifier ABI against live v3.4.0 and explicitly accept or pin/filter the ahead-of-live administrative entrypoint before merge. #845 is not required for this rollout. Generated PR/build: yes before Mainnet. #845 preview mechanism: no. @rjan90 owns the schema fix and workflow rerun after run 30998238414 failed; candidate deployment may proceed under the operator exception
FilOzone/pdp None: no PDP deployment or new release. Compatibility with live PDPVerifier 3.4.0 is confirmed for this rollout. No PDP PR/release Compatibility confirmed 2026-08-05
filecoin-project/curio #1353 remains post-upgrade/version-gated cleanup. Clarification for #1356 was requested in Slack. Does not block Phase 1, Phase 2, or Calibnet; record the answer or an explicit waiver before Mainnet announcement Issue assigned to @LexLuthr; @rjan90 tracking clarification
FilOzone/filecoin-cloud None before proxy switches; merge the automated address-sync PR after live deployment state is recorded No; post-rollout sync @rjan90 owns follow-up tracking
filecoin-project/filecoin-pin No code change or release required; successful post-Calibnet default-path filecoin-pin add remains a Mainnet gate. Open #615 may interfere operationally. Validation yes; release no Release operator owns validation; @beck-8 owns #615 investigation if needed
Other / none None: no other event-shape, ABI, linked-library, or proxy-address consumer change is required to enter later phases No Non-blocking disposition recorded 2026-08-05

Dependency Targets and Compatibility

Record the intended deployed dependency versions or addresses, then verify actual deployed state against those targets before go/no-go. Reads below were pinned at Calibnet block 3,939,384 and Mainnet block 6,240,050; details are in the Phase 1 audit.

Dependency Target version/address Calibnet observed Mainnet observed Verification/status
PDPVerifier No PDP deployment; preserve proxy and live VERSION()=3.4.0 Proxy 0x85e366Cf9DD2c0aE37E963d9556F5f4718d6417C; impl 0xd60b90f6D3C42B26a246E141ec701a20Dde2fA61; 3.4.0 Proxy 0xBADd0B92C1c71d02E7d520f64c0876538fa2557F; impl 0xb41A97FEDD2D9497C639A643ec75E56CbCeDe8BA; 3.4.0 Preserve decision accepted for Phase 2; remains pinned. Matches FWSS getters and deployment inventory. Compatibility with live v3.4.0 is confirmed; review the generated Synapse PDPVerifier ABI before merging the SDK sync PR. Technical-owner review is deferred to the pre-announce gate
FilecoinPay Preserve deployed v1.0.0 addresses; source v1.0.0 at f0a40fe 0x09a0fDc2723fAd1A7b8e3e00eE5DF73841df55a0 0x23b1e018F08BB982348b15a86ee926eEBf7F4DAa Preserve decision accepted for Phase 2; remains pinned. Matches FWSS getters and has identical live runtime hash on both networks. Technical-owner review is deferred to the pre-announce gate
ServiceProviderRegistry Preserve proxies; target implementation 1.2.0 Proxy 0x839e5c9988e4e9977d40708d0094103c0839Ac9D; current impl 0x0A2E79efFC7DB1D15912E4F6722F527F493F18Ef; 1.1.0, counter 2 Proxy 0xf55dDbf63F1b55c3F1D4FA7e339a68AB7b64A5eB; current impl 0x01293CaFdE24DE89fF26d1A19Bfc4E36CBF74F9B; 1.1.0, counter 2 Current state and target accepted for Phase 2; target implementation addresses are deployment outputs. Technical-owner review is deferred to the pre-announce gate
SessionKeyRegistry Unchanged; ref 74fc4e94500859709a97b1c64981cfae52f9bdfe 0x518411c2062E119Aaf7A8B12A2eDf9a939347655 0x74FD50525A958aF5d484601E252271f9625231aB Matches FWSS getters; executable bytecode matches after metadata removal; accepted for Phase 2
FilecoinWarmStorageServiceStateView Deploy one candidate View per network and switch existing FWSS proxies with setViewContract Current View 0xF4B446171b3677fD2B9b183a9fB76d517365700a; new address is a Phase 2 output Current View 0xAD28BBF18A72f728Ed816D07F5a1d7Ec40D68b5e; new address is a Phase 2 output Expanded scope accepted for Phase 2 and confirmed by both tagged release plans. Record and verify new addresses, then switch only after FWSS v1.3.1 is live and the pre-announce/Safe review gate is satisfied. Final inventory
USDFC Unchanged 0xb3042734b608a1B16e9e86B374A3f3e389B4cDf0 0x80B98d3aa09ffff255c3ba4A241111Ff1262F045 Matches FWSS getters; accepted for Phase 2
FilBeam beneficiary Unchanged 0x1D60d2F5960Af6341e842C539985FA297E10d6eA Match Match Accepted for Phase 2

Rollback Plan

State whether rollback is safe before any live announce transaction. Link the approved rollback procedure or script when available.

Field Value
Rollback status Accepted for Phase 2 — rollback uses an announced empty-calldata UUPS rollback. The release operator waived a separate targeted fork rehearsal as a candidate-deployment prerequisite; technical-owner review remains mandatory before announce/switch transactions
Previous FWSS implementation Calibnet 0x9e4e6699d8F67dFc883d6b0A7344Bd56F7E80B46 (1.3.0, counter 8); Mainnet 0xaF996097790c17D3C23Cc45A3035a29D293d1492 (1.3.0, counter 4)
Previous SPR implementation Calibnet 0x0A2E79efFC7DB1D15912E4F6722F527F493F18Ef (1.1.0, counter 2); Mainnet 0x01293CaFdE24DE89fF26d1A19Bfc4E36CBF74F9B (1.1.0, counter 2)
Rollback procedure/script If StateView was switched, first call setViewContract(previousView) and verify it. Announce the previous implementation, wait for the observed epoch, then call upgradeToAndCall(previousImplementation, 0x) with value 0. Reverse rollback order: StateView, FWSS, then SPR. Never call an old migration. Current execute helpers are not rollback helpers. See audit mechanics
Decision notes Operator acceptance and deferred technical-owner gate are recorded here. Forward counters become FWSS Calibnet 9, FWSS Mainnet 5, and SPR 3. A subsequent roll-forward uses empty calldata because the new reinitializers have already been consumed.

Pre-Live Validation

Record validation that proves the planned upgrade works against the full contract, Curio, and Synapse state before live rollout.

Validation Evidence/status
foc-devnet post-upgrade state validation Run 30802517410 passed 6/6 fresh-deployment scenarios against source-equivalent candidate 4d8f21a. It does not simulate upgrading proxies with existing state. The release operator explicitly accepts this evidence and waives the missing two-stage scenario as a Phase 2 candidate-deployment prerequisite; technical-owner review is deferred to the pre-announce gate. Exception
Pricing validation Release branch: forge test --offline --match-contract PriceListTest127 passed, 0 failed. Recorded evidence
Synapse SDK integration build Run 30998238414 failed before PR creation because Synapse's strict deployment schema rejects the new contracts metadata key. @rjan90 owns the schema fix and rerun. This is not a Phase 2/Calibnet blocker under the operator exception, but remains required or explicitly waived before Mainnet announcement. Details

Network Constants

Network Chain ID RPC URL FWSS Proxy Safe Owner
Calibnet 314159 https://api.calibration.node.glif.io/rpc/v1 0x02925630df557F957f70E112bA06e50965417CA0 0x6386622B4915B027900d65560b0ab84F8a1ff2AA
Mainnet 314 https://api.node.glif.io/rpc/v1 0x8408502033C418E1bbC97cE9ac48E5528F371A9f 0x6386622B4915B027900d65560b0ab84F8a1ff2AA

Operating Rules

  • Use the release issue as the rollout source of truth. Keep the schedule, Run Log, tx links, and post-upgrade evidence current.
  • Create the stack tag and GitHub Release before any live proxy switch. Mark the GitHub Release as a pre-release until Mainnet is complete and verified.
  • Keep the GitHub pre-release page updated as the external rollout tracker for consumers; keep this issue updated as the operator runbook.
  • Keep CHANGELOG focused on what changed. Put mutable deployment status, addresses, epochs, and transaction links on the GitHub Release page.
  • Tag semantics: The vX.Y.Z tag is immutable and points to the frozen deploy commit used for contract deployment and bytecode verification. Post-deploy rollout facts such as live addresses, epochs, tx links, and deployments.json follow-up PRs are not folded back into the tag. They live on main, the release issue Run Log, and the GitHub Release page. Do not create a second "final release" tag.
  • Where to find what: Use the vX.Y.Z tag for the source that produced the deployed bytecode. Use on-chain reads from the FWSS proxy for live state, including the implementation slot and address getters such as viewContractAddress(), pdpVerifierAddress(), paymentsContractAddress(), serviceProviderRegistry(), sessionKeyRegistry(), usdfcTokenAddress(), and filBeamBeneficiaryAddress(). Use the GitHub Release rollout table for the historical record of what was live for this release.
  • service_contracts/deployments.json on a release branch or vX.Y.Z tag is the copy that existed at branch-cut/tag time and may be stale after Calibnet/Mainnet proxy or View switches. Do not use it as live state. Update deployments.json on main through the follow-up PR flow, but treat chain state and linked execute transactions as the live verification source.
  • The technical owner owns the written upgrade plan, dependency target verification, and final go/no-go decision.
  • Before any live announce transaction, fill in the Technical Owner, Cross-Repo Impact, Dependency Targets and Compatibility, Rollback Plan, and foc-devnet validation status.
  • Generate owner-action calldata with CALLDATA_ONLY=true and submit it through Safe Transaction Builder.
  • In Safe Transaction Builder, use the script output exactly: target is the printed FWSS proxy, value is 0, and data is the printed calldata.
  • Do not announce Mainnet until Calibnet execution, on-chain checks, explorer checks, smoke/E2E checks, and filecoin-pin Data Set creation validation are complete.
  • Do not announce Mainnet until required cross-repo changes are merged/released or explicitly waived by the technical owner.
  • service_contracts/deployments.json reflects what is live behind proxies and View contracts. Update it only after the relevant proxy switch and, if applicable, View switch are complete, normally through follow-up PR(s) to main, and record PR links in Release Tracking.
  • In the normal delay-based flow, the requested delay starts when the Safe announcement executes. After execution, verify both fields returned by nextUpgrade() and record its exact afterEpoch as the source of truth.
  • A later announcement replaces the pending plan. Record the replacement transaction and explicitly mark it as superseding the previous announcement.

Notice Guidance

Upgrade Type Minimum Notice Recommended
Routine 2880 epochs (~24h) 1-2 days
Breaking change 20160 epochs (~1 week) 1-2 weeks

Calibnet can use a shorter window for rehearsal and validation, but use enough time for signers to coordinate. Select a positive operational delay; the contract's one-epoch floor is an emergency safety bound, not the routine notice policy.

export UPGRADE_DELAY_EPOCHS=2880 # use 240+ for Calibnet rehearsal, 20160 for breaking changes
export ANNOUNCEMENT_MODE=delay
echo "Requested upgrade delay: $UPGRADE_DELAY_EPOCHS epochs"

Temporary Bootstrap Compatibility

FWSS v1.3.0 is currently deployed on Calibnet and Mainnet and does not expose announceUpgradePlan(address,uint96). The v1.3.0 -> v1.3.1 rollout must announce through announcePlannedUpgrade((address,uint96)). Use ANNOUNCEMENT_MODE=legacy with an absolute AFTER_EPOCH for both networks and include a conservative Safe-signing buffer so the proposal is still in the future when it executes.

export ANNOUNCEMENT_MODE=legacy
export LEGACY_NOTICE_EPOCHS=2880
export SAFE_SIGNING_BUFFER_EPOCHS=240
CURRENT_EPOCH=$(cast block-number --rpc-url "$ETH_RPC_URL")
export AFTER_EPOCH=$((CURRENT_EPOCH + SAFE_SIGNING_BUFFER_EPOCHS + LEGACY_NOTICE_EPOCHS))
unset UPGRADE_DELAY_EPOCHS
echo "Legacy target epoch: $AFTER_EPOCH"

This is a v1.3.1 bootstrap exception, not a second long-term workflow. Treat legacy mode as deprecated once v1.3.1 is live on both networks, then use the Phase 5 cleanup item to remove it when rollback to v1.3.0 is retired.

Post-Upgrade Evidence Required

For each network, record evidence that:

  • FWSS proxy implementation slot equals the new implementation address.
  • VERSION() returns the expected FWSS contract version without the leading v.
  • nextUpgrade() is cleared.
  • Blockscout shows the proxy and transaction as expected.
  • A smoke/E2E test passes. The v1.2.0 rollout used the Synapse SDK storage E2E example.
  • A filecoin-pin add flow succeeds after the upgrade with unique Data Set metadata, forcing creation of a new Data Set on the target network. Record the command output, metadata, Data Set ID, tx/link, SP, and timestamp in the Run Log.

Changes

  • Upgrade FWSS from 1.3.0 to 1.3.1 with the fixes and metadata additions tracked by FWSS M4.5 GA Fast Follow Contract Upgrade #549.
  • Upgrade ServiceProviderRegistry from 1.1.0 to 1.2.0 as the documented companion exception.
  • Preserve all existing proxy addresses and deployed state.
  • Keep the release-prep PR limited to combined release notes, FWSS/SPR version bumps, and existing version assertion updates. Surface and track operational tooling gaps when their checklist phase is reached.

Action Required for Integrators

  • No proxy-address migration is expected.
  • Consumers should move future upgrade automation from the deprecated absolute-epoch announcement method to announceUpgradePlan(address,uint96) after v1.3.1/v1.2.0 are live.
  • Operators must continue using legacy announcement mode for this one bootstrap rollout. Phase 2 candidate deployments may proceed under the recorded operator exception; no announce, implementation switch, or setViewContract Safe action may proceed until Kubuxu completes the deferred technical-owner review.

Process deviation — issue created early for checklist-driven discovery

Issue #561 was intentionally created before the release-prep PR and release branch so this rollout could expose checklist gaps. The release branch release-v1.3.1 was originally cut from main at 4d8f21a after PR #562 merged, fast-forwarded to 42238fe after deployment-tooling PR #565, refreshed to 7f7037f after pinned-drift reporting PR #567, then refreshed to candidate aea9357 after StateView scope PR #568. The reusable checklist changed during this sequence, so this rendered issue was reconciled manually rather than creating a duplicate. The issue-creation checklist item remains removed from this release instance.


Release Checklist

Work through the phases in order. Do not announce Mainnet until the Calibnet execute transaction, on-chain checks, smoke/E2E test, and filecoin-pin Data Set creation validation are complete.

Phase 1: Branch, Issue, PR, and Checks

cd service_contracts
forge test --match-contract FilecoinWarmStorageServiceUpgradeTest
forge inspect src/FilecoinWarmStorageService.sol:FilecoinWarmStorageService storageLayout --extra-output storageLayout
  • Release-prep PR(s) merged so main contains the final release notes and applicable version/submodule changes before creating the release branch
  • Create release branch from main after the release-prep PR(s) land: release-v1.3.1. Refreshed by fast-forward to candidate aea9357 after chore: include StateView in v1.3.1 rollout #568 merged.
  • Name the technical owner, update the Overview, and confirm they own the written upgrade plan and go/no-go decision — @Kubuxu
  • From candidate aea9357, run the Deploy Contract workflow once for Calibnet and once for Mainnet with contract=Warm Storage stack and dry_run=true. Recorded evidence: Calibnet run 30996922868 and Mainnet run 30996922569.
  • Review and accept the complete two-network deployment inventory for Phase 2 entry. Final aea9357 plans preserve FilecoinPay and PDPVerifier and deploy ServiceProviderRegistry implementation, Rails, FilecoinWarmStorageService implementation, and StateView. Technical-owner review is deferred to the mandatory pre-announce/Safe gate. Operator exception.
  • Confirm neither release-ref plan contains an unexpected deployment. Both aea9357 plans exactly match the intended four-component deploy set and preserve dispositions. Recorded final inventory.
  • Fill Cross-Repo Impact with required PRs, issues, releases, or None — dispositions recorded above; Curio/Synapse/filecoin-pin/cloud work remains at its named later gate
  • Fill Dependency Targets and Compatibility by comparing target versions/addresses with observed Calibnet and Mainnet deployed state — accepted for Phase 2 under the operator exception; technical-owner review remains a pre-announce gate
  • Fill Rollback Plan, including whether rollback is safe and the approved procedure/script link when available — empty-calldata rollback procedure accepted; separate rehearsal waived as a Phase 2 entry prerequisite
  • Run foc-devnet post-upgrade state validation, or record an approved exception — source-equivalent 6/6 fresh-deployment evidence accepted and missing two-stage scenario waived for Phase 2 entry
  • Freeze the deploy commit and record it in Release Tracking — source tag v1.3.1 / aea9357; exact rollout tag v1.3.1-rollout.1 / c1ae9e5
  • Create and push the stack tag from the frozen deploy commit before any live proxy switch:
git tag v1.3.1
git push origin v1.3.1
  • Create the GitHub Release from v1.3.1, mark it as a pre-release, and include component versions plus a FWSS rollout status table:
GitHub Release creation commands
export RELEASE_ISSUE_URL="TBD" # replace with the generated release issue URL

cat > /tmp/fwss-release-notes.md <<'EOF'
> Status: Pre-release. Calibnet and Mainnet rollout pending; tracked in [the release issue](RELEASE_ISSUE_URL).

## Summary
- TBD

## Component Versions

| Component | Version | Notes |
|---|---|---|
| Stack (`filecoin-services`) | `v1.3.1` | Git tag / GitHub Release |
| `FilecoinWarmStorageService` | `1.3.1` | Contract `VERSION()` returned by the FWSS proxy |
| `PDPVerifier` | `TBD` | Link PDP release if this stack consumes a new PDP version |

## Rollout Status

| Network | FWSS Proxy | FWSS Implementation | StateView | Announce tx | Actual `afterEpoch` | Execute tx | Status |
|---|---|---|---|---|---:|---|---|
| Calibnet | `0x02925630df557F957f70E112bA06e50965417CA0` | `TBD` | `TBD` | `TBD` | `TBD` | `TBD` | Pending |
| Mainnet | `0x8408502033C418E1bbC97cE9ac48E5528F371A9f` | `TBD` | `TBD` | `TBD` | `TBD` | `TBD` | Pending |

## Action Required For Integrators
- TBD
EOF

perl -0pi -e 's|RELEASE_ISSUE_URL|$ENV{RELEASE_ISSUE_URL}|g' /tmp/fwss-release-notes.md

gh release create v1.3.1 \
  --verify-tag \
  --prerelease \
  --title "FWSS v1.3.1" \
  --notes-file /tmp/fwss-release-notes.md
  • Confirm the Update Synapse SDK workflow opened or updated the expected Synapse SDK PR and that its integration build passes against the intended contract ABI/types and deployment-address state, or record an exception/owner in Release Tracking. Failure and owner recorded; fix/rerun remains a Mainnet gate. Run the workflow again in Phase 5 after final deployment-address state exists.
  • Release issue Overview and Release Tracking updated with PR links, release link, summary, and action required

Phase 2: Deploy Contracts

Deploy both networks before any announce/execute.

Completed from v1.3.1-rollout.1: Calibnet evidence, Mainnet evidence, and source-verification matrix. No announce or switch has occurred.

  • Immediately before each live deployment, rerun the metadata-aware dry-run from the frozen v1.3.1 tag for that network and confirm it exactly matches the Phase 1 approved inventory. Stop and return to scope review if it differs; do not broadcast or change pins ad hoc.
  • Run the Deploy Contract workflow once per network from the same frozen tag with contract=Warm Storage stack and dry_run=false. The metadata-aware stack run deploys every approved changed, unpinned component in nonce order; do not select components manually or run separate FWSS/SPR deployment paths.
  • Run service_contracts/tools/verify-deployments.sh --chain <CHAIN> for each target network after deployment metadata is available. Resolve or explicitly waive any bytecode/metadata mismatch before live announce.
  • If linked libraries or StateView are deployed, record their actual addresses and verification status in the Run Log and carry out the ABI-publishing decision approved in Phase 1.
Deployment metadata checks
cd service_contracts

ETH_RPC_URL="https://api.calibration.node.glif.io/rpc/v1" \
  ./tools/verify-deployments.sh --chain 314159

ETH_RPC_URL="https://api.node.glif.io/rpc/v1" \
  ./tools/verify-deployments.sh --chain 314

Use the deploy dry-run output to distinguish contracts that are Pinned/preserved, Up to date, or Would deploy. Record the final deploy set before any live announce transaction.

Dry-run marks as needing deployment Operator action
SignatureVerificationLib, Rails, or FilecoinWarmStorageService The approved contract=Warm Storage stack live run deploys each changed, unpinned component automatically and records its address
ServiceProviderRegistry Only unpin in the reviewed release-prep PR when the release explicitly includes it; add an exception section to this issue, then let the approved contract=Warm Storage stack run deploy it
PDPVerifier, FilecoinPay, ProviderIdSet, or FilecoinWarmStorageServiceStateView Keep pinned in the reviewed release ref unless the release explicitly includes it and the technical owner approves the expanded scope before the live stack run
SessionKeyRegistry Only deploy if explicitly included; use the dedicated contract=SessionKeyRegistry workflow option and add an exception section to this issue

Calibnet Warm Storage Stack

  • Re-run the Deploy Contract workflow from frozen tag v1.3.1 with network=Calibnet, contract=Warm Storage stack, dry_run=true
  • Confirm the inventory exactly matches the Phase 1 approved Calibnet plan; stop and return to scope review if it differs before broadcasting
  • Re-run with dry_run=false
  • Capture CALI_NEW_IMPL, plus CALI_NEW_SPR_IMPL, new library addresses, and CALI_NEW_VIEW when those components are in the approved inventory, and add them to the Run Log
  • Verify every newly deployed contract on Sourcify and Blockscout
  • Attempt FilFox verification and record result

Mainnet Warm Storage Stack

  • Re-run the Deploy Contract workflow from frozen tag v1.3.1 with network=Mainnet, contract=Warm Storage stack, dry_run=true
  • Confirm the inventory exactly matches the Phase 1 approved Mainnet plan; stop and return to scope review if it differs before broadcasting
  • Re-run with dry_run=false
  • Capture MAIN_NEW_IMPL, plus MAIN_NEW_SPR_IMPL, new library addresses, and MAIN_NEW_VIEW when those components are in the approved inventory, and add them to the Run Log
  • Verify every newly deployed contract on Sourcify and Blockscout
  • Attempt FilFox verification and record result
  • Add both FWSS implementation addresses and every companion SPR, library, or StateView candidate address to the GitHub pre-release rollout status. Do not update service_contracts/deployments.json until proxy slots are live.

Verification command pattern:

cd service_contracts

# Calibnet: use CALI_NEW_* values; Mainnet: use MAIN_NEW_* values.
export CHAIN=314159
export FWSS_IMPL="$CALI_NEW_IMPL"
export SPR_IMPL="${CALI_NEW_SPR_IMPL:-}"
export RAILS_IMPL="${CALI_NEW_RAILS:-}"

source tools/verify-contracts.sh

verify_candidate() {
  local address="$1"
  local artifact="$2"
  [ -z "$address" ] && return 0
  verify_sourcify "$address" "$artifact"
  verify_blockscout "$address" "$artifact"
  verify_filfox "$address" "$artifact"
}

verify_candidate "$FWSS_IMPL" "src/FilecoinWarmStorageService.sol:FilecoinWarmStorageService"
verify_candidate "$SPR_IMPL" "src/ServiceProviderRegistry.sol:ServiceProviderRegistry"
verify_candidate "$RAILS_IMPL" "src/lib/Rails.sol:Rails"

Repeat for every address in the approved live inventory, including a new StateView or other library when present. Supply explorer-specific constructor/library arguments when required, and record any verification failure or waiver in the Run Log.

Optional StateView Switch

  • If the stack deploy inventory includes a new FilecoinWarmStorageServiceStateView, confirm it was deployed by the approved live stack run; do not run a second StateView deployment
  • Capture CALI_NEW_VIEW and/or MAIN_NEW_VIEW, record the deployed StateView address and verification status in the Run Log, and add the StateView address to the GitHub pre-release rollout table
  • Generate setViewContract(address) calldata for each affected network and stage it in Safe UI. Execute the staged setViewContract transaction after the corresponding FWSS proxy upgrade execute transaction unless the technical owner approves a different ordering.
  • After each setViewContract transaction lands, record its tx link in the Run Log and verify viewContractAddress() equals the new StateView address
StateView setViewContract calldata and verification
# Calibnet
cd service_contracts/tools
export ETH_RPC_URL="https://api.calibration.node.glif.io/rpc/v1"
export FWSS_PROXY_ADDRESS="0x02925630df557F957f70E112bA06e50965417CA0"
export FWSS_VIEW_ADDRESS="$CALI_NEW_VIEW"

CALLDATA_ONLY=true ./warm-storage-set-view.sh

CURRENT_VIEW=$(cast call --rpc-url "$ETH_RPC_URL" \
  "$FWSS_PROXY_ADDRESS" \
  'viewContractAddress()(address)')
echo "viewContractAddress(): $CURRENT_VIEW (expected $FWSS_VIEW_ADDRESS)"

# Mainnet
export ETH_RPC_URL="https://api.node.glif.io/rpc/v1"
export FWSS_PROXY_ADDRESS="0x8408502033C418E1bbC97cE9ac48E5528F371A9f"
export FWSS_VIEW_ADDRESS="$MAIN_NEW_VIEW"

CALLDATA_ONLY=true ./warm-storage-set-view.sh

CURRENT_VIEW=$(cast call --rpc-url "$ETH_RPC_URL" \
  "$FWSS_PROXY_ADDRESS" \
  'viewContractAddress()(address)')
echo "viewContractAddress(): $CURRENT_VIEW (expected $FWSS_VIEW_ADDRESS)"

In Safe Transaction Builder, set target to the printed FWSS proxy, value to 0, and data to the printed calldata.

Phase 3: Calibnet Announce + Execute

Announce

  • If this release has a ServiceProviderRegistry exception, generate its Calibnet bootstrap announcement with NEW_SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS="$CALI_NEW_SPR_IMPL" AFTER_EPOCH=<absolute-epoch> CALLDATA_ONLY=true ./service-provider-registry-announce-upgrade.sh, execute it through the owner Safe, then verify and record the exact implementation and afterEpoch returned by nextUpgrade() before any execute transaction. This legacy absolute-epoch path is only for upgrading a registry that does not yet expose the relative-delay entrypoint.

  • Set the Calibnet requested delay and update the schedule table. v1.3.1 bootstrap only: record the announcement mode as legacy; upgrades from v1.3.1 onward always use delay.

  • Generate announce calldata and submit/sign/execute in Safe UI:

cd service_contracts/tools
export ETH_RPC_URL="https://api.calibration.node.glif.io/rpc/v1"
export FWSS_PROXY_ADDRESS="0x02925630df557F957f70E112bA06e50965417CA0"
export NEW_FWSS_IMPLEMENTATION_ADDRESS="$CALI_NEW_IMPL"

For the normal delay-based flow:

export UPGRADE_DELAY_EPOCHS=240 # use a longer window if desired
export ANNOUNCEMENT_MODE=delay
unset AFTER_EPOCH

For the v1.3.0 -> v1.3.1 bootstrap rollout only, use this configuration instead:

export ANNOUNCEMENT_MODE=legacy
export LEGACY_NOTICE_EPOCHS=240
export SAFE_SIGNING_BUFFER_EPOCHS=240
CURRENT_EPOCH=$(cast block-number --rpc-url "$ETH_RPC_URL")
export AFTER_EPOCH=$((CURRENT_EPOCH + SAFE_SIGNING_BUFFER_EPOCHS + LEGACY_NOTICE_EPOCHS))
unset UPGRADE_DELAY_EPOCHS

Generate the transaction after selecting exactly one configuration above:

CALLDATA_ONLY=true ./warm-storage-announce-upgrade.sh
  • In Safe Transaction Builder, set target to the printed FWSS proxy, value to 0, and data to the printed calldata
  • After the Safe transaction executes, verify and read back the pending plan:
export ANNOUNCE_TX_HASH="0x..." # Safe execution transaction hash

CURRENT_VIEW=$(cast call --rpc-url "$ETH_RPC_URL" \
  "$FWSS_PROXY_ADDRESS" \
  'viewContractAddress()(address)')

UPGRADE_PLAN=($(cast call --rpc-url "$ETH_RPC_URL" \
  "$CURRENT_VIEW" \
  'nextUpgrade()(address,uint96)'))

OBSERVED_IMPL=${UPGRADE_PLAN[0]}
OBSERVED_AFTER_EPOCH=${UPGRADE_PLAN[1]}
echo "Planned implementation: $OBSERVED_IMPL (expected $CALI_NEW_IMPL)"
echo "Actual afterEpoch: $OBSERVED_AFTER_EPOCH"

if [ "${ANNOUNCEMENT_MODE:-legacy}" = "legacy" ]; then
  EXPECTED_AFTER_EPOCH=$AFTER_EPOCH
else
  ANNOUNCE_EPOCH=$(cast receipt --rpc-url "$ETH_RPC_URL" "$ANNOUNCE_TX_HASH" blockNumber)
  EFFECTIVE_DELAY_EPOCHS=$UPGRADE_DELAY_EPOCHS
  [ "$EFFECTIVE_DELAY_EPOCHS" -eq 0 ] && EFFECTIVE_DELAY_EPOCHS=1
  EXPECTED_AFTER_EPOCH=$((ANNOUNCE_EPOCH + EFFECTIVE_DELAY_EPOCHS))
fi

if [ "$(printf '%s' "$OBSERVED_IMPL" | tr '[:upper:]' '[:lower:]')" != "$(printf '%s' "$CALI_NEW_IMPL" | tr '[:upper:]' '[:lower:]')" ]; then
  echo "ERROR: announced implementation mismatch"
  exit 1
fi
if [ "$OBSERVED_AFTER_EPOCH" -ne "$EXPECTED_AFTER_EPOCH" ]; then
  echo "ERROR: afterEpoch mismatch ($OBSERVED_AFTER_EPOCH != $EXPECTED_AFTER_EPOCH)"
  exit 1
fi
  • Record the Calibnet announce tx and observed afterEpoch in the schedule and Run Log
  • Update the GitHub pre-release Calibnet rollout status with the announce tx and observed afterEpoch
  • Update the status.filecoin.cloud status page that the FWSS contract upgrade is coming to the Calibration network, following the operational-events.md documentation for contract upgrades. Include the network, scheduled date, and v1.3.1 pre-release link.

Execute

  • Wait for the observed Calibnet afterEpoch
  • If this release has a ServiceProviderRegistry exception, generate its Calibnet execution with NEW_SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS="$CALI_NEW_SPR_IMPL" NEW_VERSION=<version> CALLDATA_ONLY=true ./service-provider-registry-execute-upgrade.sh, execute it in the approved transaction order, then verify and record its implementation slot, VERSION(), initializer counter, preserved registry state, and cleared nextUpgrade()
  • Generate execute calldata and submit/sign/execute in Safe UI:
cd service_contracts/tools
export ETH_RPC_URL="https://api.calibration.node.glif.io/rpc/v1"
export FWSS_PROXY_ADDRESS="0x02925630df557F957f70E112bA06e50965417CA0"
export NEW_WARM_STORAGE_IMPLEMENTATION_ADDRESS="$CALI_NEW_IMPL"

CALLDATA_ONLY=true ./warm-storage-execute-upgrade.sh
  • In Safe Transaction Builder, set target to the printed FWSS proxy, value to 0, and data to the printed calldata
  • Record Calibnet execute tx link in the Run Log
  • Verify implementation slot equals CALI_NEW_IMPL
  • Verify VERSION() returns the expected FWSS contract version
  • Verify viewContractAddress() equals CALI_NEW_VIEW if a StateView switch was expected, or the unchanged View address otherwise
  • Verify nextUpgrade() is cleared
export ETH_RPC_URL="https://api.calibration.node.glif.io/rpc/v1"
export FWSS_PROXY_ADDRESS="0x02925630df557F957f70E112bA06e50965417CA0"
export EXPECTED_FWSS_IMPLEMENTATION_ADDRESS="$CALI_NEW_IMPL"
export EXPECTED_FWSS_VERSION="1.3.1"
export EXPECTED_FWSS_VIEW_ADDRESS="${CALI_NEW_VIEW:-unchanged}"

CURRENT_VIEW=$(cast call --rpc-url "$ETH_RPC_URL" \
  "$FWSS_PROXY_ADDRESS" \
  'viewContractAddress()(address)')
if [ "$EXPECTED_FWSS_VIEW_ADDRESS" = "unchanged" ]; then
  EXPECTED_FWSS_VIEW_ADDRESS="$CURRENT_VIEW"
fi

IMPLEMENTATION_SLOT=$(cast rpc --rpc-url "$ETH_RPC_URL" \
  eth_getStorageAt \
  "$FWSS_PROXY_ADDRESS" \
  0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc \
  latest | tr -d '"' | sed 's/^0x000000000000000000000000/0x/')

ACTUAL_VERSION=$(cast call --rpc-url "$ETH_RPC_URL" \
  "$FWSS_PROXY_ADDRESS" \
  'VERSION()(string)' | tr -d '"')

NEXT_UPGRADE=$(cast call --rpc-url "$ETH_RPC_URL" \
  "$CURRENT_VIEW" \
  'nextUpgrade()(address,uint96)')

echo "Implementation slot: $IMPLEMENTATION_SLOT (expected $EXPECTED_FWSS_IMPLEMENTATION_ADDRESS)"
echo "VERSION(): $ACTUAL_VERSION (expected $EXPECTED_FWSS_VERSION)"
echo "viewContractAddress(): $CURRENT_VIEW (expected $EXPECTED_FWSS_VIEW_ADDRESS)"
echo "nextUpgrade(): $NEXT_UPGRADE (expected zero address and 0)"

if [ "$(printf '%s' "$CURRENT_VIEW" | tr '[:upper:]' '[:lower:]')" != "$(printf '%s' "$EXPECTED_FWSS_VIEW_ADDRESS" | tr '[:upper:]' '[:lower:]')" ]; then
  echo "ERROR: viewContractAddress() mismatch"
  exit 1
fi
  • Verify FWSS pricing output, such as getPriceList(), matches the intended release pricing and record the command/output in the Run Log
  • Run and record a Calibnet smoke/E2E test result
  • Validate Calibnet Data Set creation through filecoin-pin add with --network calibration and unique --data-set-metadata, then record the command output, metadata, Data Set ID, tx/link, SP, and timestamp in the Run Log
Calibnet filecoin-pin validation
RUN_ID="fwss-v1.3.1-calibnet-$(date -u +%Y%m%dT%H%M%SZ)"
printf "FWSS v1.3.1 Calibnet smoke %s\n" "$RUN_ID" > "/tmp/$RUN_ID.txt"

filecoin-pin add "/tmp/$RUN_ID.txt" \
  --network calibration \
  --data-set-metadata fwss_release=v1.3.1 \
  --data-set-metadata smoke_run="$RUN_ID"

The unique smoke_run metadata is required so this validates new Data Set creation rather than reusing an existing Data Set.

  • Verify the proxy on Blockscout
  • Update the GitHub pre-release Calibnet rollout status with execute tx, checks, and smoke/E2E evidence
  • If Calibnet deployment addresses should be published before Mainnet, open or update a Calibnet-only follow-up PR to main for service_contracts/deployments.json after the Calibnet proxy switch and, if applicable, View switch are live, then record the PR link in Release Tracking. Otherwise record that the deployments.json update will wait for Mainnet.
  • Technical owner confirms Calibnet results are good before announcing Mainnet

Phase 4: Mainnet Announce + Execute

Announce

  • Technical owner records Mainnet go/no-go after reviewing Calibnet evidence, rollback status, dependency targets, and cross-repo status

  • Confirm required cross-repo changes are merged/released or explicitly waived by the technical owner

  • Create or update the public operational notice on status.filecoin.cloud before or alongside stakeholder notification. Use the Operational Event Communications Runbook for component, notification, update, and resolution guidance

  • Notify stakeholders before announcing Mainnet, including FilB so they can propagate the upgrade notice

  • If this release has a ServiceProviderRegistry exception, generate its Mainnet bootstrap announcement with NEW_SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS="$MAIN_NEW_SPR_IMPL" AFTER_EPOCH=<absolute-epoch> CALLDATA_ONLY=true ./service-provider-registry-announce-upgrade.sh, execute it through the owner Safe, then verify and record the exact implementation and afterEpoch returned by nextUpgrade() before any execute transaction. This legacy absolute-epoch path is only for upgrading a registry that does not yet expose the relative-delay entrypoint.

  • Set the Mainnet requested delay and update the schedule table. v1.3.1 bootstrap only: record the announcement mode as legacy; upgrades from v1.3.1 onward always use delay.

  • Generate announce calldata and submit/sign/execute in Safe UI:

cd service_contracts/tools
export ETH_RPC_URL="https://api.node.glif.io/rpc/v1"
export FWSS_PROXY_ADDRESS="0x8408502033C418E1bbC97cE9ac48E5528F371A9f"
export NEW_FWSS_IMPLEMENTATION_ADDRESS="$MAIN_NEW_IMPL"

For the normal delay-based flow:

export UPGRADE_DELAY_EPOCHS=2880 # use 20160 for breaking changes
export ANNOUNCEMENT_MODE=delay
unset AFTER_EPOCH

For the v1.3.0 -> v1.3.1 bootstrap rollout only, use this configuration instead:

export ANNOUNCEMENT_MODE=legacy
export LEGACY_NOTICE_EPOCHS=2880
export SAFE_SIGNING_BUFFER_EPOCHS=2880
CURRENT_EPOCH=$(cast block-number --rpc-url "$ETH_RPC_URL")
export AFTER_EPOCH=$((CURRENT_EPOCH + SAFE_SIGNING_BUFFER_EPOCHS + LEGACY_NOTICE_EPOCHS))
unset UPGRADE_DELAY_EPOCHS

Generate the transaction after selecting exactly one configuration above:

CALLDATA_ONLY=true ./warm-storage-announce-upgrade.sh
  • In Safe Transaction Builder, set target to the printed FWSS proxy, value to 0, and data to the printed calldata
  • After the Safe transaction executes, verify and read back the pending plan:
export ANNOUNCE_TX_HASH="0x..." # Safe execution transaction hash

CURRENT_VIEW=$(cast call --rpc-url "$ETH_RPC_URL" \
  "$FWSS_PROXY_ADDRESS" \
  'viewContractAddress()(address)')

UPGRADE_PLAN=($(cast call --rpc-url "$ETH_RPC_URL" \
  "$CURRENT_VIEW" \
  'nextUpgrade()(address,uint96)'))

OBSERVED_IMPL=${UPGRADE_PLAN[0]}
OBSERVED_AFTER_EPOCH=${UPGRADE_PLAN[1]}
echo "Planned implementation: $OBSERVED_IMPL (expected $MAIN_NEW_IMPL)"
echo "Actual afterEpoch: $OBSERVED_AFTER_EPOCH"

if [ "${ANNOUNCEMENT_MODE:-legacy}" = "legacy" ]; then
  EXPECTED_AFTER_EPOCH=$AFTER_EPOCH
else
  ANNOUNCE_EPOCH=$(cast receipt --rpc-url "$ETH_RPC_URL" "$ANNOUNCE_TX_HASH" blockNumber)
  EFFECTIVE_DELAY_EPOCHS=$UPGRADE_DELAY_EPOCHS
  [ "$EFFECTIVE_DELAY_EPOCHS" -eq 0 ] && EFFECTIVE_DELAY_EPOCHS=1
  EXPECTED_AFTER_EPOCH=$((ANNOUNCE_EPOCH + EFFECTIVE_DELAY_EPOCHS))
fi

if [ "$(printf '%s' "$OBSERVED_IMPL" | tr '[:upper:]' '[:lower:]')" != "$(printf '%s' "$MAIN_NEW_IMPL" | tr '[:upper:]' '[:lower:]')" ]; then
  echo "ERROR: announced implementation mismatch"
  exit 1
fi
if [ "$OBSERVED_AFTER_EPOCH" -ne "$EXPECTED_AFTER_EPOCH" ]; then
  echo "ERROR: afterEpoch mismatch ($OBSERVED_AFTER_EPOCH != $EXPECTED_AFTER_EPOCH)"
  exit 1
fi
  • Record the Mainnet announce tx and observed afterEpoch in the schedule and Run Log
  • Update the GitHub pre-release Mainnet rollout status with the announce tx and observed afterEpoch

Execute

  • Wait for the observed Mainnet afterEpoch
  • If this release has a ServiceProviderRegistry exception, generate its Mainnet execution with NEW_SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS="$MAIN_NEW_SPR_IMPL" NEW_VERSION=<version> CALLDATA_ONLY=true ./service-provider-registry-execute-upgrade.sh, execute it in the approved transaction order, then verify and record its implementation slot, VERSION(), initializer counter, preserved registry state, and cleared nextUpgrade()
  • Generate execute calldata and submit/sign/execute in Safe UI:
cd service_contracts/tools
export ETH_RPC_URL="https://api.node.glif.io/rpc/v1"
export FWSS_PROXY_ADDRESS="0x8408502033C418E1bbC97cE9ac48E5528F371A9f"
export NEW_WARM_STORAGE_IMPLEMENTATION_ADDRESS="$MAIN_NEW_IMPL"

CALLDATA_ONLY=true ./warm-storage-execute-upgrade.sh
  • In Safe Transaction Builder, set target to the printed FWSS proxy, value to 0, and data to the printed calldata
  • Record Mainnet execute tx link in the Run Log
  • Verify implementation slot equals MAIN_NEW_IMPL
  • Verify VERSION() returns the expected FWSS contract version
  • Verify viewContractAddress() equals MAIN_NEW_VIEW if a StateView switch was expected, or the unchanged View address otherwise
  • Verify nextUpgrade() is cleared
export ETH_RPC_URL="https://api.node.glif.io/rpc/v1"
export FWSS_PROXY_ADDRESS="0x8408502033C418E1bbC97cE9ac48E5528F371A9f"
export EXPECTED_FWSS_IMPLEMENTATION_ADDRESS="$MAIN_NEW_IMPL"
export EXPECTED_FWSS_VERSION="1.3.1"
export EXPECTED_FWSS_VIEW_ADDRESS="${MAIN_NEW_VIEW:-unchanged}"

CURRENT_VIEW=$(cast call --rpc-url "$ETH_RPC_URL" \
  "$FWSS_PROXY_ADDRESS" \
  'viewContractAddress()(address)')
if [ "$EXPECTED_FWSS_VIEW_ADDRESS" = "unchanged" ]; then
  EXPECTED_FWSS_VIEW_ADDRESS="$CURRENT_VIEW"
fi

IMPLEMENTATION_SLOT=$(cast rpc --rpc-url "$ETH_RPC_URL" \
  eth_getStorageAt \
  "$FWSS_PROXY_ADDRESS" \
  0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc \
  latest | tr -d '"' | sed 's/^0x000000000000000000000000/0x/')

ACTUAL_VERSION=$(cast call --rpc-url "$ETH_RPC_URL" \
  "$FWSS_PROXY_ADDRESS" \
  'VERSION()(string)' | tr -d '"')

NEXT_UPGRADE=$(cast call --rpc-url "$ETH_RPC_URL" \
  "$CURRENT_VIEW" \
  'nextUpgrade()(address,uint96)')

echo "Implementation slot: $IMPLEMENTATION_SLOT (expected $EXPECTED_FWSS_IMPLEMENTATION_ADDRESS)"
echo "VERSION(): $ACTUAL_VERSION (expected $EXPECTED_FWSS_VERSION)"
echo "viewContractAddress(): $CURRENT_VIEW (expected $EXPECTED_FWSS_VIEW_ADDRESS)"
echo "nextUpgrade(): $NEXT_UPGRADE (expected zero address and 0)"

if [ "$(printf '%s' "$CURRENT_VIEW" | tr '[:upper:]' '[:lower:]')" != "$(printf '%s' "$EXPECTED_FWSS_VIEW_ADDRESS" | tr '[:upper:]' '[:lower:]')" ]; then
  echo "ERROR: viewContractAddress() mismatch"
  exit 1
fi
  • Verify FWSS pricing output, such as getPriceList(), matches the intended release pricing and record the command/output in the Run Log
  • Run and record a Mainnet smoke/E2E test result
  • Validate Mainnet Data Set creation through filecoin-pin add with --network mainnet and unique --data-set-metadata, then record the command output, metadata, Data Set ID, tx/link, SP, and timestamp in the Run Log
Mainnet filecoin-pin validation
RUN_ID="fwss-v1.3.1-mainnet-$(date -u +%Y%m%dT%H%M%SZ)"
printf "FWSS v1.3.1 Mainnet smoke %s\n" "$RUN_ID" > "/tmp/$RUN_ID.txt"

filecoin-pin add "/tmp/$RUN_ID.txt" \
  --network mainnet \
  --data-set-metadata fwss_release=v1.3.1 \
  --data-set-metadata smoke_run="$RUN_ID"

The unique smoke_run metadata is required so this validates new Data Set creation rather than reusing an existing Data Set.

  • Verify the proxy on Blockscout
  • Update the GitHub pre-release Mainnet rollout status with execute tx, checks, and smoke/E2E evidence

Phase 5: Promote Release and Close Out

  • Confirm live Calibnet and Mainnet FWSS implementation slots match the new implementation addresses
  • After any ServiceProviderRegistry bootstrap upgrade is live on both networks, replace the legacy absolute-epoch announcement helper with the relative-delay announceUpgradePlan(address,uint96) flow before the next SPR upgrade, and record the cleanup PR link.
  • After FWSS v1.3.1 is live on Calibnet and Mainnet, treat ANNOUNCEMENT_MODE=legacy as deprecated and decide whether rollback to v1.3.0 is still supported. Once that rollback path is retired, open and merge a follow-up PR that removes the legacy mode, its AFTER_EPOCH handling, the temporary announcement-mode schedule column and bootstrap clauses, the README bootstrap example, and the Temporary Bootstrap Compatibility instructions; record the cleanup PR link. If v1.3.0 rollback remains supported, retain legacy mode or document the exact v1.3.1-tagged helper that operators must use.
  • Confirm cross-repo follow-ups are complete or tracked with owners
  • Open or update follow-up PR(s) to main for service_contracts/deployments.json after the relevant Calibnet/Mainnet proxy switches and, if applicable, View switches are live. Include live implementation addresses, View addresses, deployment bytecode metadata, and pdp_version / fwss_version fields for each updated network.
  • Record the service_contracts/deployments.json PR link(s) in Release Tracking, then merge after checksum validation, bytecode metadata verification, and live-slot verification
  • Verify final service_contracts/deployments.json bytecode metadata matches the live deployed contracts after all proxy and View switches are complete
Deployment bytecode metadata verification commands
cd service_contracts

# Calibnet
CHAIN=314159 ETH_RPC_URL="https://api.calibration.node.glif.io/rpc/v1" \
  ./tools/verify-deployments.sh

# Mainnet
CHAIN=314 ETH_RPC_URL="https://api.node.glif.io/rpc/v1" \
  ./tools/verify-deployments.sh
  • Merge release-prep PR(s) if still open, keeping mutable rollout details on the GitHub Release page
  • Promote the GitHub Release from pre-release to latest after Mainnet proxy switch, checks, and release-page status are complete
  • Publish or update required ABIs after linked-library or interface changes: run make -C service_contracts update-abi for checked-in service_contracts/abi updates, confirm the Synapse SDK workflow regenerated downstream ABI/types, and record any explicit linked-library ABI publishing target or None required
ABI update commands
make -C service_contracts update-abi
git status --short service_contracts/abi
  • Run the Update Synapse SDK workflow manually with the release tag and the approved source ref/SHA after the intended deployment address state is available, or record an exception/owner in Release Tracking. This Phase 5 run is the final address-state update and should not be skipped because the Phase 1 ABI/type signal already ran.
  • Merge auto-generated PRs in filecoin-cloud
  • Confirm Synapse PR/release is merged or owned
  • Capture lessons learned from this rollout and update service_contracts/tools/UPGRADE-CHECKLIST.md if the process should change
  • Add release link to this issue
  • Close this issue

Resources

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions