import { Wallet, ContractFactory, Contract } from 'zksync-ethers';
import { aI as fetchPublishedContractFromPolygon, aJ as fetchAndCacheDeployMetadata, a1 as extractConstructorParamsFromAbi, dF as getRoyaltyEngineV1ByChainId, aH as THIRDWEB_DEPLOYER, a_ as getChainProvider, Y as fetchContractMetadata } from '../../../dist/index-5a04fad8.browser.esm.js';
import { f as checkVerificationStatus, T as ThirdwebSDK, e as extractFunctionParamsFromAbi, t as convertParamValues } from '../../../dist/sdk-01baf2a7.browser.esm.js';
import { constants, utils, Contract as Contract$1 } from 'ethers';
import invariant from 'tiny-invariant';
import { parseEther } from 'ethers/lib/utils';
import { hashBytecode, create2Address } from 'zksync-ethers/build/utils';
import { f as fetchSourceFilesFromMetadata } from '../../../dist/fetchSourceFilesFromMetadata-906c835e.browser.esm.js';
import 'zod';
import '@thirdweb-dev/chains';
import '@thirdweb-dev/crypto';
import 'bn.js';
import 'bs58';
import '@thirdweb-dev/contracts-js/dist/abis/IBurnableERC20.json';
import '@thirdweb-dev/contracts-js/dist/abis/IDrop.json';
import '@thirdweb-dev/contracts-js/dist/abis/IDropERC20_V2.json';
import '@thirdweb-dev/contracts-js/dist/abis/IDropSinglePhase.json';
import '@thirdweb-dev/contracts-js/dist/abis/IDropSinglePhase_V1.json';
import '@thirdweb-dev/contracts-js/dist/abis/IERC20.json';
import '@thirdweb-dev/contracts-js/dist/abis/IERC20Permit.json';
import '@thirdweb-dev/contracts-js/dist/abis/IMintableERC20.json';
import '@thirdweb-dev/contracts-js/dist/abis/IMulticall.json';
import '@thirdweb-dev/contracts-js/dist/abis/ISignatureMintERC20.json';
import '@thirdweb-dev/contracts-js/dist/abis/IERC20Metadata.json';
import '@thirdweb-dev/contracts-js/dist/abis/IBurnableERC721.json';
import '@thirdweb-dev/contracts-js/dist/abis/IClaimableERC721.json';
import '@thirdweb-dev/contracts-js/dist/abis/IDelayedReveal.json';
import '@thirdweb-dev/contracts-js/dist/abis/IDropERC721_V3.json';
import '@thirdweb-dev/contracts-js/dist/abis/IERC721.json';
import '@thirdweb-dev/contracts-js/dist/abis/IERC721Enumerable.json';
import '@thirdweb-dev/contracts-js/dist/abis/IERC721AQueryableUpgradeable.json';
import '@thirdweb-dev/contracts-js/dist/abis/IERC721Supply.json';
import '@thirdweb-dev/contracts-js/dist/abis/ILazyMint.json';
import '@thirdweb-dev/contracts-js/dist/abis/IMintableERC721.json';
import '@thirdweb-dev/contracts-js/dist/abis/ISignatureMintERC721.json';
import '@thirdweb-dev/contracts-js/dist/abis/ISignatureMintERC721_V1.json';
import '@thirdweb-dev/contracts-js/dist/abis/LazyMintWithTier_V1.json';
import '@thirdweb-dev/contracts-js/dist/abis/SharedMetadata.json';
import '@thirdweb-dev/contracts-js/dist/abis/zora_IERC721Drop.json';
import '@thirdweb-dev/contracts-js/dist/abis/ILoyaltyCard.json';
import '@thirdweb-dev/contracts-js/dist/abis/INFTMetadata.json';
import '@thirdweb-dev/contracts-js/dist/abis/IERC721Metadata.json';
import '@thirdweb-dev/contracts-js/dist/abis/IBurnableERC1155.json';
import '@thirdweb-dev/contracts-js/dist/abis/IClaimableERC1155.json';
import '@thirdweb-dev/contracts-js/dist/abis/IDrop1155.json';
import '@thirdweb-dev/contracts-js/dist/abis/IDropERC1155_V2.json';
import '@thirdweb-dev/contracts-js/dist/abis/IDropSinglePhase1155.json';
import '@thirdweb-dev/contracts-js/dist/abis/IDropSinglePhase1155_V1.json';
import '@thirdweb-dev/contracts-js/dist/abis/IERC1155.json';
import '@thirdweb-dev/contracts-js/dist/abis/IERC1155Metadata.json';
import '@thirdweb-dev/contracts-js/dist/abis/IERC1155Supply.json';
import '@thirdweb-dev/contracts-js/dist/abis/IERC1155Enumerable.json';
import '@thirdweb-dev/contracts-js/dist/abis/IMintableERC1155.json';
import '@thirdweb-dev/contracts-js/dist/abis/ISignatureMintERC1155.json';
import '@thirdweb-dev/contracts-js/dist/abis/IERC2771Context.json';
import '@thirdweb-dev/contracts-js/dist/abis/IAppURI.json';
import '@thirdweb-dev/contracts-js/dist/abis/IContractMetadata.json';
import '@thirdweb-dev/contracts-js/dist/abis/IDirectListings.json';
import '@thirdweb-dev/contracts-js/dist/abis/IEnglishAuctions.json';
import '@thirdweb-dev/contracts-js/dist/abis/IOffers.json';
import '@thirdweb-dev/contracts-js/dist/abis/IPackVRFDirect.json';
import '@thirdweb-dev/contracts-js/dist/abis/IPermissions.json';
import '@thirdweb-dev/contracts-js/dist/abis/IPermissionsEnumerable.json';
import '@thirdweb-dev/contracts-js/dist/abis/IPlatformFee.json';
import '@thirdweb-dev/contracts-js/dist/abis/IPrimarySale.json';
import '@thirdweb-dev/contracts-js/dist/abis/IRoyalty.json';
import '@thirdweb-dev/contracts-js/dist/abis/Ownable.json';
import '@thirdweb-dev/contracts-js/dist/abis/IAirdropERC20.json';
import '@thirdweb-dev/contracts-js/dist/abis/IAirdropERC721.json';
import '@thirdweb-dev/contracts-js/dist/abis/IAirdropERC1155.json';
import '@thirdweb-dev/contracts-js/dist/abis/IAccountFactoryCore.json';
import '@thirdweb-dev/contracts-js/dist/abis/IAccountPermissions.json';
import '@thirdweb-dev/contracts-js/dist/abis/IAccountPermissions_V1.json';
import '@thirdweb-dev/contracts-js/dist/abis/IAccount.json';
import 'eventemitter3';
import '@thirdweb-dev/storage';
import '../../../dist/contract-publisher-2274d063.browser.esm.js';
import '@thirdweb-dev/contracts-js/dist/abis/ContractPublisher.json';
import '../../../dist/transactions-8e04157b.browser.esm.js';
import '@thirdweb-dev/contracts-js/dist/abis/TWMultichainRegistryLogic.json';
import '@thirdweb-dev/contracts-js/dist/abis/TWMultichainRegistryRouter.json';
import '../../../dist/fetchCurrencyValue-8077d135.browser.esm.js';
import '../../../dist/normalizePriceValue-fc556ba3.browser.esm.js';
import '@thirdweb-dev/generated-abis';
import '../../../dist/deployContractDeterministic-0d5f7f98.browser.esm.js';
import '@thirdweb-dev/contracts-js/dist/abis/TWFactory.json';

