How to Store Files on IPFS With Moralis React SDK ⛑

How to Store Files on IPFS With Moralis React SDK ⛑

Introduction

Moralis is a web3 platform that provides a backend service for blockchain projects. They offer the highest numbers of web3 and NFT APIs for authentication, blockchain account information, etc.

We'll make use of the Moralis IPFS saveIPFS() method to upload files (max 1GB) to the IPFS network.

This tutorial is a continuation of How to Store Files on the Blockchain Using IPFS. I'll advise you to check it out for an explanation of what an IPFS network is.

Prerequisites

As a prerequisite, you must be familiar with the fundamentals of React.js, which you can learn here.

Demo

Below is the demo video of the IPFS file uploader we're going to build at the end of this tutorial:

moralis-ipfs-uploader-demo.gif

The files uploaded with the saveIPFS() method are pinned on IPFS by default

At the end of this section, you'll be able to store and retrieve files from the IPFS network with Moralis.

Step 1 - Setting up Moralis Server

A Moralis server allows you to use the Moralis SDK to speed up the development of your dApp. - Moralis

In this first step, we're going to set up our Moralis Cloud Server and generate our Moralis Server API keys.

Go to Moralis.io and click on the "Sign Up for FREE" button:

Moralis landing page

Provide a valid email address with a password to create your Moralis account:

Moralis registration page - creating a Moralis account and confirm your email address

The next page is where you'll answer a few short questions.

Click next when you're done to create your Moralis account:

Moralis requesting survey questions

After successful registration, you'll be redirected to your Moralis dashboard.

On your dashboard:

1. Click on the "Create a new Server" button:

Creating a new Moralis Server

2. Select the "Mainnet Server":

Creating a new Moralis Mainnet Server

3. You'll be prompted to confirm your registered email address:

confirm your Moralis email address

4. Adding a new Mainnet Server:

From the popup:

  • Name your Moralis Server/Instance (ipfs-uploader-server).
  • Select the Region closest to you.
  • Select a Network (Mainnet).
  • For this tutorial, we're going to select all the available chains.
  • Click on the "Add Instance" button when you're done.

Moralis new Mainnet server popup form

5. Wait for Moralis to set up your server instance:

Moralis setting up new server

Step 2 - Moralis Server Details

After our server instance has been created, we can view our server credentials by clicking on the "View Details" button:

Moralis server API keys

The important server details that we need are:

  • The Server URL
  • The Application ID

Moralis server credentials

Pro tip: Do not expose your server details, as they give access to your dApp.

Step 3 - Creating a New React App

In this step, we'll create a new React application with Create React App (CRA) and npx package manager.

From your terminal:

  • Navigate to where you want your IPFS uploader project to live.

  • Run the command below to create a new moralis-ipfs-uploader React app project:

     npx create-react-app moralis-ipfs-uploader
    
  • When it's done, run the command below to navigate to the newly created moralis-ipfs-uploader directory:

     cd moralis-ipfs-uploader
    
  • Next, start your React app project server with the command below:

    npm run start
    
  • Our development server will start up on localhost:3000. Our React page should look like this: image.png

Step 4 - Installing Moralis React SDK

Now that our React application is ready, we're going to install the Moralis React SDK.

Run the following command from your moralis-ipfs-uploader directory terminal:

npm install moralis react-moralis

Step 5 - Initializing Moralis SDK in React

After setting up your Moralis server and installing the Moralis SDK (see Step 4), the next step is to establish a connection between our React app and our Moralis server through the Moralis SDK.

Create a .env file at the root of your project and store your Moralis server details above like this:

REACT_APP_MORALIS_SERVER_URL=https://XXXX.usemoralis.com:2053/server
REACT_APP_MORALIS_APP_ID=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Replace the placeholders with your Moralis credentials. Next, we need to restart our server after updating the src/.env file.

Use the short key below to stop your server:

ctrl + c

Start your server again with:

npm run start

Next, we'll wrap our App.js component with the moralisProvider from react-moralis. Update your App.js with the code below:

import "./App.css";
import { MoralisProvider } from "react-moralis";

function App() {
  const serverUrl = process.env.REACT_APP_MORALIS_SERVER_URL;
  const appId = process.env.REACT_APP_MORALIS_APP_ID;

  return (
    <MoralisProvider appId={appId} serverUrl={serverUrl}>
      <div className='App'>
        <header className='App-header'>
          <img src={logo} className='App-logo' alt='logo' />
          <p>
            Edit <code>src/App.js</code> and save to reload.
          </p>
          <a
            className='App-link'
            href='https://reactjs.org'
            target='_blank'
            rel='noopener noreferrer'
          >
            Learn React
          </a>
        </header>
      </div>
    </MoralisProvider>
  );
}

