library OpenSeaGasFreeListing {
    /**
    @notice Returns whether the operator is an OpenSea proxy for the owner, thus
    allowing it to list without the token owner paying gas.
    @dev ERC{721,1155}.isApprovedForAll should be overriden to also check if
    this function returns true.
     */
    function isApprovedForAll(address owner, address operator)
        internal
        view
        returns (bool)
    {
        address proxy = proxyFor(owner);
        return proxy != address(0) && proxy == operator;
    }

    /**
    @notice Returns the OpenSea proxy address for the owner.
     */
    function proxyFor(address owner) internal view returns (address) {
        address registry;
        uint256 chainId;

        assembly {
            chainId := chainid()
            switch chainId
            // Production networks are placed higher to minimise the number of
            // checks performed and therefore reduce gas. By the same rationale,
            // mainnet comes before Polygon as it's more expensive.
            case 1 {
                // mainnet
                registry := 0xa5409ec958c83c3f309868babaca7c86dcb077c1
            }
            case 137 {
                // polygon
                registry := 0x58807baD0B376efc12F5AD86aAc70E78ed67deaE
            }
            case 4 {
                // rinkeby
                registry := 0xf57b2c51ded3a29e6891aba85459d600256cf317
            }
            case 80001 {
                // mumbai
                registry := 0xff7Ca10aF37178BdD056628eF42fD7F799fAc77c
            }
            case 1337 {
                // The geth SimulatedBackend iff used with the ethier
                // openseatest package. This is mocked as a Wyvern proxy as it's
                // more complex than the 0x ones.
                registry := 0xE1a2bbc877b29ADBC56D2659DBcb0ae14ee62071
            }
        }

        // Unlike Wyvern, the registry itself is the proxy for all owners on 0x
        // chains.
        if (registry == address(0) || chainId == 137 || chainId == 80001) {
            return registry;
        }

        return address(ProxyRegistry(registry).proxies(owner));
    }
}
/// @notice Library to achieve gas-free listings on OpenSea.
function proxyFor(address owner) internal view returns (address) {
    address registry;
    uint256 chainId;

    assembly {
        chainId := chainid()
        switch chainId
        // Production networks are placed higher to minimise the number of
        // checks performed and therefore reduce gas. By the same rationale,
        // mainnet comes before Polygon as it's more expensive.
        case 1 {
            // mainnet
            registry := 0xa5409ec958c83c3f309868babaca7c86dcb077c1
        }
        case 137 {
            // polygon
            registry := 0x58807baD0B376efc12F5AD86aAc70E78ed67deaE
        }
        case 4 {
            // rinkeby
            registry := 0xf57b2c51ded3a29e6891aba85459d600256cf317
        }
        case 80001 {
            // mumbai
            registry := 0xff7Ca10aF37178BdD056628eF42fD7F799fAc77c
        }
        case 1337 {
            // The geth SimulatedBackend iff used with the ethier
            // openseatest package. This is mocked as a Wyvern proxy as it's
            // more complex than the 0x ones.
            registry := 0xE1a2bbc877b29ADBC56D2659DBcb0ae14ee62071
        }
    }

    // Unlike Wyvern, the registry itself is the proxy for all owners on 0x
    // chains.
    if (registry == address(0) || chainId == 137 || chainId == 80001) {
        return registry;
    }

    return address(ProxyRegistry(registry).proxies(owner));
}

/**
 @notice Returns the OpenSea proxy address for the owner.
 */