# furnace/v2.ts

    import { ethers } from "ethers";
    import type { CallbackType } from "@evo/utils/ethers/contractHelper";
    import { triggerContractByContractName, viewContractByContractName } from "@evo/utils/ethers/contractHelper";
    import { pad0xBegin } from "@evo/utils/common/utils";
    import { LandId } from "@evo/config/constants";
    import { TransactionResponse } from "@ethersproject/providers";
    import { getAddressesByLandId } from "@evo/utils/ethers/addressHelper";

    export interface furnaceGetTreasurePriceResponse {
      priceGoldBox: string;
      priceSilverBox: string;
    }

    /**
     * Get treasure price
     * @param landId Land Id
     * @param provider Provider
     * @param callback Callback
     * @returns any
     */
    export const furnaceGetTreasurePrice = async (
      landId: LandId,
      provider: ethers.providers.Provider,
      callback?: CallbackType
    ): Promise<furnaceGetTreasurePriceResponse> => {
      const results = await viewContractByContractName(landId, provider, "furnaceTreasure", "getPrice", [], callback);

      return {
        priceGoldBox: results.priceGoldBox.toHexString(),
        priceSilverBox: results.priceSilverBox.toHexString(),
      };
    };

    /**
     * Buy treasure
     * @param landId Land Id
     * @param signer Signer
     * @param to Recipient
     * @param goldBoxAmount Gold box amount
     * @param silverBoxAmount Silver box amount
     * @param cost Max cost
     * @param callback Callback
     * @returns any
     */
    export const furnaceBuyTreasure = (
      landId: LandId,
      signer: ethers.Signer,
      to: string,
      goldBoxAmount: string,
      silverBoxAmount: string,
      cost: string,
      callback?: CallbackType
    ): Promise<TransactionResponse> => {
      if (landId === LandId.ETHEREUM || landId === LandId._ETHEREUM) {
        const addresses = getAddressesByLandId(landId);
        const goldBoxAmountHex = ethers.BigNumber.from(goldBoxAmount).toHexString();
        const silverBoxAmountHex = ethers.BigNumber.from(silverBoxAmount).toHexString();

        if (!addresses || !addresses.FURNACE_TREASURE) {
          throw "address error";
        }

        return triggerContractByContractName(
          landId,
          signer,
          "ring",
          "transfer(address,uint256,bytes)",
          [
            addresses.FURNACE_TREASURE,
            cost,
            `${ethers.utils.hexZeroPad(goldBoxAmountHex, 32)}${ethers.utils.hexZeroPad(silverBoxAmountHex, 32).slice(2)}`,
          ],
          callback
        );
      }

      return triggerContractByContractName(
        landId,
        signer,
        "furnaceTreasure",
        "buyBox",
        [to, goldBoxAmount, silverBoxAmount, cost],
        callback
      );
    };

    /**
     * Use nft and elements or LP tokens in the furnace formula to the props.
     * @param signer
     * @param formulaIndex Formula for props - https://github.com/evolutionlandorg/furnace/blob/dev/src/Formula.sol
     * @param majorTokenId ERC721 token Id
     * @param minorTokenAddress Elements or LP tokens contract address
     * @param callback callback
     */
    export const furnaceEnchantProps = (
      landId: LandId,
      signer: ethers.Signer,
      formulaIndex: number,
      majorTokenId: string,
      minorTokenAddress: string,
      callback?: CallbackType
    ): Promise<TransactionResponse> => {
      return triggerContractByContractName(
        landId,
        signer,
        "furnaceItemBase",
        "enchant",
        [formulaIndex, pad0xBegin(majorTokenId), minorTokenAddress],
        callback
      );
    };

    /**
     * Disenchant furnace props, and will get elements or LP and nft
     * @param signer
     * @param propsTokenId Token Id of the Props
     * @param depth Supports one-time decomposition of high-level props. If a prop is in the second level, it needs to be restored to its original state, and the depth needs to be passed in 2
     * @param callback
     */
    export const furnaceDisenchantProps = (
      landId: LandId,
      signer: ethers.Signer,
      propsTokenId: string,
      depth: string,
      callback?: CallbackType
    ): Promise<TransactionResponse> => {
      return triggerContractByContractName(
        landId,
        signer,
        "furnaceItemBase",
        "disenchant",
        [pad0xBegin(propsTokenId), depth],
        callback
      );
    };

    /**
     * Get treasure is opened
     * @param landId Land Id
     * @param provider Provider
     * @param treasureTokenId Id of treasure
     * @param callback Callback
     * @returns any
     */
    export const furnaceGetTreasureStatus = async (
      landId: LandId,
      provider: ethers.providers.Provider,
      treasureTokenId: string,
      callback?: CallbackType
    ): Promise<boolean> => {
      const results = await viewContractByContractName(
        landId,
        provider,
        "furnaceTakeback",
        "ids",
        [pad0xBegin(treasureTokenId)],
        callback
      );
      return results[0];
    };

    /**
     * Open furnace treasure
     * @param landId Land Id
     * @param signer Signer
     * @param param2 Signature content
     * @param callback Callback
     * @returns any
     */
    export const furnaceOpenTreasure = (
      landId: LandId,
      signer: ethers.Signer,
      {
        boxIds,
        amounts,
        hashmessage,
        v,
        r,
        s,
      }: {
        boxIds: string[];
        amounts: string[];
        hashmessage: string;
        v: number;
        r: string;
        s: string;
      },
      callback?: CallbackType
    ): Promise<TransactionResponse> => {
      const silverBoxGasLimit = ethers.BigNumber.from(350000);
      const goldBoxGasLimit = ethers.BigNumber.from(400000);

      let gasLimit = ethers.BigNumber.from(amounts[0]).lt("1000000000000000000000") ? silverBoxGasLimit : goldBoxGasLimit;

      if (amounts.length > 1) {
        for (let index = 1; index < amounts.length; index++) {
          const amount = amounts[index];
          gasLimit = gasLimit.add(
            ethers.BigNumber.from(amount).lt("1000000000000000000000") ? silverBoxGasLimit : silverBoxGasLimit
          );
        }
      }

      const processedBoxIds = boxIds.map((id) => {
        return pad0xBegin(id);
      });

      return triggerContractByContractName(
        landId,
        signer,
        "furnaceTakeback",
        "openBoxes",
        [processedBoxIds, amounts, hashmessage, v, r, s],
        callback,
        {
          gasLimit: gasLimit,
        }
      );
    };

    /**
     * Disenchant Equipment and will get elements and material
     * @param landId Land Id
     * @param signer Signer
     * @param equipmentTokenId Id of Equipment
     * @param callback Callback
     * @returns any
     */
    export const furnaceDismantleEquipment = (
      landId: LandId,
      signer: ethers.Signer,
      equipmentTokenId: string,
      callback?: CallbackType
    ): Promise<TransactionResponse> => {
      return triggerContractByContractName(
        landId,
        signer,
        "pveCraft",
        "disenchant",
        [pad0xBegin(equipmentTokenId)],
        callback
      );
    };

    /**
     * Use material and elements tokens in the furnace formula to the equipment.
     * @param landId Land Id
     * @param signer Signer
     * @param equipmentTokenId  Id of Equipment
     * @param tokenContractAddress Element token address
     * @param callback Callback
     * @returns any
     */
    export const furnaceEnchantEquipment = (
      landId: LandId,
      signer: ethers.Signer,
      equipmentTokenId: string,
      tokenContractAddress: string,
      callback?: CallbackType
    ): Promise<TransactionResponse> => {
      return triggerContractByContractName(
        landId,
        signer,
        "pveCraft",
        "enchant",
        [pad0xBegin(equipmentTokenId), tokenContractAddress],
        callback
      );
    };