Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions docs/src/content/docs/cookbooks/payments-and-storage.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Two recurring rates apply per data set:
| Component | Cost | Notes |
| -------------- | -------------------- | ------------------------------------------------------- |
| **Storage** | $2.50/TiB/month per copy | Charged only while pieces exist. Empty data sets have no recurring cost |
| **Proving Service** | $0.024/data set/month | Flat per-data-set fee, added on top of the storage rate |
| **Proving Service** | $0.12/data set/month | Flat per-data-set fee, added on top of the storage rate |
| **CDN egress** | up to $14/TiB (≈ $0.014/GiB) downloaded | Optional, via Filecoin Beam. About half this when served from cache |

:::note
Expand All @@ -58,24 +58,24 @@ Each on-chain operation also pays a small one-time fee to the storage provider,
| Operation | Fee |
| -------------- | -------------------- |
| **Create data set** | $0.025 |
| **Add pieces** | $0.0005 + $0.0003 per piece |
| **Schedule piece removals** | $0.002 per call |
| **Terminate service** | $0.00112 (user-initiated only) |
| **Add pieces** | $0.008 + $0.003 per piece |
| **Schedule piece removals** | $0.007 per call |
| **Terminate service** | $0.006 for client-authorized, provider-relayed termination; no fee for direct payer or provider termination |

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.
These are paid from a refundable ~$0.50 lifecycle reserve held while the data set is active, not added separately to the required deposit 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.

### Proving Fee

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.
The monthly cost of an active data set is `(unpadded bytes / TiB) × $2.50 + $0.12`. 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. The SDK converts PDP's padded leaf counts to unpadded bytes using the Filecoin `127 / 128` ratio.

### Data Set Creation Costs

Creating a data set locks a small lifecycle reserve. The storage rate starts at zero and is set automatically when you add data:

| Scenario | Minimum Funds Required |
| -------- | ---------------------- |
| No CDN | ~0.10 USDFC (lifecycle reserve lockup) |
| With CDN | ~1.10 USDFC (0.10 reserve + 0.70 CDN egress + 0.30 cache-miss) |
| No CDN | ~0.50 USDFC (lifecycle reserve lockup) |
| With CDN | ~1.50 USDFC (0.50 reserve + 0.70 CDN egress + 0.30 cache-miss) |

One-time fees such as the $0.025 creation fee are drawn from the lifecycle reserve, not added on top of these amounts.

Expand All @@ -89,7 +89,7 @@ For each data set, FWSS creates payment channels called **rails** that stream fu
| **CDN rail** | Fixed | 0.7 USDFC lockup for CDN egress credits |
| **Cache miss** | Fixed | 0.3 USDFC lockup for cache miss credits |

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.
Every data set gets a PDP rail, which also holds the ~$0.50 lifecycle reserve that one-time fees draw from. FWSS replenishes it when the balance is below pending fees plus the $0.025 threshold. 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.

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.

Expand Down
72 changes: 37 additions & 35 deletions docs/src/content/docs/developer-guides/storage/storage-costs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ Pricing has two recurring rates and a set of small one-time fees.
| Component | Cost | Notes |
| -------------- | ------------------ | -------------------------------------------------------- |
| **Storage** | $2.50/TiB/month per copy | Charged only while pieces exist. Empty data sets have no recurring cost. |
| **Proving Service** | $0.024/data set/month | Flat per-data-set fee, added on top of the storage rate. |
| **Proving Service** | $0.12/data set/month | Flat per-data-set fee, added on top of the storage rate. |
| **CDN egress** | up to $14/TiB (≈ $0.014/GiB) downloaded | Optional, via Filecoin Beam. About half this when served from cache. |

:::note[Be aware]
"Month" means **30 days** here (86,400 epochs), not a calendar month.
:::

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.
The monthly rate for an active data set is `(FWSS-priced bytes / TiB) × $2.50 + $0.12`. 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. PDP counts the data-bearing Merkle-tree leaves of each piece, then FWSS converts the aggregate leaf count using the Filecoin `127 / 128` ratio. This priced size can exceed the exact raw payload size by up to 31 bytes per piece.

### One-time fees

