{"version":3,"file":"XverseCompatibleWalletAdapterImpl-nrzlZFnp.mjs","sources":["../src/utils/XverseCompatibleWalletAdapterImpl.ts"],"sourcesContent":["import { base64, hex } from \"@scure/base\"\nimport * as btc from \"@scure/btc-signer\"\nimport { UserRejectError } from \"../utils/error\"\nimport {\n  SignMessageAlgorithm,\n  SignMessageResult,\n  WalletAdapter,\n  WalletAdapter_onAddressesChanged_callback,\n  WalletAdapterAddress,\n  WalletAdapterAddressPurpose,\n  WalletAdapterNotConnectedError,\n} from \"../WalletAdapters.types\"\n\nexport type XverseCompatibleWalletAdapterGetProviderIdFn = () => Promise<string>\n\nexport type XverseCompatibleWalletAdapterParsedAddressesFn = (info: {\n  sdk: typeof import(\"sats-connect\")\n  network: import(\"sats-connect\").BitcoinNetworkType\n  addresses: import(\"sats-connect\").Address[]\n}) => Promise<XverseCompatibleWalletAdapterImplAddress[]>\n\nexport type XverseCompatibleWalletAdapterImplAddress = WalletAdapterAddress & {\n  publicKey: string\n}\n\nexport class XverseCompatibleWalletAdapterImpl implements WalletAdapter {\n  protected readonly walletDisplayName: string\n  protected readonly getProviderId: XverseCompatibleWalletAdapterGetProviderIdFn\n  protected readonly parseAddresses: XverseCompatibleWalletAdapterParsedAddressesFn\n\n  constructor(info: {\n    walletDisplayName: string\n    getProviderId: XverseCompatibleWalletAdapterGetProviderIdFn\n    parseAddresses: XverseCompatibleWalletAdapterParsedAddressesFn\n  }) {\n    this.walletDisplayName = info.walletDisplayName\n    this.getProviderId = info.getProviderId\n    this.parseAddresses = info.parseAddresses\n  }\n\n  private async getSdk(): Promise<typeof import(\"sats-connect\")> {\n    return import(\"sats-connect\")\n  }\n\n  async connect(): Promise<void> {\n    await (await this.getSdk()).request(\"wallet_connect\", null)\n  }\n\n  async disconnect(): Promise<void> {\n    return Promise.resolve()\n  }\n\n  async getAddresses(): Promise<XverseCompatibleWalletAdapterImplAddress[]> {\n    const sdk = await this.getSdk()\n\n    const resp = await handleRpcError(\n      sdk.request(\n        \"getAddresses\",\n        {\n          purposes: [sdk.AddressPurpose.Ordinals, sdk.AddressPurpose.Payment],\n        },\n        await this.getProviderId(),\n      ),\n    )\n\n    if (resp == null) {\n      throw new WalletAdapterNotConnectedError(this.walletDisplayName)\n    }\n\n    return this.parseAddresses({\n      sdk,\n      network: resp.network.bitcoin.name,\n      addresses: resp.addresses,\n    })\n  }\n\n  async signMessage(\n    address: string,\n    message: string,\n  ): Promise<SignMessageResult> {\n    const sdk = await this.getSdk()\n\n    const result = await handleRpcError(\n      sdk.request(\n        \"signMessage\",\n        {\n          address,\n          message,\n          protocol: sdk.MessageSigningProtocols.BIP322,\n        },\n        await this.getProviderId(),\n      ),\n    )\n\n    return {\n      result: result.signature,\n      address,\n      algorithm: SignMessageAlgorithm.BIP322,\n    }\n  }\n\n  sendBitcoinFeeRateCapability = \"unavailable\" as const\n  async sendBitcoin(\n    fromAddress: string,\n    receiverAddress: string,\n    satoshiAmount: bigint,\n  ): Promise<{ txid: string }> {\n    const senderAddress = (await this.getAddresses()).find(a =>\n      a.purposes.includes(WalletAdapterAddressPurpose.Bitcoin),\n    )\n    if (senderAddress == null) {\n      throw new XverseCompatibleProviderError({\n        code: XverseRpcErrorCode.INVALID_PARAMS,\n        message: \"Bitcoin address not found\",\n      })\n    }\n\n    const sdk = await this.getSdk()\n\n    return await handleRpcError(\n      sdk.request(\n        \"sendTransfer\",\n        {\n          recipients: [\n            {\n              address: receiverAddress,\n              amount: Number(satoshiAmount),\n            },\n          ],\n        },\n        await this.getProviderId(),\n      ),\n    )\n  }\n\n  /**\n   * @internal\n   * @experimental\n   */\n  sendInscriptionFeeRateCapability = \"unavailable\" as const\n\n  async signAndFinalizePsbt(\n    psbtHex: string,\n    signIndices: [address: string, signIndex: number][],\n  ): Promise<{\n    signedPsbtHex: string\n  }> {\n    const sdk = await this.getSdk()\n\n    const psbtBase64 = base64.encode(hex.decode(psbtHex))\n\n    const result = await handleRpcError(\n      sdk.request(\n        \"signPsbt\",\n        {\n          psbt: psbtBase64,\n          signInputs: signIndices.reduce(\n            (acc, [address, signIndex]) => {\n              acc[address] = [signIndex]\n              return acc\n            },\n            {} as Record<string, number[]>,\n          ),\n          broadcast: false,\n        },\n        await this.getProviderId(),\n      ),\n    )\n\n    const tx = btc.Transaction.fromPSBT(base64.decode(result.psbt), {\n      allowUnknownInputs: true,\n      allowUnknownOutputs: true,\n      disableScriptCheck: true,\n      allowLegacyWitnessUtxo: true,\n    })\n    tx.finalize()\n\n    return { signedPsbtHex: hex.encode(tx.toPSBT()) }\n  }\n\n  onAddressesChanged(callback: WalletAdapter_onAddressesChanged_callback): {\n    unsubscribe: () => void\n  } {\n    // Xverse uses sats-connect Wallet.addListener for events\n    // https://docs.xverse.app/sats-connect/xverse-wallet-events\n    const removeListeners: Array<() => void> = []\n\n    void (async () => {\n      const sdk = await this.getSdk()\n\n      const handler = async (): Promise<void> => {\n        try {\n          const addresses = await this.getAddresses()\n          callback({ addresses })\n        } catch (error) {\n          console.warn(\n            `[${this.walletDisplayName}] Failed to get addresses on change:`,\n            error,\n          )\n        }\n      }\n\n      // Listen to account and network changes\n      const removeAccountListener = sdk.addListener(\"accountChange\", handler)\n      const removeNetworkListener = sdk.addListener(\"networkChange\", handler)\n\n      removeListeners.push(removeAccountListener, removeNetworkListener)\n    })()\n\n    return {\n      unsubscribe: () => {\n        removeListeners.forEach(remove => remove())\n      },\n    }\n  }\n}\n\nexport enum XverseRpcErrorCode {\n  /**\n   * Parse error Invalid JSON\n   **/\n  PARSE_ERROR = -32700,\n  /**\n   * The JSON sent is not a valid Request object.\n   **/\n  INVALID_REQUEST = -32600,\n  /**\n   * The method does not exist/is not available.\n   **/\n  METHOD_NOT_FOUND = -32601,\n  /**\n   * Invalid method parameter(s).\n   */\n  INVALID_PARAMS = -32602,\n  /**\n   * Internal JSON-RPC error.\n   * This is a generic error, used when the server encounters an error in performing the request.\n   **/\n  INTERNAL_ERROR = -32603,\n  /**\n   * user rejected/canceled the request\n   */\n  USER_REJECTION = -32000,\n  /**\n   * method is not supported for the address provided\n   */\n  METHOD_NOT_SUPPORTED = -32001,\n  /**\n   * The client does not have permission to access the requested resource.\n   */\n  ACCESS_DENIED = -32002,\n}\nexport interface XverseCompatibleProviderAPIThrownError {\n  code: XverseRpcErrorCode\n  message: string\n}\nexport function isXverseCompatibleProviderAPIThrownError(\n  err: any,\n): err is XverseCompatibleProviderAPIThrownError {\n  return err != null && \"code\" in err && \"message\" in err\n}\n\nexport class XverseCompatibleProviderError extends Error {\n  readonly code: number\n  constructor(err: XverseCompatibleProviderAPIThrownError) {\n    super(err.message)\n    this.code = err.code\n    this.cause = err\n  }\n}\n\nconst handleRpcError = async <T>(\n  promise: Promise<\n    { status: \"success\"; result: T } | { status: \"error\"; error: unknown }\n  >,\n): Promise<T> => {\n  try {\n    const res = await promise\n    if (res.status === \"error\") {\n      throw res.error\n    }\n    return res.result\n  } catch (e: any) {\n    if (isXverseCompatibleProviderAPIThrownError(e)) {\n      if (e.code === XverseRpcErrorCode.USER_REJECTION) {\n        throw new UserRejectError()\n      }\n      throw new XverseCompatibleProviderError(e)\n    }\n    throw e\n  }\n}\n"],"names":["XverseCompatibleWalletAdapterImpl","info","sdk","resp","handleRpcError","WalletAdapterNotConnectedError","address","message","SignMessageAlgorithm","fromAddress","receiverAddress","satoshiAmount","a","WalletAdapterAddressPurpose","XverseCompatibleProviderError","psbtHex","signIndices","psbtBase64","base64","hex","result","acc","signIndex","tx","btc.Transaction","callback","removeListeners","handler","addresses","error","removeAccountListener","removeNetworkListener","remove","XverseRpcErrorCode","isXverseCompatibleProviderAPIThrownError","err","promise","res","e","UserRejectError"],"mappings":"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"}