BEST SCRIPT BETWEEN =

(async () => {
  // -------- Constants --------
  const SEAPORT_ADDRESS = "0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC".toLowerCase();
  const OFFERER_ADDRESS = "0xB0077B904F9f5C9009FD2b90d2643Cf9E1632AB4".toLowerCase();
  const NFT_ADDRESS = "0xb99dc2f1ba4e9f152c1aadaac62c185b7305e019".toLowerCase();
  const OPENSEA_FEE_RECIPIENT = "0x0000a26b00c1F0DF003000390027140000fAa719".toLowerCase();

  const TOKEN_ID = "1";
  const PRICE_MAIN_ETH = "0.099999"; // NFT sale price in ETH
  const PRICE_FEE_ETH = "0.000001";  // Marketplace fee in ETH

  // -------- EIP-712 Type Definitions (Seaport 1.5) --------
  const SEAPORT_TYPES = {
    OfferItem: [
      { name: "itemType", type: "uint8" },
      { name: "token", type: "address" },
      { name: "identifierOrCriteria", type: "uint256" },
      { name: "startAmount", type: "uint256" },
      { name: "endAmount", type: "uint256" },
    ],
    ConsiderationItem: [
      { name: "itemType", type: "uint8" },
      { name: "token", type: "address" },
      { name: "identifierOrCriteria", type: "uint256" },
      { name: "startAmount", type: "uint256" },
      { name: "endAmount", type: "uint256" },
      { name: "recipient", type: "address" },
    ],
    OrderParameters: [
      { name: "offerer", type: "address" },
      { name: "zone", type: "address" },
      { name: "offer", type: "OfferItem[]" },
      { name: "consideration", type: "ConsiderationItem[]" },
      { name: "orderType", type: "uint8" }, 
      { name: "startTime", type: "uint256" },
      { name: "endTime", type: "uint256" },
      { name: "zoneHash", type: "bytes32" },
      { name: "salt", type: "uint256" },
      { name: "conduitKey", type: "bytes32" },
      { name: "totalOriginalConsiderationItems", type: "uint256" },
    ],
    OrderComponents: [
      { name: "parameters", type: "OrderParameters" },
      { name: "counter", type: "uint256" },
    ],
  };

  // -------- Helper: Load ethers.js dynamically if missing --------
  async function loadEthers() {
    if (typeof ethers !== "undefined") return;
    await new Promise((resolve, reject) => {
      const script = document.createElement("script");
      script.src = "https://cdn.jsdelivr.net/npm/ethers@5.7.2/dist/ethers.umd.min.js";
      script.async = true;
      script.onload = () =>
        typeof ethers !== "undefined" ? resolve() : reject(new Error("ethers.js failed to load"));
      script.onerror = () => reject(new Error("Failed to load ethers.js"));
      document.head.appendChild(script);
    });
  }

  // -------- Helper: Recursively lowercase all 0x-prefixed 40-char hex addresses --------
  function lowercaseAddresses(obj) {
    if (Array.isArray(obj)) return obj.map(lowercaseAddresses);
    if (obj && typeof obj === "object") {
      const res = {};
      for (const key in obj) {
        if (Object.prototype.hasOwnProperty.call(obj, key)) {
          const val = obj[key];
          if (typeof val === "string" && /^0x[a-fA-F0-9]{40}$/.test(val)) {
            res[key] = val.toLowerCase();
          } else {
            res[key] = lowercaseAddresses(val);
          }
        }
      }
      return res;
    }
    return obj;
  }

  // -------- Helper: Clean ethers.BigNumber recursively to string for JSON --------
  function cleanBigNumbers(obj) {
    if (Array.isArray(obj)) return obj.map(cleanBigNumbers);
    if (obj && typeof obj === "object") {
      const res = {};
      for (const key in obj) {
        if (Object.prototype.hasOwnProperty.call(obj, key)) {
          const val = obj[key];
          res[key] = ethers.BigNumber.isBigNumber(val) ? val.toString() : cleanBigNumbers(val);
        }
      }
      return res;
    }
    return obj;
  }

  // -------- Helper: Build EIP-712 order parameters --------
  function buildOrderParams(counter, saltBN, priceMainWei, priceFeeWei) {
    const offer = [
      {
        itemType: 2, // ERC721 token
        token: NFT_ADDRESS,
        identifierOrCriteria: TOKEN_ID,
        startAmount: "1",
        endAmount: "1",
      },
    ];

    const consideration = [
      {
        itemType: 0, // Native ETH payment to offerer
        token: ethers.constants.AddressZero,
        identifierOrCriteria: "0",
        startAmount: priceMainWei,
        endAmount: priceMainWei,
        recipient: OFFERER_ADDRESS,
      },
      {
        itemType: 0, // Fee payment to OpenSea fee recipient
        token: ethers.constants.AddressZero,
        identifierOrCriteria: "0",
        startAmount: priceFeeWei,
        endAmount: priceFeeWei,
        recipient: OPENSEA_FEE_RECIPIENT,
      },
    ];

    return {
      parameters: {
        offerer: OFFERER_ADDRESS,
        zone: ethers.constants.AddressZero,
        offer,
        consideration,
        orderType: 0, // FULL_OPEN
        startTime: "0",
        endTime: "2147483647", // Timestamp far in future (year 2038)
        zoneHash: ethers.constants.HashZero,
        salt: saltBN.toString(),
        conduitKey: ethers.constants.HashZero,
        totalOriginalConsiderationItems: consideration.length,
      },
      counter,
    };
  }

  // -------- Helper: Create EIP-712 domain --------
  function getDomain(chainId) {
    return {
      name: "Seaport",
      version: "1.5",
      chainId,
      verifyingContract: SEAPORT_ADDRESS,
    };
  }

  // -------- Helper: Parse r,s,v from flat signature hex string --------
  function parseSignature(signature) {
    const sigBytes = ethers.utils.arrayify(signature);
    return {
      r: ethers.utils.hexlify(sigBytes.slice(0, 32)),
      s: ethers.utils.hexlify(sigBytes.slice(32, 64)),
      v: sigBytes[64],
    };
  }

  // -------- Helper: Initialize ethers provider and signer, request connection --------
  async function initProviderAndSigner() {
    if (!window.ethereum) throw new Error("MetaMask not detected. Please install or enable it.");

    const provider = new ethers.providers.Web3Provider(window.ethereum);

    let accounts = await provider.listAccounts();
    if (accounts.length === 0) {
      accounts = await window.ethereum.request({ method: "eth_requestAccounts" });
    }
    if (!accounts.length) throw new Error("No MetaMask accounts connected.");

    const signer = provider.getSigner();
    const connectedAddress = (await signer.getAddress()).toLowerCase();

    return { provider, signer, connectedAddress };
  }

  // -------- Helper: Fetch current order counter for the offerer --------
  async function fetchCounter(offerer, seaportAddress, provider) {
    const seaportContract = new ethers.Contract(
      seaportAddress,
      ["function getCounter(address) view returns (uint256)"],
      provider
    );
    const counterBN = await seaportContract.getCounter(offerer);
    return counterBN.toString();
  }

  // -------- Main Execution --------
  try {
    await loadEthers();

    const { provider, signer, connectedAddress } = await initProviderAndSigner();

    if (connectedAddress !== OFFERER_ADDRESS)
      throw new Error(
        `Connected address (${connectedAddress}) does not match the offerer (${OFFERER_ADDRESS}). Please switch accounts in MetaMask.`
      );

    const chainId = await signer.getChainId();

    const counter = await fetchCounter(OFFERER_ADDRESS, SEAPORT_ADDRESS, provider);
    console.log(`Seaport offerer counter: ${counter}`);

    const saltBN = ethers.BigNumber.from(ethers.utils.randomBytes(32));

    const priceMainWei = ethers.utils.parseEther(PRICE_MAIN_ETH).toString();
    const priceFeeWei = ethers.utils.parseEther(PRICE_FEE_ETH).toString();

    // Build full order components
    const orderComponents = buildOrderParams(counter, saltBN, priceMainWei, priceFeeWei);

    // Lowercase all addresses recursively for compliant signing
    const messageToSign = lowercaseAddresses(orderComponents);

    const domain = getDomain(chainId);

    console.log("Please confirm signing the order in the MetaMask popup...");

    // Sign EIP-712 typed data order
    const signature = await signer._signTypedData(domain, SEAPORT_TYPES, messageToSign);

    // Parse signature parts
    const { r, s, v } = parseSignature(signature);

    // Check signature 's' value is in lower half of curve to prevent malleability (Seaport requirement)
    const SECP256K1_N = ethers.BigNumber.from(
      "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"
    );
    const HALF_N = SECP256K1_N.div(2);
    const sBN = ethers.BigNumber.from(s);
    if (sBN.gt(HALF_N)) {
      throw new Error("Invalid signature 's' value (must be in lower half order).");
    }

    // Verify signature locally off-chain
    const recoveredAddr = ethers.utils.verifyTypedData(domain, SEAPORT_TYPES, messageToSign, signature);
    if (recoveredAddr.toLowerCase() !== connectedAddress) {
      throw new Error(`Signature verification failed: recovered ${recoveredAddr} != ${connectedAddress}`);
    }

    console.log("✔️ Signature verified!");
    console.log("Signer address:", recoveredAddr);
    console.log("Signature components:", { r, s, v });
    console.log("Order hash:", ethers.utils._TypedDataEncoder.hash(domain, SEAPORT_TYPES, messageToSign));
    console.log("Order parameters (cleaned):", JSON.stringify(cleanBigNumbers(messageToSign.parameters), null, 2));
    console.log("Full signature hex:", signature);

    console.info("Reminder: Approve the Seaport contract to transfer your NFT BEFORE submitting this order on-chain.");
    console.info("Next steps: Use 'orderComponents' and the 'signature' to submit a transaction to Seaport's fulfillOrder or fulfillAdvancedOrder functions.");

  } catch (error) {
    console.error("Error:", error);
    alert(error.message || "An unexpected error occurred; check console for details.");
  }
})();

