A modular, well-structured starter kit for building applications that interact with 0G Storage. This project provides a clean architecture for uploading and downloading files using the 0G Storage protocol.
- File upload to 0G Storage with fee calculation
- File download from 0G Storage using root hash
- Support for both Standard and Turbo network modes
- Wallet integration with connection management
- Modern React UI components with TailwindCSS
- Node.js (v16+)
- Ethereum wallet (e.g., MetaMask)
-
Clone the repository:
git clone https://github.com/yourusername/0g-storage-starter-kit.git cd 0g-storage-starter-kit
-
Install dependencies:
npm install # or yarn install
-
Set up environment variables by creating a
.env.local
file (see Environment Variables section below) -
Run the development server:
npm run dev # or yarn dev
-
Open http://localhost:3000 in your browser.
The project is organized into a clean, modular architecture:
src/
├── app/ # Next.js app router components
│ ├── providers.tsx # App providers (Wagmi, Network context)
│ ├── page.tsx # Main application page
│
├── components/ # React components
│ ├── common/ # Reusable UI components
│ │ ├── FileDropzone.tsx # Drag-and-drop file selector
│ │ ├── FileInfo.tsx # File information display
│ │ ├── FeeDisplay.tsx # Fee calculation display
│ │ ├── TransactionStatus.tsx # Transaction status display
│ │
│ ├── upload/ # Upload-specific components
│ │ ├── UploadCard.tsx # File upload card
│ │ ├── UploadCardContainer.tsx # Container with remounting logic
│ │
│ ├── download/ # Download-specific components
│ │ ├── DownloadCard.tsx # File download card
│ │ ├── DownloadCardContainer.tsx # Container with remounting logic
│ │
│ ├── ConnectButton.tsx # Wallet connection button
│ ├── NetworkToggle.tsx # Network mode toggle
│
├── hooks/ # Custom React hooks
│ ├── useWallet.ts # Wallet connection management
│ ├── useFees.ts # Fee calculation logic
│ ├── useUpload.ts # File upload logic
│ ├── useDownload.ts # File download logic
│
├── lib/ # Core utilities and SDK
│ ├── 0g/ # 0G Storage SDK utilities
│ │ ├── blob.ts # Blob creation and handling
│ │ ├── fees.ts # Fee calculation utilities
│ │ ├── network.ts # Network configuration
│ │ ├── uploader.ts # File upload utilities
│ │ ├── downloader.ts # File download utilities
│
├── utils/ # Helper functions
│ ├── format.ts # Formatting utilities
This starter kit follows a layered architecture:
Low-level utilities for interacting with the 0G Storage protocol:
- blob.ts: Functions for creating blobs, generating Merkle trees, and root hash calculation
- fees.ts: Functions for calculating storage fees and gas estimates
- network.ts: Network configuration and management
- uploader.ts: Functions for submitting transactions and uploading files
- downloader.ts: Functions for downloading files by root hash
Custom hooks that abstract the core functionalities:
- useWallet.ts: Manages wallet connection and status, handling hydration safely
- useFees.ts: Provides fee calculation for file uploads, creating blobs and Merkle trees
- useUpload.ts: Handles the file upload process including transaction submission
- useDownload.ts: Manages file downloading by root hash, including error handling
React components for the user interface:
- Common components: Reusable UI elements like
FileDropzone
,FileInfo
, etc. - Feature components: Higher-level components like
UploadCard
andDownloadCard
To calculate fees for uploading a file:
import { useFees } from '@/hooks/useFees';
import { useWallet } from '@/hooks/useWallet';
function MyComponent() {
const { isConnected } = useWallet();
const { calculateFeesForFile, feeInfo, error } = useFees();
// When a file is selected
const handleFileSelect = (file) => {
// Calculate fees for the file if wallet is connected
calculateFeesForFile(file, isConnected);
};
return (
<div>
{/* Display fee information */}
{feeInfo && (
<div>
<p>Storage Fee: {feeInfo.storageFee} A0GI</p>
<p>Estimated Gas: {feeInfo.estimatedGas} A0GI</p>
<p>Total Fee: {feeInfo.totalFee} A0GI</p>
</div>
)}
{/* Display any errors */}
{error && <p>{error}</p>}
</div>
);
}
To upload a file to 0G Storage:
import { useFees } from '@/hooks/useFees';
import { useUpload } from '@/hooks/useUpload';
function MyUploadComponent() {
// Get fee calculation hooks
const {
blob,
submission,
flowContract,
feeInfo
} = useFees();
// Get upload hooks
const {
uploadFile,
loading,
uploadStatus,
txHash,
error
} = useUpload();
// Handle upload button click
const handleUpload = async () => {
if (!blob || !submission || !flowContract || !feeInfo) {
return; // Missing required data
}
// Upload the file using the calculated fee
await uploadFile(
blob,
submission,
flowContract,
feeInfo.rawTotalFee
);
};
return (
<div>
<button
onClick={handleUpload}
disabled={loading || !submission}
>
Upload File
</button>
{/* Display upload status */}
{uploadStatus && <p>{uploadStatus}</p>}
{/* Display transaction hash if available */}
{txHash && <p>Transaction: {txHash}</p>}
{/* Display any errors */}
{error && <p>Error: {error}</p>}
</div>
);
}
To download a file from 0G Storage using a root hash:
import { useDownload } from '@/hooks/useDownload';
function MyDownloadComponent() {
const {
downloadFile,
loading,
downloadStatus,
error
} = useDownload();
// Handle download action
const handleDownload = async (rootHash, fileName) => {
await downloadFile(rootHash, fileName);
};
return (
<div>
<button
onClick={() => handleDownload('0x1234...', 'my-file.pdf')}
disabled={loading}
>
Download File
</button>
{/* Display download status */}
{downloadStatus && <p>{downloadStatus}</p>}
{/* Display any errors */}
{error && <p>Error: {error}</p>}
</div>
);
}
Create a .env.local
file in the root directory with the following variables:
# Project ID for WalletConnect (required)
NEXT_PUBLIC_PROJECT_ID=your_project_id_here
# L1 RPC URL
NEXT_PUBLIC_L1_RPC=https://evmrpc-testnet.0g.ai
# Standard network (Slower with lower fees)
NEXT_PUBLIC_STANDARD_FLOW_ADDRESS=0x0460aA47b41a66694c0a73f667a1b795A5ED3556
NEXT_PUBLIC_STANDARD_STORAGE_RPC=https://indexer-storage-testnet-standard.0g.ai
NEXT_PUBLIC_STANDARD_EXPLORER_URL=https://chainscan-newton.0g.ai/tx/
NEXT_PUBLIC_STANDARD_L1_RPC=https://evmrpc-testnet.0g.ai
# Turbo network (Faster with higher fees)
NEXT_PUBLIC_TURBO_FLOW_ADDRESS=0xbD2C3F0E65eDF5582141C35969d66e34629cC768
NEXT_PUBLIC_TURBO_STORAGE_RPC=https://indexer-storage-testnet-turbo.0g.ai
NEXT_PUBLIC_TURBO_EXPLORER_URL=https://chainscan-newton.0g.ai/tx/
NEXT_PUBLIC_TURBO_L1_RPC=https://evmrpc-testnet.0g.ai
# Default network (standard or turbo)
NEXT_PUBLIC_DEFAULT_NETWORK=standard
The application supports two network modes: Standard and Turbo. You can access and change the network mode using the useNetwork
hook:
import { useNetwork } from '@/app/providers';
import { getNetworkConfig } from '@/lib/0g/network';
function MyNetworkComponent() {
const { networkType, setNetworkType } = useNetwork();
const networkConfig = getNetworkConfig(networkType);
return (
<div>
<p>Current Network: {networkType}</p>
<p>Flow Address: {networkConfig.flowAddress}</p>
<button onClick={() => setNetworkType(networkType === 'standard' ? 'turbo' : 'standard')}>
Toggle Network
</button>
</div>
);
}
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE file for details.