How to best override private function _doSafeTransferAcceptanceCheck in ERC1155?

Hi all,

I’m trying to inherit the ERC1155 base contract as provided by OZ. Specifically, I’m overriding safeTransferFrom. I’m trying to mimic the original implementation as closely as possible, including teh call to _doSafeTransferAcceptanceCheck, however, because that function is private, I can’t call it.

What’s the best solution to getting around this problem? I can’t override it as it’s a private function (as far as I know).

I’m between two options, though I feel like there’s probably a better one I hadn’t considered.

  1. Reimplementing the doSafeTransferAcceptanceCheck under a new name
  2. Reimplementing the entire contract and adding my functions (rather than inheriting)

I certainly want this functionality in the end so removing the function call entirely seems like a bad idea.

:computer: Environment

N/A

:memo:Details

:1234: Code to reproduce

    /**
     * @dev See {IERC1155-safeTransferFrom}.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) public virtual override {
        require(to != address(0), "ERC1155: transfer to the zero address");
        require(
            from == _msgSender() ||
                isApprovedForAll(from, _msgSender())
            "ERC1155: caller is not owner, token holder, or pod manager"
        );

        // Imagine some unique implementation here

        address operator = _msgSender();

        _balances[id][from] = _balances[id][from].sub(
            amount,
            "ERC1155: insufficient balance for transfer"
        );
        _balances[id][to] = _balances[id][to].add(amount);

        emit TransferSingle(operator, from, to, id, amount);

        _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);
    }

    function _doSafeTransferAcceptanceCheck(
        address operator,
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) private override {
        if (to.isContract()) {
            try
                IERC1155Receiver(to).onERC1155Received(
                    operator,
                    from,
                    id,
                    amount,
                    data
                )
            returns (bytes4 response) {
                if (
                    response != IERC1155Receiver(to).onERC1155Received.selector
                ) {
                    revert("ERC1155: ERC1155Receiver rejected tokens");
                }
            } catch Error(string memory reason) {
                revert(reason);
            } catch {
                revert("ERC1155: transfer to non ERC1155Receiver implementer");
            }
        }
    }
1 Like

Just like what you said above, _doSafeTransferAcceptanceCheck is a private function, so you can not rewrite it, what you can do is to rewrite the function safeTransferFrom, so then you can do whatever you want to do.

1 Like

Hi @willKim19,

You could look at using the hook _beforeTokenTransfer, see Using Hooks. If you can’t do what you want to do using hooks, then you should do as @Skyge recommended.

Found this topic while trying to override the 1155 transfer function as well and ran into the same problem

The hooks solution works, but it took me a while to figure out so maybe this will help someone else too:

Here’s my working code

 function safeTransferFrom(
          address from,
          address to,
          uint256 id,
          uint256 amount,
          bytes memory data
      )
          public
          virtual
          override
      {
          //Fractal Requirements
          if(tokenIdToShares[id] > 0){
            //this is an NFT, require all the shares are locked
            require(
              (lockedToTotal[id][to] == 10000),
                "ERC1155: caller has not transferLocked this many shares to this transfer."
            );
            }
          else{
            //these are shares
            //Owner must have this many shares, and they much be unlocked.
            require(
              (getPercentByNFT(msg.sender, id) - lockedShares[msg.sender][id] >= amount),
                "Fraktal ERC1155: caller does not have this many unlocked shares."
            );
          }
           //call the original function that you wanted.
          super.safeTransferFrom(
             from,
             to,
             id,
             amount,
             data
          );
           //do some other stuff
        }

I added some of my own requirements at the top of the function, which is what I wanted changed. But _balances is private, and a few other functions were private so it didnt compile. To fix I did 2 things, after reading the Hooks explanation as linked above.

  1. make my function virtual
  2. Do the things you want differently, and then call the existing safeTransferFrom function as a super so all the good stuff happens: