How can I fix IERC20 & IAccessControl interfaces causing 'Undeclared Identifier' error?

135 views Asked by At

I'm trying to use the OpenZeppelin IERC20 & and IAccessControl interfaces instead of importing the normal contracts to prevent maxing out on size.

When I was using the normal contracts, everything worked fine, except the size on some of my contracts. Thus, I switched to using the interfaces, but now I've got 'Undeclared Identifier' errors all through my code. (See screenshot)

Screenshot Showing The Errors

I've imported the interfaces. I don't know what I'm missing.

// SPDX-License-Identifier: MIT

// Pragma Declaration
pragma solidity ^0.8.0;

// Imports
import "@openzeppelin/contracts/interfaces/IERC20.sol";
import "@openzeppelin/contracts/access/IAccessControl.sol";

// Contract: FamCash
contract FamCash is IERC20, IAccessControl {

    // Role Identifiers - Creates roles for limiting specific functionality
    bytes32 public constant PARENT = keccak256("PARENT");
    bytes32 public constant MEMBER = keccak256("MEMBER");
    
    // Maximum Supply Limit
    uint256 public maxSupplyLimit = 1000000;

    // Constructor Implementation - Sets name & ticker; Assigns roles to msg.sender
    constructor(address contractOwner, string memory tokenName, string memory tokenTicker)
    IERC20(tokenName, tokenTicker) {

        // Role Assignments
        _grantRole(DEFAULT_ADMIN_ROLE, contractOwner);
        _grantRole(PARENT, contractOwner);
        _grantRole(MEMBER, contractOwner);
    }
    
    // Mint Function - Mints new tokens
    function mint(address recipient, uint256 amount) public {

        // Requirement – Only PARENT role can mint
        require(!hasRole(PARENT), "Only parents can mint.");

        // Input validation - Checks for valid address and amount
        require(recipient != address(0), "Invalid recipient address");
        require(amount > 0, "Amount must be greater than zero");
        
        // Total Supply - Sets the supply by adding the amount
        uint256 totalSupplyAfterMint = totalSupply() + amount;

        // Post-Mint Check - Stops request from exceeding the minting limit
        require(totalSupplyAfterMint <= maxSupplyLimit, "Exceeds max supply limit");
    
        // _mint - Sends specified token amount to specified recipient
        _mint(recipient, amount);
    }
    
    // Send Function - Sends tokens to a recipient
    function send(address recipient, uint256 amount) public {
        
        // Requirement – hasRole of PARENT or FAMILY – Limit sending to family
        require(!hasRole(PARENT, msg.sender) || !hasRole(MEMBER, msg.sender),
        "Only family members can send tokens.");

        // Transfer - Transfers tokens from sender to recipient
        _transfer(msg.sender, recipient, amount);
    }

    // AddParent Function - Adds new parent
    function addParent(address parent) public {

        // Requirement – Only PARENT role can addParent
        require(!hasRole(PARENT), "Only parents can add parents.");

        // Check if address is already a parent
        require(!hasRole(PARENT, parent), "They're already a parent");
    
        // Assign PARENT & MINTER roles to specified member
        _grantRole(PARENT, parent);
    }

    // AddMember Function - Adds new family member
    function addMember(address member) public {
        
        // Requirement – Only PARENT role can mint
        require(!hasRole(PARENT), "Only parents can mint.");

        // Check if address is already a member
        require(!hasRole(MEMBER, member), "Address is already a member");
        
        // _grantRole - Assigns MEMBER role to specified member
        _grantRole(MEMBER, member);
    }
}

I haven't tried any fixes as I have no idea why it's not just reading the functions from the interface contracts. In every video and example I've seen, people just import and everything works. smh

Link to a YouTuber importing IERC20 without a problem.

1

There are 1 answers

3
fabriziogianni7 On

if you inherit from the interfaces you have to implement all the methods and then use them in your contract.

The best would be to import ERC20 and AccessControl contracts and inherit them.

this way:

// SPDX-License-Identifier: MIT

// Pragma Declaration
pragma solidity 0.8.17;
// Imports
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
// import "@openzeppelin/contracts/interfaces/IERC20.sol";

contract FamCash is ERC20, AccessControl{
    // Role Identifiers - Creates roles for limiting specific functionality
    bytes32 public constant PARENT = keccak256("PARENT");
    bytes32 public constant MEMBER = keccak256("MEMBER");

    // Maximum Supply Limit
    uint256 public maxSupplyLimit = 1000000;


    // Constructor Implementation - Sets name & ticker; Assigns roles to msg.sender
    constructor(
        address contractOwner,
        string memory tokenName,
        string memory tokenTicker
    ) ERC20(tokenName, tokenTicker) {
        // Role Assignments
        grantRole(DEFAULT_ADMIN_ROLE, contractOwner);
        grantRole(PARENT, contractOwner);
        grantRole(MEMBER, contractOwner);
    }

    // Mint Function - Mints new tokens
    function mint(address recipient, uint256 amount) public {
        // Requirement – Only PARENT role can mint
        require(!hasRole(PARENT,address(0)), "Only parents can mint.");

        // Input validation - Checks for valid address and amount
        require(recipient != address(0), "Invalid recipient address");
        require(amount > 0, "Amount must be greater than zero");

        // Total Supply - Sets the supply by adding the amount
        uint256 totalSupplyAfterMint = totalSupply() + amount;

        // Post-Mint Check - Stops request from exceeding the minting limit
        require(
            totalSupplyAfterMint <= maxSupplyLimit,
            "Exceeds max supply limit"
        );

        // _mint - Sends specified token amount to specified recipient
        _mint(recipient, amount);
    }

    // Send Function - Sends tokens to a recipient
    function send(address recipient, uint256 amount) public {
        // Requirement – hasRole of PARENT or FAMILY – Limit sending to family
        require(
            !hasRole(PARENT, msg.sender) || !hasRole(MEMBER, msg.sender),
            "Only family members can send tokens."
        );

        // Transfer - Transfers tokens from sender to recipient
        _transfer(msg.sender, recipient, amount);
    }

    // AddParent Function - Adds new parent
    function addParent(address parent) public {
        // Requirement – Only PARENT role can addParent
        require(!hasRole(PARENT,address(0)), "Only parents can add parents.");

        // Check if address is already a parent
        require(!hasRole(PARENT, parent), "They're already a parent");

        // Assign PARENT & MINTER roles to specified member
        grantRole(PARENT, parent);
    }

    // AddMember Function - Adds new family member
    function addMember(address member) public {
        // Requirement – Only PARENT role can mint
        require(!hasRole(PARENT, address(0)), "Only parents can mint.");

        // Check if address is already a member
        require(!hasRole(MEMBER, member), "Address is already a member");

        // grantRole - Assigns MEMBER role to specified member
        grantRole(MEMBER, member);
    }
}

A solution for the size of contract can be copypasting interfaces locally and modify them to use only the methods that you need (in this case just grantRole and hasRole - reimplement ERC20 is not suggested)

YouTuber importing IERC20