diff --git a/pkgs/frontend/.env.example b/pkgs/frontend/.env.example
index b1024c6..86c625b 100644
--- a/pkgs/frontend/.env.example
+++ b/pkgs/frontend/.env.example
@@ -12,4 +12,6 @@ VITE_SPLITS_CREATOR_ADDRESS=0x9c3648df4bb82fdf067a9b083900a986f9b27e9a
VITE_PIMLICO_API_KEY=
-VITE_PINATA_JWT=
\ No newline at end of file
+VITE_PINATA_JWT=
+
+VITE_PINATA_GATEWAY=
\ No newline at end of file
diff --git a/pkgs/frontend/app/routes/_index.tsx b/pkgs/frontend/app/routes/_index.tsx
index 1bf028f..dabd1c3 100644
--- a/pkgs/frontend/app/routes/_index.tsx
+++ b/pkgs/frontend/app/routes/_index.tsx
@@ -1,7 +1,11 @@
-import { Box } from "@chakra-ui/react";
+import { Box, Input } from "@chakra-ui/react";
import type { MetaFunction } from "@remix-run/node";
import { CommonButton } from "~/components/common/CommonButton";
import { useBigBang } from "hooks/useBigBang";
+import {
+ useUploadMetadataToIpfs,
+ useUploadImageFileToIpfs,
+} from "hooks/useIpfs";
export const meta: MetaFunction = () => {
return [
@@ -12,6 +16,13 @@ export const meta: MetaFunction = () => {
export default function Index() {
const { bigbang, isLoading } = useBigBang();
+ const { uploadMetadataToIpfs, isLoading: isUploadingMetadataToIpfs } =
+ useUploadMetadataToIpfs();
+ const {
+ uploadImageFileToIpfs,
+ setImageFile,
+ isLoading: isUploadingImageFileToIpfs,
+ } = useUploadImageFileToIpfs();
const handleBigBang = async () => {
const res = await bigbang({
@@ -26,11 +37,39 @@ export default function Index() {
console.log(res);
};
+ const metadata = {
+ name: "Toban test",
+ description: "Toban test",
+ responsibilities: "Toban test",
+ authorities: "Toban test",
+ eligibility: true,
+ toggle: true,
+ };
+
return (
BigBang
+ uploadMetadataToIpfs(metadata)}
+ >
+ Upload Metadata to IPFS
+
+ ) =>
+ setImageFile(e.target.files?.[0] || null)
+ }
+ />
+
+ Upload Image File to IPFS
+
);
}
diff --git a/pkgs/frontend/hooks/useIpfs.ts b/pkgs/frontend/hooks/useIpfs.ts
index 127c718..6b18ffa 100644
--- a/pkgs/frontend/hooks/useIpfs.ts
+++ b/pkgs/frontend/hooks/useIpfs.ts
@@ -1,9 +1,9 @@
import { useState } from "react";
-import { PinataSDK } from "pinata-web3";
-import { Readable } from "stream";
+import { ipfsUploadJson, ipfsUploadFile } from "utils/ipfs";
export const useUploadMetadataToIpfs = () => {
const [isLoading, setIsLoading] = useState(false);
+ const [error, setError] = useState(null);
const uploadMetadataToIpfs = async ({
name,
@@ -19,13 +19,12 @@ export const useUploadMetadataToIpfs = () => {
authorities: string;
eligibility: boolean;
toggle: boolean;
- }) => {
+ }): Promise<{ ipfsCid: string; ipfsUri: string } | null> => {
setIsLoading(true);
+ setError(null);
try {
- const pinata = new PinataSDK({ pinataJwt: process.env.VITE_PINATA_JWT });
-
- const upload = await pinata.upload.json({
+ const upload = await ipfsUploadJson({
type: "1.0",
data: {
name,
@@ -37,45 +36,64 @@ export const useUploadMetadataToIpfs = () => {
},
});
- console.log("CID:", upload.IpfsHash);
- console.log("URI:", `ipfs://${upload.IpfsHash}`);
- } catch (error) {
- console.error(error);
+ const ipfsCid = upload.IpfsHash;
+ const ipfsUri = `ipfs://${ipfsCid}`;
+
+ console.log("Successfully uploaded metadata to IPFS");
+ console.log("IPFS CID:", ipfsCid);
+ console.log("IPFS URI:", ipfsUri);
+
+ return { ipfsCid, ipfsUri };
+ } catch (err) {
+ setError(
+ err instanceof Error ? err : new Error("Unknown error occurred")
+ );
+ return null;
} finally {
setIsLoading(false);
}
};
- return { uploadMetadataToIpfs, isLoading };
+ return { uploadMetadataToIpfs, isLoading, error };
};
-export const useUploadImageToIpfs = () => {
+export const useUploadImageFileToIpfs = () => {
const [isLoading, setIsLoading] = useState(false);
const [imageFile, setImageFile] = useState(null);
+ const [error, setError] = useState(null);
- const uploadImageToIpfs = async () => {
- if (!imageFile) return;
+ const uploadImageFileToIpfs = async (): Promise<{
+ ipfsCid: string;
+ ipfsUri: string;
+ } | null> => {
+ if (!imageFile || !imageFile.type.startsWith("image/")) {
+ setError(new Error("Invalid or no image file selected"));
+ return null;
+ }
setIsLoading(true);
+ setError(null);
try {
- const pinata = new PinataSDK({ pinataJwt: process.env.VITE_PINATA_JWT });
+ const upload = await ipfsUploadFile(imageFile);
- const buffer = await imageFile.arrayBuffer();
- const stream = Readable.from(Buffer.from(buffer));
+ const ipfsCid = upload.IpfsHash;
+ const ipfsUri = `ipfs://${ipfsCid}`;
- const upload = await pinata.upload.stream(stream, {
- metadata: { name: `TobanFrontend_${new Date().getTime()}` },
- });
+ console.log("Successfully uploaded image file to IPFS");
+ console.log("IPFS CID:", ipfsCid);
+ console.log("IPFS URI:", ipfsUri);
- console.log("CID:", upload.IpfsHash);
- console.log("URI:", `ipfs://${upload.IpfsHash}`);
- } catch (error) {
- console.error(error);
+ return { ipfsCid, ipfsUri };
+ } catch (err) {
+ setError(
+ err instanceof Error ? err : new Error("Unknown error occurred")
+ );
+ return null;
} finally {
setIsLoading(false);
}
};
- return { uploadImageToIpfs, setImageFile, isLoading };
+ return { uploadImageFileToIpfs, imageFile, setImageFile, isLoading, error };
};
diff --git a/pkgs/frontend/utils/ipfs.ts b/pkgs/frontend/utils/ipfs.ts
new file mode 100644
index 0000000..d22d008
--- /dev/null
+++ b/pkgs/frontend/utils/ipfs.ts
@@ -0,0 +1,51 @@
+import { PinataSDK } from "pinata-web3";
+
+const getPinataConfig = () => {
+ const pinataJwt = import.meta.env.VITE_PINATA_JWT;
+ const pinataGateway = import.meta.env.VITE_PINATA_GATEWAY;
+
+ if (!pinataJwt) {
+ throw new Error("VITE_PINATA_JWT is not defined");
+ }
+ if (!pinataGateway) {
+ throw new Error("VITE_PINATA_GATEWAY is not defined");
+ }
+
+ return { pinataJwt, pinataGateway };
+};
+
+let ipfsClient: PinataSDK | null = null;
+
+export const createIpfsClient = () => {
+ if (ipfsClient) return ipfsClient;
+
+ const { pinataJwt, pinataGateway } = getPinataConfig();
+ ipfsClient = new PinataSDK({
+ pinataJwt,
+ pinataGateway,
+ });
+
+ return ipfsClient;
+};
+
+export const ipfsUploadJson = async (object: object) => {
+ try {
+ const ipfsClient = createIpfsClient();
+ const upload = await ipfsClient.upload.json(object);
+ return upload;
+ } catch (error) {
+ console.error("Failed to upload JSON to IPFS:", error);
+ throw error;
+ }
+};
+
+export const ipfsUploadFile = async (file: File) => {
+ try {
+ const ipfsClient = createIpfsClient();
+ const upload = await ipfsClient.upload.file(file);
+ return upload;
+ } catch (error) {
+ console.error("Failed to upload file to IPFS:", error);
+ throw error;
+ }
+};