Expand All @@ -42,11 +42,11 @@ Each on-chain operation pays a small fee to the storage provider, covering the g
| Operation | Fee |
| -------------- | ------------------ |
| **Create data set** | $0.025 |
| **Add pieces** | $0.0005 + $0.0003 per piece |
| **Schedule piece removals** | $0.002 per call |
| **Terminate service** | $0.00112 (user-initiated only) |
| **Add pieces** | $0.008 + $0.003 per piece |
| **Schedule piece removals** | $0.007 per call |
| **Terminate service** | $0.006 for client-authorized, provider-relayed termination; no fee for direct payer or provider termination |

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.
These are small one-time charges paid from a refundable lifecycle reserve (~$0.50) held while the data set is active, not added separately to the required deposit on every call. See [How the fees and lockup work](#how-the-fees-and-lockup-work) below.

:::note[CDN setup]
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.
Expand All @@ -63,20 +63,20 @@ These examples use plain arithmetic for clarity. For programmatic cost calculati
// 48.82 MiB is tiny, so the storage rate is negligible.
// The recurring cost is dominated by the flat proving fee.
const STORAGE_PRICE_PER_TIB_PER_MONTH = 2.5;
const PROVING_FEE_PER_MONTH = 0.024;
const PROVING_FEE_PER_MONTH = 0.12;

const storageTiB = 48.82 / 1024 / 1024; // ≈ 0.0000466 TiB
const storageCostPerMonth = storageTiB * STORAGE_PRICE_PER_TIB_PER_MONTH; // ≈ $0.00012

// Per copy, per month
const costPerMonth = storageCostPerMonth + PROVING_FEE_PER_MONTH; // ≈ 0.0241 USDFC
const costFor24Months = costPerMonth * 24; // ≈ 0.578 USDFC
const costPerMonth = storageCostPerMonth + PROVING_FEE_PER_MONTH; // ≈ 0.1201 USDFC
const costFor24Months = costPerMonth * 24; // ≈ 2.883 USDFC
```

| Duration | Per copy |
| --------- | ---------- |
| 1 month | ≈ 0.024 USDFC |
| 24 months | ≈ 0.58 USDFC |
| 1 month | ≈ 0.120 USDFC |
| 24 months | ≈ 2.88 USDFC |

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.

Expand All @@ -90,7 +90,7 @@ The default 2-copy configuration roughly doubles the recurring cost. One-time fe
```ts twoslash
// @lib: esnext,dom
const STORAGE_PRICE_PER_TIB_PER_MONTH = 2.5; // $2.50/TiB/month
const PROVING_FEE_PER_MONTH = 0.024; // flat per-data-set
const PROVING_FEE_PER_MONTH = 0.12; // flat per-data-set
const CDN_EGRESS_PRICE_PER_TIB = 14; // up to $14/TiB on a cache miss
const storageMiB = 100_000;
const egressMiB = 100_000;
Expand All @@ -107,38 +107,38 @@ const storageCostPerMonth = storageTiB * STORAGE_PRICE_PER_TIB_PER_MONTH;
// Egress cost per month (worst case, all cache misses): 0.0953 TiB × $14 ≈ $1.334/month
const egressCostPerMonth = egressTiB * CDN_EGRESS_PRICE_PER_TIB;

// Total cost per month: $0.238 + $0.024 proving + $1.334 egress ≈ $1.596/month
// Total cost per month: $0.238 + $0.12 proving + $1.335 egress ≈ $1.694/month
const totalCostPerMonth = storageCostPerMonth + PROVING_FEE_PER_MONTH + egressCostPerMonth;

// Total cost for 24 months: $1.596/month × 24 ≈ $38.31
// Total cost for 24 months: $1.694/month × 24 ≈ $40.65
const totalCostFor24Months = totalCostPerMonth * 24;
```

| Cost Component | Per Month | 24 Months |
| -------------- | ---------------- | ----------------- |
| Storage | ≈ 0.238 USDFC | ≈ 5.71 USDFC |
| Proving Service | ≈ 0.024 USDFC | ≈ 0.576 USDFC |
| CDN Egress | ≈ 1.334 USDFC | ≈ 32.016 USDFC |
| **Total** | **≈ 1.596 USDFC** | **≈ 38.31 USDFC** |
| Storage | ≈ 0.238 USDFC | ≈ 5.72 USDFC |
| Proving Service | ≈ 0.120 USDFC | ≈ 2.88 USDFC |
| CDN Egress | ≈ 1.335 USDFC | ≈ 32.04 USDFC |
| **Total** | **≈ 1.694 USDFC** | **≈ 40.65 USDFC** |

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.

## How the fees and lockup work

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.

**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.
**The proving fee is additive, not a floor.** The rate is `(FWSS-priced bytes / TiB) × $2.50 + $0.12`, 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.

**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.
**Add-pieces pricing scales with batch size.** Each `addPieces` call costs `$0.008 + $0.003 × 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. A single-piece call costs `$0.011`, and one SDK commit accepts at most 40 pieces.

**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.
**Fees are paid from a lifecycle reserve, not added twice to deposits.** When a data set is created, ~$0.50 of USDFC is locked as a lifecycle reserve on the data set's payment rail. Before pending one-time fees are paid, FWSS checks whether the reserve is below `pending fees + $0.025`. If so, it raises the fixed lockup enough that paying those fees leaves the reserve at its $0.50 target. The remaining reserve is refundable when the rail is finalized.

<details>
<summary>Why the reserve exists: wind-down after termination</summary>

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.

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.
If you expect to need more wind-down operations than the reserve covers, account for them before terminating. A client-authorized termination relayed by the provider charges the $0.006 termination fee, pays pending fees, and releases the remaining reserve rather than replenishing it. Direct payer and provider termination paths do not charge this termination fee.

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).