const twProxyArtifactZK = {
  _format: "hh-zksolc-artifact-1",
  contractName: "TWProxy",
  sourceName: "contracts/TWProxy.sol",
  abi: [{
    inputs: [{
      internalType: "address",
      name: "_logic",
      type: "address"
    }, {
      internalType: "bytes",
      name: "_data",
      type: "bytes"
    }],
    stateMutability: "payable",
    type: "constructor"
  }, {
    stateMutability: "payable",
    type: "fallback"
  }, {
    stateMutability: "payable",
    type: "receive"
  }],
  metadata: {
    optimizer_settings: "M3B3",
    solc_metadata: '{"compiler":{"version":"0.8.17+commit.8df45f5f"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"address","name":"_logic","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"}],"stateMutability":"payable","type":"constructor"},{"stateMutability":"payable","type":"fallback"},{"stateMutability":"payable","type":"receive"}],"devdoc":{"kind":"dev","methods":{},"stateVariables":{"_IMPLEMENTATION_SLOT":{"details":"Storage slot with the address of the current implementation. This is the keccak-256 hash of \\"eip1967.proxy.implementation\\" subtracted by 1, and is validated in the constructor."}},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"compilationTarget":{"contracts/TWProxy.sol":"TWProxy"},"evmVersion":"london","libraries":{},"metadata":{"bytecodeHash":"ipfs"},"optimizer":{"enabled":true,"runs":200},"remappings":[],"viaIR":true},"sources":{"@openzeppelin/contracts/proxy/Proxy.sol":{"keccak256":"0xc130fe33f1b2132158531a87734153293f6d07bc263ff4ac90e85da9c82c0e27","license":"MIT","urls":["bzz-raw://8831721b6f4cc26534d190f9f1631c3f59c9ff38efdd911f85e0882b8e360472","dweb:/ipfs/QmQZnLErZNStirSQ13ZNWQgvEYUtGE5tXYwn4QUPaVUfPN"]},"@openzeppelin/contracts/utils/Address.sol":{"keccak256":"0xd6153ce99bcdcce22b124f755e72553295be6abcd63804cfdffceb188b8bef10","license":"MIT","urls":["bzz-raw://35c47bece3c03caaa07fab37dd2bb3413bfbca20db7bd9895024390e0a469487","dweb:/ipfs/QmPGWT2x3QHcKxqe6gRmAkdakhbaRgx3DLzcakHz5M4eXG"]},"@openzeppelin/contracts/utils/StorageSlot.sol":{"keccak256":"0xd5c50c54bf02740ebd122ff06832546cb5fa84486d52695a9ccfd11666e0c81d","license":"MIT","urls":["bzz-raw://39e096c60a6eb1c6a257122d515496bd92d0c6a693a8f07acb6aa4b1263e95d4","dweb:/ipfs/QmPs5trJBacCiSkezP6tpevapuRYWNY6mqSFzsMCJj7e6B"]},"contracts/TWProxy.sol":{"keccak256":"0xdd8f7845b66468be6cd74a9d345983c2dbd7ad64eff7942158a3b795de19547f","license":"Apache-2.0","urls":["bzz-raw://1436d7c5b205474ba59a781ce8acadb202f59e27bdd73c0e90467416831dc075","dweb:/ipfs/Qmeh9ycc3pjwxARsreT8L1qp8FVWCA1wLawEPtBc53Ue9q"]}},"version":1}',
    zk_version: "1.3.9"
  },
  sources: {
    "contracts/TWProxy.sol": {
      content: '// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.11;\n\n/// @author thirdweb\n\n//   $$\\     $$\\       $$\\                 $$\\                         $$\\\n//   $$ |    $$ |      \\__|                $$ |                        $$ |\n// $$$$$$\\   $$$$$$$\\  $$\\  $$$$$$\\   $$$$$$$ |$$\\  $$\\  $$\\  $$$$$$\\  $$$$$$$\\\n// \\_$$  _|  $$  __$$\\ $$ |$$  __$$\\ $$  __$$ |$$ | $$ | $$ |$$  __$$\\ $$  __$$\\\n//   $$ |    $$ |  $$ |$$ |$$ |  \\__|$$ /  $$ |$$ | $$ | $$ |$$$$$$$$ |$$ |  $$ |\n//   $$ |$$\\ $$ |  $$ |$$ |$$ |      $$ |  $$ |$$ | $$ | $$ |$$   ____|$$ |  $$ |\n//   \\$$$$  |$$ |  $$ |$$ |$$ |      \\$$$$$$$ |\\$$$$$\\$$$$  |\\$$$$$$$\\ $$$$$$$  |\n//    \\____/ \\__|  \\__|\\__|\\__|       \\_______| \\_____\\____/  \\_______|\\_______/\n\nimport "@openzeppelin/contracts/proxy/Proxy.sol";\nimport "@openzeppelin/contracts/utils/Address.sol";\nimport "@openzeppelin/contracts/utils/StorageSlot.sol";\n\ncontract TWProxy is Proxy {\n    /**\n     * @dev Storage slot with the address of the current implementation.\n     * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is\n     * validated in the constructor.\n     */\n    bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n\n    constructor(address _logic, bytes memory _data) payable {\n        assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1));\n        StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = _logic;\n        if (_data.length > 0) {\n            // slither-disable-next-line unused-return\n            Address.functionDelegateCall(_logic, _data);\n        }\n    }\n\n    /**\n     * @dev Returns the current implementation address.\n     */\n    function _implementation() internal view override returns (address impl) {\n        return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n    }\n}\n'
    },
    "@openzeppelin/contracts/proxy/Proxy.sol": {
      content: "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM\n * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to\n * be specified by overriding the virtual {_implementation} function.\n *\n * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a\n * different contract through the {_delegate} function.\n *\n * The success and return data of the delegated call will be returned back to the caller of the proxy.\n */\nabstract contract Proxy {\n    /**\n     * @dev Delegates the current call to `implementation`.\n     *\n     * This function does not return to its internal call site, it will return directly to the external caller.\n     */\n    function _delegate(address implementation) internal virtual {\n        assembly {\n            // Copy msg.data. We take full control of memory in this inline assembly\n            // block because it will not return to Solidity code. We overwrite the\n            // Solidity scratch pad at memory position 0.\n            calldatacopy(0, 0, calldatasize())\n\n            // Call the implementation.\n            // out and outsize are 0 because we don't know the size yet.\n            let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\n\n            // Copy the returned data.\n            returndatacopy(0, 0, returndatasize())\n\n            switch result\n            // delegatecall returns 0 on error.\n            case 0 {\n                revert(0, returndatasize())\n            }\n            default {\n                return(0, returndatasize())\n            }\n        }\n    }\n\n    /**\n     * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function\n     * and {_fallback} should delegate.\n     */\n    function _implementation() internal view virtual returns (address);\n\n    /**\n     * @dev Delegates the current call to the address returned by `_implementation()`.\n     *\n     * This function does not return to its internal call site, it will return directly to the external caller.\n     */\n    function _fallback() internal virtual {\n        _beforeFallback();\n        _delegate(_implementation());\n    }\n\n    /**\n     * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other\n     * function in the contract matches the call data.\n     */\n    fallback() external payable virtual {\n        _fallback();\n    }\n\n    /**\n     * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data\n     * is empty.\n     */\n    receive() external payable virtual {\n        _fallback();\n    }\n\n    /**\n     * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`\n     * call, or as part of the Solidity `fallback` or `receive` functions.\n     *\n     * If overridden should call `super._beforeFallback()`.\n     */\n    function _beforeFallback() internal virtual {}\n}\n"
    },
    "@openzeppelin/contracts/utils/Address.sol": {
      content: '// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn\'t rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length > 0;\n    }\n\n    /**\n     * @dev Replacement for Solidity\'s `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance >= amount, "Address: insufficient balance");\n\n        (bool success, ) = recipient.call{value: amount}("");\n        require(success, "Address: unable to send value, recipient may have reverted");\n    }\n\n    /**\n     * @dev Performs a Solidity function call using a low level `call`. A\n     * plain `call` is an unsafe replacement for a function call: use this\n     * function instead.\n     *\n     * If `target` reverts with a revert reason, it is bubbled up by this\n     * function (like regular Solidity function calls).\n     *\n     * Returns the raw returned data. To convert to the expected return value,\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n     *\n     * Requirements:\n     *\n     * - `target` must be a contract.\n     * - calling `target` with `data` must not revert.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, "Address: low-level call failed");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but also transferring `value` wei to `target`.\n     *\n     * Requirements:\n     *\n     * - the calling contract must have an ETH balance of at least `value`.\n     * - the called Solidity function must be `payable`.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance >= value, "Address: insufficient balance for call");\n        require(isContract(target), "Address: call to non-contract");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, "Address: low-level static call failed");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), "Address: static call to non-contract");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, "Address: low-level delegate call failed");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), "Address: delegate call to non-contract");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn\'t, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length > 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n                /// @solidity memory-safe-assembly\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n'
    },
    "@openzeppelin/contracts/utils/StorageSlot.sol": {
      content: '// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for reading and writing primitive types to specific storage slots.\n *\n * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\n * This library helps with reading and writing to such slots without the need for inline assembly.\n *\n * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\n *\n * Example usage to set ERC1967 implementation slot:\n * ```\n * contract ERC1967 {\n *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n *\n *     function _getImplementation() internal view returns (address) {\n *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n *     }\n *\n *     function _setImplementation(address newImplementation) internal {\n *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");\n *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n *     }\n * }\n * ```\n *\n * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._\n */\nlibrary StorageSlot {\n    struct AddressSlot {\n        address value;\n    }\n\n    struct BooleanSlot {\n        bool value;\n    }\n\n    struct Bytes32Slot {\n        bytes32 value;\n    }\n\n    struct Uint256Slot {\n        uint256 value;\n    }\n\n    /**\n     * @dev Returns an `AddressSlot` with member `value` located at `slot`.\n     */\n    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.\n     */\n    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.\n     */\n    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.\n     */\n    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r.slot := slot\n        }\n    }\n}\n'
    }
  },
  bytecode: " ",
  linkReferences: {},
  deployedLinkReferences: {},
  factoryDeps: {}
};

