3

I have a contract called Erc20Recover in which I have the following function:

pragma solidity >=0.8.0;

contract Erc20Recover {
    function _setNonRecoverableTokens(IErc20[] calldata tokens) public {
        // ...
    }
}

I have another contract called HToken which inherits from Erc20Recover and in whose constructor I attempted to call _setNonRecoverableTokens:

pragma solidity >=0.8.0;

contract HToken is Erc20Recover {
    constructor(underlying) {
        IErc20[1] memory nonRecoverableTokens = [underlying];
        _setNonRecoverableTokens(nonRecoverableTokens);
    }
}

But the code does not compile:

Invalid type for argument in function call. Invalid implicit conversion from contract IErc20[1] memory to contract IErc20[] calldata requested.

How can I turn that in-memory static array into a calldata array? Or, more generally, how can I call _setNonRecoverableTokens?

For context: IErc20 is my implementation of the ERC-20 interface.

1
  • I couldn't figure out how to make the conversion from memory to calldata but I fixed my problem by defining the tokens array as memory. Sep 14, 2021 at 16:42

2 Answers 2

3

It's not possible to copy data from memory to calldata. Calldata, being the cheapest type of storage, is read-only and can only be used for data passed in to a function through the transaction input.

From the Solidity documentation:

As already said, the called contract (which can be the same as the caller) will receive a freshly cleared instance of memory and has access to the call payload - which will be provided in a separate area called the calldata.

As you mentioned in the comments, simply using memory instead of calldata for tokens solves the issue. If you're calling the contract through a transaction, this will simply copy the calldata to the memory.

2
  • Does it cost more gas the way I defined with memory? Sep 14, 2021 at 18:19
  • It costs slightly gas more to use memory instead of calldata, since the input data needs to be copied to memory.
    – Morten
    Sep 15, 2021 at 11:03
2

Besides what Morten wrote, one can do this._setNonRecoverableTokens(nonRecoverableTokens); to call _setNonRecoverableTokens externally which will copy your memory array to calldata (see slide '57' here). However, calling function externally will also lead to creation of a new context besides incurring previous copy operation, so, calling function internally (which happens by simple jumps) is generally more efficient.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.