Skip to content

feat(fwss): add immutable currency and storage pricing terms - #653

Open
Kubuxu wants to merge 6 commits into
mainfrom
feat-storage-terms2
Open

Kubuxu wants to merge 6 commits into
mainfrom
feat-storage-terms2

Conversation

@Kubuxu

@Kubuxu Kubuxu commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Implements #627 on top of the modular FWSS architecture.

Contract owners can register immutable storage terms defining a payment currency, token decimals, storage price, and salt. Clients select terms when creating a dataset; that selection cannot change afterward.

Changes

  • Add owner-only registration, disabling, and re-enabling of ordinary storage terms. Legacy record zero cannot be disabled through ordinary management.
  • Verify token decimals during registration and enforce the decimal-adjusted minimum price of 2.5 tokens/TiB/month.
  • Add terms-aware EIP-712 dataset creation, reusing the existing creation scope and replay protection.
  • Apply the selected currency and pricing throughout payment rails, operation fees, and lifecycle reserves.
  • Combine monthly storage and dataset charges before per-epoch rounding for every terms ID, including zero.
  • Restrict FilBeam to USDFC.
  • Add getDataSetV2 and paginated getClientDataSetsV2(client, offset, limit). Existing getters remain available with unchanged return layouts.
  • Ensure payer-signed termination remains immediate when the scaled termination fee is zero.
  • Update generated interfaces, published ABIs, specification, and rollout instructions.

USD-stablecoin economics guide the design, but currency eligibility remains the owner's responsibility. No stablecoin classification or exchange-rate conversion is enforced.

Storage and compatibility

struct StorageTerms {
    address token;
    uint8 tokenDecimals;
    bytes32 salt;
    uint96 pricePerTiBPerMonth;
}

Definitions are stored in the ERC-7201 namespace filecoin.FWSS.StorageTerms. Every ordinary definition uses its normal hash, including the exact legacy tuple.

ID zero is an independent legacy record: USDFC, 18 decimals, 2.5 USDFC/TiB/month, and zero salt. Existing datasets and legacy creation payloads select zero. New-format requests may also select it explicitly. Registering the same definition creates a separate hashed record, not an alias or pointer; each dataset uses a direct record lookup.

The terms ID is appended to DataSetInfo at relative slot 11; existing storage fields do not move. Disabling an ordinary record only blocks new dataset creation. Existing datasets continue operating under their selected terms.

disableStorageTerms(0) reverts with CannotDisableLegacyStorageTerms(). A future explicit upgrade migration may disable zero's enabled flag. Registering the matching hashed definition or repeating initialization does not re-enable zero.

Zero and hashed records use the same combined-monthly pricing formula. Compared with the previous separate truncation, a legacy dataset's rate can increase by one smallest USDFC unit per epoch when its rate is next updated.

Deployment

This change targets an already-modular FWSS deployment.

Announce and execute FWSSStorageTermsMigration, wrapping the raw Josuke route migration. The wrapper installs the routes and initializes legacy terms atomically using the installed USDFC configuration. It emits the canonical Migrate.DiamondDelegateCall event for the nested route migration. Do not execute the raw route migration directly for this upgrade.

The wrapper requires separate verification; Josuke verifies the raw route migration and facets. Fresh deployments initialize record zero through their initialization calldata. Initialization is idempotent and does not re-enable disabled terms.

Signed-off-by: Jakub Sztandera <oss@kubuxu.com>
Signed-off-by: Jakub Sztandera <oss@kubuxu.com>
@FilOzzy FilOzzy added this to FOC Oct 29, 2026
@github-project-automation github-project-automation Bot moved this to 📌 Triage in FOC Oct 29, 2026
Signed-off-by: Jakub Sztandera <oss@kubuxu.com>
Signed-off-by: Jakub Sztandera <oss@kubuxu.com>
@FilOzzy FilOzzy moved this from 📌 Triage to ⌨️ In Progress in FOC Oct 30, 2026
Signed-off-by: Jakub Sztandera <oss@kubuxu.com>
@Kubuxu
Kubuxu marked this pull request as ready for review November 2, 2026 13:09
@Kubuxu
Kubuxu requested a review from wjmelements as a code owner November 2, 2026 13:09
Copilot AI balanced review requested due to automatic review settings November 2, 2026 13:09
@Kubuxu

Kubuxu commented Nov 2, 2026

Copy link
Copy Markdown
Contributor Author

@wjmelements please review, I'm also still not certain regarding the upgrade/migration approach.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The funds-handling upgrade requires human verification of deployed migration-wrapper bytecode, facet configuration, and legacy payment continuity through a deployed-state rehearsal, since static review cannot establish these invariants.

No open issues 🎉

What changed in this PR

Implements immutable currency and storage pricing terms for modular FWSS, addressing #627 while preserving legacy billing and getter layouts.

Changes:

  • Adds owner-managed storage terms and signed dataset selection, applying currency precision to billing, fees, and reserves.
  • Adds V2 dataset getters and fixes immediate signed termination when fees round to zero.
  • Adds atomic upgrade initialization, compatibility tests, published interfaces, and rollout documentation.
