DApp Example
Learn how to build a file upload page with wallet adapter integration
Overview
In this guide, we will walk you through building a complete file upload page that integrates with the Aptos Wallet Adapter and uses the Shelby React SDK to upload files to the Shelby network.
This guide assumes you have a React application set up and understand the basics of React hooks and file handling.
Getting Started
Installation
First, install the required dependencies:
npm install @shelby-protocol/react @shelby-protocol/sdk @aptos-labs/ts-sdk @aptos-labs/wallet-adapter-react @tanstack/react-querySetting up Providers
Wrap your application with the necessary providers. Create a providers component:
"use client";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { AptosWalletAdapterProvider } from "@aptos-labs/wallet-adapter-react";
import { Network } from "@aptos-labs/ts-sdk";
import type { PropsWithChildren } from "react";
const queryClient = new QueryClient();
export function AppProviders({ children }: PropsWithChildren) {
return (
<QueryClientProvider client={queryClient}>
<AptosWalletAdapterProvider
autoConnect
dappConfig={{
network: Network.SHELBYNET,
// It is recommended to add your API key to this configuration object.
aptosApiKeys: { shelbynet: process.env.NEXT_PUBLIC_SHELBYNET_API_KEY },
}}
>
{children}
</AptosWalletAdapterProvider>
</QueryClientProvider>
);
}Then wrap your app:
import type { PropsWithChildren } from "react";
import { AppProviders } from "./AppProviders";
function App({ children }: PropsWithChildren) {
return (
<AppProviders>
{children}
</AppProviders>
);
}Creating the Shelby Client
Create a shared Shelby client instance. You can create a utility file:
import { ShelbyClient } from "@shelby-protocol/sdk/browser";
import { Network } from "@aptos-labs/ts-sdk";
export const shelbyClient = new ShelbyClient({
network: Network.SHELBYNET,
});It is recommended to create a shared instance of the Shelby client and use it throughout your application. This can be done in a utility file or a context provider.
Building the Upload Component
Now let's create a complete upload component with file input:
"use client";
import { useState, useCallback } from "react";
import { useWallet } from "@aptos-labs/wallet-adapter-react";
import { useUploadBlobs } from "@shelby-protocol/react";
import { shelbyClient } from "@/lib/shelby";
export function FileUpload() {
const { account, signAndSubmitTransaction, connected } = useWallet();
const [selectedFiles, setSelectedFiles] = useState<File[]>([]);
const uploadBlobs = useUploadBlobs({
client: shelbyClient,
onSuccess: () => {
alert("Files uploaded successfully!");
setSelectedFiles([]);
},
onError: (error) => {
alert(`Upload failed: ${error.message}`);
},
});
const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {
const files = Array.from(e.target.files || []);
setSelectedFiles(files);
};
const handleUpload = useCallback(async () => {
if (!connected || !account || !signAndSubmitTransaction) {
alert("Please connect your wallet first");
return;
}
if (selectedFiles.length === 0) {
alert("Please select at least one file");
return;
}
// Convert files to Uint8Array
const blobs = await Promise.all(
selectedFiles.map(async (file) => {
const arrayBuffer = await file.arrayBuffer();
return {
blobName: file.name,
blobData: new Uint8Array(arrayBuffer),
};
}),
);
// Set expiration time to 7 days from now (in microseconds)
const expirationMicros =
(Date.now() * 1000) + (7 * 24 * 60 * 60 * 1000 * 1000);
// Upload the blobs to the Shelby network
uploadBlobs.mutate({
signer: { account: account.accountAddress, signAndSubmitTransaction },
blobs,
expirationMicros,
});
}, [connected, account, signAndSubmitTransaction, selectedFiles, uploadBlobs]);
return (
<div>
<h1>Upload Files to Shelby</h1>
{!connected && (
<div>
<p>Please connect your wallet to upload files.</p>
</div>
)}
{connected && (
<div>
<div>
<label>
Select Files
</label>
<input
type="file"
multiple
onChange={handleFileSelect}
/>
</div>
<br/>
{selectedFiles.length > 0 && (
<div>
<p>Selected Files:</p>
<ul>
{selectedFiles.map((file, index) => (
<li key={index}>
{file.name} ({(file.size / 1024).toFixed(2)} KB)
</li>
))}
</ul>
</div>
)}
<br/>
<button
onClick={handleUpload}
disabled={uploadBlobs.isPending || selectedFiles.length === 0}
>
{uploadBlobs.isPending ? "Uploading..." : "Upload Files"}
</button>
<br/>
{uploadBlobs.isError && (
<div>
<p>
Error: {uploadBlobs.error?.message}
</p>
</div>
)}
</div>
)}
</div>
);
}Adding Wallet Connection UI
Create a simple wallet connection component:
"use client";
import { useWallet } from "@aptos-labs/wallet-adapter-react";
export function WalletConnection() {
const { connect, disconnect, connected, account, wallet } = useWallet();
if (connected && account) {
return (
<div>
<div>
<p>Connected</p>
<p>
{account.address.slice(0, 6)}...{account.address.slice(-4)}
</p>
</div>
<button onClick={disconnect}>
Disconnect
</button>
</div>
);
}
return (
<div>
<p>Connect your wallet</p>
<button onClick={connect}>
Connect Wallet
</button>
</div>
);
}For a more polished wallet connection experience, consider using one of the official wallet adapter UI packages. The Aptos Wallet Adapter provides UI components for popular design systems including shadcn/ui, Ant Design, and MUI. These packages provide pre-built wallet selector modals and connect buttons that you can integrate into your application.
Complete Example Page
Here's a complete example page that brings everything together:
"use client";
import { FileUpload } from "@/components/FileUpload";
import { WalletConnection } from "@/components/WalletConnection";
export default function UploadPage() {
return (
<div>
<header>
<div>
<h1>Shelby File Upload</h1>
<WalletConnection />
</div>
</header>
<main>
<FileUpload />
</main>
</div>
);
}Conclusion
You now have a complete file upload page that integrates with the Aptos Wallet Adapter! The page allows users to:
- Connect their wallet
- Select multiple files
- Upload files to the Shelby network
- See upload status and errors
This example demonstrates the core functionality of the Shelby React SDK. For more advanced usage and additional features, check out the mutation hooks documentation and query hooks documentation.
Upload Blobs Hook
Learn more about the useUploadBlobs hook
Account Blobs Query
Query your uploaded blobs