{"version":3,"sources":["../src/hdwallet.ts"],"sourcesContent":["import { ErrorCode, FuelError } from '@fuel-ts/errors';\nimport { bn, toBytes, toHex } from '@fuel-ts/math';\nimport { Mnemonic } from '@fuel-ts/mnemonic';\nimport { Signer } from '@fuel-ts/signer';\nimport type { BytesLike } from 'ethers';\nimport {\n  toBeHex,\n  dataSlice,\n  hexlify,\n  encodeBase58,\n  decodeBase58,\n  sha256,\n  computeHmac,\n  ripemd160,\n  getBytesCopy,\n  concat,\n} from 'ethers';\n\n// \"Bitcoin seed\"\nconst HARDENED_INDEX = 0x80000000;\n\n// 4 byte: version bytes (mainnet: 0x0488B21E public, 0x0488ADE4 private; testnet: 0x043587CF public, 0x04358394 private)\nconst MainnetPRV = hexlify('0x0488ade4');\nconst MainnetPUB = hexlify('0x0488b21e');\nconst TestnetPRV = hexlify('0x04358394');\nconst TestnetPUB = hexlify('0x043587cf');\n\nfunction base58check(data: Uint8Array): string {\n  return encodeBase58(concat([data, dataSlice(sha256(sha256(data)), 0, 4)]));\n}\n\nfunction getExtendedKeyPrefix(isPublic: boolean = false, testnet: boolean = false) {\n  if (isPublic) {\n    return testnet ? TestnetPUB : MainnetPUB;\n  }\n  return testnet ? TestnetPRV : MainnetPRV;\n}\n\nfunction isPublicExtendedKey(extendedKey: Uint8Array) {\n  return [MainnetPUB, TestnetPUB].includes(hexlify(extendedKey.slice(0, 4)));\n}\n\nfunction isValidExtendedKey(extendedKey: Uint8Array) {\n  return [MainnetPRV, TestnetPRV, MainnetPUB, TestnetPUB].includes(\n    hexlify(extendedKey.slice(0, 4))\n  );\n}\n\nfunction parsePath(path: string, depth: number = 0) {\n  const components = path.split('/');\n\n  if (components.length === 0 || (components[0] === 'm' && depth !== 0)) {\n    throw new FuelError(ErrorCode.HD_WALLET_ERROR, `invalid path - ${path}`);\n  }\n\n  if (components[0] === 'm') {\n    components.shift();\n  }\n\n  return components.map((p) =>\n    ~p.indexOf(`'`) ? parseInt(p, 10) + HARDENED_INDEX : parseInt(p, 10)\n  );\n}\n\ntype HDWalletConfig = {\n  privateKey?: BytesLike;\n  publicKey?: BytesLike;\n  chainCode: BytesLike;\n  depth?: number;\n  index?: number;\n  parentFingerprint?: string;\n};\n\nclass HDWallet {\n  depth: number = 0;\n  index: number = 0;\n  fingerprint: string = hexlify('0x00000000');\n  parentFingerprint: string = hexlify('0x00000000');\n  privateKey?: string;\n  publicKey: string;\n  chainCode: BytesLike;\n\n  /**\n   * HDWallet is a implementation of the BIP-0044 and BIP-0032, Multi-Account Hierarchy for Deterministic Wallets\n   *\n   * @param config - Wallet configurations\n   */\n  constructor(config: HDWalletConfig) {\n    // TODO: set some asserts here\n\n    if (config.privateKey) {\n      const signer = new Signer(config.privateKey);\n      this.publicKey = hexlify(signer.compressedPublicKey);\n      this.privateKey = hexlify(config.privateKey);\n    } else {\n      if (!config.publicKey) {\n        throw new FuelError(\n          ErrorCode.HD_WALLET_ERROR,\n          'Both public and private Key cannot be missing. At least one should be provided.'\n        );\n      }\n      this.publicKey = hexlify(config.publicKey);\n    }\n\n    this.parentFingerprint = config.parentFingerprint || this.parentFingerprint;\n    this.fingerprint = dataSlice(ripemd160(sha256(this.publicKey)), 0, 4);\n    this.depth = config.depth || this.depth;\n    this.index = config.index || this.index;\n    this.chainCode = config.chainCode;\n  }\n\n  get extendedKey() {\n    return this.toExtendedKey();\n  }\n\n  /**\n   * Derive the current HDWallet instance navigating only on the index.\n   * `Ex.: m/44'/0 -> Ex.: m/44'/1 -> m/44'/2`. [Learn more](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)\n   *\n   * @param index - Index of the child HDWallet.\n   * @returns A new instance of HDWallet on the derived index\n   */\n  deriveIndex(index: number) {\n    const privateKey = this.privateKey && getBytesCopy(this.privateKey);\n    const publicKey = getBytesCopy(this.publicKey);\n    const chainCode = getBytesCopy(this.chainCode);\n    const data = new Uint8Array(37);\n\n    if (index & HARDENED_INDEX) {\n      if (!privateKey) {\n        throw new FuelError(\n          ErrorCode.HD_WALLET_ERROR,\n          'Cannot derive a hardened index without a private Key.'\n        );\n      }\n\n      // 33 bytes: 0x00 || private key\n      data.set(privateKey, 1);\n    } else {\n      data.set(getBytesCopy(this.publicKey));\n    }\n\n    // child number: ser32(i)\n    data.set(toBytes(index, 4), 33);\n\n    const bytes = getBytesCopy(computeHmac('sha512', chainCode, data));\n    const IL = bytes.slice(0, 32);\n    const IR = bytes.slice(32);\n\n    if (privateKey) {\n      const N = '0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141';\n      // Child key ki is parse256(IL) + kpar (mod n).\n      const ki = bn(IL).add(privateKey).mod(N).toBytes(32);\n\n      return new HDWallet({\n        privateKey: ki,\n        chainCode: IR,\n        index,\n        depth: this.depth + 1,\n        parentFingerprint: this.fingerprint,\n      });\n    }\n\n    const signer = new Signer(hexlify(IL));\n    const Ki = signer.addPoint(publicKey);\n\n    return new HDWallet({\n      publicKey: Ki,\n      chainCode: IR,\n      index,\n      depth: this.depth + 1,\n      parentFingerprint: this.fingerprint,\n    });\n  }\n\n  /**\n   * Derive the current HDWallet instance to the path. [Learn more](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)\n   *\n   * @param path - The string representation of the child HDWallet. `Ex.: m/44'/0'/0'/0/0`\n   * @returns A new instance of HDWallet on the derived path\n   */\n  derivePath(path: string) {\n    const paths = parsePath(path, this.depth);\n\n    return paths.reduce((hdwallet, index) => hdwallet.deriveIndex(index), <HDWallet>this);\n  }\n\n  /**\n   * Get the extendKey as defined on BIP-32 from the provided seed\n   *\n   * @param isPublic - enable to export public extendedKey, it not required when HDWallet didn't have the privateKey.\n   * @param testnet - Inform if should use testnet or mainnet prefix, default value is true (`mainnet`).\n   * @returns BIP-32 extended private key\n   */\n  toExtendedKey(isPublic: boolean = false, testnet: boolean = false): string {\n    if (this.depth >= 256) {\n      throw new FuelError(\n        ErrorCode.HD_WALLET_ERROR,\n        `Exceeded max depth of 255. Current depth: ${this.depth}.`\n      );\n    }\n    const prefix = getExtendedKeyPrefix(this.privateKey == null || isPublic, testnet);\n    const depth = hexlify(Uint8Array.from([this.depth]));\n    const parentFingerprint = this.parentFingerprint;\n    const index = toHex(this.index, 4);\n    // last 32 bites from the key\n    const chainCode = this.chainCode;\n    // first 32 bites from the key\n    const key =\n      this.privateKey != null && !isPublic ? concat(['0x00', this.privateKey]) : this.publicKey;\n    const extendedKey = getBytesCopy(\n      concat([prefix, depth, parentFingerprint, index, chainCode, key])\n    );\n\n    return base58check(extendedKey);\n  }\n\n  /**\n   * Create HDWallet instance from seed\n   *\n   * @param seed - Seed\n   * @returns A new instance of HDWallet\n   */\n  static fromSeed(seed: string) {\n    const masterKey = Mnemonic.masterKeysFromSeed(seed);\n\n    return new HDWallet({\n      chainCode: getBytesCopy(masterKey.slice(32)),\n      privateKey: getBytesCopy(masterKey.slice(0, 32)),\n    });\n  }\n\n  static fromExtendedKey(extendedKey: string) {\n    const decoded = toBeHex(decodeBase58(extendedKey));\n    const bytes = getBytesCopy(decoded);\n    const validChecksum = base58check(bytes.slice(0, 78)) === extendedKey;\n\n    if (bytes.length !== 82 || !isValidExtendedKey(bytes)) {\n      throw new FuelError(ErrorCode.HD_WALLET_ERROR, 'Provided key is not a valid extended key.');\n    }\n    if (!validChecksum) {\n      throw new FuelError(ErrorCode.HD_WALLET_ERROR, 'Provided key has an invalid checksum.');\n    }\n\n    const depth = bytes[4];\n    const parentFingerprint = hexlify(bytes.slice(5, 9));\n    const index = parseInt(hexlify(bytes.slice(9, 13)).substring(2), 16);\n    const chainCode = hexlify(bytes.slice(13, 45));\n    const key = bytes.slice(45, 78);\n\n    if ((depth === 0 && parentFingerprint !== '0x00000000') || (depth === 0 && index !== 0)) {\n      throw new FuelError(\n        ErrorCode.HD_WALLET_ERROR,\n        'Inconsistency detected: Depth is zero but fingerprint/index is non-zero.'\n      );\n    }\n\n    if (isPublicExtendedKey(bytes)) {\n      if (key[0] !== 3) {\n        throw new FuelError(ErrorCode.HD_WALLET_ERROR, 'Invalid public extended key.');\n      }\n\n      return new HDWallet({\n        publicKey: key,\n        chainCode,\n        index,\n        depth,\n        parentFingerprint,\n      });\n    }\n\n    if (key[0] !== 0) {\n      throw new FuelError(ErrorCode.HD_WALLET_ERROR, 'Invalid private extended key.');\n    }\n\n    return new HDWallet({\n      privateKey: key.slice(1),\n      chainCode,\n      index,\n      depth,\n      parentFingerprint,\n    });\n  }\n}\n\nexport default HDWallet;\n"],"mappings":";AAAA,SAAS,WAAW,iBAAiB;AACrC,SAAS,IAAI,SAAS,aAAa;AACnC,SAAS,gBAAgB;AACzB,SAAS,cAAc;AAEvB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAGP,IAAM,iBAAiB;AAGvB,IAAM,aAAa,QAAQ,YAAY;AACvC,IAAM,aAAa,QAAQ,YAAY;AACvC,IAAM,aAAa,QAAQ,YAAY;AACvC,IAAM,aAAa,QAAQ,YAAY;AAEvC,SAAS,YAAY,MAA0B;AAC7C,SAAO,aAAa,OAAO,CAAC,MAAM,UAAU,OAAO,OAAO,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;AAC3E;AAEA,SAAS,qBAAqB,WAAoB,OAAO,UAAmB,OAAO;AACjF,MAAI,UAAU;AACZ,WAAO,UAAU,aAAa;AAAA,EAChC;AACA,SAAO,UAAU,aAAa;AAChC;AAEA,SAAS,oBAAoB,aAAyB;AACpD,SAAO,CAAC,YAAY,UAAU,EAAE,SAAS,QAAQ,YAAY,MAAM,GAAG,CAAC,CAAC,CAAC;AAC3E;AAEA,SAAS,mBAAmB,aAAyB;AACnD,SAAO,CAAC,YAAY,YAAY,YAAY,UAAU,EAAE;AAAA,IACtD,QAAQ,YAAY,MAAM,GAAG,CAAC,CAAC;AAAA,EACjC;AACF;AAEA,SAAS,UAAU,MAAc,QAAgB,GAAG;AAClD,QAAM,aAAa,KAAK,MAAM,GAAG;AAEjC,MAAI,WAAW,WAAW,KAAM,WAAW,CAAC,MAAM,OAAO,UAAU,GAAI;AACrE,UAAM,IAAI,UAAU,UAAU,iBAAiB,kBAAkB,MAAM;AAAA,EACzE;AAEA,MAAI,WAAW,CAAC,MAAM,KAAK;AACzB,eAAW,MAAM;AAAA,EACnB;AAEA,SAAO,WAAW;AAAA,IAAI,CAAC,MACrB,CAAC,EAAE,QAAQ,GAAG,IAAI,SAAS,GAAG,EAAE,IAAI,iBAAiB,SAAS,GAAG,EAAE;AAAA,EACrE;AACF;AAWA,IAAM,WAAN,MAAe;AAAA,EACb,QAAgB;AAAA,EAChB,QAAgB;AAAA,EAChB,cAAsB,QAAQ,YAAY;AAAA,EAC1C,oBAA4B,QAAQ,YAAY;AAAA,EAChD;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAY,QAAwB;AAGlC,QAAI,OAAO,YAAY;AACrB,YAAM,SAAS,IAAI,OAAO,OAAO,UAAU;AAC3C,WAAK,YAAY,QAAQ,OAAO,mBAAmB;AACnD,WAAK,aAAa,QAAQ,OAAO,UAAU;AAAA,IAC7C,OAAO;AACL,UAAI,CAAC,OAAO,WAAW;AACrB,cAAM,IAAI;AAAA,UACR,UAAU;AAAA,UACV;AAAA,QACF;AAAA,MACF;AACA,WAAK,YAAY,QAAQ,OAAO,SAAS;AAAA,IAC3C;AAEA,SAAK,oBAAoB,OAAO,qBAAqB,KAAK;AAC1D,SAAK,cAAc,UAAU,UAAU,OAAO,KAAK,SAAS,CAAC,GAAG,GAAG,CAAC;AACpE,SAAK,QAAQ,OAAO,SAAS,KAAK;AAClC,SAAK,QAAQ,OAAO,SAAS,KAAK;AAClC,SAAK,YAAY,OAAO;AAAA,EAC1B;AAAA,EAEA,IAAI,cAAc;AAChB,WAAO,KAAK,cAAc;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,YAAY,OAAe;AACzB,UAAM,aAAa,KAAK,cAAc,aAAa,KAAK,UAAU;AAClE,UAAM,YAAY,aAAa,KAAK,SAAS;AAC7C,UAAM,YAAY,aAAa,KAAK,SAAS;AAC7C,UAAM,OAAO,IAAI,WAAW,EAAE;AAE9B,QAAI,QAAQ,gBAAgB;AAC1B,UAAI,CAAC,YAAY;AACf,cAAM,IAAI;AAAA,UACR,UAAU;AAAA,UACV;AAAA,QACF;AAAA,MACF;AAGA,WAAK,IAAI,YAAY,CAAC;AAAA,IACxB,OAAO;AACL,WAAK,IAAI,aAAa,KAAK,SAAS,CAAC;AAAA,IACvC;AAGA,SAAK,IAAI,QAAQ,OAAO,CAAC,GAAG,EAAE;AAE9B,UAAM,QAAQ,aAAa,YAAY,UAAU,WAAW,IAAI,CAAC;AACjE,UAAM,KAAK,MAAM,MAAM,GAAG,EAAE;AAC5B,UAAM,KAAK,MAAM,MAAM,EAAE;AAEzB,QAAI,YAAY;AACd,YAAM,IAAI;AAEV,YAAM,KAAK,GAAG,EAAE,EAAE,IAAI,UAAU,EAAE,IAAI,CAAC,EAAE,QAAQ,EAAE;AAEnD,aAAO,IAAI,SAAS;AAAA,QAClB,YAAY;AAAA,QACZ,WAAW;AAAA,QACX;AAAA,QACA,OAAO,KAAK,QAAQ;AAAA,QACpB,mBAAmB,KAAK;AAAA,MAC1B,CAAC;AAAA,IACH;AAEA,UAAM,SAAS,IAAI,OAAO,QAAQ,EAAE,CAAC;AACrC,UAAM,KAAK,OAAO,SAAS,SAAS;AAEpC,WAAO,IAAI,SAAS;AAAA,MAClB,WAAW;AAAA,MACX,WAAW;AAAA,MACX;AAAA,MACA,OAAO,KAAK,QAAQ;AAAA,MACpB,mBAAmB,KAAK;AAAA,IAC1B,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,WAAW,MAAc;AACvB,UAAM,QAAQ,UAAU,MAAM,KAAK,KAAK;AAExC,WAAO,MAAM,OAAO,CAAC,UAAU,UAAU,SAAS,YAAY,KAAK,GAAa,IAAI;AAAA,EACtF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,cAAc,WAAoB,OAAO,UAAmB,OAAe;AACzE,QAAI,KAAK,SAAS,KAAK;AACrB,YAAM,IAAI;AAAA,QACR,UAAU;AAAA,QACV,6CAA6C,KAAK;AAAA,MACpD;AAAA,IACF;AACA,UAAM,SAAS,qBAAqB,KAAK,cAAc,QAAQ,UAAU,OAAO;AAChF,UAAM,QAAQ,QAAQ,WAAW,KAAK,CAAC,KAAK,KAAK,CAAC,CAAC;AACnD,UAAM,oBAAoB,KAAK;AAC/B,UAAM,QAAQ,MAAM,KAAK,OAAO,CAAC;AAEjC,UAAM,YAAY,KAAK;AAEvB,UAAM,MACJ,KAAK,cAAc,QAAQ,CAAC,WAAW,OAAO,CAAC,QAAQ,KAAK,UAAU,CAAC,IAAI,KAAK;AAClF,UAAM,cAAc;AAAA,MAClB,OAAO,CAAC,QAAQ,OAAO,mBAAmB,OAAO,WAAW,GAAG,CAAC;AAAA,IAClE;AAEA,WAAO,YAAY,WAAW;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,SAAS,MAAc;AAC5B,UAAM,YAAY,SAAS,mBAAmB,IAAI;AAElD,WAAO,IAAI,SAAS;AAAA,MAClB,WAAW,aAAa,UAAU,MAAM,EAAE,CAAC;AAAA,MAC3C,YAAY,aAAa,UAAU,MAAM,GAAG,EAAE,CAAC;AAAA,IACjD,CAAC;AAAA,EACH;AAAA,EAEA,OAAO,gBAAgB,aAAqB;AAC1C,UAAM,UAAU,QAAQ,aAAa,WAAW,CAAC;AACjD,UAAM,QAAQ,aAAa,OAAO;AAClC,UAAM,gBAAgB,YAAY,MAAM,MAAM,GAAG,EAAE,CAAC,MAAM;AAE1D,QAAI,MAAM,WAAW,MAAM,CAAC,mBAAmB,KAAK,GAAG;AACrD,YAAM,IAAI,UAAU,UAAU,iBAAiB,2CAA2C;AAAA,IAC5F;AACA,QAAI,CAAC,eAAe;AAClB,YAAM,IAAI,UAAU,UAAU,iBAAiB,uCAAuC;AAAA,IACxF;AAEA,UAAM,QAAQ,MAAM,CAAC;AACrB,UAAM,oBAAoB,QAAQ,MAAM,MAAM,GAAG,CAAC,CAAC;AACnD,UAAM,QAAQ,SAAS,QAAQ,MAAM,MAAM,GAAG,EAAE,CAAC,EAAE,UAAU,CAAC,GAAG,EAAE;AACnE,UAAM,YAAY,QAAQ,MAAM,MAAM,IAAI,EAAE,CAAC;AAC7C,UAAM,MAAM,MAAM,MAAM,IAAI,EAAE;AAE9B,QAAK,UAAU,KAAK,sBAAsB,gBAAkB,UAAU,KAAK,UAAU,GAAI;AACvF,YAAM,IAAI;AAAA,QACR,UAAU;AAAA,QACV;AAAA,MACF;AAAA,IACF;AAEA,QAAI,oBAAoB,KAAK,GAAG;AAC9B,UAAI,IAAI,CAAC,MAAM,GAAG;AAChB,cAAM,IAAI,UAAU,UAAU,iBAAiB,8BAA8B;AAAA,MAC/E;AAEA,aAAO,IAAI,SAAS;AAAA,QAClB,WAAW;AAAA,QACX;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH;AAEA,QAAI,IAAI,CAAC,MAAM,GAAG;AAChB,YAAM,IAAI,UAAU,UAAU,iBAAiB,+BAA+B;AAAA,IAChF;AAEA,WAAO,IAAI,SAAS;AAAA,MAClB,YAAY,IAAI,MAAM,CAAC;AAAA,MACvB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAEA,IAAO,mBAAQ;","names":[]}