/* eslint-disable no-useless-computed-key */
const AddressZero = "0x0000000000000000000000000000000000000000";

/**
 * @internal
 */
const CONTRACT_ADDRESSES = {
  [280]: {
    openzeppelinForwarder: AddressZero,
    openzeppelinForwarderEOA: AddressZero,
    biconomyForwarder: AddressZero
  },
  [324]: {
    openzeppelinForwarder: AddressZero,
    openzeppelinForwarderEOA: AddressZero,
    biconomyForwarder: AddressZero
  }
};

/**
 * @public
 */
const NATIVE_TOKEN_ADDRESS = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";

/**
 * @public
 */
const NATIVE_TOKENS = {
  // eslint-disable-next-line no-useless-computed-key
  [280]: {
    name: "zkSync Era Testnet",
    symbol: "ETH",
    decimals: 18,
    wrapped: {
      address: "0x20b28B1e4665FFf290650586ad76E977EAb90c5D",
      name: "Wrapped Ether",
      symbol: "WETH"
    }
  },
  [324]: {
    name: "zkSync Era Mainnet",
    symbol: "ETH",
    decimals: 18,
    wrapped: {
      address: "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91",
      name: "Wrapped Ether",
      symbol: "WETH"
    }
  }
};
const blockExplorerApiMap = {
  [324]: "https://block-explorer-api.mainnet.zksync.io/api",
  [280]: "https://block-explorer-api.testnets.zksync.dev/api",
  [300]: "https://block-explorer-api.sepolia.zksync.dev/api"
};
const IMPLEMENTATIONS = {
  // ZKSync Era Goerli Testnet (Deprecated)
  [280]: {
    DropERC721: "0xA8E28D98203848401A4f924358e6c337153D0f04",
    DropERC1155: "0xf3C7d3F0AA374a2D32489929e24D3e9313Aec8bb",
    DropERC20: "0x4027561E163a420c4e5Db46E07EBd581CAa8Bb62",
    SignatureDrop: "",
    Marketplace: "0xA77041a7A34A67D7285c8d3550110e441009436e",
    MarketplaceV3: "0x6026C3b81927f9f3bD943c32F8605C1774Df79f2",
    TokenERC721: "0xe04593be4c928769ACb157aab0214be1c4E7b6F6",
    TokenERC1155: "0x4e0C3577335961Ff800FFDA24981EB2F38D94483",
    TokenERC20: "0x0aecDe90BC11303871E6e4D7d83Ee84433BC115C",
    AirdropERC20: "0xcd3555c6058278E725A5b66d2D89aCc3b211768b",
    AirdropERC721: "0x3D9337181DC55fB1cD06D46b0738A8134295670d",
    AirdropERC1155: "0x8b0DBCf5b7D01eBB0F24525CE8AB72F16CE4F8C8"
  },
  // ZKSync Era Sepolia Testnet
  [300]: {
    DropERC721: "0x77121698E15e307D40eE1F1C6dF0ec7340F8eE71",
    DropERC1155: "0xFA0D78F98dEf58a4f458e3dCaa59D6778ea32c14",
    DropERC20: "0x6026C3b81927f9f3bD943c32F8605C1774Df79f2",
    SignatureDrop: "",
    Marketplace: "",
    MarketplaceV3: "0x58e0F289C7dD2025eBd0696d913ECC0fdc1CC8bc",
    TokenERC721: "0xA2bD9922fE19E441FF799D76B89Fa8495B60CcB3",
    TokenERC1155: "0x99E6dc722AeF030A4F8DCa5d8387b07E66A3991B",
    TokenERC20: "0xfCA4441848067f8dB83902Da0f177989ecc6328f",
    AirdropERC20: "0x4b14569c7B79DBe686Ac3Ba5996131E7EDaB7a93",
    AirdropERC721: "0xDD3E3BBa3bb4edcbbEa9d52Cd1E49289Ef3DfDE3",
    AirdropERC1155: "0x8A4E9034BC6ac77E1408AC878e0603A32B5d4b73",
    NFTStake: "0x62A032fd158EBC4044F6B4D3F42a0e5EE427803e",
    TokenStake: "0x364d188b53d5A37732f5e79C33270CAAF8Bf39D0",
    EditionStake: "0x81ED186CEBcC9428C6cB4859B9827636ff2e053F",
    VoteERC20: "0x2cf6e5ba0746Eb48B5066947E8C56982D8E4121E",
    Split: "0x13f25360dd3f9096c3e2cBe60b95c45b11ADB7E4",
    OpenEditionERC721: "0xA405a38A75194a8ea88bE695Aa8bdc74E905a903",
    Airdrop: "0x838Dbc16A6bc7B5B6f86B7f4818f6c4d41F31f91",
    Pack: "0x9Fdf34f552cdA8E2B0cD64e2EddcB732a5Ff8455",
    LoyaltyCard: "0xD5B1435b359c88FF69979166Cb6EC268Be79C6F7",
    Multiwrap: "0x5a2524Ca4E4f86a34382C5be871F34f50F014d84"
  },
  // ZKSync Era Mainnet
  [324]: {
    DropERC721: "0x9F92368dD2AbCD1f8067Ea7094f78CCe70bBa944",
    DropERC1155: "0xdb73302820d610c26242c9fbD0fCFA5C5acE3866",
    DropERC20: "0x5FC7d4642b37DfCe89A416775d36E023593c7dD5",
    SignatureDrop: "",
    Marketplace: "",
    MarketplaceV3: "0xBc02441a36Bb4029Cd191b20243c2e41B862F118",
    MarketplaceV3_aux: "0x5a2524Ca4E4f86a34382C5be871F34f50F014d84",
    TokenERC721: "0xAE6146cE093FfEED659a8d5f9904b18B770f5215",
    TokenERC1155: "0xdD60A8002086210e21FC4F7E73Ff0260D0252085",
    TokenERC20: "0x64c4aC19F2173E7c0B6eB922CF05DC410Feb2176",
    AirdropERC20: "0xDD3E3BBa3bb4edcbbEa9d52Cd1E49289Ef3DfDE3",
    AirdropERC721: "0x8A4E9034BC6ac77E1408AC878e0603A32B5d4b73",
    AirdropERC1155: "0xcd3555c6058278E725A5b66d2D89aCc3b211768b",
    NFTStake: "0x534548302852C9A311b8E74d05f71478a08D5107",
    TokenStake: "0x73DC91aD22F8d8c1048d9E8da1C055B9Bcc7E0ab",
    EditionStake: "0xfd8355dB4e86d36Bd06B7d0691C5d440E52F8885",
    VoteERC20: "0xff0AAe2734625AeF5C006235cb9Ce89aa389B5d2",
    Split: "0x22c0232257Be71224e668BA7B818395d1d33248F",
    OpenEditionERC721: "0x282eC3fD1F2650a5CC65300E1aC26A32013e7a81",
    Airdrop: "0xf74326EC19A0fEd89EE3A2232C7Cc5Fa7E3D8083",
    Pack: "0x9636a57A7A250C1EB93DfF8Ff21CB424Dec54e88",
    LoyaltyCard: "0x30995E43c78b92fd4F478A908b30b1e18926f4CE",
    Multiwrap: "0xffa87d4e9bEb7318199Dada520E9AC3bf897a3d7"
  }
};

