Harmony
Support ForumGithubTelegramDiscord
  • Welcome
  • 🎶General
    • Introduction
      • What is Harmony?‌
      • Roadmap
      • Strategy & Architecture
      • Study Materials
      • FAQ
    • Technology
      • Key Features
      • Randomness
      • Sharding
      • Consensus
      • Effective Proof-of-Stake
      • Tokenomics
      • Transactions
    • LayerZero Bridge
      • Important Notice
      • Bridge tutorial
      • FAQ
        • What token will I get after the bridge
        • How to find a bridged token address
    • Ecosystem
      • Wallets
        • 1Wallet
        • Gnosis Safe
        • Hardware Wallets
          • Trezor
          • Ledger Nano
            • Ledger with Metamask
            • Download & Setup
            • Ledger with HMY CLI
            • Ledger with Staking Dashboard
              • Sign In With Ledger
              • Sending transactions via Ledger
              • Staking Transactions via Ledger
          • Safepal
            • Download & setup
            • Create/import account
            • Send transaction
        • Browser Extension Wallets
          • Metamask
            • Installing MetaMask
            • Adding Harmony
            • Create a New Account
            • Sending & Receiving
            • Adding Custom Harmony Tokens
            • Import an Account
          • Math Wallet
            • Download & Setup
            • Create/Import/Export Wallet
            • Sending Transactions
            • Staking
            • Collecting Rewards
            • Undelegating
          • Harmony Chrome Extension Wallet
        • Desktop Wallets
          • Guarda Wallet
          • Staking4All Wallet
        • Mobile Wallets
          • Metamask Wallet
          • Blits Wallet
          • Cobo Wallet
          • Frontier Wallet
          • Guarda Wallet
          • Infinity Wallet
          • ONTO Wallet
          • Sef Wallet
          • Trust Wallet
          • Trustee Wallet
        • Web Wallets
          • Guarda Wallet
        • HMY CLI (Harmony Command Line Interface)
          • Download & Setup
          • Create or Import Wallet
          • Sending Transactions
          • Staking Transactions
          • Querying Balances
          • Querying the Blockchain
          • List of Transaction Error Messages
          • Cookbook
          • Other CLI References
      • DApps
        • User Guide
        • DeFi
          • Sushi
          • Onsen
        • CLI 1Wallet User Guide
        • Media
          • Timeless
        • FAQ
        • NFTs
      • Partners
        • Exchanges
        • Fiat Gateways
        • DeFi Protocols
      • Integrations
      • Cross-Border Finance
      • DAOs
        • Components & Tools
          • Snapshot
        • Community DAO
        • Validator DAO
        • Developer DAO
    • Community
  • 🏗️Developers
    • Getting Started
      • Network & Faucets
      • List of RPC Providers
      • Remix IDE
      • Dev Environment Setup
      • Ethereum Compatibility
    • Deploying on Harmony
      • Using Remix
        • Ethereum Remix
        • Harmony Remix
      • Using Truffle
      • Using Hardhat
      • Using Web3
      • Using Harmony-JS
        • Setup
        • Compile & Deploy
        • Demo: Deploying an Ethereum Smart Contract on Harmony
      • Deploy HRC20
      • Smart Contract Verification
    • SDK
      • Web3.js
        • Using Web3.js to Send Transactions on Harmony
        • Find the last transaction
      • JavaScript SDK
      • Go CLI
      • Java SDK
      • Python SDK
      • Harmony Ethers.js Wrapper
    • API
      • Methods
        • Account Methods
          • hmy_getBalanceByBlockNumber
          • hmy_getTransactionCount
          • hmy_getBalance
        • Filter Methods
          • hmy_getFilterLogs
          • hmy_newFilter
          • hmy_newPendingTransactionFilter
          • hmy_newBlockFilter
          • hmy_getFilterChanges
          • hmy_getLogs
        • Transaction Related Methods
          • hmy_getStakingTransactionByBlockHashAndIndex
          • hmy_getStakingTransactionByBlockNumberAndIndex
          • hmy_getStakingTransactionByHash
          • hmy_getCurrentTransactionErrorSink
          • hmy_getPendingCrossLinks
          • hmy_getPendingCXReceipts
          • hmy_getCXReceiptByHash
          • hmy_pendingTransactions
          • hmy_sendRawStakingTransaction
          • hmy_getTransactionsHistory
          • hmy_sendRawTransaction
          • hmy_getTransactionReceipt
          • hmy_getBlockTransactionCountByHash
          • hmy_getBlockTransactionCountByNumber
          • hmy_getTransactionByHash
          • hmy_getTransactionByBlockNumberAndIndex
          • hmy_getTransactionByBlockHashAndIndex
          • hmy_getBlockByNumber
          • hmy_getBlockByHash
          • hmy_getBlocks
        • Contract Related Methods
          • hmy_estimateGas
          • hmy_getStorageAt
          • hmy_call
          • hmy_getCode
        • Protocol Related Methods
          • hmy_isLastBlock
          • hmy_epochLastBlock
          • hmy_latestHeader
          • hmy_getShardingStructure
          • hmy_blockNumber
          • hmy_syncing
          • hmy_gasPrice
          • net_peerCount
          • hmy_getEpoch
          • hmy_getLeader
        • Staking Related Methods
          • hmy_getCirculatingSupply
          • hmy_getTotalSupply
          • hmy_getStakingNetworkInfo
          • hmy_getAllValidatorInformation
          • hmy_getAllValidatorInformationByBlockNumber
          • hmy_getCurrentUtilityMetrics
          • hmy_getDelegationsByValidator
          • hmy_getDelegationsByDelegatorAndValidator
          • hmy_getDelegationsByDelegator
          • hmy_getValidatorMetrics
          • hmy_getMedianRawStakeSnapshot
          • hmy_getElectedValidatorAddresses
          • hmy_getAllValidatorAddresses
          • hmy_getCurrentStakingErrorSink
          • hmy_getValidatorInformation
          • hmy_getValidators
          • hmy_getSignedBlocks
          • hmy_isBlockSigner
          • hmy_getBlockSigners
        • Tracing Methods
          • trace_block
          • trace_transaction
      • Sample Code
    • Tools
      • Harmony VRF
      • The Graph
      • Envio
      • Ganache
        • Harmony Ganache
      • Harmony-React
      • Oracles
        • Band Protocol
      • Smart Contract Verification
    • Tutorials
      • Deploying HRC20
      • Deploying HRC721/NFT
      • The Graph - Subgraphs
        • Building & Deploying Subgraph (local node)
      • Using Band Oracle
      • Using Crosschain API
        • Scripts
        • Testing
        • Webserver
      • Using Web3.py & Pyhmy
      • Using IPFS & Filecoin
        • Using IPFS
        • Using NFT.storage
      • Indexing HRC20 with Envio
      • Building a Simple Metaverse Contract
      • Building a Simple Bridge with Ethereum
      • Staking for Multisig
    • DApp Examples
      • DApp Samples
      • Games
        • Harmony Puzzle
      • Cross-Chain
      • DeFi
      • Hackathons
        • DevPost
        • Hack the Horizon
      • Others
    • Wallets
      • Metamask
        • Interacting With Metamask
        • Using Metamask with Harmony Smart Contracts
        • Add or Switch to Harmony chain on Metamask
      • Harmony Chrome Extension Wallet
      • Math Wallet
      • WalletConnect
    • Harmony Stack and Projects
  • 🌏Network
    • Governance
      • Network Governance
        • Voting via Governance App
        • Voting via HMY CLI
      • HRC-20 Governance
      • FAQ
    • Validators
      • Terms & Concepts
        • Validator, BLS key, Instance
          • Shard Assignment
        • Slots Bidding and Election
        • Effective Proof-of-Stake
        • Block Reward
        • Epoch Transition
        • Slashing
        • Undelegation
      • Server Setup
        • Requirements
        • Cloud Guides
          • Digital Ocean
          • Vultr
          • AWS
          • Google Cloud
        • Raspberry Pi Guide
      • Node Setup
        • 1. HMY CLI Download
        • 2. Setting up BLS Keys
        • 3. Syncing DB
        • 4. Installing & Updating
          • Installing A Node
            • Using Node Binary
            • (Deprecated) Using AutoNode
              • Install & Run
              • Update
              • Monitor
              • BLS Key Management
              • Collect Rewards
              • Maintenance
              • Troubleshoot
              • Extra
            • (deprecated) Using Node.sh
          • Upgrading A Node
            • Using Node Binary
            • Using AutoNode (deprecated)
            • Using Node.sh (deprecated)
          • Checking A Node
      • Creating A Validator
      • Managing A Validator
        • Checking Validator Information
        • Changing Validator Information
        • Delegating To A Validator
        • Undelegating From A Validator
        • Check Your Delegations
        • Collecting Rewards
        • Adding A Validator Logo
      • Staking Dashboard Basics
      • Validator Information Terms
      • Validator Security Tips
      • Slashing and Uptime
      • Monitoring
        • Node Sync
        • Prometheus & Grafana
        • Network Status
      • Troubleshooting
        • Why am i not Elected?
        • Frequently Asked Questions (FAQ)
      • Tools
        • Telegram Bots
        • Dashboards
        • Reward Calculators
        • Text User Interface (TUI)
        • HMY Bidder
        • Mobile Apps
          • One Validator Dashboard
          • Termux
    • Delegators
      • Introduction
      • Staking
        • Via Browser
          • Staking Dashboard
          • Staking Transactions
          • Sending Transactions
        • Via Mobile
        • FAQ
      • Redelegation
      • Informational Videos
