Error: Unexpected type for UPGRADE_INTERFACE_VERSION

I've recently upgraded my Hardhat/Ethers/OZ upgrades stack. And I'm now experiencing a really perplexing thing. I have a set of 6 upgradeable contracts, and before up upgraded the module versions, all upgradeability tests passed. Now, all are still passing my tests except one!

Here's the test (I've removed all except one that works "ETSAccessControl" and the one that is failing "ETSAuctionHouse"):

const { setup, getFactories, getArtifacts } = require("./setup.js");
const { expectEvent } = require("@openzeppelin/test-helpers");
const { upgrades } = require("hardhat");
const { assert } = require("chai");

let artifacts, factories;

describe("Upgrades tests", function () {
  beforeEach("Setup test", async function () {
    artifacts = await getArtifacts();
    factories = await getFactories();
    [accounts, contracts, initSettings] = await setup();

  });

  describe("ETSAccessControl", async function () {
    it("is upgradeable", async function () {
      // Upgrade the proxy.
      contracts.ETSAccessControls = await upgrades.upgradeProxy(
        await contracts.ETSAccessControls.getAddress(),
        factories.ETSAccessControlsUpgrade,
      );

      const upgradeTxn = await contracts.ETSAccessControls.deployTransaction.hash;
      await expectEvent.inTransaction(upgradeTxn, artifacts.ETSAccessControlsUpgrade, "Upgraded");
      // Upgraded contract has new function upgradeTest()
      assert((await contracts.ETSAccessControls.upgradeTest()) === true);
    });
  });


  describe.only("ETSAuctionHouse", function () {
    it("is upgradeable", async function () {
      // Upgrade the proxy.
      contracts.ETSAuctionHouse = await upgrades.upgradeProxy(
        await contracts.ETSAuctionHouse.getAddress(),
        factories.ETSAuctionHouseUpgrade,
      );

      const upgradeTxn = contracts.ETSAuctionHouse.deployTransaction.hash;
      await expectEvent.inTransaction(upgradeTxn, artifacts.ETSAuctionHouseUpgrade, "Upgraded");
      // Upgraded contract has new function upgradeTest()
      assert((await contracts.ETSAuctionHouse.upgradeTest()) === true);
    });
  });
});

Here's the error:

> hardhat test

  Upgrades tests
    ETSAccessControl
      βœ” is upgradeable (133ms)
    ETSAuctionHouse
      1) is upgradeable


  1 passing (4s)
  1 failing

  1) Upgrades tests
       ETSAuctionHouse
         is upgradeable:
     Error: Unexpected type for UPGRADE_INTERFACE_VERSION at address 0x67d269191c92Caf3cD7723F116c85e6E9bf55933. Expected a string
      at getUpgradeInterfaceVersion (/Users/User/Sites/ets/node_modules/.pnpm/@openzeppelin+upgrades-core@1.31.1/node_modules/@openzeppelin/upgrades-core/src/upgrade-interface-version.ts:16:13)
      at processTicksAndRejections (node:internal/process/task_queues:96:5)
      at async getUpgrader (/Users/User/Sites/ets/node_modules/.pnpm/@openzeppelin+hardhat-upgrades@2.4.1_@nomicfoundation+hardhat-ethers@3.0.4_ethers@6.8.1_hardhat@2.19.0/node_modules/@openzeppelin/hardhat-upgrades/src/upgrade-proxy.ts:57:39)
      at async Proxy.upgradeProxy (/Users/User/Sites/ets/node_modules/.pnpm/@openzeppelin+hardhat-upgrades@2.4.1_@nomicfoundation+hardhat-ethers@3.0.4_ethers@6.8.1_hardhat@2.19.0/node_modules/@openzeppelin/hardhat-upgrades/src/upgrade-proxy.ts:32:23)
      at async Context.<anonymous> (test/ETSUpgradeable.test.js:85:35)

I'm almost certain the issue is not in my testing stack (ie. factories, artifacts, etc.) and that it's in the ETSAuctionHouse contract itself. Here's the contract:

// SPDX-License-Identifier: GPL-3.0

/**
 * @title ETS DAO Auction House
 * @author Ethereum Tag Service <team@ets.xyz>
 *
 *  β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—
 *  β–ˆβ–ˆβ•”β•β•β•β•β•β•šβ•β•β–ˆβ–ˆβ•”β•β•β•β–ˆβ–ˆβ•”β•β•β•β•β•
 *  β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—     β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—
 *  β–ˆβ–ˆβ•”β•β•β•     β–ˆβ–ˆβ•‘   β•šβ•β•β•β•β–ˆβ–ˆβ•‘
 *  β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—   β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•‘`
 *  β•šβ•β•β•β•β•β•β•   β•šβ•β•   β•šβ•β•β•β•β•β•β•
 *
 * @notice ETSAuctionHouse.sol is a modified version of Nouns NounsAuctionHouse.sol:
 * https://github.com/nounsDAO/nouns-monorepo/blob/master/packages/nouns-contracts/contracts/NounsAuctionHouse.sol
 * which itself is a modified version of Zora AuctionHouse.sol
 *
 * AuctionHouse.sol source code Copyright Zora licensed under the GPL-3.0 license.
 * With modifications by Ethereum Tag Service.
 *
 * ETS modification include enabling more than one concurrent auction via a protocol controlled
 * setting and requiring a bid to start the auction timer.
 */

pragma solidity ^0.8.6;

import { IWMATIC } from "./interfaces/IWMATIC.sol";
import { IETSToken } from "./interfaces/IETSToken.sol";
import { IETSAuctionHouse } from "./interfaces/IETSAuctionHouse.sol";
import { IETSAccessControls } from "./interfaces/IETSAccessControls.sol";

import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";

import { IERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import { SafeERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import { CountersUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/CountersUpgradeable.sol";

/**
 * @title ETSAuctionHouse
 * @author Ethereum Tag Service <team@ets.xyz>
 *
 * @notice ETSAuctionHouse contract governs the sale of Ethereum Tag Service composable tags (CTAGs).
 */
contract ETSAuctionHouse is
    Initializable,
    PausableUpgradeable,
    ReentrancyGuardUpgradeable,
    IETSAuctionHouse,
    UUPSUpgradeable
{
    using CountersUpgradeable for CountersUpgradeable.Counter;

    IETSToken public etsToken;
    IETSAccessControls public etsAccessControls;

    /// Public constants

    string public constant NAME = "ETS Auction House";
    uint256 public constant MODULO = 100;

    /// Public variables
    uint256 public maxAuctions;

    // Open for bidding
    CountersUpgradeable.Counter activeAuctions;

    // Unique auction id
    CountersUpgradeable.Counter auctionId;

    /// @dev Mapping of active auctions
    mapping(uint256 => IETSAuctionHouse.Auction) public auctions;

    /// @dev The address of the WMATIC contract
    address public wmatic;

    /// @dev The minimum amount of time left in an auction after a new bid is created
    uint256 public timeBuffer;

    /// @dev The minimum price accepted in an auction
    uint256 public reservePrice;

    /// @dev The minimum percentage difference between the last bid amount and the current bid
    uint8 public minBidIncrementPercentage;

    /// @dev The duration of a single auction
    uint256 public duration;

    /// @dev Percentage of auction proceeds allocated to CTAG Creator
    uint256 public creatorPercentage;

    /// @dev Percentage of auction proceeds allocated to CTAG Relayer.
    uint256 public relayerPercentage;

    /// @dev Percentage of auction proceeds allocated to ETS.
    uint256 public platformPercentage;

    /// @dev Map for holding amount accrued to participant address wallets.
    mapping(address => uint256) public accrued;

    /// @dev Map for holding lifetime amount drawn down from accrued by participants.
    mapping(address => uint256) public paid;

    /// Modifiers

    modifier tagExists(uint256 tokenId) {
        require(etsToken.tagExistsById(tokenId), "CTAG does not exist");
        _;
    }

    modifier platformOwned(uint256 tokenId) {
        // Returns "ERC721: owner query for nonexistent token" for non-existent token.
        require(etsToken.ownerOf(tokenId) == etsAccessControls.getPlatformAddress(), "CTAG not owned by ETS");
        _;
    }

    modifier onlyAuctionOracle() {
        require(etsAccessControls.isAuctionOracle(_msgSender()), "Caller not auction oracle");
        _;
    }

    modifier onlyAdmin() {
        require(etsAccessControls.isAdmin(_msgSender()), "Caller must be administrator");
        _;
    }

    modifier onlyPlatform() {
        require(etsAccessControls.getPlatformAddress() == _msgSender(), "Only platform may release CTAG");
        _;
    }

    modifier isAuction(uint256 tokenId) {
        require(_isAuction(tokenId), "Auction doesn't exist");
        _;
    }

    // ============ UUPS INTERFACE ============

    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor() {
        _disableInitializers();
    }

    function initialize(
        IETSToken _etsToken,
        IETSAccessControls _etsAccessControls,
        address _wmatic,
        uint256 _maxAuctions,
        uint256 _timeBuffer,
        uint256 _reservePrice,
        uint8 _minBidIncrementPercentage,
        uint256 _duration,
        uint256 _relayerPercentage,
        uint256 _platformPercentage
    ) external initializer {
        __Pausable_init();
        __ReentrancyGuard_init();

        _pause();

        etsToken = _etsToken;
        etsAccessControls = _etsAccessControls;
        wmatic = _wmatic;

        activeAuctions.reset();
        auctionId.reset();

        setMaxAuctions(_maxAuctions);
        setMinBidIncrementPercentage(_minBidIncrementPercentage);
        setDuration(_duration);
        setReservePrice(_reservePrice);
        setTimeBuffer(_timeBuffer);
        setProceedPercentages(_platformPercentage, _relayerPercentage);
    }

    // solhint-disable-next-line
    function _authorizeUpgrade(address) internal override onlyAdmin {}

    // ============ OWNER/ADMIN INTERFACE ============

    function pause() public onlyAdmin {
        _pause();
    }

    function unpause() public onlyAdmin {
        _unpause();
    }

    function setMaxAuctions(uint256 _maxAuctions) public onlyAdmin {
        maxAuctions = _maxAuctions;
        emit AuctionsMaxSet(_maxAuctions);
    }

    function setDuration(uint256 _duration) public onlyAdmin {
        duration = _duration;
        emit AuctionDurationSet(_duration);
    }

    function setMinBidIncrementPercentage(uint8 _minBidIncrementPercentage) public onlyAdmin {
        minBidIncrementPercentage = _minBidIncrementPercentage;
        emit AuctionMinBidIncrementPercentageSet(_minBidIncrementPercentage);
    }

    function setReservePrice(uint256 _reservePrice) public onlyAdmin {
        reservePrice = _reservePrice;
        emit AuctionReservePriceSet(_reservePrice);
    }

    function setTimeBuffer(uint256 _timeBuffer) public onlyAdmin {
        timeBuffer = _timeBuffer;
        emit AuctionTimeBufferSet(_timeBuffer);
    }

    function setProceedPercentages(uint256 _platformPercentage, uint256 _relayerPercentage) public onlyAdmin {
        require(_platformPercentage + _relayerPercentage <= 100, "Input must not exceed 100%");
        platformPercentage = _platformPercentage;
        relayerPercentage = _relayerPercentage;
        creatorPercentage = MODULO - platformPercentage - relayerPercentage;

        emit AuctionProceedPercentagesSet(platformPercentage, relayerPercentage, creatorPercentage);
    }

    // ============ PUBLIC INTERFACE ============

    /**
     * @notice Settle the current auction, and release next auction.
     */
    function settleCurrentAndCreateNewAuction(uint256 _tokenId) public nonReentrant whenNotPaused {
        _settleAuction(_tokenId);
        _requestCreateAuction();
    }

    /**
     * @notice Settle the current auction.
     * @dev This function can only be called when the contract is paused.
     */
    function settleAuction(uint256 _tokenId) public whenPaused nonReentrant {
        _settleAuction(_tokenId);
    }

    // Public function to release another auction using the auction Oracle.
    function createNextAuction() public whenNotPaused {
        require(activeAuctions.current() < maxAuctions, "No open auction slots");
        _requestCreateAuction();
    }

    // Capture reponse from next auction oracle.
    function fulfillRequestCreateAuction(uint256 _tokenId) public onlyAuctionOracle {
        // Let's double check the oracle's work.
        // Note: First check returns "ERC721: invalid token ID" for non-existent token.
        require(etsToken.ownerOf(_tokenId) == etsAccessControls.getPlatformAddress(), "CTAG not owned by ETS");
        require(activeAuctions.current() < maxAuctions, "No open auction slots");
        require(!_isAuction(_tokenId), "Auction exists");
        _createAuction(_tokenId);
    }

    function createBid(uint256 _tokenId) public payable nonReentrant whenNotPaused {
        // Retrieve active auction or create new one if _tokenId exists and is platform owned.
        Auction memory auction = _getAuction(_tokenId);

        require(auction.auctionId > 0, "Auction not found");
        if (auction.startTime > 0) {
            require(block.timestamp < auction.endTime, "Auction ended");
        }
        require(msg.value >= reservePrice, "Must send at least reservePrice");
        require(msg.value >= auction.amount + ((auction.amount * minBidIncrementPercentage) / 100), "Bid too low");

        address payable lastBidder = auction.bidder;

        // Refund the last bidder, if applicable
        if (lastBidder != address(0)) {
            _safeTransferETHWithFallback(lastBidder, auction.amount);
        }

        if (auction.startTime == 0) {
            // Start the auction
            uint256 startTime = block.timestamp;
            uint256 endTime = startTime + duration;
            auctions[_tokenId].startTime = startTime;
            auctions[_tokenId].endTime = endTime;
        }

        auctions[_tokenId].amount = msg.value;
        auctions[_tokenId].bidder = payable(msg.sender);

        // Extend the auction if the bid was received within `timeBuffer` of the auction end time
        bool extended = false;
        if (auction.startTime > 0) {
            extended = auction.endTime - block.timestamp < timeBuffer;
            if (extended) {
                auctions[_tokenId].endTime = auction.endTime = block.timestamp + timeBuffer;
                emit AuctionExtended(_tokenId, auction.endTime);
            }
        }

        emit AuctionBid(_tokenId, msg.sender, msg.value, extended);
    }

    /**
     * @notice Function for withdrawing funds from an accrual account. Can be called by the account owner
     * or on behalf of the account. Does nothing when there is nothing due to the account.
     *
     * @param _account Address of account being drawn down and which will receive the funds.
     */
    function drawDown(address payable _account) external nonReentrant {
        uint256 balanceDue = totalDue(_account);
        if (balanceDue > 0 && balanceDue <= address(this).balance) {
            paid[_account] = paid[_account] + balanceDue;

            bool success = _safeTransferETH(_account, balanceDue);
            require(success, "Transfer failed");

            emit AuctionProceedsWithdrawn(_account, balanceDue);
        }
    }

    // ============ INTERNAL FUNCTIONS ============

    function _requestCreateAuction() private {
        // Trigger of chain oracle to pick and release next auction.
        emit RequestCreateAuction();
    }

    function _createAuction(uint256 _tokenId) internal {
        auctionId.increment();
        activeAuctions.increment();
        // Create new auction but don't start it.
        auctions[_tokenId] = Auction({
            auctionId: auctionId.current(),
            amount: 0,
            startTime: 0,
            endTime: 0,
            reservePrice: reservePrice,
            bidder: payable(address(0)),
            auctioneer: etsAccessControls.getPlatformAddress(),
            settled: false
        });

        emit AuctionCreated(_tokenId);
    }

    function _settleAuction(uint256 _tokenId) internal {
        Auction memory auction = _getAuction(_tokenId);
        require(_isAuction(_tokenId), "Auction does not exist");
        require(!(auction.settled), "Auction already settled");
        require(auction.startTime != 0, "Auction has not begun");
        require(block.timestamp >= auction.endTime, "Auction has not ended");

        auctions[_tokenId].settled = true;
        activeAuctions.decrement();
        etsToken.transferFrom(etsAccessControls.getPlatformAddress(), auction.bidder, _tokenId);
        _processAuctionRevenue(_tokenId, auction.amount);
        emit AuctionSettled(_tokenId);
    }

    // @dev Internal function to divide up auction revenue and accrue it to ETS participants.
    function _processAuctionRevenue(uint256 _tokenId, uint256 _amount) private {
        // Distribute proceeds to actors.
        IETSToken.Tag memory ctag = etsToken.getTagById(_tokenId);
        address platform = etsAccessControls.getPlatformAddress();

        uint256 relayerProceeds = (_amount * relayerPercentage) / MODULO;
        uint256 creatorProceeds = (_amount * creatorPercentage) / MODULO;
        uint256 platformProceeds = _amount - (relayerProceeds + creatorProceeds);

        accrued[ctag.relayer] = accrued[ctag.relayer] + relayerProceeds;
        accrued[ctag.creator] = accrued[ctag.creator] + creatorProceeds;
        accrued[platform] = accrued[platform] + platformProceeds;
    }

    function _getAuction(uint256 _tokenId) private view returns (Auction memory auction) {
        return auctions[_tokenId];
    }

    function _safeTransferETHWithFallback(address to, uint256 amount) internal {
        if (!_safeTransferETH(to, amount)) {
            IWMATIC(wmatic).deposit{ value: amount }();
            IERC20Upgradeable(wmatic).transfer(to, amount);
        }
    }

    function _safeTransferETH(address to, uint256 value) internal returns (bool) {
        (bool success, ) = to.call{ value: value, gas: 30_000 }(new bytes(0));
        return success;
    }

    function _isAuction(uint256 _tokenId) internal view returns (bool) {
        return (auctions[_tokenId].auctionId != 0);
    }

    // ============ PUBLIC VIEW FUNCTIONS ============

    function auctionExists(uint256 _tokenId) public view returns (bool) {
        return _isAuction(_tokenId);
    }

    function auctionEnded(uint256 _tokenId) public view returns (bool) {
        return (auctions[_tokenId].endTime > block.timestamp);
    }

    function auctionSettled(uint256 _tokenId) public view returns (bool) {
        return (_isAuction(_tokenId) && auctions[_tokenId].settled);
    }

    function getAuction(uint256 _tokenId) public view returns (Auction memory) {
        return auctions[_tokenId];
    }

    function getActiveCount() public view returns (uint256) {
        return activeAuctions.current();
    }

    function getTotalCount() public view returns (uint256) {
        return auctionId.current();
    }

    function getBalance() public view returns (uint) {
        return address(this).balance;
    }

    function totalDue(address _account) public view returns (uint256 _due) {
        return accrued[_account] - paid[_account];
    }

    /* solhint-disable */
    receive() external payable {}

    fallback() external payable {}
    /* solhint-enable */
}

Finally, here's the upgrade contracts used by the tests:

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

import { ETSAccessControls } from "../ETSAccessControls.sol";
import { ETSAuctionHouse } from "../ETSAuctionHouse.sol";

contract ETSAccessControlsUpgrade is ETSAccessControls {
    // Extend existing contract with new function.
    function upgradeTest() public pure returns (bool) {
        return true;
    }
}

contract ETSAuctionHouseUpgrade is ETSAuctionHouse {
    // Extend existing contract with new function.
    function upgradeTest() public pure returns (bool) {
        return true;
    }
}

If you've made it this far, thanks for having a look and sharing your thoughts!

Hi, which network are you using? Can you please share the information listed under Required information when requesting support for Upgrades Plugins so that we can take a closer look?

Ugg the classic "didn't read the instructions." Thanks @ericglau for pointing me to that. Here's the items in order requested in the document.

1. Debug Logs

User@swaylock ~/Sites/ets/packages/contracts (13-tag-auction●●●)$ export DEBUG=@openzeppelin:*                                                [3.2.2]
User@swaylock ~/Sites/ets/packages/contracts (13-tag-auction●●●)$ hardhat test test/ETSUpgradeable.test.js                                    [3.2.2]


  Upgrades tests
    ETSAccessControl
  @openzeppelin:upgrades:core development manifest directory: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades +0ms
  @openzeppelin:upgrades:core development manifest file: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades/hardhat-31337-0x4da65430d56b547f80850352900d650fc8510de7c40be600352f1961df0c7d69.json fallback file: .openzeppelin/unknown-31337.json +0ms
  @openzeppelin:upgrades:core development manifest directory: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades +13ms
  @openzeppelin:upgrades:core development manifest file: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades/hardhat-31337-0x4da65430d56b547f80850352900d650fc8510de7c40be600352f1961df0c7d69.json fallback file: .openzeppelin/unknown-31337.json +0ms
  @openzeppelin:upgrades:core fetching deployment of implementation d245e4705533026615fa459ee93f2ac3866ec26d0a95ff9be4ad23c2fc23e029 +2ms
  @openzeppelin:upgrades:core initiated deployment transaction hash: 0x043a8f16039ef700e2254e069a50c1ae704cecbd866e4b81b7159216ead31aae merge: false +62ms
  @openzeppelin:upgrades:core polling timeout 60000 polling interval 5000 +6ms
  @openzeppelin:upgrades:core verifying deployment tx mined 0x043a8f16039ef700e2254e069a50c1ae704cecbd866e4b81b7159216ead31aae +0ms
  @openzeppelin:upgrades:core succeeded verifying deployment tx mined 0x043a8f16039ef700e2254e069a50c1ae704cecbd866e4b81b7159216ead31aae +1ms
  @openzeppelin:upgrades:core verifying code in target address 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512 +0ms
  @openzeppelin:upgrades:core code in target address found 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512 +1ms
  @openzeppelin:upgrades:core development manifest directory: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades +67ms
  @openzeppelin:upgrades:core development manifest file: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades/hardhat-31337-0x4da65430d56b547f80850352900d650fc8510de7c40be600352f1961df0c7d69.json fallback file: .openzeppelin/unknown-31337.json +0ms
  @openzeppelin:upgrades:core development manifest directory: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades +8ms
  @openzeppelin:upgrades:core development manifest file: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades/hardhat-31337-0x4da65430d56b547f80850352900d650fc8510de7c40be600352f1961df0c7d69.json fallback file: .openzeppelin/unknown-31337.json +0ms
  @openzeppelin:upgrades:core fetching deployment of implementation dddd4efb59318d3b4729945864956744e3f1db85ced3511314fa01cebd1ff4f4 +1ms
  @openzeppelin:upgrades:core initiated deployment transaction hash: 0x0ef675f407e3c1651e78214531a676c7c80ceb7f085aa60b2f3fa9ce6b9a5757 merge: false +33ms
  @openzeppelin:upgrades:core polling timeout 60000 polling interval 5000 +1ms
  @openzeppelin:upgrades:core verifying deployment tx mined 0x0ef675f407e3c1651e78214531a676c7c80ceb7f085aa60b2f3fa9ce6b9a5757 +0ms
  @openzeppelin:upgrades:core succeeded verifying deployment tx mined 0x0ef675f407e3c1651e78214531a676c7c80ceb7f085aa60b2f3fa9ce6b9a5757 +0ms
  @openzeppelin:upgrades:core verifying code in target address 0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9 +0ms
  @openzeppelin:upgrades:core code in target address found 0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9 +1ms
  @openzeppelin:upgrades:core development manifest directory: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades +71ms
  @openzeppelin:upgrades:core development manifest file: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades/hardhat-31337-0x4da65430d56b547f80850352900d650fc8510de7c40be600352f1961df0c7d69.json fallback file: .openzeppelin/unknown-31337.json +0ms
  @openzeppelin:upgrades:core development manifest directory: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades +7ms
  @openzeppelin:upgrades:core development manifest file: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades/hardhat-31337-0x4da65430d56b547f80850352900d650fc8510de7c40be600352f1961df0c7d69.json fallback file: .openzeppelin/unknown-31337.json +0ms
  @openzeppelin:upgrades:core fetching deployment of implementation e1dffd4772d39e3f71dd9cb8f9d6a2c0c80f17c6c57a709f7783ec90b824da88 +1ms
  @openzeppelin:upgrades:core initiated deployment transaction hash: 0xc8ceeed7306329e7fcc777bd00ff9ea3e0ce7a1f15110cc28c76f57bb55591c8 merge: false +21ms
  @openzeppelin:upgrades:core polling timeout 60000 polling interval 5000 +2ms
  @openzeppelin:upgrades:core verifying deployment tx mined 0xc8ceeed7306329e7fcc777bd00ff9ea3e0ce7a1f15110cc28c76f57bb55591c8 +0ms
  @openzeppelin:upgrades:core succeeded verifying deployment tx mined 0xc8ceeed7306329e7fcc777bd00ff9ea3e0ce7a1f15110cc28c76f57bb55591c8 +0ms
  @openzeppelin:upgrades:core verifying code in target address 0x5FC8d32690cc91D4c39d9d3abcBD16989F875707 +0ms
  @openzeppelin:upgrades:core code in target address found 0x5FC8d32690cc91D4c39d9d3abcBD16989F875707 +1ms
  @openzeppelin:upgrades:core development manifest directory: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades +74ms
  @openzeppelin:upgrades:core development manifest file: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades/hardhat-31337-0x4da65430d56b547f80850352900d650fc8510de7c40be600352f1961df0c7d69.json fallback file: .openzeppelin/unknown-31337.json +0ms
  @openzeppelin:upgrades:core development manifest directory: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades +7ms
  @openzeppelin:upgrades:core development manifest file: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades/hardhat-31337-0x4da65430d56b547f80850352900d650fc8510de7c40be600352f1961df0c7d69.json fallback file: .openzeppelin/unknown-31337.json +0ms
  @openzeppelin:upgrades:core fetching deployment of implementation 40e007f1d18f1d81ee6c91532a5de11fdf7feccc39da634c5ab907c5acd9ca96 +1ms
  @openzeppelin:upgrades:core initiated deployment transaction hash: 0xa6e19d32aca2f42f5828e7af744220da6ffee8fffb46124aa9500438c4dd6d3a merge: false +17ms
  @openzeppelin:upgrades:core polling timeout 60000 polling interval 5000 +1ms
  @openzeppelin:upgrades:core verifying deployment tx mined 0xa6e19d32aca2f42f5828e7af744220da6ffee8fffb46124aa9500438c4dd6d3a +1ms
  @openzeppelin:upgrades:core succeeded verifying deployment tx mined 0xa6e19d32aca2f42f5828e7af744220da6ffee8fffb46124aa9500438c4dd6d3a +0ms
  @openzeppelin:upgrades:core verifying code in target address 0xa513E6E4b8f2a923D98304ec87F64353C4D5C853 +0ms
  @openzeppelin:upgrades:core code in target address found 0xa513E6E4b8f2a923D98304ec87F64353C4D5C853 +0ms
  @openzeppelin:upgrades:core development manifest directory: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades +29ms
  @openzeppelin:upgrades:core development manifest file: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades/hardhat-31337-0x4da65430d56b547f80850352900d650fc8510de7c40be600352f1961df0c7d69.json fallback file: .openzeppelin/unknown-31337.json +0ms
  @openzeppelin:upgrades:core development manifest directory: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades +7ms
  @openzeppelin:upgrades:core development manifest file: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades/hardhat-31337-0x4da65430d56b547f80850352900d650fc8510de7c40be600352f1961df0c7d69.json fallback file: .openzeppelin/unknown-31337.json +0ms
  @openzeppelin:upgrades:core fetching deployment of implementation 4d12adf8440ae553785d9c224f9dcfd3bf15f5e4b41ee43a440b2233cfcf20ae +0ms
  @openzeppelin:upgrades:core initiated deployment transaction hash: 0x179f7515167fd4eb381ce72449506b4b70c616854cd134db8112296b065a96ed merge: false +16ms
  @openzeppelin:upgrades:core polling timeout 60000 polling interval 5000 +2ms
  @openzeppelin:upgrades:core verifying deployment tx mined 0x179f7515167fd4eb381ce72449506b4b70c616854cd134db8112296b065a96ed +0ms
  @openzeppelin:upgrades:core succeeded verifying deployment tx mined 0x179f7515167fd4eb381ce72449506b4b70c616854cd134db8112296b065a96ed +0ms
  @openzeppelin:upgrades:core verifying code in target address 0x8A791620dd6260079BF849Dc5567aDC3F2FdC318 +0ms
  @openzeppelin:upgrades:core code in target address found 0x8A791620dd6260079BF849Dc5567aDC3F2FdC318 +0ms
  @openzeppelin:upgrades:core development manifest directory: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades +32ms
  @openzeppelin:upgrades:core development manifest file: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades/hardhat-31337-0x4da65430d56b547f80850352900d650fc8510de7c40be600352f1961df0c7d69.json fallback file: .openzeppelin/unknown-31337.json +0ms
  @openzeppelin:upgrades:core development manifest directory: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades +8ms
  @openzeppelin:upgrades:core development manifest file: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades/hardhat-31337-0x4da65430d56b547f80850352900d650fc8510de7c40be600352f1961df0c7d69.json fallback file: .openzeppelin/unknown-31337.json +0ms
  @openzeppelin:upgrades:core fetching deployment of implementation 7bd30af036079265a3d8d8099bd8c76e945ff1c2a23d752147b08fc26f6e18fc +1ms
  @openzeppelin:upgrades:core initiated deployment transaction hash: 0x778caa97dc41c67744af8756d6dac3fd62942c2f3cf21dd878c2e1f4d47c21ff merge: false +24ms
  @openzeppelin:upgrades:core polling timeout 60000 polling interval 5000 +1ms
  @openzeppelin:upgrades:core verifying deployment tx mined 0x778caa97dc41c67744af8756d6dac3fd62942c2f3cf21dd878c2e1f4d47c21ff +0ms
  @openzeppelin:upgrades:core succeeded verifying deployment tx mined 0x778caa97dc41c67744af8756d6dac3fd62942c2f3cf21dd878c2e1f4d47c21ff +0ms
  @openzeppelin:upgrades:core verifying code in target address 0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e +0ms
  @openzeppelin:upgrades:core code in target address found 0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e +1ms
  @openzeppelin:upgrades:core development manifest directory: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades +414ms
  @openzeppelin:upgrades:core development manifest file: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades/hardhat-31337-0x4da65430d56b547f80850352900d650fc8510de7c40be600352f1961df0c7d69.json fallback file: .openzeppelin/unknown-31337.json +0ms
  @openzeppelin:upgrades:core development manifest directory: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades +3ms
  @openzeppelin:upgrades:core development manifest file: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades/hardhat-31337-0x4da65430d56b547f80850352900d650fc8510de7c40be600352f1961df0c7d69.json fallback file: .openzeppelin/unknown-31337.json +0ms
  @openzeppelin:upgrades:core development manifest directory: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades +12ms
  @openzeppelin:upgrades:core development manifest file: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades/hardhat-31337-0x4da65430d56b547f80850352900d650fc8510de7c40be600352f1961df0c7d69.json fallback file: .openzeppelin/unknown-31337.json +0ms
  @openzeppelin:upgrades:core fetching deployment of implementation 1202495c74ed2740a7a8c35e475fd12fd245035dbfc0ab8e2d004b0f474bfecc +1ms
  @openzeppelin:upgrades:core initiated deployment transaction hash: 0x9d25b13b8b1e37d4700aa12e7e1c4487328d19a12697f31cbd843c16d46a8f9b merge: false +24ms
  @openzeppelin:upgrades:core polling timeout 60000 polling interval 5000 +1ms
  @openzeppelin:upgrades:core verifying deployment tx mined 0x9d25b13b8b1e37d4700aa12e7e1c4487328d19a12697f31cbd843c16d46a8f9b +0ms
  @openzeppelin:upgrades:core succeeded verifying deployment tx mined 0x9d25b13b8b1e37d4700aa12e7e1c4487328d19a12697f31cbd843c16d46a8f9b +0ms
  @openzeppelin:upgrades:core verifying code in target address 0xa85233C63b9Ee964Add6F2cffe00Fd84eb32338f +0ms
  @openzeppelin:upgrades:core code in target address found 0xa85233C63b9Ee964Add6F2cffe00Fd84eb32338f +0ms
      βœ” is upgradeable (162ms)
    ETSAuctionHouse
  @openzeppelin:upgrades:core development manifest directory: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades +676ms
  @openzeppelin:upgrades:core development manifest file: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades/hardhat-31337-0x4da65430d56b547f80850352900d650fc8510de7c40be600352f1961df0c7d69.json fallback file: .openzeppelin/unknown-31337.json +0ms
  @openzeppelin:upgrades:core development manifest directory: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades +19ms
  @openzeppelin:upgrades:core development manifest file: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades/hardhat-31337-0x4da65430d56b547f80850352900d650fc8510de7c40be600352f1961df0c7d69.json fallback file: .openzeppelin/unknown-31337.json +0ms
  @openzeppelin:upgrades:core fetching deployment of implementation d245e4705533026615fa459ee93f2ac3866ec26d0a95ff9be4ad23c2fc23e029 +1ms
  @openzeppelin:upgrades:core found previous deployment 0x043a8f16039ef700e2254e069a50c1ae704cecbd866e4b81b7159216ead31aae +1ms
  @openzeppelin:upgrades:core resuming previous deployment 0x043a8f16039ef700e2254e069a50c1ae704cecbd866e4b81b7159216ead31aae +1ms
  @openzeppelin:upgrades:core polling timeout 60000 polling interval 5000 +0ms
  @openzeppelin:upgrades:core verifying deployment tx mined 0x043a8f16039ef700e2254e069a50c1ae704cecbd866e4b81b7159216ead31aae +0ms
  @openzeppelin:upgrades:core succeeded verifying deployment tx mined 0x043a8f16039ef700e2254e069a50c1ae704cecbd866e4b81b7159216ead31aae +0ms
  @openzeppelin:upgrades:core verifying code in target address 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512 +0ms
  @openzeppelin:upgrades:core code in target address found 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512 +1ms
  @openzeppelin:upgrades:core development manifest directory: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades +33ms
  @openzeppelin:upgrades:core development manifest file: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades/hardhat-31337-0x4da65430d56b547f80850352900d650fc8510de7c40be600352f1961df0c7d69.json fallback file: .openzeppelin/unknown-31337.json +0ms
  @openzeppelin:upgrades:core development manifest directory: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades +7ms
  @openzeppelin:upgrades:core development manifest file: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades/hardhat-31337-0x4da65430d56b547f80850352900d650fc8510de7c40be600352f1961df0c7d69.json fallback file: .openzeppelin/unknown-31337.json +0ms
  @openzeppelin:upgrades:core fetching deployment of implementation dddd4efb59318d3b4729945864956744e3f1db85ced3511314fa01cebd1ff4f4 +0ms
  @openzeppelin:upgrades:core found previous deployment 0x0ef675f407e3c1651e78214531a676c7c80ceb7f085aa60b2f3fa9ce6b9a5757 +1ms
  @openzeppelin:upgrades:core resuming previous deployment 0x0ef675f407e3c1651e78214531a676c7c80ceb7f085aa60b2f3fa9ce6b9a5757 +1ms
  @openzeppelin:upgrades:core polling timeout 60000 polling interval 5000 +0ms
  @openzeppelin:upgrades:core verifying deployment tx mined 0x0ef675f407e3c1651e78214531a676c7c80ceb7f085aa60b2f3fa9ce6b9a5757 +0ms
  @openzeppelin:upgrades:core succeeded verifying deployment tx mined 0x0ef675f407e3c1651e78214531a676c7c80ceb7f085aa60b2f3fa9ce6b9a5757 +0ms
  @openzeppelin:upgrades:core verifying code in target address 0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9 +0ms
  @openzeppelin:upgrades:core code in target address found 0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9 +1ms
  @openzeppelin:upgrades:core development manifest directory: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades +46ms
  @openzeppelin:upgrades:core development manifest file: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades/hardhat-31337-0x4da65430d56b547f80850352900d650fc8510de7c40be600352f1961df0c7d69.json fallback file: .openzeppelin/unknown-31337.json +0ms
  @openzeppelin:upgrades:core development manifest directory: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades +7ms
  @openzeppelin:upgrades:core development manifest file: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades/hardhat-31337-0x4da65430d56b547f80850352900d650fc8510de7c40be600352f1961df0c7d69.json fallback file: .openzeppelin/unknown-31337.json +0ms
  @openzeppelin:upgrades:core fetching deployment of implementation e1dffd4772d39e3f71dd9cb8f9d6a2c0c80f17c6c57a709f7783ec90b824da88 +0ms
  @openzeppelin:upgrades:core found previous deployment 0xc8ceeed7306329e7fcc777bd00ff9ea3e0ce7a1f15110cc28c76f57bb55591c8 +1ms
  @openzeppelin:upgrades:core resuming previous deployment 0xc8ceeed7306329e7fcc777bd00ff9ea3e0ce7a1f15110cc28c76f57bb55591c8 +1ms
  @openzeppelin:upgrades:core polling timeout 60000 polling interval 5000 +0ms
  @openzeppelin:upgrades:core verifying deployment tx mined 0xc8ceeed7306329e7fcc777bd00ff9ea3e0ce7a1f15110cc28c76f57bb55591c8 +0ms
  @openzeppelin:upgrades:core succeeded verifying deployment tx mined 0xc8ceeed7306329e7fcc777bd00ff9ea3e0ce7a1f15110cc28c76f57bb55591c8 +0ms
  @openzeppelin:upgrades:core verifying code in target address 0x5FC8d32690cc91D4c39d9d3abcBD16989F875707 +0ms
  @openzeppelin:upgrades:core code in target address found 0x5FC8d32690cc91D4c39d9d3abcBD16989F875707 +0ms
  @openzeppelin:upgrades:core development manifest directory: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades +64ms
  @openzeppelin:upgrades:core development manifest file: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades/hardhat-31337-0x4da65430d56b547f80850352900d650fc8510de7c40be600352f1961df0c7d69.json fallback file: .openzeppelin/unknown-31337.json +0ms
  @openzeppelin:upgrades:core development manifest directory: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades +6ms
  @openzeppelin:upgrades:core development manifest file: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades/hardhat-31337-0x4da65430d56b547f80850352900d650fc8510de7c40be600352f1961df0c7d69.json fallback file: .openzeppelin/unknown-31337.json +0ms
  @openzeppelin:upgrades:core fetching deployment of implementation 40e007f1d18f1d81ee6c91532a5de11fdf7feccc39da634c5ab907c5acd9ca96 +0ms
  @openzeppelin:upgrades:core found previous deployment 0xa6e19d32aca2f42f5828e7af744220da6ffee8fffb46124aa9500438c4dd6d3a +1ms
  @openzeppelin:upgrades:core resuming previous deployment 0xa6e19d32aca2f42f5828e7af744220da6ffee8fffb46124aa9500438c4dd6d3a +1ms
  @openzeppelin:upgrades:core polling timeout 60000 polling interval 5000 +0ms
  @openzeppelin:upgrades:core verifying deployment tx mined 0xa6e19d32aca2f42f5828e7af744220da6ffee8fffb46124aa9500438c4dd6d3a +0ms
  @openzeppelin:upgrades:core succeeded verifying deployment tx mined 0xa6e19d32aca2f42f5828e7af744220da6ffee8fffb46124aa9500438c4dd6d3a +0ms
  @openzeppelin:upgrades:core verifying code in target address 0xa513E6E4b8f2a923D98304ec87F64353C4D5C853 +0ms
  @openzeppelin:upgrades:core code in target address found 0xa513E6E4b8f2a923D98304ec87F64353C4D5C853 +0ms
  @openzeppelin:upgrades:core development manifest directory: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades +25ms
  @openzeppelin:upgrades:core development manifest file: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades/hardhat-31337-0x4da65430d56b547f80850352900d650fc8510de7c40be600352f1961df0c7d69.json fallback file: .openzeppelin/unknown-31337.json +1ms
  @openzeppelin:upgrades:core development manifest directory: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades +5ms
  @openzeppelin:upgrades:core development manifest file: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades/hardhat-31337-0x4da65430d56b547f80850352900d650fc8510de7c40be600352f1961df0c7d69.json fallback file: .openzeppelin/unknown-31337.json +0ms
  @openzeppelin:upgrades:core fetching deployment of implementation 4d12adf8440ae553785d9c224f9dcfd3bf15f5e4b41ee43a440b2233cfcf20ae +1ms
  @openzeppelin:upgrades:core found previous deployment 0x179f7515167fd4eb381ce72449506b4b70c616854cd134db8112296b065a96ed +1ms
  @openzeppelin:upgrades:core resuming previous deployment 0x179f7515167fd4eb381ce72449506b4b70c616854cd134db8112296b065a96ed +0ms
  @openzeppelin:upgrades:core polling timeout 60000 polling interval 5000 +0ms
  @openzeppelin:upgrades:core verifying deployment tx mined 0x179f7515167fd4eb381ce72449506b4b70c616854cd134db8112296b065a96ed +0ms
  @openzeppelin:upgrades:core succeeded verifying deployment tx mined 0x179f7515167fd4eb381ce72449506b4b70c616854cd134db8112296b065a96ed +1ms
  @openzeppelin:upgrades:core verifying code in target address 0x8A791620dd6260079BF849Dc5567aDC3F2FdC318 +0ms
  @openzeppelin:upgrades:core code in target address found 0x8A791620dd6260079BF849Dc5567aDC3F2FdC318 +0ms
  @openzeppelin:upgrades:core development manifest directory: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades +26ms
  @openzeppelin:upgrades:core development manifest file: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades/hardhat-31337-0x4da65430d56b547f80850352900d650fc8510de7c40be600352f1961df0c7d69.json fallback file: .openzeppelin/unknown-31337.json +0ms
  @openzeppelin:upgrades:core development manifest directory: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades +7ms
  @openzeppelin:upgrades:core development manifest file: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades/hardhat-31337-0x4da65430d56b547f80850352900d650fc8510de7c40be600352f1961df0c7d69.json fallback file: .openzeppelin/unknown-31337.json +0ms
  @openzeppelin:upgrades:core fetching deployment of implementation 7bd30af036079265a3d8d8099bd8c76e945ff1c2a23d752147b08fc26f6e18fc +0ms
  @openzeppelin:upgrades:core found previous deployment 0x778caa97dc41c67744af8756d6dac3fd62942c2f3cf21dd878c2e1f4d47c21ff +1ms
  @openzeppelin:upgrades:core resuming previous deployment 0x778caa97dc41c67744af8756d6dac3fd62942c2f3cf21dd878c2e1f4d47c21ff +1ms
  @openzeppelin:upgrades:core polling timeout 60000 polling interval 5000 +0ms
  @openzeppelin:upgrades:core verifying deployment tx mined 0x778caa97dc41c67744af8756d6dac3fd62942c2f3cf21dd878c2e1f4d47c21ff +0ms
  @openzeppelin:upgrades:core succeeded verifying deployment tx mined 0x778caa97dc41c67744af8756d6dac3fd62942c2f3cf21dd878c2e1f4d47c21ff +0ms
  @openzeppelin:upgrades:core verifying code in target address 0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e +0ms
  @openzeppelin:upgrades:core code in target address found 0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e +1ms
  @openzeppelin:upgrades:core development manifest directory: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades +371ms
  @openzeppelin:upgrades:core development manifest file: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades/hardhat-31337-0x4da65430d56b547f80850352900d650fc8510de7c40be600352f1961df0c7d69.json fallback file: .openzeppelin/unknown-31337.json +1ms
  @openzeppelin:upgrades:core development manifest directory: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades +2ms
  @openzeppelin:upgrades:core development manifest file: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades/hardhat-31337-0x4da65430d56b547f80850352900d650fc8510de7c40be600352f1961df0c7d69.json fallback file: .openzeppelin/unknown-31337.json +0ms
  @openzeppelin:upgrades:core development manifest directory: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades +10ms
  @openzeppelin:upgrades:core development manifest file: /var/folders/zx/h2c7004s1r98llfkfff4x0j00000gp/T/openzeppelin-upgrades/hardhat-31337-0x4da65430d56b547f80850352900d650fc8510de7c40be600352f1961df0c7d69.json fallback file: .openzeppelin/unknown-31337.json +0ms
  @openzeppelin:upgrades:core fetching deployment of implementation e7b96c2dcf59c82dbee1efcf301365b6f1d5ec8169801bd4c5d7fb0c47a5680b +1ms
  @openzeppelin:upgrades:core initiated deployment transaction hash: 0xd8ce5418d9e7dbc99f14aca0d707fddcba62b3652b409a43f812feec0cfbb1ea merge: false +17ms
  @openzeppelin:upgrades:core polling timeout 60000 polling interval 5000 +1ms
  @openzeppelin:upgrades:core verifying deployment tx mined 0xd8ce5418d9e7dbc99f14aca0d707fddcba62b3652b409a43f812feec0cfbb1ea +1ms
  @openzeppelin:upgrades:core succeeded verifying deployment tx mined 0xd8ce5418d9e7dbc99f14aca0d707fddcba62b3652b409a43f812feec0cfbb1ea +0ms
  @openzeppelin:upgrades:core verifying code in target address 0x8f86403A4DE0BB5791fa46B8e795C547942fE4Cf +0ms
  @openzeppelin:upgrades:core code in target address found 0x8f86403A4DE0BB5791fa46B8e795C547942fE4Cf +0ms
      1) is upgradeable


  1 passing (5s)
  1 failing

  1) Upgrades tests
       ETSAuctionHouse
         is upgradeable:
     Error: Unexpected type for UPGRADE_INTERFACE_VERSION at address 0x67d269191c92Caf3cD7723F116c85e6E9bf55933. Expected a string
      at getUpgradeInterfaceVersion (/Users/User/Sites/ets/node_modules/.pnpm/@openzeppelin+upgrades-core@1.31.1/node_modules/@openzeppelin/upgrades-core/src/upgrade-interface-version.ts:16:13)
      at processTicksAndRejections (node:internal/process/task_queues:96:5)
      at async getUpgrader (/Users/User/Sites/ets/node_modules/.pnpm/@openzeppelin+hardhat-upgrades@2.4.1_@nomicfoundation+hardhat-ethers@3.0.4_ethers@6.8.1_hardhat@2.19.0/node_modules/@openzeppelin/hardhat-upgrades/src/upgrade-proxy.ts:57:39)
      at async Proxy.upgradeProxy (/Users/User/Sites/ets/node_modules/.pnpm/@openzeppelin+hardhat-upgrades@2.4.1_@nomicfoundation+hardhat-ethers@3.0.4_ethers@6.8.1_hardhat@2.19.0/node_modules/@openzeppelin/hardhat-upgrades/src/upgrade-proxy.ts:32:23)
      at async Context.<anonymous> (test/ETSUpgradeable.test.js:85:35)

2. Network file

I only have an old mumbai file in there. Not seeing one in there for hardhat/localdev network.

3. Hardhat or Truffle config file

//import "hardhat-ethernal";
import "@typechain/hardhat";
import {HardhatUserConfig} from "hardhat/types";
import "hardhat-deploy";
import "solidity-docgen";
import "solidity-coverage";
import "hardhat-abi-exporter";
import "@nomiclabs/hardhat-web3";
import "@nomiclabs/hardhat-ethers";
import "@nomiclabs/hardhat-waffle";
import "@nomiclabs/hardhat-truffle5";
import "@nomiclabs/hardhat-etherscan";
import "@openzeppelin/hardhat-upgrades";
import "@nomicfoundation/hardhat-chai-matchers";

import {resolve} from "path";
import {config as dotenvConfig} from "dotenv";
//import {HttpNetworkAccountsUserConfig} from "hardhat/types";

import "./tasks";

dotenvConfig({path: resolve(__dirname, "../../.env")});

const mnemonic = {
  local: `${process.env.MNEMONIC_LOCAL}`.replace(/_/g, " "),
  mumbai: `${process.env.MNEMONIC_MUMBAI}`.replace(/_/g, " "),
};

const config: HardhatUserConfig = {
  networks: {
    hardhat: {
      mining: {
        auto: false,
        interval: 2000,
        mempool: {
          order: "fifo",
        },
      },
      accounts: {
        mnemonic: mnemonic.local,
      },
      chainId: 31337,
    },
    localhost: {
      url: "http://localhost:8545",
      accounts: {
        mnemonic: mnemonic.local,
      },
      chainId: 31337,
    },
    mumbai: {
      url: `https://polygon-mumbai.g.alchemy.com/v2/${process.env.ALCHEMY_MUMBAI}`,
      //url: `https://polygon-mumbai.infura.io/v3/${process.env.INFURA_API_KEY}`,
      chainId: 80001,
      accounts: {
        mnemonic: mnemonic.mumbai,
      },
      gas: 2100000,
      gasPrice: 8000000000,
    },
  },
  abiExporter: {
    path: "./abi",
    runOnCompile: true,
  },
  // ETS administration accounts.
  namedAccounts: {
    ETSAdmin: {default: 0},
    ETSPlatform: {default: 1},
  },
  etherscan: {
    apiKey: process.env.ETHERSCAN_API_KEY,
  },
  docgen: {
    outputDir: "docs",
    pages: "files",
    templates: "./templates",
    exclude: ["mocks", "test", "utils"],
  },
  // typechain: {
  //   outDir: '../app/types',
  // },
  solidity: {
    compilers: [
      {
        version: "0.4.24",
      },
      {
        version: "0.6.12",
        settings: {
          optimizer: {
            enabled: true,
            runs: 1000,
          },
        },
      },
      {
        version: "0.8.2",
        settings: {
          optimizer: {
            enabled: true,
            runs: 1000,
          },
        },
      },
      {
        version: "0.8.7",
        settings: {
          optimizer: {
            enabled: true,
            runs: 1000,
          },
        },
      },
      {
        version: "0.8.12",
        settings: {
          optimizer: {
            enabled: true,
            runs: 1000,
          },
        },
      },
    ],
  },
  //  ethernal: {
  //    disableSync: false,
  //    disableTrace: true,
  //    workspace: process.env.ETHERNAL_WORKSPACE ? process.env.ETHERNAL_WORKSPACE : undefined,
  //    uploadAst: false,
  //    disabled: process.env.ETHERNAL_DISABLED == "true" ? true : false,
  //    resetOnStart: process.env.ETHERNAL_WORKSPACE ? process.env.ETHERNAL_WORKSPACE : undefined,
  //  },
};

export default config;

3. Script(s)

# ETSUpgradeable.test.js

const { setup, getFactories, getArtifacts } = require("./setup.js");
const { expectEvent } = require("@openzeppelin/test-helpers");
const { upgrades } = require("hardhat");
const { assert } = require("chai");

let artifacts, factories;

describe("Upgrades tests", function () {
  beforeEach("Setup test", async function () {
    artifacts = await getArtifacts();
    factories = await getFactories();
    [accounts, contracts, initSettings] = await setup();

  });

  describe("ETSAccessControl", async function () {
    it("is upgradeable", async function () {
      // Upgrade the proxy.
      contracts.ETSAccessControls = await upgrades.upgradeProxy(
        await contracts.ETSAccessControls.getAddress(),
        factories.ETSAccessControlsUpgrade,
      );

      const upgradeTxn = await contracts.ETSAccessControls.deployTransaction.hash;
      await expectEvent.inTransaction(upgradeTxn, artifacts.ETSAccessControlsUpgrade, "Upgraded");
      // Upgraded contract has new function upgradeTest()
      assert((await contracts.ETSAccessControls.upgradeTest()) === true);
    });
  });

  describe("ETSAuctionHouse", function () {
    it("is upgradeable", async function () {
      // Upgrade the proxy.
      contracts.ETSAuctionHouse = await upgrades.upgradeProxy(
        await contracts.ETSAuctionHouse.getAddress(),
        factories.ETSAuctionHouseUpgrade,
      );

      const upgradeTxn = contracts.ETSAuctionHouse.deployTransaction.hash;
      await expectEvent.inTransaction(upgradeTxn, artifacts.ETSAuctionHouseUpgrade, "Upgraded");
      // Upgraded contract has new function upgradeTest()
      assert((await contracts.ETSAuctionHouse.upgradeTest()) === true);
    });
  });
});

# setup.js
const { ethers, upgrades, artifacts } = require("hardhat");
const initSettings = {
  // Token
  TAG_MIN_STRING_LENGTH: 2,
  TAG_MAX_STRING_LENGTH: 32,
  OWNERSHIP_TERM_LENGTH: 730,
  // Auction
  MAX_AUCTIONS: 1,
  TIME_BUFFER: 600, // 600 secs / 10 minutes
  RESERVE_PRICE: "1", // 1 MATIC
  MIN_INCREMENT_BID_PERCENTAGE: 5,
  DURATION: 30 * 60, // 30 minutes
  RELAYER_PERCENTAGE: 20,
  CREATOR_PERCENTAGE: 40,
  PLATFORM_PERCENTAGE: 40,
  // ETS core (Tagging records)
  TAGGING_FEE: "0.1", // .1 MATIC
  TAGGING_FEE_PLATFORM_PERCENTAGE: 20,
  TAGGING_FEE_RELAYER_PERCENTAGE: 30,
};

async function getAccounts() {
  const namedAccounts = await ethers.getNamedSigners();
  const unnamedAccounts = await ethers.getUnnamedSigners();
  const accounts = {
    ETSAdmin: namedAccounts["ETSAdmin"],
    ETSPlatform: namedAccounts["ETSPlatform"],
    Buyer: unnamedAccounts[0],
    RandomOne: unnamedAccounts[1],
    RandomTwo: unnamedAccounts[2],
    Creator: unnamedAccounts[3],
  };
  return accounts;
}

async function getArtifacts() {
  const allArtifacts = {
    ETSAccessControls: artifacts.readArtifactSync("ETSAccessControls"),
    ETSToken: artifacts.readArtifactSync("ETSToken"),
    ETSTarget: artifacts.readArtifactSync("ETSTarget"),
    ETSEnrichTarget: artifacts.readArtifactSync("ETSEnrichTarget"),
    ETSAuctionHouse: artifacts.readArtifactSync("ETSAuctionHouse"),
    ETS: artifacts.readArtifactSync("ETS"),
    ETSRelayerV1: artifacts.readArtifactSync("ETSRelayerV1"),
    ETSRelayerFactory: artifacts.readArtifactSync("ETSRelayerFactory"),

    /// .sol test contracts.
    ETSAccessControlsUpgrade: artifacts.readArtifactSync("ETSAccessControlsUpgrade"),
    ETSTokenUpgrade: artifacts.readArtifactSync("ETSTokenUpgrade"),
    ETSAuctionHouseUpgrade: artifacts.readArtifactSync("ETSAuctionHouseUpgrade"),
    ETSEnrichTargetUpgrade: artifacts.readArtifactSync("ETSEnrichTargetUpgrade"),
    ETSTargetUpgrade: artifacts.readArtifactSync("ETSTargetUpgrade"),
    ETSUpgrade: artifacts.readArtifactSync("ETSUpgrade"),
  };
  return allArtifacts;
}

async function getFactories() {
  const allFactories = {
    ETSAccessControls: await ethers.getContractFactory("ETSAccessControls"),
    ETSToken: await ethers.getContractFactory("ETSToken"),
    ETSTarget: await ethers.getContractFactory("ETSTarget"),
    ETSEnrichTarget: await ethers.getContractFactory("ETSEnrichTarget"),
    ETSAuctionHouse: await ethers.getContractFactory("ETSAuctionHouse"),
    ETS: await ethers.getContractFactory("ETS"),
    ETSRelayerV1: await ethers.getContractFactory("ETSRelayerV1"),
    ETSRelayerFactory: await ethers.getContractFactory("ETSRelayerFactory"),

    /// .sol test contracts.
    WMATIC: await ethers.getContractFactory("WMATIC"),
    ETSAccessControlsUpgrade: await ethers.getContractFactory("ETSAccessControlsUpgrade"),
    ETSAuctionHouseUpgrade: await ethers.getContractFactory("ETSAuctionHouseUpgrade"),
    ETSTokenUpgrade: await ethers.getContractFactory("ETSTokenUpgrade"),
    ETSEnrichTargetUpgrade: await ethers.getContractFactory("ETSEnrichTargetUpgrade"),
    ETSTargetUpgrade: await ethers.getContractFactory("ETSTargetUpgrade"),
    ETSUpgrade: await ethers.getContractFactory("ETSUpgrade"),
    ETSRelayerV2test: await ethers.getContractFactory("ETSRelayerV2test"),
  };
  return allFactories;
}

function getInitSettings() {
  return initSettings;
}

async function setup() {

  const factories = await getFactories();
  const accounts = await getAccounts();

  await network.provider.send("evm_setAutomine", [true]);

  // ============ DEPLOY CONTRACTS ============

  const WMATIC = await factories.WMATIC.deploy();
  await WMATIC.waitForDeployment();
  const WMATICAddress = await WMATIC.getAddress();

  const ETSAccessControls = await upgrades.deployProxy(factories.ETSAccessControls, [accounts.ETSPlatform.address], {
    kind: "uups",
  });
  await ETSAccessControls.waitForDeployment();
  const ETSAccessControlsAddress = await ETSAccessControls.getAddress();

  const ETSToken = await upgrades.deployProxy(
    factories.ETSToken,
    [
      ETSAccessControlsAddress,
      initSettings.TAG_MIN_STRING_LENGTH,
      initSettings.TAG_MAX_STRING_LENGTH,
      initSettings.OWNERSHIP_TERM_LENGTH,
    ],
    { kind: "uups" },
  );
  await ETSToken.waitForDeployment();
  const ETSTokenAddress = await ETSToken.getAddress();

  const ETSAuctionHouse = await upgrades.deployProxy(
    factories.ETSAuctionHouse,
    [
      ETSTokenAddress,
      ETSAccessControlsAddress,
      WMATICAddress,
      initSettings.MAX_AUCTIONS,
      initSettings.TIME_BUFFER,
      ethers.parseUnits(initSettings.RESERVE_PRICE, "ether"),
      initSettings.MIN_INCREMENT_BID_PERCENTAGE,
      initSettings.DURATION,
      initSettings.RELAYER_PERCENTAGE,
      initSettings.PLATFORM_PERCENTAGE,
    ],
    { kind: "uups" },
  );
  await ETSAuctionHouse.waitForDeployment();
  const ETSAuctionHouseAddress = await ETSAuctionHouse.getAddress();

  const ETSTarget = await upgrades.deployProxy(factories.ETSTarget, [ETSAccessControlsAddress], { kind: "uups" });
  await ETSTarget.waitForDeployment();
  const ETSTargetAddress = await ETSTarget.getAddress();

  const ETSEnrichTarget = await upgrades.deployProxy(
    factories.ETSEnrichTarget,
    [ETSAccessControlsAddress, ETSTargetAddress],
    {
      kind: "uups",
    },
  );
  await ETSEnrichTarget.waitForDeployment();
  const ETSEnrichTargetAddress = await ETSEnrichTarget.getAddress();

  const ETS = await upgrades.deployProxy(
    factories.ETS,
    [
      ETSAccessControlsAddress,
      ETSTokenAddress,
      ETSTargetAddress,
      ethers.parseUnits(initSettings.TAGGING_FEE, "ether"),
      initSettings.TAGGING_FEE_PLATFORM_PERCENTAGE,
      initSettings.TAGGING_FEE_RELAYER_PERCENTAGE,
    ],
    {
      kind: "uups",
    },
  );
  await ETS.waitForDeployment();
  const ETSAddress = await ETS.getAddress();

  // Deploy the relayer logic contract.
  // We deploy with proxy with no arguments because factory will supply them.
  const ETSRelayerImplementation = await factories.ETSRelayerV1.deploy();
  await ETSRelayerImplementation.waitForDeployment();
  const ETSRelayerImplementationAddress = await ETSRelayerImplementation.getAddress();

  // Deploy relayer factory, which will deploy the above implementation as upgradable proxies.
  const ETSRelayerFactory = await factories.ETSRelayerFactory.deploy(
    ETSRelayerImplementationAddress,
    ETSAccessControlsAddress,
    ETSAddress,
    ETSTokenAddress,
    ETSTargetAddress,
  );
  await ETSRelayerFactory.waitForDeployment();
  const ETSRelayerFactoryAddress = await ETSRelayerFactory.getAddress();

  const contracts = {
    WMATIC: WMATIC,
    ETSAccessControls: ETSAccessControls,
    ETSToken: ETSToken,
    ETSAuctionHouse: ETSAuctionHouse,
    ETSTarget: ETSTarget,
    ETSEnrichTarget: ETSEnrichTarget,
    ETS: ETS,
    ETSRelayerFactory: ETSRelayerFactory,
    ETSRelayerImplementation: ETSRelayerImplementation,
  };

  // ============ GRANT ROLES & APPROVALS ============

  // Allows relayer admin role to grant relayer factory role.
  await ETSAccessControls.setRoleAdmin(await ETSAccessControls.RELAYER_FACTORY_ROLE(), await ETSAccessControls.RELAYER_ADMIN_ROLE());

  // Allows relayer factory role to grant relayer role.
  await ETSAccessControls.setRoleAdmin(await ETSAccessControls.RELAYER_ROLE(), await ETSAccessControls.RELAYER_FACTORY_ROLE());

  await ETSAccessControls.grantRole(await ETSAccessControls.RELAYER_ADMIN_ROLE(), accounts.ETSAdmin.address);
  await ETSAccessControls.grantRole(await ETSAccessControls.RELAYER_ADMIN_ROLE(), accounts.ETSPlatform.address);
  await ETSAccessControls.grantRole(await ETSAccessControls.RELAYER_ADMIN_ROLE(), ETSAccessControlsAddress);
  await ETSAccessControls.grantRole(await ETSAccessControls.RELAYER_ADMIN_ROLE(), ETSTokenAddress);

  // Set auction oracle to platform just for testing.
  await ETSAccessControls.grantRole(await ETSAccessControls.AUCTION_ORACLE_ROLE(), accounts.ETSPlatform.address);
  await ETSAccessControls.grantRole(await ETSAccessControls.SMART_CONTRACT_ROLE(), accounts.ETSAdmin.address);

  await ETSTarget.connect(accounts.ETSPlatform).setEnrichTarget(ETSEnrichTargetAddress);

  // Approve auction house contract to move tokens owned by platform.
  await ETSToken.connect(accounts.ETSPlatform).setApprovalForAll(ETSAuctionHouseAddress, true);

  // Set ETS Core on ETSToken.
  await ETSToken.connect(accounts.ETSPlatform).setETSCore(ETSAddress);

  // Grant RELAYER_FACTORY_ROLE to ETSRelayerFactory so it can deploy relayer contracts.
  await ETSAccessControls.grantRole(await ETSAccessControls.RELAYER_FACTORY_ROLE(), ETSRelayerFactoryAddress);

  // Add a relayer proxy for use in tests. Note: ETSPlatform not required to own CTAG to add relayer.
  await ETSRelayerFactory.connect(accounts.ETSPlatform).addRelayer("ETSRelayer");
  relayerAddress = await ETSAccessControls.getRelayerAddressFromName("ETSRelayer");
  etsRelayerV1ABI = require("../abi/contracts/relayers/ETSRelayerV1.sol/ETSRelayerV1.json");
  contracts.ETSRelayer = new ethers.Contract(relayerAddress, etsRelayerV1ABI, accounts.RandomOne);
  return [accounts, contracts, initSettings];
}

module.exports = {
  getInitSettings,
  getAccounts,
  getArtifacts,
  getFactories,
  setup,
};

4. Command that was run

# in contracts root folder
hardhat test test/ETSUpgradeable.test.js

5. Addresses

No applicable. Hardhat testsuite.

6. Installed versions of packages

User@swaylock ~/Sites/ets/packages/contracts (13-tag-auction●●●)$ pnpm list                                                                   [3.2.2]
Legend: production dependency, optional only, dev only

@ethereum-tag-service/contracts@0.1.0-alpha.1 /Users/User/Sites/ets/packages/contracts

dependencies:
@openzeppelin/contracts 4.9.2
@openzeppelin/contracts-upgradeable 4.9.2

devDependencies:
@enzoferey/ethers-error-parser 0.2.3             @types/mocha 10.0.1                              node-watch 0.7.3                                 
@ethereum-tag-service/tsconfig link:../tsconfig  @types/node 20.1.4                               prettier 2.8.8                                   
@ethersproject/abstract-signer 5.7.0             chai 4.3.6                                       prettier-plugin-solidity 1.1.3                   
@nomicfoundation/hardhat-chai-matchers 2.0.2     dotenv 16.0.3                                    random-words 1.2.0                               
@nomiclabs/hardhat-etherscan 3.1.0               ethereum-waffle 4.0.10                           solhint 3.4.1                                    
@nomiclabs/hardhat-truffle5 2.0.7                ethereumjs-util 7.1.5                            solhint-plugin-prettier 0.0.5                    
@nomiclabs/hardhat-waffle 2.0.3                  ethers 6.8.1                                     solidity-coverage 0.8.2                          
@nomiclabs/hardhat-web3 2.0.0                    hardhat 2.19.0                                   solidity-docgen 0.6.0-beta.35                    
@openzeppelin/hardhat-upgrades 2.4.1             hardhat-abi-exporter 2.10.0                      ts-node 10.9.1                                   
@openzeppelin/test-helpers 0.5.16                hardhat-deploy 0.11.43                           typechain 8.1.0                                  
@typechain/ethers-v5 11.1.2                      hardhat-deploy-ethers 0.4.1                      typescript 5.0.4                                 
@typechain/hardhat 9.1.0                         hardhat-ethernal 3.1.0                           
@types/chai 4.3.3                                lodash.merge 4.6.2 

User@swaylock ~/Sites/ets/packages/contracts (13-tag-auction●●●)$ pnpm list @openzeppelin/upgrades-core                                       [3.2.2]
User@swaylock ~/Sites/ets/packages/contracts (13-tag-auction●●●)$ npm list @openzeppelin/upgrades-core                                        [3.2.2]
npm WARN logfile could not be created: Error: EACCES: permission denied, open '/Users/User/.npm/_logs/2023-11-17T19_08_57_256Z-debug-0.log'
@ethereum-tag-service/contracts@0.1.0-alpha.1 /Users/User/Sites/ets/packages/contracts
└─┬ @openzeppelin/hardhat-upgrades@2.4.1 -> ./../../node_modules/.pnpm/@openzeppelin+hardhat-upgrades@2.4.1_@nomicfoundation+hardhat-ethers@3.0.4_ethers@6.8.1_hardhat@2.19.0/node_modules/@openzeppelin/hardhat-upgrades
  └── @openzeppelin/upgrades-core@1.31.1 -> ./../../node_modules/.pnpm/@openzeppelin+upgrades-core@1.31.1/node_modules/@openzeppelin/upgrades-core

7. Implementation contract(s)

// SPDX-License-Identifier: GPL-3.0

/**
 * @title ETS Auction House
 * @author Ethereum Tag Service <team@ets.xyz>
 *
 *  β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—
 *  β–ˆβ–ˆβ•”β•β•β•β•β•β•šβ•β•β–ˆβ–ˆβ•”β•β•β•β–ˆβ–ˆβ•”β•β•β•β•β•
 *  β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—     β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—
 *  β–ˆβ–ˆβ•”β•β•β•     β–ˆβ–ˆβ•‘   β•šβ•β•β•β•β–ˆβ–ˆβ•‘
 *  β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—   β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•‘`
 *  β•šβ•β•β•β•β•β•β•   β•šβ•β•   β•šβ•β•β•β•β•β•β•
 *
 * @notice ETSAuctionHouse.sol is a modified version of Nouns NounsAuctionHouse.sol:
 * https://github.com/nounsDAO/nouns-monorepo/blob/master/packages/nouns-contracts/contracts/NounsAuctionHouse.sol
 * which itself is a modified version of Zora AuctionHouse.sol
 *
 * AuctionHouse.sol source code Copyright Zora licensed under the GPL-3.0 license.
 * With modifications by Ethereum Tag Service.
 *
 * ETS modification include enabling more than one concurrent auction via a protocol controlled
 * setting and requiring a bid to start the auction timer.
 */

pragma solidity ^0.8.6;

import { IWMATIC } from "./interfaces/IWMATIC.sol";
import { IETSToken } from "./interfaces/IETSToken.sol";
import { IETSAuctionHouse } from "./interfaces/IETSAuctionHouse.sol";
import { IETSAccessControls } from "./interfaces/IETSAccessControls.sol";

import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";

import { IERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import { SafeERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import { CountersUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/CountersUpgradeable.sol";

/**
 * @title ETSAuctionHouse
 * @author Ethereum Tag Service <team@ets.xyz>
 *
 * @notice ETSAuctionHouse contract governs the sale of Ethereum Tag Service composable tags (CTAGs).
 */
contract ETSAuctionHouse is
    Initializable,
    PausableUpgradeable,
    ReentrancyGuardUpgradeable,
    IETSAuctionHouse,
    UUPSUpgradeable
{
    using CountersUpgradeable for CountersUpgradeable.Counter;

    IETSToken public etsToken;
    IETSAccessControls public etsAccessControls;

    /// Public constants

    string public constant NAME = "ETS Auction House";
    uint256 public constant MODULO = 100;

    /// Public variables
    uint256 public maxAuctions;

    // Open for bidding
    CountersUpgradeable.Counter activeAuctions;

    // Unique auction id
    CountersUpgradeable.Counter auctionId;

    /// @dev Mapping of active auctions
    mapping(uint256 => IETSAuctionHouse.Auction) public auctions;

    /// @dev The address of the WMATIC contract
    address public wmatic;

    /// @dev The minimum amount of time left in an auction after a new bid is created
    uint256 public timeBuffer;

    /// @dev The minimum price accepted in an auction
    uint256 public reservePrice;

    /// @dev The minimum percentage difference between the last bid amount and the current bid
    uint8 public minBidIncrementPercentage;

    /// @dev The duration of a single auction
    uint256 public duration;

    /// @dev Percentage of auction proceeds allocated to CTAG Creator
    uint256 public creatorPercentage;

    /// @dev Percentage of auction proceeds allocated to CTAG Relayer.
    uint256 public relayerPercentage;

    /// @dev Percentage of auction proceeds allocated to ETS.
    uint256 public platformPercentage;

    /// @dev Map for holding amount accrued to participant address wallets.
    mapping(address => uint256) public accrued;

    /// @dev Map for holding lifetime amount drawn down from accrued by participants.
    mapping(address => uint256) public paid;

    /// Modifiers

    modifier tagExists(uint256 tokenId) {
        require(etsToken.tagExistsById(tokenId), "CTAG does not exist");
        _;
    }

    modifier platformOwned(uint256 tokenId) {
        // Returns "ERC721: owner query for nonexistent token" for non-existent token.
        require(etsToken.ownerOf(tokenId) == etsAccessControls.getPlatformAddress(), "CTAG not owned by ETS");
        _;
    }

    modifier onlyAuctionOracle() {
        require(etsAccessControls.isAuctionOracle(_msgSender()), "Caller not auction oracle");
        _;
    }

    modifier onlyAdmin() {
        require(etsAccessControls.isAdmin(_msgSender()), "Caller must be administrator");
        _;
    }

    modifier onlyPlatform() {
        require(etsAccessControls.getPlatformAddress() == _msgSender(), "Only platform may release CTAG");
        _;
    }

    modifier isAuction(uint256 tokenId) {
        require(_isAuction(tokenId), "Auction doesn't exist");
        _;
    }

    // ============ UUPS INTERFACE ============

    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor() {
        _disableInitializers();
    }

    function initialize(
        IETSToken _etsToken,
        IETSAccessControls _etsAccessControls,
        address _wmatic,
        uint256 _maxAuctions,
        uint256 _timeBuffer,
        uint256 _reservePrice,
        uint8 _minBidIncrementPercentage,
        uint256 _duration,
        uint256 _relayerPercentage,
        uint256 _platformPercentage
    ) external initializer {
        __Pausable_init();
        __ReentrancyGuard_init();

        _pause();

        etsToken = _etsToken;
        etsAccessControls = _etsAccessControls;
        wmatic = _wmatic;

        activeAuctions.reset();
        auctionId.reset();

        setMaxAuctions(_maxAuctions);
        setMinBidIncrementPercentage(_minBidIncrementPercentage);
        setDuration(_duration);
        setReservePrice(_reservePrice);
        setTimeBuffer(_timeBuffer);
        setProceedPercentages(_platformPercentage, _relayerPercentage);
    }

    // solhint-disable-next-line
    function _authorizeUpgrade(address) internal override onlyAdmin {}

    // ============ OWNER/ADMIN INTERFACE ============

    function pause() public onlyAdmin {
        _pause();
    }

    function unpause() public onlyAdmin {
        _unpause();
    }

    function setMaxAuctions(uint256 _maxAuctions) public onlyAdmin {
        maxAuctions = _maxAuctions;
        emit AuctionsMaxSet(_maxAuctions);
    }

    function setDuration(uint256 _duration) public onlyAdmin {
        duration = _duration;
        emit AuctionDurationSet(_duration);
    }

    function setMinBidIncrementPercentage(uint8 _minBidIncrementPercentage) public onlyAdmin {
        minBidIncrementPercentage = _minBidIncrementPercentage;
        emit AuctionMinBidIncrementPercentageSet(_minBidIncrementPercentage);
    }

    function setReservePrice(uint256 _reservePrice) public onlyAdmin {
        reservePrice = _reservePrice;
        emit AuctionReservePriceSet(_reservePrice);
    }

    function setTimeBuffer(uint256 _timeBuffer) public onlyAdmin {
        timeBuffer = _timeBuffer;
        emit AuctionTimeBufferSet(_timeBuffer);
    }

    function setProceedPercentages(uint256 _platformPercentage, uint256 _relayerPercentage) public onlyAdmin {
        require(_platformPercentage + _relayerPercentage <= 100, "Input must not exceed 100%");
        platformPercentage = _platformPercentage;
        relayerPercentage = _relayerPercentage;
        creatorPercentage = MODULO - platformPercentage - relayerPercentage;

        emit AuctionProceedPercentagesSet(platformPercentage, relayerPercentage, creatorPercentage);
    }

    // ============ PUBLIC INTERFACE ============

    /**
     * @notice Settle the current auction, and release next auction.
     */
    function settleCurrentAndCreateNewAuction(uint256 _tokenId) public nonReentrant whenNotPaused {
        _settleAuction(_tokenId);
        _requestCreateAuction();
    }

    /**
     * @notice Settle the current auction.
     * @dev This function can only be called when the contract is paused.
     */
    function settleAuction(uint256 _tokenId) public whenPaused nonReentrant {
        _settleAuction(_tokenId);
    }

    // Public function to release another auction using the auction Oracle.
    function createNextAuction() public whenNotPaused {
        require(activeAuctions.current() < maxAuctions, "No open auction slots");
        _requestCreateAuction();
    }

    // Capture reponse from next auction oracle.
    function fulfillRequestCreateAuction(uint256 _tokenId) public onlyAuctionOracle {
        // Let's double check the oracle's work.
        // Note: First check returns "ERC721: invalid token ID" for non-existent token.
        require(etsToken.ownerOf(_tokenId) == etsAccessControls.getPlatformAddress(), "CTAG not owned by ETS");
        require(activeAuctions.current() < maxAuctions, "No open auction slots");
        require(!_isAuction(_tokenId), "Auction exists");
        _createAuction(_tokenId);
    }

    function createBid(uint256 _tokenId) public payable nonReentrant whenNotPaused {
        // Retrieve active auction or create new one if _tokenId exists and is platform owned.
        Auction memory auction = _getAuction(_tokenId);

        require(auction.auctionId > 0, "Auction not found");
        if (auction.startTime > 0) {
            require(block.timestamp < auction.endTime, "Auction ended");
        }
        require(msg.value >= reservePrice, "Must send at least reservePrice");
        require(msg.value >= auction.amount + ((auction.amount * minBidIncrementPercentage) / 100), "Bid too low");

        address payable lastBidder = auction.bidder;

        // Refund the last bidder, if applicable
        if (lastBidder != address(0)) {
            _safeTransferETHWithFallback(lastBidder, auction.amount);
        }

        if (auction.startTime == 0) {
            // Start the auction
            uint256 startTime = block.timestamp;
            uint256 endTime = startTime + duration;
            auctions[_tokenId].startTime = startTime;
            auctions[_tokenId].endTime = endTime;
        }

        auctions[_tokenId].amount = msg.value;
        auctions[_tokenId].bidder = payable(msg.sender);

        // Extend the auction if the bid was received within `timeBuffer` of the auction end time
        bool extended = false;
        if (auction.startTime > 0) {
            extended = auction.endTime - block.timestamp < timeBuffer;
            if (extended) {
                auctions[_tokenId].endTime = auction.endTime = block.timestamp + timeBuffer;
                emit AuctionExtended(_tokenId, auction.endTime);
            }
        }

        emit AuctionBid(_tokenId, msg.sender, msg.value, extended);
    }

    /**
     * @notice Function for withdrawing funds from an accrual account. Can be called by the account owner
     * or on behalf of the account. Does nothing when there is nothing due to the account.
     *
     * @param _account Address of account being drawn down and which will receive the funds.
     */
    function drawDown(address payable _account) external nonReentrant {
        uint256 balanceDue = totalDue(_account);
        if (balanceDue > 0 && balanceDue <= address(this).balance) {
            paid[_account] = paid[_account] + balanceDue;

            bool success = _safeTransferETH(_account, balanceDue);
            require(success, "Transfer failed");

            emit AuctionProceedsWithdrawn(_account, balanceDue);
        }
    }

    // ============ INTERNAL FUNCTIONS ============

    function _requestCreateAuction() private {
        // Trigger of chain oracle to pick and release next auction.
        emit RequestCreateAuction();
    }

    function _createAuction(uint256 _tokenId) internal {
        auctionId.increment();
        activeAuctions.increment();
        // Create new auction but don't start it.
        auctions[_tokenId] = Auction({
            auctionId: auctionId.current(),
            amount: 0,
            startTime: 0,
            endTime: 0,
            reservePrice: reservePrice,
            bidder: payable(address(0)),
            auctioneer: etsAccessControls.getPlatformAddress(),
            settled: false
        });

        emit AuctionCreated(_tokenId);
    }

    function _settleAuction(uint256 _tokenId) internal {
        Auction memory auction = _getAuction(_tokenId);
        require(_isAuction(_tokenId), "Auction does not exist");
        require(!(auction.settled), "Auction already settled");
        require(auction.startTime != 0, "Auction has not begun");
        require(block.timestamp >= auction.endTime, "Auction has not ended");

        auctions[_tokenId].settled = true;
        activeAuctions.decrement();
        etsToken.transferFrom(etsAccessControls.getPlatformAddress(), auction.bidder, _tokenId);
        _processAuctionRevenue(_tokenId, auction.amount);
        emit AuctionSettled(_tokenId);
    }

    // @dev Internal function to divide up auction revenue and accrue it to ETS participants.
    function _processAuctionRevenue(uint256 _tokenId, uint256 _amount) private {
        // Distribute proceeds to actors.
        IETSToken.Tag memory ctag = etsToken.getTagById(_tokenId);
        address platform = etsAccessControls.getPlatformAddress();

        uint256 relayerProceeds = (_amount * relayerPercentage) / MODULO;
        uint256 creatorProceeds = (_amount * creatorPercentage) / MODULO;
        uint256 platformProceeds = _amount - (relayerProceeds + creatorProceeds);

        accrued[ctag.relayer] = accrued[ctag.relayer] + relayerProceeds;
        accrued[ctag.creator] = accrued[ctag.creator] + creatorProceeds;
        accrued[platform] = accrued[platform] + platformProceeds;
    }

    function _getAuction(uint256 _tokenId) private view returns (Auction memory auction) {
        return auctions[_tokenId];
    }

    function _safeTransferETHWithFallback(address to, uint256 amount) internal {
        if (!_safeTransferETH(to, amount)) {
            IWMATIC(wmatic).deposit{ value: amount }();
            IERC20Upgradeable(wmatic).transfer(to, amount);
        }
    }

    function _safeTransferETH(address to, uint256 value) internal returns (bool) {
        (bool success, ) = to.call{ value: value, gas: 30_000 }(new bytes(0));
        return success;
    }

    function _isAuction(uint256 _tokenId) internal view returns (bool) {
        return (auctions[_tokenId].auctionId != 0);
    }

    // ============ PUBLIC VIEW FUNCTIONS ============

    function auctionExists(uint256 _tokenId) public view returns (bool) {
        return _isAuction(_tokenId);
    }

    function auctionEnded(uint256 _tokenId) public view returns (bool) {
        return (auctions[_tokenId].endTime > block.timestamp);
    }

    function auctionSettled(uint256 _tokenId) public view returns (bool) {
        return (_isAuction(_tokenId) && auctions[_tokenId].settled);
    }

    function getAuction(uint256 _tokenId) public view returns (Auction memory) {
        return auctions[_tokenId];
    }

    function getActiveCount() public view returns (uint256) {
        return activeAuctions.current();
    }

    function getTotalCount() public view returns (uint256) {
        return auctionId.current();
    }

    function getBalance() public view returns (uint) {
        return address(this).balance;
    }

    function totalDue(address _account) public view returns (uint256 _due) {
        return accrued[_account] - paid[_account];
    }

    /* solhint-disable */
    receive() external payable {}

    fallback() external payable {}
    /* solhint-enable */
}


# UUPSTesting.sol

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

import { ETSAccessControls } from "../ETSAccessControls.sol";
import { ETSEnrichTarget } from "../ETSEnrichTarget.sol";
import { ETSTarget } from "../ETSTarget.sol";
import { ETSToken } from "../ETSToken.sol";
import { ETS } from "../ETS.sol";
import { ETSAuctionHouse } from "../ETSAuctionHouse.sol";

contract ETSAccessControlsUpgrade is ETSAccessControls {
    // Extend existing contract with new function.
    function upgradeTest() public pure returns (bool) {
        return true;
    }
}

contract ETSEnrichTargetUpgrade is ETSEnrichTarget {
    // Extend existing contract with new function.
    function upgradeTest() public pure returns (bool) {
        return true;
    }
}

contract ETSTargetUpgrade is ETSTarget {
    // Extend existing contract with new function.
    function upgradeTest() public pure returns (bool) {
        return true;
    }
}

contract ETSTokenUpgrade is ETSToken {
    // Extend existing contract with new function.
    function upgradeTest() public pure returns (bool) {
        return true;
    }
}

contract ETSUpgrade is ETS {
    // Extend existing contract with new function.
    function upgradeTest() public pure returns (bool) {
        return true;
    }
}

contract ETSAuctionHouseUpgrade is ETSAuctionHouse {
    // Extend existing contract with new function.
    function upgradeTest() public pure returns (bool) {
        return true;
    }
}

Thanks again for looking.

Thanks for providing that information. The existence of the fallback function fallback() external payable {} is causing the upgrades plugin to behave incorrectly when it is looking for an UPGRADE_INTERFACE_VERSION selector to determine what version of OpenZeppelin Contracts the implementation is using. I've opened issue https://github.com/OpenZeppelin/openzeppelin-upgrades/issues/925 and we will address this in a patch release of the plugin.

Thanks @ericglau!

Curious to know what path you took to uncover that?

The plugin attempts to read the value of the string constant UPGRADE_INTERFACE_VERSION (using a selector with this signature) specifically to detect if implementations are using OpenZeppelin Contracts 5.0. However, you are using OpenZeppelin Contracts 4.9.2, and that version does not have this constant. Regardless, the plugin was able to make a call to that selector without reverting, and it was returning something other than a string. The only explanation was the existence of a fallback function, and this was confirmed by looking at your source code.

This is fixed as of @openzeppelin/hardhat-upgrades@2.4.2

Thanks @ericglau!
ᐧ

1 Like