import { utils, BigNumber, constants } from 'ethers';
import deepEqual from 'fast-deep-equal';
import { aR as resolveAddress, cB as AmountSchema, B as includesErrorMessage, da as isNode, cx as ContractWrapper } from './index-a68568e5.esm.js';
import { y as transformResultToClaimCondition, z as legacyContractModelToAbstract, A as newContractModelToAbstract, C as ClaimEligibility, D as convertQuantityToBigNumber, f as fetchSnapshotEntryForAddress, E as prepareClaim, F as SnapshotFormatVersion, H as processClaimConditionInputs, I as abstractContractModelToLegacy, J as abstractContractModelToNew, K as updateExistingClaimConditions } from './signature-557cbb19.esm.js';
import { i as isNativeToken, C as ContractEncoder } from './fetchCurrencyValue-a8809041.esm.js';
import { d as detectContractFeature, h as hasFunction } from './contract-appuri-c9dcc95c.esm.js';
import { b as buildTransactionFunction, T as Transaction } from './transactions-4f40d881.esm.js';

/**
 * Manages claim conditions for NFT Drop contracts
 * @erc721
 * @public
 */
class DropClaimConditions {
  constructor(contractWrapper, metadata, storage) {
    this.storage = storage;
    this.contractWrapper = contractWrapper;
    this.metadata = metadata;
  }

  /** ***************************************
   * READ FUNCTIONS
   *****************************************/

  /**
   * Get the currently active claim condition
   *
   * @returns The claim condition metadata
   */
  async getActive(options) {
    const [cc, metadata, tokenDecimals] = await Promise.all([this.get(), this.metadata.get(), this.getTokenDecimals()]);
    return await transformResultToClaimCondition(cc, tokenDecimals, this.contractWrapper.getProvider(), metadata.merkle || {}, this.storage, options?.withAllowList || false);
  }
  async get(conditionId) {
    if (this.isLegacySinglePhaseDrop(this.contractWrapper)) {
      const contractModel = await this.contractWrapper.read("claimCondition", []);
      return legacyContractModelToAbstract(contractModel);
    } else if (this.isLegacyMultiPhaseDrop(this.contractWrapper)) {
      const id = conditionId !== undefined ? conditionId : await this.contractWrapper.read("getActiveClaimConditionId", []);
      const contractModel = await this.contractWrapper.read("getClaimConditionById", [id]);
      return legacyContractModelToAbstract(contractModel);
    } else if (this.isNewSinglePhaseDrop(this.contractWrapper)) {
      const contractModel = await this.contractWrapper.read("claimCondition", []);
      return newContractModelToAbstract(contractModel);
    } else if (this.isNewMultiphaseDrop(this.contractWrapper)) {
      const id = conditionId !== undefined ? conditionId : await this.contractWrapper.read("getActiveClaimConditionId", []);
      const contractModel = await this.contractWrapper.read("getClaimConditionById", [id]);
      return newContractModelToAbstract(contractModel);
    } else {
      throw new Error("Contract does not support claim conditions");
    }
  }

  /**
   * Get all the claim conditions
   *
   * @returns The claim conditions metadata
   */
  async getAll(options) {
    if (this.isLegacyMultiPhaseDrop(this.contractWrapper) || this.isNewMultiphaseDrop(this.contractWrapper)) {
      const [currentStartId, countBn] = await this.contractWrapper.read("claimCondition", []);
      const startId = currentStartId.toNumber();
      const count = countBn.toNumber();
      const conditions = [];
      for (let i = startId; i < startId + count; i++) {
        conditions.push(this.get(i));
      }
      const [metadata, decimals, ...fetchedConditions] = await Promise.all([this.metadata.get(), this.getTokenDecimals(), ...conditions]);
      return Promise.all(fetchedConditions.map(c => transformResultToClaimCondition(c, decimals, this.contractWrapper.getProvider(), metadata.merkle, this.storage, options?.withAllowList || false)));
    } else {
      return [await this.getActive(options)];
    }
  }