/**
 * @internal
 * @param chainId - chain id
 * @param contractType - contract type
 */
function getImplementation(chainId, contractName, version) {
  if (chainId in IMPLEMENTATIONS) {
    const approvedImpls = IMPLEMENTATIONS[chainId];
    if (contractName in approvedImpls) {
      if (contractName === "MarketplaceV3" && version === "1.1.2" && chainId === 324) {
        return approvedImpls["MarketplaceV3_aux"];
      }
      return approvedImpls[contractName];
    }
  }
  return null;
}

/**
 *
 * @param chainId - chain id
 * @returns The array of trusted forwarders for the given chain id
 * @internal
 */
/* eslint-disable @typescript-eslint/no-unused-vars */
function zkGetDefaultTrustedForwarders(chainId, contractName) {
  //  Since ZkSync has gas sponsoring through native Account Abstraction,
  //  it doesn’t need a forwarder
  return [];
}

/**
 * Returns the native token for a given chain
 * @param chainId - the chain id
 * @public
 */
function getZkNativeTokenByChainId(chainId) {
  return NATIVE_TOKENS[chainId] || {
    name: "Ether",
    symbol: "ETH",
    decimals: 18,
    wrapped: {
      address: constants.AddressZero,
      name: "Wrapped Ether",
      symbol: "WETH"
    }
  };
}

