I have two contract that are separately deployed.
FirstContract.sol
contract FirstContract is ERC721 {
using Counters for Counters.Counter;
Counters.Counter public _id;
address payable _admin;
constructor(address admin) ERC721("Token Name", "TOKEN") {
_admin = payable(admin);
}
function incrementToken() public {
_id.increment();
}
}
SecondContract.sol
import "./FirstContract.sol";
contract SecondContract {
FirstContract firstContract;
constructor(address _address) {
firstContract = FirstContract(_address);
}
function increment() external {
firstContract.incrementToken();
}
function transferValue(uint value) external {
firstContract._admin.transfer(value); // error here
}
}
I'm getting the error:
Member "transfer" not found or not visible after argument-dependent lookup in function () view external returns (address payable).
I'm not sure why this error occurs because the function is marked public
here.
FirstContract
derives from ERC721
but your link at the end of the question points at ERC20
contract. So the definition of transfer()
in the ERC20
is not relevant in this context.
firstContract._admin.transfer(value);
This snippet is attempting to use the Solidity native transfer()
member of the address payable
type, i.e. transfer ETH (not an ERC20 token). But it's failing because the firstContract._admin
is not visible.
It would be visible if the FirstContract
was a parent of SecondContract
, as well as if the _admin
had public
visibility modifier. Since it doesn't have any visibility modifier specified, the default value internal
is used.
_admin
property the public
visibility modifieraddress payable public _admin;
Then you need to change the call of firstContract._admin
(property) to firstContract._admin()
(function) because of the way that the compiler handles public properties in external contracts. See more about autogenerated getter functions in the docs.
firstContract._admin().transfer(value);
Mind that the SecondContract
doesn't hold any ETH and currently has no way to receive any. So if you were trying to transfer()
more than the current balance of the SecondContract
(which is 0), the transaction would revert.
For testing purposes, you can add the payable
modifier to the constructor and send it some ETH with the deployment transaction, so that you can test the transferValue()
.
constructor(address _address) payable {