1

I have a question about something that has been bugging me for quite some time now. I am a bit confused on naming schemes in solidity and how I should go about it. For example, the biggest thing for me is how I should name variables in functions. I understand function variables are local variables however sometimes they can have the same name as a state variable. In that case would I have to change the function variables(the variable being used as an arguement I mean) or can I keep them the same? I get the undefined identifier error often so a lot of my errors involve naming scheme issues. I will post my contract down below to gice you guys a picture of what I mean. It is not a completed contract at all but I feel like this naming scheme thing is a big issue for me to understand clearly. Thank you guys so much in advance!

    // SPDX-License-Identifier: MIT


    pragma solidity 0.8.19;

    import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
    import "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Receiver.sol";
    import "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Supply.sol";
    import "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol";
    import  "@openzeppelin/contracts/token/common/ERC2981.sol";
    import "@openzeppelin/contracts/utils/Counters.sol";

    contract Horizons is ERC1155, ERC2981, ERC1155Supply, ERC1155URIStorage, 
    ERC1155Receiver{

    enum nftStatus{SOLD,INITIATED,CANCELLED}


    event nftListed(uint indexed tokenIds, address indexed creator, uint indexed price);
  

    event nftBought(uint indexed tokenIds, address indexed to, uint indexed price);
  

    event nftSold(uint indexed tokenIds, address indexed from, uint indexed price);


    event nftCancelled(uint indexed tokenIds,uint indexed owner);




    uint256 public tokenSupply;




    using Counters for Counters.Counter;
    //_tokenIds variable has the most recent minted tokenId
    Counters.Counter private _tokenIds;
    //Keeps track of the number of items sold on the marketplace
    Counters.Counter private _itemsSold;
    //owner is the contract address that created the smart contract
    address payable owner;
    //The fee charged by the marketplace to be allowed to list an NFT
    uint256 listPrice = 0.01 ether;



    //an NFT item struct that contains the values of an NFT token
    struct nftItem{
        address owner;
        address from;
        address to;
        uint tokenId;
        uint price;
        bool currentlyListed;
    }


     //a mapping that holds the value of the nftItem struct
     mapping(uint256 => nftItem) public _nftItem;

    //initiating the nftItem struct
    nftItem public NftItem ;



        //constructor will set the owner of this contract to the msg.sender
      constructor () {
        owner = payable(msg.sender);
    }



      //a function that gets the details of an NFT
    function getNftDetails() public view returns (address _owner, uint256 _price, 
    address _creator) {
        return (nftItem.owner, nftItem.price, nftItem.creator);
   
    }




    function updateListing(uint256 _listPrice) public payable {
        require( owner == msg.sender, "Only the owner can update this listing price");
        listPrice = _listPrice;
    }




    function getListingPrice() public view returns(uint256) {
        return listPrice;
    }





    function getCurrentToken() public view returns(uint256){
        return _tokenIds.current();
    }






        //a function that allows a user to list their NFTs. No need to create a minting 
    function as ERC1155 implements the function already
    
    function listNFT(
        uint nftId, 
        uint priceOfNft
    ) 
       external 
    {
       require (balanceOf[msg.sender] > 0, "Not enough funds to list NFT");
       require (priceOfNft[nftId] >= 0, "Listing price must be greater than 0");

          if(balanceOf[msg.sender] <= 0){

         revert("Funds not sufficient enough to list NFT");
     }


      if(priceOfNft[nftId] <= 0){
        revert("Listing price must be greater than 0");
      }

      balanceOf[msg.sender] += amount;
      tokenSupply.increment();

      tokenIds = _tokenIds;

       emit nftListed(tokenIds, creator, price);
     }



    function getListing(uint memory tokenId)
       public
       view
       virtual
       returns (nftItem memory)
    {
     return _nftItem[tokenIdss];
    }




        //a function that allows users to cancel a listing
   function cancelListing(uint256 nftId) external {
       require(exists[nftId] > 0, "NFT does not exist");
       require(balance[msg.sender] > 0, "Balance not sufficient enough to cover 
   cancellation costs");

       if(exists[nftId] <= 0){
        revert("NFT does not exist");
      }

      if(balance[msg.sender] <= 0){
           revert("Balance cannot cover costs to cover cancellation fee");
      }

    }





    //a function that will allow users to purchase their chosen NFTs.
    function buyNFT(
      uint nftId, 
      uint priceOfNFT, 
      address _to
    )
      external payable
    {
       require (balanceOf[msg.sender] > 0, "Not enough funds");
       require (balanceOf[msg.sender] >= priceOfNFT[nftId], "Funds not sufficient enough 
   to purchase this NFT");
       require(msg.sender != address(0));
       require(_exists(nftId));


      if(balanceOf[msg.sender] <= 0){
            
          revert ("Transaction cannot proceed due to insuffiecient funds");
      }

         if(balanceOf[msg.sender] <= 0){

        revert("Transaction cannot proceed due to insufficient funds to purchase this 
      NFT");
         }

        balance[msg.sender] -= amount;
        balance[_from] += amount;



        emit nftBought(tokenId, to, price);

   }








       function resellNFT(
        uint _tokenId, 
        uint _price, 
        address _from
    ) 
        external 
    {
        require (_tokenId[amount] > 0, "NFT is not availible");
        require (_price[_tokenId] > 0, "NFT price must be greater than 0");
        require (_from[_tokenId] = _owner[_tokenId]);

        balance[_to] -= amount;
        balance[msg.sender] += amount;

      }




    //This will return all the NFTs currently listed to be sold on the marketplace
    function getAllNFTs() public view returns (nftItem[] memory) {
        uint nftCount = _tokenId.current();
        nftItem[] memory tokens = new nftItem[](nftCount);
        uint currentIndex = 0;

        //at the moment currentlyListed is true for all, if it becomes false in the 
        future we will 
       //filter out currentlyListed == false over here

    for(uint i=0;i<nftCount;i++)
        {
         uint currentId = i + 1;
         nftItem storage currentItem = idToNftIten[currentId];
         tokens[currentIndex] = currentItem;
         currentIndex += 1;
       }
      //the array 'tokens' has the list of all NFTs in the marketplace
       return tokens;
     }






    //Returns all the NFTs that the current user is owner or seller in
    function getMyNFTs() public view returns (nftItem[] memory) {
        uint totalItemCount = _tokenId.current();
        uint itemCount = 0;
        uint currentIndex = 0;
    
      //Important to get a count of all the NFTs that belong to the user before we can 
    make an array for them
 
    for(uint i=0; i < totalItemCount; i++)
     {
      if(idToNftItem[i+1].owner == msg.sender || idToNftItem[i+1].seller == msg.sender){
            itemCount += 1;
       }
     }

       //Once you have the count of relevant NFTs, create an array then store all the 
    NFTs in it

    NftItem[] memory items = new nftItem[](itemCount);
     for(uint i=0; i < totalItemCount; i++) {
     if(idToNftItem[i+1].owner == msg.sender || idToNftItem[i+1].seller == msg.sender) {
        uint currentId = i+1;
        nftItem storage currentItem = idToNftItem[currentId];
        items[currentIndex] = currentItem;
        currentIndex += 1;
         }
      }
         return items;
     }

Code looks messy I know I am working on it. I am building an NFT Marketplace so its a bit crazy right now haha. Basically all the errors that I get are undeclared identifiers. For example, I get an undelcared identifier for tokenIds = _tokenIds saying that did you mean tokenIds = tokenIds?, Another example would be for balance[_to] when the compiler says did you mean to instead of _to? Everything is involving my naming schemes and declaration apparently.

1 Answer 1

1

Solidity may warn you about having identical variable names when you compile, but it will still let you deploy the contracts so you have to be careful when using names that shadow an existing one.

Use this contract as an example:

contract NameScheme {

    uint apple = 0;
    uint orange = 0;
    uint banana = 0;

    //  Since apple, orange, and banana are declared in the scope of the function, 
    //  it will use the input as opposed to the state variables with the same name
    //  meaning this function returns 3 when given the input: 1, 1, 1
    function a(uint apple, uint orange, uint banana) public pure returns(uint) {
        return apple + orange + banana;
    }

    // Since apple and orange are declared in the scope of the function,
    // it will use those two variables as opposed to the state variables, 
    // however since banana is never declared in the scope of the function, 
    // it will use the only existing state variable
    // meaning this function returns 2 when given the input: 1, 1
    function b(uint apple, uint orange) public view returns(uint) {
        return apple + orange + banana;
    }

    // the three variables are shadowed like in `a()`, 
    // but this time they are also declared inside the function itself
    // since the shadowed variables are shadowed again, 
    // the newest shadow variable will be used
    // meaning this function returns 6 when given the input: 1, 1, 1
    function c(uint apple, uint orange, uint banana) public pure returns(uint) {
        uint apple = 2;
        uint orange = 2;
        uint banana = 2;
        return apple + orange + banana;
    }
    
}

To get around having to keep track of which scope you are in, its probably best practice to avoid shadowing existing variables. A good solution to this is to use slightly altered forms of the existing names, which comes naturally if you follow some of the style guides for variable names.

Some common ones that I've seen used are:

  1. underscore prefix internal/private variables

string private name; --> string private _name;

  1. i prefix for immutable variables

string immutable name; --> string immutable i_name;

  1. all caps for constant variables

string constant name = alice; --> string constant NAME = alice;

By using some of these naming conventions, you can then use a normal looking name for your function's input.

uint private _name;

function setName(string memory name) public {
_name = name;
}

Despite all of that, your particular error is because you have your variable order backwards:

Instead of trying to set _tokenIds object to tokenIds like this: tokenIds = _tokenIds, it should be _tokenIds = tokenIds.

And your other function:

 function resellNFT(
        uint _tokenId, 
        uint _price, 
        address _from
    ) 
        external 
    {
        require (_tokenId[amount] > 0, "NFT is not availible");
        require (_price[_tokenId] > 0, "NFT price must be greater than 0");
        require (_from[_tokenId] = _owner[_tokenId]);

        balance[_to] -= amount;
        balance[msg.sender] += amount;

      }

You use _to inside of balance[_to] -= amount;, however, the variable _to is never declared inside the function or as a state variable.

5
  • thank you so much for responding. Ever since I put this question I have been working on mu contract and I seemed to have fixed almost all the issues. The naming thing is something I need to get a hang on. So when it comes down to using variables in functions, they are unrelated to the state variables declared in the global scope of your contract? And in order to declare function variables I have to input those variables as arguements in the function ?
    – EGstacking
    Commented Sep 13, 2023 at 15:08
  • 1
    @EGstacking Yes, even shadowed-named variables inside of a function are unrelated to global variables with the same name. And no, you can declare variables inside of functions in almost the same way you do with global variables, one main difference is that you don't need to pass the visibility.
    – Rohan Nero
    Commented Sep 13, 2023 at 20:18
  • 1
    Ok that makes so much sense now. That has been confusing me for a long time now. So when it comes down to variable usage in a function, in all comes down to them being defined and declared within the function itself? So basically everything is being created within the function ?
    – EGstacking
    Commented Sep 14, 2023 at 17:37
  • 1
    @EGstacking If you declare a variable inside a function, then only that function can see/use the variable. If you declare a variable outside of a function, i.e. global variables, any function can see/use it. So if function a() needs to use a variable uint x, it either needs to be declared globally, inputted to the function as a parameter, or declared inside the function. (Also side note, whenever you ask a question and an answer actually solves it, make sure to mark it as such using the little green check mark to the left of the answer, this lets other people know it is a valid solution)
    – Rohan Nero
    Commented Sep 14, 2023 at 20:10
  • 1
    I see. Thank you so much for the help! This has been bugging me for a really long time and you just cleared it up well. I gave all your comments a check mark:)
    – EGstacking
    Commented Sep 14, 2023 at 20:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.