# land/v1.ts

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

    /**
     * Land Bid With Token
     * @param signer Ethers signer
     * @param landTokenId Land token id
     * @param referrer Referrer
     * @param amount Amount of price in RING token
     * @param callback Callback
     */
    export const landBidWithToken = async (
      landId: LandId,
      signer: ethers.Signer,
      landTokenId: string,
      referrer: string | null,
      amount: string,
      callback?: CallbackType
    ): Promise<TransactionResponse> => {
      const finalReferrer =
        referrer && ethers.utils.isAddress(referrer) ? referrer : "0x0000000000000000000000000000000000000000";

      if (landId === LandId.ETHEREUM || landId === LandId._ETHEREUM) {
        const data = finalReferrer
          ? `${pad0xBegin(landTokenId)}${ethers.utils.hexZeroPad(finalReferrer, 32).slice(2)}`
          : pad0xBegin(landTokenId);

        const addresses = getAddressesByLandId(landId);
        if (!addresses || !addresses.LAND_CLOCK_AUCTION) {
          throw "address error";
        }

        return triggerContractByContractName(
          landId,
          signer,
          "ring",
          "transfer(address,uint256,bytes)",
          [addresses.LAND_CLOCK_AUCTION, amount, data],
          callback
        );
      }

      return triggerContractByContractName(
        landId,
        signer,
        "landClockAuctionV3",
        "bidWithToken",
        [pad0xBegin(landTokenId), finalReferrer, amount],
        callback
      );
    };

    /**
     * Land Available Resources
     * @param provider Ethers provider
     * @param tokenId Token id
     * @param resources Resources
     * @param callback Callback
     * @returns String[]
     */
    export const landGetAvailableResources = async (
      landId: LandId,
      provider: ethers.providers.Provider,
      tokenId: string,
      resources: string[],
      callback?: CallbackType
    ): Promise<string[]> => {
      const addresses = getAddressesByLandId(landId);
      if (!addresses) {
        return [];
      }

      const finalRes = resources.length
        ? [...resources]
        : [
            addresses.ELEMENT_GOLD,
            addresses.ELEMENT_WOOD,
            addresses.ELEMENT_WATER,
            addresses.ELEMENT_FIRE,
            addresses.ELEMENT_SOIL,
          ];
      const results = await viewContractByContractName(
        landId,
        provider,
        "apostleLandResource",
        "availableLandResources",
        [pad0xBegin(tokenId), finalRes],
        callback
      );
      return results[0].map((res: ethers.BigNumber[]) => {
        return res.toString();
      });
    };

    /**
     * Land Batch Claim Land Resource
     * @param signer Ethers signer
     * @param tokenIds Token ids
     * @param callback Callback
     */
    export const landBatchClaimLandResource = (
      landId: LandId,
      signer: ethers.Signer,
      tokenIds: string[],
      callback?: CallbackType
    ): Promise<TransactionResponse> => {
      return triggerContractByContractName(
        landId,
        signer,
        "apostleLandResource",
        "batchClaimLandResource",
        [tokenIds.map((tokenId) => pad0xBegin(tokenId))],
        callback
      );
    };

    /**
     * Returns the current price of an auction.
     * @param provider Ethers signer
     * @param tokenId Token Id
     * @param callback Callback
     * @returns any
     */
    export const landGetCurrentPriceByTokenId = async (
      landId: LandId,
      provider: ethers.providers.Provider,
      tokenId: string,
      callback?: CallbackType
    ): Promise<string> => {
      const results = await viewContractByContractName(
        landId,
        provider,
        "landClockAuctionV3",
        "getCurrentPriceInToken",
        [pad0xBegin(tokenId)],
        callback
      );
      return (results[0] as ethers.BigNumber).toHexString();
    };

    /**
     * Sell land asset
     * @param signer Ethers signer
     * @param from
     * @param tokenId - Land tokenId
     * @param start - start price
     * @param end - end price
     * @param duration - bid duration time in second
     * @param callback Callback
     * @returns {Promise<void>}
     */
    export const landAskWithToken = (
      landId: LandId,
      signer: ethers.Signer,
      from: string,
      tokenId: string,
      startPrice: string,
      endPrice: string,
      duration: string,
      callback?: CallbackType
    ): Promise<TransactionResponse> => {
      const _from = padLeft(from.slice(2), 64, "0");
      const _start = toHexAndPadLeft(startPrice).slice(2);
      const _end = toHexAndPadLeft(endPrice).slice(2);
      const _duration = toHexAndPadLeft(duration).slice(2);
      const data = `0x${_start}${_end}${_duration}${_from}`;
      const landClockAuctionContract = getContractAddressAndAbiByContractName(landId, signer, "landClockAuctionV3");

      return triggerContractByContractName(
        landId,
        signer,
        "objectOwnership",
        "approveAndCall",
        [landClockAuctionContract.address, pad0xBegin(tokenId), data],
        callback
      );
    };

    /**
     * Cancel a land auction.
     * @param landId Land Id
     * @param signer Signer
     * @param tokenId Id of the Land
     * @param callback Callback
     * @returns any
     */
    export const landCancelAskWithToken = (
      landId: LandId,
      signer: ethers.Signer,
      tokenId: string,
      callback?: CallbackType
    ): Promise<TransactionResponse> => {
      return triggerContractByContractName(
        landId,
        signer,
        "landClockAuctionV3",
        "cancelAuction",
        [pad0xBegin(tokenId)],
        callback
      );
    };

    /**
     * Get Avaliable item resources.
     * @param landId Land Id
     * @param provider Provider
     * @param porpsContractAddress Item contract address
     * @param tokenId Id of item
     * @param resourcesContractAddress Array of resources contract address
     * @param callback Callback
     * @returns any
     */
    export const landGetAvailableItemResources = async (
      landId: LandId,
      provider: ethers.providers.Provider,
      porpsContractAddress: string,
      tokenId: string,
      resourcesContractAddress: string[],
      callback?: CallbackType
    ): Promise<string[]> => {
      const results = await viewContractByContractName(
        landId,
        provider,
        "apostleLandResource",
        "availableItemResources",
        [porpsContractAddress, pad0xBegin(tokenId), resourcesContractAddress],
        callback
      );

      return results[0].map((res: ethers.BigNumber) => res.toString());
    };

    /**
     * Batch claim item resource.
     * @param landId Land Id
     * @param signer Signer
     * @param drillContractAddress drill contract address
     * @param tokenIds Array of drill token Ids
     * @param callback Callback
     * @returns any
     */
    export const landBatchClaimItemResource = (
      landId: LandId,
      signer: ethers.Signer,
      drillContractAddress: string[],
      tokenIds: string[],
      callback?: CallbackType
    ): Promise<TransactionResponse> => {
      return triggerContractByContractName(
        landId,
        signer,
        "apostleLandResourceV2",
        "batchClaimItemResource",
        [drillContractAddress, tokenIds.map((tokenId) => pad0xBegin(tokenId))],
        callback
      );
    };

    /**
     * Claim item resource.
     * @param landId Land Id
     * @param signer Signer
     * @param drillContractAddress Drill contract address
     * @param tokenId Token Id
     * @param callback Callback
     * @returns any
     */
    export const landClaimItemResource = (
      landId: LandId,
      signer: ethers.Signer,
      drillContractAddress: string,
      tokenId: string,
      callback?: CallbackType
    ): Promise<TransactionResponse> => {
      return triggerContractByContractName(
        landId,
        signer,
        "apostleLandResource",
        "claimItemResource",
        [drillContractAddress, pad0xBegin(tokenId)],
        callback
      );
    };

    /**
     * Transfer land
     * @param landId Land Id
     * @param signer Signer
     * @param from Land owner
     * @param to Recipient
     * @param tokenId Token Id
     * @param callback Callback
     * @returns any
     */
    export const landTransfer = (
      landId: LandId,
      signer: ethers.Signer,
      from: string,
      to: string,
      tokenId: string,
      callback?: CallbackType
    ): Promise<TransactionResponse> => {
      return triggerContractByContractName(
        landId,
        signer,
        "objectOwnership",
        "transferFrom",
        [from, to, pad0xBegin(tokenId)],
        callback
      );
    };

    /**
     * Claim land asset
     * @param landId Land Id
     * @param signer Signer
     * @param landTokenId Land token Id
     * @param callback Callback
     * @returns any
     */
    export const landClaimLand = (
      landId: LandId,
      signer: ethers.Signer,
      landTokenId: string,
      callback?: CallbackType
    ): Promise<TransactionResponse> => {
      return triggerContractByContractName(
        landId,
        signer,
        "landClockAuctionV3",
        "claimLandAsset",
        [pad0xBegin(landTokenId)],
        callback
      );
    };