Search code examples
compiler-errorsethereumsoliditysmartcontractsremix

Data location must be "calldata" for parameter in external function, but none was given. --> Undeclared identifier


In Remix, I'm getting the following error.

contracts/TestBench.sol:138:30:
TypeError: Data location must be "calldata" for parameter
in external function, but none was given.
    function updateTokenName(string _name) external onlyOwner { 
                             ^----------^

That error references the below line of code (full smart contract is appended at the bottom).

function updateTokenName(string _name) external onlyOwner {

Then, after replacing the above problematic line with the following line like this:

function updateTokenName(string calldata _name) external onlyOwner {

I get a series of new errors that look like this. They all reference previous lines of code that passed the compiler without errors before I made the "fix" by adding calldata.

contracts/TestBench.sol:52:9:
DeclarationError: Undeclared identifier.
        allowed[msg.sender][_spender] = _tokens; / ...
        ^-----^

The full function that error references is as follows.

function approve(address _spender, uint256 _tokens) external { 
    allowed[msg.sender][_spender] = _tokens; // Allow spender to withdraw from msg.sender's account multiple times, up to the specified amount of tokens. 
}

What am I doing wrong and how can I fix these errors? What is the proper way to declare the identifiers the error message is referencing?

Full smart contract
pragma solidity ^0.5.0; 
contract FractionalizedAssets {

    address public owner; // contract creator

    mapping (address => uint) public tokenBalanceOf; // map of address and token balance 

    constructor() public { 
        owner = msg.sender; 
    }

    function mint(uint256 _amount, address _to) external onlyOwner {
        require(_amount > 0);  
        tokenBalanceOf[_to] += _amount; // Increase the token balance for user's account by specified amount.     
    }

    function transfer(address _from, address _to, uint256 _tokens) external { // Allow users to trade tokens between each other
        require(tokenBalanceOf[_from] >=_tokens && _tokens > 0); // Ensure that sender has enough tokens to send
        tokenBalanceOf[_from] -=_tokens; // Substract tokens from sender's account
        tokenBalanceOf[_to] +=_tokens; // Add tokens to receiver's account
        emit Transfer(_from,_to,_tokens); // Notify listeners about transfer event
    }
    
    event Transfer(address indexed from, address indexed to, uint256 value);

    modifier onlyOwner() {
        require( msg.sender == owner );
        _;
    }

    function burn(uint256 _amount, address _from) external onlyOwner { 
        require(_amount > 0);
        tokenBalanceOf[_from] -= _amount; // Decrease the token balance for user's account by specified amount.     
    }

    function totalSupply() public view returns (uint256) { 
       return address(this).balance; // Return the total supply of tokens in circulation. 
    }

    function balanceOf(address _owner) public view returns (uint256) { 
        return tokenBalanceOf[_owner]; // Return the token balance of specified address. 
    }

    function transferFrom(address _from, address _to, uint256 _tokens) external { 
        require(_tokens > 0 && tokenBalanceOf[_from] >=_tokens); // Ensure that sender has enough tokens to send
        tokenBalanceOf[_from] -=_tokens; // Substract tokens from sender's account
        tokenBalanceOf[_to] +=_tokens; // Add tokens to receiver's account
        emit Transfer(_from,_to,_tokens); // Notify listeners about transfer event
    }

    function approve(address _spender, uint256 _tokens) external { 
        allowed[msg.sender][_spender] = _tokens; // Allow spender to withdraw from msg.sender's account multiple times, up to the specified amount of tokens. 
    }

    function allowance(address _owner, address _spender) public view returns (uint256) {
        return allowed[_owner][_spender]; // Return the remaining number of tokens that spender is still allowed to withdraw from owner's account.
    }

    function transferFrom(address _from, address _to, uint256 _tokens) external { 
        require(_tokens > 0 && tokenBalanceOf[_from] >=_tokens && allowed[_from][msg.sender] >=_tokens); // Ensure that sender has enough tokens to send
        tokenBalanceOf[_from] -= _tokens; // Substract tokens from sender's account
        tokenBalanceOf[_to] += _tokens; // Add tokens to receiver's account
        allowed[_from][msg.sender] -= _tokens; // Decrease the amount of remaining tokens spender is still allowed to withdraw from owner's account
        emit Transfer(_from,_to,_tokens); // Notify listeners about transfer event
    }

    function increaseApproval(address _spender, uint256 _addedValue) external { 
        allowed[msg.sender][_spender] += _addedValue; // Increase the amount of tokens that spender is still allowed to withdraw from owner's account. 
    }
    
    function decreaseApproval(address _spender, uint256 _subtractedValue) external {
        allowed[msg.sender][_spender] -= _subtractedValue; // Decrease the amount of tokens that spender is still allowed to withdraw from owner's account.
    }

    function burnFrom(address _from, uint256 _tokens) external { 
        require(_tokens > 0 && tokenBalanceOf[_from] >=_tokens && allowed[_from][msg.sender] >=_tokens); // Ensure that sender has enough tokens to send
        tokenBalanceOf[_from] -=_tokens; // Substract tokens from sender's account
        allowed[_from][msg.sender]-=_tokens; // Decrease the amount of remaining tokens spender is still allowed to withdraw from owner's account
        emit Burn(_from,_to,_tokens); // Notify listeners about transfer event
    }

    event Burn(address indexed from, address indexed to, uint256 value);

    function burnAll(address _from) external onlyOwner { 
        uint256 balance = tokenBalanceOf[_from]; // Get the user's current token balance. 
        require(balance > 0); // Ensure that user has tokens to burn. 
        tokenBalanceOf[_from] = 0; // Set the user's token balance to zero. 
        emit Burn(_from, address(0), balance); // Notify listeners about transfer event.  
    }

    function pause() external onlyOwner { 
        paused = true; // Set the contract to a paused state. 
        emit Pause(); // Notify listeners about transfer event.  
    }

    function unpause() external onlyOwner {
        paused = false; // Set the contract to an unpaused state.
    }

    event Pause();
    
    function renounceOwnership() external onlyOwner { 
        emit OwnershipRenounced(owner); // Notify listeners about transfer event.  
        owner = address(0); // Set the contract's owner to zero. 
    }

    event OwnershipRenounced(address indexed previousOwner);


    function transferOwnership(address _newOwner) external onlyOwner { 
        require(_newOwner != address(0)); // Ensure that new owner is not zero. 
        emit OwnershipTransferred(owner, _newOwner); // Notify listeners about transfer event.  
        owner = _newOwner; // Set the contract's owner to the new owner. 
    } 

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    function reclaimEther() external onlyOwner { 
        owner.transfer(address(this).balance); // Transfer all ether in the contract to the owner's address. 
        emit ReclaimEther(); // Notify listeners about transfer event.  
    } 
    
    event ReclaimEther();

    function destroy() external onlyOwner { 
        selfdestruct(owner); // Destroy the contract and transfer all ether in the contract to the owner's address. 
        emit Destroy(); // Notify listeners about transfer event.  
    }
 
    event Destroy();
    
    function updateOwner(address _newOwner) external onlyOwner { 
        require(_newOwner != address(0)); // Ensure that new owner is not zero. 
        emit OwnershipTransferred(owner, _newOwner); // Notify listeners about transfer event.  
        owner = _newOwner; // Set the contract's owner to the new owner. 
    }

    function updateTokenName(string calldata _name) external onlyOwner { 
        tokenName = _name; // Update the name of the token. 
        emit TokenNameUpdated(_name); // Notify listeners about transfer event.
    }

    event TokenNameUpdated(string indexed newTokenName);
}

Solution

  • from here

    Explicit data location for all variables of struct, array or mapping types is now mandatory. This is also applied to function parameters and return variables. For example, change uint[] x = m_x to uint[] storage x = m_x, and function f(uint[][] x) to function f(uint[][] memory x) where memory is the data location and might be replaced by storage or calldata accordingly. Note that external functions require parameters with a data location of calldata.

    • Then you had to define allowed mapping and paused storage variables:

      bool private paused;
      string tokenName;
      // address1 allows address2 uint amount token 
       mapping(address=>mapping(address=>uint)) public allowed;
      
    • You defined transferFrom function with the same signature twice. you either change the signatures or you have to remove one of the functions.

    • emitting Burn event inside burnFrom is wrong

      // _to is not defined
      emit Burn(_from,_to,_tokens)
      
    • owner type needs to be changed because of this

    "send" and "transfer" are only available for objects of type "address payable", not "address".

    address payable public owner; // contract creator
    // you do not need public
    constructor() { 
            owner = payable(msg.sender); 
        }
         
    
    function renounceOwnership() external onlyOwner { 
            emit OwnershipRenounced(owner); // Notify listeners about transfer event.  
            // owner type is set payable above
            owner = payable(address(0)); // Set the contract's owner to zero. 
        }
    
    // owner to payable in below two functions
    function transferOwnership(address _newOwner) external onlyOwner { 
            require(_newOwner != address(0)); // Ensure that new owner is not zero. 
            emit OwnershipTransferred(owner, _newOwner); // Notify listeners about transfer event.  
            owner = payable(_newOwner); // Set the contract's owner to the new owner. 
        } 
    
    function updateOwner(address _newOwner) external onlyOwner { 
            require(_newOwner != address(0)); // Ensure that new owner is not zero. 
            emit OwnershipTransferred(owner, _newOwner); // Notify listeners about transfer event.  
            owner = payable(_newOwner); // Set the contract's owner to the new owner. 
        }
    

    Now your app is ready to compile in pragma solidity >=0.8.0 <0.9.0;