{"version":3,"sources":["../../src/utils/helpers.ts"],"sourcesContent":["// Copyright © Aptos Foundation\n// SPDX-License-Identifier: Apache-2.0\n\nimport { Base64, decode } from \"js-base64\";\nimport { MoveFunctionId, MoveStructId } from \"../types\";\nimport { AccountAddress } from \"../core/accountAddress\";\nimport { createObjectAddress } from \"../core/account/utils/address\";\n\n/**\n * Checks if the current runtime environment is Bun.\n * This is useful for detecting Bun-specific compatibility issues.\n *\n * @returns true if running in Bun, false otherwise.\n * @group Implementation\n * @category Utils\n */\nexport function isBun(): boolean {\n  try {\n    // Bun exposes a global `Bun` object.\n    return typeof globalThis !== \"undefined\" && \"Bun\" in globalThis;\n  } catch {\n    return false;\n  }\n}\n\n/**\n * Logs a warning message to the console only in development environments.\n * This function helps reduce information leakage in production while maintaining\n * helpful warnings during development.\n *\n * @param message - The warning message to log.\n * @group Implementation\n * @category Utils\n */\nexport function warnIfDevelopment(message: string): void {\n  // Check common environment variables to determine if we're in development\n  // This works in Node.js, bundlers like webpack/vite, and most build systems\n  const isDevelopment =\n    typeof process !== \"undefined\" &&\n    process.env &&\n    (process.env.NODE_ENV === \"development\" ||\n      process.env.NODE_ENV === \"test\" ||\n      process.env.APTOS_SDK_WARNINGS === \"true\");\n\n  if (isDevelopment) {\n    console.warn(message);\n  }\n}\n\n/**\n * Sleep for the specified amount of time in milliseconds.\n * This function can be used to introduce delays in asynchronous operations.\n *\n * @param timeMs - The time in milliseconds to sleep.\n * @group Implementation\n * @category Utils\n */\nexport async function sleep(timeMs: number): Promise<null> {\n  return new Promise((resolve) => {\n    setTimeout(resolve, timeMs);\n  });\n}\n\n/**\n * Get the error message from an unknown error.\n *\n * @param error The error to get the message from\n * @returns The error message\n * @group Implementation\n * @category Utils\n */\nexport function getErrorMessage(error: unknown): string {\n  return error instanceof Error ? error.message : String(error);\n}\n\n/**\n * @group Implementation\n * @category Utils\n */\nexport const nowInSeconds = () => Math.floor(Date.now() / 1000);\n\n/**\n * Floors the given timestamp to the nearest whole hour.\n * This function is useful for normalizing timestamps to hourly intervals.\n *\n * @param timestampInSeconds - The timestamp in seconds to be floored.\n * @group Implementation\n * @category Utils\n */\nexport function floorToWholeHour(timestampInSeconds: number): number {\n  const date = new Date(timestampInSeconds * 1000);\n  // Reset minutes and seconds to zero\n  date.setMinutes(0);\n  date.setSeconds(0);\n  date.setMilliseconds(0);\n  return Math.floor(date.getTime() / 1000);\n}\n\n/**\n * Decodes a base64 URL-encoded string into its original form.\n * This function is useful for converting base64 URL-encoded data back to a readable format.\n *\n * @param base64Url - The base64 URL-encoded string to decode.\n * @returns The decoded string.\n * @group Implementation\n * @category Utils\n */\nexport function base64UrlDecode(base64Url: string): string {\n  // Replace base64url-specific characters\n  const base64 = base64Url.replace(/-/g, \"+\").replace(/_/g, \"/\");\n  // Pad the string with '=' characters if needed\n  const paddedBase64 = base64 + \"==\".substring(0, (3 - (base64.length % 3)) % 3);\n  const decodedString = decode(paddedBase64);\n  return decodedString;\n}\n\nexport function base64UrlToBytes(base64Url: string): Uint8Array {\n  // Convert Base64Url to Base64\n  let base64 = base64Url.replace(/-/g, \"+\").replace(/_/g, \"/\");\n  // Add padding if needed\n  while (base64.length % 4 !== 0) {\n    base64 += \"=\";\n  }\n  // Use js-base64 to convert base64 to Uint8Array\n  return Base64.toUint8Array(base64);\n}\n\n/**\n * Amount is represented in the smallest unit format on chain, this function converts\n * a human-readable amount format to the smallest unit format\n * @example\n * human-readable amount format: 500\n * on chain amount format when decimal is 8: 50000000000\n *\n * @param value The value in human-readable format\n * @param decimal The token decimal\n * @returns The value in the smallest units\n * @group Implementation\n * @category Utils\n */\nexport const convertAmountFromHumanReadableToOnChain = (value: number, decimal: number) => value * 10 ** decimal;\n\n/**\n * Amount is represented in the smallest unit format on chain, this function converts\n * the smallest unit format to a human-readable amount format\n * @example\n * human-readable amount format: 500\n * on chain amount format when decimal is 8: 50000000000\n *\n * @param value The value in human-readable format\n * @param decimal The token decimal\n * @returns The value in the smallest units\n * @group Implementation\n * @category Utils\n */\nexport const convertAmountFromOnChainToHumanReadable = (value: number, decimal: number) => value / 10 ** decimal;\n\n/**\n * Convert a hex string to an ascii string with the `0x` prefix.\n *\n * `0x6170746f735f636f696e` --> `aptos_coin`\n *\n * @param hex The hex string to convert (e.g. `0x6170746f735f636f696e`)\n * @returns The ascii string\n * @group Implementation\n * @category Utils\n */\nconst hexToAscii = (hex: string) => {\n  let str = \"\";\n  for (let n = 2; n < hex.length; n += 2) {\n    str += String.fromCharCode(parseInt(hex.substring(n, n + 2), 16));\n  }\n  return str;\n};\n\n/**\n * Convert an encoded struct to a MoveStructId.\n *\n * @example\n * const structObj = {\n *   account_address: \"0x1\",\n *   module_name: \"0x6170746f735f636f696e\",\n *   struct_name: \"0x4170746f73436f696e\",\n * };\n * // structId is \"0x1::aptos_coin::AptosCoin\"\n * const structId = parseEncodedStruct(structObj);\n *\n * @param structObj The struct with account_address, module_name, and struct_name properties\n * @returns The MoveStructId\n * @group Implementation\n * @category Utils\n */\nexport const parseEncodedStruct = (structObj: {\n  account_address: string;\n  module_name: string;\n  struct_name: string;\n}): MoveStructId => {\n  const { account_address, module_name, struct_name } = structObj;\n  const moduleName = hexToAscii(module_name);\n  const structName = hexToAscii(struct_name);\n  return `${account_address}::${moduleName}::${structName}`;\n};\n\n/**\n * Determines whether the given object is an encoded struct type with the following properties:\n * - account_address: string\n * - module_name: string\n * - struct_name: string\n *\n * @param structObj The object to check\n * @returns Whether the object is an encoded struct type\n * @group Implementation\n * @category Utils\n */\nexport const isEncodedStruct = (\n  structObj: any,\n): structObj is {\n  account_address: string;\n  module_name: string;\n  struct_name: string;\n} =>\n  typeof structObj === \"object\" &&\n  !Array.isArray(structObj) &&\n  structObj !== null &&\n  \"account_address\" in structObj &&\n  \"module_name\" in structObj &&\n  \"struct_name\" in structObj &&\n  typeof structObj.account_address === \"string\" &&\n  typeof structObj.module_name === \"string\" &&\n  typeof structObj.struct_name === \"string\";\n\n/**\n * Splits a function identifier into its constituent parts: module address, module name, and function name.\n * This function helps in validating and extracting details from a function identifier string.\n *\n * @param functionArg - The function identifier string in the format \"moduleAddress::moduleName::functionName\".\n * @returns An object containing the module address, module name, and function name.\n * @throws Error if the function identifier does not contain exactly three parts.\n * @group Implementation\n * @category Transactions\n */\nexport function getFunctionParts(functionArg: MoveFunctionId) {\n  const funcNameParts = functionArg.split(\"::\");\n  if (funcNameParts.length !== 3) {\n    throw new Error(`Invalid function ${functionArg}`);\n  }\n  const moduleAddress = funcNameParts[0];\n  const moduleName = funcNameParts[1];\n  const functionName = funcNameParts[2];\n  return { moduleAddress, moduleName, functionName };\n}\n\n/**\n * Validates the provided function information.\n *\n * @param functionInfo - The function information to validate.\n * @returns Whether the function information is valid.\n * @group Implementation\n * @category Utils\n */\nexport function isValidFunctionInfo(functionInfo: string): boolean {\n  const parts = functionInfo.split(\"::\");\n  return parts.length === 3 && AccountAddress.isValid({ input: parts[0] }).valid;\n}\n\n/**\n * Truncates the provided wallet address at the middle with an ellipsis.\n *\n * @param address - The wallet address to truncate.\n * @param start - The number of characters to show at the beginning of the address.\n * @param end - The number of characters to show at the end of the address.\n * @returns The truncated address.\n * @group Implementation\n * @category Utils\n */\nexport function truncateAddress(address: string, start: number = 6, end: number = 5) {\n  return `${address.slice(0, start)}...${address.slice(-end)}`;\n}\n\n/**\n * Constants for metadata address calculation\n */\nconst APTOS_COIN_TYPE_STR = \"0x1::aptos_coin::AptosCoin\";\n\n/**\n * Helper function to standardize Move type string by converting all addresses to short form,\n * including addresses within nested type parameters\n */\nfunction standardizeMoveTypeString(input: string): string {\n  // Regular expression to match addresses in the type string, including those within type parameters\n  // This regex matches \"0x\" followed by hex digits, handling both standalone addresses and those within <>\n  const addressRegex = /0x[0-9a-fA-F]+/g;\n\n  return input.replace(addressRegex, (match) =>\n    // Use AccountAddress to handle the address\n    AccountAddress.from(match, { maxMissingChars: 63 }).toStringShort(),\n  );\n}\n\n/**\n * Calculates the paired FA metadata address for a given coin type.\n * This function is tolerant of various address formats in the coin type string,\n * including complex nested types.\n *\n * @example\n * // All these formats are valid and will produce the same result:\n * pairedFaMetadataAddress(\"0x1::aptos_coin::AptosCoin\")  // simple form\n * pairedFaMetadataAddress(\"0x0000000000000000000000000000000000000000000000000000000000000001::aptos_coin::AptosCoin\")  // long form\n * pairedFaMetadataAddress(\"0x00001::aptos_coin::AptosCoin\")  // with leading zeros\n * pairedFaMetadataAddress(\"0x1::coin::Coin<0x1412::a::struct<0x0001::aptos_coin::AptosCoin>>\")  // nested type parameters\n *\n * @param coinType - The coin type string in any of these formats:\n *   - Short form address: \"0x1::aptos_coin::AptosCoin\"\n *   - Long form address: \"0x0000000000000000000000000000000000000000000000000000000000000001::aptos_coin::AptosCoin\"\n *   - With leading zeros: \"0x00001::aptos_coin::AptosCoin\"\n *   - With nested types: \"0x1::coin::Coin<0x1412::a::struct<0x0001::aptos_coin::AptosCoin>>\"\n * @returns The calculated metadata address as an AccountAddress instance\n */\nexport function pairedFaMetadataAddress(coinType: `0x${string}::${string}::${string}`): AccountAddress {\n  // Standardize the coin type string to handle any address format\n  const standardizedMoveTypeName = standardizeMoveTypeString(coinType);\n\n  return standardizedMoveTypeName === APTOS_COIN_TYPE_STR\n    ? AccountAddress.A\n    : createObjectAddress(AccountAddress.A, standardizedMoveTypeName);\n}\n"],"mappings":"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","names":["Base64","decode","isBun","warnIfDevelopment","message","sleep","timeMs","resolve","getErrorMessage","error","nowInSeconds","floorToWholeHour","timestampInSeconds","date","base64UrlDecode","base64Url","base64","paddedBase64","decode","base64UrlToBytes","Base64","convertAmountFromHumanReadableToOnChain","value","decimal","convertAmountFromOnChainToHumanReadable","hexToAscii","hex","str","n","parseEncodedStruct","structObj","account_address","module_name","struct_name","moduleName","structName","isEncodedStruct","getFunctionParts","functionArg","funcNameParts","moduleAddress","functionName","isValidFunctionInfo","functionInfo","parts","AccountAddress","truncateAddress","address","start","end","APTOS_COIN_TYPE_STR","standardizeMoveTypeString","input","addressRegex","match","pairedFaMetadataAddress","coinType","standardizedMoveTypeName","createObjectAddress"]}