  /**
   * Can Claim
   *
   * @remarks Check if the drop can currently be claimed.
   *
   * @example
   * ```javascript
   * // Quantity of tokens to check claimability of
   * const quantity = 1;
   * const canClaim = await contract.canClaim(quantity);
   * ```
   */
  async canClaim(quantity, addressToCheck) {
    // TODO switch to use verifyClaim
    if (addressToCheck) {
      addressToCheck = await resolveAddress(addressToCheck);
    }
    return (await this.getClaimIneligibilityReasons(quantity, addressToCheck)).length === 0;
  }

  /**
   * For any claim conditions that a particular wallet is violating,
   * this function returns human readable information about the
   * breaks in the condition that can be used to inform the user.
   *
   * @param quantity - The desired quantity that would be claimed.
   * @param addressToCheck - The wallet address, defaults to the connected wallet.
   *
   */
  async getClaimIneligibilityReasons(quantity, addressToCheck) {
    const reasons = [];
    let activeConditionIndex;
    let claimCondition;
    if (addressToCheck === undefined) {
      try {
        addressToCheck = await this.contractWrapper.getSignerAddress();
      } catch (err) {
        console.warn("failed to get signer address", err);
      }
    }

    // if we have been unable to get a signer address, we can't check eligibility, so return a NoWallet error reason
    if (!addressToCheck) {
      return [ClaimEligibility.NoWallet];
    }
    const [resolvedAddress, decimals] = await Promise.all([resolveAddress(addressToCheck), this.getTokenDecimals()]);
    const quantityWithDecimals = utils.parseUnits(AmountSchema.parse(quantity), decimals);
    try {
      claimCondition = await this.getActive();
    } catch (err) {
      if (includesErrorMessage(err, "!CONDITION") || includesErrorMessage(err, "no active mint condition") || includesErrorMessage(err, "DropNoActiveCondition")) {
        reasons.push(ClaimEligibility.NoClaimConditionSet);
        return reasons;
      }
      console.warn("failed to get active claim condition", err);
      reasons.push(ClaimEligibility.Unknown);
      return reasons;
    }
    if (claimCondition.availableSupply !== "unlimited") {
      const supplyWithDecimals = utils.parseUnits(claimCondition.availableSupply, decimals);
      if (supplyWithDecimals.lt(quantityWithDecimals)) {
        reasons.push(ClaimEligibility.NotEnoughSupply);
        return reasons;
      }
    }

    // check for merkle root inclusion
    const merkleRootArray = utils.stripZeros(claimCondition.merkleRootHash);
    const hasAllowList = merkleRootArray.length > 0;
    let allowListEntry = null;
    if (hasAllowList) {
      allowListEntry = await this.getClaimerProofs(resolvedAddress);
      if (!allowListEntry && (this.isLegacySinglePhaseDrop(this.contractWrapper) || this.isLegacyMultiPhaseDrop(this.contractWrapper))) {
        // exclusive allowlist behavior
        reasons.push(ClaimEligibility.AddressNotAllowed);
        return reasons;
      }
      if (allowListEntry) {
        try {
          const claimVerification = await this.prepareClaim(quantity, false, decimals, resolvedAddress);
          let validMerkleProof;
          if (this.isLegacyMultiPhaseDrop(this.contractWrapper)) {
            activeConditionIndex = await this.contractWrapper.read("getActiveClaimConditionId", []);
            // legacy verifyClaimerMerkleProofs function
            [validMerkleProof] = await this.contractWrapper.read("verifyClaimMerkleProof", [activeConditionIndex, resolvedAddress, quantity, claimVerification.proofs, claimVerification.maxClaimable]);
            if (!validMerkleProof) {
              reasons.push(ClaimEligibility.AddressNotAllowed);
              return reasons;
            }
          } else if (this.isLegacySinglePhaseDrop(this.contractWrapper)) {
            [validMerkleProof] = await this.contractWrapper.read("verifyClaimMerkleProof", [resolvedAddress, quantity, {
              proof: claimVerification.proofs,
              maxQuantityInAllowlist: claimVerification.maxClaimable
            }]);
            if (!validMerkleProof) {
              reasons.push(ClaimEligibility.AddressNotAllowed);
              return reasons;
            }
          } else if (this.isNewSinglePhaseDrop(this.contractWrapper)) {
            await this.contractWrapper.read("verifyClaim", [resolvedAddress, quantity, claimVerification.currencyAddress, claimVerification.price, {
              proof: claimVerification.proofs,
              quantityLimitPerWallet: claimVerification.maxClaimable,
              currency: claimVerification.currencyAddressInProof,
              pricePerToken: claimVerification.priceInProof
            }]);
          } else if (this.isNewMultiphaseDrop(this.contractWrapper)) {
            activeConditionIndex = await this.contractWrapper.read("getActiveClaimConditionId", []);
            await this.contractWrapper.read("verifyClaim", [activeConditionIndex, resolvedAddress, quantity, claimVerification.currencyAddress, claimVerification.price, {
              proof: claimVerification.proofs,
              quantityLimitPerWallet: claimVerification.maxClaimable,
              currency: claimVerification.currencyAddressInProof,
              pricePerToken: claimVerification.priceInProof
            }]);
          }
        } catch (e) {
          console.warn("Merkle proof verification failed:", "reason" in e ? e.reason || e.errorName : e);
          const reason = e.reason || e.errorName;
          switch (reason) {
            case "!Qty":
            case "DropClaimExceedLimit":
              reasons.push(ClaimEligibility.OverMaxClaimablePerWallet);
              break;
            case "!PriceOrCurrency":
            case "DropClaimInvalidTokenPrice":
              reasons.push(ClaimEligibility.WrongPriceOrCurrency);
              break;
            case "!MaxSupply":
            case "DropClaimExceedMaxSupply":
              reasons.push(ClaimEligibility.NotEnoughSupply);
              break;
            case "cant claim yet":
            case "DropClaimNotStarted":
              reasons.push(ClaimEligibility.ClaimPhaseNotStarted);
              break;
            default:
              {
                reasons.push(ClaimEligibility.AddressNotAllowed);
                break;
              }
          }
          return reasons;
        }
      }
    }
    if (this.isNewSinglePhaseDrop(this.contractWrapper) || this.isNewMultiphaseDrop(this.contractWrapper)) {
      let claimedSupply = BigNumber.from(0);
      let maxClaimable = convertQuantityToBigNumber(claimCondition.maxClaimablePerWallet, decimals);
      try {
        claimedSupply = await this.getSupplyClaimedByWallet(resolvedAddress);
      } catch (e) {
        // no-op
      }
      if (allowListEntry) {
        maxClaimable = convertQuantityToBigNumber(allowListEntry.maxClaimable, decimals);
      }
      if (maxClaimable.gt(0) && maxClaimable.lt(claimedSupply.add(quantityWithDecimals))) {
        reasons.push(ClaimEligibility.OverMaxClaimablePerWallet);
        return reasons;
      }

      // if there is no allowlist, or if there is an allowlist and the address is not in it
      // if maxClaimable is 0, we consider it as the address is not allowed
      if (!hasAllowList || hasAllowList && !allowListEntry) {
        if (maxClaimable.lte(claimedSupply) || maxClaimable.eq(0)) {
          reasons.push(ClaimEligibility.AddressNotAllowed);
          return reasons;
        }
      }
    }

    // check for claim timestamp between claims (ONLY FOR LEGACY)
    if (this.isLegacySinglePhaseDrop(this.contractWrapper) || this.isLegacyMultiPhaseDrop(this.contractWrapper)) {
      let [lastClaimedTimestamp, timestampForNextClaim] = [BigNumber.from(0), BigNumber.from(0)];
      if (this.isLegacyMultiPhaseDrop(this.contractWrapper)) {
        activeConditionIndex = await this.contractWrapper.read("getActiveClaimConditionId", []);
        [lastClaimedTimestamp, timestampForNextClaim] = await this.contractWrapper.read("getClaimTimestamp", [activeConditionIndex, resolvedAddress]);
      } else if (this.isLegacySinglePhaseDrop(this.contractWrapper)) {
        // check for claim timestamp between claims
        [lastClaimedTimestamp, timestampForNextClaim] = await this.contractWrapper.read("getClaimTimestamp", [resolvedAddress]);
      }
      const now = BigNumber.from(Date.now()).div(1000);
      if (lastClaimedTimestamp.gt(0) && now.lt(timestampForNextClaim)) {
        // contract will return MaxUint256 if user has already claimed and cannot claim again
        if (timestampForNextClaim.eq(constants.MaxUint256)) {
          reasons.push(ClaimEligibility.AlreadyClaimed);
        } else {
          reasons.push(ClaimEligibility.WaitBeforeNextClaimTransaction);
        }
        return reasons;
      }
    }

    // if not within a browser context, check for wallet balance.
    // In browser context, let the wallet do that job
    if (claimCondition.price.gt(0) && isNode()) {
      const totalPrice = claimCondition.price.mul(BigNumber.from(quantity));
      const provider = this.contractWrapper.getProvider();
      if (isNativeToken(claimCondition.currencyAddress)) {
        const balance = await provider.getBalance(resolvedAddress);
        if (balance.lt(totalPrice)) {
          reasons.push(ClaimEligibility.NotEnoughTokens);
        }
      } else {
        const ERC20Abi = (await import('@thirdweb-dev/contracts-js/dist/abis/IERC20.json')).default;
        const erc20 = new ContractWrapper(provider, claimCondition.currencyAddress, ERC20Abi, {}, this.storage);
        const balance = await erc20.read("balanceOf", [resolvedAddress]);
        if (balance.lt(totalPrice)) {
          reasons.push(ClaimEligibility.NotEnoughTokens);
        }
      }
    }
    return reasons;
  }

