diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs index 18debdbf..a4251f61 100644 --- a/docs/astro.config.mjs +++ b/docs/astro.config.mjs @@ -175,6 +175,10 @@ export default defineConfig({ ecTwoSlash({ twoslashOptions: { lib: ['esnext', 'dom'], + compilerOptions: { + jsx: 4, // react-jsx + jsxImportSource: 'react', + }, }, }), ], diff --git a/docs/package.json b/docs/package.json index 42aea78d..433716f0 100644 --- a/docs/package.json +++ b/docs/package.json @@ -11,11 +11,14 @@ }, "dependencies": { "@filoz/synapse-core": "workspace:*", + "@filoz/synapse-react": "workspace:*", "@filoz/synapse-sdk": "workspace:*", "starlight-auto-sidebar": "^0.1.3", "starlight-changelogs": "^0.4.0", "starlight-links-validator": "^0.19.2", - "viem": "catalog:" + "viem": "catalog:", + "wagmi": "catalog:", + "@tanstack/react-query": "5.x" }, "devDependencies": { "@astrojs/starlight": "^0.37.5", diff --git a/docs/src/content/docs/developer-guides/components.mdx b/docs/src/content/docs/developer-guides/components.mdx index d7fa7a3d..a8899614 100644 --- a/docs/src/content/docs/developer-guides/components.mdx +++ b/docs/src/content/docs/developer-guides/components.mdx @@ -1,109 +1,64 @@ --- title: Components -description: Learn about the Synapse SDK architecture and components. +description: Learn about the available Synapse packages and how they relate. sidebar: order: 1 --- -This page describes the components of the Synapse SDK and how they work together. You'll learn how each component can be used independently, how they are organized within the SDK architecture, and how they interact with the underlying smart contracts and storage providers. +This page describes the available Synapse packages and how to choose the one that fits your use case. -The SDK is built from these core components: +## Packages -- **`Synapse`** - Main SDK entry point with simple, high-level API -- **`PaymentsService`** - SDK client for managing deposits, approvals, and payment rails (interacts with Filecoin Pay contract) -- **`StorageManager`**, **`StorageContext`** - Storage operation classes -- **`WarmStorageService`** - SDK client for storage coordination and pricing (interacts with WarmStorage contract) +| Package | Best For | +|---------|----------| +| **[Synapse SDK](/developer-guides/synapse/)** | CLI tools, scripts, Node.js backends | +| **[Synapse Core](/developer-guides/synapse-core/)** | Fine-grained control, custom integrations | +| **[Synapse React](/developer-guides/react-integration/)** | React applications | -The following diagram illustrates how these components relate to each other and the external systems they interact with: +The packages form three layers: -```mermaid -graph LR - subgraph "Public API" - Synapse - end - - subgraph "Payment Services" - PS[PaymentsService] - end - - subgraph "Storage Services" - SM[StorageManager] - end - - subgraph "Lower-Level" - WSS[WarmStorageService] - SC[StorageContext] - end - Synapse --> SM - Synapse --> PS - SM --> SC - SM --> WSS - PS --> SC -``` - -The SDK architecture is guided by several key principles that ensure maintainability, flexibility, and ease of use: - -**Design Principles**: - -- **Separation of Concerns**: Protocol, business logic, and application layers are distinct -- **Composability**: Each component can be used independently or together -- **Abstraction**: SDK hides blockchain complexity from applications -- **Verification**: All storage backed by cryptographic proofs - -## SDK Components - -The SDK is organized into three layers, each serving a specific purpose: - -- **High-Level API**: The `Synapse` class provides a simple interface for common operations. -- **Service Layer**: `PaymentsService` and `StorageManager` handle domain-specific logic. -- **Lower-Level Clients**: Direct access to contracts and providers for advanced use cases. - -### Synapse - -**Purpose**: Main SDK entry point with simple, high-level API - -**API Reference**: [Synapse API Reference](/reference/filoz/synapse-sdk/synapse/classes/synapse/) - -### PaymentsService - -The PaymentsService provides direct access to the Filecoin Pay contract, enabling you to: - -- Manage token deposits and withdrawals -- Approve operators for automated payments -- Query and settle payment rails -- Monitor account health and balance +1. **Core** - Composable modules for each filecoin onchain cloud operation. Both the SDK and React packages build on Core. +2. **SDK** - Wraps Core into a single `Synapse` entry point that manages payments, storage, and provider discovery. +3. **React** - Wraps Core into React hooks. -This is your primary interface for all payment-related operations in the SDK. +## Synapse SDK -**API Reference**: [PaymentsService API Reference](/reference/filoz/synapse-sdk/payments/classes/paymentsservice/) +**Synapse SDK** is the recommended starting point. A single `Synapse` class coordinates payments, storage, provider discovery, and session keys behind a high-level API. -Check out the [Payment Operations](/developer-guides/payments/payment-operations/) guide for more details. +- **Payments**: Deposits, withdrawals, operator approvals ([Payments Operations Guide →](/developer-guides/payments/payment-operations/)) +- **Storage**: Upload and download files to storage providers ([Storage Operations Guide →](/developer-guides/storage/storage-operations/)) +- **Provider Discovery**: Query registered storage providers and products +- **Session Keys**: Delegate signing authority for automated workflows -### StorageManager +[**Synapse SDK Guide →**](/developer-guides/synapse/) -**Purpose**: High-level, auto-managed storage operations - upload and download data to and from the Filecoin Onchain Cloud. +[**Synapse SDK Reference →**](/reference/filoz/synapse-sdk/toc/) -**API Reference**: [StorageManager API Reference](/reference/filoz/synapse-sdk/storage/classes/storagemanager/) +## Synapse Core -Check out the [Storage Operations](/developer-guides/storage/storage-operations/) guide for more details. +**Synapse Core** is a low-level building blocks that the SDK and React packages build on. Use when you need direct control over individual operations. -### StorageContext +- **Contract functions** - Filecoin Pay, Warm Storage, PDP Verifier, Service Provider Registry +- **Storage provider HTTP API**: Data set creation, piece uploads, deletions +- **PieceCID utilities** - Calculate, parse, and validate piece identifiers +- **EIP-712 typed data** - Sign operations for data set and piece management +- **Chain configuration** - Mainnet, calibration, and devnet definitions -**Purpose**: Provider-specific storage operations - upload and download data to and from the Filecoin Onchain Cloud. +[**Synapse Core Guide →**](/developer-guides/synapse-core/) -**API Reference**: [StorageContext API Reference](/reference/filoz/synapse-sdk/storage/classes/storagecontext/) +[**Synapse Core Reference →**](/reference/filoz/synapse-core/toc/) -Check out the [Storage Context](/developer-guides/storage/storage-context/) guide for more details. +## Synapse React -### WarmStorageService +React hooks for payments, storage, and provider operations. Built on [Wagmi](https://wagmi.sh) and [TanStack Query](https://tanstack.com/query). -**Purpose**: SDK client for storage coordination and pricing - storage pricing and cost calculations, data set management and queries, metadata operations (data sets and pieces), service provider approval management, contract address discovery, data set creation verification. +[**Synapse React Guide →**](/developer-guides/react-integration/) -**API Reference**: [WarmStorageService API Reference](/reference/filoz/synapse-sdk/warmstorage/classes/warmstorageservice/) +[**Synapse React Reference →**](/reference/filoz/synapse-react/toc/) ## Complete Data Flow -This sequence diagram shows the complete lifecycle of a file upload operation, from initialization through verification. Each step represents an actual blockchain transaction or API call. +The sequence below shows the complete lifecycle of a file upload — from initialization through on-chain verification. ```mermaid sequenceDiagram @@ -158,7 +113,7 @@ sequenceDiagram Choose your learning path based on your immediate needs: -### Ready to Build? +#### Ready to Build? Jump straight to code with the [**Getting Started Guide →**](/getting-started/) @@ -166,8 +121,9 @@ Jump straight to code with the [**Getting Started Guide →**](/getting-started/ - [**Storage Context →**](/developer-guides/storage/storage-context/) - Advanced storage operations and batch uploads - [**Payment Operations →**](/developer-guides/payments/payment-operations/) - Fund your account and manage payments - [**Rails & Settlement →**](/developer-guides/payments/rails-settlement/) - Payment mechanics and settlement strategies +- [**React Integration →**](/developer-guides/react-integration/) - Use Synapse React hooks in your React app -### Want to Learn More? +#### Want to Learn More? - [**Architecture →**](/core-concepts/architecture/) - Understanding how all components work together - [**PDP Overview →**](/core-concepts/pdp-overview/) - Proof verification and data integrity diff --git a/docs/src/content/docs/developer-guides/payments/payment-operations.mdx b/docs/src/content/docs/developer-guides/payments/payment-operations.mdx index c4c63553..9471b061 100644 --- a/docs/src/content/docs/developer-guides/payments/payment-operations.mdx +++ b/docs/src/content/docs/developer-guides/payments/payment-operations.mdx @@ -58,9 +58,17 @@ await synapse.client.waitForTransactionReceipt({ hash }); If you cannot use permit-based deposits, you can use the traditional two-transaction approach: -```ts +```ts twoslash +// @lib: esnext,dom +import { Synapse, parseUnits } from "@filoz/synapse-sdk"; +import { privateKeyToAccount } from 'viem/accounts' +const synapse = Synapse.create({ account: privateKeyToAccount('0x...') }); +// ---cut--- +const filecoinpay = synapse.chain.contracts.filecoinPay.address +const amount = parseUnits("100"); + // 1. Approve USDFC spending -await usdfc.approve(paymentAddress, depositAmount); +await synapse.payments.approve({spender: filecoinpay, amount}); // 2. Deposit await synapse.payments.deposit({ amount }); diff --git a/docs/src/content/docs/developer-guides/react-integration.mdx b/docs/src/content/docs/developer-guides/react-integration.mdx index 914fda01..8f8053c1 100644 --- a/docs/src/content/docs/developer-guides/react-integration.mdx +++ b/docs/src/content/docs/developer-guides/react-integration.mdx @@ -1,6 +1,6 @@ --- title: React Integration -description: Guide to integrating Synapse SDK into React applications with Wagmi or MetaMask. +description: Guide to integrating Synapse into React applications using Synapse React hooks. sidebar: order: 6 --- @@ -10,119 +10,140 @@ sidebar: **Install dependencies:** ```bash -# Core (required) -npm install @filoz/synapse-sdk ethers - -# Wagmi integration (recommended) -npm install wagmi viem @tanstack/react-query +npm install @filoz/synapse-react wagmi viem @tanstack/react-query ``` **Requirements:** -- React 18+, Ethers 6.x, Wagmi 2.x (if used), Node 18+ +- React 18+, Wagmi 3.x, viem 2.x, TanStack Query 5.x - Connected Web3 wallet - Supported networks: Filecoin Mainnet, Filecoin Calibration -## Wagmi Integration (Recommended) +**Wagmi config:** -Multi-wallet support, React Query caching, type-safe. +```tsx twoslash +// @lib: esnext,dom +import { calibration, mainnet } from "@filoz/synapse-core/chains"; +import { createConfig, http } from "wagmi"; -### 1. viem to ethers Signer Hook +export const wagmiConfig = createConfig({ + chains: [calibration, mainnet], + transports: { + [mainnet.id]: http(), + [calibration.id]: http(), + }, +}); +``` -```typescript -import { BrowserProvider, JsonRpcSigner } from "ethers"; -import { type Config, useConnectorClient } from "wagmi"; +**Provider setup:** -export const useEthersSigner = ({ chainId }: { chainId?: number } = {}) => { - const { data: client } = useConnectorClient({ chainId }); - if (!client) return null; - const { account, chain, transport } = client; - const provider = new BrowserProvider(transport, { - chainId: chain.id, - name: chain.name, - }); - return new JsonRpcSigner(provider, account.address); -}; -``` +Synapse React hooks work within [Wagmi](https://wagmi.sh) and [TanStack Query](https://tanstack.com/query) providers. Set these up at the root of your app: -### 2. Simple Component Example - -```tsx -import { Synapse, TOKENS } from "@filoz/synapse-sdk"; -import { ethers } from "ethers"; -import { useEffect, useState } from "react"; -import { useEthersSigner } from "./useEthersSigner"; - -const SimpleWagmiExample = () => { - const signer = useEthersSigner(); - const [synapse, setSynapse] = useState(null); - - useEffect(() => { - if (signer) - Synapse.create({ signer }).then(setSynapse).catch(console.error); - }, [signer]); - - const deposit = async () => { - if (!synapse) return; - const amount = ethers.parseUnits("1", 18); - const tx = await synapse.payments.deposit(amount, TOKENS.USDFC); - await tx.wait(); - alert("Deposit confirmed!"); - }; - - return synapse ? ( - - ) : ( -
Connect wallet
+```tsx twoslash +// @lib: esnext,dom +import type { Config } from "wagmi"; +const config = {} as Config; +const YourApp = () =>
; +// ---cut--- +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { WagmiProvider } from "wagmi"; + +const queryClient = new QueryClient(); + +export default function App() { + return ( + + + + + ); -}; +} ``` -## MetaMask Integration +## Payments -Minimal dependencies, smaller bundle. MetaMask-only. +Query account info and make deposits using hooks: -```tsx -import { Synapse, TOKENS } from "@filoz/synapse-sdk"; -import { BrowserProvider } from "ethers"; -import { useState } from "react"; -import { ethers } from "ethers"; - -const SimpleMetaMaskExample = () => { - const [synapse, setSynapse] = useState(null); - - const connect = async () => { - if (!window.ethereum) return alert("Install MetaMask"); - await window.ethereum.request({ method: "eth_requestAccounts" }); - const provider = new BrowserProvider(window.ethereum); - const signer = await provider.getSigner(); - setSynapse(await Synapse.create({ signer })); - }; - const deposit = async () => { - if (!synapse) return; - const amount = ethers.parseUnits("1", 18); - const tx = await synapse.payments.deposit(amount, TOKENS.USDFC); - await tx.wait(); - alert("Deposit confirmed!"); - }; - - return synapse ? ( - - ) : ( - +```tsx twoslash +// @lib: esnext,dom +import { useAccountInfo, useDepositAndApprove } from "@filoz/synapse-react"; +import { parseUnits } from "viem"; + +const PaymentsExample = () => { + const { data: account, isLoading } = useAccountInfo({ watch: true }); + + const deposit = useDepositAndApprove({ + onHash: (hash) => console.log("Tx:", hash), + }); + + if (isLoading) return
Loading...
; + + return ( +
+

Available: {account?.availableFunds.toString()} USDFC

+ +
); }; ``` -## Next Steps +## Storage + +Upload files and list data sets: + +```tsx twoslash +// @lib: esnext,dom +import { useUpload, useDataSets, useProviders } from "@filoz/synapse-react"; +import { useState } from "react"; -### Ready to Build? +const StorageExample = () => { + const { data: providers } = useProviders(); + const { data: dataSets } = useDataSets({}); + const [files, setFiles] = useState([]); -Jump straight to code with the [**Getting Started Guide →**](/getting-started/) + const upload = useUpload({ + onHash: (hash) => console.log("Tx:", hash), + }); -- [**Storage Operations →**](/developer-guides/storage/storage-operations/) - Upload and download your first file -- [**Storage Context →**](/developer-guides/storage/storage-context/) - Advanced storage operations and batch uploads -- [**Payment Operations →**](/developer-guides/payments/payment-operations/) - Fund your account and manage payments -- [**Rails & Settlement →**](/developer-guides/payments/rails-settlement/) - Payment mechanics and settlement strategies + return ( +
+

Providers: {providers?.length ?? 0}

+

Data sets: {dataSets?.length ?? 0}

+ + {dataSets?.map((ds) => ( +
+

Dataset {ds.dataSetId.toString()}: {ds.pieces.length} pieces

+ + e.target.files && setFiles(Array.from(e.target.files)) + } + /> + + {ds.pieces.map((p) => ( +
+

Piece {p.id.toString()}: {p.cid.toV1().toString()}

+

URL: {p.url}

+

Metadata: {JSON.stringify(p.metadata)}

+
+ ))} +
+ ))} +
+ ); +}; +``` -**Resources**: [Wagmi](https://wagmi.sh) · [Ethers v6](https://docs.ethers.org/v6/) · [React](https://react.dev/learn) · [Filecoin](https://docs.filecoin.io) +Check out the [Synapse React Reference](/reference/filoz/synapse-react/toc/) for all available query and mutation hooks. diff --git a/docs/src/content/docs/developer-guides/storage/storage-context.mdx b/docs/src/content/docs/developer-guides/storage/storage-context.mdx index c5ff7597..7d999d30 100644 --- a/docs/src/content/docs/developer-guides/storage/storage-context.mdx +++ b/docs/src/content/docs/developer-guides/storage/storage-context.mdx @@ -41,17 +41,27 @@ type StorageContextCallbacks = { provider: PDPProvider; }) => void; }; +type Address = `0x${string}` // ---cut--- interface StorageServiceOptions { - providerId?: number; // Specific provider ID to use (optional) - excludeProviderIds?: number[]; // Do not select any of these providers (optional) - providerAddress?: string; // Specific provider address to use (optional) - dataSetId?: number; // Specific data set ID to use (optional) - withCDN?: boolean; // Enable CDN services (optional) - forceCreateDataSet?: boolean; // Force creation of a new data set, even if a candidate exists (optional) - callbacks?: StorageContextCallbacks; // Progress callbacks (optional) - metadata?: Record; // Metadata requirements for data set selection/creation - uploadBatchSize?: number; // Max uploads per batch (default: 32, min: 1) + /** Specific provider ID to use (optional) */ + providerId?: bigint + /** Do not select any of these providers */ + excludeProviderIds?: bigint[] + /** Specific provider address to use (optional) */ + providerAddress?: Address + /** Specific data set ID to use (optional) */ + dataSetId?: bigint + /** Whether to enable CDN services */ + withCDN?: boolean + /** Force creation of a new data set, even if a candidate exists */ + forceCreateDataSet?: boolean + /** Maximum number of uploads to process in a single batch (default: 32, minimum: 1) */ + uploadBatchSize?: number + /** Callbacks for creation process */ + callbacks?: StorageContextCallbacks + /** Custom metadata for the data set (key-value pairs) */ + metadata?: Record } ``` @@ -147,62 +157,72 @@ import { PieceStatus, } from "@filoz/synapse-sdk"; import { Hash } from 'viem' -type Transaction = Promise; +type Address = `0x${string}` type Hex = `0x${string}`; +type UploadPieceStreamingData = Uint8Array | ReadableStream | File | Blob export interface UploadCallbacks { /** Called periodically during upload with bytes uploaded so far */ onProgress?: (bytesUploaded: number) => void; /** Called when upload to service provider completes */ onUploadComplete?: (pieceCid: PieceCID) => void; /** Called when the service provider has added the piece(s) and submitted the transaction to the chain */ - onPiecesAdded?: (transaction?: Hex, pieces?: { pieceCid: PieceCID }[]) => void; + onPiecesAdded?: (transaction: Hex, pieces?: { pieceCid: PieceCID }[]) => void; /** Called when the service provider agrees that the piece addition(s) are confirmed on-chain */ - onPiecesConfirmed?: (dataSetId: number, pieces: PieceRecord[]) => void; + onPiecesConfirmed?: (dataSetId: bigint, pieces: PieceRecord[]) => void; } /** * Options for uploading individual pieces to an existing storage context * @param metadata - Custom metadata for this specific piece (key-value pairs) + * @param pieceCid - Optional pre-calculated PieceCID to skip CommP calculation + * @param signal - Optional AbortSignal to cancel the upload * @param onUploadComplete - Called when upload to service provider completes * @param onPiecesAdded - Called when the service provider has added the piece(s) and submitted the transaction to the chain * @param onPiecesConfirmed - Called when the service provider agrees that the piece addition(s) are confirmed on-chain and provides the dataSetId */ type UploadOptions = { metadata?: Record; + pieceCid?: PieceCID; + signal?: AbortSignal; onUploadComplete?: (pieceCid: PieceCID) => void; - onPiecesAdded?: (transaction?: Hex, pieces?: { pieceCid: PieceCID }[]) => void; - onPiecesConfirmed?: (dataSetId: number, pieces: PieceRecord[]) => void; + onPiecesAdded?: (transaction: Hex, pieces?: { pieceCid: PieceCID }[]) => void; + onPiecesConfirmed?: (dataSetId: bigint, pieces: PieceRecord[]) => void; +}; + +type DownloadOptions = { + pieceCid: string | PieceCID; + withCDN?: boolean; }; // ---cut--- interface StorageContextAPI { // Properties readonly provider: PDPProvider; - readonly serviceProvider: string; + readonly serviceProvider: Address; readonly withCDN: boolean; - readonly dataSetId: number | undefined; + readonly dataSetId: bigint | undefined; readonly dataSetMetadata: Record; // Upload & Download upload( - data: File, + data: UploadPieceStreamingData, options?: UploadOptions ): Promise; - download(pieceCid: string | PieceCID): Promise; + download(options: DownloadOptions): Promise; // Piece Queries - hasPiece(pieceCid: string | PieceCID): Promise; - pieceStatus(pieceCid: string | PieceCID): Promise; - getDataSetPieces(): Promise; + hasPiece(options: { pieceCid: string | PieceCID }): Promise; + pieceStatus(options: { pieceCid: string | PieceCID }): Promise; + getPieces(options?: { batchSize?: bigint }): AsyncGenerator; // Piece Management - deletePiece(piece: string | PieceCID | number): Promise; + deletePiece(options: { piece: string | PieceCID | bigint }): Promise; // Info & Preflight getProviderInfo(): Promise; - preflightUpload(size: number): Promise; + preflightUpload(options: { size: number }): Promise; // Lifecycle - terminate(): Transaction; + terminate(): Promise; } ``` @@ -284,14 +304,24 @@ The SDK batches up to 32 uploads by default (configurable via `uploadBatchSize`) :::tip[Batch Upload Performance] **For best performance, start all uploads without awaiting** and let the SDK batch them automatically. This can significantly reduce total upload time for multiple files. -```typescript +```ts twoslash +// @lib: esnext,dom +import { Synapse } from "@filoz/synapse-sdk"; +import { privateKeyToAccount } from 'viem/accounts' +const synapse = Synapse.create({ account: privateKeyToAccount('0x...') }); +const context = await synapse.storage.createContext({ + providerAddress: "0x...", // Optional: use specific provider address + withCDN: true, // Optional: enable CDN for faster downloads +}); +const files = [] as File[] +// ---cut--- // ✅ Efficient: Batched automatically -const uploads = dataArray.map((data) => context.upload(data)); +const uploads = files.map((file) => context.upload(file)); const results = await Promise.all(uploads); // ❌ Slow: Forces sequential processing -for (const data of dataArray) { - await context.upload(data); +for (const file of files) { + await context.upload(file); } ``` diff --git a/docs/src/content/docs/developer-guides/storage/storage-costs.mdx b/docs/src/content/docs/developer-guides/storage/storage-costs.mdx index fda43761..f467799c 100644 --- a/docs/src/content/docs/developer-guides/storage/storage-costs.mdx +++ b/docs/src/content/docs/developer-guides/storage/storage-costs.mdx @@ -156,6 +156,7 @@ Allowances are **cumulative** - you must add your new storage requirements to an - **Rate Allowance**: Total per-epoch spending across all datasets - **Lockup Allowance**: Total 30-day buffer across all datasets +::: ```ts twoslash // @lib: esnext,dom diff --git a/docs/src/content/docs/developer-guides/storage/storage-operations.mdx b/docs/src/content/docs/developer-guides/storage/storage-operations.mdx index abadd1c5..2ee3c808 100644 --- a/docs/src/content/docs/developer-guides/storage/storage-operations.mdx +++ b/docs/src/content/docs/developer-guides/storage/storage-operations.mdx @@ -170,15 +170,13 @@ console.log("Piece metadata:", metadata); ## Getting the size of a specific piece -Calculate size of a specific piece by extracting the size from the PieceCID: +Extract the size directly from a PieceCID using Synapse Core: ```ts twoslash // @lib: esnext,dom -const pieceCid = null as unknown as string; -// @ts-ignore -// ---cut--- -import { getSizeFromPieceCID } from "@filoz/synapse-sdk/piece"; +import { getSizeFromPieceCID } from "@filoz/synapse-core/piece"; +const pieceCid = "bafkzcib..."; const size = getSizeFromPieceCID(pieceCid); console.log(`Piece size: ${size} bytes`); ``` diff --git a/docs/src/content/docs/developer-guides/synapse-core.mdx b/docs/src/content/docs/developer-guides/synapse-core.mdx new file mode 100644 index 00000000..a0f6f10d --- /dev/null +++ b/docs/src/content/docs/developer-guides/synapse-core.mdx @@ -0,0 +1,221 @@ +--- +title: Synapse Core +description: Low-level building blocks for direct contract interaction and storage provider communication. +sidebar: + order: 5 +--- + +**Synapse Core** (`@filoz/synapse-core`) is the low-level foundation that both the [Synapse SDK](/developer-guides/synapse/) and [Synapse React](/developer-guides/react-integration/) build on. Use Synapse Core when you need: + +- Direct control over individual contract calls without the `Synapse` class abstraction +- Custom integrations that combine only the modules you need + + + +## Setup + +**Install dependencies:** + +```bash +npm install @filoz/synapse-core viem +``` + +Synapse Core requires [viem](https://viem.sh) 2.x as a peer dependency. + +**Client setup:** + +All Synapse Core functions accept a viem `Client` as their first argument. Create one using viem's standard client factories: + +```ts twoslash +// @lib: esnext,dom +import { createPublicClient, createWalletClient, http } from "viem" +import { privateKeyToAccount } from "viem/accounts" +import { calibration, mainnet } from "@filoz/synapse-core/chains" + +// Read-only client for queries +const publicClient = createPublicClient({ + chain: calibration, // or mainnet + transport: http(), +}) + +// Wallet client for transactions +const account = privateKeyToAccount("0x...") +const walletClient = createWalletClient({ + account, + chain: calibration, // or mainnet + transport: http(), +}) +``` + +The `@filoz/synapse-core/chains` subpath exports chain definitions with all contract addresses pre-configured for Filecoin Mainnet (`mainnet`) and Filecoin testnet (`calibration`) networks. + +## Payments + +Query account balances, deposit funds, manage operator approvals, and settle payment rails on the Filecoin Pay contract. + +```ts twoslash +// @lib: esnext,dom +import { createPublicClient, createWalletClient, http } from "viem" +import { privateKeyToAccount } from "viem/accounts" +import { calibration } from "@filoz/synapse-core/chains" +const publicClient = createPublicClient({ chain: calibration, transport: http() }) +const account = privateKeyToAccount("0x0000000000000000000000000000000000000000000000000000000000000001") +const walletClient = createWalletClient({ account, chain: calibration, transport: http() }) +// ---cut--- +import * as pay from "@filoz/synapse-core/pay" +import { parseUnits } from "viem" + +// Query Filecoin Pay account info for the USDFC token +const info = await pay.accounts(publicClient, { + // If not provided, the USDFC token address will be used. + token: calibration.contracts.usdfc.address, + address: account.address, +}) +console.log(info.availableFunds) // bigint — funds available in Filecoin Pay + +// Deposit USDFC in Filecoin Pay +const depositTxHash = await pay.depositAndApprove(walletClient, { + // If not provided, the USDFC token address will be used. + token: calibration.contracts.usdfc.address, + amount: parseUnits("1", 18), // 1 USDFC +}) + +await publicClient.waitForTransactionReceipt({ + hash: depositTxHash +}) + +// Withdraw USDFC from Filecoin Pay +const withdrawTxHash = await pay.withdraw(walletClient, { + // If not provided, the USDFC token address will be used. + token: calibration.contracts.usdfc.address, + amount: parseUnits("1", 18), // 1 USDFC +}) + +await publicClient.waitForTransactionReceipt({ + hash: withdrawTxHash +}) + +``` + +## Storage + +List approved storage providers. + +```ts twoslash +// @lib: esnext,dom +import { createPublicClient, http } from "viem" +import { calibration } from "@filoz/synapse-core/chains" +const publicClient = createPublicClient({ chain: calibration, transport: http() }) +// ---cut--- +import * as warmStorage from "@filoz/synapse-core/warm-storage" + +// List approved providers +const providers = await warmStorage.getApprovedProviders(publicClient) +console.log(providers) // bigint[] — approved provider IDs +``` + +--- + +Create a data set and upload a file. + +```ts twoslash +// @lib: esnext,dom +import { createWalletClient, http } from "viem" +import { privateKeyToAccount } from "viem/accounts" +import { calibration } from "@filoz/synapse-core/chains" +const account = privateKeyToAccount("0x1") +const walletClient = createWalletClient({ account, chain: calibration, transport: http() }) +const data = new Uint8Array([1, 2, 3]) +// ---cut--- +import * as piece from "@filoz/synapse-core/piece" +import * as sp from "@filoz/synapse-core/sp" +import { getPDPProvider } from "@filoz/synapse-core/sp-registry" + +// 1. Select a provider +const provider = await getPDPProvider(walletClient, { providerId: 1n }) + +// 2. Calculate PieceCID and upload data +const pieceCid = piece.calculate(data) +const size = piece.getSize(pieceCid) +console.log(size) // size of the piece in bytes +await sp.uploadPiece({ + data, + pieceCid, + serviceURL: provider.pdp.serviceURL, +}) + +console.log("Piece uploaded") + +await sp.findPiece({ + pieceCid, + serviceURL: provider.pdp.serviceURL, + retry: true, +}) + +console.log("Piece parked") + +// 3. Create a data set and add the piece on-chain +const result = await sp.createDataSetAndAddPieces(walletClient, { + serviceURL: provider.pdp.serviceURL, + payee: provider.payee, + cdn: false, + pieces: [{ pieceCid }], +}) + +console.log("Creating data set and adding piece") + +// 4. Wait for confirmation +const confirmed = await sp.waitForCreateDataSetAddPieces({ + statusUrl: result.statusUrl, +}) + +console.log(confirmed.dataSetId) // bigint — on-chain data set ID +console.log(confirmed.piecesIds) // bigint[] — confirmed piece IDs +``` + +
+*For large files, use `uploadPieceStreaming` instead of `uploadPiece`:* + +```ts twoslash +// @lib: esnext,dom +import * as sp from "@filoz/synapse-core/sp" +const serviceURL = "https://provider.example.com" +// ---cut--- +// Stream upload — PieceCID is calculated during transfer +const stream = new ReadableStream({ /* ... */ }) +const uploaded = await sp.uploadPieceStreaming({ + data: stream, + serviceURL, + onProgress(bytes) { + console.log(`${bytes} bytes uploaded`) + }, +}) +console.log(uploaded.pieceCid) // PieceCID — calculated from streamed data +console.log(uploaded.size) // number — total bytes uploaded +``` + +
+ +--- + +Download a piece from a storage provider. + +```ts twoslash +// @lib: esnext,dom +import { createPublicClient, http } from "viem" +import { getPDPProvider } from "@filoz/synapse-core/sp-registry" +import { calibration } from "@filoz/synapse-core/chains" +const publicClient = createPublicClient({ chain: calibration, transport: http() }) +const provider = await getPDPProvider(publicClient, { providerId: 1n }) +// ---cut--- +import { downloadAndValidate } from "@filoz/synapse-core/piece" + +// Download a piece +const data = await downloadAndValidate({ + url: `${provider.pdp.serviceURL}/piece`, + expectedPieceCid: "bafkzcib...", +}) +console.log(data) // Uint8Array — downloaded piece data +``` + +Check out the [Synapse Core Reference](/reference/filoz/synapse-core/toc/) for all available modules and functions. diff --git a/docs/src/content/docs/developer-guides/synapse.md b/docs/src/content/docs/developer-guides/synapse.md index 192fb73e..1038e03f 100644 --- a/docs/src/content/docs/developer-guides/synapse.md +++ b/docs/src/content/docs/developer-guides/synapse.md @@ -24,38 +24,38 @@ The SDK integrates with four key components of the Filecoin Onchain Cloud: Looking for Python or Go? Check out [Community Projects](/resources/community-projects/) for community-maintained SDKs. ::: -The SDK provides two primary components: - -- **`synapse.payments`** - Token operations, service authorizations, and payment rail settlements -- **`synapse.storage`** - Data upload, download, and storage context management - -The main `Synapse` class exposes this simple interface for all operations: +The `Synapse` class provides a single entry point for all operations: ```ts twoslash // @lib: esnext,dom import { Synapse, SynapseOptions, - StorageInfo, - PDPProvider, } from "@filoz/synapse-sdk" import type { PaymentsService } from "@filoz/synapse-sdk/payments" import type { StorageManager } from "@filoz/synapse-sdk/storage" +import type { FilBeamService } from "@filoz/synapse-sdk/filbeam" +import type { SPRegistryService } from "@filoz/synapse-sdk/sp-registry" +import type { Chain } from '@filoz/synapse-core/chains' +import { + type Client, +} from 'viem' +import type { PDPProvider } from '@filoz/synapse-core/sp-registry' + // ---cut--- interface SynapseAPI { // Create a new Synapse instance - create(options: SynapseOptions): Promise + create(options: SynapseOptions): Synapse // Properties + client: Client + chain: Chain + // Services payments: PaymentsService storage: StorageManager - // Storage Information (pricing, providers, service parameters, allowances) - getStorageInfo(): Promise + providers: SPRegistryService + filbeam: FilBeamService + // Storage provider info getter getProviderInfo(providerAddress: string): Promise - getChainId(): number - // Contract Addresses - getWarmStorageAddress(): string - getPaymentsAddress(): string - getPDPVerifierAddress(): string } ``` @@ -75,19 +75,17 @@ Fund your account and manage payments for Filecoin storage services. ### Storage Operations -The SDK provides comprehensive storage capabilities through two main approaches: - -- **Auto-managed storage**: Quick and simple - the SDK handles provider selection and data set creation. -- **Explicit control**: Full control over providers, data sets, and batch operations. +The SDK provides two storage approaches: -To understand these storage approaches, you'll need to be familiar with several key concepts: +- **Auto-managed** — The SDK handles provider selection and data set creation +- **Explicit control** — Full control over providers, data sets, and batch operations -#### Core Concepts +#### Key Concepts -- **Storage Contexts**: Manage storage lifecycle and provider connections. -- **Data Sets**: Organize related data pieces with shared payment rails. -- **PieceCIDs**: Unique content-addressed identifiers for stored data. -- **Service Providers**: Infrastructure for decentralized storage with cryptographic proofs. +- **Storage Contexts** — Manage storage lifecycle and provider connections +- **Data Sets** — Organize related data pieces with shared payment rails +- **PieceCIDs** — Content-addressed identifiers for stored data +- **Service Providers** — Decentralized storage with cryptographic proofs [View Storage Operations Guide →](/developer-guides/storage/storage-operations/) - _Learn the basics in less than 10 minutes_ @@ -95,9 +93,7 @@ To understand these storage approaches, you'll need to be familiar with several [View Storage Costs Guide →](/developer-guides/storage/storage-costs/) - _Learn how to calculate your storage costs_ -## Technical Constraints and Concepts - -The following sections cover important technical constraints and concepts that apply to all storage operations. +## Technical Constraints ### Metadata Limits @@ -119,15 +115,13 @@ These limits are enforced by the blockchain contracts. The SDK will validate met ### Size Constraints -The storage service enforces the following size limits for uploads: +Upload size limits: - **Minimum**: 127 bytes (required for PieceCID calculation) -- **Maximum**: 200 MiB (209,715,200 bytes) - -Attempting to upload data outside these limits will result in an error. +- **Maximum**: ~1 GiB (1,065,353,216 bytes) :::note -These limits are defined in the SDK constants (`SIZE_CONSTANTS.MIN_UPLOAD_SIZE` and `SIZE_CONSTANTS.MAX_UPLOAD_SIZE`). While the underlying Curio PDP service supports files up to 254 MiB, the SDK currently limits uploads to 200 MiB. Future versions will support larger files through chunking and aggregate PieceCIDs. +These limits are defined in the SDK constants (`SIZE_CONSTANTS.MIN_UPLOAD_SIZE` and `SIZE_CONSTANTS.MAX_UPLOAD_SIZE`). Future versions will support larger files through chunking and aggregate PieceCIDs. See [this issue](https://github.com/FilOzone/synapse-sdk/issues/110) for details. ::: @@ -153,18 +147,6 @@ LegacyPieceCID (v1 format) conversion utilities are provided for interoperabilit **Technical Reference:** See [FRC-0069](https://github.com/filecoin-project/FIPs/blob/master/FRCs/frc-0069.md) for the complete specification of PieceCID ("v2 Piece CID") and its relationship to LegacyPieceCID ("v1 Piece CID"). Most Filecoin tooling currently uses v1, but the ecosystem is transitioning to v2. -## Error Handling - -The SDK provides consistent error handling across all operations to help you debug issues quickly. - -```ts -try { - await synapse.payments.deposit(amount); -} catch (error) { - console.error(error.message); // Clear error description - console.error(error.cause); // Underlying error if any -} -``` ## Additional Resources