Table of contents
- Introduction
- Prerequisites
- Demo
- Step 1 - Setting up Moralis Server
- Step 2 - Moralis Server Details
- Step 3 - Creating a New React App
- Step 4 - Installing Moralis React SDK
- Step 5 - Initializing Moralis SDK in React
- Step 6 - Creating Moralis Login With Wallet Component
- Step 7 - Creating Moralis IPFS Uploader Component
- Step 8 - Creating Moralis IPFS Success Component
- Wrapping Up
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:
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:
Provide a valid email address with a password to create your Moralis account:
The next page is where you'll answer a few short questions.
Click next when you're done to create your Moralis account:
After successful registration, you'll be redirected to your Moralis dashboard.
On your dashboard:
1. Click on the "Create a new Server" button:
2. Select the "Mainnet Server":
3. You'll be prompted to confirm your registered 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.
5. Wait for Moralis to set up your server instance:
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:
The important server details that we need are:
- The Server URL
- The Application ID
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:
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.
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 thecomponent
folder. - Then, create a new
Login.jsx
file inside theauth
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 newFileUploader.jsx
andfile-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
andsuccess.css
folder in thesuccess
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:
Our IPFS uploader should look like this:
While our success page should look like this:
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.