Powered by GitBook
On this page
  • Context
  • Video link
  • Github Link
  • Prerequisites
  • Step 1 - Install IPFS
  • Step 2 - Install Metamask
  • Step 3 - Create a smart contract
  • Step 4 - Integrating IPFS + Harmony Blockchain
  • Conclusion

Was this helpful?

Export as PDF
  1. Developers
  2. Tutorials
  3. Using IPFS & Filecoin

Using IPFS

This tutorial will show how to use IPFS on harmony blockchain

PreviousUsing IPFS & FilecoinNextUsing NFT.storage

Last updated 3 years ago

Was this helpful?

Context

Harmony blockchain can be used to store data. But is it really worth the cost? To put into perspective 1 byte of a data can cost you 42,107 gas or 0.00042017 ONE token, or equal to about $0.00003092031 in today's market. It maybe small for just one byte of data but let's say you want to store a file with 1 GB data (1,000,000,000 bytes) it will cost you $30920.31. The solution is IPFS, the InterPlanetary File System.

What is IPFS?

IPFS is a distributed system for storing and accessing files, websites, applications, and data. Using IPFS as a storage you don't need to store entire files to harmony blockchain you just need to store the hash of the IPFS to the harmony blockchain, thus make it much more cheaper then just storing the file.

In this tutorial, we are going to use IPFS to store some files offchain and store the hash of the file to the blockchain. And we will also get the data back from blockchain, and show it to the webpage.