  /**
   * Returns allow list information and merkle proofs for the given address.
   * @param claimerAddress - the claimer address
   * @param claimConditionId - optional the claim condition id to get the proofs for
   */
  async getClaimerProofs(claimerAddress, claimConditionId) {
    const claimCondition = await this.get(claimConditionId);
    const merkleRoot = claimCondition.merkleRoot;
    const merkleRootArray = utils.stripZeros(merkleRoot);
    if (merkleRootArray.length > 0) {
      const [metadata, resolvedAddress] = await Promise.all([this.metadata.get(), resolveAddress(claimerAddress)]);
      return await fetchSnapshotEntryForAddress(resolvedAddress, merkleRoot.toString(), metadata.merkle, this.contractWrapper.getProvider(), this.storage, this.getSnapshotFormatVersion());
    } else {
      return null;
    }
  }

  /**
   * Get the total supply claimed by a specific wallet
   * @param walletAddress - the wallet address to check
   * @returns The total supply claimed
   */
  async getSupplyClaimedByWallet(walletAddress) {
    const resolvedAddress = await resolveAddress(walletAddress);
    if (this.isNewSinglePhaseDrop(this.contractWrapper)) {
      return await this.contractWrapper.read("getSupplyClaimedByWallet", [resolvedAddress]);
    }
    if (this.isNewMultiphaseDrop(this.contractWrapper)) {
      const activeClaimConditionId = await this.contractWrapper.read("getActiveClaimConditionId", []);
      return await this.contractWrapper.read("getSupplyClaimedByWallet", [activeClaimConditionId, resolvedAddress]);
    }
    throw new Error("This contract does not support the getSupplyClaimedByWallet function");
  }