/**
 * Check if a contract exists at the given address
 *
 * @internal
 * @param address - The address to check
 * @param provider - The provider to use
 */
async function isZkContractDeployed(address, provider) {
  const code = await provider.getCode(address);
  return code !== "0x" && code !== "0x0";
}

const SINGLETON_FACTORY = "0xa51baf6a9c0ef5Db8C1898d5aDD92Bf3227d6088";
const KNOWN_CODES_STORAGE = "0x0000000000000000000000000000000000008004";
const PUBLISHED_PRIVATE_KEY = "";
const getMarkerAbi = ["function getMarker(bytes32) public view returns (uint256)"];
const singletonDeployAbi = ["function deploy(bytes32,bytes32,bytes) external payable"];

const zkSingletonFactoryArtifact = {
  abi: ["function deploy(bytes32,bytes32,bytes) external payable"],
  bytecode: " "
};

/**
 * Deploy ZkSyncSingletonFactory
 * Ref: https://explorer.zksync.io/address/0xa51baf6a9c0ef5Db8C1898d5aDD92Bf3227d6088
 *
 * @public
 * @param signer - The signer to use
 */
async function zkDeployCreate2Factory(signer) {
  invariant(signer.provider, "No provider");
  const singletonFactoryExists = await isZkContractDeployed(SINGLETON_FACTORY, signer.provider);
  if (singletonFactoryExists) {
    return SINGLETON_FACTORY;
  }

  // send balance to the create2 signer
  const valueToSend = parseEther("0.01");
  const create2Signer = new Wallet(PUBLISHED_PRIVATE_KEY, signer.provider);
  if ((await create2Signer.getBalance()).lt(valueToSend)) {
    await signer.transfer({
      to: create2Signer.address,
      amount: valueToSend
    });
  }
  const create2FactoryDeploy = new ContractFactory(zkSingletonFactoryArtifact.abi, zkSingletonFactoryArtifact.bytecode, create2Signer, "create");
  const create2Factory = await create2FactoryDeploy.deploy();
  await create2Factory.deployed();
  return create2Factory.address;
}

// import type { DeploymentPreset } from "../../types/any-evm/deploy-data";

const caches = {
  deploymentPresets: {}
};

/**
 * Pre-compute a contract's deployment address for a CREATE2 deployment.
 *
 * @public
 * @param bytecode - Creation bytecode of the contract to deploy
 * @param encodedArgs - Abi-encoded constructor params
 * @param create2FactoryAddress - The create2 factory address to use
 */
function zkComputeDeploymentAddress(bytecode, encodedArgs, create2FactoryAddress, salt) {
  const bytecodePrefixed = bytecode.startsWith("0x") ? bytecode : `0x${bytecode}`;
  const saltHash = salt ? utils.id(salt) : utils.id("thirdweb");
  const bytecodeHash = utils.hexlify(hashBytecode(bytecodePrefixed));
  const addr = create2Address(create2FactoryAddress, bytecodeHash, saltHash, encodedArgs);
  return addr;
}

async function zkComputeDeploymentInfo(contractType, provider, storage, create2Factory, contractOptions, clientId, secretKey) {
  const contractName = contractOptions && contractOptions.contractName;
  const version = contractOptions && contractOptions.version;
  let publisherAddress = contractOptions && contractOptions.publisherAddress;
  let metadata = contractOptions && contractOptions.metadata;
  invariant(contractName || metadata, "Require contract name or metadata");
  if (contractName && caches.deploymentPresets[contractName]) {
    return caches.deploymentPresets[contractName];
  }
  if (!metadata) {
    invariant(contractName, "Require contract name");
    if (!publisherAddress) {
      publisherAddress = THIRDWEB_DEPLOYER;
    }
    const publishedContract = await fetchPublishedContractFromPolygon(publisherAddress, contractName, version, storage, clientId, secretKey);
    metadata = (await fetchAndCacheDeployMetadata(publishedContract.metadataUri, storage, {
      compilerType: "zksolc"
    })).compilerMetadata;
  }
  const args = await encodeConstructorParamsForImplementation(metadata, provider, contractOptions?.constructorParams);
  const address = zkComputeDeploymentAddress(metadata.bytecode, args.encodedArgs, create2Factory);
  const contractDeployed = await isZkContractDeployed(address, provider);
  let constructorCalldata;
  let bytecodeHash;
  let bytecodePrefixed;
  if (!contractDeployed) {
    bytecodePrefixed = metadata.bytecode.startsWith("0x") ? metadata.bytecode : `0x${metadata.bytecode}`;
    bytecodeHash = utils.hexlify(hashBytecode(bytecodePrefixed));
    constructorCalldata = utils.arrayify(args.encodedArgs);
  }
  return {
    name: contractName,
    type: contractType,
    transaction: {
      predictedAddress: address,
      to: create2Factory,
      constructorCalldata: constructorCalldata,
      bytecode: bytecodePrefixed,
      bytecodeHash: bytecodeHash,
      abi: metadata.abi,
      params: args.params
    }
  };
}

/**
 * @internal
 *
 * Determine constructor params required by an implementation contract.
 * Return abi-encoded params.
 */