Expand All @@ -154,23 +154,25 @@ Getting the costs for uploading to an existing data set:
// @lib: esnext,dom
// @noErrors
import { Synapse, SIZE_CONSTANTS } from "@filoz/synapse-sdk"
import { getDataSetLeafCount } from '@filoz/synapse-core/pdp-verifier'
import { getDataSet } from '@filoz/synapse-core/warm-storage'
import { privateKeyToAccount } from 'viem/accounts'
const synapse = Synapse.create({ account: privateKeyToAccount('0x...'), source: 'my-app' })
// ---cut---
// Pass currentDataSetSize so rates reflect the data set's new total size
// Read the existing data set so reserve replenishment is estimated correctly.
const dataSet = await getDataSet(synapse.readClient, { dataSetId: 42n })
if (dataSet == null) throw new Error('Data set not found')
const dataSetLeafCount = await getDataSetLeafCount(synapse.readClient, { dataSetId: 42n })

const { rates, fees, depositNeeded } = await synapse.storage.getUploadCosts({
isNewDataSet: false,
currentDataSetSize: 50n * SIZE_CONSTANTS.MiB,
dataSize: 100n * SIZE_CONSTANTS.MiB,
dataSetLeafCount,
currentLifecycleReserveBalance: dataSet.lifecycleReserveBalance,
pendingOneTimePayments: dataSet.pendingOneTimePayments,
pieceSizes: [100n * SIZE_CONSTANTS.MiB],
})
// fees.addPiecesFee is the one-time fee for this upload
// (pass pieceCount when adding more than one piece)

// Without currentDataSetSize, rates cover the new data alone
const costs2 = await synapse.storage.getUploadCosts({
isNewDataSet: false,
dataSize: 100n * SIZE_CONSTANTS.MiB,
})
// Pass every known raw piece size when committing a multi-piece batch.
```

Getting the costs for uploading to a new data set:
Expand All @@ -183,7 +185,7 @@ import { privateKeyToAccount } from 'viem/accounts'
const synapse = Synapse.create({ account: privateKeyToAccount('0x...'), source: 'my-app' })
// ---cut---
const { rates, fees, lockups, depositNeeded, needsFwssMaxApproval, ready } = await synapse.storage.getUploadCosts({
dataSize: 100n * SIZE_CONSTANTS.MiB,
pieceSizes: [100n * SIZE_CONSTANTS.MiB],
isNewDataSet: true,
withCDN: true,
})
Expand Down Expand Up @@ -221,7 +223,7 @@ import { privateKeyToAccount } from 'viem/accounts'
const synapse = Synapse.create({ account: privateKeyToAccount('0x...'), source: 'my-app' });
// ---cut---
const { costs, transaction } = await synapse.storage.prepare({
dataSize: SIZE_CONSTANTS.GiB,
pieceSizes: [SIZE_CONSTANTS.GiB],
})

// Inspect costs
Expand Down Expand Up @@ -258,7 +260,7 @@ const oneYear = TIME_CONSTANTS.EPOCHS_PER_MONTH * 12n
// Prepare a single deposit covering all 3 copies for 1 year
const { costs, transaction } = await synapse.storage.prepare({
context: contexts,
dataSize: 50n * SIZE_CONSTANTS.GiB,
pieceSizes: [50n * SIZE_CONSTANTS.GiB],
extraRunwayEpochs: oneYear,
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ import { privateKeyToAccount } from "viem/accounts"

const synapse = Synapse.create({ account: privateKeyToAccount("0x...") })

const prep = await synapse.storage.prepare({ dataSize: 1073741824n }) // 1 GiB
const prep = await synapse.storage.prepare({ pieceSizes: [1073741824n] }) // one 1 GiB piece
if (prep.transaction) {
await prep.transaction.execute()
}
Expand Down
4 changes: 2 additions & 2 deletions docs/src/content/docs/getting-started/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ const file = new TextEncoder().encode(
requirement of 127 bytes per upload.`
);
const prep = await synapse.storage.prepare({
dataSize: BigInt(file.byteLength),
pieceSizes: [BigInt(file.byteLength)],
})
if (prep.transaction) {
const { hash } = await prep.transaction.execute()
Expand Down Expand Up @@ -169,7 +169,7 @@ Now let's break down each step...

// Prepare account
const prep = await synapse.storage.prepare({
dataSize: 1073741824n, // 1 GiB
pieceSizes: [1073741824n], // one 1 GiB piece
});

console.log("Deposit needed:", prep.costs.depositNeeded);
Expand Down
4 changes: 2 additions & 2 deletions docs/src/content/docs/introduction/about.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,10 @@ All payments are settled automatically through Filecoin Pay, ensuring on-chain a
| **Service** | **Pricing** | **Description** |
| ------- | --------- | -------------------- |
| **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. |
| **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. |
| **Proving Service** | **$0.12/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. |
| **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. |

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.
Beyond these recurring rates, each on-chain operation (creating a data set, adding or removing pieces, and some termination paths) carries a one-time fee paid to the storage provider to cover its gas. These fees are drawn from a refundable lifecycle reserve (~$0.50 USDFC) held while the data set is active. See [Storage Costs](/developer-guides/storage/storage-costs/) for the full breakdown.

:::note[Verifiable Payment]
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.
Expand Down
Loading
Loading