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
  );
};