async function encodeConstructorParamsForImplementation(compilerMetadata, provider, constructorParamMap) {
  const constructorParams = extractConstructorParamsFromAbi(compilerMetadata.abi);
  const constructorParamTypes = constructorParams.map(p => {
    if (p.type === "tuple[]" || p.type === "tuple") {
      return utils.ParamType.from(p);
    } else {
      return p.type;
    }
  });
  const constructorParamValues = await Promise.all(constructorParams.map(async p => {
    if (constructorParamMap && constructorParamMap[p.name]) {
      if (constructorParamMap[p.name].type) {
        invariant(constructorParamMap[p.name].type === p.type, `Provided type ${constructorParamMap[p.name].type} doesn't match the actual type ${p.type} from Abi`);
      }
      return constructorParamMap[p.name].value;
    }
    if (p.name && p.name.includes("nativeTokenWrapper")) {
      const chainId = (await provider.getNetwork()).chainId;
      const nativeTokenWrapperAddress = getZkNativeTokenByChainId(chainId).wrapped.address;
      return nativeTokenWrapperAddress;
    } else if (p.name && p.name.includes("royaltyEngineAddress")) {
      const chainId = (await provider.getNetwork()).chainId;
      return getRoyaltyEngineV1ByChainId(chainId);
    } else if (p.name && p.name.includes("marketplaceV3Params")) {
      const chainId = (await provider.getNetwork()).chainId;
      const royaltyEngineAddress = getRoyaltyEngineV1ByChainId(chainId);
      const nativeTokenWrapper = getZkNativeTokenByChainId(chainId).wrapped.address;
      const extensions = constructorParamMap ? constructorParamMap["_extensions"].value : [];
      return {
        extensions: extensions,
        royaltyEngineAddress: royaltyEngineAddress,
        nativeTokenWrapper: nativeTokenWrapper
      };
    } else {
      throw new Error("Can't resolve constructor arguments");
    }
  }));
  const encodedArgs = utils.defaultAbiCoder.encode(constructorParamTypes, constructorParamValues);
  return {
    encodedArgs,
    params: constructorParamValues
  };
}

/**
 *
 * Returns txn data for keyless deploys as well as signer deploys.
 * Also provides a list of infra contracts to deploy.
 *
 * @internal
 *
 * @param metadataUri - The metadata uri to use
 * @param storage - The storage to use
 * @param provider - The provider to use
 * @param create2Factory - The create2 factory to use
 */
async function getZkDeploymentInfo(deployMetadata, storage, provider, create2Factory, clientId, secretKey) {
  caches.deploymentPresets = {};
  const create2FactoryAddress = create2Factory ? create2Factory : SINGLETON_FACTORY;
  const compilerMetadata = deployMetadata.compilerMetadata;
  const customParams = {};
  const finalDeploymentInfo = [];
  const implementationDeployInfo = await zkComputeDeploymentInfo("implementation", provider, storage, create2FactoryAddress, {
    metadata: compilerMetadata,
    constructorParams: customParams
  }, clientId, secretKey);
  finalDeploymentInfo.push(...Object.values(caches.deploymentPresets));
  finalDeploymentInfo.push(implementationDeployInfo);
  return finalDeploymentInfo;
}

const RequestStatus = {
  OK: "1",
  NOTOK: "0"
};

//
// ==================================
// ======== Core Functions ==========
// ==================================
//

async function zkVerify(contractAddress, chainId, explorerAPIUrl, explorerAPIKey, storage, metadataUri, zkVersion, encodedConstructorArgs) {
  try {
    const provider = getChainProvider(chainId, {});
    const contractBytecode = await provider.getCode(contractAddress);
    let compilerMetadata = {};
    if (contractBytecode === twProxyArtifactZK.bytecode) {
      compilerMetadata = {
        name: twProxyArtifactZK.contractName,
        abi: twProxyArtifactZK.abi,
        metadata: JSON.parse(twProxyArtifactZK.metadata.solc_metadata),
        zk_version: twProxyArtifactZK.metadata.zk_version
      };
      compilerMetadata.metadata.sources = twProxyArtifactZK.sources;
    } else {
      if (!metadataUri || metadataUri.length === 0) {
        metadataUri = await fetchFromMultiChainRegistry(contractAddress, chainId);
      }
      invariant(metadataUri && metadataUri.length > 0, "No contract URI found");
      const parsedMetadata = await fetchContractMetadata(metadataUri, storage);
      const zk_version = parsedMetadata.metadata.settings.zkVersion || zkVersion;
      if (!zk_version) {
        console.error("zk version not found");
      }
      compilerMetadata = {
        name: parsedMetadata.name,
        abi: parsedMetadata.abi,
        metadata: parsedMetadata.metadata,
        zk_version
      };
    }
    const compilerVersion = compilerMetadata.metadata.compiler.version;
    const sources = await fetchSourceFilesFromMetadata(compilerMetadata, storage);
    const sourcesWithUrl = compilerMetadata.metadata.sources;
    const sourcesWithContents = {};
    for (const path of Object.keys(sourcesWithUrl)) {
      const sourceCode = sources.find(source => path === source.filename);
      if (!sourceCode) {
        throw new Error(`Could not find source file for ${path}`);
      }
      sourcesWithContents[path] = {
        content: sourceCode.source
      };
    }
    const compilerInput = {
      language: "Solidity",
      settings: compilerMetadata.metadata.settings.optimizer,
      sources: sourcesWithContents
    };
    const compilationTarget = compilerMetadata.metadata.settings.compilationTarget;
    const targets = Object.keys(compilationTarget);
    const contractPath = targets[0];
    const encodedArgs = encodedConstructorArgs ? encodedConstructorArgs : await zkFetchConstructorParams(explorerAPIUrl, explorerAPIKey, contractAddress, compilerMetadata.abi, provider);
    const requestBody = {
      module: "contract",
      action: "verifysourcecode",
      contractaddress: contractAddress,
      sourceCode: compilerInput,
      codeformat: "solidity-standard-json-input",
      contractname: `${contractPath}:${compilerMetadata.name}`,
      compilerversion: `${compilerVersion.split("+")[0]}`,
      zkCompilerVersion: `v${compilerMetadata.zk_version}`,
      runs: compilerMetadata.metadata.settings.optimizer.runs,
      optimizationUsed: compilerMetadata.metadata.settings.optimizer.enabled ? "1" : "0",
      constructorArguements: encodedArgs
    };
    const result = await fetch(`${explorerAPIUrl}`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json"
      },
      body: JSON.stringify(requestBody)
    });
    const data = await result.json();
    if (data.status === RequestStatus.OK) {
      console.info("Checking verification status...");
      const verificationStatus = await checkVerificationStatus(explorerAPIUrl, explorerAPIKey, data.result);
      console.info(verificationStatus);
    } else {
      throw new Error(`${data.result}`);
    }
  } catch (e) {
    throw new Error(e.toString());
  }
}

//
// ==================================
// ======== Helper Functions ========
// ==================================
//

