{"version":3,"sources":["../../src/core/accountAddress.ts"],"sourcesContent":["// Copyright © Aptos Foundation\n// SPDX-License-Identifier: Apache-2.0\n\nimport { bytesToHex, hexToBytes } from \"@noble/hashes/utils\";\nimport { Serializable, Serializer } from \"../bcs/serializer\";\nimport { Deserializer } from \"../bcs/deserializer\";\nimport { ParsingError, ParsingResult } from \"./common\";\nimport { TransactionArgument } from \"../transactions/instances/transactionArgument\";\nimport { HexInput, ScriptTransactionArgumentVariants } from \"../types\";\n\n/**\n * This enum is used to explain why an address was invalid.\n */\nexport enum AddressInvalidReason {\n  INCORRECT_NUMBER_OF_BYTES = \"incorrect_number_of_bytes\",\n  INVALID_HEX_CHARS = \"invalid_hex_chars\",\n  TOO_SHORT = \"too_short\",\n  TOO_LONG = \"too_long\",\n  LEADING_ZERO_X_REQUIRED = \"leading_zero_x_required\",\n  LONG_FORM_REQUIRED_UNLESS_SPECIAL = \"long_form_required_unless_special\",\n  INVALID_PADDING_ZEROES = \"INVALID_PADDING_ZEROES\",\n}\n\nexport type AccountAddressInput = HexInput | AccountAddress;\n\n/**\n * NOTE: Only use this class for account addresses. For other hex data, e.g. transaction\n * hashes, use the Hex class.\n *\n * AccountAddress is used for working with account addresses. Account addresses, when\n * represented as a string, generally look like these examples:\n * - 0x1\n * - 0xaa86fe99004361f747f91342ca13c426ca0cccb0c1217677180c9493bad6ef0c\n *\n * Proper formatting and parsing of account addresses is defined by AIP-40.\n * To learn more about the standard, read the AIP here:\n * https://github.com/aptos-foundation/AIPs/blob/main/aips/aip-40.md.\n *\n * The comments in this class make frequent reference to the LONG and SHORT formats,\n * as well as \"special\" addresses. To learn what these refer to see AIP-40.\n */\nexport class AccountAddress extends Serializable implements TransactionArgument {\n  /**\n   * This is the internal representation of an account address.\n   */\n  readonly data: Uint8Array;\n\n  /**\n   * The number of bytes that make up an account address.\n   */\n  static readonly LENGTH: number = 32;\n\n  /**\n   * The length of an address string in LONG form without a leading 0x.\n   */\n  static readonly LONG_STRING_LENGTH: number = 64;\n\n  static ZERO: AccountAddress = AccountAddress.from(\"0x0\");\n\n  static ONE: AccountAddress = AccountAddress.from(\"0x1\");\n\n  static TWO: AccountAddress = AccountAddress.from(\"0x2\");\n\n  static THREE: AccountAddress = AccountAddress.from(\"0x3\");\n\n  static FOUR: AccountAddress = AccountAddress.from(\"0x4\");\n\n  /**\n   * Creates an instance of AccountAddress from a Uint8Array.\n   *\n   * @param args.data A Uint8Array representing an account address.\n   */\n  constructor(input: Uint8Array) {\n    super();\n    if (input.length !== AccountAddress.LENGTH) {\n      throw new ParsingError(\n        \"AccountAddress data should be exactly 32 bytes long\",\n        AddressInvalidReason.INCORRECT_NUMBER_OF_BYTES,\n      );\n    }\n    this.data = input;\n  }\n\n  /**\n   * Returns whether an address is special, where special is defined as 0x0 to 0xf\n   * inclusive. In other words, the last byte of the address must be < 0b10000 (16)\n   * and every other byte must be zero.\n   *\n   * For more information on how special addresses are defined see AIP-40:\n   * https://github.com/aptos-foundation/AIPs/blob/main/aips/aip-40.md.\n   *\n   * @returns true if the address is special, false if not.\n   */\n  isSpecial(): boolean {\n    return (\n      this.data.slice(0, this.data.length - 1).every((byte) => byte === 0) && this.data[this.data.length - 1] < 0b10000\n    );\n  }\n\n  // ===\n  // Methods for representing an instance of AccountAddress as other types.\n  // ===\n\n  /**\n   * Return the AccountAddress as a string as per AIP-40.\n   * https://github.com/aptos-foundation/AIPs/blob/main/aips/aip-40.md.\n   *\n   * In short, it means that special addresses are represented in SHORT form, meaning\n   * 0x0 through to 0xf inclusive, and every other address is represented in LONG form,\n   * meaning 0x + 64 hex characters.\n   *\n   * @returns AccountAddress as a string conforming to AIP-40.\n   */\n  toString(): `0x${string}` {\n    return `0x${this.toStringWithoutPrefix()}`;\n  }\n\n  /**\n   * NOTE: Prefer to use `toString` where possible.\n   *\n   * Return the AccountAddress as a string as per AIP-40 but without the leading 0x.\n   *\n   * Learn more by reading the docstring of `toString`.\n   *\n   * @returns AccountAddress as a string conforming to AIP-40 but without the leading 0x.\n   */\n  toStringWithoutPrefix(): string {\n    let hex = bytesToHex(this.data);\n    if (this.isSpecial()) {\n      hex = hex[hex.length - 1];\n    }\n    return hex;\n  }\n\n  /**\n   * NOTE: Prefer to use `toString` where possible.\n   *\n   * Whereas toString will format special addresses (as defined by isSpecial) using the\n   * SHORT form (no leading 0s), this format the address in the LONG format\n   * unconditionally.\n   *\n   * This means it will be 0x + 64 hex characters.\n   *\n   * @returns AccountAddress as a string in LONG form.\n   */\n  toStringLong(): `0x${string}` {\n    return `0x${this.toStringLongWithoutPrefix()}`;\n  }\n\n  /**\n   * NOTE: Prefer to use `toString` where possible.\n   *\n   * Whereas toString will format special addresses (as defined by isSpecial) using the\n   * SHORT form (no leading 0s), this function will include leading zeroes. The string\n   * will not have a leading zero.\n   *\n   * This means it will be 64 hex characters without a leading 0x.\n   *\n   * @returns AccountAddress as a string in LONG form without a leading 0x.\n   */\n  toStringLongWithoutPrefix(): string {\n    return bytesToHex(this.data);\n  }\n\n  /**\n   * Get the inner hex data. The inner data is already a Uint8Array so no conversion\n   * is taking place here, it just returns the inner data.\n   *\n   * @returns Hex data as Uint8Array\n   */\n  toUint8Array(): Uint8Array {\n    return this.data;\n  }\n\n  /**\n   * Serialize the AccountAddress to a Serializer instance's data buffer.\n   * @param serializer The serializer to serialize the AccountAddress to.\n   * @returns void\n   * @example\n   * const serializer = new Serializer();\n   * const address = AccountAddress.fromString(\"0x1\");\n   * address.serialize(serializer);\n   * const bytes = serializer.toUint8Array();\n   * // `bytes` is now the BCS-serialized address.\n   */\n  serialize(serializer: Serializer): void {\n    serializer.serializeFixedBytes(this.data);\n  }\n\n  serializeForEntryFunction(serializer: Serializer): void {\n    const bcsBytes = this.bcsToBytes();\n    serializer.serializeBytes(bcsBytes);\n  }\n\n  serializeForScriptFunction(serializer: Serializer): void {\n    serializer.serializeU32AsUleb128(ScriptTransactionArgumentVariants.Address);\n    serializer.serialize(this);\n  }\n\n  /**\n   * Deserialize an AccountAddress from the byte buffer in a Deserializer instance.\n   * @param deserializer The deserializer to deserialize the AccountAddress from.\n   * @returns An instance of AccountAddress.\n   * @example\n   * const bytes = hexToBytes(\"0x0102030405060708091011121314151617181920212223242526272829303132\");\n   * const deserializer = new Deserializer(bytes);\n   * const address = AccountAddress.deserialize(deserializer);\n   * // `address` is now an instance of AccountAddress.\n   */\n  static deserialize(deserializer: Deserializer): AccountAddress {\n    const bytes = deserializer.deserializeFixedBytes(AccountAddress.LENGTH);\n    return new AccountAddress(bytes);\n  }\n\n  // ===\n  // Methods for creating an instance of AccountAddress from other types.\n  // ===\n\n  /**\n   * NOTE: This function has strict parsing behavior. For relaxed behavior, please use\n   * the `fromString` function.\n   *\n   * Creates an instance of AccountAddress from a hex string.\n   *\n   * This function allows only the strictest formats defined by AIP-40. In short this\n   * means only the following formats are accepted:\n   *\n   * - LONG\n   * - SHORT for special addresses\n   *\n   * Where:\n   * - LONG is defined as 0x + 64 hex characters.\n   * - SHORT for special addresses is 0x0 to 0xf inclusive without padding zeroes.\n   *\n   * This means the following are not accepted:\n   * - SHORT for non-special addresses.\n   * - Any address without a leading 0x.\n   *\n   * Learn more about the different address formats by reading AIP-40:\n   * https://github.com/aptos-foundation/AIPs/blob/main/aips/aip-40.md.\n   *\n   * @param input A hex string representing an account address.\n   *\n   * @returns An instance of AccountAddress.\n   */\n  static fromStringStrict(input: string): AccountAddress {\n    // Assert the string starts with 0x.\n    if (!input.startsWith(\"0x\")) {\n      throw new ParsingError(\"Hex string must start with a leading 0x.\", AddressInvalidReason.LEADING_ZERO_X_REQUIRED);\n    }\n\n    const address = AccountAddress.fromString(input);\n\n    // Check if the address is in LONG form. If it is not, this is only allowed for\n    // special addresses, in which case we check it is in proper SHORT form.\n    if (input.length !== AccountAddress.LONG_STRING_LENGTH + 2) {\n      if (!address.isSpecial()) {\n        throw new ParsingError(\n          `The given hex string ${input} is not a special address, it must be represented as 0x + 64 chars.`,\n          AddressInvalidReason.LONG_FORM_REQUIRED_UNLESS_SPECIAL,\n        );\n      } else if (input.length !== 3) {\n        // 0x + one hex char is the only valid SHORT form for special addresses.\n        throw new ParsingError(\n          // eslint-disable-next-line max-len\n          `The given hex string ${input} is a special address not in LONG form, it must be 0x0 to 0xf without padding zeroes.`,\n          AddressInvalidReason.INVALID_PADDING_ZEROES,\n        );\n      }\n    }\n\n    return address;\n  }\n\n  /**\n   * NOTE: This function has relaxed parsing behavior. For strict behavior, please use\n   * the `fromStringStrict` function. Where possible use `fromStringStrict` rather than this\n   * function, `fromString` is only provided for backwards compatibility.\n   *\n   * Creates an instance of AccountAddress from a hex string.\n   *\n   * This function allows all formats defined by AIP-40. In short this means the\n   * following formats are accepted:\n   *\n   * - LONG, with or without leading 0x\n   * - SHORT, with or without leading 0x\n   *\n   * Where:\n   * - LONG is 64 hex characters.\n   * - SHORT is 1 to 63 hex characters inclusive.\n   * - Padding zeroes are allowed, e.g. 0x0123 is valid.\n   *\n   * Learn more about the different address formats by reading AIP-40:\n   * https://github.com/aptos-foundation/AIPs/blob/main/aips/aip-40.md.\n   *\n   * @param input A hex string representing an account address.\n   *\n   * @returns An instance of AccountAddress.\n   */\n  static fromString(input: string): AccountAddress {\n    let parsedInput = input;\n    // Remove leading 0x for parsing.\n    if (input.startsWith(\"0x\")) {\n      parsedInput = input.slice(2);\n    }\n\n    // Ensure the address string is at least 1 character long.\n    if (parsedInput.length === 0) {\n      throw new ParsingError(\n        \"Hex string is too short, must be 1 to 64 chars long, excluding the leading 0x.\",\n        AddressInvalidReason.TOO_SHORT,\n      );\n    }\n\n    // Ensure the address string is not longer than 64 characters.\n    if (parsedInput.length > 64) {\n      throw new ParsingError(\n        \"Hex string is too long, must be 1 to 64 chars long, excluding the leading 0x.\",\n        AddressInvalidReason.TOO_LONG,\n      );\n    }\n\n    let addressBytes: Uint8Array;\n    try {\n      // Pad the address with leading zeroes, so it is 64 chars long and then convert\n      // the hex string to bytes. Every two characters in a hex string constitutes a\n      // single byte. So a 64 length hex string becomes a 32 byte array.\n      addressBytes = hexToBytes(parsedInput.padStart(64, \"0\"));\n    } catch (error: any) {\n      // At this point the only way this can fail is if the hex string contains\n      // invalid characters.\n      throw new ParsingError(`Hex characters are invalid: ${error?.message}`, AddressInvalidReason.INVALID_HEX_CHARS);\n    }\n\n    return new AccountAddress(addressBytes);\n  }\n\n  /**\n   * Convenience method for creating an AccountAddress from all known inputs.\n   *\n   * This handles, Uint8array, string, and AccountAddress itself\n   * @param input\n   */\n  static from(input: AccountAddressInput): AccountAddress {\n    if (input instanceof AccountAddress) {\n      return input;\n    }\n    if (input instanceof Uint8Array) {\n      return new AccountAddress(input);\n    }\n    return AccountAddress.fromString(input);\n  }\n\n  /**\n   * Convenience method for creating an AccountAddress from all known inputs.\n   *\n   * This handles, Uint8array, string, and AccountAddress itself\n   * @param input\n   */\n  static fromStrict(input: AccountAddressInput): AccountAddress {\n    if (input instanceof AccountAddress) {\n      return input;\n    }\n    if (input instanceof Uint8Array) {\n      return new AccountAddress(input);\n    }\n    return AccountAddress.fromStringStrict(input);\n  }\n\n  // ===\n  // Methods for checking validity.\n  // ===\n\n  /**\n   * Check if the string is a valid AccountAddress.\n   *\n   * @param args.input A hex string representing an account address.\n   * @param args.strict If true, use strict parsing behavior. If false, use relaxed parsing behavior.\n   *\n   * @returns valid = true if the string is valid, valid = false if not. If the string\n   * is not valid, invalidReason will be set explaining why it is invalid.\n   */\n  static isValid(args: { input: AccountAddressInput; strict?: boolean }): ParsingResult<AddressInvalidReason> {\n    try {\n      if (args.strict) {\n        AccountAddress.fromStrict(args.input);\n      } else {\n        AccountAddress.from(args.input);\n      }\n      return { valid: true };\n    } catch (error: any) {\n      return {\n        valid: false,\n        invalidReason: error?.invalidReason,\n        invalidReasonMessage: error?.message,\n      };\n    }\n  }\n\n  /**\n   * Return whether AccountAddresses are equal. AccountAddresses are considered equal\n   * if their underlying byte data is identical.\n   *\n   * @param other The AccountAddress to compare to.\n   * @returns true if the AccountAddresses are equal, false if not.\n   */\n  equals(other: AccountAddress): boolean {\n    if (this.data.length !== other.data.length) return false;\n    return this.data.every((value, index) => value === other.data[index]);\n  }\n}\n"],"mappings":"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","names":["bytesToHex","hexToBytes","AddressInvalidReason","_AccountAddress","Serializable","input","ParsingError","byte","hex","bytesToHex","serializer","bcsBytes","deserializer","bytes","address","parsedInput","addressBytes","hexToBytes","error","args","other","value","index","AccountAddress"]}