0

I am building a chat DApp. I have a smart contract and a mostly complete nextjs front end. My contract is deploying properly however, whenever I call my contract from the front end it doesn't work. My complete smart contract is attached at the bottom. Why isn't the mint function from my smart contract passing to the createProfile function in my front end?

The error occurs where the contract is called at 'contract.mint':

      const createProfile = async () => {
      if (!avatar || !username) return;
      try {
        const result = await client.add(JSON.stringify({ avatar, username }));
        setIsLoading(true);
        await (await contract.mint(`https://ipfs.infura.io/ipfs/${result.path}`)).wait();
            fetchMyNFTs();
            router.push('/');
        } catch (error) {
            window.alert("ipfs uri upload error: ", error)
        }
    };

The contract is called via the following path:

1st as a prop at the beginning of the larger react arrow function:

const Profile = ({ contract }) => {
etc ...
    const createProfile = async () => { etc ...

The 'contract' prop is defined in and passed from the _app.js file as {...pageProps}:

import Script from 'next/script';
import { ThemeProvider } from 'next-themes';
import { useState, useEffect } from 'react';
import { ethers } from "ethers";
import { BrowserRouter, Routes, Route, Router } from "react-router-dom";
import reactDom from 'react-dom';

import { Navbar } from '../components';
import '../styles/globals.css';
import DecentratwitterAbi from './contractsData/decentratwitter.json'
import DecentratwitterAddress from './contractsData/decentratwitter-address.json'
import { ChatProvider } from '../context/ChatContext.js';


const MyApp = ({ Component, pageProps }) => {
  const [currentAccount, setCurrentAccount] = useState(null);
  const [contract, setContract] = useState({});

  const web3Handler = async () => {
    let accounts = await window.ethereum.request({ method: 'eth_requestAccounts' });
    setCurrentAccount(accounts[0]);

    window.ethereum.on('chainChanged', () => {
      window.location.reload();
    })
    window.ethereum.on('accountsChanged', async () => {
      setIsLoading(true);
      web3Handler();
    });
    const provider = new ethers.providers.Web3Provider(window.ethereum);
    const signer = provider.getSigner();
    fetchContract(signer);
  };

  const fetchContract = async (signer) => {
    const contract = new ethers.Contract(DecentratwitterAddress, DecentratwitterAbi, signer);
    setContract(contract);
    setIsLoading(false);
  };

  return (
    <ChatProvider>
      <ThemeProvider attribute="class">
        <div className="dark:bg-nft-dark bg-white min-h-screen">
          <Navbar {...pageProps} />
          <div className="pt-65">
            <Component {...pageProps} />
          </div>
        </div>
        
        <Script src="https://kit.fontawesome.com/0faf8c3dc2.js" crossorigin="anonymous" />
      </ThemeProvider>
    </ChatProvider>
  );
};

export default MyApp;

Lastly, my 'DecentratwitterAbi' and 'DecentratwitterAddress' variables are passed into the contractsData folder from my deployment script:

const fs = require('fs');
const hre = require('hardhat');

async function main() {
  const Decentratwitter = await hre.ethers.getContractFactory('Decentratwitter');
  const decentratwitter = await Decentratwitter.deploy();

  await decentratwitter.deployed();

  const contractsDir = __dirname + "/../pages/contractsData";
  if (!fs.existsSync(contractsDir)) {
    fs.mkdirSync(contractsDir);
  }

  fs.writeFileSync(
    contractsDir + `/decentratwitter-address.json`,
    JSON.stringify({ address: decentratwitter.address }, undefined, 2)
  );

  const contractArtifact = artifacts.readArtifactSync("Decentratwitter");

  fs.writeFileSync(
    contractsDir + `/decentratwitter.json`,
    JSON.stringify(contractArtifact, null, 2)
  );

  console.log('Decentratwitter deployed to:', decentratwitter.address);
}

main()
  .then(() => process.exit(0))
  .catch((error) => {
    console.error(error);
    process.exit(1);
  });

Contract:

//SPDX-License-Identifier: MIT
// Two pages to app: Home and Profile
// Must have NFT to post content
// NFT will represent avatar. Store username and image as NFT metadata
// For profile page, if user has not created an NFT yet then a form will appear that allows users to mint their own NFT profile.
// For profile page, if user has created an NFT then it will display the users profile picture and username at the top of the page
// and below that there will be a form at the bottom that allows users to create a new NFT for their profile.

pragma solidity ^0.8.0;

import "hardhat/console.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";

contract Decentratwitter is ERC721URIStorage {
    uint256 public tokenCount;
    uint256 public postCount;
    mapping(uint256 => Post) public posts;
    // address --> nft id
    mapping(address => uint256) public profiles;

    struct Post {
        uint256 id;
        string hash;
        uint256 tipAmount;
        address payable author;
    }

    event PostCreated(
        uint256 id,
        string hash,
        uint256 tipAmount,
        address payable author
    );

    event PostTipped(
        uint256 id,
        string hash,
        uint256 tipAmount,
        address payable author
    );

    constructor() ERC721("Decentratwitter", "DAPP") {}

    function mint(string memory _tokenURI) external returns (uint256) {
        tokenCount++;
        _safeMint(msg.sender, tokenCount);
        _setTokenURI(tokenCount, _tokenURI);
        setProfile(tokenCount);
        return (tokenCount);
    }

    function setProfile(uint256 _id) public {
        require(
            ownerOf(_id) == msg.sender,
            "Must own the nft you want to select as your profile"
        );
        profiles[msg.sender] = _id;
    }

    function uploadPost(string memory _postHash) external {
        // Check that the user owns an nft
        require(
            balanceOf(msg.sender) > 0,
            "Must own a decentratwitter nft to post"
        );
        // Make sure the post hash exists
        require(bytes(_postHash).length > 0, "Cannot pass an empty hash");
        // Increment post count
        postCount++;
        // Add post to the contract
        posts[postCount] = Post(postCount, _postHash, 0, payable(msg.sender));
        // Trigger an event
        emit PostCreated(postCount, _postHash, 0, payable(msg.sender));
    }

    function tipPostOwner(uint256 _id) external payable {
        // Make sure the id is valid
        require(_id > 0 && _id <= postCount, "Invalid post id");
        // Fetch the post
        Post memory _post = posts[_id];
        require(_post.author != msg.sender, "Cannot tip your own post");
        // Pay the author by sending them Ether
        _post.author.transfer(msg.value);
        // Increment the tip amount
        _post.tipAmount += msg.value;
        // Update the image
        posts[_id] = _post;
        // Trigger an event
        emit PostTipped(_id, _post.hash, _post.tipAmount, _post.author);
    }

    // Fetches all the posts
    function getAllPosts() external view returns (Post[] memory _posts) {
        _posts = new Post[](postCount);
        for (uint256 i = 0; i < _posts.length; i++) {
            _posts[i] = posts[i + 1];
        }
    }

    // Fetches all of the users nfts
    function getMyNfts() external view returns (uint256[] memory _ids) {
        _ids = new uint256[](balanceOf(msg.sender));
        uint256 currentIndex;
        uint256 _tokenCount = tokenCount;
        for (uint256 i = 0; i < _tokenCount; i++) {
            if (ownerOf(i + 1) == msg.sender) {
                _ids[currentIndex] = i + 1;
                currentIndex++;
            }
        }
    }
}
2
  • Not an answer to your question but you should know that smart contracts are not databases. User profiles should not be stored on-chain. Jul 27 at 10:42
  • Also: consider using custom errors instead of revert reason strings. Compared to revert reason strings, custom errors are easier to work with, more gas efficient, and more elegant. Jul 27 at 10:42

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.