Using the SafeERC20 library in a parent contract

Hi everyone, please help me. Why in parent contract using SafeERC20 library in child contract when using token.safeTransferFrom(msg.sender, address(this), amount); I get TypeError: Member "safeTransferFrom" not found or not visible after argument-dependent lookup in contract IERC20. Is this normal behavior or am I doing something wrong?

:1234: Code to reproduce

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

import {Parent} from "./Parent.sol";

contract Child is Parent {

    constructor(address token_) Parent(token_) {
    }

    function test(uint256 amount) external {
        token.safeTransferFrom(msg.sender, address(this), amount);
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

abstract contract Parent {
    using SafeERC20 for IERC20;

    IERC20 public immutable token;

    constructor(address token_) {
        token = IERC20(token_);
    }
}

You need to declare that also in the Child contract.
In fact, you may as well remove it from the Parent contract, because it is not being used there.

Yes, I realize it's not being used. I only used the code for the sake of the example. My idea was to make a "base" contract that would use SafeERC20 and all contracts that would inherit it would not have to write it. I wanted to make Staking is StakingReferralProgram, and in turn StakingReferralProgram is StakingBase with SafeERC20. Thanks a lot for the reply!

Would not have to write what, a single using SafeERC20 for IERC20 statement?

I wouldn't spend time on this effort, let alone the fact that inheriting your contract, by itself requires "writing something", so you'd essentially be replacing the need for one "piece of text" with another.

Solidity's using statement allows you to enjoy a specific type of sugar-syntax in your code.
But the compiler implementation currently requires you to explicitly declare this statement in every contract where you wish to be able to enjoy that sugar-syntax.

Not one, this will be used in two contracts, Staking and StakingReferralProgram. And why I came to this in the first place: I also have a built-in purchase in Staking for any ERC20 token that my contract supports and for it I just use IERC20, and for my token I use the extended interface because it has a burn logic that I need to use. And it turns out that in total I will have three uses of "using" when I could have had two. I'm probably overthinking this.

And in each one of them, you'll need to write this:

is Parent

Instead of this:

using SafeERC20 for IERC20;

Where's the gain?

And even regardless of the above "tradeoff"... Where's the gain?

Why? I wrote to you above. Staking is StakingReferralProgram, and in turn StakingReferralProgram is StakingBase with SafeERC20. Staking will include StakingBase.

and then I would have a "using" in Staking for regular IERC20 (for purchases) and using in StakingBase to do transfers to StakingReferralProgram and Staking for staking token

As I wrote in a previous comment:

Sounds like this is all that you're hoping to achieve - remove a single line of code, in a few contracts.

Where's the gain?

StakingBase is not only used for that, it stores some state variables. And if I could do make the code one line shorter, why not? I think it would be beautiful.
Sorry for taking up your time

So what has that got to do with the original question, and how exactly would a potential solution for your issue make any difference whatsoever with regards to these state variables?


First of all, because the compiler currently doesn't support it.

Second, because even if it did, placing a using statement in one contract or the other would make absolutely no runtime difference whatsoever.

The bytecode would remain literally identical regardless of where that statement would be placed.

In fact, it remains identical even if you don't place that statement anywhere to begin with, and just use the full syntax instead, for example, SafeERC20.safeTransfer(token, ...).


NP :slight_smile:

I get your point, thanks for the detailed reply!

1 Like