File Description
SPEC.md Documents terms, pricing, compatibility, and termination behavior.
service_contracts/​tools/​UPGRADE-CHECKLIST.md Adds migration-wrapper deployment and verification steps.
service_contracts/​tools/​generate_fwss_interface.sh Maps new types for interface generation.
service_contracts/​test/​StorageTermsCreation.t.sol Tests signed selection, scaled charges, and termination.
service_contracts/​test/​StoragePricing.t.sol Tests legacy pricing and combined monthly rounding.
service_contracts/​test/​SignatureFixtureTest.t.sol Adds terms-aware signature generation and verification.
service_contracts/​test/​modules/​FWSSViewModule.t.sol Tests V2 pagination and legacy decoding compatibility.
service_contracts/​test/​modules/​FWSSStorageTermsModule.t.sol Tests registration, permissions, decimals, and minimum prices.
service_contracts/​test/​FWSSDispatcher.t.sol Tests migration initialization and upgrade-route safeguards.
service_contracts/​test/​external_signatures.json Adds terms-aware signature reference vectors.
service_contracts/​src/​storage/​README.md Documents storage layout and initialization guarantees.
service_contracts/​src/​storage/​FWSSStorage.sol Appends the dataset’s selected terms ID.
service_contracts/​src/​modules/​FWSSViewModule.sol Adds V2 dataset and paginated client getters.
service_contracts/​src/​modules/​FWSSStorageTermsModule.sol Adds owner-controlled terms registration and disabling.
service_contracts/​src/​modules/​FWSSDataSetModule.sol Applies signed terms during dataset creation.
service_contracts/​src/​modules/​FWSSAuthorizationModule.sol Scales operation fees and handles zero-fee termination.
service_contracts/​src/​lib/​StorageTerms.sol Defines terms and stored-record structures.
service_contracts/​src/​lib/​StoragePricing.sol Implements decimal scaling and terms-based rates.
service_contracts/​src/​lib/​LibStorageTerms.sol Manages namespaced records and canonical legacy ID zero.
service_contracts/​src/​lib/​LibStoragePayments.sol Passes selected terms into payment updates.
service_contracts/​src/​lib/​LibSignatureVerification.sol Adds terms-aware EIP-712 hashing.
service_contracts/​src/​lib/​LibRails.sol Applies selected currency precision to rails and reserves.
service_contracts/​src/​lib/​FWSSViewTypes.sol Defines the V2 dataset view structure.
service_contracts/​src/​lib/​FilecoinWarmStorageServiceStateLibrary.sol Adds public V2 state-reading helpers.
service_contracts/​src/​lib/​FilecoinWarmStorageServiceStateInternalLibrary.sol Adds internal V2 state-reading helpers.
service_contracts/​src/​interfaces/​IFilecoinWarmStorageService.sol Exposes terms management and V2 getters.
service_contracts/​src/​FWSSStorageTermsMigration.sol Wraps route migration with atomic legacy initialization.
service_contracts/​src/​FWSSInitializer.sol Initializes legacy terms for fresh deployments.
service_contracts/​script/​lib/​FWSSDeployer.sol Supplies legacy currency to initialization.
service_contracts/​contract-size-policy.json Includes new contracts in size checks.
service_contracts/​abi/​FilecoinWarmStorageServiceStateLibrary.abi.json Publishes V2 state-library getter definitions.
service_contracts/​abi/​FilecoinWarmStorageService.abi.json Publishes terms APIs, events, errors, and V2 getters.
CHANGELOG.md Records features, compatibility, migration, and termination changes.

Review effort: Balanced

Comment thread service_contracts/src/lib/LibRails.sol Resolved
Comment thread service_contracts/src/lib/LibRails.sol Resolved
Signed-off-by: Jakub Sztandera <oss@kubuxu.com>
@Kubuxu

Kubuxu commented Nov 3, 2026

Copy link
Copy Markdown
Contributor Author

Changed the storage-terms implementation:

  • Legacy record zero is independent. Every registered definition uses its normal hash, including the exact legacy tuple. No alias pointer or additional storage lookup.
  • Ordinary management cannot disable zero. Added CannotDisableLegacyStorageTerms() and a code note explaining how a future explicit migration could disable it. Initialization and registration of the hashed definition do not re-enable a migration-disabled zero record.
  • Unified pricing arithmetic. All terms combine monthly storage and dataset charges before per-epoch division. Removed the legacy rounding branch and obsolete rate helpers.
  • Reused scaled rail amounts, emitted the canonical nested Migrate.DiamondDelegateCall event, standardized deprecation annotations, documented the storage-slot derivation, and removed allocation from terms hashing.

@Kubuxu
Kubuxu requested a review from wjmelements November 4, 2026 15:02
@BigLep BigLep moved this from ⌨️ In Progress to 🔎 Awaiting review in FOC Nov 4, 2026
Comment on lines +37 to +38
uint256 dataSetId; // DataSet ID
bytes32 storageTermsId; // Storage terms selected at data set creation

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are in a strange order. either put dataSetId at the top or at the bottom. or remove it

@github-project-automation github-project-automation Bot moved this from 🔎 Awaiting review to ✔️ Approved by reviewer in FOC Nov 4, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: ✔️ Approved by reviewer

Development

Successfully merging this pull request may close these issues.

3 participants