I don't get that how to connect interface declaration to implementation part in solidity
Here is pseudo code that leaves only important part which is related.
ApproveAndCall.sol
contract ApproveAndCall {
function receiveApproval(address _sender, uint256 _amount, address _addressOfToken, bytes _extraData) external {
emit ReceiveApproval(_sender, _amount, _addressOfToken, _extraData);
}
}
TokenERC20.sol
interface tokenRecipient {
function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) external;
}
contract TokenERC20 is Pausable {
function approveAndCall(address _spender, uint256 _value, bytes _extraData) public noReentrancy returns (bool success) {
tokenRecipient spender = tokenRecipient(_spender);
spender.receiveApproval(msg.sender, _value, this, _extraData);
}
}
just like you see, interface "tokenRecipient" was declared in TokenERC20.sol and the tokenRecipient named "spender" would call function "receiveApproval".
but How does TokenERC20 smart contract know that real "receiveApproval" which is called by "spender"?
I think it seems not like any connection with addresses or some other thing.
Both smart contract was already deployed on rinkeby testnet. and it still seems to work well.
This interface is just for convenience, so you can easily call the interface methods. You can cast any smart contract address to this interface, even if they are not an instance of this interface.
For instance, if I would make the following changes to your example:
ApproveAndCall.sol
contract ApproveAndCall {
function receiveApproval(address _sender, uint256 _amount, address _addressOfToken, bytes _extraData) external {
emit ReceiveApproval(_sender, _amount, _addressOfToken, _extraData);
}
}
contract ApproveAndCall2 {
function() public {
emit Fallback(msg.data);
}
}
TokenERC20.sol
interface tokenRecipient {
function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) external;
}
contract TokenERC20 is Pausable {
function approveAndCall(address _spender, uint256 _value, bytes _extraData) public noReentrancy returns (bool success) {
tokenRecipient spender = tokenRecipient(_spender);
spender.receiveApproval(msg.sender, _value, this, _extraData);
}
}
If the address of an ApproveAndCall
contract would be used as the _spender
parameter, it would work as expected, because the corresponding function is in fact defined in the smart contract, so receiveApproval
gets called.
However, if the address of an ApproveAndCall2
contract would be used as the _spender
parameter, instead the 'fallback function' would be called, because the receiveApproval
function does not exist on the ApproveAndCall2
contract. The msg.data
variable contains the encoded calldata for this function call (function name, parameter values etc.).