{"version":3,"file":"barrel.mjs","names":[],"sources":["../src/signer.ts","../src/signersFactory.ts","../src/barrel.ts"],"sourcesContent":["import { ccc } from \"@ckb-ccc/core\";\nimport { Psbt } from \"bitcoinjs-lib\";\nimport * as v from \"valibot\";\nimport {\n  Address,\n  AddressPurpose,\n  BtcProvider,\n  MessageSigningProtocols,\n  Requests,\n  Return,\n  RpcErrorCode,\n  RpcResponse,\n  WalletNetworkName,\n  rpcErrorResponseMessageSchema,\n  rpcSuccessResponseMessageSchema,\n} from \"./advancedBarrel.js\";\n\nasync function checkResponse<T extends keyof Requests>(\n  response: Promise<RpcResponse<T>>,\n): Promise<Return<T>> {\n  const res = await response;\n  if (v.is(rpcErrorResponseMessageSchema, res)) {\n    // eslint-disable-next-line @typescript-eslint/only-throw-error\n    throw res.error;\n  }\n\n  if (v.is(rpcSuccessResponseMessageSchema, res)) {\n    return res.result;\n  }\n\n  // eslint-disable-next-line @typescript-eslint/only-throw-error\n  throw {\n    code: RpcErrorCode.INTERNAL_ERROR,\n    message: \"Received unknown response from provider.\",\n    data: res,\n  };\n}\n\n/**\n * Class representing a Bitcoin signer that extends SignerBtc\n * @public\n */\nexport class Signer extends ccc.SignerBtc {\n  private addressCache: Promise<Address | undefined> | undefined;\n\n  /**\n   * Creates an instance of Signer.\n   * @param client - The client instance.\n   * @param provider - The provider instance.\n   */\n  constructor(\n    client: ccc.Client,\n    public readonly provider: BtcProvider,\n    _preferredNetworks?: ccc.NetworkPreference[],\n    public readonly network?: WalletNetworkName,\n  ) {\n    super(client);\n  }\n\n  async assertAddress(): Promise<Address> {\n    const request = this.addressCache ?? this.requestAddress();\n    this.addressCache = request;\n\n    let address: Address | undefined;\n    try {\n      address = await request;\n    } catch (error) {\n      if (this.addressCache === request) {\n        this.addressCache = undefined;\n      }\n      throw error;\n    }\n\n    if (address) {\n      return address;\n    }\n    this.addressCache = undefined;\n    throw Error(\"Not connected\");\n  }\n\n  private async requestAddress(): Promise<Address | undefined> {\n    if (this.network && (await this.getNetwork()) !== this.network) {\n      return;\n    }\n\n    return (\n      await checkResponse(\n        this.provider.request(\"getAddresses\", {\n          purposes: [AddressPurpose.Payment],\n        }),\n      )\n    ).addresses[0];\n  }\n\n  /**\n   * Gets the Bitcoin account address.\n   * @returns A promise that resolves to the Bitcoin account address.\n   */\n  async getBtcAccount(): Promise<string> {\n    return (await this.assertAddress()).address;\n  }\n\n  /**\n   * Gets the Bitcoin public key.\n   * @returns A promise that resolves to the Bitcoin public key.\n   */\n  async getBtcPublicKey(): Promise<ccc.Hex> {\n    return ccc.hexFrom((await this.assertAddress()).publicKey);\n  }\n\n  /**\n   * Connects to the provider by requesting accounts.\n   * @returns A promise that resolves when the connection is established.\n   */\n  async connect(): Promise<void> {\n    if (await this.isConnected()) {\n      return;\n    }\n\n    await checkResponse(\n      this.provider.request(\"wallet_requestPermissions\", undefined),\n    );\n    const currentNetwork = this.network ? await this.getNetwork() : undefined;\n    if (this.network && currentNetwork !== this.network) {\n      await checkResponse(\n        this.provider.request(\"wallet_changeNetwork\", { name: this.network }),\n      );\n      this.addressCache = undefined;\n    }\n  }\n\n  async disconnect(): Promise<void> {\n    this.addressCache = undefined;\n  }\n\n  onReplaced(listener: () => void): () => void {\n    const stops: (() => void)[] = [];\n    const stop = () => {\n      stops.splice(0).forEach((unregister) => unregister());\n    };\n    const replacer = () => {\n      listener();\n      stop();\n    };\n    stops.push(\n      this.provider.addListener(\"accountChange\", replacer),\n      this.provider.addListener(\"networkChange\", replacer),\n    );\n\n    return stop;\n  }\n\n  /**\n   * Checks if the signer is connected.\n   * @returns A promise that resolves to true if connected, false otherwise.\n   */\n  async isConnected(): Promise<boolean> {\n    try {\n      const address = await this.requestAddress();\n      if (address) {\n        this.addressCache = Promise.resolve(address);\n      } else {\n        this.addressCache = undefined;\n      }\n      return address !== undefined;\n    } catch (_error) {\n      this.addressCache = undefined;\n      return false;\n    }\n  }\n\n  private async getNetwork(): Promise<WalletNetworkName> {\n    return (\n      await checkResponse(this.provider.request(\"wallet_getNetwork\", null))\n    ).bitcoin.name;\n  }\n\n  /**\n   * Signs a raw message with the Bitcoin account.\n   * @param message - The message to sign.\n   * @returns A promise that resolves to the signed message.\n   */\n  async signMessageRaw(message: string | ccc.BytesLike): Promise<string> {\n    const challenge =\n      typeof message === \"string\" ? message : ccc.hexFrom(message).slice(2);\n\n    return (\n      await checkResponse(\n        this.provider.request(\"signMessage\", {\n          message: challenge,\n          address: (await this.assertAddress()).address,\n          protocol: MessageSigningProtocols.ECDSA,\n        }),\n      )\n    ).signature;\n  }\n\n  /**\n   * Build default inputsToSign for all unsigned inputs\n   */\n  private buildDefaultinputsToSign(\n    psbtHex: ccc.Hex,\n    address: string,\n  ): ccc.InputToSignLike[] {\n    const inputsToSign: ccc.InputToSignLike[] = [];\n\n    try {\n      // Collect all unsigned inputs\n      const psbt = Psbt.fromHex(psbtHex.slice(2));\n      psbt.data.inputs.forEach((input, index) => {\n        const isSigned =\n          input.finalScriptSig ||\n          input.finalScriptWitness ||\n          input.tapKeySig ||\n          (input.partialSig && input.partialSig.length > 0) ||\n          (input.tapScriptSig && input.tapScriptSig.length > 0);\n\n        if (!isSigned) {\n          inputsToSign.push({ index, address });\n        }\n      });\n\n      // If no unsigned inputs found, the PSBT is already fully signed\n      // Let the wallet handle this case (likely a no-op or error)\n    } catch (error) {\n      const errorMessage =\n        error instanceof Error ? error.message : String(error);\n      throw new Error(\n        `Failed to parse PSBT hex. Please provide inputsToSign explicitly in options. Original error: ${errorMessage}`,\n        { cause: error },\n      );\n    }\n\n    return inputsToSign;\n  }\n\n  private async prepareSignPsbtParams(\n    psbtHex: ccc.Hex,\n    options?: ccc.SignPsbtOptionsLike,\n  ): Promise<{\n    psbtBase64: string;\n    signInputs: Record<string, number[]>;\n  }> {\n    let inputsToSign = options?.inputsToSign;\n\n    if (!inputsToSign || !inputsToSign.length) {\n      const address = await this.getBtcAccount();\n      inputsToSign = this.buildDefaultinputsToSign(psbtHex, address);\n    }\n\n    const psbtBase64 = ccc.bytesTo(psbtHex, \"base64\");\n\n    const signInputs = inputsToSign.reduce(\n      (acc, input) => {\n        if (!input.address) {\n          throw new Error(\n            \"Xverse only supports signing with address. Please provide 'address' in inputsToSign.\",\n          );\n        }\n        if (acc[input.address]) {\n          acc[input.address].push(input.index);\n        } else {\n          acc[input.address] = [input.index];\n        }\n        return acc;\n      },\n      {} as Record<string, number[]>,\n    );\n\n    return { psbtBase64, signInputs };\n  }\n\n  /**\n   * Signs a PSBT using Xverse wallet.\n   *\n   * @param psbtHex - The hex string of PSBT to sign.\n   * @param options - Options for signing the PSBT\n   * @returns A promise that resolves to the signed PSBT as a Hex string\n   *\n   * @remarks\n   * Xverse accepts:\n   * - psbt: A string representing the PSBT to sign, encoded in base64\n   * - signInputs: A Record<string, number[]> where:\n   *   - keys are the addresses to use for signing\n   *   - values are the indexes of the inputs to sign with each address\n   *\n   * Xverse returns:\n   * - psbt: The base64 encoded signed PSBT\n   *\n   * @see https://docs.xverse.app/sats-connect/bitcoin-methods/signpsbt\n   */\n  async signPsbt(\n    psbtHex: ccc.HexLike,\n    options?: ccc.SignPsbtOptionsLike,\n  ): Promise<ccc.Hex> {\n    const { psbtBase64, signInputs } = await this.prepareSignPsbtParams(\n      ccc.hexFrom(psbtHex),\n      options,\n    );\n\n    const signedPsbtBase64 = (\n      await checkResponse(\n        this.provider.request(\"signPsbt\", {\n          psbt: psbtBase64,\n          signInputs,\n          broadcast: false,\n        }),\n      )\n    ).psbt;\n\n    return ccc.hexFrom(ccc.bytesFrom(signedPsbtBase64, \"base64\"));\n  }\n\n  /**\n   * Broadcasts a PSBT to the Bitcoin network.\n   *\n   * @remarks\n   * Xverse does not support broadcasting a signed PSBT directly.\n   * It only supports \"Sign and Broadcast\" as a single atomic operation via `signAndBroadcastPsbt`.\n   */\n  async broadcastPsbt(\n    _psbtHex: ccc.HexLike,\n    _options?: ccc.SignPsbtOptionsLike,\n  ): Promise<ccc.Hex> {\n    throw new Error(\n      \"Xverse does not support broadcasting signed PSBTs directly. Use signAndBroadcastPsbt instead.\",\n    );\n  }\n\n  async signAndBroadcastPsbt(\n    psbtHex: ccc.HexLike,\n    options?: ccc.SignPsbtOptionsLike,\n  ): Promise<ccc.Hex> {\n    // ccc.hexFrom adds 0x prefix, but BTC expects non-0x\n    const { psbtBase64, signInputs } = await this.prepareSignPsbtParams(\n      ccc.hexFrom(psbtHex),\n      options,\n    );\n\n    const result = await checkResponse(\n      this.provider.request(\"signPsbt\", {\n        psbt: psbtBase64,\n        signInputs,\n        broadcast: true,\n      }),\n    );\n\n    if (!result.txid) {\n      throw new Error(\"Failed to broadcast PSBT\");\n    }\n\n    return ccc.hexFrom(result.txid);\n  }\n}\n","import { ccc } from \"@ckb-ccc/core\";\nimport { BtcProvider, Provider } from \"./advancedBarrel.js\";\nimport { Signer } from \"./signer.js\";\n\nfunction getProviderById(providerId: string) {\n  return (\n    providerId\n      ?.split(\".\")\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-return\n      .reduce((acc: any, part) => acc?.[part], window) as BtcProvider\n  );\n}\n\n/**\n * Retrieves the Xverse signer if available.\n * @public\n *\n * @param client - The client instance.\n * @returns All Xverse Signer instances\n */\nexport function getXverseSigners(\n  client: ccc.Client,\n  preferredNetworks?: ccc.NetworkPreference[],\n): { wallet: ccc.Wallet; signerInfo: ccc.SignerInfo }[] {\n  const windowRef = window as {\n    BitcoinProvider?: BtcProvider;\n    XverseProviders?: {\n      BitcoinProvider?: BtcProvider;\n    };\n    btc_providers?: Provider[];\n  };\n\n  const signers = (() => {\n    if (windowRef.btc_providers) {\n      return windowRef.btc_providers.flatMap((provider) => {\n        const networks =\n          provider.name === \"Xverse Wallet\" ||\n          (provider.methods?.includes(\"wallet_getNetwork\") &&\n            provider.methods.includes(\"wallet_changeNetwork\"))\n            ? ([\"Mainnet\", \"Testnet4\", \"Signet\", \"Regtest\"] as const)\n            : ([undefined] as const);\n\n        return networks\n          .filter(\n            (network) =>\n              client.addressPrefix !== \"ckb\" || network === \"Mainnet\",\n          )\n          .map((network) => ({\n            wallet: {\n              name: provider.name,\n              icon: provider.icon,\n            },\n            signerInfo: {\n              name: network && network !== \"Mainnet\" ? `BTC ${network}` : \"BTC\",\n              signer: new Signer(\n                client,\n                getProviderById(provider.id),\n                preferredNetworks,\n                network,\n              ),\n            },\n          }));\n      });\n    }\n\n    return [];\n  })();\n\n  return signers;\n}\n","export * from \"./signer.js\";\nexport * from \"./signersFactory.js\";\n"],"mappings":"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"}