Skip to content

Commit 881cf6b

Browse files
authored
docs: update pricing for per-operation fees (#820)
* chore(docs): update latest pricing changes * docs: update pricing docs for per-op model and fix MDX tables Aligns three docs files with the per-op pricing model landed in synapse-sdk#823 (synapse-sdk 1.0.1 / synapse-core 0.7.0): - payments-and-storage.mdx: replace floor/sybil pricing with recurring rates ($2.50/TiB/mo, $0.024/dataset/mo proving) and per-op fees table; update dataset creation cost table; fix CDN unit to $14/TiB - storage-costs.mdx: fix CDN unit, remove stale SDK-update caution, update getUploadCosts() examples to surface fees and lockups fields - about.mdx: add proving-fee conditionality clause, fix CDN unit, mention lockup reserve in per-op fees sentence - astro.config.mjs: add gfm: true to fix MDX table rendering (Astro 6 deprecated but still respects the option via @astrojs/mdx) * docs: say empty data sets have no recurring cost "Free"/"costs nothing" overstated it: an empty data set still pays the one-time creation fee. Reword the storage rows and proving text on the storage-costs, payments-and-storage, and about pages. * docs: drop earlier-pricing comparisons State current pricing only. The old $0.06/month floor comparison adds noise here; release history belongs in a changelog. * docs: note CDN must be enabled at data set creation CDN cannot currently be added to an existing data set; the previous wording implied it could be enabled later. Link FilOzone/filecoin-services#529 so readers can follow or weigh in on changing this. * docs: clarify CDN lockups are refunded only if unused The egress and cache-miss lockups are returned on finalization only to the extent they were not spent. * docs: normalize spelling to US English finalised/finalisation -> finalized/finalization, matching the rest of the repo and this file's existing usage.
1 parent 0ef7a93 commit 881cf6b

4 files changed

Lines changed: 120 additions & 51 deletions

File tree

docs/astro.config.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export default defineConfig({
3030
},
3131
],
3232
],
33+
gfm: true,
3334
},
3435
integrations: [
3536
mermaid({

docs/src/content/docs/cookbooks/payments-and-storage.mdx

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ sidebar:
88
:::tip[What You'll Learn]
99

1010
- The mental model: deposit USDFC, FWSS handles payments to storage providers
11-
- How much storage costs (pricing, floors, CDN)
12-
- What payment rails are and why each dataset has up to three
11+
- How much storage costs (pricing, fees, CDN)
12+
- What payment rails are and why each data set has up to three
1313
- What happens if your account runs low on funds
1414

1515
:::
@@ -41,47 +41,59 @@ This cookbook explains the underlying payment model. For practical code:
4141

4242
## Pricing
4343

44+
Two recurring rates apply per data set:
45+
4446
| Component | Cost | Notes |
4547
| -------------- | -------------------- | ------------------------------------------------------- |
46-
| **Storage** | $2.50/TiB/month | Minimum $0.06/month per dataset (~24.567 GiB threshold) |
47-
| **Sybil fee** | 0.1 USDFC (one-time) | Per new dataset creation; prevents state-growth spam |
48-
| **CDN egress** | $14/TiB downloaded | 1 USDFC top-up ≈ 71.5 GiB of downloads |
49-
| **CDN setup** | 1 USDFC (one-time) | Per dataset; reusing existing datasets incurs no cost |
48+
| **Storage** | $2.50/TiB/month per copy | Charged only while pieces exist. Empty data sets have no recurring cost |
49+
| **Proving Service** | $0.024/data set/month | Flat per-data-set fee, added on top of the storage rate |
50+
| **CDN egress** | up to $14/TiB (≈ $0.014/GiB) downloaded | Optional, via Filecoin Beam. About half this when served from cache |
5051

5152
:::note
5253
"Month" always means exactly **30 days = 86,400 epochs** throughout the system. Filecoin epochs are ~30 seconds each.
5354
:::
5455

55-
### Floor Pricing
56+
Each on-chain operation also pays a small one-time fee to the storage provider, covering the gas it spends on your behalf:
57+
58+
| Operation | Fee |
59+
| -------------- | -------------------- |
60+
| **Create data set** | $0.025 |
61+
| **Add pieces** | $0.0005 + $0.0003 per piece |
62+
| **Schedule piece removals** | $0.002 per call |
63+
| **Terminate service** | $0.00112 (user-initiated only) |
64+
65+
These are fractions of a cent. They are drawn from a ~$0.10 lockup reserve held while the data set is active, not billed separately on each call. See [Storage Costs: How the fees and lockup work](/developer-guides/storage/storage-costs/#how-the-fees-and-lockup-work) for the mechanics.
66+
67+
### Proving Fee
5668

57-
Every dataset has a minimum monthly charge of **$0.06/month**, regardless of size. This compensates storage providers for the overhead of maintaining a dataset. Files under ~24.567 GiB all pay this same floor rate. Above that threshold, the natural rate (`bytes/TiB × $2.50/month`) takes over.
69+
The monthly cost of an active data set is `(bytes / TiB) × $2.50 + $0.024`. There is no minimum floor: a data set with no pieces has no recurring cost, and the rate activates when the first piece is added. The proving fee is a flat addition per data set, on top of the per-size storage rate.
5870

59-
### Dataset Creation Costs
71+
### Data Set Creation Costs
6072

61-
Creating a new dataset requires minimum available funds to cover the initial lockup plus the sybil fee:
73+
Creating a data set locks a small lifecycle reserve. The storage rate starts at zero and is set automatically when you add data:
6274

6375
| Scenario | Minimum Funds Required |
6476
| -------- | ---------------------- |
65-
| No CDN | 0.16 USDFC (0.06 floor lockup + 0.10 sybil fee) |
66-
| With CDN | 1.16 USDFC (0.06 floor + 0.10 sybil + 0.70 CDN + 0.30 cache miss) |
77+
| No CDN | ~0.10 USDFC (lifecycle reserve lockup) |
78+
| With CDN | ~1.10 USDFC (0.10 reserve + 0.70 CDN egress + 0.30 cache-miss) |
6779

68-
The storage rate starts at zero when a dataset is created and is set automatically when you add data.
80+
One-time fees such as the $0.025 creation fee are drawn from the lifecycle reserve, not added on top of these amounts.
6981

7082
## Payment Rails
7183

72-
For each dataset, FWSS creates payment channels called **rails** that stream funds from your account to the storage provider. A dataset can have up to three rails:
84+
For each data set, FWSS creates payment channels called **rails** that stream funds from your account to the storage provider. A data set can have up to three rails:
7385

7486
| Rail | Type | Purpose |
7587
| -------------- | --------- | ---------------------------------------- |
7688
| **PDP rail** | Streaming | Pays for storage at a rate per epoch |
7789
| **CDN rail** | Fixed | 0.7 USDFC lockup for CDN egress credits |
7890
| **Cache miss** | Fixed | 0.3 USDFC lockup for cache miss credits |
7991

80-
Every dataset gets a PDP rail. CDN and cache miss rails are added only when CDN is enabled.
92+
Every data set gets a PDP rail, which also holds the ~$0.10 lifecycle reserve that one-time fees draw from. CDN and cache miss rails are added only when CDN is enabled, which must happen at data set creation. CDN cannot currently be added to an existing data set. Follow [FilOzone/filecoin-services#529](https://github.com/FilOzone/filecoin-services/issues/529) to share your use case or track changes.
8193

8294
FWSS enforces a **30-day lockup period**: your account must always have enough funds to cover at least 30 days of storage at the current rate. Think of it as a security deposit. The funds aren't spent upfront, but they're reserved so providers are guaranteed payment even if you stop topping up.
8395

84-
When you add data to an existing dataset, FWSS automatically adjusts the rail's payment rate. The SDK calculates the correct deposit amount for you via `getUploadCosts()` and `prepare()`.
96+
When you add data to an existing data set, FWSS automatically adjusts the rail's payment rate. The SDK calculates the correct deposit amount for you via `getUploadCosts()` and `prepare()`.
8597

8698
## Operator Approval
8799

docs/src/content/docs/developer-guides/storage/storage-costs.mdx

Lines changed: 86 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,38 @@ An **epoch** is Filecoin's block time, which is 30 seconds. Storage costs are ca
1919

2020
## Pricing Components
2121

22+
Pricing has two recurring rates and a set of small one-time fees.
23+
24+
### Recurring rates
25+
2226
| Component | Cost | Notes |
2327
| -------------- | ------------------ | -------------------------------------------------------- |
24-
| **Storage** | $2.50/TiB/month | Minimum $0.06/month per data set (~24.567 GiB threshold) |
25-
| **Sybil Fee** | 0.1 USDFC (one-time) | Per new data set creation; prevents state-growth spam |
26-
| **CDN Egress** | $14/TiB downloaded | 1 USDFC top-up ≈ 71.5 GiB of downloads |
27-
| **CDN Setup** | 1 USDFC (one-time) | Per data set; reusing existing data sets incurs no cost |
28+
| **Storage** | $2.50/TiB/month per copy | Charged only while pieces exist. Empty data sets have no recurring cost. |
29+
| **Proving Service** | $0.024/data set/month | Flat per-data-set fee, added on top of the storage rate. |
30+
| **CDN egress** | up to $14/TiB (≈ $0.014/GiB) downloaded | Optional, via Filecoin Beam. About half this when served from cache. |
2831

2932
:::note[Be aware]
30-
Per month means **per 30 days** here, not calendar month like a traditional storage service.
33+
"Month" means **30 days** here (86,400 epochs), not a calendar month.
3134
:::
32-
**Pricing Logic:**
3335

34-
- Storage **< 24.567 GiB**: Minimum $0.06/month applies
35-
- Storage **≥ 24.567 GiB**: Actual cost `(bytes / TiB) × $2.50/month`
36-
- CDN data sets require 1 USDFC setup on first creation only
37-
- CDN egress credits can be topped up anytime
36+
The monthly rate for an active data set is `(bytes / TiB) × $2.50 + $0.024`. There is no minimum floor: a data set with no pieces has no recurring cost, and the rate activates when the first piece is added.
37+
38+
### One-time fees
39+
40+
Each on-chain operation pays a small fee to the storage provider, covering the gas that provider spends on your behalf:
41+
42+
| Operation | Fee |
43+
| -------------- | ------------------ |
44+
| **Create data set** | $0.025 |
45+
| **Add pieces** | $0.0005 + $0.0003 per piece |
46+
| **Schedule piece removals** | $0.002 per call |
47+
| **Terminate service** | $0.00112 (user-initiated only) |
48+
49+
These are fractions of a cent. Think of them like gas: negligible for normal use, only adding up at very high operation volumes. They are paid from a small lockup reserve (~$0.10) held while the data set is active, not billed separately on every call. See [How the fees and lockup work](#how-the-fees-and-lockup-work) below.
50+
51+
:::note[CDN setup]
52+
Enabling CDN adds two refundable lockups on first use: ~0.7 USDFC for egress credits and ~0.3 USDFC for cache-miss credits. Reusing an existing CDN data set incurs no new setup. These are lockups, not fees, and are returned when the rail is finalized if unused.
53+
:::
3854

3955
### Real-World Cost Examples
4056

@@ -44,17 +60,25 @@ These examples use plain arithmetic for clarity. For programmatic cost calculati
4460

4561
```ts twoslash
4662
// @lib: esnext,dom
47-
// 48.82 MiB less than 24.567 GiB threshold
48-
// Price is $0.06/month
49-
const PRICE_PER_MONTH = 0.06;
50-
const months = 24;
51-
const PRICE_FOR_24_MONTHS = PRICE_PER_MONTH * 24; // 1.44 USDFC
63+
// 48.82 MiB is tiny, so the storage rate is negligible.
64+
// The recurring cost is dominated by the flat proving fee.
65+
const STORAGE_PRICE_PER_TIB_PER_MONTH = 2.5;
66+
const PROVING_FEE_PER_MONTH = 0.024;
67+
68+
const storageTiB = 48.82 / 1024 / 1024; // ≈ 0.0000466 TiB
69+
const storageCostPerMonth = storageTiB * STORAGE_PRICE_PER_TIB_PER_MONTH; // ≈ $0.00012
70+
71+
// Per copy, per month
72+
const costPerMonth = storageCostPerMonth + PROVING_FEE_PER_MONTH; // ≈ 0.0241 USDFC
73+
const costFor24Months = costPerMonth * 24; // ≈ 0.578 USDFC
5274
```
5375

54-
| Duration | Total Cost |
76+
| Duration | Per copy |
5577
| --------- | ---------- |
56-
| 1 month | 0.06 USDFC |
57-
| 24 months | 1.44 USDFC |
78+
| 1 month | ≈ 0.024 USDFC |
79+
| 24 months | ≈ 0.58 USDFC |
80+
81+
The default 2-copy configuration roughly doubles the recurring cost. One-time fees apply once: $0.025 to create the data set plus the per-batch add-pieces fee.
5882

5983
---
6084

@@ -66,7 +90,8 @@ const PRICE_FOR_24_MONTHS = PRICE_PER_MONTH * 24; // 1.44 USDFC
6690
```ts twoslash
6791
// @lib: esnext,dom
6892
const STORAGE_PRICE_PER_TIB_PER_MONTH = 2.5; // $2.50/TiB/month
69-
const CDN_EGRESS_PRICE_PER_TIB = 14; // $14/TiB downloaded
93+
const PROVING_FEE_PER_MONTH = 0.024; // flat per-data-set
94+
const CDN_EGRESS_PRICE_PER_TIB = 14; // up to $14/TiB on a cache miss
7095
const storageMiB = 100_000;
7196
const egressMiB = 100_000;
7297

@@ -79,27 +104,51 @@ const egressTiB = egressMiB / 1024 / 1024;
79104
// Storage cost per month: 0.0953 TiB × $2.50 ≈ $0.238/month
80105
const storageCostPerMonth = storageTiB * STORAGE_PRICE_PER_TIB_PER_MONTH;
81106

82-
// Egress cost per month: 0.0953 TiB × $14 ≈ $1.334/month
107+
// Egress cost per month (worst case, all cache misses): 0.0953 TiB × $14 ≈ $1.334/month
83108
const egressCostPerMonth = egressTiB * CDN_EGRESS_PRICE_PER_TIB;
84109

85-
// Total cost per month: $0.238/month + $1.334/month ≈ $1.572/month
86-
const totalCostPerMonth = storageCostPerMonth + egressCostPerMonth;
110+
// Total cost per month: $0.238 + $0.024 proving + $1.334 egress ≈ $1.596/month
111+
const totalCostPerMonth = storageCostPerMonth + PROVING_FEE_PER_MONTH + egressCostPerMonth;
87112

88-
// Total cost for 24 months: $1.572/month × 24 ≈ $37.728
113+
// Total cost for 24 months: $1.596/month × 24 ≈ $38.31
89114
const totalCostFor24Months = totalCostPerMonth * 24;
90115
```
91116

92117
| Cost Component | Per Month | 24 Months |
93118
| -------------- | ---------------- | ----------------- |
94119
| Storage | ≈ 0.238 USDFC | ≈ 5.71 USDFC |
120+
| Proving Service | ≈ 0.024 USDFC | ≈ 0.576 USDFC |
95121
| CDN Egress | ≈ 1.334 USDFC | ≈ 32.016 USDFC |
96-
| **Total** | **≈ 1.572 USDFC** | **≈ 37.728 USDFC** |
122+
| **Total** | **≈ 1.596 USDFC** | **≈ 38.31 USDFC** |
123+
124+
Egress here is the worst case where every byte is a cache miss. When content is served from the Filecoin Beam cache, egress is roughly half this.
125+
126+
## How the fees and lockup work
127+
128+
Most developers can stop at the tables above. This section explains the mechanics behind the per-operation fees and the lockup reserve for anyone who needs the detail.
129+
130+
**The proving fee is additive, not a floor.** The rate is `(bytes / TiB) × $2.50 + $0.024`, so storage scales with size and the proving fee is a flat addition per data set. A data set with no pieces has no recurring charge until the first piece is added.
131+
132+
**Add-pieces pricing scales with batch size.** Each `addPieces` call costs `$0.0005 + $0.0003 × N`, where `N` is the number of pieces in the batch. The base fee is shared across the batch, so adding many pieces in one call is cheaper per piece than adding them one at a time. When estimating the cost of a single piece, assume the single-piece price (`$0.0008`); batching only makes it cheaper.
133+
134+
**Fees are paid from a small lockup reserve, not billed per call.** When a data set is created, ~$0.10 of USDFC is locked as a lifecycle reserve on the data set's payment rail. One-time fees are drawn from this reserve as operations happen, and the reserve is topped back up toward its target as it is drawn down. You see ~$0.10 of additional locked USDFC while the data set is active. It is refunded when the rail is finalized.
135+
136+
<details>
137+
<summary>Why the reserve exists: wind-down after termination</summary>
138+
139+
Filecoin Pay does not allow raising a rail's fixed lockup once the rail has been terminated. The lifecycle reserve gives you headroom to run wind-down operations (such as scheduling piece removals) after termination, when the reserve can no longer be refilled.
140+
141+
If you expect to need more wind-down operations than the reserve covers, fund the reserve before terminating. User-initiated termination charges the $0.00112 termination fee and makes a best-effort top-up of the reserve. Provider-initiated termination charges no fee and does not top up, so those data sets are limited to whatever was in the reserve at termination.
142+
143+
For the full lockup model (streaming versus fixed lockup, rail settlement, finalization), see the [Payments & Storage cookbook](/cookbooks/payments-and-storage/) and the [Filecoin Pay spec](https://github.com/FilOzone/filecoin-pay/blob/main/SPEC.md).
144+
145+
</details>
97146

98147
## Querying Upload Costs
99148

100-
Use `getUploadCosts()` to preview costs without executing any transaction. This is useful for displaying pricing in a UI or letting users confirm before proceeding.
149+
Use `getUploadCosts()` to preview costs without executing any transaction. This is useful for displaying pricing in a UI or letting users confirm before proceeding. The result reads the on-chain price list, so it reflects the rates, one-time fees, and lockups described above.
101150

102-
Getting the costs for uploading to an existing dataset:
151+
Getting the costs for uploading to an existing data set:
103152

104153
```ts twoslash
105154
// @lib: esnext,dom
@@ -108,23 +157,23 @@ import { Synapse, SIZE_CONSTANTS } from "@filoz/synapse-sdk"
108157
import { privateKeyToAccount } from 'viem/accounts'
109158
const synapse = Synapse.create({ account: privateKeyToAccount('0x...'), source: 'my-app' })
110159
// ---cut---
111-
// With currentDataSetSize — accurate floor-aware delta
112-
const { rates, depositNeeded } = await synapse.storage.getUploadCosts({
160+
// Pass currentDataSetSize so rates reflect the data set's new total size
161+
const { rates, fees, depositNeeded } = await synapse.storage.getUploadCosts({
113162
isNewDataSet: false,
114163
currentDataSetSize: 50n * SIZE_CONSTANTS.MiB,
115164
dataSize: 100n * SIZE_CONSTANTS.MiB,
116165
})
117-
// Shows incremental cost (newRate - currentRate), handles floor-to-floor
166+
// fees.addPiecesFee is the one-time fee for this upload
167+
// (pass pieceCount when adding more than one piece)
118168

119-
// Without currentDataSetSize — safe overestimate for floor cases
169+
// Without currentDataSetSize, rates cover the new data alone
120170
const costs2 = await synapse.storage.getUploadCosts({
121171
isNewDataSet: false,
122172
dataSize: 100n * SIZE_CONSTANTS.MiB,
123173
})
124-
// Accurate for above-floor datasets, overestimates for floor-priced ones
125174
```
126175

127-
Getting the costs for uploading to a new dataset:
176+
Getting the costs for uploading to a new data set:
128177

129178
```ts twoslash
130179
// @lib: esnext,dom
@@ -133,7 +182,7 @@ import { Synapse, formatUnits, SIZE_CONSTANTS } from "@filoz/synapse-sdk"
133182
import { privateKeyToAccount } from 'viem/accounts'
134183
const synapse = Synapse.create({ account: privateKeyToAccount('0x...'), source: 'my-app' })
135184
// ---cut---
136-
const { rates, depositNeeded, needsFwssMaxApproval, ready } = await synapse.storage.getUploadCosts({
185+
const { rates, fees, lockups, depositNeeded, needsFwssMaxApproval, ready } = await synapse.storage.getUploadCosts({
137186
dataSize: 100n * SIZE_CONSTANTS.MiB,
138187
isNewDataSet: true,
139188
withCDN: true,
@@ -143,6 +192,10 @@ const { rates, depositNeeded, needsFwssMaxApproval, ready } = await synapse.stor
143192
console.log("Rate per epoch:", formatUnits(rates.perEpoch), "USDFC")
144193
// Storage rate per month
145194
console.log("Rate per month:", formatUnits(rates.perMonth), "USDFC")
195+
// One-time fees (create data set + add pieces)
196+
console.log("One-time fees:", formatUnits(fees.total), "USDFC")
197+
// Locked while the data set is active (lifecycle reserve, streaming, CDN)
198+
console.log("Total lockup:", formatUnits(lockups.total), "USDFC")
146199
// USDFC to deposit
147200
console.log("Deposit needed:", formatUnits(depositNeeded), "USDFC")
148201
// Whether FWSS needs to be approved

docs/src/content/docs/introduction/about.mdx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,11 @@ All payments are settled automatically through Filecoin Pay, ensuring on-chain a
6565

6666
| **Service** | **Pricing** | **Description** |
6767
| ------- | --------- | -------------------- |
68-
| **Base Storage & Retrival** | **$2.5/TiB/month/copy** (minimum 2 copies) | Redundant storage ensures durability and continuous PDP verification.<br />Minimum monthly charge of **0.06 USDFC**, covering roughly **24 GiB** of total data (two copies). |
69-
| **Add-on Retrieval (Filecoin Beam)** | **Up to $0.014/GiB egress** | Charged for outbound data delivered via Filecoin Beam gateways or retrieval providers. |
68+
| **Storage** | **$2.50/TiB/month/copy** (minimum 2 copies) | Redundant storage with continuous PDP verification. Empty data sets have no recurring cost; charges begin when the first piece is added. |
69+
| **Proving Service** | **$0.024/data set/month** | Flat per-data-set fee for proof verification, added on top of the storage rate. Charged only while the data set holds pieces. |
70+
| **Add-on Retrieval (Filecoin Beam)** | **Up to $14/TiB (≈ $0.014/GiB) egress** | Outbound data delivered via Filecoin Beam. Roughly half this when served from cache, up to the full rate on a cache miss. |
71+
72+
Beyond these recurring rates, each on-chain operation (creating a data set, adding or removing pieces, terminating service) carries a small one-time fee paid to the storage provider to cover its gas. These fees are fractions of a cent, drawn from a small refundable lockup reserve (~$0.10 USDFC) held while the data set is active, and only matter at very high operation volumes. See [Storage Costs](/developer-guides/storage/storage-costs/) for the full breakdown.
7073

7174
:::note[Verifiable Payment]
7275
All storage and retrieval charges are denominated in **USDFC** (or supported ERC-20 tokens) and settled via **Filecoin Pay**. Every transaction is on-chain, auditable, and linked to verifiable service proofs.

0 commit comments

Comments
 (0)