async function zkFetchConstructorParams(explorerAPIUrl, explorerAPIKey, contractAddress, abi, provider) {
  const constructorParamTypes = extractConstructorParamsFromAbi(abi);
  if (constructorParamTypes.length === 0) {
    return "0x";
  }
  const result = await fetch(`${explorerAPIUrl}?module=contract&action=getcontractcreation&contractaddresses=${contractAddress}&apikey=${explorerAPIKey}`);
  const creationTx = await result.json();
  if (creationTx && creationTx.status === RequestStatus.OK && creationTx.result[0] !== undefined) {
    const txHash = creationTx.result[0].txHash;
    const transaction = await provider.getTransaction(txHash);
    if (transaction.to === "0x0000000000000000000000000000000000008006") {
      const decoded = utils.defaultAbiCoder.decode(["bytes32", "bytes32", "bytes"], utils.hexDataSlice(transaction.data, 4));
      return decoded[2].startsWith("0x") ? decoded[2] : `0x${decoded[2]}`;
    } else {
      // TODO: decode for create2 deployments via factory
      return "0x";
    }
  } else {
    // Could not retrieve constructor parameters, using empty parameters as fallback
    return "0x";
  }
}
async function fetchFromMultiChainRegistry(address, chainId) {
  try {
    // random wallet is fine here, we're doing gasless calls
    const sdk = new ThirdwebSDK("polygon");
    const uri = await sdk.multiChainRegistry.getContractMetadataURI(chainId, address);
    return uri;
  } catch (e) {}
}

/**
 * Deploy a contract at a deterministic address, using Create2 method
 * Address depends on the Create2 factory address.
 *
 * @public
 *
 * @param signer - The signer to use
 * @param bytecode - The bytecode to deploy
 * @param encodedArgs - The encoded constructor args to use
 * @param create2FactoryAddress - The create2 factory address to use
 */
async function zkDeployContractDeterministic(signer, transaction, storage, metadataUri, options) {
  let gasLimit = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 5_000_000;
  // Check if the implementation contract is already deployed
  invariant(signer.provider, "Provider required");
  const contractDeployed = await isZkContractDeployed(transaction.predictedAddress, signer.provider);
  if (!contractDeployed) {
    // check if bytecodehash is known
    const kcs = new Contract(KNOWN_CODES_STORAGE, getMarkerAbi, signer);
    const marker = await kcs.getMarker(transaction.bytecodeHash);
    const parsedMarker = marker.toString();

    // if not known, deploy once directly (create, not create2)
    if (parsedMarker !== "1") {
      try {
        const implFactory = new ContractFactory(transaction.abi, transaction.bytecode, signer, "create");
        console.debug(`Bytecodehash not known. Deploying contract directly.`);
        const impl = await implFactory.deploy(...transaction.params);
        await impl.deployed();
      } catch (e) {
        throw new Error("Error deploying directly.");
      }
    }

    // deploy again with create2
    console.debug(`deploying contract via create2 factory at: ${transaction.predictedAddress}`);
    const singleton = new Contract(transaction.to || "0xa51baf6a9c0ef5Db8C1898d5aDD92Bf3227d6088", singletonDeployAbi, signer);
    const salt = options?.saltForProxyDeploy ? utils.id(options.saltForProxyDeploy) : utils.id("thirdweb");
    options?.notifier?.("deploying", "preset");
    try {
      const deployTx = await singleton.deploy(salt, transaction.bytecodeHash, transaction.constructorCalldata);
      await deployTx.wait();
      options?.notifier?.("deployed", "preset");
    } catch (e) {
      if (e.toString().includes(`method="estimateGas"`)) {
        const deployTx = await singleton.deploy(salt, transaction.bytecodeHash, transaction.constructorCalldata, {
          gasLimit
        });
        await deployTx.wait();
        options?.notifier?.("deployed", "preset");
      } else {
        console.debug("error estimating gas while deploying prebuilt: ", e);
      }
    }

    // register on multichain registry, and verify -- no await
    if (metadataUri && storage) {
      const chainId = await signer.getChainId();
      try {
        registerContractOnMultiChainRegistry(transaction.predictedAddress, chainId, metadataUri);
      } catch (error) {}
      try {
        zkVerify(transaction.predictedAddress, chainId, blockExplorerApiMap[chainId], "", storage, metadataUri);
      } catch (error) {}
    }
  }
}
async function registerContractOnMultiChainRegistry(address, chainId, metadataURI) {
  try {
    // random wallet is fine here, we're doing gasless calls
    const wallet = Wallet.createRandom();
    const sdk = ThirdwebSDK.fromPrivateKey(wallet.privateKey, "polygon", {
      gasless: {
        openzeppelin: {
          relayerUrl: "https://api.defender.openzeppelin.com/autotasks/dad61716-3624-46c9-874f-0e73f15f04d5/runs/webhook/7d6a1834-dd33-4b7b-8af4-b6b4719a0b97/FdHMqyF3p6MGHw6K2nkLsv",
          relayerForwarderAddress: "0x409d530a6961297ece29121dbee2c917c3398659"
        },
        experimentalChainlessSupport: true
      }
    });
    const existingMeta = await sdk.multiChainRegistry.getContractMetadataURI(chainId, address);
    if (existingMeta && existingMeta !== "") {
      return true;
    }
    // add to multichain registry with metadata uri unlocks the contract on SDK/dashboard for everyone
    await sdk.multiChainRegistry.addContract({
      address,
      chainId,
      metadataURI
    });
    return true;
  } catch (e) {
    console.debug("Error registering contract on multi chain registry", e);
    return false;
  }
}

/**
 * Deploy a proxy contract of a given implementation via thirdweb's Clone factory
 * @param publishMetadataUri - the uri of the publish metadata
 * @param constructorParamValues - the constructor param values
 * @param deployMetadata - the deploy metadata
 * @param signer - the signer to use
 * @param options - the deploy options
 */
