Use interface or a contract instance to interact with an existing contract

I thought using an interface would be lighter in terms of gas cost, but the experiment I did showed otherwise. See the following two snippets.

// SPDX-License-Identifier: MIT

pragma solidity 0.8.4;

interface IToken {
    function totalSupply() external returns(uint256);
}

contract Test {
    
    IToken token;
    
    constructor(address addr) {
        token = IToken(addr);
    }
    
    function getter() public returns(uint256) {
        return token.totalSupply();
    }
}

Versus this:

// SPDX-License-Identifier: MIT

pragma solidity 0.8.4;

import "./Token.sol";

contract Test {
    
    Token token;
    
    constructor(address addr) {
        token = Token(addr);
    }
    
    function getter() public returns(uint256) {
        return token.totalSupply();
    }
}

My thought was the one above, not importing a contract and only using an interface, should have a smaller gas cost, whereas the one below should cost more. The numbers are saying the opposite, although the difference is not a lot.

I am wondering why this is the case and which one is a better approach. Thanks.

I assume Token.sol is just

interface IToken {
    function totalSupply() external returns(uint256);
}

Right?

Or is it something else?

How are you doing the gas test?

In my personal experience I find testing these things to be really difficult because gas is always variable and changing depending on network traffic.

1 Like

Maybe you can use this tool to estimate gas

1 Like

@Yoshiko @Skyge Thanks guys. Sometimes, I got the answer myself not too long after asking the question. The point I was trying to get clarified is, importing a contract will increase the size of a contract, whereas using an interface to call the functionalities in a deployed contract is much lighter. Cheers!

1 Like

NP!