export default App;

Navigate to your browser network tab and search for the trackEvent request (refresh the page if you can't find it at first). If the response status is set to true that means our React application has established a connection with our Moralis Mainnet server.

image.png

Pro tip: Do not hard code your Moralis details in the MoralisProvider component.

Step 6 - Creating Moralis Login With Wallet Component

In this step, we'll create the login component of our IPFS uploader. Moralis doesn't support public file upload to IPFS, which means a user wallet must be connected before we can successfully save a file to the IPFS network with Moralis SDK.

From your src folder:

  • Create a new component folder.
  • Next, create a new auth folder in the component folder.
  • Then, create a new Login.jsx file inside the auth folder with the following lines of code:
import React from "react";
import { FileUploader } from "./../file-uploader/FileUploader";

// 0. Import Moralis SDK
import Moralis from "moralis";

export const Login = () => {
  const [isAuthenticated, setIsAuthenticated] = React.useState(false);
  const [isAuthenticating, setIsAuthenticating] = React.useState(false);

  // 1. Connect wallet function
  const connectWallet = async () => {
    // 2. Set isAuthenticating to true for button
    setIsAuthenticating(true);

    // 3. Connect wallet
    Moralis.authenticate()
      .then((user) => {
        // 4. Set isAuthenticated to true
        console.log(user);
        setIsAuthenticated(true);
        setIsAuthenticating(false);
      })
      .catch((error) => {
        // 5. Set isAuthenticated to false and alert the user of the error
        alert("Error authenticating: " + error);
        setIsAuthenticated(false);
        setIsAuthenticating(false);
      });
  };

  // 6. If a wallet is connected render the FileUploader component
  if (isAuthenticated) {
    return <FileUploader />;
  }

  return (
    <React.Fragment>
      <button onClick={connectWallet}>
        {isAuthenticating ? "Connecting Your Wallet..." : "Connect Your Wallet"}
      </button>
    </React.Fragment>
  );
};

From the code above, we're rendering a "login" button for the user to connect their wallet via MetaMask. When the user's wallet is connected, the authentication state is set to true so that we can render the FileUploader component, which we'll create in the next step.

Update your App.jsx file with the code below to render our Login component:

import "./App.css";
import { MoralisProvider } from "react-moralis";
import { Login } from "./component/auth/Login";

function App() {
  const serverUrl = process.env.REACT_APP_MORALIS_SERVER_URL;
  const appId = process.env.REACT_APP_MORALIS_APP_ID;

  return (
    <MoralisProvider appId={appId} serverUrl={serverUrl}>
      <Login />
    </MoralisProvider>
  );
}

export default App;

Step 7 - Creating Moralis IPFS Uploader Component

In this step, we're going to create our IPFS file uploader component named FileUploader — a form component that includes a file input and a button for the user to upload a file to the IPFS network.

From your component folder:

  • Create a new file-uploader folder.
  • In the file-uploader folder, create a new FileUploader.jsx and file-uploader.css files.
  • Next, copy and paste the CSS code below in our file-uploader.css file:
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  background-color: #1d1d1d;
  color: #fff;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
}

.form-wrapper {
  width: 100%;
  height: 100%;
  border: 1px solid #ccc;
  border-radius: 4px;
  box-shadow: 0 0 5px #ccc;
  padding: 10px;
}

.form-wrapper h2 {
  font-size: 1.5rem;
  margin-bottom: 1rem;
  text-align: center;
}