async function zkDeployViaAutoFactory(deployMetadata, signer, storage, options, clientId, secretKey) {
  // any evm deployment flow

  // 1. Deploy CREATE2 factory (if not already exists)
  const create2Factory = await zkDeployCreate2Factory(signer);

  // 2. get deployment info for any evm
  const deploymentInfo = await getZkDeploymentInfo(deployMetadata, storage, signer.provider, create2Factory, clientId, secretKey);
  const implementationAddress = deploymentInfo.find(i => i.type === "implementation")?.transaction.predictedAddress;

  // filter out already deployed contracts (data is empty)
  const transactionsToSend = deploymentInfo.filter(i => i.transaction.bytecodeHash && i.transaction.bytecodeHash.length > 0);
  const transactionsforDirectDeploy = transactionsToSend.map(i => i.transaction);

  // send each transaction directly to Create2 factory
  // process txns one at a time
  for (const tx of transactionsforDirectDeploy) {
    try {
      await zkDeployContractDeterministic(signer, tx, storage, deployMetadata.compilerMetadata.fetchedMetadataUri, options);
    } catch (e) {
      console.debug(`Error deploying contract at ${tx.predictedAddress}`, e?.message);
    }
  }
  return implementationAddress;
}
async function zkDeployContractFromUri(publishMetadataUri, constructorParamValues, signer, storage, chainId, options, directDeployDeterministic, clientId, secretKey) {
  const {
    compilerMetadata,
    extendedMetadata
  } = await fetchAndCacheDeployMetadata(publishMetadataUri, storage, options?.compilerOptions);
  let deterministicDeployment = false;
  if (options?.compilerOptions && extendedMetadata?.compilers) {
    if (options.compilerOptions.compilerType !== "zksolc") {
      throw Error("Invalid compiler type");
    }
    deterministicDeployment = true;
  }
  const forceDirectDeploy = options?.forceDirectDeploy || false;
  const isNetworkEnabled = extendedMetadata?.networksForDeployment?.networksEnabled.includes(chainId) || extendedMetadata?.networksForDeployment?.allNetworks;
  if (extendedMetadata?.networksForDeployment && !isNetworkEnabled) {
    throw new Error(`Deployments disabled on this network, with chainId: ${chainId}`);
  }
  let deployedAddress;
  if (extendedMetadata && extendedMetadata.factoryDeploymentData && !forceDirectDeploy && (!extendedMetadata.deployType || extendedMetadata.deployType !== "standard")) {
    if (extendedMetadata.isDeployableViaProxy || extendedMetadata.isDeployableViaFactory || extendedMetadata.deployType === "autoFactory") {
      let implementationAddress;
      if (deterministicDeployment) {
        invariant(extendedMetadata.factoryDeploymentData.implementationInitializerFunction, `implementationInitializerFunction not set'`);
        try {
          implementationAddress = await zkDeployViaAutoFactory({
            compilerMetadata,
            extendedMetadata
          }, signer, storage, options, clientId, secretKey);
        } catch (e) {}
      }
      if (!implementationAddress) {
        implementationAddress = getImplementation(chainId, compilerMetadata.name, extendedMetadata.version);
      }
      if (!implementationAddress) {
        throw new Error("Contract not supported yet.");
      }
      const initializerParamTypes = extractFunctionParamsFromAbi(compilerMetadata.abi, extendedMetadata.factoryDeploymentData.implementationInitializerFunction).map(p => p.type);
      const paramValues = convertParamValues(initializerParamTypes, constructorParamValues);
      const encodedInitializer = Contract$1.getInterface(compilerMetadata.abi).encodeFunctionData(extendedMetadata.factoryDeploymentData.implementationInitializerFunction, paramValues);
      const proxyFactory = new ContractFactory(twProxyArtifactZK.abi, twProxyArtifactZK.bytecode, signer, "create");
      const proxy = await proxyFactory.deploy(implementationAddress, encodedInitializer);
      await proxy.deployed();

      // register on multichain registry
      await registerContractOnMultiChainRegistry(proxy.address, chainId, compilerMetadata.fetchedMetadataUri);
      deployedAddress = proxy.address;
    } else {
      throw new Error("Invalid deploy type");
    }
  } else {
    // throw new Error("Contract not supported yet.");
    const bytecode = compilerMetadata.bytecode.startsWith("0x") ? compilerMetadata.bytecode : `0x${compilerMetadata.bytecode}`;
    if (!utils.isHexString(bytecode)) {
      throw new Error(`Contract bytecode is invalid.\n\n${bytecode}`);
    }
    const constructorParamTypes = extractConstructorParamsFromAbi(compilerMetadata.abi).map(p => p.type);
    const paramValues = convertParamValues(constructorParamTypes, constructorParamValues);
    if (directDeployDeterministic && !deterministicDeployment) {
      throw new Error("Deterministic deployment not supported for this contract.");
    } else if (directDeployDeterministic && deterministicDeployment) {
      const create2Factory = await zkDeployCreate2Factory(signer);
      const encodedArgs = utils.defaultAbiCoder.encode(constructorParamTypes, constructorParamValues);
      deployedAddress = zkComputeDeploymentAddress(bytecode, encodedArgs, create2Factory, options?.saltForProxyDeploy);
      if (await isZkContractDeployed(deployedAddress, signer.provider)) {
        throw new Error("Contract already deployed.");
      }
      const tx = {
        predictedAddress: deployedAddress,
        to: create2Factory,
        constructorCalldata: utils.arrayify(encodedArgs),
        bytecode,
        bytecodeHash: utils.hexlify(hashBytecode(bytecode)),
        abi: compilerMetadata.abi,
        params: paramValues
      };
      try {
        await zkDeployContractDeterministic(signer, tx, storage, compilerMetadata.fetchedMetadataUri, options);
      } catch (e) {
        console.debug(`Error deploying contract at ${tx.predictedAddress}`, e?.message);
      }
    } else {
      const factory = new ContractFactory(compilerMetadata.abi, compilerMetadata.bytecode, signer, "create");
      const contract = await factory.deploy(...paramValues);
      deployedAddress = contract.address;
    }
    if (deployedAddress) {
      // register on multichain registry
      await registerContractOnMultiChainRegistry(deployedAddress, chainId, compilerMetadata.fetchedMetadataUri);
    }
  }

  // fire-and-forget verification, don't await
  try {
    zkVerify(deployedAddress, chainId, blockExplorerApiMap[chainId], "", storage, compilerMetadata.fetchedMetadataUri);
  } catch (error) {
    // ignore error
  }
  return deployedAddress;
}
async function getZkTransactionsForDeploy() {
  const transactions = [];
  transactions.push({
    contractType: "proxy",
    addresses: []
  });
  return transactions;
}

export { CONTRACT_ADDRESSES, IMPLEMENTATIONS, NATIVE_TOKENS, NATIVE_TOKEN_ADDRESS, blockExplorerApiMap, getImplementation, getZkNativeTokenByChainId, getZkTransactionsForDeploy, zkDeployContractFromUri, zkGetDefaultTrustedForwarders, zkVerify };
