Skip to content

Commit ced63da

Browse files
rjan90SgtPooki
andauthored
feat: add --network flag for mainnet and calibration network selection (#240)
* feat: add --network flag for mainnet and calibration network selection Add support for selecting Filecoin network via --network flag or NETWORK environment variable. Users can now easily switch between mainnet and calibration testnet without manually specifying RPC URLs. feat: add --network flag for mainnet and calibration network selection * fix: format long option strings in CLI commands Split long .option() calls across multiple lines to satisfy Biome formatter requirements in server.ts and cli-options.ts. * fix: create re-usable network option with ENV and choice validation * chore: fix lint * fix: help output for network option * fix: getRpcUrl returns url immediately if given --------- Co-authored-by: Russell Dempsey <[email protected]>
1 parent 996af92 commit ced63da

File tree

7 files changed

+143
-20
lines changed

7 files changed

+143
-20
lines changed

README.md

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
## Status
88

9-
**⚠️ Not ready yet for production** - At least as of 2025-10-15, Filecoin Pin runs on Filecoin Calibration testnet only. It's not ready for production use yet.
9+
**⚠️ Not ready yet for production** - Filecoin Pin supports both Filecoin Mainnet and Calibration testnet. The CLI defaults to Calibration testnet for safety, but you can use `--network mainnet` to connect to Mainnet, but filecoin-pin is not ready for production use yet.
1010

1111
Register for updates and a later 2025 Q4 GA announcement at [filecoin.cloud](https://filecoin.cloud/).
1212

@@ -125,9 +125,13 @@ If using a different affordance like the CLI or example GitHub Action, then the
125125
### Prerequisites
126126

127127
- **Node.js 24+** for CLI and library usage
128-
- **Filecoin Calibration testnet wallet** with:
129-
- Test FIL for transaction gas ([Faucet](https://faucet.calibnet.chainsafe-fil.io/funds.html))
130-
- Test USDFC stablecoin for storage payments ([USDFC Faucet](https://forest-explorer.chainsafe.dev/faucet/calibnet_usdfc))
128+
- **Filecoin wallet** (Calibration testnet or Mainnet) with:
129+
- **For Calibration testnet:**
130+
- Test FIL for transaction gas ([Faucet](https://faucet.calibnet.chainsafe-fil.io/funds.html))
131+
- Test USDFC stablecoin for storage payments ([USDFC Faucet](https://forest-explorer.chainsafe.dev/faucet/calibnet_usdfc))
132+
- **For Mainnet:**
133+
- FIL for transaction gas
134+
- USDFC stablecoin for storage payments
131135

132136
### Installation
133137

@@ -143,11 +147,14 @@ npm install -g filecoin-pin
143147
# 1. Configure payment permissions (one-time setup)
144148
filecoin-pin payments setup --auto
145149

146-
# 2. Upload a file to Filecoin
150+
# 2. Upload a file to Filecoin (defaults to Calibration testnet)
147151
filecoin-pin add myfile.txt
148152

149153
# 3. Verify storage with cryptographic proofs
150154
filecoin-pin data-set <dataset-id>
155+
156+
# To use Mainnet instead:
157+
filecoin-pin add myfile.txt --network mainnet
151158
```
152159

153160
For detailed guides, see:
@@ -159,13 +166,47 @@ Configuration of the Filecoin Pin CLI can be performed either with arguments, or
159166

160167
The Pinning Server requires the use of environment variables, as detailed below.
161168

169+
### Network Selection
170+
171+
Filecoin Pin supports both **Mainnet** and **Calibration testnet**. By default, the CLI uses Calibration testnet during development.
172+
173+
**Using the CLI:**
174+
```bash
175+
# Use Calibration testnet (default)
176+
filecoin-pin add myfile.txt
177+
178+
# Use Mainnet
179+
filecoin-pin add myfile.txt --network mainnet
180+
181+
# Explicitly specify Calibration
182+
filecoin-pin add myfile.txt --network calibration
183+
```
184+
185+
**Using environment variables:**
186+
```bash
187+
# Set network via environment variable
188+
export NETWORK=mainnet
189+
filecoin-pin add myfile.txt
190+
191+
# Or override RPC URL directly
192+
export RPC_URL=wss://wss.node.glif.io/apigw/lotus/rpc/v1
193+
filecoin-pin add myfile.txt
194+
```
195+
196+
**Priority order:**
197+
1. `--rpc-url` flag (highest priority)
198+
2. `RPC_URL` environment variable
199+
3. `--network` flag or `NETWORK` environment variable
200+
4. Default to Calibration testnet
201+
162202
### Common CLI Arguments
163203

164204
* `-h`, `--help`: Display help information for each command
165205
* `-V`, `--version`: Output the version number
166206
* `-v`, `--verbose`: Verbose output
167207
* `--private-key`: Ethereum-style (`0x`) private key, funded with USDFC (required)
168-
* `--rpc-url`: Filecoin RPC endpoint (default: Calibration testnet)
208+
* `--network`: Filecoin network to use: `mainnet` or `calibration` (default: `calibration`)
209+
* `--rpc-url`: Filecoin RPC endpoint (overrides `--network` if specified)
169210

170211
Other arguments are possible for individual commands, use `--help` to find out more.
171212

@@ -175,8 +216,11 @@ Other arguments are possible for individual commands, use `--help` to find out m
175216
# Required
176217
PRIVATE_KEY=0x... # Ethereum private key with USDFC tokens
177218

178-
# Optional
179-
RPC_URL=wss://... # Filecoin RPC endpoint (default: Calibration testnet)
219+
# Optional - Network Configuration
220+
NETWORK=mainnet # Network to use: mainnet or calibration (default: calibration)
221+
RPC_URL=wss://... # Filecoin RPC endpoint (overrides NETWORK if specified)
222+
# Mainnet: wss://wss.node.glif.io/apigw/lotus/rpc/v1
223+
# Calibration: wss://wss.calibration.node.glif.io/apigw/lotus/rpc/v1
180224

181225
# Optional for Pinning Server Daemon
182226
PORT=3456 # Daemon server port

src/commands/server.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { RPC_URLS } from '@filoz/synapse-sdk'
22
import { Command } from 'commander'
33
import { startServer } from '../server.js'
4+
import { addNetworkOptions } from '../utils/cli-options.js'
45

56
export const serverCommand = new Command('server')
67
.description('Start the IPFS Pinning Service API server')
@@ -9,14 +10,23 @@ export const serverCommand = new Command('server')
910
.option('--car-storage <path>', 'path for CAR file storage', './cars')
1011
.option('--database <path>', 'path to SQLite database', './pins.db')
1112
.option('--private-key <key>', 'private key for Synapse (or use PRIVATE_KEY env var)')
12-
.option('--rpc-url <url>', 'RPC URL for Filecoin network', RPC_URLS.calibration.websocket)
13+
14+
addNetworkOptions(serverCommand)
15+
.option(
16+
'--rpc-url <url>',
17+
'RPC URL for Filecoin network (overrides --network, can also use RPC_URL env)',
18+
RPC_URLS.calibration.websocket
19+
)
1320
.action(async (options) => {
1421
// Override environment variables with CLI options if provided
1522
if (options.privateKey) {
1623
process.env.PRIVATE_KEY = options.privateKey
1724
}
25+
// RPC URL takes precedence over network flag
1826
if (options.rpcUrl) {
1927
process.env.RPC_URL = options.rpcUrl
28+
} else if (options.network) {
29+
process.env.NETWORK = options.network
2030
}
2131
if (options.carStorage) {
2232
process.env.CAR_STORAGE_PATH = options.carStorage

src/common/get-rpc-url.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { RPC_URLS } from '@filoz/synapse-sdk'
2+
import type { CLIAuthOptions } from '../utils/cli-auth.js'
3+
4+
/**
5+
* Get the RPC URL from the CLI options and environment variables
6+
*
7+
* Network selection priority:
8+
* 1. Explicit --rpc-url (highest priority)
9+
* 2. RPC_URL environment variable
10+
* 3. --network flag or NETWORK environment variable (converted to RPC URL)
11+
* 4. Default to calibration
12+
*/
13+
export function getRpcUrl(options: CLIAuthOptions): string {
14+
// Determine RPC URL with priority: explicit rpcUrl > RPC_URL env > network flag/env > default
15+
let rpcUrl: string | undefined
16+
if (options.rpcUrl || process.env.RPC_URL) {
17+
// Explicit RPC URL takes highest priority
18+
rpcUrl = options.rpcUrl || process.env.RPC_URL
19+
}
20+
if (rpcUrl) {
21+
return rpcUrl
22+
}
23+
// Try to use network flag/env var
24+
const network = (options.network || process.env.NETWORK)?.toLowerCase().trim()
25+
if (network) {
26+
// Validate network value
27+
if (network !== 'mainnet' && network !== 'calibration') {
28+
throw new Error(`Invalid network: "${network}". Must be "mainnet" or "calibration"`)
29+
}
30+
// Convert network to RPC URL
31+
rpcUrl = RPC_URLS[network as 'mainnet' | 'calibration']?.websocket
32+
if (!rpcUrl) {
33+
throw new Error(`RPC URL not available for network: "${network}"`)
34+
}
35+
return rpcUrl
36+
}
37+
38+
return RPC_URLS.calibration.websocket
39+
}

src/config.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { homedir, platform } from 'node:os'
22
import { join } from 'node:path'
3-
import { RPC_URLS } from '@filoz/synapse-sdk'
3+
import { getRpcUrl } from './common/get-rpc-url.js'
44
import type { Config } from './core/synapse/index.js'
55

66
function getDataDirectory(): string {
@@ -31,20 +31,27 @@ function getDataDirectory(): string {
3131
*
3232
* This demonstrates configuration best practices for Synapse SDK:
3333
* - PRIVATE_KEY: Required for transaction signing (keep secure!)
34-
* - RPC_URL: Filecoin network endpoint (mainnet or calibration)
34+
* - RPC_URL: Filecoin network endpoint (mainnet or calibration) - takes precedence over NETWORK
35+
* - NETWORK: Filecoin network name (mainnet or calibration) - used if RPC_URL not set
3536
* - WARM_STORAGE_ADDRESS: Optional override for testing custom contracts
3637
*/
3738
export function createConfig(): Config {
3839
const dataDir = getDataDirectory()
3940

41+
// Determine RPC URL: RPC_URL env var takes precedence, then NETWORK, then default to calibration
42+
const rpcUrl = getRpcUrl({
43+
network: process.env.NETWORK,
44+
rpcUrl: process.env.RPC_URL,
45+
})
46+
4047
return {
4148
// Application-specific configuration
4249
port: parseInt(process.env.PORT ?? '3456', 10),
4350
host: process.env.HOST ?? 'localhost',
4451

4552
// Synapse SDK configuration
4653
privateKey: process.env.PRIVATE_KEY, // Required: Ethereum-compatible private key
47-
rpcUrl: process.env.RPC_URL ?? RPC_URLS.calibration.websocket, // Default: calibration testnet websocket
54+
rpcUrl, // Determined from RPC_URL, NETWORK, or default to calibration
4855
warmStorageAddress: process.env.WARM_STORAGE_ADDRESS, // Optional: custom contract address
4956

5057
// Storage paths

src/test/mocks/synapse-sdk.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ export const RPC_URLS = {
8282
calibration: {
8383
websocket: 'wss://wss.calibration.node.glif.io/apigw/lotus/rpc/v1',
8484
},
85+
mainnet: {
86+
websocket: 'wss://wss.node.glif.io/apigw/lotus/rpc/v1',
87+
},
8588
}
8689

8790
// Export mock METADATA_KEYS matching SDK's structure

src/utils/cli-auth.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import type { Synapse } from '@filoz/synapse-sdk'
99
import { TELEMETRY_CLI_APP_NAME } from '../common/constants.js'
10+
import { getRpcUrl } from '../common/get-rpc-url.js'
1011
import type { SynapseSetupConfig } from '../core/synapse/index.js'
1112
import { initializeSynapse } from '../core/synapse/index.js'
1213
import { createLogger } from '../logger.js'
@@ -22,7 +23,9 @@ export interface CLIAuthOptions {
2223
walletAddress?: string | undefined
2324
/** Session key private key */
2425
sessionKey?: string | undefined
25-
/** RPC endpoint URL */
26+
/** Filecoin network: mainnet or calibration */
27+
network?: string | undefined
28+
/** RPC endpoint URL (overrides network if specified) */
2629
rpcUrl?: string | undefined
2730
/** Optional warm storage address override */
2831
warmStorageAddress?: string | undefined
@@ -48,9 +51,10 @@ export function parseCLIAuth(options: CLIAuthOptions): Partial<SynapseSetupConfi
4851
const privateKey = options.privateKey || process.env.PRIVATE_KEY
4952
const walletAddress = options.walletAddress || process.env.WALLET_ADDRESS
5053
const sessionKey = options.sessionKey || process.env.SESSION_KEY
51-
const rpcUrl = options.rpcUrl || process.env.RPC_URL
5254
const warmStorageAddress = options.warmStorageAddress || process.env.WARM_STORAGE_ADDRESS
5355

56+
const rpcUrl = getRpcUrl(options)
57+
5458
// Build config - only include defined values, validation happens in initializeSynapse()
5559
const config: any = {}
5660

src/utils/cli-options.ts

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*/
77

88
import { RPC_URLS } from '@filoz/synapse-sdk'
9-
import type { Command } from 'commander'
9+
import { type Command, Option } from 'commander'
1010

1111
/**
1212
* Decorator to add common authentication options to a Commander command
@@ -15,7 +15,8 @@ import type { Command } from 'commander'
1515
* - --private-key for standard authentication
1616
* - --wallet-address for session key authentication
1717
* - --session-key for session key authentication
18-
* - --rpc-url for network configuration
18+
* - --network for network selection (mainnet or calibration)
19+
* - --rpc-url for network configuration (overrides --network)
1920
*
2021
* The function modifies the command in-place and returns it for chaining.
2122
*
@@ -29,20 +30,26 @@ import type { Command } from 'commander'
2930
* .description('Do something')
3031
* .option('--my-option <value>', 'My custom option')
3132
* .action(async (options) => {
32-
* // options will include: privateKey, walletAddress, sessionKey, rpcUrl, myOption
33-
* const { privateKey, walletAddress, sessionKey, rpcUrl, myOption } = options
33+
* // options will include: privateKey, walletAddress, sessionKey, network, rpcUrl, myOption
34+
* const { privateKey, walletAddress, sessionKey, network, rpcUrl, myOption } = options
3435
* })
3536
*
3637
* // Add authentication options after the command is fully defined
3738
* addAuthOptions(myCommand)
3839
* ```
3940
*/
4041
export function addAuthOptions(command: Command): Command {
41-
return command
42+
command
4243
.option('--private-key <key>', 'Private key for standard auth (can also use PRIVATE_KEY env)')
4344
.option('--wallet-address <address>', 'Wallet address for session key auth (can also use WALLET_ADDRESS env)')
4445
.option('--session-key <key>', 'Session key for session key auth (can also use SESSION_KEY env)')
45-
.option('--rpc-url <url>', 'RPC endpoint (can also use RPC_URL env)', RPC_URLS.calibration.websocket)
46+
47+
return addNetworkOptions(command)
48+
.option(
49+
'--rpc-url <url>',
50+
'RPC endpoint (can also use RPC_URL env, overrides --network)',
51+
RPC_URLS.calibration.websocket
52+
)
4653
.option(
4754
'--warm-storage-address <address>',
4855
'Warm storage contract address override (can also use WARM_STORAGE_ADDRESS env)'
@@ -80,3 +87,12 @@ export function addProviderOptions(command: Command): Command {
8087
)
8188
.option('--provider-id <id>', 'Override provider selection by ID (can also use PROVIDER_ID env)')
8289
}
90+
91+
export function addNetworkOptions(command: Command): Command {
92+
return command.addOption(
93+
new Option('--network <network>', 'Filecoin network to use')
94+
.choices(['mainnet', 'calibration'])
95+
.env('NETWORK')
96+
.default('calibration')
97+
)
98+
}

0 commit comments

Comments
 (0)