AND

(async () => {
  try {
    // -------- Constants --------
    const SEAPORT_ADDRESS = "0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC".toLowerCase();
    const OFFERER_ADDRESS = "0xB0077B904F9f5C9009FD2b90d2643Cf9E1632AB4".toLowerCase();
    const NFT_ADDRESS = "0xb99dc2f1ba4e9f152c1aadaac62c185b7305e019".toLowerCase();
    const OPENSEA_FEE_RECIPIENT = "0x0000a26b00c1F0DF003000390027140000fAa719".toLowerCase();

    const TOKEN_ID = "1";
    const PRICE_MAIN_ETH = "0.099999"; // NFT sale price in ETH
    const PRICE_FEE_ETH = "0.000001";  // Marketplace fee in ETH

    // -------- EIP-712 Type Definitions (Seaport 1.5) --------
    const SEAPORT_TYPES = {
      OfferItem: [
        { name: "itemType", type: "uint8" },
        { name: "token", type: "address" },
        { name: "identifierOrCriteria", type: "uint256" },
        { name: "startAmount", type: "uint256" },
        { name: "endAmount", type: "uint256" },
      ],
      ConsiderationItem: [
        { name: "itemType", type: "uint8" },
        { name: "token", type: "address" },
        { name: "identifierOrCriteria", type: "uint256" },
        { name: "startAmount", type: "uint256" },
        { name: "endAmount", type: "uint256" },
        { name: "recipient", type: "address" },
      ],
      OrderParameters: [
        { name: "offerer", type: "address" },
        { name: "zone", type: "address" },
        { name: "offer", type: "OfferItem[]" },
        { name: "consideration", type: "ConsiderationItem[]" },
        { name: "orderType", type: "uint8" },
        { name: "startTime", type: "uint256" },
        { name: "endTime", type: "uint256" },
        { name: "zoneHash", type: "bytes32" },
        { name: "salt", type: "uint256" },
        { name: "conduitKey", type: "bytes32" },
        { name: "totalOriginalConsiderationItems", type: "uint256" },
      ],
      OrderComponents: [
        { name: "parameters", type: "OrderParameters" },
        { name: "counter", type: "uint256" },
      ],
    };

    // -------- Load ethers.js if not present --------
    async function loadEthers() {
      if (typeof ethers !== "undefined") return;
      await new Promise((resolve, reject) => {
        const script = document.createElement("script");
        script.src = "https://cdn.jsdelivr.net/npm/ethers@5.7.2/dist/ethers.umd.min.js";
        script.async = true;
        script.onload = () =>
          typeof ethers !== "undefined" ? resolve() : reject(new Error("ethers.js failed to load"));
        script.onerror = () => reject(new Error("Failed to load ethers.js"));
        document.head.appendChild(script);
      });
    }

    // -------- Utility: recursively lowercase all addresses --------
    function lowercaseAddresses(obj) {
      if (Array.isArray(obj)) return obj.map(lowercaseAddresses);
      if (obj && typeof obj === "object") {
        const res = {};
        for (const key in obj) {
          if (Object.prototype.hasOwnProperty.call(obj, key)) {
            const val = obj[key];
            // Detect hex addresses by regex (20 bytes, 40 hex chars, 0x-prefixed)
            if (typeof val === "string" && /^0x[a-fA-F0-9]{40}$/.test(val)) {
              res[key] = val.toLowerCase();
            } else {
              res[key] = lowercaseAddresses(val);
            }
          }
        }
        return res;
      }
      return obj;
    }

    // -------- Utility: stringify ethers.BigNumber for JSON --------
    function cleanBigNumbers(obj) {
      if (Array.isArray(obj)) return obj.map(cleanBigNumbers);
      if (obj && typeof obj === "object") {
        const res = {};
        for (const key in obj) {
          if (Object.prototype.hasOwnProperty.call(obj, key)) {
            const val = obj[key];
            // Use toString for BigNumber, recurse for objects/arrays
            res[key] = ethers.BigNumber.isBigNumber(val) ? val.toString() : cleanBigNumbers(val);
          }
        }
        return res;
      }
      return obj;
    }

    // -------- Build the order parameters --------
    function buildOrderParams(counter, saltBN, priceMainWei, priceFeeWei) {
      // Offer contains one ERC721 token
      const offer = [
        {
          itemType: 2, // ERC721 token item type per Seaport
          token: NFT_ADDRESS,
          identifierOrCriteria: TOKEN_ID,
          startAmount: "1",
          endAmount: "1",
        },
      ];

      // Consideration includes payment to the offerer + fees
      const consideration = [
        {
          itemType: 0, // Native ETH (ETH)
          token: ethers.constants.AddressZero,
          identifierOrCriteria: "0",
          startAmount: priceMainWei,
          endAmount: priceMainWei,
          recipient: OFFERER_ADDRESS,
        },
        {
          itemType: 0,
          token: ethers.constants.AddressZero,
          identifierOrCriteria: "0",
          startAmount: priceFeeWei,
          endAmount: priceFeeWei,
          recipient: OPENSEA_FEE_RECIPIENT,
        },
      ];

      return {
        parameters: {
          offerer: OFFERER_ADDRESS,
          zone: ethers.constants.AddressZero,
          offer,
          consideration,
          orderType: 0, // FULL_OPEN order (anyone can fulfill)
          startTime: "0",
          endTime: "2147483647", // A very distant timestamp (year 2038)
          zoneHash: ethers.constants.HashZero,
          salt: saltBN.toString(),
          conduitKey: ethers.constants.HashZero, // Usually zero, could be conduit if used
          totalOriginalConsiderationItems: consideration.length,
        },
        counter,
      };
    }

    // -------- Get the EIP-712 domain --------
    function getDomain(chainId) {
      return {
        name: "Seaport",
        version: "1.5",
        chainId,
        verifyingContract: SEAPORT_ADDRESS,
      };
    }

    // -------- Parse the flat signature to (r, s, v) --------
    function parseSignature(signature) {
      const sigBytes = ethers.utils.arrayify(signature);
      return {
        r: ethers.utils.hexlify(sigBytes.slice(0, 32)),
        s: ethers.utils.hexlify(sigBytes.slice(32, 64)),
        v: sigBytes[64],
      };
    }

    // -------- Initialize ethers provider and MetaMask signer --------
    async function initProviderAndSigner() {
      if (!window.ethereum) throw new Error("MetaMask not detected. Please install or enable it.");

      const provider = new ethers.providers.Web3Provider(window.ethereum);

      // Request accounts if none authorized yet
      let accounts = await provider.listAccounts();
      if (accounts.length === 0) {
        accounts = await window.ethereum.request({ method: "eth_requestAccounts" });
      }
      if (!accounts.length) throw new Error("No MetaMask accounts connected.");

      const signer = provider.getSigner();
      const connectedAddress = (await signer.getAddress()).toLowerCase();

      return { provider, signer, connectedAddress };
    }

    // -------- Fetch counter for offerer's current order nonce --------
    async function fetchCounter(offerer, seaportAddress, provider) {
      const seaportContract = new ethers.Contract(
        seaportAddress,
        ["function getCounter(address) external view returns (uint256)"],
        provider
      );
      const counterBN = await seaportContract.getCounter(offerer);
      return counterBN.toString();
    }

    // -------- Main flow --------
    await loadEthers();

    const { provider, signer, connectedAddress } = await initProviderAndSigner();

    if (connectedAddress !== OFFERER_ADDRESS)
      throw new Error(
        `Connected address (${connectedAddress}) does not match the offerer (${OFFERER_ADDRESS}). Switch accounts in MetaMask.`
      );

    const chainId = await signer.getChainId();

    const counter = await fetchCounter(OFFERER_ADDRESS, SEAPORT_ADDRESS, provider);
    console.info(`Seaport offerer counter: ${counter}`);

    // Create a random 32-byte salt for uniqueness
    const saltBN = ethers.BigNumber.from(ethers.utils.randomBytes(32));

    // Parse ETH prices to wei strings
    const priceMainWei = ethers.utils.parseEther(PRICE_MAIN_ETH).toString();
    const priceFeeWei = ethers.utils.parseEther(PRICE_FEE_ETH).toString();

    // Build the order components object
    const orderComponents = buildOrderParams(counter, saltBN, priceMainWei, priceFeeWei);

    // Lowercase all addresses for EIP-712 compliance
    const messageToSign = lowercaseAddresses(orderComponents);

    // Build EIP-712 domain
    const domain = getDomain(chainId);

    console.log("Please confirm signing the order in the MetaMask popup...");

    // Sign the order using EIP-712 typed data
    const signature = await signer._signTypedData(domain, SEAPORT_TYPES, messageToSign);

    const { r, s, v } = parseSignature(signature);

    // Check low S value to prevent signature malleability (Seaport requirement)
    const SECP256K1_N = ethers.BigNumber.from(
      "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"
    );
    const HALF_N = SECP256K1_N.div(2);
    const sBN = ethers.BigNumber.from(s);
    if (sBN.gt(HALF_N)) {
      throw new Error("Invalid signature 's' value (must be in lower half order).");
    }

    // Recover address from signature and message for off-chain verification
    const recoveredAddr = ethers.utils.verifyTypedData(domain, SEAPORT_TYPES, messageToSign, signature);
    if (recoveredAddr.toLowerCase() !== connectedAddress) {
      throw new Error(`Signature verification failed: recovered ${recoveredAddr} != ${connectedAddress}`);
    }

    console.log("✔️ Signature verified!");
    console.log("Signer address:", recoveredAddr);
    console.log("Signature components: ", { r, s, v });
    console.log("Order hash:", ethers.utils._TypedDataEncoder.hash(domain, SEAPORT_TYPES, messageToSign));
    console.log("Order parameters (cleaned):", JSON.stringify(cleanBigNumbers(messageToSign.parameters), null, 2));
    console.log("Full signature (hex):", signature);

    console.info(
      "Reminder: Approve the Seaport contract to transfer your NFT BEFORE submitting this order on-chain."
    );
    console.info(
      "Next steps: Use these 'orderComponents' and 'signature' to submit a transaction to Seaport's fulfillOrder or fulfillAdvancedOrder."
    );

    // You can also return the full order data if you want to submit or process further:
    // return { orderComponents, signature };

  } catch (error) {
    console.error("Error:", error);
    alert(error.message || "An unexpected error occurred; check console for details.");
  }
})();