  /** ***************************************
   * WRITE FUNCTIONS
   *****************************************/

  /**
   * Set public mint conditions
   *
   * @remarks Sets the public mint conditions that need to be fullfiled by users to claim NFTs.
   *
   * @example
   * ```javascript
   * const presaleStartTime = new Date();
   * const publicSaleStartTime = new Date(Date.now() + 60 * 60 * 24 * 1000);
   *
   * // Optionally specify addresses that can claim
   * const snapshots = ['0x...', '0x...']
   *
   * // Or alternatively, you can pass snapshots with the max number of NFTs each address can claim
   * // const snapshots = [{ address: '0x...', maxClaimable: 1 }, { address: '0x...', maxClaimable: 2 }]
   *
   * const claimConditions = [
   *   {
   *     startTime: presaleStartTime, // start the presale now
   *     maxClaimableSupply: 2, // limit how many mints for this presale
   *     price: 0.01, // presale price
   *     snapshot: snapshots, // limit minting to only certain addresses
   *   },
   *   {
   *     startTime: publicSaleStartTime, // 24h after presale, start public sale
   *     price: 0.08, // public sale price
   *   }
   * ]);
   *
   * await dropContract.claimConditions.set(claimConditions);
   * ```
   *
   * @param claimConditionInputs - The claim conditions
   * @param resetClaimEligibilityForAll - Whether to reset the state of who already claimed NFTs previously
   */
  set = /* @__PURE__ */buildTransactionFunction((() => {
    var _this = this;
    return async function (claimConditionInputs) {
      let resetClaimEligibilityForAll = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
      let claimConditionsProcessed = claimConditionInputs;
      if (_this.isLegacySinglePhaseDrop(_this.contractWrapper) || _this.isNewSinglePhaseDrop(_this.contractWrapper)) {
        resetClaimEligibilityForAll = true;
        if (claimConditionInputs.length === 0) {
          claimConditionsProcessed = [{
            startTime: new Date(0),
            currencyAddress: constants.AddressZero,
            price: 0,
            maxClaimableSupply: 0,
            maxClaimablePerWallet: 0,
            waitInSeconds: 0,
            merkleRootHash: utils.hexZeroPad([0], 32),
            snapshot: []
          }];
        } else if (claimConditionInputs.length > 1) {
          throw new Error("Single phase drop contract cannot have multiple claim conditions, only one is allowed");
        }
      }

      // if using new snapshot format, make sure that maxClaimablePerWallet is set if allowlist is set as well
      if (_this.isNewSinglePhaseDrop(_this.contractWrapper) || _this.isNewMultiphaseDrop(_this.contractWrapper)) {
        claimConditionsProcessed.forEach(cc => {
          if (cc.snapshot && cc.snapshot.length > 0 && (cc.maxClaimablePerWallet === undefined || cc.maxClaimablePerWallet === "unlimited")) {
            throw new Error("maxClaimablePerWallet must be set to a specific value when an allowlist is set.\n" + "Example: Set it to 0 to only allow addresses in the allowlist to claim the amount specified in the allowlist.\n" + "contract.claimConditions.set([{ snapshot: [{ address: '0x...', maxClaimable: 1 }], maxClaimablePerWallet: 0 }])");
          }
          if (cc.snapshot && cc.snapshot.length > 0 && cc.maxClaimablePerWallet?.toString() === "0" && cc.snapshot.map(s => {
            if (typeof s === "string") {
              return 0;
            } else {
              return Number(s.maxClaimable?.toString() || 0);
            }
          }).reduce((acc, current) => {
            return acc + current;
          }, 0) === 0) {
            throw new Error("maxClaimablePerWallet is set to 0, and all addresses in the allowlist have max claimable 0. This means that no one can claim.");
          }
        });
      }

      // process inputs
      const {
        snapshotInfos,
        sortedConditions
      } = await processClaimConditionInputs(claimConditionsProcessed, await _this.getTokenDecimals(), _this.contractWrapper.getProvider(), _this.storage, _this.getSnapshotFormatVersion());
      const merkleInfo = {};
      snapshotInfos.forEach(s => {
        merkleInfo[s.merkleRoot] = s.snapshotUri;
      });
      const metadata = await _this.metadata.get();
      const encoded = [];

      // upload new merkle roots to snapshot URIs if updated
      if (!deepEqual(metadata.merkle, merkleInfo)) {
        const mergedMetadata = await _this.metadata.parseInputMetadata({
          ...metadata,
          merkle: merkleInfo
        });
        // using internal method to just upload, avoids one contract call
        const contractURI = await _this.metadata._parseAndUploadMetadata(mergedMetadata);

        // TODO (cc) we could write the merkle tree info on the claim condition metadata instead
        // TODO (cc) but we still need to maintain the behavior here for older contracts
        if (hasFunction("setContractURI", _this.contractWrapper)) {
          const contractEncoder = new ContractEncoder(_this.contractWrapper);
          encoded.push(contractEncoder.encode("setContractURI", [contractURI]));
        } else {
          throw new Error("Setting a merkle root requires implementing ContractMetadata in your contract to support storing a merkle root.");
        }
      }
      const cw = _this.contractWrapper;
      const baseContractEncoder = new ContractEncoder(cw);
      if (_this.isLegacySinglePhaseDrop(cw)) {
        const contractEncoderLegacy = new ContractEncoder(cw);
        encoded.push(contractEncoderLegacy.encode("setClaimConditions", [abstractContractModelToLegacy(sortedConditions[0]), resetClaimEligibilityForAll]));
      } else if (_this.isLegacyMultiPhaseDrop(cw)) {
        encoded.push(baseContractEncoder.encode("setClaimConditions", [sortedConditions.map(abstractContractModelToLegacy), resetClaimEligibilityForAll]));
      } else if (_this.isNewSinglePhaseDrop(cw)) {
        encoded.push(baseContractEncoder.encode("setClaimConditions", [abstractContractModelToNew(sortedConditions[0]), resetClaimEligibilityForAll]));
      } else if (_this.isNewMultiphaseDrop(cw)) {
        encoded.push(baseContractEncoder.encode("setClaimConditions", [sortedConditions.map(abstractContractModelToNew), resetClaimEligibilityForAll]));
      } else {
        throw new Error("Contract does not support claim conditions");
      }
      if (hasFunction("multicall", _this.contractWrapper)) {
        return Transaction.fromContractWrapper({
          contractWrapper: _this.contractWrapper,
          method: "multicall",
          args: [encoded]
        });
      }
      throw new Error("Contract does not support multicall");
    };
  })());

