Patterns of using interfaces

Hi there, this is more of a design question than a technical question. When instantiating an interface, which one is better? in storage or in memory?

An example can be IERC20(tokenAddress).totalSupply(); versus IERC20 token = IERC20(tokenAddress); token.totalSupply();. The former, I believe, would create an instance in memory and hence is cheaper and the later would do in storage hence more expensive? Is that true?

Besides, the former leaves room for upgradeability, whereas the later is fixed.

Other than factors like these, is there any other to consider? What benefits does the later have? A cleaner code? Readability?

Thanks.

Hi, I think so, but in order to avoid I miss something, @martriay could you please have a look at this question, thanks!

If that’s local to a function, I think they both live in the stack. I think the interface is treated as an address type which is a value type. And local value types are stored in the stack, which costs the same as memory.

function _totalSupply(address tokenAddress) public returns (uint256) view {
    return IERC20(tokenAddress).totalSupply();
    // vs
    IERC20 token = IERC20(tokenAddress);
    return token.totalSupply();
}
2 Likes

But just like maxaero said, if contract address is a function parameter, so when call its function, will it use mload? And if the contract address is a global variable, when call its function, will it use sload?

I’ll just add some motivating examples to make the conversations more meaningful.

The following snippet of code comes from the swap function in PancakePair contract, and it is reasonable to use IERC20 interface to instantiate tokens since it is meant for many pairs of tokens.

    balance0 = IERC20(_token0).balanceOf(address(this));
    balance1 = IERC20(_token1).balanceOf(address(this));

The following snippet is from swapExactTokensForETHSupportingFeeOnTransferTokens function in the PancakeRouter02 contract, and WETH is supposed to be fixed. Is instantiating it a more reasonable approach in this scenario?

    uint amountOut = IERC20(WETH).balanceOf(address(this));
    require(amountOut >= amountOutMin, 'PancakeRouter: INSUFFICIENT_OUTPUT_AMOUNT');
    IWETH(WETH).withdraw(amountOut);
1 Like