Skip to content

Migration Guide

If you are coming from an earlier version of any of the Synapse packages, you will need to make sure to update the APIs listed below.


Action: Migrate paginated reads to cursors and pages

Section titled “Action: Migrate paginated reads to cursors and pages”

Paginated actions in @filoz/synapse-core now share a bounded cursor interface:

type PaginationOptions = {
cursor?: bigint
limit?: bigint
}
type Page<T> = {
items: T[]
nextCursor?: bigint
}

Replace contract-specific offset, hasMore, and array result handling with cursor, items, and nextCursor. Treat nextCursor as opaque and pass it back unchanged. Omitting limit uses a bounded default; limit: 0n is now rejected instead of meaning “fetch everything.”

// before
const dataSets = await getClientDataSets(client, {
address,
offset: 0n,
limit: 0n,
})
// after: read one page
const page = await getClientDataSets(client, {
address,
limit: 100n,
})
console.log(page.items)
const nextPage = page.nextCursor === undefined
? undefined
: await getClientDataSets(client, {
address,
cursor: page.nextCursor,
limit: 100n,
})

Use the generic paginate() generator to traverse every page or accumulate all items:

import { paginate } from '@filoz/synapse-core'
import { getClientDataSets } from '@filoz/synapse-core/warm-storage'
for await (const dataSet of paginate(({ cursor }) =>
getClientDataSets(client, { address, cursor })
)) {
console.log(dataSet.dataSetId)
}
const allDataSets = await Array.fromAsync(
paginate(({ cursor }) => getClientDataSets(client, { address, cursor }))
)

This result change applies to paginated payment rails, FWSS client data sets and approved providers, PDP pieces and CID matches, and service-provider registry queries. Payment rail pages additionally include total.

The WarmStorageService.getClientDataSets() and getClientDataSetIds() methods in @filoz/synapse-sdk expose the same page interface. Higher-level SDK methods whose names promise all results, such as provider listing and rail listing methods, continue to return complete arrays and paginate internally.

Action: Replace getActivePieces with getActivePiecesByCursor

Section titled “Action: Replace getActivePieces with getActivePiecesByCursor”

The offset-based getActivePieces action was removed. Use piece-ID cursor pagination instead:

// before
const result = await getActivePieces(client, {
dataSetId,
offset: 0n,
limit: 100n,
})
// after
const page = await getActivePiecesByCursor(client, {
dataSetId,
limit: 100n,
})
// iterate
for await (const piece of paginate(({ cursor }) =>
getActivePiecesByCursor(client, { dataSetId, cursor, limit: 100n })
)) {
console.log(piece.id, piece.cid)
}

findPieceIdsByCid, getPieces, and getPiecesWithMetadata also return pages and accept cursor rather than startPieceId or offset at the action level.

Raw *Call helpers in @filoz/synapse-core remain ABI-oriented: provide their required contract-facing offset or startPieceId and limit fields explicitly when constructing multicalls.

Action: Replace core activePieceCount with hasActivePieces

Section titled “Action: Replace core activePieceCount with hasActivePieces”

The enriched PdpDataSet values returned by getPdpDataSet() and getPdpDataSets() no longer include an exact activePieceCount. They now expose hasActivePieces, derived from a non-zero getDataSetLeafCount read. Leaf count is an O(1) storage lookup, unlike getActivePiecesByCursor and getActivePieceCount, which scan piece IDs and can run out of gas on large or fully drained data sets:

// before
const dataSet = await getPdpDataSet(client, { dataSetId })
if (dataSet && dataSet.activePieceCount > 0n) {
// the data set has pieces
}
// after
const dataSet = await getPdpDataSet(client, { dataSetId })
if (dataSet?.hasActivePieces) {
// the data set has pieces
}

WarmStorageService.hasActivePieces() keeps the same public API, but now uses the same leaf-count proxy instead of calculating an exact count. EnhancedDataSetInfo from getClientDataSetsWithDetails() / findDataSets() also exposes hasActivePieces instead of activePieceCount.

The core getActivePieceCount() action remains available, but the underlying contract getter scans the data set’s piece-ID range and can fail for large data sets. WarmStorageService.getActivePieceCount() now paginates getActivePiecesByCursor to derive an exact count:

const activePieceCount = await warmStorageService.getActivePieceCount({ dataSetId })

To paginate explicitly in core:

let activePieceCount = 0n
for await (const _piece of paginate(({ cursor }) =>
getActivePiecesByCursor(client, { dataSetId, cursor })
)) {
activePieceCount++
}

Action: Replace terminateDataSet with terminateService

Section titled “Action: Replace terminateDataSet with terminateService”

Data set termination is now service termination. terminateDataSet was removed.