Video link

Github Link

Prerequisites

In this entire tutorial i'm using windows 10, but you can use any other os.

Step 1 - Install IPFS

ipfs config --json API.HTTPHeaders.Access-Control-Allow-Origin "["""webui://-""", """http://localhost:3000""", """http://127.0.0.1:5001""", """https://webui.ipfs.io"""]"

ipfs config --json API.HTTPHeaders.Access-Control-Allow-Methods "["""PUT""", """POST"""]"

This command needed so that we can upload our file without any CORS problem. After that run this command to run ipfs locally:

ipfs daemon

Step 2 - Install Metamask

Then after that write this one by one:

Network Name :
Harmony Testnet

New RPC URL :
https://api.s0.b.hmny.io

Chain ID :
1666700000

Currency Symbol :
ONE

Block Explorer URL :
https://explorer.pops.one/

you will then get your address like this :

Put it in the harmony testnet faucet and click send me and you will get your harmony one token filling up.

Step 3 - Create a smart contract

First we need to install truffle. To install truffle go to your command prompt and type:

npm install -g truffle

Now create a folder and go inside that folder and type on the command prompt:

truffle init

After you run that command basically you will get some file and folder like this:

contracts/  migrations/  test/  truffle-config.js

So now i want you to go to contract folder and create a file called IPFSstorage.sol and paste this code in that file:

pragma solidity 0.8.6;
contract IPFSstorage {
 string ipfsHash;

 function sendHash(string memory x) public {
   ipfsHash = x;
 }

 function getHash() public view returns (string memory x) {
   return ipfsHash;
 }
}

So this is actually a really basic smart contract with the purpose of storing the hash of the file to the blockchain. sendHash is to store the hash, and getHash is to get the hash. After that go to the migrations folder and create a file called 2_ipfs_storage_migration.js and paste this code into that file :

var IPFSstorage = artifacts.require("./IPFSstorage.sol");

module.exports = function(deployer) {
    // Demo is the contract's name
    deployer.deploy(IPFSstorage);
};

This code is basically used for deploying our contract to our testnet later using truffle. Now go back to the root of our folder and look for truffle-config.js file and replace the code inside of that file with this :

require('dotenv').config()

const PrivateKeyProvider = require('./private-provider')

const networkId = {
  Mainnet: 1666600000,
  Testnet: 1666700000
}

module.exports = {
  networks: {
    localnet: {
      provider: () => {
        return new PrivateKeyProvider(process.env.LOCALNET_PRIVATE_KEY, 'http://localhost:9500', networkId.Testnet)
      },
      network_id: networkId.Testnet
    },

    testnet: {
      provider: () => {
        return new PrivateKeyProvider(process.env.TESTNET_PRIVATE_KEY, 'https://api.s0.b.hmny.io', networkId.Testnet)
      },
      network_id: networkId.Testnet
    },

    mainnet: {
      provider: () => {
        return new PrivateKeyProvider(process.env.MAINNET_PRIVATE_KEY, 'https://api.s0.t.hmny.io', networkId.Mainnet)
      },
      network_id: networkId.Mainnet
    }
  },

  compilers: {
    solc: {
      version: '0.8.6'
    },
  }
}

After that create a file called private-provider.js and copy paste this code :

const ProviderEngine = require('@trufflesuite/web3-provider-engine');
const WalletSubprovider = require('@trufflesuite/web3-provider-engine/subproviders/wallet');
const RpcSubprovider = require('@trufflesuite/web3-provider-engine/subproviders/rpc');
const EthereumjsWallet = require('ethereumjs-wallet');

// ChainIdSubProvider
function ChainIdSubProvider(chainId) {
  this.chainId = chainId;
}
ChainIdSubProvider.prototype.setEngine = function (engine) {
  const self = this;
  if (self.engine) return;
  self.engine = engine;
};
ChainIdSubProvider.prototype.handleRequest = function (payload, next, end) {
  if (
    payload.method == 'eth_sendTransaction' &&
    payload.params.length > 0 &&
  typeof payload.params[0].chainId == 'undefined'
  ) {
    payload.params[0].chainId = this.chainId;
  }
  next();
};

// NonceSubProvider
function NonceSubProvider() { }
NonceSubProvider.prototype.setEngine = function (engine) {
   const self = this;
   if (self.engine) return;
   self.engine = engine;
};
NonceSubProvider.prototype.handleRequest = function (payload, next, end) {
  if (payload.method == 'eth_sendTransaction') {
    this.engine.sendAsync(
    {
      jsonrpc: '2.0',
      id: Math.ceil(Math.random() * 4415011859092441),
      method: 'eth_getTransactionCount',
      params: [payload.params[0].from, 'latest'],
    },
    (err, result) => {
      const nonce =
        typeof result.result == 'string'
          ? result.result == '0x'
            ? 0
            : parseInt(result.result.substring(2), 16)
          : 0;
      payload.params[0].nonce = nonce || 0;
      next();
    });
  } else {
    next();
  }
};

// PrivateKeyProvider
function PrivateKeyProvider(privateKey, providerUrl, chainId) {
  if (!privateKey) {
    throw new Error(
      `Private Key missing, non-empty string expected, got "${privateKey}"`
    );
  }

  if (!providerUrl) {
    throw new Error(
      `Provider URL missing, non-empty string expected, got "${providerUrl}"`
    );
  }

  this.wallet = EthereumjsWallet.default.fromPrivateKey(Buffer.from(privateKey, 'hex'));
  this.address = `0x${this.wallet.getAddress().toString('hex')}`;

  this.engine = new ProviderEngine({ useSkipCache: false });

  this.engine.addProvider(new ChainIdSubProvider(chainId));
  this.engine.addProvider(new NonceSubProvider());
  this.engine.addProvider(new WalletSubprovider(this.wallet, {}));
  this.engine.addProvider(new RpcSubprovider({ rpcUrl: providerUrl }));

  this.engine.start();
}

PrivateKeyProvider.prototype.sendAsync = function (payload, callback) {
  return this.engine.sendAsync.apply(this.engine, arguments);
};

PrivateKeyProvider.prototype.send = function () {
  return this.engine.send.apply(this.engine, arguments);
};

module.exports = PrivateKeyProvider;

Now create a file called package.json and copy paste this code :

{
  "name": "harmony-box",
  "version": "1.0.0",
  "dependencies": {
    "@openzeppelin/contracts": "^3.4.0",
    "@trufflesuite/web3-provider-engine": "^15.0.13-1",
    "ethereumjs-wallet": "^1.0.1",
    "dotenv": "^8.2.0",
    "truffle": "^5.1.66",
    "solc": "^0.7.6"
  }
}

And run npm install to install all the dependencies. Now create a file called .env and copy paste this code :

LOCALNET_PRIVATE_KEY='ENTER_PRIVATE_KEY_HERE'
TESTNET_PRIVATE_KEY='ENTER_PRIVATE_KEY_HERE'
MAINNET_PRIVATE_KEY='ENTER_PRIVATE_KEY_HERE'

Because we are gonna use testnet, we need to get our private key and set it in the .env file, on the TESTNET_PRIVATE_KEY variable. Let's go to the metamask and get our private key. Click the three dot again and click account detail and click export private key :

After you input your password you should see your private key, after that just copy past it in the .env file, on the TESTNET_PRIVATE_KEY variable. After that to deploy our smart contract you just need to run this command :

truffle migrate --network testnet --reset

Wait for it to complete and then you will get a contract address like this :

Save that contract address in the safe place, because we will need it in the next step.

Step 4 - Integrating IPFS + Harmony Blockchain

First thing first, we need to create a react application to communicate with the harmony blockchain and IPFS, much more easily, we gonna use nextjs framework for this one so to create it first we need to run this command :

npx create-next-app harmony-ipfs --use-npm --example "https://github.com/vercel/next-learn-starter/tree/master/learn-starter"
npm i @chakra-ui/react @emotion/react@^11 @emotion/styled@^11 framer-motion@^4 ipfs-http-client

After that create a directory called abi and copy paste the abi file called IPFSstorage.json from build/contracts folder on the root of the project.

Now go inside pages folder and create a file called _app.js and copy paste this code :

import { ChakraProvider } from "@chakra-ui/react"

function MyApp({ Component, pageProps }) {
  return (
    <ChakraProvider>
      <Component {...pageProps} />
    </ChakraProvider>
  )
}

export default MyApp

Now go to index.js and replace the code with this one :

import Head from 'next/head'
import { Container } from "@chakra-ui/react";
export default function Home() {
  return (
    <Container>
      <Head>
        <title>IPFS + Harmony</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>
    </Container>
  )
}

Add all of the import first below import { Container } from "@chakra-ui/react"; :

import { Button } from "@chakra-ui/react";
import { Center } from "@chakra-ui/react";
import Web3 from "web3";
import {
  Table,
  Thead,
  Tbody,
  Tr,
  Th,
  Td 
} from "@chakra-ui/react";
import {useRef,useState, useEffect} from "react"
import { create } from 'ipfs-http-client'
import IPFScontract from "../abi/IPFSstorage.json"

Let's create all the state that we need so that our application can function properly, below export default function Home() { copy paste this code :

const [inputFile,setInputFile]=useState(null)
  const [ethereumEnabled,setEthereumEnabled]=useState(false)
  const [web3,setWeb3]=useState(null)
  const [transaction,setTransaction]=useState(null)
  const [ipfsHash,setIpfsHash]=useState(null)

And then let's create a function that can be used for later to connect to our metamask put it below the state :

const ethEnabled = async () => {
    if (window.ethereum) {
      await window.ethereum.send('eth_requestAccounts');
      setWeb3(new Web3(window.ethereum))
      setEthereumEnabled(true)
      return true;
    }
    setEthereumEnabled(false)
    return false;
  }

And then let's create some code that can trigger the choose file button and also upload to ipfs :

 const fileInput = useRef(null); // trigger choose file button for later
  const client = create('http://localhost:5001/api/v0') // function to create a client to upload to ipfs later
  async function onChange(e){ // function to detect file change
    const file = e.target.files[0]
    setInputFile(file)  
  }

Let's create a function that can be used to upload the file to ipfs and harmony blockchain :

  async function uploadFileToIPFS(file){
    try {
      const added = await client.add(file)
      let contract = new web3.eth.Contract(IPFScontract.abi, "<contract address>")
      const from=(await web3.eth.getAccounts())[0]
      const contractTransaction=await contract.methods.sendHash(added.path).send({ from })
      setTransaction(contractTransaction)
      console.log(contractTransaction)
   setInputFile(null)

    } catch (error) {
      console.log('Error uploading file: ', error)
      return false

    }  
  }

If you remember before you save the contract address of IPFSstorage contract right replace <contract address> with your saved contract address, then after that let's create a function that can be used to get the hash of the file that we uploaded to IPFS :

async function getIPFSHash(){
    try {

      let contract = new web3.eth.Contract(IPFScontract.abi, "<contract address>")
      const contractIpfsHash=await contract.methods.getHash().call()
      setIpfsHash(contractIpfsHash)

    } catch (error) {
      console.log('Error getting hash: ', error)
      return false

    }  
  }

Last but not least, create a html that can be used to upload and display our blockchain transaction also our ipfs hash that we get from harmony blockchain copy paste this code below </Head> tag :

<input
      ref={fileInput}
        type="file"
        style={{visibility:"hidden"}}
        onChange={onChange}
      />
      <Center mt="10px"><b>Upload file to ipfs and harmony blockchain</b></Center>
      <Center h="100px" color="white">
      {!ethereumEnabled?<Button colorScheme="blue" onClick={()=>ethEnabled()}>Login with metamask</Button>:<Button colorScheme="orange">Logout</Button>}


      </Center>
      <Center style={{display:!ethereumEnabled?"none":"flex"}} h="100px" color="white">

        <Button colorScheme="blue" onClick={()=>fileInput.current.click()}>{inputFile?inputFile.name:"Choose File"}</Button>


      </Center>
      <Center style={{display:!ethereumEnabled||!inputFile?"none":"flex"}} h="100px" color="white">
        <Button colorScheme="green" onClick={()=>uploadFileToIPFS(inputFile)}>Upload File</Button>
      </Center>
      <Center style={{display:!ethereumEnabled||!transaction?"none":"flex"}}><b>Transaction Detail</b></Center>
      <Table style={{display:!ethereumEnabled||!transaction?"none":""}} variant="simple">
        <Thead>
          <Tr>
            <Th>Key</Th>
            <Th>Value</Th>
          </Tr>
        </Thead>
        <Tbody>
          <Tr>
            <Td>Transaction Hash</Td>
            <Td>{transaction?.transactionHash}</Td>

          </Tr>
          <Tr>
            <Td>Status</Td>
            <Td>{transaction?.status}</Td>

          </Tr>
          <Tr>
            <Td>Gas Used</Td>
            <Td>{transaction?.gasUsed}</Td>

          </Tr>
          <Tr>
            <Td>Block Number</Td>
            <Td>{transaction?.blockNumber}</Td>

          </Tr>
          <Tr>
            <Td>Block Hash</Td>
            <Td>{transaction?.blockHash}</Td>

          </Tr>
        </Tbody>

      </Table>
      <Center style={{display:!ethereumEnabled||!transaction?"none":"flex"}} h="100px" color="white">

        <Button colorScheme="blue" onClick={()=>getIPFSHash()}>Get IPFS URL</Button>



      </Center>
      <Center><a target="_blank" href={ipfsHash?`http://localhost:8080/ipfs/${ipfsHash}`:"#"}>{ipfsHash?`http://localhost:8080/ipfs/${ipfsHash}`:""}</a></Center>

This is our final code of index.js file :

import Head from 'next/head'
import { Container } from "@chakra-ui/react";
import { Button } from "@chakra-ui/react";
import { Center } from "@chakra-ui/react";
import Web3 from "web3";
import {
  Table,
  Thead,
  Tbody,
  Tr,
  Th,
  Td 
} from "@chakra-ui/react";
import {useRef,useState, useEffect} from "react"
import { create } from 'ipfs-http-client'
import IPFScontract from "../abi/IPFSstorage.json"
export default function Home() {
  const [inputFile,setInputFile]=useState(null)
  const [ethereumEnabled,setEthereumEnabled]=useState(false)
  const [web3,setWeb3]=useState(null)
  const [transaction,setTransaction]=useState(null)
  const [ipfsHash,setIpfsHash]=useState(null)
  const ethEnabled = async () => {
    if (window.ethereum) {
      await window.ethereum.send('eth_requestAccounts');
      setWeb3(new Web3(window.ethereum))
      setEthereumEnabled(true)
      return true;
    }
    setEthereumEnabled(false)
    return false;
  }
  const fileInput = useRef(null); // trigger choose file button for later
  const client = create('http://localhost:5001/api/v0') // function to upload to ipfs
  async function onChange(e){ // function to detect file change
    const file = e.target.files[0]
    setInputFile(file)  
  }
  async function uploadFileToIPFS(file){
    try {
      const added = await client.add(file)
      let contract = new web3.eth.Contract(IPFScontract.abi, "<contract address>")
      const from=(await web3.eth.getAccounts())[0]
      const contractTransaction=await contract.methods.sendHash(added.path).send({ from })
      setTransaction(contractTransaction)
      console.log(contractTransaction)
   setInputFile(null)

    } catch (error) {
      console.log('Error uploading file: ', error)
      return false

    }  
  }
  async function getIPFSHash(){
    try {

      let contract = new web3.eth.Contract(IPFScontract.abi, "<contract address>")
      const contractIpfsHash=await contract.methods.getHash().call()
      setIpfsHash(contractIpfsHash)

    } catch (error) {
      console.log('Error getting hash: ', error)
      return false

    }  
  }
  return (
    <Container>
      <Head>
        <title>IPFS + Harmony</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <input
      ref={fileInput}
        type="file"
        style={{visibility:"hidden"}}
        onChange={onChange}
      />
      <Center mt="10px"><b>Upload file to ipfs and harmony blockchain</b></Center>
      <Center h="100px" color="white">
      {!ethereumEnabled?<Button colorScheme="blue" onClick={()=>ethEnabled()}>Login with metamask</Button>:<Button colorScheme="orange">Logout</Button>}


      </Center>
      <Center style={{display:!ethereumEnabled?"none":"flex"}} h="100px" color="white">

        <Button colorScheme="blue" onClick={()=>fileInput.current.click()}>{inputFile?inputFile.name:"Choose File"}</Button>


      </Center>
      <Center style={{display:!ethereumEnabled||!inputFile?"none":"flex"}} h="100px" color="white">
        <Button colorScheme="green" onClick={()=>uploadFileToIPFS(inputFile)}>Upload File</Button>
      </Center>
      <Center style={{display:!ethereumEnabled||!transaction?"none":"flex"}}><b>Transaction Detail</b></Center>
      <Table style={{display:!ethereumEnabled||!transaction?"none":""}} variant="simple">
        <Thead>
          <Tr>
            <Th>Key</Th>
            <Th>Value</Th>
          </Tr>
        </Thead>
        <Tbody>
          <Tr>
            <Td>Transaction Hash</Td>
            <Td>{transaction?.transactionHash}</Td>

          </Tr>
          <Tr>
            <Td>Status</Td>
            <Td>{transaction?.status}</Td>

          </Tr>
          <Tr>
            <Td>Gas Used</Td>
            <Td>{transaction?.gasUsed}</Td>

          </Tr>
          <Tr>
            <Td>Block Number</Td>
            <Td>{transaction?.blockNumber}</Td>

          </Tr>
          <Tr>
            <Td>Block Hash</Td>
            <Td>{transaction?.blockHash}</Td>

          </Tr>
        </Tbody>

      </Table>
      <Center style={{display:!ethereumEnabled||!transaction?"none":"flex"}} h="100px" color="white">

        <Button colorScheme="blue" onClick={()=>getIPFSHash()}>Get IPFS URL</Button>



      </Center>
      <Center><a target="_blank" href={ipfsHash?`http://localhost:8080/ipfs/${ipfsHash}`:"#"}>{ipfsHash?`http://localhost:8080/ipfs/${ipfsHash}`:""}</a></Center>
    </Container>
  )
}

If you're successfully follow this tutorial you will get something like this :

Let's click on login button and you will see something like this :

Choose your account and click next and connect.

If you see connected button like above you're successfully connected to the site.

Click on choose file button and choose your file.

Click on upload file

Click on confirm and wait for a while.

After that if you get your transaction detail you're successfully uploaded your file to IPFS and harmony blockchain.

If you click on "Get IPFS URL" you will get your IPFS URL.

Conclusion

To install IPFS on your machine, there are so many ways to do it. You can see for yourself here . After that go to your command prompt and type:

There is also so many way to download metamask. If you're using chrome you can download it from here , and click on install metamask for chrome after you install the metamask you need to setup the metamask so that it can interact with harmony blockchain click on Custom RPC like below :

networks

Now you have an harmony one account on metamask testnet we need to fill some harmony one token you can do that by going to harmony one testnet faucet like this one , to get your address click on the three dot and click on view in explorer like this :

explorer
s
export
contract address

It will create a new directory called harmony-ipfs and install all the dependencies for you. We also need to style our app with some css, so we gonna use for this. Go inside the harmony-ipfs directory and install the dependencies :

metmask
choose
connected
choose file
upload
confirm
success
harmony

Congrats! You're successfully uploaded your file to IPFS and harmony blockchain. This is just a simple use case to upload and get a file from harmony blockchain. You can be creative and create a more complex use case like NFT metadata storage or something like that. And if you notice we are using local IPFS node. Which means if our IPFS node is down, you can't get your file. One thing you can do is using service like infura it is a free with some limitation IPFS service. You can also automatically pin your file to infura by changing the localhost:8080 to ipfs.infura.io, and your file can be seen forever, but you can't unpin it so be careful when using infura to upload your private file. That's it for now if you have any questions or suggestions feel free to ask in

🏗️
https://www.youtube.com/watch?v=AUzmku4xQLw
https://github.com/harmony-one/harmony-ipfs
Node.js
IPFS
Metamask
https://docs.ipfs.io/install/command-line/#official-distributions
https://metamask.io/download.html
https://faucet.pops.one/
chakra-ui
Official Harmony Discord