DeclarationError: Undeclared identifier error when using sendValue()

Hi, I am currently working on my own project, but my compile fails due to a declaration error with the sendValue() function within Address.sol.

Here is the code handling the inheritance and constructor of my contract:

pragma solidity ^0.8.0;

// This is an open source for the ERC721 Token Standard
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/utils/Address.sol"; 

contract nftSmartContract is ERC721 {
    using Counters for Counters.Counter;
    using Address for address;

    Counters.Counter private _tokenIdTracker;
    string private _baseTokenURI;
    bool lock = false;

    event Sent(address indexed payee, uint256 amount, uint256 balance);
    event Received(address indexed payer, uint tokenId, uint256 amount, uint256 balance);

    constructor(string memory name, string memory symbol, string memory baseTokenURI) ERC721(name, symbol) {
        _baseTokenURI = baseTokenURI;
    }

Here is the function that calls the sendValue() function:

    //gets called in the tokenSale() function
    //sends the eth from the buyer to the seller, with commission held within this contract
    function salePayout(
        address payable _payee, 
        uint256 _value
    ) 
        internal 
    {
        require(_payee != address(0) && _payee != address(this), "the person you are trying to payout to is the '0' address or this address");
        require(_value > 0 && _value <= address(this).balance, "there is not enough eth in this contract to send to the payee");
        require(!lock, "function is currently locked, failing due to potential re-entry attack");
        lock = true;

        sendValue(_payee, _value);
        emit Sent(_payee, _value, address(this).balance);

        lock = false;
    }

Here is the compile error I am receiving:

DeclarationError: Undeclared identifier.
  --> /C/Users/Brend/Documents/Programming/SpaceForce/ContractService/SmartContract/contracts/nftSmartContract.sol:79:9:
   |
79 |         sendValue(_payee, _value);
   |

I have imported Address.sol into my contract, so I am unsure as to why it is unable to see the function.

Any help or guidance is appreciated!

Library functions are not visible in the global namespace. You need to qualify the call with the library name:

Address.sendValue(_payee, _value);

Since you have using Address for address there you can alternatively use the function as a member of the address type:

_payee.sendValue(_value);

But this will only work if the using statement is in the same contract that contains salePayout(). using statements are not inherited from base contract (at least in recent Solidity versions).

2 Likes

Thank you! That seems to take away the error. Now I am able to call the function, but it does not actually send the ether.

The code for sendValue() is:

    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (bool success, ) = recipient.call{ value: amount }("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

For context, I am calling salePayout() as the contract to move ether from the contract to the _payee. for example, I am calling Address.sendValue(_payee, 1) After calling the salePayout() function, the state of the contract does not seem to change. I would expect to see either “Address: insufficient balance” or “Address: unable to send value, recipient may have reverted” if it fails, but I receive neither of these messages, but both balances stay the same.

Assuming the contracts balance is 3 ether and the account I am sending the ether to, _payee, has a balance of 0 eth before calling the function, the balances stay the same after the function is called as well. Any thoughts on why it may not be sending the eth?

1 Like

Is _payee actually a contract? If it’s not the call will succeed but do nothing. The high level calls have a protection against that but you’re using the low-level call which does not.

Units and global variables > Members of address type:

Due to the fact that the EVM considers a call to a non-existing contract to always succeed, Solidity includes an extra check using the extcodesize opcode when performing external calls. This ensures that the contract that is about to be called either actually exists (it contains code) or an exception is raised.

The low-level calls which operate on addresses rather than contract instances (i.e. .call() , .delegatecall() , .staticcall() , .send() and .transfer() ) do not include this check, which makes them cheaper in terms of gas but also less safe.

1 Like

So _payee is actually intended to be a person’s wallet address. So in this case, I won’t be able to use the sendValue() function, as it requires the recipient to be the address of a contract and I will need to use something like .transfer()?

1 Like

Sorry, what I said was not entirely correct. I think your call() should still successfully send the ether even if it “does nothing”, i.e. does not actually call any function on the other side when it’s an EOA.

So another possible cause - are you sure that the balance of _payee after the operation is exactly 0? You’re sending a very small fraction of an ether (1 means one wei; for one ether you need to use 1 ether or 10**18) so maybe it actually works but the UI you’re using to view the balance rounds that down and shows you zero?

1 Like