  /**
   * Update a single claim condition with new data.
   *
   * @param index - the index of the claim condition to update, as given by the index from the result of `getAll()`
   * @param claimConditionInput - the new data to update, previous data will be retained
   */
  update = /* @__PURE__ */buildTransactionFunction(async (index, claimConditionInput) => {
    const existingConditions = await this.getAll();
    const newConditionInputs = await updateExistingClaimConditions(index, claimConditionInput, existingConditions);
    return await this.set.prepare(newConditionInputs);
  });

  /** ***************************************
   * PRIVATE FUNCTIONS
   *****************************************/

  async getTokenDecimals() {
    if (detectContractFeature(this.contractWrapper, "ERC20")) {
      return this.contractWrapper.read("decimals", []);
    } else {
      return Promise.resolve(0);
    }
  }

  /**
   * Returns proofs and the overrides required for the transaction.
   *
   * @returns  `overrides` and `proofs` as an object.
   * @internal
   */
  async prepareClaim(quantity, checkERC20Allowance) {
    let decimals = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
    let address = arguments.length > 3 ? arguments[3] : undefined;
    const [addressToClaim, activeClaimConditions] = await Promise.all([address ? address : this.contractWrapper.getSignerAddress(), this.getActive()]);
    return prepareClaim(addressToClaim, quantity, activeClaimConditions, async () => (await this.metadata.get()).merkle, decimals, this.contractWrapper, this.storage, checkERC20Allowance, this.getSnapshotFormatVersion());
  }
  async getClaimArguments(destinationAddress, quantity, claimVerification) {
    const resolvedAddress = await resolveAddress(destinationAddress);
    if (this.isLegacyMultiPhaseDrop(this.contractWrapper)) {
      return [resolvedAddress, quantity, claimVerification.currencyAddress, claimVerification.price, claimVerification.proofs, claimVerification.maxClaimable];
    } else if (this.isLegacySinglePhaseDrop(this.contractWrapper)) {
      return [resolvedAddress, quantity, claimVerification.currencyAddress, claimVerification.price, {
        proof: claimVerification.proofs,
        maxQuantityInAllowlist: claimVerification.maxClaimable
      }, utils.toUtf8Bytes("")];
    }
    return [resolvedAddress, quantity, claimVerification.currencyAddress, claimVerification.price, {
      proof: claimVerification.proofs,
      quantityLimitPerWallet: claimVerification.maxClaimable,
      pricePerToken: claimVerification.priceInProof,
      currency: claimVerification.currencyAddressInProof
    }, utils.toUtf8Bytes("")];
  }