// before
const hash = await synapse.storage.terminateDataSet({ dataSetId })
await synapse.client.waitForTransactionReceipt({ hash })
// after: provider-relayed by default
const result = await synapse.storage.terminateService({ dataSetId })
console.log(result.endEpoch)
// independent on-chain fallback
const direct = await synapse.storage.terminateService({ dataSetId, onChain: true })
console.log(direct.txHash, direct.endEpoch)

context.terminate() now uses the same provider-relayed default and returns { txHash?, dataSetId, endEpoch }.

getServicePrice() was removed from both @filoz/synapse-core and WarmStorageService. Use getPriceList(), which returns the full on-chain price catalogue (token, rates, fees, lockups).

// before
const price = await warmStorage.getServicePrice()
price.pricePerTiBPerMonthNoCDN
price.pricePerTiBCdnEgress
// after
const priceList = await warmStorage.getPriceList()
priceList.rates.storagePerTibPerMonth
priceList.rates.cdnEgressPerTib

The React useServicePrice() hook was removed in favor of usePriceList().

// before
import { useServicePrice } from '@filoz/synapse-react'
const { data } = useServicePrice()
data?.pricePerTiBPerMonthNoCDN
// after
import { usePriceList } from '@filoz/synapse-react'
const { data } = usePriceList()
data?.rates.storagePerTibPerMonth

Action: Read upload rates from costs.rates

Section titled “Action: Read upload rates from costs.rates”

The rate alias on upload-cost results was removed. Use rates.

// before
const { costs } = await synapse.storage.prepare({ dataSize })
costs.rate.perMonth
// after
const { costs } = await synapse.storage.prepare({ dataSize })
costs.rates.perMonth

Action: Replace the LOCKUP_PERIOD constant

Section titled “Action: Replace the LOCKUP_PERIOD constant”

The LOCKUP_PERIOD export was removed from @filoz/synapse-core. The lockup period is now read from the chain; use getPriceList().lockups.defaultLockupPeriod if you need the value.

Action: Re-mint session keys for service termination

Section titled “Action: Re-mint session keys for service termination”

DeleteDataSetPermission has been replaced by TerminateServicePermission.

Existing session keys granted with DeleteDataSetPermission will fail the Synapse.create() permission check. Re-authorize session keys so they include TerminateServicePermission.

// before
SessionKey.DeleteDataSetPermission
TypedData.signDeleteDataSet(client, { dataSetId })
// after
SessionKey.TerminateServicePermission
TypedData.signTerminateService(client, { dataSetId })

synapse-sdk moved to a viem-first API, removed deprecated modules/methods, and standardized method signatures around options objects plus bigint identifiers.

Action: Migrate from ethers setup to viem setup

