Search code examples
interfacegrammarethereumsolidity

how to get to know where is interface's link between implementation and declaration on ethereum blockchain


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.


Solution

  • 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.).