  /**
   * Construct a claim transaction without executing it.
   * This is useful for estimating the gas cost of a claim transaction, overriding transaction options and having fine grained control over the transaction execution.
   * @param destinationAddress - The address to claim to
   * @param quantity - The quantity to claim
   * @param options - Options to override the claim transaction
   *
   * @deprecated Use `contract.erc721.claim.prepare(...args)` instead
   */
  async getClaimTransaction(destinationAddress, quantity, options) {
    // TODO: Transaction Sequence Pattern
    if (options?.pricePerToken) {
      throw new Error("Price per token is be set via claim conditions by calling `contract.erc721.claimConditions.set()`");
    }
    const claimVerification = await this.prepareClaim(quantity, options?.checkERC20Allowance === undefined ? true : options.checkERC20Allowance, await this.getTokenDecimals());
    return Transaction.fromContractWrapper({
      contractWrapper: this.contractWrapper,
      method: "claim",
      args: await this.getClaimArguments(destinationAddress, quantity, claimVerification),
      overrides: claimVerification.overrides
    });
  }
  isNewSinglePhaseDrop(contractWrapper) {
    return detectContractFeature(contractWrapper, "ERC721ClaimConditionsV2") || detectContractFeature(contractWrapper, "ERC20ClaimConditionsV2");
  }
  isNewMultiphaseDrop(contractWrapper) {
    return detectContractFeature(contractWrapper, "ERC721ClaimPhasesV2") || detectContractFeature(contractWrapper, "ERC20ClaimPhasesV2");
  }
  isLegacySinglePhaseDrop(contractWrapper) {
    return detectContractFeature(contractWrapper, "ERC721ClaimConditionsV1") || detectContractFeature(contractWrapper, "ERC20ClaimConditionsV1");
  }
  isLegacyMultiPhaseDrop(contractWrapper) {
    return detectContractFeature(contractWrapper, "ERC721ClaimPhasesV1") || detectContractFeature(contractWrapper, "ERC20ClaimPhasesV1");
  }
  getSnapshotFormatVersion() {
    return this.isLegacyMultiPhaseDrop(this.contractWrapper) || this.isLegacySinglePhaseDrop(this.contractWrapper) ? SnapshotFormatVersion.V1 : SnapshotFormatVersion.V2;
  }
}

export { DropClaimConditions as D };