.form {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

input[type="file"] {
  width: 100%;
  height: 100%;
  border-bottom: 1px solid #ccc;
  padding: 10px;
  font-size: 16px;
  outline: none;
}

button {
  width: 100%;
  height: 100%;
  border: none;
  border-bottom: 1px solid #ccc;
  padding: 10px;
  font-size: 16px;
  outline: none;
  background: #00bcd4;
  color: #fff;
  cursor: pointer;
}

Next, we'll update our FileUploader.jsx component with the following code:

import React from "react";
import "./file-uploader.css";
import { Success } from "./../success/Success";

// 0. Import Moralis SDK
import Moralis from "moralis";

export const FileUploader = () => {
  // 1. Component States
  const [file, setFile] = React.useState(null);
  const [hash, setHash] = React.useState(null);
  const [loading, setLoading] = React.useState(false);

  // 3. File uploader handler
  const uploadFileToIpfs = async (e) => {
    e.preventDefault(); // Prevent page refresh

    // 4 Check if file is selected
    if (!file) {
      alert("Please select a file to upload");
      return;
    }

    // 5 Set loading state to true for button
    setLoading(true);

    try {
      // 6 Create a new file Moralis instance
      const moralisFileInstance = new Moralis.File(file.name, file);

      // 7 Upload file to IPFS
      await moralisFileInstance.saveIPFS({ useMasterKey: true });

      // 8 Get the file hash from IPFS
      console.log(moralisFileInstance.ipfs(), moralisFileInstance.hash());

      // 9 Set the file hash to state
      setHash(moralisFileInstance.hash());
    } catch (error) {
      // 10 Handle error
      alert("Error uploading file to IPFS: " + error);
    } finally {
      // 11 Set loading state to false for button
      setLoading(false);
    }
  };

  // 12 Render the success component if hash is set
  if (hash) {
    return <Success hash={hash} setHash={setHash} />;
  }

  return (
    <div className='form-wrapper'>
      <h2>Moralis IPFS Uploader</h2>
      <form>
        <input
          type='file'
          onChange={(e) => {
            setFile(e.target.files[0]);
          }}
        />
        <button onClick={uploadFileToIpfs}>
          {loading ? "Uploading..." : "Upload"}
        </button>
      </form>
    </div>
  );
};

From the code above, when an authenticated user has successfully uploaded a file to the IPFS network, we can then retrieve the hash of the file from the moralisFileInstance.hash() method.

We'll pass the hash and setHash as a prop to the <Success /> component which we'll create in the next step.

Step 8 - Creating Moralis IPFS Success Component

In this final step, we're going to create the <Success /> component that will be rendered after a file has been successfully created and the file hash is present.

In your component folder:

  • Create a new success folder.
  • Next, create a new Success.jsx and success.css folder in the success folder.
  • Next, copy and paste the CSS code below in our success.css file:
/* card */
.card {
  background-color: #fff;
  border-radius: 2px;
  box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
  margin-bottom: 20px;
  padding: 20px;
}

.card-body {
  padding: 0;
  color: #00bcd4;
}

.card-title {
  font-size: 1.5rem;
  margin-bottom: 1rem;
  text-align: center;
}

.card-text{
    font-size: 1.2rem;
    margin-bottom: 1rem;
    text-align: center;
}


.card-text-h3{
    font-size: 1.2rem;
    margin-bottom: 1rem;
    text-align: center;
}

.card-text-span{
    font-size: 0.8rem;
    margin-bottom: 1rem;
    text-align: center;
    font-weight: 500;

}

.img-wrapper {
  height: 255px;
}

img {
  width: 100%;
  height: 100%;
}

.card-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  justify-content: center;
}

.card-footer button {
  width: 50%;
  height: 100%;
  padding: 10px;
  font-size: 16px;
  color: #00bcd4;
  background: #fff;
  border: 1px solid #ccc;
  border-right: none;

}

.card-footer a {
    width: 50%;
    height: 100%;
    border: 1px solid #ccc;
    border-left: none;
    padding: 10px;
    font-size: 16px;
    outline: none;
    text-align: center;
    background: #00bcd4;
    color: #ffffff;
    text-decoration: none;
}

Next, we'll update our Success.jsx component with the following code:

import React from "react";
import "./success.css";
export const Success = ({ hash, setHash }) => {
  return (
    <div>
      <div className='card'>
        <div className='card-body'>
          <h5 className='card-title'>Success! 👍 </h5>
          <p className='card-text'>Your file has been uploaded to IPFS.</p>
          <h3 className='card-text-h3'>
            File Hash: <br />
            <span className='card-text-span'>{hash}</span>
          </h3>
          <div className='img-wrapper'>
            <img
              src={`https://ipfs.moralis.io:2053/ipfs/${hash}`}
              alt='ipfs-img'
            />
          </div>
        </div>
        <div className='card-footer'>
          <button onClick={() => setHash(null)}>Back</button>
          <a
            href={`https://ipfs.moralis.io:2053/ipfs/${hash}`}
            target={"_blank"}
            rel='noopener noreferrer'
          >
            View on IPFS
          </a>
        </div>
      </div>
    </div>
  );
};

Our Login page should look like this:

Screenshot 2022-05-02 at 12.43.09 AM.png

Our IPFS uploader should look like this:

Screenshot 2022-05-02 at 12.43.35 AM.png

While our success page should look like this:

Screenshot 2022-05-02 at 12.41.44 AM.png

Wrapping Up

InterPlanetary File System (IPFS) is a reliable and decentralized storage system. It is also widely regarded as the future of file storage.

In this article, we learned how to upload and access contents from the IPFS network using Moralis SDK.


This article is a part of the Hashnode Web3 blog, where a team of curated writers are bringing out new resources to help you discover the universe of web3. Check us out for more on NFTs, DAOs, blockchains, and the decentralized future.