diff --git a/.github/scripts/create-upgrade-announcement.js b/.github/scripts/create-upgrade-announcement.js
new file mode 100644
index 00000000..b0695bcb
--- /dev/null
+++ b/.github/scripts/create-upgrade-announcement.js
@@ -0,0 +1,440 @@
+#!/usr/bin/env node
+/**
+ * Create FWSS Contract Upgrade Release Issue
+ *
+ * Generates a release issue that combines user-facing upgrade information
+ * with a release engineer checklist (similar to Lotus release issues).
+ *
+ * See help text below for more info.
+ */
+
+const https = require("https");
+
+// Parse command line arguments
+const args = process.argv.slice(2);
+const dryRun = args.includes("--dry-run");
+const showHelp = args.includes("--help") || args.includes("-h");
+
+if (showHelp) {
+ console.log(`
+Create FWSS Contract Upgrade Release Issue
+
+Usage:
+ node create-upgrade-announcement.js [options]
+
+Options:
+ --dry-run Output issue text without creating an issue
+ --help Show this help message
+
+Environment variables:
+ NETWORK Target network (Calibnet or Mainnet)
+ UPGRADE_TYPE Type of upgrade (Routine or Breaking Change)
+ AFTER_EPOCH Block number after which upgrade can execute
+ CHANGELOG_PR PR number with changelog updates
+ CHANGES_SUMMARY Summary of changes (use | for multiple lines)
+ ACTION_REQUIRED Action required for integrators (default: None)
+ UPGRADE_REGISTRY Also upgrading ServiceProviderRegistry? (true/false, default: false, rare)
+ UPGRADE_STATE_VIEW Also redeploying StateView? (true/false, default: false, rare)
+ RELEASE_TAG Release tag (optional, usually added after upgrade completes)
+ GITHUB_TOKEN GitHub token (required when not using --dry-run)
+ GITHUB_REPOSITORY Repository in format owner/repo (required when not using --dry-run)
+
+Example:
+ NETWORK=Calibnet UPGRADE_TYPE=Routine AFTER_EPOCH=12345 \\
+ CHANGELOG_PR=100 CHANGES_SUMMARY="Fix bug|Add feature" \\
+ node create-upgrade-announcement.js --dry-run
+`);
+ process.exit(0);
+}
+
+// Get configuration from environment
+const config = {
+ network: process.env.NETWORK,
+ upgradeType: process.env.UPGRADE_TYPE,
+ afterEpoch: process.env.AFTER_EPOCH,
+ changelogPr: process.env.CHANGELOG_PR,
+ changesSummary: process.env.CHANGES_SUMMARY,
+ actionRequired: process.env.ACTION_REQUIRED || "None",
+ upgradeRegistry: process.env.UPGRADE_REGISTRY === "true",
+ upgradeStateView: process.env.UPGRADE_STATE_VIEW === "true",
+ releaseTag: process.env.RELEASE_TAG || "",
+ githubToken: process.env.GITHUB_TOKEN,
+ githubRepository: process.env.GITHUB_REPOSITORY,
+ // Optional: pre-computed time estimate (from workflow)
+ timeEstimate: process.env.TIME_ESTIMATE,
+};
+
+// Validate required fields
+function validateConfig() {
+ const required = ["network", "upgradeType", "afterEpoch", "changelogPr", "changesSummary"];
+ const missing = required.filter((key) => !config[key]);
+
+ if (missing.length > 0) {
+ console.error(`Error: Missing required environment variables: ${missing.join(", ")}`);
+ console.error("Run with --help for usage information.");
+ process.exit(1);
+ }
+
+ if (!dryRun) {
+ if (!config.githubToken) {
+ console.error("Error: GITHUB_TOKEN is required when not using --dry-run");
+ process.exit(1);
+ }
+ if (!config.githubRepository) {
+ console.error("Error: GITHUB_REPOSITORY is required when not using --dry-run");
+ process.exit(1);
+ }
+ }
+}
+
+// Fetch current epoch from Filecoin RPC
+async function getCurrentEpoch(network) {
+ const rpcUrl =
+ network === "Mainnet"
+ ? "https://api.node.glif.io/rpc/v1"
+ : "https://api.calibration.node.glif.io/rpc/v1";
+
+ return new Promise((resolve, reject) => {
+ const url = new URL(rpcUrl);
+ const postData = JSON.stringify({
+ jsonrpc: "2.0",
+ method: "eth_blockNumber",
+ params: [],
+ id: 1,
+ });
+
+ const options = {
+ hostname: url.hostname,
+ path: url.pathname,
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ "Content-Length": Buffer.byteLength(postData),
+ },
+ };
+
+ const req = https.request(options, (res) => {
+ let data = "";
+ res.on("data", (chunk) => (data += chunk));
+ res.on("end", () => {
+ try {
+ const result = JSON.parse(data);
+ if (result.result) {
+ resolve(parseInt(result.result, 16));
+ } else {
+ reject(new Error("Invalid RPC response"));
+ }
+ } catch (e) {
+ reject(e);
+ }
+ });
+ });
+
+ req.on("error", reject);
+ req.write(postData);
+ req.end();
+ });
+}
+
+// Calculate estimated execution time
+async function calculateTimeEstimate(network, afterEpoch) {
+ // If pre-computed estimate is provided, use it
+ if (config.timeEstimate) {
+ return config.timeEstimate;
+ }
+
+ try {
+ const currentEpoch = await getCurrentEpoch(network);
+ const epochsRemaining = afterEpoch - currentEpoch;
+
+ if (epochsRemaining < 0) {
+ return "Immediately (epoch already passed)";
+ }
+
+ // Filecoin has ~30 second block times
+ const secondsRemaining = epochsRemaining * 30;
+ const hours = Math.floor(secondsRemaining / 3600);
+ const minutes = Math.floor((secondsRemaining % 3600) / 60);
+
+ const futureDate = new Date(Date.now() + secondsRemaining * 1000);
+ const dateStr = futureDate.toISOString().replace("T", " ").substring(0, 16) + " UTC";
+
+ return `~${dateStr} (~${hours}h ${minutes}m from current epoch ${currentEpoch})`;
+ } catch (error) {
+ console.error("Warning: Could not fetch current epoch:", error.message);
+ return "Unknown (could not fetch current epoch)";
+ }
+}
+
+// Format changes summary from pipe-separated to bullet points
+function formatChanges(changesSummary) {
+ return changesSummary
+ .split("|")
+ .map((line) => line.trim())
+ .filter((line) => line.length > 0)
+ .map((line) => `- ${line}`)
+ .join("\n");
+}
+
+// Build the list of contracts being upgraded (FWSS is always included)
+function buildContractsList() {
+ const contracts = ["FilecoinWarmStorageService"];
+
+ if (config.upgradeRegistry) {
+ contracts.push("ServiceProviderRegistry");
+ }
+ if (config.upgradeStateView) {
+ contracts.push("FilecoinWarmStorageServiceStateView");
+ }
+
+ return contracts;
+}
+
+// Generate issue title
+function generateTitle() {
+ return `[Release] FWSS ${config.network} Upgrade - Epoch ${config.afterEpoch}`;
+}
+
+// Generate issue body
+function generateBody(timeEstimate) {
+ const [owner, repo] = (config.githubRepository || "OWNER/REPO").split("/");
+ const baseUrl = `https://github.com/${owner}/${repo}`;
+
+ const changelogPrLink = `${baseUrl}/pull/${config.changelogPr}`;
+ const changelogLink = `${baseUrl}/blob/main/CHANGELOG.md`;
+ const upgradeProcessLink = `${baseUrl}/blob/main/service_contracts/tools/UPGRADE-PROCESS.md`;
+ const releaseLink = config.releaseTag ? `${baseUrl}/releases/tag/${config.releaseTag}` : null;
+
+ const changes = formatChanges(config.changesSummary);
+ const contracts = buildContractsList();
+ const isMainnet = config.network === "Mainnet";
+ const isBreaking = config.upgradeType === "Breaking Change";
+
+ // Build contracts checklist for the release checklist section
+ const deployChecklist = contracts
+ .map((c) => {
+ if (c === "FilecoinWarmStorageService") {
+ return "- [ ] Deploy FWSS implementation: `./warm-storage-deploy-implementation.sh`";
+ } else if (c === "ServiceProviderRegistry") {
+ return "- [ ] Deploy Registry implementation: `./service-provider-registry-deploy.sh`";
+ } else if (c === "FilecoinWarmStorageServiceStateView") {
+ return "- [ ] Deploy StateView: `./warm-storage-deploy-view.sh`";
+ }
+ return `- [ ] Deploy ${c}`;
+ })
+ .join("\n");
+
+ const announceChecklist = contracts
+ .map((c) => {
+ if (c === "FilecoinWarmStorageService") {
+ return "- [ ] Announce FWSS upgrade: `./warm-storage-announce-upgrade.sh`";
+ } else if (c === "ServiceProviderRegistry") {
+ return "- [ ] Announce Registry upgrade: `./service-provider-registry-announce-upgrade.sh`";
+ }
+ return null;
+ })
+ .filter(Boolean)
+ .join("\n");
+
+ const executeChecklist = contracts
+ .map((c) => {
+ if (c === "FilecoinWarmStorageService") {
+ return "- [ ] Execute FWSS upgrade: `./warm-storage-execute-upgrade.sh`";
+ } else if (c === "ServiceProviderRegistry") {
+ return "- [ ] Execute Registry upgrade: `./service-provider-registry-execute-upgrade.sh`";
+ }
+ return null;
+ })
+ .filter(Boolean)
+ .join("\n");
+
+ return `## Overview
+
+| Field | Value |
+|-------|-------|
+| **Network** | ${config.network} |
+| **Upgrade Type** | ${config.upgradeType} |
+| **Target Epoch** | ${config.afterEpoch} |
+| **Estimated Execution** | ${timeEstimate} |
+| **Changelog PR** | ${changelogPrLink} |
+${releaseLink ? `| **Release** | ${releaseLink} |` : ""}
+
+### Contracts in Scope
+${contracts.map((c) => `- ${c}`).join("\n")}
+
+### Changes
+${changes}
+
+### Action Required for Integrators
+${config.actionRequired}
+
+---
+
+## Release Checklist
+
+> Full process details: [UPGRADE-PROCESS.md](${upgradeProcessLink})
+
+### Phase 1: Prepare
+- [ ] Changelog entry prepared in [CHANGELOG.md](${changelogLink})
+- [ ] Version string updated in contracts (if applicable)
+- [ ] Upgrade PR created: #${config.changelogPr}
+${isBreaking ? "- [ ] Migration guide prepared for breaking changes" : ""}
+
+### Phase 2: Calibnet Rehearsal
+${isMainnet ? `
+Calibnet steps (expand)
+
+` : ""}**Deploy Implementation**
+${deployChecklist}
+- [ ] Commit updated \`deployments.json\`
+
+**Announce Upgrade**
+${announceChecklist}
+
+**Execute Upgrade**
+${executeChecklist}
+- [ ] Verify on Blockscout
+${isMainnet ? `
+
+` : ""}
+${
+ isMainnet
+ ? `### Phase 3: Mainnet Deployment
+${deployChecklist}
+- [ ] Commit updated \`deployments.json\`
+
+### Phase 4: Announce Mainnet Upgrade
+${announceChecklist}
+- [ ] Notify stakeholders (post in relevant channels)
+
+### Phase 5: Execute Mainnet Upgrade
+> ⏳ Wait until after epoch ${config.afterEpoch}
+
+${executeChecklist}
+- [ ] Verify on Blockscout
+`
+ : ""
+}
+### Phase ${isMainnet ? "6" : "3"}: Verify and Release
+- [ ] Verify upgrade on Blockscout
+- [ ] Confirm \`deployments.json\` is up to date
+- [ ] Merge changelog PR: #${config.changelogPr}
+- [ ] Tag release: \`git tag vX.Y.Z && git push origin vX.Y.Z\`
+- [ ] Create GitHub Release with changelog
+- [ ] Merge auto-generated PRs in [filecoin-cloud](https://github.com/FilOzone/filecoin-cloud/pulls) so docs.filecoin.cloud and filecoin.cloud reflect new contract versions
+- [ ] Create "Upgrade Synapse to use newest contracts" issue
+- [ ] Update this issue with release link
+- [ ] Close this issue
+
+---
+
+### Resources
+- [Changelog](${changelogLink})
+- [Upgrade Process Documentation](${upgradeProcessLink})
+${releaseLink ? `- [Release](${releaseLink})` : ""}
+
+### Deployed Addresses
+
+| Contract | Network | Address |
+|----------|---------|---------|
+| | | |`;
+}
+
+// Generate labels for the issue
+function generateLabels() {
+ const labels = ["release"];
+ if (config.upgradeType === "Breaking Change") {
+ labels.push("breaking-change");
+ }
+ return labels;
+}
+
+// Create GitHub issue
+async function createGitHubIssue(title, body, labels) {
+ const [owner, repo] = config.githubRepository.split("/");
+
+ return new Promise((resolve, reject) => {
+ const postData = JSON.stringify({ title, body, labels });
+
+ const options = {
+ hostname: "api.github.com",
+ path: `/repos/${owner}/${repo}/issues`,
+ method: "POST",
+ headers: {
+ Authorization: `Bearer ${config.githubToken}`,
+ Accept: "application/vnd.github+json",
+ "Content-Type": "application/json",
+ "Content-Length": Buffer.byteLength(postData),
+ "User-Agent": "create-upgrade-announcement-script",
+ "X-GitHub-Api-Version": "2022-11-28",
+ },
+ };
+
+ const req = https.request(options, (res) => {
+ let data = "";
+ res.on("data", (chunk) => (data += chunk));
+ res.on("end", () => {
+ try {
+ const result = JSON.parse(data);
+ if (res.statusCode === 201) {
+ resolve(result);
+ } else {
+ reject(new Error(`GitHub API error: ${res.statusCode} - ${result.message || data}`));
+ }
+ } catch (e) {
+ reject(e);
+ }
+ });
+ });
+
+ req.on("error", reject);
+ req.write(postData);
+ req.end();
+ });
+}
+
+// Main execution
+async function main() {
+ validateConfig();
+
+ const timeEstimate = await calculateTimeEstimate(config.network, parseInt(config.afterEpoch));
+ const title = generateTitle();
+ const body = generateBody(timeEstimate);
+ const labels = generateLabels();
+
+ if (dryRun) {
+ console.log("=== DRY RUN - Issue Preview ===\n");
+ console.log(`Title: ${title}\n`);
+ console.log(`Labels: ${labels.join(", ")}\n`);
+ console.log("--- Body ---");
+ console.log(body);
+ console.log("\n=== End of Preview ===");
+
+ // Output in GitHub Actions format if running in that context
+ if (process.env.GITHUB_OUTPUT) {
+ const fs = require("fs");
+ fs.appendFileSync(process.env.GITHUB_OUTPUT, `title=${title}\n`);
+ fs.appendFileSync(process.env.GITHUB_OUTPUT, `labels=${labels.join(",")}\n`);
+ // For multiline body, use delimiter syntax
+ fs.appendFileSync(process.env.GITHUB_OUTPUT, `body<> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ echo "**Network**: ${{ inputs.network }}" >> $GITHUB_STEP_SUMMARY
+ echo "**After Epoch**: ${{ inputs.after_epoch }}" >> $GITHUB_STEP_SUMMARY
+ echo "" >> $GITHUB_STEP_SUMMARY
+ if [ "${{ inputs.dry_run }}" = "true" ]; then
+ echo "This was a dry run. No issue was created." >> $GITHUB_STEP_SUMMARY
+ else
+ echo "See the created issue for full details." >> $GITHUB_STEP_SUMMARY
+ fi
diff --git a/service_contracts/README.md b/service_contracts/README.md
index 0e4e6813..40a85ad1 100644
--- a/service_contracts/README.md
+++ b/service_contracts/README.md
@@ -16,8 +16,8 @@ This directory contains the smart contracts for different Filecoin services usin
- `FilecoinWarmStorageService.t.sol` - Tests for the service contract
- `tools/` - Deployment and utility scripts
- `create_data_set_with_payments.sh` - Script to create data sets with payments
- - `deploy-warm-storage-calibnet.sh` - Deployment script for Warm Storage service on Calibnet
- - `deploy-all-warm-storage-calibnet.sh` - Deployment script for all Warm Storage contracts on Calibnet
+ - `warm-storage-deploy-calibnet.sh` - Deployment script for Warm Storage service on Calibnet
+ - `warm-storage-deploy-all.sh` - Deployment script for all Warm Storage contracts
- Note: deployment scripts now deploy and link `SignatureVerificationLib` when deploying `FilecoinWarmStorageService`.
The scripts will deploy `src/lib/SignatureVerificationLib.sol` (or simulate it in dry-run) and pass the library address
to `forge create` via the `--libraries` flag so the service implementation is correctly linked.
diff --git a/service_contracts/src/FilecoinWarmStorageService.sol b/service_contracts/src/FilecoinWarmStorageService.sol
index 947aac14..f9340ecb 100644
--- a/service_contracts/src/FilecoinWarmStorageService.sol
+++ b/service_contracts/src/FilecoinWarmStorageService.sol
@@ -60,7 +60,7 @@ contract FilecoinWarmStorageService is
EIP712Upgradeable
{
// Version tracking
- string public constant VERSION = "1.0.0";
+ string public constant VERSION = "1.1.0";
// =========================================================================
// Events
diff --git a/service_contracts/src/ServiceProviderRegistry.sol b/service_contracts/src/ServiceProviderRegistry.sol
index b0cc214c..c658e71c 100644
--- a/service_contracts/src/ServiceProviderRegistry.sol
+++ b/service_contracts/src/ServiceProviderRegistry.sol
@@ -43,7 +43,7 @@ contract ServiceProviderRegistry is
}
/// @notice Version of the contract implementation
- string public constant VERSION = "1.0.0";
+ string public constant VERSION = "1.1.0";
/// @notice Maximum length for service URL
uint256 private constant MAX_SERVICE_URL_LENGTH = 256;
diff --git a/service_contracts/test/FilecoinWarmStorageService.t.sol b/service_contracts/test/FilecoinWarmStorageService.t.sol
index dca54a07..5df116de 100644
--- a/service_contracts/test/FilecoinWarmStorageService.t.sol
+++ b/service_contracts/test/FilecoinWarmStorageService.t.sol
@@ -5387,7 +5387,7 @@ contract FilecoinWarmStorageServiceUpgradeTest is Test {
if (logs[i].topics[0] == expectedTopic) {
// Decode and verify the event data
(string memory version, address implementation) = abi.decode(logs[i].data, (string, address));
- assertEq(version, "1.0.0", "Version should be 1.0.0");
+ assertEq(version, "1.1.0", "Version should be 1.1.0");
assertTrue(implementation != address(0), "Implementation address should not be zero");
foundEvent = true;
break;
diff --git a/service_contracts/test/ServiceProviderRegistry.t.sol b/service_contracts/test/ServiceProviderRegistry.t.sol
index ae4315a1..f69aeaa7 100644
--- a/service_contracts/test/ServiceProviderRegistry.t.sol
+++ b/service_contracts/test/ServiceProviderRegistry.t.sol
@@ -38,7 +38,7 @@ contract ServiceProviderRegistryTest is MockFVMTest {
function testInitialState() public view {
// Check version
- assertEq(registry.VERSION(), "1.0.0", "Version should be 1.0.0");
+ assertEq(registry.VERSION(), "1.1.0", "Version should be 1.1.0");
// Check owner
assertEq(registry.owner(), owner, "Service provider should be deployer");
diff --git a/service_contracts/test/ServiceProviderRegistryFull.t.sol b/service_contracts/test/ServiceProviderRegistryFull.t.sol
index 5211ff56..9fe0c9d8 100644
--- a/service_contracts/test/ServiceProviderRegistryFull.t.sol
+++ b/service_contracts/test/ServiceProviderRegistryFull.t.sol
@@ -85,7 +85,7 @@ contract ServiceProviderRegistryFullTest is MockFVMTest {
// ========== Initial State Tests ==========
function testInitialState() public view {
- assertEq(registry.VERSION(), "1.0.0", "Version should be 1.0.0");
+ assertEq(registry.VERSION(), "1.1.0", "Version should be 1.1.0");
assertEq(registry.owner(), owner, "Service provider should be deployer");
assertEq(registry.getNextProviderId(), 1, "Next provider ID should start at 1");
assertEq(registry.REGISTRATION_FEE(), 5 ether, "Registration fee should be 5 FIL");
diff --git a/service_contracts/tools/README.md b/service_contracts/tools/README.md
index 9ad4a0dd..0aeafd9b 100644
--- a/service_contracts/tools/README.md
+++ b/service_contracts/tools/README.md
@@ -2,25 +2,51 @@
This directory contains scripts for deploying and upgrading the FilecoinWarmStorageService contract on Calibration testnet and Mainnet.
+> **For detailed upgrade procedures**, see [UPGRADE-PROCESS.md](./UPGRADE-PROCESS.md).
+
## Scripts Overview
-### Available Scripts
+Scripts are organized with prefixes for better discoverability:
+
+### Warm Storage Scripts
+
+| Script | Description |
+|--------|-------------|
+| `warm-storage-deploy-all.sh` | Deploy all contracts (PDPVerifier, FilecoinPayV1, FWSS, etc.) |
+| `warm-storage-deploy-implementation.sh` | Deploy FWSS implementation only (for upgrades) |
+| `warm-storage-deploy-view.sh` | Deploy FilecoinWarmStorageServiceStateView |
+| `warm-storage-deploy-calibnet.sh` | Deploy FWSS only (requires existing dependencies) |
+| `warm-storage-announce-upgrade.sh` | Announce a planned FWSS upgrade |
+| `warm-storage-execute-upgrade.sh` | Execute a previously announced FWSS upgrade |
+| `warm-storage-set-view.sh` | Set the StateView address on FWSS |
+
+### Service Provider Registry Scripts
+
+| Script | Description |
+|--------|-------------|
+| `service-provider-registry-deploy.sh` | Deploy ServiceProviderRegistry |
+| `service-provider-registry-announce-upgrade.sh` | Announce a planned registry upgrade |
+| `service-provider-registry-execute-upgrade.sh` | Execute a previously announced registry upgrade |
+
+### Other Scripts
-- `deploy-warm-storage-calibnet.sh` - Deploy FilecoinWarmStorageService only (requires existing PDPVerifier and FilecoinPayV1 contracts)
-- `deploy-all-warm-storage.sh` - Deploy all contracts to either Calibnet or Mainnet
-- `upgrade-warm-storage-calibnet.sh` - Upgrade existing FilecoinWarmStorageService contract with new proving period parameters
+| Script | Description |
+|--------|-------------|
+| `session-key-registry-deploy.sh` | Deploy SessionKeyRegistry |
+| `provider-id-set-deploy.sh` | Deploy ProviderIdSet |
### Usage
```bash
-# Deploy to Calibnet
-./tools/deploy-warm-storage-calibnet.sh
-
# Deploy all contracts
-./tools/deploy-all-warm-storage.sh
+./tools/warm-storage-deploy-all.sh
+
+# Deploy to Calibnet (FWSS only)
+./tools/warm-storage-deploy-calibnet.sh
-# Upgrade existing deployment
-./tools/upgrade-warm-storage-calibnet.sh
+# Upgrade existing deployment (see UPGRADE-PROCESS.md for details)
+./tools/warm-storage-announce-upgrade.sh # Step 1: Announce
+./tools/warm-storage-execute-upgrade.sh # Step 2: Execute (after AFTER_EPOCH)
```
## Deployment Parameters
@@ -115,17 +141,14 @@ These scripts now follow forge/cast's environment variable conventions. Set the
- `ETH_FROM` - Optional: address to use as deployer (forge/cast default is taken from the keystore)
### Required for specific scripts:
-- `deploy-warm-storage-calibnet.sh` requires:
-
+- `warm-storage-deploy-calibnet.sh` requires:
- `PDP_VERIFIER_PROXY_ADDRESS` - Address of deployed PDPVerifier contract
- `FILECOIN_PAY_ADDRESS` - Address of deployed FilecoinPayV1 contract
-
-- `deploy-all-warm-storage.sh` requires:
+- `warm-storage-deploy-all.sh` requires:
- `CHALLENGE_FINALITY` - Challenge finality parameter for PDPVerifier
-- `upgrade-warm-storage-calibnet.sh` requires:
- - `WARM_STORAGE_SERVICE_PROXY_ADDRESS` - Address of existing FilecoinWarmStorageService proxy to upgrade
+- Upgrade scripts - see [UPGRADE-PROCESS.md](./UPGRADE-PROCESS.md) for complete environment variable reference
## Usage Examples
@@ -143,7 +166,7 @@ export CHALLENGE_FINALITY="10" # Use "150" for mainnet
export MAX_PROVING_PERIOD="240" # 240 epochs for calibnet, 2880 for mainnet
export CHALLENGE_WINDOW_SIZE="20" # 20 epochs for calibnet, 60 for mainnet
-./deploy-all-warm-storage.sh
+./warm-storage-deploy-all.sh
```
### Deploy FilecoinWarmStorageService Only
@@ -155,30 +178,29 @@ export ETH_RPC_URL="https://api.calibration.node.glif.io/rpc/v1"
export PDP_VERIFIER_PROXY_ADDRESS="0x123..."
export FILECOIN_PAY_ADDRESS="0x456..."
-./deploy-warm-storage-calibnet.sh
+./warm-storage-deploy-calibnet.sh
```
### Upgrade Existing Contract
-```bash
-export ETH_KEYSTORE="/path/to/keystore.json"
-export PASSWORD="your-password"
-export ETH_RPC_URL="https://api.calibration.node.glif.io/rpc/v1"
-export WARM_STORAGE_SERVICE_PROXY_ADDRESS="0x789..."
+See [UPGRADE-PROCESS.md](./UPGRADE-PROCESS.md) for the complete two-step upgrade workflow.
-# Optional: Custom proving periods
-export MAX_PROVING_PERIOD="240" # 240 epochs for calibnet, 2880 for mainnet
-export CHALLENGE_WINDOW_SIZE="20" # 20 epochs for calibnet, 60 for mainnet
+## Contract Upgrade Process
-./upgrade-warm-storage-calibnet.sh
-```
+The FilecoinWarmStorageService and ServiceProviderRegistry contracts use a **two-step upgrade process** for security:
-## Contract Upgrade Process
+1. **Announce**: Call `announcePlannedUpgrade()` with the new implementation address and a future epoch
+2. **Execute**: After the announced epoch, call `upgradeToAndCall()` to complete the upgrade
+
+This gives stakeholders time to review changes before execution.
-The FilecoinWarmStorageService contract uses OpenZeppelin's upgradeable pattern. When upgrading:
+**For complete upgrade documentation**, including:
+- Step-by-step upgrade workflows
+- Environment variable reference
+- Immutable dependency handling
+- Verification procedures
-1. **Deploy new implementation**: The script deploys a new implementation contract
-2. **Upgrade proxy**: Uses `upgradeToAndCall` to point the proxy to the new implementation
+See [UPGRADE-PROCESS.md](./UPGRADE-PROCESS.md).
## Testing
diff --git a/service_contracts/tools/UPGRADE-PROCESS.md b/service_contracts/tools/UPGRADE-PROCESS.md
new file mode 100644
index 00000000..7584fce6
--- /dev/null
+++ b/service_contracts/tools/UPGRADE-PROCESS.md
@@ -0,0 +1,272 @@
+# FWSS Contract Upgrade Process
+
+This document describes the upgrade process for FilecoinWarmStorageService (FWSS), organized as a phase-based runbook. Most upgrades only involve the FWSS implementation contract.
+
+## Contract Overview
+
+| Contract | Upgradeable? | Notes |
+|----------|--------------|-------|
+| **FilecoinWarmStorageService (FWSS)** | Yes (UUPS, two-step) | Primary contract, most upgrades are here |
+| ServiceProviderRegistry | Yes (UUPS, two-step) | Rarely upgraded separately |
+| FilecoinWarmStorageServiceStateView | No (redeploy) | Helper contract, redeploy if view logic changes |
+| PDPVerifier | Yes (ERC1967) | Via [pdp repo](https://github.com/FilOzone/pdp) |
+| FilecoinPayV1, SessionKeyRegistry | No (immutable) | Not expected to change |
+
+**UUPS, two-step** — These contracts use the [UUPS (ERC-1822)](https://eips.ethereum.org/EIPS/eip-1822) proxy pattern via OpenZeppelin's `UUPSUpgradeable`, where the upgrade authorization logic lives in the *implementation* contract rather than the proxy. On top of standard UUPS, we add a **two-step upgrade mechanism**: the owner must first call `announcePlannedUpgrade()` to record the new implementation address and a future epoch, then wait for that epoch to pass before `upgradeToAndCall()` will succeed.
+
+> For upgrading ServiceProviderRegistry or redeploying StateView, see [Upgrading Other Contracts](#upgrading-other-contracts).
+
+## Two-Step Upgrade Mechanism
+
+FWSS uses a two-step upgrade to give stakeholders notice:
+
+1. **Announce** - Call `announcePlannedUpgrade()` with the new implementation address and `AFTER_EPOCH`
+2. **Execute** - After `AFTER_EPOCH` passes, call `upgradeToAndCall()` to complete the upgrade
+
+## Choosing AFTER_EPOCH
+
+| Upgrade Type | Minimum Notice | Recommended |
+|--------------|----------------|-------------|
+| Routine (bug fixes, minor features) | ~24 hours (~2880 epochs) | 1-2 days |
+| Breaking changes | ~1 week (~20160 epochs) | 1-2 weeks |
+
+Calculate an `AFTER_EPOCH`:
+```bash
+UPGRADE_WAIT_DURATION_EPOCHS=2880 # ~24 hours
+CURRENT_EPOCH=$(cast block-number --rpc-url "$ETH_RPC_URL")
+AFTER_EPOCH=$((CURRENT_EPOCH + UPGRADE_WAIT_DURATION_EPOCHS))
+echo "Current: $CURRENT_EPOCH, Upgrade after: $AFTER_EPOCH"
+```
+
+**Considerations:**
+- Allow time for stakeholder review
+- Avoid weekends/holidays for mainnet upgrades
+- Calibnet can use shorter notice periods for testing
+
+---
+
+## Phase 1: Prepare
+
+1. **Prepare changelog entry** in [`CHANGELOG.md`](../../CHANGELOG.md):
+ - Document all changes since [last release](https://github.com/FilOzone/filecoin-services/releases)
+ - Mark breaking changes clearly
+ - Include migration notes if needed
+
+2. **Update the [version](https://github.com/FilOzone/filecoin-services/blob/main/service_contracts/src/FilecoinWarmStorageService.sol#L63)** string in the contract.
+
+3. **Create an upgrade PR** with your changelog updates.
+ - Example title: `feat: FWSS v1.2.0 upgrade`
+
+4. **Create release issue** using the [Create Release Issue](https://github.com/FilOzone/filecoin-services/actions/workflows/create-upgrade-announcement-issue.yml) GitHub Action.
+ - Or preview locally: `node .github/scripts/create-upgrade-announcement.js --dry-run`
+
+## Phase 2: Calibnet Rehearsal
+
+Always test the upgrade on Calibnet before mainnet.
+
+### Deploy Implementation
+
+```bash
+cd service_contracts/tools
+export ETH_RPC_URL="https://api.calibration.node.glif.io/rpc/v1"
+
+./warm-storage-deploy-implementation.sh
+```
+
+The script updates `deployments.json` automatically. Commit the changes in the branch of the "upgrade PR" above.
+
+### Announce Upgrade
+
+```bash
+export WARM_STORAGE_PROXY_ADDRESS="0x..."
+export NEW_WARM_STORAGE_IMPLEMENTATION_ADDRESS="0x..."
+export AFTER_EPOCH="123456"
+
+./warm-storage-announce-upgrade.sh
+```
+
+### Execute Upgrade
+
+After `AFTER_EPOCH` passes:
+
+```bash
+export WARM_STORAGE_PROXY_ADDRESS="0x..."
+export NEW_WARM_STORAGE_IMPLEMENTATION_ADDRESS="0x..."
+
+./warm-storage-execute-upgrade.sh
+```
+
+Verify the upgrade on [Calibnet Blockscout](https://calibration.filfox.info/).
+
+## Phase 3: Mainnet Deployment
+
+```bash
+cd service_contracts/tools
+export ETH_RPC_URL="https://api.node.glif.io/rpc/v1"
+
+./warm-storage-deploy-implementation.sh
+```
+
+Commit the updated `deployments.json` in the branch of the "upgrade PR" above.
+
+## Phase 4: Announce Mainnet Upgrade
+
+```bash
+export ETH_RPC_URL="https://api.node.glif.io/rpc/v1"
+export WARM_STORAGE_PROXY_ADDRESS="0x..."
+export NEW_WARM_STORAGE_IMPLEMENTATION_ADDRESS="0x..."
+export AFTER_EPOCH="123456"
+
+./warm-storage-announce-upgrade.sh
+```
+
+Notify stakeholders (see [Stakeholder Communication](#stakeholder-communication)).
+
+## Phase 5: Execute Mainnet Upgrade
+
+After `AFTER_EPOCH` passes:
+
+```bash
+export ETH_RPC_URL="https://api.node.glif.io/rpc/v1"
+export WARM_STORAGE_PROXY_ADDRESS="0x..."
+export NEW_WARM_STORAGE_IMPLEMENTATION_ADDRESS="0x..."
+
+./warm-storage-execute-upgrade.sh
+```
+
+## Phase 6: Verify and Release
+
+1. **Verify** the upgrade on [Mainnet Blockscout](https://filfox.info/).
+2. **Confirm** `deployments.json` is up to date.
+3. **Merge** the changelog PR.
+4. **Tag release**:
+ ```bash
+ git tag v1.X.0
+ git push origin v1.X.0
+ ```
+5. **Create GitHub Release** with the changelog.
+6. **Close the release issue** after updating it with the release link.
+
+---
+
+## Stakeholder Communication
+
+> **Tip**: Use the [Create Release Issue](https://github.com/FilOzone/filecoin-services/actions/workflows/create-upgrade-announcement-issue.yml) GitHub Action to generate a release issue. Go to **Actions → Create Release Issue → Run workflow**.
+
+The release issue serves as both the public announcement and the release engineer's checklist. It includes:
+- Overview with network, epoch, estimated time, and changelog link
+- Summary of changes and action required for integrators
+- Full release checklist with all phases
+- Deployed addresses table (filled in during the process)
+
+### Breaking Changes
+
+For breaking API changes:
+- Provide extended notice period (1-2 weeks recommended)
+- Create a migration guide for affected integrators
+- Consider phased rollout: Calibnet first, then Mainnet after validation
+
+---
+
+## Upgrading Other Contracts
+
+Most upgrades only involve FWSS. This section covers the rare cases where you need to upgrade other contracts.
+
+### ServiceProviderRegistry
+
+The registry uses the same two-step upgrade mechanism as FWSS. Only upgrade it when:
+- There are changes to provider registration logic
+- Storage or validation rules need updating
+
+**Deploy new implementation:**
+```bash
+./service-provider-registry-deploy.sh
+```
+
+**Announce upgrade:**
+```bash
+export REGISTRY_PROXY_ADDRESS="0x..."
+export NEW_REGISTRY_IMPLEMENTATION_ADDRESS="0x..."
+export AFTER_EPOCH="123456"
+
+./service-provider-registry-announce-upgrade.sh
+```
+
+**Execute upgrade (after AFTER_EPOCH):**
+```bash
+export SERVICE_PROVIDER_REGISTRY_PROXY_ADDRESS="0x..."
+export NEW_REGISTRY_IMPLEMENTATION_ADDRESS="0x..."
+
+./service-provider-registry-execute-upgrade.sh
+```
+
+**Environment variables:**
+
+| Variable | Description |
+|----------|-------------|
+| `REGISTRY_PROXY_ADDRESS` | Address of registry proxy (for announce script) |
+| `SERVICE_PROVIDER_REGISTRY_PROXY_ADDRESS` | Address of registry proxy (for upgrade script) |
+| `NEW_REGISTRY_IMPLEMENTATION_ADDRESS` | Address of new implementation |
+| `AFTER_EPOCH` | Block number after which upgrade can execute |
+
+### FilecoinWarmStorageServiceStateView
+
+StateView is a helper contract (not upgradeable). Redeploy it when:
+- The view logic changes
+- FWSS changes require updated read functions
+
+**Deploy new StateView:**
+```bash
+./warm-storage-deploy-view.sh
+```
+
+**Update FWSS to use new StateView (during upgrade):**
+```bash
+export NEW_WARM_STORAGE_VIEW_ADDRESS="0x..."
+./warm-storage-execute-upgrade.sh
+```
+
+### Immutable Dependencies
+
+FWSS has these immutable dependencies that are **not expected to change**:
+
+```solidity
+IPDPVerifier public immutable pdpVerifier;
+FilecoinPayV1 public immutable paymentsContract;
+IERC20Metadata public immutable usdfcTokenAddress;
+address public immutable filBeamBeneficiaryAddress;
+ServiceProviderRegistry public immutable serviceProviderRegistry;
+SessionKeyRegistry public immutable sessionKeyRegistry;
+```
+
+If any of these need to change, it requires redeploying FWSS entirely. This should be announced well in advance (~2-4 weeks) with a migration plan.
+
+---
+
+## Environment Variables Reference
+
+### Common Variables
+
+| Variable | Description |
+|----------|-------------|
+| `ETH_RPC_URL` | RPC endpoint |
+| `ETH_KEYSTORE` | Path to Ethereum keystore file |
+| `PASSWORD` | Keystore password |
+| `CHAIN` | Chain ID (auto-detected if not set) |
+
+### FWSS Variables
+
+| Variable | Description |
+|----------|-------------|
+| `WARM_STORAGE_PROXY_ADDRESS` | Address of FWSS proxy contract |
+| `NEW_WARM_STORAGE_IMPLEMENTATION_ADDRESS` | Address of new implementation |
+| `AFTER_EPOCH` | Block number after which upgrade can execute |
+| `NEW_WARM_STORAGE_VIEW_ADDRESS` | (Optional) New StateView address to set during upgrade |
+
+## Deployment Address Management
+
+All deployment scripts automatically load and update addresses in `deployments.json`. See [README.md](./README.md) for details on:
+
+- How addresses are loaded by chain ID
+- Environment variable overrides
+- Control flags (`SKIP_LOAD_DEPLOYMENTS`, `SKIP_UPDATE_DEPLOYMENTS`)
diff --git a/service_contracts/tools/deploy-registry-calibnet.sh b/service_contracts/tools/deploy-registry-calibnet.sh
deleted file mode 100755
index a48868cd..00000000
--- a/service_contracts/tools/deploy-registry-calibnet.sh
+++ /dev/null
@@ -1,167 +0,0 @@
-#!/bin/bash
-# deploy-registry-calibnet deploys the Service Provider Registry contract to calibration net
-# Assumption: ETH_KEYSTORE, PASSWORD, ETH_RPC_URL env vars are set to an appropriate eth keystore path and password
-# and to a valid ETH_RPC_URL for the calibnet.
-# Assumption: forge, cast, jq are in the PATH
-# Assumption: called from contracts directory so forge paths work out
-#
-
-# Get script directory and source deployments.sh
-SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")"
-source "$SCRIPT_DIR/deployments.sh"
-
-echo "Deploying Service Provider Registry Contract"
-
-export CHAIN=314159
-
-# Load deployment addresses from deployments.json
-load_deployment_addresses "$CHAIN"
-
-if [ -z "$ETH_RPC_URL" ]; then
- echo "Error: ETH_RPC_URL is not set"
- exit 1
-fi
-
-if [ -z "$ETH_KEYSTORE" ]; then
- echo "Error: ETH_KEYSTORE is not set"
- exit 1
-fi
-
-# Optional: Check if PASSWORD is set (some users might use empty password)
-if [ -z "$PASSWORD" ]; then
- echo "Warning: PASSWORD is not set, using empty password"
-fi
-
-ADDR=$(cast wallet address --password "$PASSWORD")
-echo "Deploying contracts from address $ADDR"
-
-# Get current balance and nonce (cast will use ETH_RPC_URL)
-BALANCE=$(cast balance "$ADDR")
-echo "Deployer balance: $BALANCE"
-
-NONCE="$(cast nonce "$ADDR")"
-echo "Starting nonce: $NONCE"
-
-# Deploy ServiceProviderRegistry implementation
-SPR_INIT_COUNTER=1
-echo ""
-echo "=== STEP 1: Deploying ServiceProviderRegistry Implementation ==="
-SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS=$(forge create --password "$PASSWORD" --broadcast --nonce $NONCE src/ServiceProviderRegistry.sol:ServiceProviderRegistry --optimizer-runs 1 --via-ir --constructor-args $SPR_INIT_COUNTER | grep "Deployed to" | awk '{print $3}')
-if [ -z "$SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS" ]; then
- echo "Error: Failed to extract ServiceProviderRegistry implementation address"
- exit 1
-fi
-echo "✓ ServiceProviderRegistry implementation deployed at: $SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS"
-NONCE=$(expr $NONCE + "1")
-
-# Deploy ServiceProviderRegistry proxy
-echo ""
-echo "=== STEP 2: Deploying ServiceProviderRegistry Proxy ==="
-# Initialize with no parameters for basic initialization
-INIT_DATA=$(cast calldata "initialize()")
-echo "Initialization calldata: $INIT_DATA"
-
-REGISTRY_PROXY_ADDRESS=$(forge create --password "$PASSWORD" --broadcast --nonce $NONCE lib/pdp/src/ERC1967Proxy.sol:MyERC1967Proxy --constructor-args $SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS $INIT_DATA --optimizer-runs 1 --via-ir | grep "Deployed to" | awk '{print $3}')
-if [ -z "$REGISTRY_PROXY_ADDRESS" ]; then
- echo "Error: Failed to extract ServiceProviderRegistry proxy address"
- exit 1
-fi
-echo "✓ ServiceProviderRegistry proxy deployed at: $REGISTRY_PROXY_ADDRESS"
-
-# Verify deployment by calling version() on the proxy
-echo ""
-echo "=== STEP 3: Verifying Deployment ==="
-VERSION=$(cast call $REGISTRY_PROXY_ADDRESS "version()(string)")
-if [ -z "$VERSION" ]; then
- echo "Warning: Could not verify contract version"
-else
- echo "✓ Contract version: $VERSION"
-fi
-
-# Get registration fee
-FEE=$(cast call $REGISTRY_PROXY_ADDRESS "REGISTRATION_FEE()(uint256)")
-if [ -z "$FEE" ]; then
- echo "Warning: Could not retrieve registration fee"
- FEE_IN_FIL="unknown"
-else
- echo "✓ Registration fee: $FEE attoFIL"
- FEE_IN_FIL="$FEE attoFIL"
-fi
-
-# Get burn actor address
-BURN_ACTOR=$(cast call $REGISTRY_PROXY_ADDRESS "BURN_ACTOR()(address)")
-if [ -z "$BURN_ACTOR" ]; then
- echo "Warning: Could not retrieve burn actor address"
-else
- echo "✓ Burn actor address: $BURN_ACTOR"
-fi
-
-# Get contract version (this should be used instead of hardcoded version)
-CONTRACT_VERSION=$(cast call $REGISTRY_PROXY_ADDRESS "VERSION()(string)")
-if [ -z "$CONTRACT_VERSION" ]; then
- echo "Warning: Could not retrieve contract version"
- CONTRACT_VERSION="Unknown"
-fi
-
-# Get contract version (this should be used instead of hardcoded version)
-CONTRACT_VERSION=$(cast call $REGISTRY_PROXY_ADDRESS "VERSION()(string)")
-if [ -z "$CONTRACT_VERSION" ]; then
- echo "Warning: Could not retrieve contract version"
- CONTRACT_VERSION="Unknown"
-fi
-
-# Summary of deployed contracts
-echo ""
-echo "=========================================="
-echo "=== DEPLOYMENT SUMMARY ==="
-echo "=========================================="
-echo "ServiceProviderRegistry Implementation: $SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS"
-echo "ServiceProviderRegistry Proxy: $REGISTRY_PROXY_ADDRESS"
-echo "=========================================="
-
-# Update deployments.json
-if [ -n "$SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS" ]; then
- update_deployment_address "$CHAIN" "SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS" "$SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS"
-fi
-if [ -n "$REGISTRY_PROXY_ADDRESS" ]; then
- update_deployment_address "$CHAIN" "SERVICE_PROVIDER_REGISTRY_PROXY_ADDRESS" "$REGISTRY_PROXY_ADDRESS"
-fi
-if [ -n "$SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS" ] || [ -n "$REGISTRY_PROXY_ADDRESS" ]; then
- update_deployment_metadata "$CHAIN"
-fi
-echo ""
-echo "Contract Details:"
-echo " - Version: $CONTRACT_VERSION"
-echo " - Registration Fee: $FEE_IN_FIL (burned)"
-echo " - Burn Actor: $BURN_ACTOR"
-echo " - Chain: Calibration testnet (314159)"
-echo ""
-echo "Next steps:"
-echo "1. Save the proxy address: export REGISTRY_ADDRESS=$REGISTRY_PROXY_ADDRESS"
-echo "2. Verify the deployment by calling getProviderCount() - should return 0"
-echo "3. Test registration with: cast send --value attoFIL ..."
-echo "4. Transfer ownership if needed using transferOwnership()"
-echo "5. The registry is ready for provider registrations"
-echo ""
-echo "To interact with the registry:"
-echo " View functions:"
-echo " cast call $REGISTRY_PROXY_ADDRESS \"getProviderCount()(uint256)\""
-echo " cast call $REGISTRY_PROXY_ADDRESS \"getAllActiveProviders()(uint256[])\""
-echo " State changes (requires registration fee):"
-echo " Register as provider (requires proper encoding of PDPData)"
-echo ""
-
-# Automatic contract verification
-if [ "${AUTO_VERIFY:-true}" = "true" ]; then
- echo
- echo "🔍 Starting automatic contract verification..."
-
- pushd "$(dirname $0)/.." >/dev/null
- source tools/verify-contracts.sh
- verify_contracts_batch "$SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS,src/ServiceProviderRegistry.sol:ServiceProviderRegistry"
- popd >/dev/null
-else
- echo
- echo "⏭️ Skipping automatic verification (export AUTO_VERIFY=true to enable)"
-fi
-echo "=========================================="
diff --git a/service_contracts/tools/deploy-provider-id-set.sh b/service_contracts/tools/provider-id-set-deploy.sh
similarity index 97%
rename from service_contracts/tools/deploy-provider-id-set.sh
rename to service_contracts/tools/provider-id-set-deploy.sh
index 68631732..f60f7dfb 100755
--- a/service_contracts/tools/deploy-provider-id-set.sh
+++ b/service_contracts/tools/provider-id-set-deploy.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# deploy-provider-id-set deploys a ProviderIdSet contract
+# provider-id-set-deploy.sh deploys a ProviderIdSet contract
# Assumption: ETH_KEYSTORE, PASSWORD, ETH_RPC_URL env vars are set to an appropriate eth keystore path and password
# Assumption: forge, cast, jq are in the PATH
# Assumption: called from contracts directory so forge paths work out
diff --git a/service_contracts/tools/announce-planned-upgrade-registry.sh b/service_contracts/tools/service-provider-registry-announce-upgrade.sh
similarity index 95%
rename from service_contracts/tools/announce-planned-upgrade-registry.sh
rename to service_contracts/tools/service-provider-registry-announce-upgrade.sh
index 00542ab1..7428bdcd 100755
--- a/service_contracts/tools/announce-planned-upgrade-registry.sh
+++ b/service_contracts/tools/service-provider-registry-announce-upgrade.sh
@@ -1,6 +1,6 @@
#!/bin/bash
-# announce-planned-upgrade-registry.sh: Announces a planned upgrade for ServiceProviderRegistry
+# service-provider-registry-announce-upgrade.sh: Announces a planned upgrade for ServiceProviderRegistry
# Required args: ETH_RPC_URL, SERVICE_PROVIDER_REGISTRY_PROXY_ADDRESS, ETH_KEYSTORE, PASSWORD, NEW_SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS, AFTER_EPOCH
if [ -z "$ETH_RPC_URL" ]; then
diff --git a/service_contracts/tools/service-provider-registry-deploy.sh b/service_contracts/tools/service-provider-registry-deploy.sh
new file mode 100755
index 00000000..b6dd2c6b
--- /dev/null
+++ b/service_contracts/tools/service-provider-registry-deploy.sh
@@ -0,0 +1,219 @@
+#!/bin/bash
+# service-provider-registry-deploy.sh deploys the Service Provider Registry contract to a target network
+# Assumption: ETH_KEYSTORE, PASSWORD, ETH_RPC_URL env vars are set to an appropriate eth keystore path and password
+# and to a valid ETH_RPC_URL for the target network.
+# Assumption: forge, cast, jq are in the PATH
+# Assumption: called from contracts directory so forge paths work out
+#
+
+# Get script directory and source deployments.sh
+SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")"
+source "$SCRIPT_DIR/deployments.sh"
+
+echo "Deploying Service Provider Registry Contract"
+
+WITH_PROXY=false
+for arg in "$@"; do
+ case "$arg" in
+ --with-proxy)
+ WITH_PROXY=true
+ ;;
+ -h|--help)
+ echo "Usage: $(basename "$0") [--with-proxy]"
+ echo ""
+ echo "Default: deploy implementation only (upgrade)."
+ echo " --with-proxy Also deploy a new proxy and initialize it."
+ exit 0
+ ;;
+ *)
+ echo "Error: Unknown option '$arg'"
+ echo "Run with --help for usage."
+ exit 1
+ ;;
+ esac
+done
+
+if [ "$WITH_PROXY" = "true" ]; then
+ echo "Mode: implementation + proxy deployment"
+else
+ echo "Mode: implementation-only deployment with no new proxy and no proxy changes"
+fi
+
+if [ -z "$ETH_RPC_URL" ]; then
+ echo "Error: ETH_RPC_URL is not set"
+ exit 1
+fi
+
+# Auto-detect chain ID from RPC if not already set
+if [ -z "$CHAIN" ]; then
+ export CHAIN=$(cast chain-id)
+ if [ -z "$CHAIN" ]; then
+ echo "Error: Failed to detect chain ID from RPC"
+ exit 1
+ fi
+fi
+
+# Load deployment addresses from deployments.json
+load_deployment_addresses "$CHAIN"
+
+if [ -z "$ETH_KEYSTORE" ]; then
+ echo "Error: ETH_KEYSTORE is not set"
+ exit 1
+fi
+
+# Optional: Check if PASSWORD is set (some users might use empty password)
+if [ -z "$PASSWORD" ]; then
+ echo "Warning: PASSWORD is not set, using empty password"
+fi
+
+ADDR=$(cast wallet address --password "$PASSWORD")
+echo "Deploying contracts from address $ADDR"
+
+# Get current balance and nonce (cast will use ETH_RPC_URL)
+BALANCE=$(cast balance "$ADDR")
+echo "Deployer balance: $BALANCE"
+
+NONCE="$(cast nonce "$ADDR")"
+echo "Starting nonce: $NONCE"
+
+# Deploy ServiceProviderRegistry implementation
+echo ""
+echo "=== STEP 1: Deploying ServiceProviderRegistry Implementation ==="
+SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS=$(forge create --password "$PASSWORD" --broadcast --nonce $NONCE src/ServiceProviderRegistry.sol:ServiceProviderRegistry --optimizer-runs 1 --via-ir | grep "Deployed to" | awk '{print $3}')
+if [ -z "$SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS" ]; then
+ echo "Error: Failed to extract ServiceProviderRegistry implementation address"
+ exit 1
+fi
+echo "✓ ServiceProviderRegistry implementation deployed at: $SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS"
+NONCE=$(expr $NONCE + "1")
+
+if [ "$WITH_PROXY" = "true" ]; then
+ # Deploy ServiceProviderRegistry proxy
+ echo ""
+ echo "=== STEP 2: Deploying ServiceProviderRegistry Proxy ==="
+ # Initialize with no parameters for basic initialization
+ INIT_DATA=$(cast calldata "initialize()")
+ echo "Initialization calldata: $INIT_DATA"
+
+ REGISTRY_PROXY_ADDRESS=$(forge create --password "$PASSWORD" --broadcast --nonce $NONCE lib/pdp/src/ERC1967Proxy.sol:MyERC1967Proxy --constructor-args $SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS $INIT_DATA --optimizer-runs 1 --via-ir | grep "Deployed to" | awk '{print $3}')
+ if [ -z "$REGISTRY_PROXY_ADDRESS" ]; then
+ echo "Error: Failed to extract ServiceProviderRegistry proxy address"
+ exit 1
+ fi
+ echo "✓ ServiceProviderRegistry proxy deployed at: $REGISTRY_PROXY_ADDRESS"
+
+ # Verify deployment by calling version() on the proxy
+ echo ""
+ echo "=== STEP 3: Verifying Deployment ==="
+ VERSION=$(cast call $REGISTRY_PROXY_ADDRESS "version()(string)")
+ if [ -z "$VERSION" ]; then
+ echo "Warning: Could not verify contract version"
+ else
+ echo "✓ Contract version: $VERSION"
+ fi
+
+ # Get registration fee
+ FEE=$(cast call $REGISTRY_PROXY_ADDRESS "REGISTRATION_FEE()(uint256)")
+ if [ -z "$FEE" ]; then
+ echo "Warning: Could not retrieve registration fee"
+ FEE_IN_FIL="unknown"
+ else
+ echo "✓ Registration fee: $FEE attoFIL"
+ FEE_IN_FIL="$FEE attoFIL"
+ fi
+
+ # Get burn actor address
+ BURN_ACTOR=$(cast call $REGISTRY_PROXY_ADDRESS "BURN_ACTOR()(address)")
+ if [ -z "$BURN_ACTOR" ]; then
+ echo "Warning: Could not retrieve burn actor address"
+ else
+ echo "✓ Burn actor address: $BURN_ACTOR"
+ fi
+
+ # Get contract version (this should be used instead of hardcoded version)
+ CONTRACT_VERSION=$(cast call $REGISTRY_PROXY_ADDRESS "VERSION()(string)")
+ if [ -z "$CONTRACT_VERSION" ]; then
+ echo "Warning: Could not retrieve contract version"
+ CONTRACT_VERSION="Unknown"
+ fi
+else
+ echo ""
+ echo "=== STEP 2: Skipping Proxy Deployment ==="
+ echo "Use --with-proxy to deploy and initialize a new proxy."
+ CONTRACT_VERSION="n/a"
+ FEE_IN_FIL="n/a"
+ BURN_ACTOR="n/a"
+fi
+
+# Summary of deployed contracts
+echo ""
+echo "=========================================="
+echo "=== DEPLOYMENT SUMMARY ==="
+echo "=========================================="
+echo "ServiceProviderRegistry Implementation: $SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS"
+if [ "$WITH_PROXY" = "true" ]; then
+ echo "ServiceProviderRegistry Proxy: $REGISTRY_PROXY_ADDRESS"
+fi
+echo "=========================================="
+
+# Update deployments.json
+if [ -n "$SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS" ]; then
+ update_deployment_address "$CHAIN" "SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS" "$SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS"
+fi
+if [ "$WITH_PROXY" = "true" ] && [ -n "$REGISTRY_PROXY_ADDRESS" ]; then
+ update_deployment_address "$CHAIN" "SERVICE_PROVIDER_REGISTRY_PROXY_ADDRESS" "$REGISTRY_PROXY_ADDRESS"
+fi
+if [ -n "$SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS" ] || [ -n "$REGISTRY_PROXY_ADDRESS" ]; then
+ update_deployment_metadata "$CHAIN"
+fi
+echo ""
+echo "Contract Details:"
+echo " - Version: $CONTRACT_VERSION"
+echo " - Registration Fee: $FEE_IN_FIL (burned)"
+echo " - Burn Actor: $BURN_ACTOR"
+CHAIN_LABEL="unknown"
+if [ "$CHAIN" = "314159" ]; then
+ CHAIN_LABEL="Calibration testnet (314159)"
+elif [ "$CHAIN" = "314" ]; then
+ CHAIN_LABEL="Filecoin mainnet (314)"
+else
+ CHAIN_LABEL="Chain ID $CHAIN"
+fi
+echo " - Chain: $CHAIN_LABEL"
+echo ""
+echo "Next steps:"
+if [ "$WITH_PROXY" = "true" ]; then
+ echo "1. Save the proxy address: export REGISTRY_ADDRESS=$REGISTRY_PROXY_ADDRESS"
+ echo "2. Verify the deployment by calling getProviderCount() - should return 0"
+ echo "3. Test registration with: cast send --value attoFIL ..."
+ echo "4. Transfer ownership if needed using transferOwnership()"
+ echo "5. The registry is ready for provider registrations"
+else
+ echo "1. Save the implementation address for upgrade announcement"
+ echo "2. Proceed with service-provider-registry-announce-upgrade.sh"
+fi
+echo ""
+if [ "$WITH_PROXY" = "true" ]; then
+ echo "To interact with the registry:"
+ echo " View functions:"
+ echo " cast call $REGISTRY_PROXY_ADDRESS \"getProviderCount()(uint256)\""
+ echo " cast call $REGISTRY_PROXY_ADDRESS \"getAllActiveProviders()(uint256[])\""
+ echo " State changes (requires registration fee):"
+ echo " Register as provider (requires proper encoding of PDPData)"
+ echo ""
+fi
+
+# Automatic contract verification
+if [ "${AUTO_VERIFY:-true}" = "true" ]; then
+ echo
+ echo "🔍 Starting automatic contract verification..."
+
+ pushd "$(dirname $0)/.." >/dev/null
+ source tools/verify-contracts.sh
+ verify_contracts_batch "$SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS,src/ServiceProviderRegistry.sol:ServiceProviderRegistry"
+ popd >/dev/null
+else
+ echo
+ echo "⏭️ Skipping automatic verification (export AUTO_VERIFY=true to enable)"
+fi
+echo "=========================================="
diff --git a/service_contracts/tools/upgrade-registry.sh b/service_contracts/tools/service-provider-registry-execute-upgrade.sh
similarity index 96%
rename from service_contracts/tools/upgrade-registry.sh
rename to service_contracts/tools/service-provider-registry-execute-upgrade.sh
index fbd7f9ca..96d3e63c 100755
--- a/service_contracts/tools/upgrade-registry.sh
+++ b/service_contracts/tools/service-provider-registry-execute-upgrade.sh
@@ -1,6 +1,6 @@
#!/bin/bash
-# upgrade-registry.sh: Completes a pending upgrade for ServiceProviderRegistry
+# service-provider-registry-execute-upgrade.sh: Completes a pending upgrade for ServiceProviderRegistry
# Required args: ETH_RPC_URL, SERVICE_PROVIDER_REGISTRY_PROXY_ADDRESS, ETH_KEYSTORE, PASSWORD, NEW_SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS
# Optional args: NEW_VERSION
# Calculated if unset: CHAIN
@@ -91,13 +91,13 @@ if [ $CAST_CALL_EXIT_CODE -eq 0 ] && [ -n "$UPGRADE_PLAN_OUTPUT" ]; then
# Method exists but returns zero - no planned upgrade or already completed
# On new contracts, _authorizeUpgrade requires a planned upgrade, so one-step will fail
echo "No planned upgrade detected (nextUpgrade returns zero)"
- echo "Error: This contract requires a planned upgrade. Please call announce-planned-upgrade-registry.sh first."
+ echo "Error: This contract requires a planned upgrade. Please call service-provider-registry-announce-upgrade.sh first."
exit 1
fi
else
# Method doesn't exist (old contract without nextUpgrade) or call failed
echo "nextUpgrade() method not found or call failed, using one-step mechanism (direct upgrade)"
- echo "WARNING: This is the legacy upgrade path. For new deployments, use announce-planned-upgrade-registry.sh first."
+ echo "WARNING: This is the legacy upgrade path. For new deployments, use service-provider-registry-announce-upgrade.sh first."
fi
if [ -n "$NEW_VERSION" ]; then
diff --git a/service_contracts/tools/deploy-session-key-registry.sh b/service_contracts/tools/session-key-registry-deploy.sh
similarity index 100%
rename from service_contracts/tools/deploy-session-key-registry.sh
rename to service_contracts/tools/session-key-registry-deploy.sh
diff --git a/service_contracts/tools/announce-planned-upgrade.sh b/service_contracts/tools/warm-storage-announce-upgrade.sh
similarity index 96%
rename from service_contracts/tools/announce-planned-upgrade.sh
rename to service_contracts/tools/warm-storage-announce-upgrade.sh
index 88d650b2..ef624731 100755
--- a/service_contracts/tools/announce-planned-upgrade.sh
+++ b/service_contracts/tools/warm-storage-announce-upgrade.sh
@@ -1,6 +1,6 @@
#!/bin/bash
-# announce-planned-upgrade.sh: Completes a pending upgrade
+# warm-storage-announce-upgrade.sh: Completes a pending upgrade
# Required args: ETH_RPC_URL, FWSS_PROXY_ADDRESS, ETH_KEYSTORE, PASSWORD, NEW_FWSS_IMPLEMENTATION_ADDRESS, AFTER_EPOCH
if [ -z "$ETH_RPC_URL" ]; then
diff --git a/service_contracts/tools/deploy-all-warm-storage.sh b/service_contracts/tools/warm-storage-deploy-all.sh
similarity index 97%
rename from service_contracts/tools/deploy-all-warm-storage.sh
rename to service_contracts/tools/warm-storage-deploy-all.sh
index 590439a8..08ed63bf 100755
--- a/service_contracts/tools/deploy-all-warm-storage.sh
+++ b/service_contracts/tools/warm-storage-deploy-all.sh
@@ -1,5 +1,5 @@
#! /bin/bash
-# deploy-all-warm-storage deploys the PDP verifier, FilecoinPayV1 contract, and Warm Storage service
+# warm-storage-deploy-all.sh deploys the PDP verifier, FilecoinPayV1 contract, and Warm Storage service
# Auto-detects network based on RPC chain ID and sets appropriate configuration
# Assumption: KEYSTORE, PASSWORD, ETH_RPC_URL env vars are set to an appropriate eth keystore path and password
# and to a valid ETH_RPC_URL for the target network.
@@ -271,7 +271,7 @@ deploy_proxy_if_needed() {
echo
}
-# Deploy session key registry if needed (uses ./deploy-session-key-registry.sh)
+# Deploy session key registry if needed (uses ./session-key-registry-deploy.sh)
deploy_session_key_registry_if_needed() {
if [ -n "$SESSION_KEY_REGISTRY_ADDRESS" ]; then
echo -e "${BOLD}SessionKeyRegistry${RESET}"
@@ -287,7 +287,7 @@ deploy_session_key_registry_if_needed() {
echo " 🧪 Using dummy address: $SESSION_KEY_REGISTRY_ADDRESS"
else
echo " 🔧 Using external deployment script..."
- source "$SCRIPT_DIR/deploy-session-key-registry.sh"
+ source "$SCRIPT_DIR/session-key-registry-deploy.sh"
NONCE=$(expr $NONCE + "1")
echo " ✅ Deployed at: $SESSION_KEY_REGISTRY_ADDRESS"
@@ -299,7 +299,7 @@ deploy_session_key_registry_if_needed() {
echo
}
-# Deploy endorsements ProviderIdSet contract if needed (uses ./deploy-provider-id-set.sh)
+# Deploy endorsements ProviderIdSet contract if needed (uses ./provider-id-set-deploy.sh)
deploy_endorsements_if_needed() {
if [ -n "$ENDORSEMENT_SET_ADDRESS" ]; then
echo -e "${BOLD}Endorsements ProviderIdSet${RESET}"
@@ -318,7 +318,7 @@ deploy_endorsements_if_needed() {
AUTO_VERIFY_BEFORE=${AUTO_VERIFY:-true}
AUTO_VERIFY=false # override so as to set last
# This also updates deployments.json
- source "$SCRIPT_DIR/deploy-provider-id-set.sh"
+ source "$SCRIPT_DIR/provider-id-set-deploy.sh"
AUTO_VERIFY=$AUTO_VERIFY_BEFORE
NONCE=$(expr $NONCE + "1")
echo " ✅ Deployed at: $ENDORSEMENT_SET_ADDRESS"
@@ -486,7 +486,7 @@ if [ "$DRY_RUN" = "true" ]; then
echo " ✅ Deployment planned (dummy: $FWSS_VIEW_ADDRESS)"
else
echo " 🔧 Using external deployment script..."
- source "$SCRIPT_DIR/deploy-warm-storage-view.sh"
+ source "$SCRIPT_DIR/warm-storage-deploy-view.sh"
echo " ✅ Deployed at: $FWSS_VIEW_ADDRESS"
NONCE=$(expr $NONCE + "1")
@@ -503,7 +503,7 @@ if [ "$DRY_RUN" = "true" ]; then
echo " 🔍 Would set view contract address on main contract (skipping in dry-run)"
else
echo " 🔧 Setting view address on FilecoinWarmStorageService..."
- source "$SCRIPT_DIR/set-warm-storage-view.sh"
+ source "$SCRIPT_DIR/warm-storage-set-view.sh"
echo " ✅ View address set"
NONCE=$(expr $NONCE + "1")
fi
@@ -517,7 +517,7 @@ if [ "$DRY_RUN" = "true" ]; then
echo "✅ Dry run completed successfully!"
echo "🔍 All contract compilations and simulations passed"
echo
- echo "To perform actual deployment, run with: DRY_RUN=false ./tools/deploy-all-warm-storage.sh"
+ echo "To perform actual deployment, run with: DRY_RUN=false ./tools/warm-storage-deploy-all.sh"
echo
echo "# DRY-RUN SUMMARY ($NETWORK_NAME)"
else
diff --git a/service_contracts/tools/deploy-warm-storage-calibnet.sh b/service_contracts/tools/warm-storage-deploy-calibnet.sh
similarity index 98%
rename from service_contracts/tools/deploy-warm-storage-calibnet.sh
rename to service_contracts/tools/warm-storage-deploy-calibnet.sh
index 5c8a72ec..bd727599 100755
--- a/service_contracts/tools/deploy-warm-storage-calibnet.sh
+++ b/service_contracts/tools/warm-storage-deploy-calibnet.sh
@@ -1,5 +1,5 @@
#! /bin/bash
-# deploy-warm-storage-calibnet deploys the Warm Storage service contract to calibration net
+# warm-storage-deploy-calibnet.sh deploys the Warm Storage service contract to calibration net
# Assumption: ETH_KEYSTORE, PASSWORD, ETH_RPC_URL env vars are set to an appropriate eth keystore path and password
# and to a valid ETH_RPC_URL for the calibnet.
# Assumption: forge, cast, jq are in the PATH
@@ -109,7 +109,7 @@ if [ "$MAX_PROVING_PERIOD" -lt "$MIN_REQUIRED" ]; then
echo " MAX_PROVING_PERIOD must be at least $MIN_REQUIRED (CHALLENGE_FINALITY + CHALLENGE_WINDOW_SIZE/2)"
echo " To fix: Set MAX_PROVING_PERIOD to at least $MIN_REQUIRED"
echo ""
- echo " Example: MAX_PROVING_PERIOD=$MIN_REQUIRED CHALLENGE_WINDOW_SIZE=$CHALLENGE_WINDOW_SIZE ./deploy-warm-storage-calibnet.sh"
+ echo " Example: MAX_PROVING_PERIOD=$MIN_REQUIRED CHALLENGE_WINDOW_SIZE=$CHALLENGE_WINDOW_SIZE ./warm-storage-deploy-calibnet.sh"
exit 1
fi
diff --git a/service_contracts/tools/deploy-warm-storage-implementation-only.sh b/service_contracts/tools/warm-storage-deploy-implementation.sh
similarity index 74%
rename from service_contracts/tools/deploy-warm-storage-implementation-only.sh
rename to service_contracts/tools/warm-storage-deploy-implementation.sh
index 27df2a3b..47428450 100755
--- a/service_contracts/tools/deploy-warm-storage-implementation-only.sh
+++ b/service_contracts/tools/warm-storage-deploy-implementation.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-# deploy-warm-storage-implementation-only.sh - Deploy only FilecoinWarmStorageService implementation (no proxy)
+# warm-storage-deploy-implementation.sh - Deploy only FilecoinWarmStorageService implementation (no proxy)
# This allows updating an existing proxy to point to the new implementation
# Assumption: ETH_KEYSTORE, PASSWORD, ETH_RPC_URL env vars are set
# Assumption: forge, cast are in the PATH
@@ -24,6 +24,10 @@ if [ -z "$CHAIN" ]; then
fi
fi
+# Load deployments.json helpers and populate defaults if available
+source "$(dirname "$0")/deployments.sh"
+load_deployment_addresses "$CHAIN"
+
if [ -z "$ETH_KEYSTORE" ]; then
echo "Error: ETH_KEYSTORE is not set"
@@ -65,8 +69,34 @@ if [ -z "$SESSION_KEY_REGISTRY_ADDRESS" ]; then
exit 1
fi
-USDFC_TOKEN_ADDRESS="0xb3042734b608a1B16e9e86B374A3f3e389B4cDf0" # USDFC token address on calibnet
+# Set network-specific USDFC token address based on chain ID
+case "$CHAIN" in
+ "31415926")
+ # Devnet requires explicit USDFC_TOKEN_ADDRESS (mock token)
+ if [ -z "$USDFC_TOKEN_ADDRESS" ]; then
+ echo "Error: USDFC_TOKEN_ADDRESS is not set (required for devnet)"
+ echo "Please set USDFC_TOKEN_ADDRESS to your deployed MockUSDFC address"
+ exit 1
+ fi
+ ;;
+ "314159")
+ USDFC_TOKEN_ADDRESS="${USDFC_TOKEN_ADDRESS:-0xb3042734b608a1B16e9e86B374A3f3e389B4cDf0}" # calibnet
+ ;;
+ "314")
+ USDFC_TOKEN_ADDRESS="${USDFC_TOKEN_ADDRESS:-0x80B98d3aa09ffff255c3ba4A241111Ff1262F045}" # mainnet
+ ;;
+ *)
+ echo "Error: Unsupported network"
+ echo " Supported networks:"
+ echo " 31415926 - Filecoin local development network"
+ echo " 314159 - Filecoin Calibration testnet"
+ echo " 314 - Filecoin mainnet"
+ echo " Detected chain ID: $CHAIN"
+ exit 1
+ ;;
+esac
+SIGNATURE_LIB_DEPLOYED=false
if [ -z "$SIGNATURE_VERIFICATION_LIB_ADDRESS" ]; then
# Deploy SignatureVerificationLib first so we can link it into the implementation
echo "Deploying SignatureVerificationLib..."
@@ -77,6 +107,7 @@ if [ -z "$SIGNATURE_VERIFICATION_LIB_ADDRESS" ]; then
exit 1
fi
echo "SignatureVerificationLib deployed at: $SIGNATURE_VERIFICATION_LIB_ADDRESS"
+ SIGNATURE_LIB_DEPLOYED=true
# Increment nonce for the next deployment
NONCE=$((NONCE + 1))
else
@@ -112,6 +143,13 @@ echo "SignatureVerificationLib deployed at: $SIGNATURE_VERIFICATION_LIB_ADDRESS"
echo "FilecoinWarmStorageService Implementation deployed at: $FWSS_IMPLEMENTATION_ADDRESS"
echo ""
+# Persist deployment addresses + metadata
+update_deployment_address "$CHAIN" "FWSS_IMPLEMENTATION_ADDRESS" "$FWSS_IMPLEMENTATION_ADDRESS"
+if [ "$SIGNATURE_LIB_DEPLOYED" = "true" ]; then
+ update_deployment_address "$CHAIN" "SIGNATURE_VERIFICATION_LIB_ADDRESS" "$SIGNATURE_VERIFICATION_LIB_ADDRESS"
+fi
+update_deployment_metadata "$CHAIN"
+
# Automatic contract verification
if [ "${AUTO_VERIFY:-true}" = "true" ]; then
echo
diff --git a/service_contracts/tools/deploy-warm-storage-view.sh b/service_contracts/tools/warm-storage-deploy-view.sh
similarity index 83%
rename from service_contracts/tools/deploy-warm-storage-view.sh
rename to service_contracts/tools/warm-storage-deploy-view.sh
index 5db5b7ef..f25abb6a 100755
--- a/service_contracts/tools/deploy-warm-storage-view.sh
+++ b/service_contracts/tools/warm-storage-deploy-view.sh
@@ -24,6 +24,11 @@ if [ -z "$CHAIN" ]; then
fi
fi
+# Load deployments.json helpers and populate defaults if available
+SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")"
+source "$SCRIPT_DIR/deployments.sh"
+load_deployment_addresses "$CHAIN"
+
if [ -z "$FWSS_PROXY_ADDRESS" ]; then
echo "Error: FWSS_PROXY_ADDRESS is not set"
exit 1
@@ -47,6 +52,10 @@ export FWSS_VIEW_ADDRESS=$(forge create --password "$PASSWORD" --broadcast --non
echo FilecoinWarmStorageServiceStateView deployed at $FWSS_VIEW_ADDRESS
+# Persist deployment address + metadata
+update_deployment_address "$CHAIN" "FWSS_VIEW_ADDRESS" "$FWSS_VIEW_ADDRESS"
+update_deployment_metadata "$CHAIN"
+
# Automatic contract verification
if [ "${AUTO_VERIFY:-true}" = "true" ]; then
echo
diff --git a/service_contracts/tools/upgrade.sh b/service_contracts/tools/warm-storage-execute-upgrade.sh
similarity index 98%
rename from service_contracts/tools/upgrade.sh
rename to service_contracts/tools/warm-storage-execute-upgrade.sh
index bb8ea307..35941ad0 100755
--- a/service_contracts/tools/upgrade.sh
+++ b/service_contracts/tools/warm-storage-execute-upgrade.sh
@@ -1,6 +1,6 @@
#!/bin/bash
-# upgrade.sh: Completes a pending upgrade
+# warm-storage-execute-upgrade.sh: Completes a pending upgrade
# Required args: ETH_RPC_URL, FWSS_PROXY_ADDRESS, ETH_KEYSTORE, PASSWORD, NEW_WARM_STORAGE_IMPLEMENTATION_ADDRESS
# Optional args: NEW_FWSS_VIEW_ADDRESS
# Calculated if unset: CHAIN, FWSS_VIEW_ADDRESS
diff --git a/service_contracts/tools/set-warm-storage-view.sh b/service_contracts/tools/warm-storage-set-view.sh
similarity index 84%
rename from service_contracts/tools/set-warm-storage-view.sh
rename to service_contracts/tools/warm-storage-set-view.sh
index 01c6efdf..35484d88 100755
--- a/service_contracts/tools/set-warm-storage-view.sh
+++ b/service_contracts/tools/warm-storage-set-view.sh
@@ -25,6 +25,11 @@ if [ -z "$CHAIN" ]; then
fi
fi
+# Load deployments.json helpers and populate defaults if available
+SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")"
+source "$SCRIPT_DIR/deployments.sh"
+load_deployment_addresses "$CHAIN"
+
if [ -z "$FWSS_PROXY_ADDRESS" ]; then
echo "Error: FWSS_PROXY_ADDRESS is not set"
exit 1
@@ -55,6 +60,8 @@ TX_OUTPUT=$(cast send --password "$PASSWORD" --nonce $NONCE $FWSS_PROXY_ADDRESS
if [ $? -eq 0 ]; then
echo "View contract address set successfully"
+ update_deployment_address "$CHAIN" "FWSS_VIEW_ADDRESS" "$FWSS_VIEW_ADDRESS"
+ update_deployment_metadata "$CHAIN"
else
echo "Error: Failed to set view contract address"
echo "$TX_OUTPUT"