Section titled “Action: Migrate from ethers setup to viem setup”
// before
import { Synapse } from '@filoz/synapse-sdk'
const synapse = await Synapse.create({
privateKey: PRIVATE_KEY,
rpcURL: 'https://api.calibration.node.glif.io/rpc/v1'
})
// after
import { calibration } from '@filoz/synapse-sdk'
import { privateKeyToAccount } from 'viem/accounts'
import { http } from 'viem'
import { Synapse } from '@filoz/synapse-sdk'
const synapse = Synapse.create({
account: privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`),
source: 'my-app',
chain: calibration, // optional
transport: http() // optional
})

Action: Remove deprecated SDK module imports

Section titled “Action: Remove deprecated SDK module imports”

The following subpath exports were removed from @filoz/synapse-sdk:

  • @filoz/synapse-sdk/pdp
  • @filoz/synapse-sdk/subgraph
  • @filoz/synapse-sdk/telemetry
// before
import { PDPAuthHelper, PDPServer, PDPVerifier } from '@filoz/synapse-sdk/pdp'
import { SubgraphService } from '@filoz/synapse-sdk/subgraph'
import { getGlobalTelemetry } from '@filoz/synapse-sdk/telemetry'
// after
import { Synapse } from '@filoz/synapse-sdk'
import { PaymentsService } from '@filoz/synapse-sdk/payments'
import { SPRegistryService } from '@filoz/synapse-sdk/sp-registry'
import { StorageContext, StorageManager } from '@filoz/synapse-sdk/storage'
import { WarmStorageService } from '@filoz/synapse-sdk/warm-storage'

Action: Convert positional parameters to object parameters

Section titled “Action: Convert positional parameters to object parameters”

Most service methods now take an options object. IDs are now bigint in the public API.

// before
await synapse.storage.download(pieceCid, { withCDN: true })
await synapse.payments.allowance(spender)
await synapse.payments.settle(12, 5000)
await synapse.providers.getProvider(1)
// after
await synapse.storage.download({ pieceCid, withCDN: true })
await synapse.payments.allowance({ spender })
await synapse.payments.settle({ railId: 12n, untilEpoch: 5000n })
await synapse.providers.getProvider({ providerId: 1n })

This change applies broadly across:

  • PaymentsService
  • WarmStorageService
  • SPRegistryService
  • retrievers and storage download APIs

Action: Replace removed deprecated methods

Section titled “Action: Replace removed deprecated methods”

Deprecated methods that were previously shimmed were removed from Synapse.

// before
const storage = await synapse.createStorage({ providerId: 1 })
const data = await synapse.download(pieceCid)
const info = await synapse.getStorageInfo()
// after
const context = await synapse.storage.createContext({ providerId: 1n })
const data = await synapse.storage.download({ pieceCid })
const info = await synapse.storage.getStorageInfo()

Action: Update dataset and callback assumptions

Section titled “Action: Update dataset and callback assumptions”
// before
if (dataSet.currentPieceCount > 0) {
// ...
}
callbacks: {
onPieceAdded: () => {},
onPieceConfirmed: () => {}
}
// after
if (dataSet.activePieceCount > 0n) {
// ...
}
callbacks: {
onPiecesAdded: (txHash, pieces) => {},
onPiecesConfirmed: (dataSetId, pieces) => {}
}
  1. Replace ethers-based initialization (privateKey/provider/signer) with viem (account + transport + chain).
  2. Remove imports from @filoz/synapse-sdk/pdp, @filoz/synapse-sdk/subgraph, and @filoz/synapse-sdk/telemetry.
  3. Migrate method calls to options-object style and switch numeric IDs to bigint.
  4. Replace removed deprecated methods (synapse.createStorage, synapse.download, synapse.getStorageInfo) with synapse.storage.*.
  5. Update dataset field usage (currentPieceCount -> activePieceCount) and callback names (onPieceAdded/onPieceConfirmed -> plural callbacks).

Starting with version 0.24.0, the SDK introduces comprehensive terminology changes to better align with Filecoin ecosystem conventions:

  • PandoraWarm Storage
  • Proof SetsData Sets
  • RootsPieces
  • Storage ProvidersService Providers
    • Note: most service providers are, in fact, storage providers, however this language reflects the emergence of new service types on Filecoin beyond storage.

This is a breaking change that affects imports, type names, method names, and configuration options throughout the SDK.

Before (v0.23.x and earlier):

import { PandoraService } from '@filoz/synapse-sdk/pandora'

After (v0.24.0+):

import { WarmStorageService } from '@filoz/synapse-sdk/warm-storage'
Old Type (< v0.24.0)New Type (v0.24.0+)
ProofSetIdDataSetId
RootDataPieceData
ProofSetInfoDataSetInfo
EnhancedProofSetInfoEnhancedDataSetInfo
ProofSetCreationStatusResponseDataSetCreationStatusResponse
RootAdditionStatusResponsePieceAdditionStatusResponse
StorageProviderServiceProvider

Synapse Class:

// Before (< v0.24.0)
synapse.getPandoraAddress()
// After (v0.24.0+)
synapse.getWarmStorageAddress()

WarmStorageService (formerly PandoraService):

// Before (< v0.24.0)
pandoraService.getClientProofSets(client)
pandoraService.getAddRootsInfo(proofSetId)
// After (v0.24.0+)
warmStorageService.getClientDataSets(client)
warmStorageService.getAddPiecesInfo(dataSetId)

PDPAuthHelper:

// Before (< v0.24.0)
authHelper.signCreateProofSet(serviceProvider, clientDataSetId)
authHelper.signAddRoots(proofSetId, rootData)
// After (v0.24.0+)
authHelper.signCreateDataSet(serviceProvider, clientDataSetId)
authHelper.signAddPieces(dataSetId, pieceData)

PDPServer:

// Before (< v0.24.0)
pdpServer.createProofSet(serviceProvider, clientDataSetId)
pdpServer.addRoots(proofSetId, clientDataSetId, nextRootId, rootData)
// After (v0.24.0+)
pdpServer.createDataSet(clientDataSetId, serviceProvider, metadata, recordKeeper)
pdpServer.addPieces(dataSetId, clientDataSetId, pieceData, metadata)

v0.24.0 introduces the SPRegistryService for on-chain provider management:

import { SPRegistryService } from '@filoz/synapse-sdk/sp-registry'
// Query and manage providers through the registry
const spRegistry = new SPRegistryService(provider, registryAddress)
const providers = await spRegistry.getAllActiveProviders()

This replaces previous provider discovery methods and provides a standardized way to register and manage service providers on-chain.

StorageService Properties:

// Before (< v0.24.0)
storage.storageProvider // Provider address property
// After (v0.24.0+)
storage.serviceProvider // Renamed property

Callback Interfaces:

// Before (< v0.24.0)
onProofSetResolved?: (info: { proofSetId: number }) => void
// After (v0.24.0+)
onDataSetResolved?: (info: { dataSetId: number }) => void

Before (< v0.24.0):

const synapse = await Synapse.create({
pandoraAddress: '0x...',
// ...
})

After (v0.24.0+):

const synapse = await Synapse.create({
warmStorageAddress: '0x...',
// ...
})

Before (< v0.24.0):

import { PandoraService } from '@filoz/synapse-sdk/pandora'
import type { StorageProvider } from '@filoz/synapse-sdk'
const pandoraService = new PandoraService(provider, pandoraAddress)
const proofSets = await pandoraService.getClientProofSets(client)
for (const proofSet of proofSets) {
console.log(`Proof set ${proofSet.railId} has ${proofSet.rootMetadata.length} roots`)
}
// Using storage service
const storage = await synapse.createStorage({
callbacks: {
onProofSetResolved: (info) => {
console.log(`Using proof set ${info.proofSetId}`)
}
}
})
console.log(`Storage provider: ${storage.storageProvider}`)

After (v0.24.0+):

import { WarmStorageService } from '@filoz/synapse-sdk/warm-storage'
import type { ServiceProvider } from '@filoz/synapse-sdk'
const warmStorageService = await WarmStorageService.create(provider, warmStorageAddress)
const dataSets = await warmStorageService.getClientDataSets(client)
for (const dataSet of dataSets) {
console.log(`Data set ${dataSet.railId} has ${dataSet.pieceMetadata.length} pieces`)
}
// Using new storage context API
const context = await synapse.storage.createContext({
callbacks: {
onDataSetResolved: (info) => {
console.log(`Using data set ${info.dataSetId}`)
}
}
})
console.log(`Service provider: ${context.serviceProvider}`)
// Downloads now use clearer method names
const data = await context.download(pieceCid) // Download from this context's provider
const anyData = await synapse.storage.download(pieceCid) // Download from any provider

The storage API has been redesigned for simplicity and clarity:

Simplified Storage API:

// Before (< v0.24.0)
const storage = await synapse.createStorage()
await storage.upload(data)
await storage.providerDownload(pieceCid) // Confusing method name
await synapse.download(pieceCid) // Duplicate functionality
// After (v0.24.0+) - Recommended approach
await synapse.storage.upload(data) // Simple: auto-managed contexts
await synapse.storage.download(pieceCid) // Simple: download from anywhere
// Advanced usage (when you need explicit control)
const context = await synapse.storage.createContext({ providerAddress: '0x...' })
await context.upload(data) // Upload to specific provider
await context.download(pieceCid) // Download from specific provider

Key improvements:

  • Access all storage operations via synapse.storage
  • Automatic context management - no need to explicitly create contexts for basic usage
  • Clear separation between SP-agnostic downloads (synapse.storage.download()) and context-specific downloads (context.download())

When upgrading from versions prior to v0.24.0:

  1. Update imports - Replace @filoz/synapse-sdk/pandora with @filoz/synapse-sdk/warm-storage
  2. Update type references:
    • Replace all ProofSet/proofSet with DataSet/dataSet
    • Replace all Root/root with Piece/piece
    • Replace StorageProvider type with ServiceProvider
  3. Update interface properties:
    • ApprovedProviderInfo.ownerApprovedProviderInfo.serviceProvider
    • ApprovedProviderInfo.pdpUrlApprovedProviderInfo.serviceURL
    • storage.storageProviderstorage.serviceProvider
  4. Update callback names:
    • onProofSetResolvedonDataSetResolved
    • Callback parameter proofSetIddataSetId
  5. Simplify storage API calls:
    • synapse.createStorage()synapse.storage.upload() (for simple usage)
    • synapse.createStorage()synapse.storage.createContext() (for advanced usage)
    • storage.providerDownload()context.download()
    • synapse.download()synapse.storage.download()
  6. Update method calls - Use the new method names as shown above
  7. Update configuration - Replace pandoraAddress with warmStorageAddress
  8. Update environment variables - PANDORA_ADDRESSWARM_STORAGE_ADDRESS
  9. Update GraphQL queries (if using subgraph) - proofSetsdataSets, rootspieces

All PaymentsService methods now consistently place the token parameter last with USDFC as the default:

Before (< v0.24.0):

await payments.allowance(TOKENS.USDFC, spender)
await payments.approve(TOKENS.USDFC, spender, amount)
await payments.deposit(amount, TOKENS.USDFC, callbacks)

After (v0.24.0+):

await payments.allowance(spender) // USDFC is default
await payments.approve(spender, amount) // USDFC is default
await payments.deposit(amount, TOKENS.USDFC, callbacks) // callbacks last for deposit

The SDK now automatically discovers all necessary contract addresses. The warmStorageAddress option in Synapse.create() has been removed as addresses are managed internally by the SDK for each network.

Note: There is no backward compatibility layer. All applications must update to the new terminology and API signatures when upgrading to v0.24.0 or later.